ETH Price: $1,922.99 (+5.29%)
Gas: 0.04 Gwei

Transaction Decoder

Block:
23554747 at Oct-11-2025 01:21:11 PM +UTC
Transaction Fee:
0.000044594322035796 ETH $0.09
Gas Used:
69,537 Gas / 0.641303508 Gwei

Emitted Events:

651 FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000001bd040f0f0e8f40f130ec63b318cb1420522beed, 0x00000000000000000000000033b41fe18d3a39046ad672f8a0c8c415454f629c, 0000000000000000000000000000000000000000000000000000000a82211fb2 )
652 0x1bd040f0f0e8f40f130ec63b318cb1420522beed.0xe346f5c97a360db5188bfa5d3ec5f0583abde420c6ba4d08b6cfe61addc17105( 0xe346f5c97a360db5188bfa5d3ec5f0583abde420c6ba4d08b6cfe61addc17105, b6d76078fc06cf199b12d77925974f373f668495a62c8a3299235462ad38a565 )

Account State Difference:

  Address   Before After State Difference Code
0x1Bd040F0...20522bEed 0.00014108661189 Eth0 Eth0.00014108661189
0x22C6E59c...86165F782
4.120028831795425836 Eth
Nonce: 41632
4.11998423747339004 Eth
Nonce: 41633
0.000044594322035796
0x33b41fE1...5454F629c 61.432537791413708294 Eth61.432678878025598294 Eth0.00014108661189
(Titan Builder)
14.511442474985054452 Eth14.511442525767925552 Eth0.0000000507828711
0xA0b86991...E3606eB48

Execution Trace

TransparentUpgradeableProxy.1f3177ba( )
  • 0x9b0030f882b913d75d09805321b32710ec4218da.1f3177ba( )
    • 0x1bd040f0f0e8f40f130ec63b318cb1420522beed.23305703( )
      • EscrowSrc.withdraw( secret=B6D76078FC06CF199B12D77925974F373F668495A62C8A3299235462AD38A565, immutables=[{name:orderHash, type:bytes32, order:1, indexed:false, value:CC437EF22E70AC9D3BAF860C545D62330A856B8B40FEC5A6FDA6E59D96B4586F, valueString:CC437EF22E70AC9D3BAF860C545D62330A856B8B40FEC5A6FDA6E59D96B4586F}, {name:hashlock, type:bytes32, order:2, indexed:false, value:6DD3C32D5F039734B7B91C979EE2AC1B6E5D18070F36B3D9CBA3F085338FC0CE, valueString:6DD3C32D5F039734B7B91C979EE2AC1B6E5D18070F36B3D9CBA3F085338FC0CE}, {name:maker, type:uint256, order:3, indexed:false, value:506190950194770310333838503201306692094500537789, valueString:506190950194770310333838503201306692094500537789}, {name:taker, type:uint256, order:4, indexed:false, value:295175440679871226750959972043725454192436798108, valueString:295175440679871226750959972043725454192436798108}, {name:token, type:uint256, order:5, indexed:false, value:917551056842671309452305380979543736893630245704, valueString:917551056842671309452305380979543736893630245704}, {name:amount, type:uint256, order:6, indexed:false, value:45132881842, valueString:45132881842}, {name:safetyDeposit, type:uint256, order:7, indexed:false, value:141086611890000, valueString:141086611890000}, {name:timelocks, type:uint256, order:8, indexed:false, value:47454596468675299979121725885618368449474007848524260545797149696689321279524, valueString:47454596468675299979121725885618368449474007848524260545797149696689321279524}] )
        • FiatTokenProxy.a9059cbb( )
          • FiatTokenV2_2.transfer( to=0x33b41fE18D3A39046ad672f8a0C8c415454F629c, value=45132881842 ) => ( True )
          • ETH 0.00014108661189 TransparentUpgradeableProxy.CALL( )
            • ETH 0.00014108661189 0x9b0030f882b913d75d09805321b32710ec4218da.DELEGATECALL( )
              File 1 of 4: TransparentUpgradeableProxy
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
              pragma solidity ^0.8.20;
              import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
              import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol";
              import {IERC1967} from "../../interfaces/IERC1967.sol";
              import {ProxyAdmin} from "./ProxyAdmin.sol";
              /**
               * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
               * does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch
               * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
               * include them in the ABI so this interface must be used to interact with it.
               */
              interface ITransparentUpgradeableProxy is IERC1967 {
                  function upgradeToAndCall(address, bytes calldata) external payable;
              }
              /**
               * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance.
               *
               * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
               * clashing], which can potentially be used in an attack, this contract uses the
               * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
               * things that go hand in hand:
               *
               * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
               * that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself.
               * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to
               * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating
               * the proxy admin cannot fallback to the target implementation.
               *
               * These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a
               * dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to
               * call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and
               * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative
               * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership.
               *
               * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
               * inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch
               * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
               * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
               * implementation.
               *
               * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a
               * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract.
               *
               * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an
               * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be
               * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an
               * undesirable state where the admin slot is different from the actual admin. Relying on the value of the admin slot
               * is generally fine if the implementation is trusted.
               *
               * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the
               * compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new
               * function and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This
               * could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency.
               */
              contract TransparentUpgradeableProxy is ERC1967Proxy {
                  // An immutable address for the admin to avoid unnecessary SLOADs before each call
                  // at the expense of removing the ability to change the admin once it's set.
                  // This is acceptable if the admin is always a ProxyAdmin instance or similar contract
                  // with its own ability to transfer the permissions to another account.
                  address private immutable _admin;
                  /**
                   * @dev The proxy caller is the current admin, and can't fallback to the proxy target.
                   */
                  error ProxyDeniedAdminAccess();
                  /**
                   * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
                   * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
                   * {ERC1967Proxy-constructor}.
                   */
                  constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                      _admin = address(new ProxyAdmin(initialOwner));
                      // Set the storage value and emit an event for ERC-1967 compatibility
                      ERC1967Utils.changeAdmin(_proxyAdmin());
                  }
                  /**
                   * @dev Returns the admin of this proxy.
                   */
                  function _proxyAdmin() internal view virtual returns (address) {
                      return _admin;
                  }
                  /**
                   * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
                   */
                  function _fallback() internal virtual override {
                      if (msg.sender == _proxyAdmin()) {
                          if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
                              revert ProxyDeniedAdminAccess();
                          } else {
                              _dispatchUpgradeToAndCall();
                          }
                      } else {
                          super._fallback();
                      }
                  }
                  /**
                   * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
                   *
                   * Requirements:
                   *
                   * - If `data` is empty, `msg.value` must be zero.
                   */
                  function _dispatchUpgradeToAndCall() private {
                      (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
                      ERC1967Utils.upgradeToAndCall(newImplementation, data);
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
              pragma solidity ^0.8.20;
              import {IBeacon} from "../beacon/IBeacon.sol";
              import {Address} from "../../utils/Address.sol";
              import {StorageSlot} from "../../utils/StorageSlot.sol";
              /**
               * @dev This abstract contract provides getters and event emitting update functions for
               * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
               */
              library ERC1967Utils {
                  /**
                   * @dev Emitted when the implementation is upgraded.
                   */
                  event Upgraded(address indexed implementation);
                  /**
                   * @dev Emitted when the admin account has changed.
                   */
                  event AdminChanged(address previousAdmin, address newAdmin);
                  /**
                   * @dev Emitted when the beacon is changed.
                   */
                  event BeaconUpgraded(address indexed beacon);
                  /**
                   * @dev Storage slot with the address of the current implementation.
                   * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                  /**
                   * @dev The `implementation` of the proxy is invalid.
                   */
                  error ERC1967InvalidImplementation(address implementation);
                  /**
                   * @dev The `admin` of the proxy is invalid.
                   */
                  error ERC1967InvalidAdmin(address admin);
                  /**
                   * @dev The `beacon` of the proxy is invalid.
                   */
                  error ERC1967InvalidBeacon(address beacon);
                  /**
                   * @dev An upgrade function sees `msg.value > 0` that may be lost.
                   */
                  error ERC1967NonPayable();
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function getImplementation() internal view returns (address) {
                      return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the ERC-1967 implementation slot.
                   */
                  function _setImplementation(address newImplementation) private {
                      if (newImplementation.code.length == 0) {
                          revert ERC1967InvalidImplementation(newImplementation);
                      }
                      StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                  }
                  /**
                   * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                   * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                   * to avoid stuck value in the contract.
                   *
                   * Emits an {IERC1967-Upgraded} event.
                   */
                  function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                      _setImplementation(newImplementation);
                      emit Upgraded(newImplementation);
                      if (data.length > 0) {
                          Address.functionDelegateCall(newImplementation, data);
                      } else {
                          _checkNonPayable();
                      }
                  }
                  /**
                   * @dev Storage slot with the admin of the contract.
                   * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                  /**
                   * @dev Returns the current admin.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
                   * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                   */
                  function getAdmin() internal view returns (address) {
                      return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the ERC-1967 admin slot.
                   */
                  function _setAdmin(address newAdmin) private {
                      if (newAdmin == address(0)) {
                          revert ERC1967InvalidAdmin(address(0));
                      }
                      StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                  }
                  /**
                   * @dev Changes the admin of the proxy.
                   *
                   * Emits an {IERC1967-AdminChanged} event.
                   */
                  function changeAdmin(address newAdmin) internal {
                      emit AdminChanged(getAdmin(), newAdmin);
                      _setAdmin(newAdmin);
                  }
                  /**
                   * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                   * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                  /**
                   * @dev Returns the current beacon.
                   */
                  function getBeacon() internal view returns (address) {
                      return StorageSlot.getAddressSlot(BEACON_SLOT).value;
                  }
                  /**
                   * @dev Stores a new beacon in the ERC-1967 beacon slot.
                   */
                  function _setBeacon(address newBeacon) private {
                      if (newBeacon.code.length == 0) {
                          revert ERC1967InvalidBeacon(newBeacon);
                      }
                      StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                      address beaconImplementation = IBeacon(newBeacon).implementation();
                      if (beaconImplementation.code.length == 0) {
                          revert ERC1967InvalidImplementation(beaconImplementation);
                      }
                  }
                  /**
                   * @dev Change the beacon and trigger a setup call if data is nonempty.
                   * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                   * to avoid stuck value in the contract.
                   *
                   * Emits an {IERC1967-BeaconUpgraded} event.
                   *
                   * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                   * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                   * efficiency.
                   */
                  function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                      _setBeacon(newBeacon);
                      emit BeaconUpgraded(newBeacon);
                      if (data.length > 0) {
                          Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                      } else {
                          _checkNonPayable();
                      }
                  }
                  /**
                   * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                   * if an upgrade doesn't perform an initialization call.
                   */
                  function _checkNonPayable() private {
                      if (msg.value > 0) {
                          revert ERC1967NonPayable();
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
              pragma solidity ^0.8.20;
              import {Proxy} from "../Proxy.sol";
              import {ERC1967Utils} from "./ERC1967Utils.sol";
              /**
               * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
               * implementation address that can be changed. This address is stored in storage in the location specified by
               * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967], so that it doesn't conflict with the storage layout of the
               * implementation behind the proxy.
               */
              contract ERC1967Proxy is Proxy {
                  /**
                   * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
                   *
                   * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
                   * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
                   *
                   * Requirements:
                   *
                   * - If `data` is empty, `msg.value` must be zero.
                   */
                  constructor(address implementation, bytes memory _data) payable {
                      ERC1967Utils.upgradeToAndCall(implementation, _data);
                  }
                  /**
                   * @dev Returns the current implementation address.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
                   * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                   */
                  function _implementation() internal view virtual override returns (address) {
                      return ERC1967Utils.getImplementation();
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
               */
              interface IERC1967 {
                  /**
                   * @dev Emitted when the implementation is upgraded.
                   */
                  event Upgraded(address indexed implementation);
                  /**
                   * @dev Emitted when the admin account has changed.
                   */
                  event AdminChanged(address previousAdmin, address newAdmin);
                  /**
                   * @dev Emitted when the beacon is changed.
                   */
                  event BeaconUpgraded(address indexed beacon);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol)
              pragma solidity ^0.8.20;
              import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
              import {Ownable} from "../../access/Ownable.sol";
              /**
               * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
               * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
               */
              contract ProxyAdmin is Ownable {
                  /**
                   * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)`
                   * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
                   * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string.
                   * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must
                   * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
                   * during an upgrade.
                   */
                  string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
                  /**
                   * @dev Sets the initial owner who can perform upgrades.
                   */
                  constructor(address initialOwner) Ownable(initialOwner) {}
                  /**
                   * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation.
                   * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}.
                   *
                   * Requirements:
                   *
                   * - This contract must be the admin of `proxy`.
                   * - If `data` is empty, `msg.value` must be zero.
                   */
                  function upgradeAndCall(
                      ITransparentUpgradeableProxy proxy,
                      address implementation,
                      bytes memory data
                  ) public payable virtual onlyOwner {
                      proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev This is the interface that {BeaconProxy} expects of its beacon.
               */
              interface IBeacon {
                  /**
                   * @dev Must return an address that can be used as a delegate call target.
                   *
                   * {UpgradeableBeacon} will check that this address is a contract.
                   */
                  function implementation() external view returns (address);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
              pragma solidity ^0.8.20;
              import {Errors} from "./Errors.sol";
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev There's no code at `target` (it is not a contract).
                   */
                  error AddressEmptyCode(address target);
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      if (address(this).balance < amount) {
                          revert Errors.InsufficientBalance(address(this).balance, amount);
                      }
                      (bool success, ) = recipient.call{value: amount}("");
                      if (!success) {
                          revert Errors.FailedCall();
                      }
                  }
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain `call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason or custom error, it is bubbled
                   * up by this function (like regular Solidity function calls). However, if
                   * the call reverted with no returned reason, this function reverts with a
                   * {Errors.FailedCall} error.
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      if (address(this).balance < value) {
                          revert Errors.InsufficientBalance(address(this).balance, value);
                      }
                      (bool success, bytes memory returndata) = target.call{value: value}(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                   * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
                   * of an unsuccessful call.
                   */
                  function verifyCallResultFromTarget(
                      address target,
                      bool success,
                      bytes memory returndata
                  ) internal view returns (bytes memory) {
                      if (!success) {
                          _revert(returndata);
                      } else {
                          // only check if target is a contract if the call was successful and the return data is empty
                          // otherwise we already know that it was a contract
                          if (returndata.length == 0 && target.code.length == 0) {
                              revert AddressEmptyCode(target);
                          }
                          return returndata;
                      }
                  }
                  /**
                   * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                   * revert reason or with a default {Errors.FailedCall} error.
                   */
                  function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                      if (!success) {
                          _revert(returndata);
                      } else {
                          return returndata;
                      }
                  }
                  /**
                   * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
                   */
                  function _revert(bytes memory returndata) private pure {
                      // Look for revert reason and bubble it up if present
                      if (returndata.length > 0) {
                          // The easiest way to bubble the revert reason is using memory via assembly
                          /// @solidity memory-safe-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert Errors.FailedCall();
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.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 ERC-1967 implementation slot:
               * ```solidity
               * contract ERC1967 {
               *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
               *     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;
               *     }
               * }
               * ```
               *
               * TIP: Consider using this library along with {SlotDerivation}.
               */
              library StorageSlot {
                  struct AddressSlot {
                      address value;
                  }
                  struct BooleanSlot {
                      bool value;
                  }
                  struct Bytes32Slot {
                      bytes32 value;
                  }
                  struct Uint256Slot {
                      uint256 value;
                  }
                  struct Int256Slot {
                      int256 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 `Int256Slot` with member `value` located at `slot`.
                   */
                  function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot 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) (proxy/Proxy.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
               * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
               * be specified by overriding the virtual {_implementation} function.
               *
               * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
               * different contract through the {_delegate} function.
               *
               * The success and return data of the delegated call will be returned back to the caller of the proxy.
               */
              abstract contract Proxy {
                  /**
                   * @dev Delegates the current call to `implementation`.
                   *
                   * This function does not return to its internal call site, it will return directly to the external caller.
                   */
                  function _delegate(address implementation) internal virtual {
                      assembly {
                          // Copy msg.data. We take full control of memory in this inline assembly
                          // block because it will not return to Solidity code. We overwrite the
                          // Solidity scratch pad at memory position 0.
                          calldatacopy(0, 0, calldatasize())
                          // Call the implementation.
                          // out and outsize are 0 because we don't know the size yet.
                          let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                          // Copy the returned data.
                          returndatacopy(0, 0, returndatasize())
                          switch result
                          // delegatecall returns 0 on error.
                          case 0 {
                              revert(0, returndatasize())
                          }
                          default {
                              return(0, returndatasize())
                          }
                      }
                  }
                  /**
                   * @dev This is a virtual function that should be overridden so it returns the address to which the fallback
                   * function and {_fallback} should delegate.
                   */
                  function _implementation() internal view virtual returns (address);
                  /**
                   * @dev Delegates the current call to the address returned by `_implementation()`.
                   *
                   * This function does not return to its internal call site, it will return directly to the external caller.
                   */
                  function _fallback() internal virtual {
                      _delegate(_implementation());
                  }
                  /**
                   * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                   * function in the contract matches the call data.
                   */
                  fallback() external payable virtual {
                      _fallback();
                  }
              }
              // 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
              pragma solidity ^0.8.20;
              /**
               * @dev Collection of common custom errors used in multiple contracts
               *
               * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
               * It is recommended to avoid relying on the error API for critical functionality.
               */
              library Errors {
                  /**
                   * @dev The ETH balance of the account is not enough to perform the operation.
                   */
                  error InsufficientBalance(uint256 balance, uint256 needed);
                  /**
                   * @dev A call to an address target failed. The target may have reverted.
                   */
                  error FailedCall();
                  /**
                   * @dev The deployment failed.
                   */
                  error FailedDeployment();
              }
              // 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;
                  }
              }
              

              File 2 of 4: FiatTokenProxy
              pragma solidity ^0.4.24;
              
              // File: zos-lib/contracts/upgradeability/Proxy.sol
              
              /**
               * @title Proxy
               * @dev Implements delegation of calls to other contracts, with proper
               * forwarding of return values and bubbling of failures.
               * It defines a fallback function that delegates all calls to the address
               * returned by the abstract _implementation() internal function.
               */
              contract Proxy {
                /**
                 * @dev Fallback function.
                 * Implemented entirely in `_fallback`.
                 */
                function () payable external {
                  _fallback();
                }
              
                /**
                 * @return The Address of the implementation.
                 */
                function _implementation() internal view returns (address);
              
                /**
                 * @dev Delegates execution to an implementation contract.
                 * This is a low level function that doesn't return to its internal call site.
                 * It will return to the external caller whatever the implementation returns.
                 * @param implementation Address to delegate.
                 */
                function _delegate(address implementation) internal {
                  assembly {
                    // Copy msg.data. We take full control of memory in this inline assembly
                    // block because it will not return to Solidity code. We overwrite the
                    // Solidity scratch pad at memory position 0.
                    calldatacopy(0, 0, calldatasize)
              
                    // Call the implementation.
                    // out and outsize are 0 because we don't know the size yet.
                    let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
              
                    // Copy the returned data.
                    returndatacopy(0, 0, returndatasize)
              
                    switch result
                    // delegatecall returns 0 on error.
                    case 0 { revert(0, returndatasize) }
                    default { return(0, returndatasize) }
                  }
                }
              
                /**
                 * @dev Function that is run as the first thing in the fallback function.
                 * Can be redefined in derived contracts to add functionality.
                 * Redefinitions must call super._willFallback().
                 */
                function _willFallback() internal {
                }
              
                /**
                 * @dev fallback implementation.
                 * Extracted to enable manual triggering.
                 */
                function _fallback() internal {
                  _willFallback();
                  _delegate(_implementation());
                }
              }
              
              // File: openzeppelin-solidity/contracts/AddressUtils.sol
              
              /**
               * Utility library of inline functions on addresses
               */
              library AddressUtils {
              
                /**
                 * Returns whether the target address is a contract
                 * @dev This function will return false if invoked during the constructor of a contract,
                 * as the code is not actually created until after the constructor finishes.
                 * @param addr address to check
                 * @return whether the target address is a contract
                 */
                function isContract(address addr) internal view returns (bool) {
                  uint256 size;
                  // XXX Currently there is no better way to check if there is a contract in an address
                  // than to check the size of the code at that address.
                  // See https://ethereum.stackexchange.com/a/14016/36603
                  // for more details about how this works.
                  // TODO Check this again before the Serenity release, because all addresses will be
                  // contracts then.
                  // solium-disable-next-line security/no-inline-assembly
                  assembly { size := extcodesize(addr) }
                  return size > 0;
                }
              
              }
              
              // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol
              
              /**
               * @title UpgradeabilityProxy
               * @dev This contract implements a proxy that allows to change the
               * implementation address to which it will delegate.
               * Such a change is called an implementation upgrade.
               */
              contract UpgradeabilityProxy is Proxy {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 * @param implementation Address of the new implementation.
                 */
                event Upgraded(address implementation);
              
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is
                 * validated in the constructor.
                 */
                bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;
              
                /**
                 * @dev Contract constructor.
                 * @param _implementation Address of the initial implementation.
                 */
                constructor(address _implementation) public {
                  assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation"));
              
                  _setImplementation(_implementation);
                }
              
                /**
                 * @dev Returns the current implementation.
                 * @return Address of the current implementation
                 */
                function _implementation() internal view returns (address impl) {
                  bytes32 slot = IMPLEMENTATION_SLOT;
                  assembly {
                    impl := sload(slot)
                  }
                }
              
                /**
                 * @dev Upgrades the proxy to a new implementation.
                 * @param newImplementation Address of the new implementation.
                 */
                function _upgradeTo(address newImplementation) internal {
                  _setImplementation(newImplementation);
                  emit Upgraded(newImplementation);
                }
              
                /**
                 * @dev Sets the implementation address of the proxy.
                 * @param newImplementation Address of the new implementation.
                 */
                function _setImplementation(address newImplementation) private {
                  require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
              
                  bytes32 slot = IMPLEMENTATION_SLOT;
              
                  assembly {
                    sstore(slot, newImplementation)
                  }
                }
              }
              
              // File: zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol
              
              /**
               * @title AdminUpgradeabilityProxy
               * @dev This contract combines an upgradeability proxy with an authorization
               * mechanism for administrative tasks.
               * All external functions in this contract must be guarded by the
               * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
               * feature proposal that would enable this to be done automatically.
               */
              contract AdminUpgradeabilityProxy is UpgradeabilityProxy {
                /**
                 * @dev Emitted when the administration has been transferred.
                 * @param previousAdmin Address of the previous admin.
                 * @param newAdmin Address of the new admin.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
              
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is
                 * validated in the constructor.
                 */
                bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;
              
                /**
                 * @dev Modifier to check whether the `msg.sender` is the admin.
                 * If it is, it will run the function. Otherwise, it will delegate the call
                 * to the implementation.
                 */
                modifier ifAdmin() {
                  if (msg.sender == _admin()) {
                    _;
                  } else {
                    _fallback();
                  }
                }
              
                /**
                 * Contract constructor.
                 * It sets the `msg.sender` as the proxy administrator.
                 * @param _implementation address of the initial implementation.
                 */
                constructor(address _implementation) UpgradeabilityProxy(_implementation) public {
                  assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin"));
              
                  _setAdmin(msg.sender);
                }
              
                /**
                 * @return The address of the proxy admin.
                 */
                function admin() external view ifAdmin returns (address) {
                  return _admin();
                }
              
                /**
                 * @return The address of the implementation.
                 */
                function implementation() external view ifAdmin returns (address) {
                  return _implementation();
                }
              
                /**
                 * @dev Changes the admin of the proxy.
                 * Only the current admin can call this function.
                 * @param newAdmin Address to transfer proxy administration to.
                 */
                function changeAdmin(address newAdmin) external ifAdmin {
                  require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
                  emit AdminChanged(_admin(), newAdmin);
                  _setAdmin(newAdmin);
                }
              
                /**
                 * @dev Upgrade the backing implementation of the proxy.
                 * Only the admin can call this function.
                 * @param newImplementation Address of the new implementation.
                 */
                function upgradeTo(address newImplementation) external ifAdmin {
                  _upgradeTo(newImplementation);
                }
              
                /**
                 * @dev Upgrade the backing implementation of the proxy and call a function
                 * on the new implementation.
                 * This is useful to initialize the proxied contract.
                 * @param newImplementation Address of the new implementation.
                 * @param data Data to send as msg.data in the low level call.
                 * It should include the signature and the parameters of the function to be
                 * called, as described in
                 * https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding.
                 */
                function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin {
                  _upgradeTo(newImplementation);
                  require(address(this).call.value(msg.value)(data));
                }
              
                /**
                 * @return The admin slot.
                 */
                function _admin() internal view returns (address adm) {
                  bytes32 slot = ADMIN_SLOT;
                  assembly {
                    adm := sload(slot)
                  }
                }
              
                /**
                 * @dev Sets the address of the proxy admin.
                 * @param newAdmin Address of the new proxy admin.
                 */
                function _setAdmin(address newAdmin) internal {
                  bytes32 slot = ADMIN_SLOT;
              
                  assembly {
                    sstore(slot, newAdmin)
                  }
                }
              
                /**
                 * @dev Only fall back when the sender is not the admin.
                 */
                function _willFallback() internal {
                  require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
                  super._willFallback();
                }
              }
              
              // File: contracts/FiatTokenProxy.sol
              
              /**
              * Copyright CENTRE SECZ 2018
              *
              * Permission is hereby granted, free of charge, to any person obtaining a copy 
              * of this software and associated documentation files (the "Software"), to deal 
              * in the Software without restriction, including without limitation the rights 
              * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
              * copies of the Software, and to permit persons to whom the Software is furnished to 
              * do so, subject to the following conditions:
              *
              * The above copyright notice and this permission notice shall be included in all 
              * copies or substantial portions of the Software.
              *
              * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
              * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
              * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
              * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
              * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
              * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
              */
              
              pragma solidity ^0.4.24;
              
              
              /**
               * @title FiatTokenProxy
               * @dev This contract proxies FiatToken calls and enables FiatToken upgrades
              */ 
              contract FiatTokenProxy is AdminUpgradeabilityProxy {
                  constructor(address _implementation) public AdminUpgradeabilityProxy(_implementation) {
                  }
              }

              File 3 of 4: EscrowSrc
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.23;
              import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
              import { SafeERC20 } from "solidity-utils/contracts/libraries/SafeERC20.sol";
              import { AddressLib, Address } from "solidity-utils/contracts/libraries/AddressLib.sol";
              import { Timelocks, TimelocksLib } from "./libraries/TimelocksLib.sol";
              import { ImmutablesLib } from "./libraries/ImmutablesLib.sol";
              import { IEscrowSrc } from "./interfaces/IEscrowSrc.sol";
              import { BaseEscrow } from "./BaseEscrow.sol";
              import { Escrow } from "./Escrow.sol";
              /**
               * @title Source Escrow contract for cross-chain atomic swap.
               * @notice Contract to initially lock funds and then unlock them with verification of the secret presented.
               * @dev Funds are locked in at the time of contract deployment. For this Limit Order Protocol
               * calls the `EscrowFactory.postInteraction` function.
               * To perform any action, the caller must provide the same Immutables values used to deploy the clone contract.
               * @custom:security-contact security@1inch.io
               */
              contract EscrowSrc is Escrow, IEscrowSrc {
                  using AddressLib for Address;
                  using ImmutablesLib for Immutables;
                  using SafeERC20 for IERC20;
                  using TimelocksLib for Timelocks;
                  constructor(uint32 rescueDelay, IERC20 accessToken) BaseEscrow(rescueDelay, accessToken) {}
                  /**
                   * @notice See {IBaseEscrow-withdraw}.
                   * @dev The function works on the time interval highlighted with capital letters:
                   * ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- PUBLIC WITHDRAWAL --/--
                   * --/-- private cancellation --/-- public cancellation ----
                   */
                  function withdraw(bytes32 secret, Immutables calldata immutables)
                      external
                      onlyTaker(immutables)
                      onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcWithdrawal))
                      onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation))
                  {
                      _withdrawTo(secret, msg.sender, immutables);
                  }
                  /**
                   * @notice See {IEscrowSrc-withdrawTo}.
                   * @dev The function works on the time interval highlighted with capital letters:
                   * ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- PUBLIC WITHDRAWAL --/--
                   * --/-- private cancellation --/-- public cancellation ----
                   */
                  function withdrawTo(bytes32 secret, address target, Immutables calldata immutables)
                      external
                      onlyTaker(immutables)
                      onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcWithdrawal))
                      onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation))
                  {
                      _withdrawTo(secret, target, immutables);
                  }
                  /**
                   * @notice See {IEscrowSrc-publicWithdraw}.
                   * @dev The function works on the time interval highlighted with capital letters:
                   * ---- contract deployed --/-- finality --/-- private withdrawal --/-- PUBLIC WITHDRAWAL --/--
                   * --/-- private cancellation --/-- public cancellation ----
                   */
                  function publicWithdraw(bytes32 secret, Immutables calldata immutables)
                      external
                      onlyAccessTokenHolder()
                      onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcPublicWithdrawal))
                      onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation))
                  {
                      _withdrawTo(secret, immutables.taker.get(), immutables);
                  }
                  /**
                   * @notice See {IBaseEscrow-cancel}.
                   * @dev The function works on the time intervals highlighted with capital letters:
                   * ---- contract deployed --/-- finality --/-- private withdrawal --/-- public withdrawal --/--
                   * --/-- PRIVATE CANCELLATION --/-- PUBLIC CANCELLATION ----
                   */
                  function cancel(Immutables calldata immutables)
                      external
                      onlyTaker(immutables)
                      onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation))
                  {
                      _cancel(immutables);
                  }
                  /**
                   * @notice See {IEscrowSrc-publicCancel}.
                   * @dev The function works on the time intervals highlighted with capital letters:
                   * ---- contract deployed --/-- finality --/-- private withdrawal --/-- public withdrawal --/--
                   * --/-- private cancellation --/-- PUBLIC CANCELLATION ----
                   */
                  function publicCancel(Immutables calldata immutables)
                      external
                      onlyAccessTokenHolder()
                      onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcPublicCancellation))
                  {
                      _cancel(immutables);
                  }
                  /**
                   * @dev Transfers ERC20 tokens to the target and native tokens to the caller.
                   * @param secret The secret that unlocks the escrow.
                   * @param target The address to transfer ERC20 tokens to.
                   * @param immutables The immutable values used to deploy the clone contract.
                   */
                  function _withdrawTo(bytes32 secret, address target, Immutables calldata immutables)
                      internal
                      onlyValidImmutables(immutables)
                      onlyValidSecret(secret, immutables)
                  {
                      IERC20(immutables.token.get()).safeTransfer(target, immutables.amount);
                      _ethTransfer(msg.sender, immutables.safetyDeposit);
                      emit EscrowWithdrawal(secret);
                  }
                  /**
                   * @dev Transfers ERC20 tokens to the maker and native tokens to the caller.
                   * @param immutables The immutable values used to deploy the clone contract.
                   */
                  function _cancel(Immutables calldata immutables) internal onlyValidImmutables(immutables) {
                      IERC20(immutables.token.get()).safeTransfer(immutables.maker.get(), immutables.amount);
                      _ethTransfer(msg.sender, immutables.safetyDeposit);
                      emit EscrowCancelled();
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Interface of the ERC-20 standard as defined in the ERC.
               */
              interface IERC20 {
                  /**
                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                   * another (`to`).
                   *
                   * Note that `value` may be zero.
                   */
                  event Transfer(address indexed from, address indexed to, uint256 value);
                  /**
                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                   * a call to {approve}. `value` is the new allowance.
                   */
                  event Approval(address indexed owner, address indexed spender, uint256 value);
                  /**
                   * @dev Returns the value of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
                  /**
                   * @dev Returns the value of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
                  /**
                   * @dev Moves a `value` amount of tokens from the caller's account to `to`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address to, uint256 value) external returns (bool);
                  /**
                   * @dev Returns the remaining number of tokens that `spender` will be
                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                   * zero by default.
                   *
                   * This value changes when {approve} or {transferFrom} are called.
                   */
                  function allowance(address owner, address spender) external view returns (uint256);
                  /**
                   * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
                   * caller's tokens.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                   * that someone may use both the old and the new allowance by unfortunate
                   * transaction ordering. One possible solution to mitigate this race
                   * condition is to first reduce the spender's allowance to 0 and set the
                   * desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   *
                   * Emits an {Approval} event.
                   */
                  function approve(address spender, uint256 value) external returns (bool);
                  /**
                   * @dev Moves a `value` amount of tokens from `from` to `to` using the
                   * allowance mechanism. `value` is then deducted from the caller's
                   * allowance.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transferFrom(address from, address to, uint256 value) external returns (bool);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
              import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
              import "../interfaces/IDaiLikePermit.sol";
              import "../interfaces/IPermit2.sol";
              import "../interfaces/IERC7597Permit.sol";
              import "../interfaces/IWETH.sol";
              import "../libraries/RevertReasonForwarder.sol";
              /**
               * @title Implements efficient safe methods for ERC20 interface.
               * @notice Compared to the standard ERC20, this implementation offers several enhancements:
               * 1. more gas-efficient, providing significant savings in transaction costs.
               * 2. support for different permit implementations
               * 3. forceApprove functionality
               * 4. support for WETH deposit and withdraw
               */
              library SafeERC20 {
                  error SafeTransferFailed();
                  error SafeTransferFromFailed();
                  error ForceApproveFailed();
                  error SafeIncreaseAllowanceFailed();
                  error SafeDecreaseAllowanceFailed();
                  error SafePermitBadLength();
                  error Permit2TransferAmountTooHigh();
                  // Uniswap Permit2 address
                  address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
                  bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857;  // SafePermitBadLength.selector
                  uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
                  /**
                   * @notice Fetches the balance of a specific ERC20 token held by an account.
                   * Consumes less gas then regular `ERC20.balanceOf`.
                   * @dev Note that the implementation does not perform dirty bits cleaning, so it is the
                   * responsibility of the caller to make sure that the higher 96 bits of the `account` parameter are clean.
                   * @param token The IERC20 token contract for which the balance will be fetched.
                   * @param account The address of the account whose token balance will be fetched.
                   * @return tokenBalance The balance of the specified ERC20 token held by the account.
                   */
                  function safeBalanceOf(
                      IERC20 token,
                      address account
                  ) internal view returns(uint256 tokenBalance) {
                      bytes4 selector = IERC20.balanceOf.selector;
                      assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                          mstore(0x00, selector)
                          mstore(0x04, account)
                          let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20)
                          tokenBalance := mload(0)
                          if or(iszero(success), lt(returndatasize(), 0x20)) {
                              let ptr := mload(0x40)
                              returndatacopy(ptr, 0, returndatasize())
                              revert(ptr, returndatasize())
                          }
                      }
                  }
                  /**
                   * @notice Attempts to safely transfer tokens from one address to another.
                   * @dev If permit2 is true, uses the Permit2 standard; otherwise uses the standard ERC20 transferFrom.
                   * Either requires `true` in return data, or requires target to be smart-contract and empty return data.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
                   * @param token The IERC20 token contract from which the tokens will be transferred.
                   * @param from The address from which the tokens will be transferred.
                   * @param to The address to which the tokens will be transferred.
                   * @param amount The amount of tokens to transfer.
                   * @param permit2 If true, uses the Permit2 standard for the transfer; otherwise uses the standard ERC20 transferFrom.
                   */
                  function safeTransferFromUniversal(
                      IERC20 token,
                      address from,
                      address to,
                      uint256 amount,
                      bool permit2
                  ) internal {
                      if (permit2) {
                          safeTransferFromPermit2(token, from, to, amount);
                      } else {
                          safeTransferFrom(token, from, to, amount);
                      }
                  }
                  /**
                   * @notice Attempts to safely transfer tokens from one address to another using the ERC20 standard.
                   * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
                   * @param token The IERC20 token contract from which the tokens will be transferred.
                   * @param from The address from which the tokens will be transferred.
                   * @param to The address to which the tokens will be transferred.
                   * @param amount The amount of tokens to transfer.
                   */
                  function safeTransferFrom(
                      IERC20 token,
                      address from,
                      address to,
                      uint256 amount
                  ) internal {
                      bytes4 selector = token.transferFrom.selector;
                      bool success;
                      assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                          let data := mload(0x40)
                          mstore(data, selector)
                          mstore(add(data, 0x04), from)
                          mstore(add(data, 0x24), to)
                          mstore(add(data, 0x44), amount)
                          success := call(gas(), token, 0, data, 100, 0x0, 0x20)
                          if success {
                              switch returndatasize()
                              case 0 {
                                  success := gt(extcodesize(token), 0)
                              }
                              default {
                                  success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                              }
                          }
                      }
                      if (!success) revert SafeTransferFromFailed();
                  }
                  /**
                   * @notice Attempts to safely transfer tokens from one address to another using the Permit2 standard.
                   * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
                   * @param token The IERC20 token contract from which the tokens will be transferred.
                   * @param from The address from which the tokens will be transferred.
                   * @param to The address to which the tokens will be transferred.
                   * @param amount The amount of tokens to transfer.
                   */
                  function safeTransferFromPermit2(
                      IERC20 token,
                      address from,
                      address to,
                      uint256 amount
                  ) internal {
                      if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh();
                      bytes4 selector = IPermit2.transferFrom.selector;
                      bool success;
                      assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                          let data := mload(0x40)
                          mstore(data, selector)
                          mstore(add(data, 0x04), from)
                          mstore(add(data, 0x24), to)
                          mstore(add(data, 0x44), amount)
                          mstore(add(data, 0x64), token)
                          success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0)
                          if success {
                              success := gt(extcodesize(_PERMIT2), 0)
                          }
                      }
                      if (!success) revert SafeTransferFromFailed();
                  }
                  /**
                   * @notice Attempts to safely transfer tokens to another address.
                   * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `to` parameter are clean.
                   * @param token The IERC20 token contract from which the tokens will be transferred.
                   * @param to The address to which the tokens will be transferred.
                   * @param value The amount of tokens to transfer.
                   */
                  function safeTransfer(
                      IERC20 token,
                      address to,
                      uint256 value
                  ) internal {
                      if (!_makeCall(token, token.transfer.selector, to, value)) {
                          revert SafeTransferFailed();
                      }
                  }
                  /**
                   * @notice Attempts to approve a spender to spend a certain amount of tokens.
                   * @dev If `approve(from, to, amount)` fails, it tries to set the allowance to zero, and retries the `approve` call.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
                   * @param token The IERC20 token contract on which the call will be made.
                   * @param spender The address which will spend the funds.
                   * @param value The amount of tokens to be spent.
                   */
                  function forceApprove(
                      IERC20 token,
                      address spender,
                      uint256 value
                  ) internal {
                      if (!_makeCall(token, token.approve.selector, spender, value)) {
                          if (
                              !_makeCall(token, token.approve.selector, spender, 0) ||
                              !_makeCall(token, token.approve.selector, spender, value)
                          ) {
                              revert ForceApproveFailed();
                          }
                      }
                  }
                  /**
                   * @notice Safely increases the allowance of a spender.
                   * @dev Increases with safe math check. Checks if the increased allowance will overflow, if yes, then it reverts the transaction.
                   * Then uses `forceApprove` to increase the allowance.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
                   * @param token The IERC20 token contract on which the call will be made.
                   * @param spender The address which will spend the funds.
                   * @param value The amount of tokens to increase the allowance by.
                   */
                  function safeIncreaseAllowance(
                      IERC20 token,
                      address spender,
                      uint256 value
                  ) internal {
                      uint256 allowance = token.allowance(address(this), spender);
                      if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed();
                      forceApprove(token, spender, allowance + value);
                  }
                  /**
                   * @notice Safely decreases the allowance of a spender.
                   * @dev Decreases with safe math check. Checks if the decreased allowance will underflow, if yes, then it reverts the transaction.
                   * Then uses `forceApprove` to increase the allowance.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
                   * @param token The IERC20 token contract on which the call will be made.
                   * @param spender The address which will spend the funds.
                   * @param value The amount of tokens to decrease the allowance by.
                   */
                  function safeDecreaseAllowance(
                      IERC20 token,
                      address spender,
                      uint256 value
                  ) internal {
                      uint256 allowance = token.allowance(address(this), spender);
                      if (value > allowance) revert SafeDecreaseAllowanceFailed();
                      forceApprove(token, spender, allowance - value);
                  }
                  /**
                   * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
                   * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
                   * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
                   * @param token The IERC20 token to execute the permit function on.
                   * @param permit The permit data to be used in the function call.
                   */
                  function safePermit(IERC20 token, bytes calldata permit) internal {
                      if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert();
                  }
                  /**
                   * @notice Attempts to execute the `permit` function on the provided token with custom owner and spender parameters.
                   * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
                   * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
                   * @param token The IERC20 token to execute the permit function on.
                   * @param owner The owner of the tokens for which the permit is made.
                   * @param spender The spender allowed to spend the tokens by the permit.
                   * @param permit The permit data to be used in the function call.
                   */
                  function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal {
                      if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert();
                  }
                  /**
                   * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
                   * @dev Invokes `tryPermit` with sender as owner and contract as spender.
                   * @param token The IERC20 token to execute the permit function on.
                   * @param permit The permit data to be used in the function call.
                   * @return success Returns true if the permit function was successfully executed, false otherwise.
                   */
                  function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) {
                      return tryPermit(token, msg.sender, address(this), permit);
                  }
                  /**
                   * @notice The function attempts to call the permit function on a given ERC20 token.
                   * @dev The function is designed to support a variety of permit functions, namely: IERC20Permit, IDaiLikePermit, IERC7597Permit and IPermit2.
                   * It accommodates both Compact and Full formats of these permit types.
                   * Please note, it is expected that the `expiration` parameter for the compact Permit2 and the `deadline` parameter
                   * for the compact Permit are to be incremented by one before invoking this function. This approach is motivated by
                   * gas efficiency considerations; as the unlimited expiration period is likely to be the most common scenario, and
                   * zeros are cheaper to pass in terms of gas cost. Thus, callers should increment the expiration or deadline by one
                   * before invocation for optimized performance.
                   * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
                   * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
                   * @param token The address of the ERC20 token on which to call the permit function.
                   * @param owner The owner of the tokens. This address should have signed the off-chain permit.
                   * @param spender The address which will be approved for transfer of tokens.
                   * @param permit The off-chain permit data, containing different fields depending on the type of permit function.
                   * @return success A boolean indicating whether the permit call was successful.
                   */
                  function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) {
                      // load function selectors for different permit standards
                      bytes4 permitSelector = IERC20Permit.permit.selector;
                      bytes4 daiPermitSelector = IDaiLikePermit.permit.selector;
                      bytes4 permit2Selector = IPermit2.permit.selector;
                      bytes4 erc7597PermitSelector = IERC7597Permit.permit.selector;
                      assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                          let ptr := mload(0x40)
                          // Switch case for different permit lengths, indicating different permit standards
                          switch permit.length
                          // Compact IERC20Permit
                          case 100 {
                              mstore(ptr, permitSelector)     // store selector
                              mstore(add(ptr, 0x04), owner)   // store owner
                              mstore(add(ptr, 0x24), spender) // store spender
                              // Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs)
                              {  // stack too deep
                                  let deadline := shr(224, calldataload(add(permit.offset, 0x20))) // loads permit.offset 0x20..0x23
                                  let vs := calldataload(add(permit.offset, 0x44))                 // loads permit.offset 0x44..0x63
                                  calldatacopy(add(ptr, 0x44), permit.offset, 0x20)            // store value     = copy permit.offset 0x00..0x19
                                  mstore(add(ptr, 0x64), sub(deadline, 1))                     // store deadline  = deadline - 1
                                  mstore(add(ptr, 0x84), add(27, shr(255, vs)))                // store v         = most significant bit of vs + 27 (27 or 28)
                                  calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // store r         = copy permit.offset 0x24..0x43
                                  mstore(add(ptr, 0xc4), shr(1, shl(1, vs)))                   // store s         = vs without most significant bit
                              }
                              // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                              success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
                          }
                          // Compact IDaiLikePermit
                          case 72 {
                              mstore(ptr, daiPermitSelector)  // store selector
                              mstore(add(ptr, 0x04), owner)   // store owner
                              mstore(add(ptr, 0x24), spender) // store spender
                              // Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs)
                              {  // stack too deep
                                  let expiry := shr(224, calldataload(add(permit.offset, 0x04))) // loads permit.offset 0x04..0x07
                                  let vs := calldataload(add(permit.offset, 0x28))               // loads permit.offset 0x28..0x47
                                  mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) // store nonce   = copy permit.offset 0x00..0x03
                                  mstore(add(ptr, 0x64), sub(expiry, 1))                        // store expiry  = expiry - 1
                                  mstore(add(ptr, 0x84), true)                                  // store allowed = true
                                  mstore(add(ptr, 0xa4), add(27, shr(255, vs)))                 // store v       = most significant bit of vs + 27 (27 or 28)
                                  calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20)  // store r       = copy permit.offset 0x08..0x27
                                  mstore(add(ptr, 0xe4), shr(1, shl(1, vs)))                    // store s       = vs without most significant bit
                              }
                              // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                              success := call(gas(), token, 0, ptr, 0x104, 0, 0)
                          }
                          // IERC20Permit
                          case 224 {
                              mstore(ptr, permitSelector)
                              calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                              // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                              success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
                          }
                          // IDaiLikePermit
                          case 256 {
                              mstore(ptr, daiPermitSelector)
                              calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                              // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                              success := call(gas(), token, 0, ptr, 0x104, 0, 0)
                          }
                          // Compact IPermit2
                          case 96 {
                              // Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs)
                              mstore(ptr, permit2Selector)  // store selector
                              mstore(add(ptr, 0x04), owner) // store owner
                              mstore(add(ptr, 0x24), token) // store token
                              calldatacopy(add(ptr, 0x50), permit.offset, 0x14)             // store amount = copy permit.offset 0x00..0x13
                              // and(0xffffffffffff, ...) - conversion to uint48
                              mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // store expiration = ((permit.offset 0x14..0x17 - 1) & 0xffffffffffff)
                              mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // store nonce = copy permit.offset 0x18..0x1b
                              mstore(add(ptr, 0xa4), spender)                               // store spender
                              // and(0xffffffffffff, ...) - conversion to uint48
                              mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // store sigDeadline = ((permit.offset 0x1c..0x1f - 1) & 0xffffffffffff)
                              mstore(add(ptr, 0xe4), 0x100)                                 // store offset = 256
                              mstore(add(ptr, 0x104), 0x40)                                 // store length = 64
                              calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // store r      = copy permit.offset 0x20..0x3f
                              calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // store vs     = copy permit.offset 0x40..0x5f
                              // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                              success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
                          }
                          // IPermit2
                          case 352 {
                              mstore(ptr, permit2Selector)
                              calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                              // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                              success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
                          }
                          // Dynamic length
                          default {
                              mstore(ptr, erc7597PermitSelector)
                              calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                              // IERC7597Permit.permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature)
                              success := call(gas(), token, 0, ptr, add(permit.length, 4), 0, 0)
                          }
                      }
                  }
                  /**
                   * @dev Executes a low level call to a token contract, making it resistant to reversion and erroneous boolean returns.
                   * @param token The IERC20 token contract on which the call will be made.
                   * @param selector The function signature that is to be called on the token contract.
                   * @param to The address to which the token amount will be transferred.
                   * @param amount The token amount to be transferred.
                   * @return success A boolean indicating if the call was successful. Returns 'true' on success and 'false' on failure.
                   * In case of success but no returned data, validates that the contract code exists.
                   * In case of returned data, ensures that it's a boolean `true`.
                   */
                  function _makeCall(
                      IERC20 token,
                      bytes4 selector,
                      address to,
                      uint256 amount
                  ) private returns (bool success) {
                      assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                          let data := mload(0x40)
                          mstore(data, selector)
                          mstore(add(data, 0x04), to)
                          mstore(add(data, 0x24), amount)
                          success := call(gas(), token, 0, data, 0x44, 0x0, 0x20)
                          if success {
                              switch returndatasize()
                              case 0 {
                                  success := gt(extcodesize(token), 0)
                              }
                              default {
                                  success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                              }
                          }
                      }
                  }
                  /**
                   * @notice Safely deposits a specified amount of Ether into the IWETH contract. Consumes less gas then regular `IWETH.deposit`.
                   * @param weth The IWETH token contract.
                   * @param amount The amount of Ether to deposit into the IWETH contract.
                   */
                  function safeDeposit(IWETH weth, uint256 amount) internal {
                      if (amount > 0) {
                          bytes4 selector = IWETH.deposit.selector;
                          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                              mstore(0, selector)
                              if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
                                  let ptr := mload(0x40)
                                  returndatacopy(ptr, 0, returndatasize())
                                  revert(ptr, returndatasize())
                              }
                          }
                      }
                  }
                  /**
                   * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract. Consumes less gas then regular `IWETH.withdraw`.
                   * @dev Uses inline assembly to interact with the IWETH contract.
                   * @param weth The IWETH token contract.
                   * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
                   */
                  function safeWithdraw(IWETH weth, uint256 amount) internal {
                      bytes4 selector = IWETH.withdraw.selector;
                      assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
                          mstore(0, selector)
                          mstore(4, amount)
                          if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
                              let ptr := mload(0x40)
                              returndatacopy(ptr, 0, returndatasize())
                              revert(ptr, returndatasize())
                          }
                      }
                  }
                  /**
                   * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract to a specified recipient.
                   * Consumes less gas then regular `IWETH.withdraw`.
                   * @param weth The IWETH token contract.
                   * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
                   * @param to The recipient of the withdrawn Ether.
                   */
                  function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
                      safeWithdraw(weth, amount);
                      if (to != address(this)) {
                          assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
                              if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) {
                                  let ptr := mload(0x40)
                                  returndatacopy(ptr, 0, returndatasize())
                                  revert(ptr, returndatasize())
                              }
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              type Address is uint256;
              /**
              * @notice AddressLib
              * @notice Library for working with addresses encoded as uint256 values, which can include flags in the highest bits.
              */
              library AddressLib {
                  uint256 private constant _LOW_160_BIT_MASK = (1 << 160) - 1;
                  /**
                  * @notice Returns the address representation of a uint256.
                  * @param a The uint256 value to convert to an address.
                  * @return The address representation of the provided uint256 value.
                  */
                  function get(Address a) internal pure returns (address) {
                      return address(uint160(Address.unwrap(a) & _LOW_160_BIT_MASK));
                  }
                  /**
                  * @notice Checks if a given flag is set for the provided address.
                  * @param a The address to check for the flag.
                  * @param flag The flag to check for in the provided address.
                  * @return True if the provided flag is set in the address, false otherwise.
                  */
                  function getFlag(Address a, uint256 flag) internal pure returns (bool) {
                      return (Address.unwrap(a) & flag) != 0;
                  }
                  /**
                  * @notice Returns a uint32 value stored at a specific bit offset in the provided address.
                  * @param a The address containing the uint32 value.
                  * @param offset The bit offset at which the uint32 value is stored.
                  * @return The uint32 value stored in the address at the specified bit offset.
                  */
                  function getUint32(Address a, uint256 offset) internal pure returns (uint32) {
                      return uint32(Address.unwrap(a) >> offset);
                  }
                  /**
                  * @notice Returns a uint64 value stored at a specific bit offset in the provided address.
                  * @param a The address containing the uint64 value.
                  * @param offset The bit offset at which the uint64 value is stored.
                  * @return The uint64 value stored in the address at the specified bit offset.
                  */
                  function getUint64(Address a, uint256 offset) internal pure returns (uint64) {
                      return uint64(Address.unwrap(a) >> offset);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.20;
              /**
               * @dev Timelocks for the source and the destination chains plus the deployment timestamp.
               * Timelocks store the number of seconds from the time the contract is deployed to the start of a specific period.
               * For illustrative purposes, it is possible to describe timelocks by two structures:
               * struct SrcTimelocks {
               *     uint256 withdrawal;
               *     uint256 publicWithdrawal;
               *     uint256 cancellation;
               *     uint256 publicCancellation;
               * }
               *
               * struct DstTimelocks {
               *     uint256 withdrawal;
               *     uint256 publicWithdrawal;
               *     uint256 cancellation;
               * }
               *
               * withdrawal: Period when only the taker with a secret can withdraw tokens for taker (source chain) or maker (destination chain).
               * publicWithdrawal: Period when anyone with a secret can withdraw tokens for taker (source chain) or maker (destination chain).
               * cancellation: Period when escrow can only be cancelled by the taker.
               * publicCancellation: Period when escrow can be cancelled by anyone.
               *
               * @custom:security-contact security@1inch.io
               */
              type Timelocks is uint256;
              /**
               * @title Timelocks library for compact storage of timelocks in a uint256.
               */
              library TimelocksLib {
                  enum Stage {
                      SrcWithdrawal,
                      SrcPublicWithdrawal,
                      SrcCancellation,
                      SrcPublicCancellation,
                      DstWithdrawal,
                      DstPublicWithdrawal,
                      DstCancellation
                  }
                  uint256 private constant _DEPLOYED_AT_MASK = 0xffffffff00000000000000000000000000000000000000000000000000000000;
                  uint256 private constant _DEPLOYED_AT_OFFSET = 224;
                  /**
                   * @notice Sets the Escrow deployment timestamp.
                   * @param timelocks The timelocks to set the deployment timestamp to.
                   * @param value The new Escrow deployment timestamp.
                   * @return The timelocks with the deployment timestamp set.
                   */
                  function setDeployedAt(Timelocks timelocks, uint256 value) internal pure returns (Timelocks) {
                      return Timelocks.wrap((Timelocks.unwrap(timelocks) & ~uint256(_DEPLOYED_AT_MASK)) | value << _DEPLOYED_AT_OFFSET);
                  }
                  /**
                   * @notice Returns the start of the rescue period.
                   * @param timelocks The timelocks to get the rescue delay from.
                   * @return The start of the rescue period.
                   */
                  function rescueStart(Timelocks timelocks, uint256 rescueDelay) internal pure returns (uint256) {
                      unchecked {
                          return rescueDelay + (Timelocks.unwrap(timelocks) >> _DEPLOYED_AT_OFFSET);
                      }
                  }
                  /**
                   * @notice Returns the timelock value for the given stage.
                   * @param timelocks The timelocks to get the value from.
                   * @param stage The stage to get the value for.
                   * @return The timelock value for the given stage.
                   */
                  function get(Timelocks timelocks, Stage stage) internal pure returns (uint256) {
                      uint256 data = Timelocks.unwrap(timelocks);
                      uint256 bitShift = uint256(stage) * 32;
                      // The maximum uint32 value will be reached in 2106.
                      return (data >> _DEPLOYED_AT_OFFSET) + uint32(data >> bitShift);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.20;
              import { IBaseEscrow } from "../interfaces/IBaseEscrow.sol";
              /**
               * @title Library for escrow immutables.
               * @custom:security-contact security@1inch.io
               */
              library ImmutablesLib {
                  uint256 internal constant ESCROW_IMMUTABLES_SIZE = 0x100;
                  /**
                   * @notice Returns the hash of the immutables.
                   * @param immutables The immutables to hash.
                   * @return ret The computed hash.
                   */
                  function hash(IBaseEscrow.Immutables calldata immutables) internal pure returns(bytes32 ret) {
                      assembly ("memory-safe") {
                          let ptr := mload(0x40)
                          calldatacopy(ptr, immutables, ESCROW_IMMUTABLES_SIZE)
                          ret := keccak256(ptr, ESCROW_IMMUTABLES_SIZE)
                      }
                  }
                  /**
                   * @notice Returns the hash of the immutables.
                   * @param immutables The immutables to hash.
                   * @return ret The computed hash.
                   */
                  function hashMem(IBaseEscrow.Immutables memory immutables) internal pure returns(bytes32 ret) {
                      assembly ("memory-safe") {
                          ret := keccak256(immutables, ESCROW_IMMUTABLES_SIZE)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              import { IEscrow } from "./IEscrow.sol";
              /**
               * @title Source Escrow interface for cross-chain atomic swap.
               * @notice Interface implies locking funds initially and then unlocking them with verification of the secret presented.
               * @custom:security-contact security@1inch.io
               */
              interface IEscrowSrc is IEscrow {
                  /**
                   * @notice Withdraws funds to a specified target.
                   * @dev Withdrawal can only be made during the withdrawal period and with secret with hash matches the hashlock.
                   * The safety deposit is sent to the caller.
                   * @param secret The secret that unlocks the escrow.
                   * @param target The address to withdraw the funds to.
                   * @param immutables The immutables of the escrow contract.
                   */
                  function withdrawTo(bytes32 secret, address target, IEscrow.Immutables calldata immutables) external;
                  /**
                   * @notice Withdraws funds to the taker.
                   * @dev Withdrawal can only be made during the public withdrawal period and with secret with hash matches the hashlock.
                   * @param secret The secret that unlocks the escrow.
                   * @param immutables The immutables of the escrow contract.
                   */
                  function publicWithdraw(bytes32 secret, Immutables calldata immutables) external;
                  /**
                   * @notice Cancels the escrow and returns tokens to the maker.
                   * @dev The escrow can only be cancelled during the public cancellation period.
                   * The safety deposit is sent to the caller.
                   * @param immutables The immutables of the escrow contract.
                   */
                  function publicCancel(IEscrow.Immutables calldata immutables) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.23;
              import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
              import { AddressLib, Address } from "solidity-utils/contracts/libraries/AddressLib.sol";
              import { SafeERC20 } from "solidity-utils/contracts/libraries/SafeERC20.sol";
              import { ImmutablesLib } from "./libraries/ImmutablesLib.sol";
              import { Timelocks, TimelocksLib } from "./libraries/TimelocksLib.sol";
              import { IBaseEscrow } from "./interfaces/IBaseEscrow.sol";
              /**
               * @title Base abstract Escrow contract for cross-chain atomic swap.
               * @dev {IBaseEscrow-withdraw}, {IBaseEscrow-cancel} and _validateImmutables functions must be implemented in the derived contracts.
               * @custom:security-contact security@1inch.io
               */
              abstract contract BaseEscrow is IBaseEscrow {
                  using AddressLib for Address;
                  using SafeERC20 for IERC20;
                  using TimelocksLib for Timelocks;
                  using ImmutablesLib for Immutables;
                  // Token that is used to access public withdraw or cancel functions.
                  IERC20 private immutable _ACCESS_TOKEN;
                  /// @notice See {IBaseEscrow-RESCUE_DELAY}.
                  uint256 public immutable RESCUE_DELAY;
                  /// @notice See {IBaseEscrow-FACTORY}.
                  address public immutable FACTORY = msg.sender;
                  constructor(uint32 rescueDelay, IERC20 accessToken) {
                      RESCUE_DELAY = rescueDelay;
                      _ACCESS_TOKEN = accessToken;
                  }
                  modifier onlyTaker(Immutables calldata immutables) {
                      if (msg.sender != immutables.taker.get()) revert InvalidCaller();
                      _;
                  }
                  modifier onlyValidImmutables(Immutables calldata immutables) virtual {
                      _validateImmutables(immutables);
                      _;
                  }
                  modifier onlyValidSecret(bytes32 secret, Immutables calldata immutables) {
                      if (_keccakBytes32(secret) != immutables.hashlock) revert InvalidSecret();
                      _;
                  }
                  modifier onlyAfter(uint256 start) {
                      if (block.timestamp < start) revert InvalidTime();
                      _;
                  }
                  modifier onlyBefore(uint256 stop) {
                      if (block.timestamp >= stop) revert InvalidTime();
                      _;
                  }
                  modifier onlyAccessTokenHolder() {
                      if (_ACCESS_TOKEN.balanceOf(msg.sender) == 0) revert InvalidCaller();
                      _;
                  }
                  /**
                   * @notice See {IBaseEscrow-rescueFunds}.
                   */
                  function rescueFunds(address token, uint256 amount, Immutables calldata immutables)
                      external
                      onlyTaker(immutables)
                      onlyValidImmutables(immutables)
                      onlyAfter(immutables.timelocks.rescueStart(RESCUE_DELAY))
                  {
                      _uniTransfer(token, msg.sender, amount);
                      emit FundsRescued(token, amount);
                  }
                  /**
                   * @dev Transfers ERC20 or native tokens to the recipient.
                   */
                  function _uniTransfer(address token, address to, uint256 amount) internal {
                      if (token == address(0)) {
                          _ethTransfer(to, amount);
                      } else {
                          IERC20(token).safeTransfer(to, amount);
                      }
                  }
                  /**
                   * @dev Transfers native tokens to the recipient.
                   */
                  function _ethTransfer(address to, uint256 amount) internal {
                      (bool success,) = to.call{ value: amount }("");
                      if (!success) revert NativeTokenSendingFailure();
                  }
                  /**
                   * @dev Should verify that the computed escrow address matches the address of this contract.
                   */
                  function _validateImmutables(Immutables calldata immutables) internal view virtual;
                  /**
                   * @dev Computes the Keccak-256 hash of the secret.
                   * @param secret The secret that unlocks the escrow.
                   * @return ret The computed hash.
                   */
                  function _keccakBytes32(bytes32 secret) private pure returns (bytes32 ret) {
                      assembly ("memory-safe") {
                          mstore(0, secret)
                          ret := keccak256(0, 0x20)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.23;
              import { Create2 } from "openzeppelin-contracts/contracts/utils/Create2.sol";
              import { ImmutablesLib } from "./libraries/ImmutablesLib.sol";
              import { ProxyHashLib } from "./libraries/ProxyHashLib.sol";
              import { IEscrow } from "./interfaces/IEscrow.sol";
              import { BaseEscrow } from "./BaseEscrow.sol";
              /**
               * @title Abstract Escrow contract for cross-chain atomic swap.
               * @dev {IBaseEscrow-withdraw} and {IBaseEscrow-cancel} functions must be implemented in the derived contracts.
               * @custom:security-contact security@1inch.io
               */
              abstract contract Escrow is BaseEscrow, IEscrow {
                  using ImmutablesLib for Immutables;
                  /// @notice See {IEscrow-PROXY_BYTECODE_HASH}.
                  bytes32 public immutable PROXY_BYTECODE_HASH = ProxyHashLib.computeProxyBytecodeHash(address(this));
                  /**
                   * @dev Verifies that the computed escrow address matches the address of this contract.
                   */
                  function _validateImmutables(Immutables calldata immutables) internal view virtual override {
                      bytes32 salt = immutables.hash();
                      if (Create2.computeAddress(salt, PROXY_BYTECODE_HASH, FACTORY) != address(this)) {
                          revert InvalidImmutables();
                      }
                  }
              }
              // 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 ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
               * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
               *
               * Adds the {permit} method, which can be used to change an account's ERC-20 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
              pragma solidity ^0.8.0;
              /**
               * @title IDaiLikePermit
               * @dev Interface for Dai-like permit function allowing token spending via signatures.
               */
              interface IDaiLikePermit {
                  /**
                   * @notice Approves spending of tokens via off-chain signatures.
                   * @param holder Token holder's address.
                   * @param spender Spender's address.
                   * @param nonce Current nonce of the holder.
                   * @param expiry Time when the permit expires.
                   * @param allowed True to allow, false to disallow spending.
                   * @param v, r, s Signature components.
                   */
                  function permit(
                      address holder,
                      address spender,
                      uint256 nonce,
                      uint256 expiry,
                      bool allowed,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              /**
               * @title IPermit2
               * @dev Interface for a flexible permit system that extends ERC20 tokens to support permits in tokens lacking native permit functionality.
               */
              interface IPermit2 {
                  /**
                   * @dev Struct for holding permit details.
                   * @param token ERC20 token address for which the permit is issued.
                   * @param amount The maximum amount allowed to spend.
                   * @param expiration Timestamp until which the permit is valid.
                   * @param nonce An incrementing value for each signature, unique per owner, token, and spender.
                   */
                  struct PermitDetails {
                      address token;
                      uint160 amount;
                      uint48 expiration;
                      uint48 nonce;
                  }
                  /**
                   * @dev Struct for a single token allowance permit.
                   * @param details Permit details including token, amount, expiration, and nonce.
                   * @param spender Address authorized to spend the tokens.
                   * @param sigDeadline Deadline for the permit signature, ensuring timeliness of the permit.
                   */
                  struct PermitSingle {
                      PermitDetails details;
                      address spender;
                      uint256 sigDeadline;
                  }
                  /**
                   * @dev Struct for packed allowance data to optimize storage.
                   * @param amount Amount allowed.
                   * @param expiration Permission expiry timestamp.
                   * @param nonce Unique incrementing value for tracking allowances.
                   */
                  struct PackedAllowance {
                      uint160 amount;
                      uint48 expiration;
                      uint48 nonce;
                  }
                  /**
                   * @notice Executes a token transfer from one address to another.
                   * @param user The token owner's address.
                   * @param spender The address authorized to spend the tokens.
                   * @param amount The amount of tokens to transfer.
                   * @param token The address of the token being transferred.
                   */
                  function transferFrom(address user, address spender, uint160 amount, address token) external;
                  /**
                   * @notice Issues a permit for spending tokens via a signed authorization.
                   * @param owner The token owner's address.
                   * @param permitSingle Struct containing the permit details.
                   * @param signature The signature proving the owner authorized the permit.
                   */
                  function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
                  /**
                   * @notice Retrieves the allowance details between a token owner and spender.
                   * @param user The token owner's address.
                   * @param token The token address.
                   * @param spender The spender's address.
                   * @return The packed allowance details.
                   */
                  function allowance(address user, address token, address spender) external view returns (PackedAllowance memory);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              /**
               * @title IERC7597Permit
               * @dev A new extension for ERC-2612 permit, which has already been added to USDC v2.2.
               */
              interface IERC7597Permit {
                  /**
                   * @notice Update allowance with a signed permit.
                   * @dev Signature bytes can be used for both EOA wallets and contract wallets.
                   * @param owner Token owner's address (Authorizer).
                   * @param spender Spender's address.
                   * @param value Amount of allowance.
                   * @param deadline The time at which the signature expires (unixtime).
                   * @param signature Unstructured bytes signature signed by an EOA wallet or a contract wallet.
                   */
                  function permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      bytes memory signature
                  ) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
              /**
               * @title IWETH
               * @dev Interface for wrapper as WETH-like token.
               */
              interface IWETH is IERC20 {
                  /**
                   * @notice Emitted when Ether is deposited to get wrapper tokens.
                   */
                  event Deposit(address indexed dst, uint256 wad);
                  /**
                   * @notice Emitted when wrapper tokens is withdrawn as Ether.
                   */
                  event Withdrawal(address indexed src, uint256 wad);
                  /**
                   * @notice Deposit Ether to get wrapper tokens.
                   */
                  function deposit() external payable;
                  /**
                   * @notice Withdraw wrapped tokens as Ether.
                   * @param amount Amount of wrapped tokens to withdraw.
                   */
                  function withdraw(uint256 amount) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              /**
               * @title RevertReasonForwarder
               * @notice Provides utilities for forwarding and retrieving revert reasons from failed external calls.
               */
              library RevertReasonForwarder {
                  /**
                   * @dev Forwards the revert reason from the latest external call.
                   * This method allows propagating the revert reason of a failed external call to the caller.
                   */
                  function reRevert() internal pure {
                      // bubble up revert reason from latest external call
                      assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                          let ptr := mload(0x40)
                          returndatacopy(ptr, 0, returndatasize())
                          revert(ptr, returndatasize())
                      }
                  }
                  /**
                   * @dev Retrieves the revert reason from the latest external call.
                   * This method enables capturing the revert reason of a failed external call for inspection or processing.
                   * @return reason The latest external call revert reason.
                   */
                  function reReason() internal pure returns (bytes memory reason) {
                      assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                          reason := mload(0x40)
                          let length := returndatasize()
                          mstore(reason, length)
                          returndatacopy(add(reason, 0x20), 0, length)
                          mstore(0x40, add(reason, add(0x20, length)))
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              import { Address } from "solidity-utils/contracts/libraries/AddressLib.sol";
              import { Timelocks } from "../libraries/TimelocksLib.sol";
              /**
               * @title Base Escrow interface for cross-chain atomic swap.
               * @notice Interface implies locking funds initially and then unlocking them with verification of the secret presented.
               * @custom:security-contact security@1inch.io
               */
              interface IBaseEscrow {
                  struct Immutables {
                      bytes32 orderHash;
                      bytes32 hashlock;  // Hash of the secret.
                      Address maker;
                      Address taker;
                      Address token;
                      uint256 amount;
                      uint256 safetyDeposit;
                      Timelocks timelocks;
                  }
                  /**
                   * @notice Emitted on escrow cancellation.
                   */
                  event EscrowCancelled();
                  /**
                   * @notice Emitted when funds are rescued.
                   * @param token The address of the token rescued. Zero address for native token.
                   * @param amount The amount of tokens rescued.
                   */
                  event FundsRescued(address token, uint256 amount);
                  /**
                   * @notice Emitted on successful withdrawal.
                   * @param secret The secret that unlocks the escrow.
                   */
                  event EscrowWithdrawal(bytes32 secret);
                  error InvalidCaller();
                  error InvalidImmutables();
                  error InvalidSecret();
                  error InvalidTime();
                  error NativeTokenSendingFailure();
                  /* solhint-disable func-name-mixedcase */
                  /// @notice Returns the delay for rescuing funds from the escrow.
                  function RESCUE_DELAY() external view returns (uint256);
                  /// @notice Returns the address of the factory that created the escrow.
                  function FACTORY() external view returns (address);
                  /* solhint-enable func-name-mixedcase */
                  /**
                   * @notice Withdraws funds to a predetermined recipient.
                   * @dev Withdrawal can only be made during the withdrawal period and with secret with hash matches the hashlock.
                   * The safety deposit is sent to the caller.
                   * @param secret The secret that unlocks the escrow.
                   * @param immutables The immutables of the escrow contract.
                   */
                  function withdraw(bytes32 secret, Immutables calldata immutables) external;
                  /**
                   * @notice Cancels the escrow and returns tokens to a predetermined recipient.
                   * @dev The escrow can only be cancelled during the cancellation period.
                   * The safety deposit is sent to the caller.
                   * @param immutables The immutables of the escrow contract.
                   */
                  function cancel(Immutables calldata immutables) external;
                  /**
                   * @notice Rescues funds from the escrow.
                   * @dev Funds can only be rescued by the taker after the rescue delay.
                   * @param token The address of the token to rescue. Zero address for native token.
                   * @param amount The amount of tokens to rescue.
                   * @param immutables The immutables of the escrow contract.
                   */
                  function rescueFunds(address token, uint256 amount, Immutables calldata immutables) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.0;
              import { IBaseEscrow } from "./IBaseEscrow.sol";
              /**
               * @title Escrow interface for cross-chain atomic swap.
               * @notice Interface implies locking funds initially and then unlocking them with verification of the secret presented.
               * @custom:security-contact security@1inch.io
               */
              interface IEscrow is IBaseEscrow {
                  /// @notice Returns the bytecode hash of the proxy contract.
                  function PROXY_BYTECODE_HASH() external view returns (bytes32); // solhint-disable-line func-name-mixedcase
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/Create2.sol)
              pragma solidity ^0.8.20;
              import {Errors} from "./Errors.sol";
              /**
               * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
               * `CREATE2` can be used to compute in advance the address where a smart
               * contract will be deployed, which allows for interesting new mechanisms known
               * as 'counterfactual interactions'.
               *
               * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
               * information.
               */
              library Create2 {
                  /**
                   * @dev There's no code to deploy.
                   */
                  error Create2EmptyBytecode();
                  /**
                   * @dev Deploys a contract using `CREATE2`. The address where the contract
                   * will be deployed can be known in advance via {computeAddress}.
                   *
                   * The bytecode for a contract can be obtained from Solidity with
                   * `type(contractName).creationCode`.
                   *
                   * Requirements:
                   *
                   * - `bytecode` must not be empty.
                   * - `salt` must have not been used for `bytecode` already.
                   * - the factory must have a balance of at least `amount`.
                   * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
                   */
                  function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
                      if (address(this).balance < amount) {
                          revert Errors.InsufficientBalance(address(this).balance, amount);
                      }
                      if (bytecode.length == 0) {
                          revert Create2EmptyBytecode();
                      }
                      /// @solidity memory-safe-assembly
                      assembly {
                          addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
                      }
                      if (addr == address(0)) {
                          revert Errors.FailedDeployment();
                      }
                  }
                  /**
                   * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
                   * `bytecodeHash` or `salt` will result in a new destination address.
                   */
                  function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
                      return computeAddress(salt, bytecodeHash, address(this));
                  }
                  /**
                   * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
                   * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
                   */
                  function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          let ptr := mload(0x40) // Get free memory pointer
                          // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
                          // |-------------------|---------------------------------------------------------------------------|
                          // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
                          // | salt              |                                      BBBBBBBBBBBBB...BB                   |
                          // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
                          // | 0xFF              |            FF                                                             |
                          // |-------------------|---------------------------------------------------------------------------|
                          // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
                          // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
                          mstore(add(ptr, 0x40), bytecodeHash)
                          mstore(add(ptr, 0x20), salt)
                          mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
                          let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
                          mstore8(start, 0xff)
                          addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.20;
              /**
               * @title Library to compute the hash of the proxy bytecode.
               * @custom:security-contact security@1inch.io
               */
              library ProxyHashLib {
                  /**
                   * @notice Returns the hash of the proxy bytecode concatenated with the implementation address.
                   * @param implementation The address of the contract to clone.
                   * @return bytecodeHash The hash of the resulting bytecode.
                   */
                  function computeProxyBytecodeHash(address implementation) internal pure returns (bytes32 bytecodeHash) {
                      assembly ("memory-safe") {
                          // Stores the bytecode after address
                          mstore(0x20, 0x5af43d82803e903d91602b57fd5bf3)
                          // implementation address
                          mstore(0x11, implementation)
                          // Packs the first 3 bytes of the `implementation` address with the bytecode before the address.
                          mstore(0x00, or(shr(0x88, implementation), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
                          bytecodeHash := keccak256(0x09, 0x37)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.20;
              /**
               * @dev Collection of common custom errors used in multiple contracts
               *
               * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
               * It is recommended to avoid relying on the error API for critical functionality.
               */
              library Errors {
                  /**
                   * @dev The ETH balance of the account is not enough to perform the operation.
                   */
                  error InsufficientBalance(uint256 balance, uint256 needed);
                  /**
                   * @dev A call to an address target failed. The target may have reverted.
                   */
                  error FailedCall();
                  /**
                   * @dev The deployment failed.
                   */
                  error FailedDeployment();
              }
              

              File 4 of 4: FiatTokenV2_2
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { EIP712Domain } from "./EIP712Domain.sol"; // solhint-disable-line no-unused-import
              import { Blacklistable } from "../v1/Blacklistable.sol"; // solhint-disable-line no-unused-import
              import { FiatTokenV1 } from "../v1/FiatTokenV1.sol"; // solhint-disable-line no-unused-import
              import { FiatTokenV2 } from "./FiatTokenV2.sol"; // solhint-disable-line no-unused-import
              import { FiatTokenV2_1 } from "./FiatTokenV2_1.sol";
              import { EIP712 } from "../util/EIP712.sol";
              // solhint-disable func-name-mixedcase
              /**
               * @title FiatToken V2.2
               * @notice ERC20 Token backed by fiat reserves, version 2.2
               */
              contract FiatTokenV2_2 is FiatTokenV2_1 {
                  /**
                   * @notice Initialize v2.2
                   * @param accountsToBlacklist   A list of accounts to migrate from the old blacklist
                   * @param newSymbol             New token symbol
                   * data structure to the new blacklist data structure.
                   */
                  function initializeV2_2(
                      address[] calldata accountsToBlacklist,
                      string calldata newSymbol
                  ) external {
                      // solhint-disable-next-line reason-string
                      require(_initializedVersion == 2);
                      // Update fiat token symbol
                      symbol = newSymbol;
                      // Add previously blacklisted accounts to the new blacklist data structure
                      // and remove them from the old blacklist data structure.
                      for (uint256 i = 0; i < accountsToBlacklist.length; i++) {
                          require(
                              _deprecatedBlacklisted[accountsToBlacklist[i]],
                              "FiatTokenV2_2: Blacklisting previously unblacklisted account!"
                          );
                          _blacklist(accountsToBlacklist[i]);
                          delete _deprecatedBlacklisted[accountsToBlacklist[i]];
                      }
                      _blacklist(address(this));
                      delete _deprecatedBlacklisted[address(this)];
                      _initializedVersion = 3;
                  }
                  /**
                   * @dev Internal function to get the current chain id.
                   * @return The current chain id.
                   */
                  function _chainId() internal virtual view returns (uint256) {
                      uint256 chainId;
                      assembly {
                          chainId := chainid()
                      }
                      return chainId;
                  }
                  /**
                   * @inheritdoc EIP712Domain
                   */
                  function _domainSeparator() internal override view returns (bytes32) {
                      return EIP712.makeDomainSeparator(name, "2", _chainId());
                  }
                  /**
                   * @notice Update allowance with a signed permit
                   * @dev EOA wallet signatures should be packed in the order of r, s, v.
                   * @param owner       Token owner's address (Authorizer)
                   * @param spender     Spender's address
                   * @param value       Amount of allowance
                   * @param deadline    The time at which the signature expires (unix time), or max uint256 value to signal no expiration
                   * @param signature   Signature bytes signed by an EOA wallet or a contract wallet
                   */
                  function permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      bytes memory signature
                  ) external whenNotPaused {
                      _permit(owner, spender, value, deadline, signature);
                  }
                  /**
                   * @notice Execute a transfer with a signed authorization
                   * @dev EOA wallet signatures should be packed in the order of r, s, v.
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param signature     Signature bytes signed by an EOA wallet or a contract wallet
                   */
                  function transferWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      bytes memory signature
                  ) external whenNotPaused notBlacklisted(from) notBlacklisted(to) {
                      _transferWithAuthorization(
                          from,
                          to,
                          value,
                          validAfter,
                          validBefore,
                          nonce,
                          signature
                      );
                  }
                  /**
                   * @notice Receive a transfer with a signed authorization from the payer
                   * @dev This has an additional check to ensure that the payee's address
                   * matches the caller of this function to prevent front-running attacks.
                   * EOA wallet signatures should be packed in the order of r, s, v.
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param signature     Signature bytes signed by an EOA wallet or a contract wallet
                   */
                  function receiveWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      bytes memory signature
                  ) external whenNotPaused notBlacklisted(from) notBlacklisted(to) {
                      _receiveWithAuthorization(
                          from,
                          to,
                          value,
                          validAfter,
                          validBefore,
                          nonce,
                          signature
                      );
                  }
                  /**
                   * @notice Attempt to cancel an authorization
                   * @dev Works only if the authorization is not yet used.
                   * EOA wallet signatures should be packed in the order of r, s, v.
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   * @param signature     Signature bytes signed by an EOA wallet or a contract wallet
                   */
                  function cancelAuthorization(
                      address authorizer,
                      bytes32 nonce,
                      bytes memory signature
                  ) external whenNotPaused {
                      _cancelAuthorization(authorizer, nonce, signature);
                  }
                  /**
                   * @dev Helper method that sets the blacklist state of an account on balanceAndBlacklistStates.
                   * If _shouldBlacklist is true, we apply a (1 << 255) bitmask with an OR operation on the
                   * account's balanceAndBlacklistState. This flips the high bit for the account to 1,
                   * indicating that the account is blacklisted.
                   *
                   * If _shouldBlacklist if false, we reset the account's balanceAndBlacklistStates to their
                   * balances. This clears the high bit for the account, indicating that the account is unblacklisted.
                   * @param _account         The address of the account.
                   * @param _shouldBlacklist True if the account should be blacklisted, false if the account should be unblacklisted.
                   */
                  function _setBlacklistState(address _account, bool _shouldBlacklist)
                      internal
                      override
                  {
                      balanceAndBlacklistStates[_account] = _shouldBlacklist
                          ? balanceAndBlacklistStates[_account] | (1 << 255)
                          : _balanceOf(_account);
                  }
                  /**
                   * @dev Helper method that sets the balance of an account on balanceAndBlacklistStates.
                   * Since balances are stored in the last 255 bits of the balanceAndBlacklistStates value,
                   * we need to ensure that the updated balance does not exceed (2^255 - 1).
                   * Since blacklisted accounts' balances cannot be updated, the method will also
                   * revert if the account is blacklisted
                   * @param _account The address of the account.
                   * @param _balance The new fiat token balance of the account (max: (2^255 - 1)).
                   */
                  function _setBalance(address _account, uint256 _balance) internal override {
                      require(
                          _balance <= ((1 << 255) - 1),
                          "FiatTokenV2_2: Balance exceeds (2^255 - 1)"
                      );
                      require(
                          !_isBlacklisted(_account),
                          "FiatTokenV2_2: Account is blacklisted"
                      );
                      balanceAndBlacklistStates[_account] = _balance;
                  }
                  /**
                   * @inheritdoc Blacklistable
                   */
                  function _isBlacklisted(address _account)
                      internal
                      override
                      view
                      returns (bool)
                  {
                      return balanceAndBlacklistStates[_account] >> 255 == 1;
                  }
                  /**
                   * @dev Helper method to obtain the balance of an account. Since balances
                   * are stored in the last 255 bits of the balanceAndBlacklistStates value,
                   * we apply a ((1 << 255) - 1) bit bitmask with an AND operation on the
                   * balanceAndBlacklistState to obtain the balance.
                   * @param _account  The address of the account.
                   * @return          The fiat token balance of the account.
                   */
                  function _balanceOf(address _account)
                      internal
                      override
                      view
                      returns (uint256)
                  {
                      return balanceAndBlacklistStates[_account] & ((1 << 255) - 1);
                  }
                  /**
                   * @inheritdoc FiatTokenV1
                   */
                  function approve(address spender, uint256 value)
                      external
                      override
                      whenNotPaused
                      returns (bool)
                  {
                      _approve(msg.sender, spender, value);
                      return true;
                  }
                  /**
                   * @inheritdoc FiatTokenV2
                   */
                  function permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external override whenNotPaused {
                      _permit(owner, spender, value, deadline, v, r, s);
                  }
                  /**
                   * @inheritdoc FiatTokenV2
                   */
                  function increaseAllowance(address spender, uint256 increment)
                      external
                      override
                      whenNotPaused
                      returns (bool)
                  {
                      _increaseAllowance(msg.sender, spender, increment);
                      return true;
                  }
                  /**
                   * @inheritdoc FiatTokenV2
                   */
                  function decreaseAllowance(address spender, uint256 decrement)
                      external
                      override
                      whenNotPaused
                      returns (bool)
                  {
                      _decreaseAllowance(msg.sender, spender, decrement);
                      return true;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.2 <0.8.0;
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain`call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0, errorMessage);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      require(isContract(target), "Address: call to non-contract");
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: value }(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      return functionStaticCall(target, data, "Address: low-level static call failed");
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                      require(isContract(target), "Address: static call to non-contract");
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      require(isContract(target), "Address: delegate call to non-contract");
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
                  function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                      if (success) {
                          return returndata;
                      } else {
                          // Look for revert reason and bubble it up if present
                          if (returndata.length > 0) {
                              // The easiest way to bubble the revert reason is using memory via assembly
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <0.8.0;
              import "./IERC20.sol";
              import "../../math/SafeMath.sol";
              import "../../utils/Address.sol";
              /**
               * @title SafeERC20
               * @dev Wrappers around ERC20 operations that throw on failure (when the token
               * contract returns false). Tokens that return no value (and instead revert or
               * throw on failure) are also supported, non-reverting calls are assumed to be
               * successful.
               * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
               * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
               */
              library SafeERC20 {
                  using SafeMath for uint256;
                  using Address for address;
                  function safeTransfer(IERC20 token, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                  }
                  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                  }
                  /**
                   * @dev Deprecated. This function has issues similar to the ones found in
                   * {IERC20-approve}, and its usage is discouraged.
                   *
                   * Whenever possible, use {safeIncreaseAllowance} and
                   * {safeDecreaseAllowance} instead.
                   */
                  function safeApprove(IERC20 token, address spender, uint256 value) internal {
                      // safeApprove should only be called when setting an initial allowance,
                      // or when resetting it to zero. To increase and decrease it, use
                      // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                      // solhint-disable-next-line max-line-length
                      require((value == 0) || (token.allowance(address(this), spender) == 0),
                          "SafeERC20: approve from non-zero to non-zero allowance"
                      );
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                  }
                  function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).add(value);
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
                  /**
                   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                   * on the return value: the return value is optional (but if data is returned, it must not be false).
                   * @param token The token targeted by the call.
                   * @param data The call data (encoded using abi.encode or one of its variants).
                   */
                  function _callOptionalReturn(IERC20 token, bytes memory data) private {
                      // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                      // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                      // the target address contains contract code and also asserts for success in the low-level call.
                      bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                      if (returndata.length > 0) { // Return data is optional
                          // solhint-disable-next-line max-line-length
                          require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <0.8.0;
              /**
               * @dev Interface of the ERC20 standard as defined in the EIP.
               */
              interface IERC20 {
                  /**
                   * @dev Returns the amount of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
                  /**
                   * @dev Returns the amount of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
                  /**
                   * @dev Moves `amount` tokens from the caller's account to `recipient`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address recipient, uint256 amount) external returns (bool);
                  /**
                   * @dev Returns the remaining number of tokens that `spender` will be
                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                   * zero by default.
                   *
                   * This value changes when {approve} or {transferFrom} are called.
                   */
                  function allowance(address owner, address spender) external view returns (uint256);
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                   * that someone may use both the old and the new allowance by unfortunate
                   * transaction ordering. One possible solution to mitigate this race
                   * condition is to first reduce the spender's allowance to 0 and set the
                   * desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   *
                   * Emits an {Approval} event.
                   */
                  function approve(address spender, uint256 amount) external returns (bool);
                  /**
                   * @dev Moves `amount` tokens from `sender` to `recipient` using the
                   * allowance mechanism. `amount` is then deducted from the caller's
                   * allowance.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
                  /**
                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                   * another (`to`).
                   *
                   * Note that `value` may be zero.
                   */
                  event Transfer(address indexed from, address indexed to, uint256 value);
                  /**
                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                   * a call to {approve}. `value` is the new allowance.
                   */
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <0.8.0;
              /**
               * @dev Wrappers over Solidity's arithmetic operations with added overflow
               * checks.
               *
               * Arithmetic operations in Solidity wrap on overflow. This can easily result
               * in bugs, because programmers usually assume that an overflow raises an
               * error, which is the standard behavior in high level programming languages.
               * `SafeMath` restores this intuition by reverting the transaction when an
               * operation overflows.
               *
               * Using this library instead of the unchecked operations eliminates an entire
               * class of bugs, so it's recommended to use it always.
               */
              library SafeMath {
                  /**
                   * @dev Returns the addition of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      uint256 c = a + b;
                      if (c < a) return (false, 0);
                      return (true, c);
                  }
                  /**
                   * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b > a) return (false, 0);
                      return (true, a - b);
                  }
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                      if (a == 0) return (true, 0);
                      uint256 c = a * b;
                      if (c / a != b) return (false, 0);
                      return (true, c);
                  }
                  /**
                   * @dev Returns the division of two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a / b);
                  }
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a % b);
                  }
                  /**
                   * @dev Returns the addition of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `+` operator.
                   *
                   * Requirements:
                   *
                   * - Addition cannot overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a, "SafeMath: addition overflow");
                      return c;
                  }
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting on
                   * overflow (when the result is negative).
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a, "SafeMath: subtraction overflow");
                      return a - b;
                  }
                  /**
                   * @dev Returns the multiplication of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `*` operator.
                   *
                   * Requirements:
                   *
                   * - Multiplication cannot overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      if (a == 0) return 0;
                      uint256 c = a * b;
                      require(c / a == b, "SafeMath: multiplication overflow");
                      return c;
                  }
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: division by zero");
                      return a / b;
                  }
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting when dividing by zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: modulo by zero");
                      return a % b;
                  }
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                   * overflow (when the result is negative).
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {trySub}.
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b <= a, errorMessage);
                      return a - b;
                  }
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                   * division by zero. The result is rounded towards zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryDiv}.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a / b;
                  }
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting with custom message when dividing by zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryMod}.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a % b;
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { FiatTokenV2 } from "./FiatTokenV2.sol";
              // solhint-disable func-name-mixedcase
              /**
               * @title FiatToken V2.1
               * @notice ERC20 Token backed by fiat reserves, version 2.1
               */
              contract FiatTokenV2_1 is FiatTokenV2 {
                  /**
                   * @notice Initialize v2.1
                   * @param lostAndFound  The address to which the locked funds are sent
                   */
                  function initializeV2_1(address lostAndFound) external {
                      // solhint-disable-next-line reason-string
                      require(_initializedVersion == 1);
                      uint256 lockedAmount = _balanceOf(address(this));
                      if (lockedAmount > 0) {
                          _transfer(address(this), lostAndFound, lockedAmount);
                      }
                      _blacklist(address(this));
                      _initializedVersion = 2;
                  }
                  /**
                   * @notice Version string for the EIP712 domain separator
                   * @return Version string
                   */
                  function version() external pure returns (string memory) {
                      return "2";
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { FiatTokenV1_1 } from "../v1.1/FiatTokenV1_1.sol";
              import { EIP712 } from "../util/EIP712.sol";
              import { EIP3009 } from "./EIP3009.sol";
              import { EIP2612 } from "./EIP2612.sol";
              /**
               * @title FiatToken V2
               * @notice ERC20 Token backed by fiat reserves, version 2
               */
              contract FiatTokenV2 is FiatTokenV1_1, EIP3009, EIP2612 {
                  uint8 internal _initializedVersion;
                  /**
                   * @notice Initialize v2
                   * @param newName   New token name
                   */
                  function initializeV2(string calldata newName) external {
                      // solhint-disable-next-line reason-string
                      require(initialized && _initializedVersion == 0);
                      name = newName;
                      _DEPRECATED_CACHED_DOMAIN_SEPARATOR = EIP712.makeDomainSeparator(
                          newName,
                          "2"
                      );
                      _initializedVersion = 1;
                  }
                  /**
                   * @notice Increase the allowance by a given increment
                   * @param spender   Spender's address
                   * @param increment Amount of increase in allowance
                   * @return True if successful
                   */
                  function increaseAllowance(address spender, uint256 increment)
                      external
                      virtual
                      whenNotPaused
                      notBlacklisted(msg.sender)
                      notBlacklisted(spender)
                      returns (bool)
                  {
                      _increaseAllowance(msg.sender, spender, increment);
                      return true;
                  }
                  /**
                   * @notice Decrease the allowance by a given decrement
                   * @param spender   Spender's address
                   * @param decrement Amount of decrease in allowance
                   * @return True if successful
                   */
                  function decreaseAllowance(address spender, uint256 decrement)
                      external
                      virtual
                      whenNotPaused
                      notBlacklisted(msg.sender)
                      notBlacklisted(spender)
                      returns (bool)
                  {
                      _decreaseAllowance(msg.sender, spender, decrement);
                      return true;
                  }
                  /**
                   * @notice Execute a transfer with a signed authorization
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param v             v of the signature
                   * @param r             r of the signature
                   * @param s             s of the signature
                   */
                  function transferWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external whenNotPaused notBlacklisted(from) notBlacklisted(to) {
                      _transferWithAuthorization(
                          from,
                          to,
                          value,
                          validAfter,
                          validBefore,
                          nonce,
                          v,
                          r,
                          s
                      );
                  }
                  /**
                   * @notice Receive a transfer with a signed authorization from the payer
                   * @dev This has an additional check to ensure that the payee's address
                   * matches the caller of this function to prevent front-running attacks.
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param v             v of the signature
                   * @param r             r of the signature
                   * @param s             s of the signature
                   */
                  function receiveWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external whenNotPaused notBlacklisted(from) notBlacklisted(to) {
                      _receiveWithAuthorization(
                          from,
                          to,
                          value,
                          validAfter,
                          validBefore,
                          nonce,
                          v,
                          r,
                          s
                      );
                  }
                  /**
                   * @notice Attempt to cancel an authorization
                   * @dev Works only if the authorization is not yet used.
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   * @param v             v of the signature
                   * @param r             r of the signature
                   * @param s             s of the signature
                   */
                  function cancelAuthorization(
                      address authorizer,
                      bytes32 nonce,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external whenNotPaused {
                      _cancelAuthorization(authorizer, nonce, v, r, s);
                  }
                  /**
                   * @notice Update allowance with a signed permit
                   * @param owner       Token owner's address (Authorizer)
                   * @param spender     Spender's address
                   * @param value       Amount of allowance
                   * @param deadline    The time at which the signature expires (unix time), or max uint256 value to signal no expiration
                   * @param v           v of the signature
                   * @param r           r of the signature
                   * @param s           s of the signature
                   */
                  function permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  )
                      external
                      virtual
                      whenNotPaused
                      notBlacklisted(owner)
                      notBlacklisted(spender)
                  {
                      _permit(owner, spender, value, deadline, v, r, s);
                  }
                  /**
                   * @dev Internal function to increase the allowance by a given increment
                   * @param owner     Token owner's address
                   * @param spender   Spender's address
                   * @param increment Amount of increase
                   */
                  function _increaseAllowance(
                      address owner,
                      address spender,
                      uint256 increment
                  ) internal override {
                      _approve(owner, spender, allowed[owner][spender].add(increment));
                  }
                  /**
                   * @dev Internal function to decrease the allowance by a given decrement
                   * @param owner     Token owner's address
                   * @param spender   Spender's address
                   * @param decrement Amount of decrease
                   */
                  function _decreaseAllowance(
                      address owner,
                      address spender,
                      uint256 decrement
                  ) internal override {
                      _approve(
                          owner,
                          spender,
                          allowed[owner][spender].sub(
                              decrement,
                              "ERC20: decreased allowance below zero"
                          )
                      );
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              // solhint-disable func-name-mixedcase
              /**
               * @title EIP712 Domain
               */
              contract EIP712Domain {
                  // was originally DOMAIN_SEPARATOR
                  // but that has been moved to a method so we can override it in V2_2+
                  bytes32 internal _DEPRECATED_CACHED_DOMAIN_SEPARATOR;
                  /**
                   * @notice Get the EIP712 Domain Separator.
                   * @return The bytes32 EIP712 domain separator.
                   */
                  function DOMAIN_SEPARATOR() external view returns (bytes32) {
                      return _domainSeparator();
                  }
                  /**
                   * @dev Internal method to get the EIP712 Domain Separator.
                   * @return The bytes32 EIP712 domain separator.
                   */
                  function _domainSeparator() internal virtual view returns (bytes32) {
                      return _DEPRECATED_CACHED_DOMAIN_SEPARATOR;
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { AbstractFiatTokenV2 } from "./AbstractFiatTokenV2.sol";
              import { EIP712Domain } from "./EIP712Domain.sol";
              import { SignatureChecker } from "../util/SignatureChecker.sol";
              import { MessageHashUtils } from "../util/MessageHashUtils.sol";
              /**
               * @title EIP-3009
               * @notice Provide internal implementation for gas-abstracted transfers
               * @dev Contracts that inherit from this must wrap these with publicly
               * accessible functions, optionally adding modifiers where necessary
               */
              abstract contract EIP3009 is AbstractFiatTokenV2, EIP712Domain {
                  // keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
                  bytes32
                      public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = 0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267;
                  // keccak256("ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
                  bytes32
                      public constant RECEIVE_WITH_AUTHORIZATION_TYPEHASH = 0xd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de8;
                  // keccak256("CancelAuthorization(address authorizer,bytes32 nonce)")
                  bytes32
                      public constant CANCEL_AUTHORIZATION_TYPEHASH = 0x158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429;
                  /**
                   * @dev authorizer address => nonce => bool (true if nonce is used)
                   */
                  mapping(address => mapping(bytes32 => bool)) private _authorizationStates;
                  event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce);
                  event AuthorizationCanceled(
                      address indexed authorizer,
                      bytes32 indexed nonce
                  );
                  /**
                   * @notice Returns the state of an authorization
                   * @dev Nonces are randomly generated 32-byte data unique to the
                   * authorizer's address
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   * @return True if the nonce is used
                   */
                  function authorizationState(address authorizer, bytes32 nonce)
                      external
                      view
                      returns (bool)
                  {
                      return _authorizationStates[authorizer][nonce];
                  }
                  /**
                   * @notice Execute a transfer with a signed authorization
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param v             v of the signature
                   * @param r             r of the signature
                   * @param s             s of the signature
                   */
                  function _transferWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) internal {
                      _transferWithAuthorization(
                          from,
                          to,
                          value,
                          validAfter,
                          validBefore,
                          nonce,
                          abi.encodePacked(r, s, v)
                      );
                  }
                  /**
                   * @notice Execute a transfer with a signed authorization
                   * @dev EOA wallet signatures should be packed in the order of r, s, v.
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param signature     Signature byte array produced by an EOA wallet or a contract wallet
                   */
                  function _transferWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      bytes memory signature
                  ) internal {
                      _requireValidAuthorization(from, nonce, validAfter, validBefore);
                      _requireValidSignature(
                          from,
                          keccak256(
                              abi.encode(
                                  TRANSFER_WITH_AUTHORIZATION_TYPEHASH,
                                  from,
                                  to,
                                  value,
                                  validAfter,
                                  validBefore,
                                  nonce
                              )
                          ),
                          signature
                      );
                      _markAuthorizationAsUsed(from, nonce);
                      _transfer(from, to, value);
                  }
                  /**
                   * @notice Receive a transfer with a signed authorization from the payer
                   * @dev This has an additional check to ensure that the payee's address
                   * matches the caller of this function to prevent front-running attacks.
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param v             v of the signature
                   * @param r             r of the signature
                   * @param s             s of the signature
                   */
                  function _receiveWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) internal {
                      _receiveWithAuthorization(
                          from,
                          to,
                          value,
                          validAfter,
                          validBefore,
                          nonce,
                          abi.encodePacked(r, s, v)
                      );
                  }
                  /**
                   * @notice Receive a transfer with a signed authorization from the payer
                   * @dev This has an additional check to ensure that the payee's address
                   * matches the caller of this function to prevent front-running attacks.
                   * EOA wallet signatures should be packed in the order of r, s, v.
                   * @param from          Payer's address (Authorizer)
                   * @param to            Payee's address
                   * @param value         Amount to be transferred
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   * @param nonce         Unique nonce
                   * @param signature     Signature byte array produced by an EOA wallet or a contract wallet
                   */
                  function _receiveWithAuthorization(
                      address from,
                      address to,
                      uint256 value,
                      uint256 validAfter,
                      uint256 validBefore,
                      bytes32 nonce,
                      bytes memory signature
                  ) internal {
                      require(to == msg.sender, "FiatTokenV2: caller must be the payee");
                      _requireValidAuthorization(from, nonce, validAfter, validBefore);
                      _requireValidSignature(
                          from,
                          keccak256(
                              abi.encode(
                                  RECEIVE_WITH_AUTHORIZATION_TYPEHASH,
                                  from,
                                  to,
                                  value,
                                  validAfter,
                                  validBefore,
                                  nonce
                              )
                          ),
                          signature
                      );
                      _markAuthorizationAsUsed(from, nonce);
                      _transfer(from, to, value);
                  }
                  /**
                   * @notice Attempt to cancel an authorization
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   * @param v             v of the signature
                   * @param r             r of the signature
                   * @param s             s of the signature
                   */
                  function _cancelAuthorization(
                      address authorizer,
                      bytes32 nonce,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) internal {
                      _cancelAuthorization(authorizer, nonce, abi.encodePacked(r, s, v));
                  }
                  /**
                   * @notice Attempt to cancel an authorization
                   * @dev EOA wallet signatures should be packed in the order of r, s, v.
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   * @param signature     Signature byte array produced by an EOA wallet or a contract wallet
                   */
                  function _cancelAuthorization(
                      address authorizer,
                      bytes32 nonce,
                      bytes memory signature
                  ) internal {
                      _requireUnusedAuthorization(authorizer, nonce);
                      _requireValidSignature(
                          authorizer,
                          keccak256(
                              abi.encode(CANCEL_AUTHORIZATION_TYPEHASH, authorizer, nonce)
                          ),
                          signature
                      );
                      _authorizationStates[authorizer][nonce] = true;
                      emit AuthorizationCanceled(authorizer, nonce);
                  }
                  /**
                   * @notice Validates that signature against input data struct
                   * @param signer        Signer's address
                   * @param dataHash      Hash of encoded data struct
                   * @param signature     Signature byte array produced by an EOA wallet or a contract wallet
                   */
                  function _requireValidSignature(
                      address signer,
                      bytes32 dataHash,
                      bytes memory signature
                  ) private view {
                      require(
                          SignatureChecker.isValidSignatureNow(
                              signer,
                              MessageHashUtils.toTypedDataHash(_domainSeparator(), dataHash),
                              signature
                          ),
                          "FiatTokenV2: invalid signature"
                      );
                  }
                  /**
                   * @notice Check that an authorization is unused
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   */
                  function _requireUnusedAuthorization(address authorizer, bytes32 nonce)
                      private
                      view
                  {
                      require(
                          !_authorizationStates[authorizer][nonce],
                          "FiatTokenV2: authorization is used or canceled"
                      );
                  }
                  /**
                   * @notice Check that authorization is valid
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   * @param validAfter    The time after which this is valid (unix time)
                   * @param validBefore   The time before which this is valid (unix time)
                   */
                  function _requireValidAuthorization(
                      address authorizer,
                      bytes32 nonce,
                      uint256 validAfter,
                      uint256 validBefore
                  ) private view {
                      require(
                          now > validAfter,
                          "FiatTokenV2: authorization is not yet valid"
                      );
                      require(now < validBefore, "FiatTokenV2: authorization is expired");
                      _requireUnusedAuthorization(authorizer, nonce);
                  }
                  /**
                   * @notice Mark an authorization as used
                   * @param authorizer    Authorizer's address
                   * @param nonce         Nonce of the authorization
                   */
                  function _markAuthorizationAsUsed(address authorizer, bytes32 nonce)
                      private
                  {
                      _authorizationStates[authorizer][nonce] = true;
                      emit AuthorizationUsed(authorizer, nonce);
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { AbstractFiatTokenV2 } from "./AbstractFiatTokenV2.sol";
              import { EIP712Domain } from "./EIP712Domain.sol";
              import { MessageHashUtils } from "../util/MessageHashUtils.sol";
              import { SignatureChecker } from "../util/SignatureChecker.sol";
              /**
               * @title EIP-2612
               * @notice Provide internal implementation for gas-abstracted approvals
               */
              abstract contract EIP2612 is AbstractFiatTokenV2, EIP712Domain {
                  // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
                  bytes32
                      public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
                  mapping(address => uint256) private _permitNonces;
                  /**
                   * @notice Nonces for permit
                   * @param owner Token owner's address (Authorizer)
                   * @return Next nonce
                   */
                  function nonces(address owner) external view returns (uint256) {
                      return _permitNonces[owner];
                  }
                  /**
                   * @notice Verify a signed approval permit and execute if valid
                   * @param owner     Token owner's address (Authorizer)
                   * @param spender   Spender's address
                   * @param value     Amount of allowance
                   * @param deadline  The time at which the signature expires (unix time), or max uint256 value to signal no expiration
                   * @param v         v of the signature
                   * @param r         r of the signature
                   * @param s         s of the signature
                   */
                  function _permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) internal {
                      _permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));
                  }
                  /**
                   * @notice Verify a signed approval permit and execute if valid
                   * @dev EOA wallet signatures should be packed in the order of r, s, v.
                   * @param owner      Token owner's address (Authorizer)
                   * @param spender    Spender's address
                   * @param value      Amount of allowance
                   * @param deadline   The time at which the signature expires (unix time), or max uint256 value to signal no expiration
                   * @param signature  Signature byte array signed by an EOA wallet or a contract wallet
                   */
                  function _permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      bytes memory signature
                  ) internal {
                      require(
                          deadline == type(uint256).max || deadline >= now,
                          "FiatTokenV2: permit is expired"
                      );
                      bytes32 typedDataHash = MessageHashUtils.toTypedDataHash(
                          _domainSeparator(),
                          keccak256(
                              abi.encode(
                                  PERMIT_TYPEHASH,
                                  owner,
                                  spender,
                                  value,
                                  _permitNonces[owner]++,
                                  deadline
                              )
                          )
                      );
                      require(
                          SignatureChecker.isValidSignatureNow(
                              owner,
                              typedDataHash,
                              signature
                          ),
                          "EIP2612: invalid signature"
                      );
                      _approve(owner, spender, value);
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { AbstractFiatTokenV1 } from "../v1/AbstractFiatTokenV1.sol";
              abstract contract AbstractFiatTokenV2 is AbstractFiatTokenV1 {
                  function _increaseAllowance(
                      address owner,
                      address spender,
                      uint256 increment
                  ) internal virtual;
                  function _decreaseAllowance(
                      address owner,
                      address spender,
                      uint256 decrement
                  ) internal virtual;
              }
              /**
               * SPDX-License-Identifier: MIT
               *
               * Copyright (c) 2016 Smart Contract Solutions, Inc.
               * Copyright (c) 2018-2020 CENTRE SECZ
               *
               * Permission is hereby granted, free of charge, to any person obtaining a copy
               * of this software and associated documentation files (the "Software"), to deal
               * in the Software without restriction, including without limitation the rights
               * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
               * copies of the Software, and to permit persons to whom the Software is
               * furnished to do so, subject to the following conditions:
               *
               * The above copyright notice and this permission notice shall be included in
               * copies or substantial portions of the Software.
               *
               * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
               * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
               * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
               * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
               * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
               * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
               * SOFTWARE.
               */
              pragma solidity 0.6.12;
              import { Ownable } from "./Ownable.sol";
              /**
               * @notice Base contract which allows children to implement an emergency stop
               * mechanism
               * @dev Forked from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/feb665136c0dae9912e08397c1a21c4af3651ef3/contracts/lifecycle/Pausable.sol
               * Modifications:
               * 1. Added pauser role, switched pause/unpause to be onlyPauser (6/14/2018)
               * 2. Removed whenNotPause/whenPaused from pause/unpause (6/14/2018)
               * 3. Removed whenPaused (6/14/2018)
               * 4. Switches ownable library to use ZeppelinOS (7/12/18)
               * 5. Remove constructor (7/13/18)
               * 6. Reformat, conform to Solidity 0.6 syntax and add error messages (5/13/20)
               * 7. Make public functions external (5/27/20)
               */
              contract Pausable is Ownable {
                  event Pause();
                  event Unpause();
                  event PauserChanged(address indexed newAddress);
                  address public pauser;
                  bool public paused = false;
                  /**
                   * @dev Modifier to make a function callable only when the contract is not paused.
                   */
                  modifier whenNotPaused() {
                      require(!paused, "Pausable: paused");
                      _;
                  }
                  /**
                   * @dev throws if called by any account other than the pauser
                   */
                  modifier onlyPauser() {
                      require(msg.sender == pauser, "Pausable: caller is not the pauser");
                      _;
                  }
                  /**
                   * @dev called by the owner to pause, triggers stopped state
                   */
                  function pause() external onlyPauser {
                      paused = true;
                      emit Pause();
                  }
                  /**
                   * @dev called by the owner to unpause, returns to normal state
                   */
                  function unpause() external onlyPauser {
                      paused = false;
                      emit Unpause();
                  }
                  /**
                   * @notice Updates the pauser address.
                   * @param _newPauser The address of the new pauser.
                   */
                  function updatePauser(address _newPauser) external onlyOwner {
                      require(
                          _newPauser != address(0),
                          "Pausable: new pauser is the zero address"
                      );
                      pauser = _newPauser;
                      emit PauserChanged(pauser);
                  }
              }
              /**
               * SPDX-License-Identifier: MIT
               *
               * Copyright (c) 2018 zOS Global Limited.
               * Copyright (c) 2018-2020 CENTRE SECZ
               *
               * Permission is hereby granted, free of charge, to any person obtaining a copy
               * of this software and associated documentation files (the "Software"), to deal
               * in the Software without restriction, including without limitation the rights
               * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
               * copies of the Software, and to permit persons to whom the Software is
               * furnished to do so, subject to the following conditions:
               *
               * The above copyright notice and this permission notice shall be included in
               * copies or substantial portions of the Software.
               *
               * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
               * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
               * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
               * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
               * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
               * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
               * SOFTWARE.
               */
              pragma solidity 0.6.12;
              /**
               * @notice The Ownable contract has an owner address, and provides basic
               * authorization control functions
               * @dev Forked from https://github.com/OpenZeppelin/openzeppelin-labs/blob/3887ab77b8adafba4a26ace002f3a684c1a3388b/upgradeability_ownership/contracts/ownership/Ownable.sol
               * Modifications:
               * 1. Consolidate OwnableStorage into this contract (7/13/18)
               * 2. Reformat, conform to Solidity 0.6 syntax, and add error messages (5/13/20)
               * 3. Make public functions external (5/27/20)
               */
              contract Ownable {
                  // Owner of the contract
                  address private _owner;
                  /**
                   * @dev Event to show ownership has been transferred
                   * @param previousOwner representing the address of the previous owner
                   * @param newOwner representing the address of the new owner
                   */
                  event OwnershipTransferred(address previousOwner, address newOwner);
                  /**
                   * @dev The constructor sets the original owner of the contract to the sender account.
                   */
                  constructor() public {
                      setOwner(msg.sender);
                  }
                  /**
                   * @dev Tells the address of the owner
                   * @return the address of the owner
                   */
                  function owner() external view returns (address) {
                      return _owner;
                  }
                  /**
                   * @dev Sets a new owner address
                   */
                  function setOwner(address newOwner) internal {
                      _owner = newOwner;
                  }
                  /**
                   * @dev Throws if called by any account other than the owner.
                   */
                  modifier onlyOwner() {
                      require(msg.sender == _owner, "Ownable: caller is not the 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) external onlyOwner {
                      require(
                          newOwner != address(0),
                          "Ownable: new owner is the zero address"
                      );
                      emit OwnershipTransferred(_owner, newOwner);
                      setOwner(newOwner);
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
              import { AbstractFiatTokenV1 } from "./AbstractFiatTokenV1.sol";
              import { Ownable } from "./Ownable.sol";
              import { Pausable } from "./Pausable.sol";
              import { Blacklistable } from "./Blacklistable.sol";
              /**
               * @title FiatToken
               * @dev ERC20 Token backed by fiat reserves
               */
              contract FiatTokenV1 is AbstractFiatTokenV1, Ownable, Pausable, Blacklistable {
                  using SafeMath for uint256;
                  string public name;
                  string public symbol;
                  uint8 public decimals;
                  string public currency;
                  address public masterMinter;
                  bool internal initialized;
                  /// @dev A mapping that stores the balance and blacklist states for a given address.
                  /// The first bit defines whether the address is blacklisted (1 if blacklisted, 0 otherwise).
                  /// The last 255 bits define the balance for the address.
                  mapping(address => uint256) internal balanceAndBlacklistStates;
                  mapping(address => mapping(address => uint256)) internal allowed;
                  uint256 internal totalSupply_ = 0;
                  mapping(address => bool) internal minters;
                  mapping(address => uint256) internal minterAllowed;
                  event Mint(address indexed minter, address indexed to, uint256 amount);
                  event Burn(address indexed burner, uint256 amount);
                  event MinterConfigured(address indexed minter, uint256 minterAllowedAmount);
                  event MinterRemoved(address indexed oldMinter);
                  event MasterMinterChanged(address indexed newMasterMinter);
                  /**
                   * @notice Initializes the fiat token contract.
                   * @param tokenName       The name of the fiat token.
                   * @param tokenSymbol     The symbol of the fiat token.
                   * @param tokenCurrency   The fiat currency that the token represents.
                   * @param tokenDecimals   The number of decimals that the token uses.
                   * @param newMasterMinter The masterMinter address for the fiat token.
                   * @param newPauser       The pauser address for the fiat token.
                   * @param newBlacklister  The blacklister address for the fiat token.
                   * @param newOwner        The owner of the fiat token.
                   */
                  function initialize(
                      string memory tokenName,
                      string memory tokenSymbol,
                      string memory tokenCurrency,
                      uint8 tokenDecimals,
                      address newMasterMinter,
                      address newPauser,
                      address newBlacklister,
                      address newOwner
                  ) public {
                      require(!initialized, "FiatToken: contract is already initialized");
                      require(
                          newMasterMinter != address(0),
                          "FiatToken: new masterMinter is the zero address"
                      );
                      require(
                          newPauser != address(0),
                          "FiatToken: new pauser is the zero address"
                      );
                      require(
                          newBlacklister != address(0),
                          "FiatToken: new blacklister is the zero address"
                      );
                      require(
                          newOwner != address(0),
                          "FiatToken: new owner is the zero address"
                      );
                      name = tokenName;
                      symbol = tokenSymbol;
                      currency = tokenCurrency;
                      decimals = tokenDecimals;
                      masterMinter = newMasterMinter;
                      pauser = newPauser;
                      blacklister = newBlacklister;
                      setOwner(newOwner);
                      initialized = true;
                  }
                  /**
                   * @dev Throws if called by any account other than a minter.
                   */
                  modifier onlyMinters() {
                      require(minters[msg.sender], "FiatToken: caller is not a minter");
                      _;
                  }
                  /**
                   * @notice Mints fiat tokens to an address.
                   * @param _to The address that will receive the minted tokens.
                   * @param _amount The amount of tokens to mint. Must be less than or equal
                   * to the minterAllowance of the caller.
                   * @return True if the operation was successful.
                   */
                  function mint(address _to, uint256 _amount)
                      external
                      whenNotPaused
                      onlyMinters
                      notBlacklisted(msg.sender)
                      notBlacklisted(_to)
                      returns (bool)
                  {
                      require(_to != address(0), "FiatToken: mint to the zero address");
                      require(_amount > 0, "FiatToken: mint amount not greater than 0");
                      uint256 mintingAllowedAmount = minterAllowed[msg.sender];
                      require(
                          _amount <= mintingAllowedAmount,
                          "FiatToken: mint amount exceeds minterAllowance"
                      );
                      totalSupply_ = totalSupply_.add(_amount);
                      _setBalance(_to, _balanceOf(_to).add(_amount));
                      minterAllowed[msg.sender] = mintingAllowedAmount.sub(_amount);
                      emit Mint(msg.sender, _to, _amount);
                      emit Transfer(address(0), _to, _amount);
                      return true;
                  }
                  /**
                   * @dev Throws if called by any account other than the masterMinter
                   */
                  modifier onlyMasterMinter() {
                      require(
                          msg.sender == masterMinter,
                          "FiatToken: caller is not the masterMinter"
                      );
                      _;
                  }
                  /**
                   * @notice Gets the minter allowance for an account.
                   * @param minter The address to check.
                   * @return The remaining minter allowance for the account.
                   */
                  function minterAllowance(address minter) external view returns (uint256) {
                      return minterAllowed[minter];
                  }
                  /**
                   * @notice Checks if an account is a minter.
                   * @param account The address to check.
                   * @return True if the account is a minter, false if the account is not a minter.
                   */
                  function isMinter(address account) external view returns (bool) {
                      return minters[account];
                  }
                  /**
                   * @notice Gets the remaining amount of fiat tokens a spender is allowed to transfer on
                   * behalf of the token owner.
                   * @param owner   The token owner's address.
                   * @param spender The spender's address.
                   * @return The remaining allowance.
                   */
                  function allowance(address owner, address spender)
                      external
                      override
                      view
                      returns (uint256)
                  {
                      return allowed[owner][spender];
                  }
                  /**
                   * @notice Gets the totalSupply of the fiat token.
                   * @return The totalSupply of the fiat token.
                   */
                  function totalSupply() external override view returns (uint256) {
                      return totalSupply_;
                  }
                  /**
                   * @notice Gets the fiat token balance of an account.
                   * @param account  The address to check.
                   * @return balance The fiat token balance of the account.
                   */
                  function balanceOf(address account)
                      external
                      override
                      view
                      returns (uint256)
                  {
                      return _balanceOf(account);
                  }
                  /**
                   * @notice Sets a fiat token allowance for a spender to spend on behalf of the caller.
                   * @param spender The spender's address.
                   * @param value   The allowance amount.
                   * @return True if the operation was successful.
                   */
                  function approve(address spender, uint256 value)
                      external
                      virtual
                      override
                      whenNotPaused
                      notBlacklisted(msg.sender)
                      notBlacklisted(spender)
                      returns (bool)
                  {
                      _approve(msg.sender, spender, value);
                      return true;
                  }
                  /**
                   * @dev Internal function to set allowance.
                   * @param owner     Token owner's address.
                   * @param spender   Spender's address.
                   * @param value     Allowance amount.
                   */
                  function _approve(
                      address owner,
                      address spender,
                      uint256 value
                  ) internal override {
                      require(owner != address(0), "ERC20: approve from the zero address");
                      require(spender != address(0), "ERC20: approve to the zero address");
                      allowed[owner][spender] = value;
                      emit Approval(owner, spender, value);
                  }
                  /**
                   * @notice Transfers tokens from an address to another by spending the caller's allowance.
                   * @dev The caller must have some fiat token allowance on the payer's tokens.
                   * @param from  Payer's address.
                   * @param to    Payee's address.
                   * @param value Transfer amount.
                   * @return True if the operation was successful.
                   */
                  function transferFrom(
                      address from,
                      address to,
                      uint256 value
                  )
                      external
                      override
                      whenNotPaused
                      notBlacklisted(msg.sender)
                      notBlacklisted(from)
                      notBlacklisted(to)
                      returns (bool)
                  {
                      require(
                          value <= allowed[from][msg.sender],
                          "ERC20: transfer amount exceeds allowance"
                      );
                      _transfer(from, to, value);
                      allowed[from][msg.sender] = allowed[from][msg.sender].sub(value);
                      return true;
                  }
                  /**
                   * @notice Transfers tokens from the caller.
                   * @param to    Payee's address.
                   * @param value Transfer amount.
                   * @return True if the operation was successful.
                   */
                  function transfer(address to, uint256 value)
                      external
                      override
                      whenNotPaused
                      notBlacklisted(msg.sender)
                      notBlacklisted(to)
                      returns (bool)
                  {
                      _transfer(msg.sender, to, value);
                      return true;
                  }
                  /**
                   * @dev Internal function to process transfers.
                   * @param from  Payer's address.
                   * @param to    Payee's address.
                   * @param value Transfer amount.
                   */
                  function _transfer(
                      address from,
                      address to,
                      uint256 value
                  ) internal override {
                      require(from != address(0), "ERC20: transfer from the zero address");
                      require(to != address(0), "ERC20: transfer to the zero address");
                      require(
                          value <= _balanceOf(from),
                          "ERC20: transfer amount exceeds balance"
                      );
                      _setBalance(from, _balanceOf(from).sub(value));
                      _setBalance(to, _balanceOf(to).add(value));
                      emit Transfer(from, to, value);
                  }
                  /**
                   * @notice Adds or updates a new minter with a mint allowance.
                   * @param minter The address of the minter.
                   * @param minterAllowedAmount The minting amount allowed for the minter.
                   * @return True if the operation was successful.
                   */
                  function configureMinter(address minter, uint256 minterAllowedAmount)
                      external
                      whenNotPaused
                      onlyMasterMinter
                      returns (bool)
                  {
                      minters[minter] = true;
                      minterAllowed[minter] = minterAllowedAmount;
                      emit MinterConfigured(minter, minterAllowedAmount);
                      return true;
                  }
                  /**
                   * @notice Removes a minter.
                   * @param minter The address of the minter to remove.
                   * @return True if the operation was successful.
                   */
                  function removeMinter(address minter)
                      external
                      onlyMasterMinter
                      returns (bool)
                  {
                      minters[minter] = false;
                      minterAllowed[minter] = 0;
                      emit MinterRemoved(minter);
                      return true;
                  }
                  /**
                   * @notice Allows a minter to burn some of its own tokens.
                   * @dev The caller must be a minter, must not be blacklisted, and the amount to burn
                   * should be less than or equal to the account's balance.
                   * @param _amount the amount of tokens to be burned.
                   */
                  function burn(uint256 _amount)
                      external
                      whenNotPaused
                      onlyMinters
                      notBlacklisted(msg.sender)
                  {
                      uint256 balance = _balanceOf(msg.sender);
                      require(_amount > 0, "FiatToken: burn amount not greater than 0");
                      require(balance >= _amount, "FiatToken: burn amount exceeds balance");
                      totalSupply_ = totalSupply_.sub(_amount);
                      _setBalance(msg.sender, balance.sub(_amount));
                      emit Burn(msg.sender, _amount);
                      emit Transfer(msg.sender, address(0), _amount);
                  }
                  /**
                   * @notice Updates the master minter address.
                   * @param _newMasterMinter The address of the new master minter.
                   */
                  function updateMasterMinter(address _newMasterMinter) external onlyOwner {
                      require(
                          _newMasterMinter != address(0),
                          "FiatToken: new masterMinter is the zero address"
                      );
                      masterMinter = _newMasterMinter;
                      emit MasterMinterChanged(masterMinter);
                  }
                  /**
                   * @inheritdoc Blacklistable
                   */
                  function _blacklist(address _account) internal override {
                      _setBlacklistState(_account, true);
                  }
                  /**
                   * @inheritdoc Blacklistable
                   */
                  function _unBlacklist(address _account) internal override {
                      _setBlacklistState(_account, false);
                  }
                  /**
                   * @dev Helper method that sets the blacklist state of an account.
                   * @param _account         The address of the account.
                   * @param _shouldBlacklist True if the account should be blacklisted, false if the account should be unblacklisted.
                   */
                  function _setBlacklistState(address _account, bool _shouldBlacklist)
                      internal
                      virtual
                  {
                      _deprecatedBlacklisted[_account] = _shouldBlacklist;
                  }
                  /**
                   * @dev Helper method that sets the balance of an account.
                   * @param _account The address of the account.
                   * @param _balance The new fiat token balance of the account.
                   */
                  function _setBalance(address _account, uint256 _balance) internal virtual {
                      balanceAndBlacklistStates[_account] = _balance;
                  }
                  /**
                   * @inheritdoc Blacklistable
                   */
                  function _isBlacklisted(address _account)
                      internal
                      virtual
                      override
                      view
                      returns (bool)
                  {
                      return _deprecatedBlacklisted[_account];
                  }
                  /**
                   * @dev Helper method to obtain the balance of an account.
                   * @param _account  The address of the account.
                   * @return          The fiat token balance of the account.
                   */
                  function _balanceOf(address _account)
                      internal
                      virtual
                      view
                      returns (uint256)
                  {
                      return balanceAndBlacklistStates[_account];
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { Ownable } from "./Ownable.sol";
              /**
               * @title Blacklistable Token
               * @dev Allows accounts to be blacklisted by a "blacklister" role
               */
              abstract contract Blacklistable is Ownable {
                  address public blacklister;
                  mapping(address => bool) internal _deprecatedBlacklisted;
                  event Blacklisted(address indexed _account);
                  event UnBlacklisted(address indexed _account);
                  event BlacklisterChanged(address indexed newBlacklister);
                  /**
                   * @dev Throws if called by any account other than the blacklister.
                   */
                  modifier onlyBlacklister() {
                      require(
                          msg.sender == blacklister,
                          "Blacklistable: caller is not the blacklister"
                      );
                      _;
                  }
                  /**
                   * @dev Throws if argument account is blacklisted.
                   * @param _account The address to check.
                   */
                  modifier notBlacklisted(address _account) {
                      require(
                          !_isBlacklisted(_account),
                          "Blacklistable: account is blacklisted"
                      );
                      _;
                  }
                  /**
                   * @notice Checks if account is blacklisted.
                   * @param _account The address to check.
                   * @return True if the account is blacklisted, false if the account is not blacklisted.
                   */
                  function isBlacklisted(address _account) external view returns (bool) {
                      return _isBlacklisted(_account);
                  }
                  /**
                   * @notice Adds account to blacklist.
                   * @param _account The address to blacklist.
                   */
                  function blacklist(address _account) external onlyBlacklister {
                      _blacklist(_account);
                      emit Blacklisted(_account);
                  }
                  /**
                   * @notice Removes account from blacklist.
                   * @param _account The address to remove from the blacklist.
                   */
                  function unBlacklist(address _account) external onlyBlacklister {
                      _unBlacklist(_account);
                      emit UnBlacklisted(_account);
                  }
                  /**
                   * @notice Updates the blacklister address.
                   * @param _newBlacklister The address of the new blacklister.
                   */
                  function updateBlacklister(address _newBlacklister) external onlyOwner {
                      require(
                          _newBlacklister != address(0),
                          "Blacklistable: new blacklister is the zero address"
                      );
                      blacklister = _newBlacklister;
                      emit BlacklisterChanged(blacklister);
                  }
                  /**
                   * @dev Checks if account is blacklisted.
                   * @param _account The address to check.
                   * @return true if the account is blacklisted, false otherwise.
                   */
                  function _isBlacklisted(address _account)
                      internal
                      virtual
                      view
                      returns (bool);
                  /**
                   * @dev Helper method that blacklists an account.
                   * @param _account The address to blacklist.
                   */
                  function _blacklist(address _account) internal virtual;
                  /**
                   * @dev Helper method that unblacklists an account.
                   * @param _account The address to unblacklist.
                   */
                  function _unBlacklist(address _account) internal virtual;
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
              abstract contract AbstractFiatTokenV1 is IERC20 {
                  function _approve(
                      address owner,
                      address spender,
                      uint256 value
                  ) internal virtual;
                  function _transfer(
                      address from,
                      address to,
                      uint256 value
                  ) internal virtual;
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { Ownable } from "../v1/Ownable.sol";
              import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
              import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
              contract Rescuable is Ownable {
                  using SafeERC20 for IERC20;
                  address private _rescuer;
                  event RescuerChanged(address indexed newRescuer);
                  /**
                   * @notice Returns current rescuer
                   * @return Rescuer's address
                   */
                  function rescuer() external view returns (address) {
                      return _rescuer;
                  }
                  /**
                   * @notice Revert if called by any account other than the rescuer.
                   */
                  modifier onlyRescuer() {
                      require(msg.sender == _rescuer, "Rescuable: caller is not the rescuer");
                      _;
                  }
                  /**
                   * @notice Rescue ERC20 tokens locked up in this contract.
                   * @param tokenContract ERC20 token contract address
                   * @param to        Recipient address
                   * @param amount    Amount to withdraw
                   */
                  function rescueERC20(
                      IERC20 tokenContract,
                      address to,
                      uint256 amount
                  ) external onlyRescuer {
                      tokenContract.safeTransfer(to, amount);
                  }
                  /**
                   * @notice Updates the rescuer address.
                   * @param newRescuer The address of the new rescuer.
                   */
                  function updateRescuer(address newRescuer) external onlyOwner {
                      require(
                          newRescuer != address(0),
                          "Rescuable: new rescuer is the zero address"
                      );
                      _rescuer = newRescuer;
                      emit RescuerChanged(newRescuer);
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { FiatTokenV1 } from "../v1/FiatTokenV1.sol";
              import { Rescuable } from "./Rescuable.sol";
              /**
               * @title FiatTokenV1_1
               * @dev ERC20 Token backed by fiat reserves
               */
              contract FiatTokenV1_1 is FiatTokenV1, Rescuable {
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              import { ECRecover } from "./ECRecover.sol";
              import { IERC1271 } from "../interface/IERC1271.sol";
              /**
               * @dev Signature verification helper that can be used instead of `ECRecover.recover` to seamlessly support both ECDSA
               * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets.
               *
               * Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/21bb89ef5bfc789b9333eb05e3ba2b7b284ac77c/contracts/utils/cryptography/SignatureChecker.sol
               */
              library SignatureChecker {
                  /**
                   * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
                   * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECRecover.recover`.
                   * @param signer        Address of the claimed signer
                   * @param digest        Keccak-256 hash digest of the signed message
                   * @param signature     Signature byte array associated with hash
                   */
                  function isValidSignatureNow(
                      address signer,
                      bytes32 digest,
                      bytes memory signature
                  ) external view returns (bool) {
                      if (!isContract(signer)) {
                          return ECRecover.recover(digest, signature) == signer;
                      }
                      return isValidERC1271SignatureNow(signer, digest, signature);
                  }
                  /**
                   * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
                   * against the signer smart contract using ERC1271.
                   * @param signer        Address of the claimed signer
                   * @param digest        Keccak-256 hash digest of the signed message
                   * @param signature     Signature byte array associated with hash
                   *
                   * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
                   * change through time. It could return true at block N and false at block N+1 (or the opposite).
                   */
                  function isValidERC1271SignatureNow(
                      address signer,
                      bytes32 digest,
                      bytes memory signature
                  ) internal view returns (bool) {
                      (bool success, bytes memory result) = signer.staticcall(
                          abi.encodeWithSelector(
                              IERC1271.isValidSignature.selector,
                              digest,
                              signature
                          )
                      );
                      return (success &&
                          result.length >= 32 &&
                          abi.decode(result, (bytes32)) ==
                          bytes32(IERC1271.isValidSignature.selector));
                  }
                  /**
                   * @dev Checks if the input address is a smart contract.
                   */
                  function isContract(address addr) internal view returns (bool) {
                      uint256 size;
                      assembly {
                          size := extcodesize(addr)
                      }
                      return size > 0;
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              /**
               * @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-712 typed data (EIP-191 version `0x01`).
                   * Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/21bb89ef5bfc789b9333eb05e3ba2b7b284ac77c/contracts/utils/cryptography/MessageHashUtils.sol
                   *
                   * 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.
                   *
                   * @param domainSeparator    Domain separator
                   * @param structHash         Hashed EIP-712 data struct
                   * @return digest            The keccak256 digest of an EIP-712 typed data
                   */
                  function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash)
                      internal
                      pure
                      returns (bytes32 digest)
                  {
                      assembly {
                          let ptr := mload(0x40)
                          mstore(ptr, "\\x19\\x01")
                          mstore(add(ptr, 0x02), domainSeparator)
                          mstore(add(ptr, 0x22), structHash)
                          digest := keccak256(ptr, 0x42)
                      }
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              /**
               * @title EIP712
               * @notice A library that provides EIP712 helper functions
               */
              library EIP712 {
                  /**
                   * @notice Make EIP712 domain separator
                   * @param name      Contract name
                   * @param version   Contract version
                   * @param chainId   Blockchain ID
                   * @return Domain separator
                   */
                  function makeDomainSeparator(
                      string memory name,
                      string memory version,
                      uint256 chainId
                  ) internal view returns (bytes32) {
                      return
                          keccak256(
                              abi.encode(
                                  // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
                                  0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,
                                  keccak256(bytes(name)),
                                  keccak256(bytes(version)),
                                  chainId,
                                  address(this)
                              )
                          );
                  }
                  /**
                   * @notice Make EIP712 domain separator
                   * @param name      Contract name
                   * @param version   Contract version
                   * @return Domain separator
                   */
                  function makeDomainSeparator(string memory name, string memory version)
                      internal
                      view
                      returns (bytes32)
                  {
                      uint256 chainId;
                      assembly {
                          chainId := chainid()
                      }
                      return makeDomainSeparator(name, version, chainId);
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              /**
               * @title ECRecover
               * @notice A library that provides a safe ECDSA recovery function
               */
              library ECRecover {
                  /**
                   * @notice Recover signer's address from a signed message
                   * @dev Adapted from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/65e4ffde586ec89af3b7e9140bdc9235d1254853/contracts/cryptography/ECDSA.sol
                   * Modifications: Accept v, r, and s as separate arguments
                   * @param digest    Keccak-256 hash digest of the signed message
                   * @param v         v of the signature
                   * @param r         r of the signature
                   * @param s         s of the signature
                   * @return Signer address
                   */
                  function recover(
                      bytes32 digest,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) internal pure returns (address) {
                      // 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 (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): 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
                      ) {
                          revert("ECRecover: invalid signature 's' value");
                      }
                      if (v != 27 && v != 28) {
                          revert("ECRecover: invalid signature 'v' value");
                      }
                      // If the signature is valid (and not malleable), return the signer address
                      address signer = ecrecover(digest, v, r, s);
                      require(signer != address(0), "ECRecover: invalid signature");
                      return signer;
                  }
                  /**
                   * @notice Recover signer's address from a signed message
                   * @dev Adapted from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/0053ee040a7ff1dbc39691c9e67a69f564930a88/contracts/utils/cryptography/ECDSA.sol
                   * @param digest    Keccak-256 hash digest of the signed message
                   * @param signature Signature byte array associated with hash
                   * @return Signer address
                   */
                  function recover(bytes32 digest, bytes memory signature)
                      internal
                      pure
                      returns (address)
                  {
                      require(signature.length == 65, "ECRecover: invalid signature length");
                      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 recover(digest, v, r, s);
                  }
              }
              /**
               * SPDX-License-Identifier: Apache-2.0
               *
               * Copyright (c) 2023, Circle Internet Financial, LLC.
               *
               * Licensed under the Apache License, Version 2.0 (the "License");
               * you may not use this file except in compliance with the License.
               * You may obtain a copy of the License at
               *
               * http://www.apache.org/licenses/LICENSE-2.0
               *
               * Unless required by applicable law or agreed to in writing, software
               * distributed under the License is distributed on an "AS IS" BASIS,
               * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
               * See the License for the specific language governing permissions and
               * limitations under the License.
               */
              pragma solidity 0.6.12;
              /**
               * @dev Interface of the ERC1271 standard signature validation method for
               * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
               */
              interface IERC1271 {
                  /**
                   * @dev Should return whether the signature provided is valid for the provided data
                   * @param hash          Hash of the data to be signed
                   * @param signature     Signature byte array associated with the provided data hash
                   * @return magicValue   bytes4 magic value 0x1626ba7e when function passes
                   */
                  function isValidSignature(bytes32 hash, bytes memory signature)
                      external
                      view
                      returns (bytes4 magicValue);
              }