ETH Price: $4,427.42 (-0.85%)

Transaction Decoder

Block:
15920235 at Nov-07-2022 07:28:11 PM +UTC
Transaction Fee:
0.00154116809186015 ETH $6.82
Gas Used:
64,775 Gas / 23.792637466 Gwei

Emitted Events:

203 StandardToken.Transfer( from=[Sender] 0x732909fe6178e74bf358b2fdbba222b677911123, to=[Receiver] Router, value=2903000000000000000 )
204 Router.0xaa3a3bc72b8c754ca6ee8425a5531bafec37569ec012d62d5f682ca909ae06f1( 0xaa3a3bc72b8c754ca6ee8425a5531bafec37569ec012d62d5f682ca909ae06f1, 0000000000000000000000000000000000000000000000000000000000000127, 0000000000000000000000004a220e6096b25eadb88358cb44068a3248254675, 00000000000000000000000000000000000000000000000000000000000000a0, 0000000000000000000000000000000000000000000000002849871e86f58000, 00000000000000000000000000000000000000000000000000339150caea3000, 0000000000000000000000000000000000000000000000000000000000000008, 0800100018a7ae29000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x367e59b5...66c4Cd4B7
0x4a220E60...248254675
0x732909Fe...677911123
0.0114005252493521 Eth
Nonce: 1
0.00985935715749195 Eth
Nonce: 2
0.00154116809186015
(Flashbots: Builder)
1.204570681493747698 Eth1.204667843993747698 Eth0.0000971625

Execution Trace

Router.b258848a( )
  • RouterFacet.lock( _targetChain=295, _nativeToken=0x4a220E6096B25EADb88358cb44068A3248254675, _amount=2903000000000000000, _receiver=0x0800100018A7AE29 )
    • StandardToken.transferFrom( _from=0x732909Fe6178E74Bf358b2fDBBa222b677911123, _to=0x367e59b559283C8506207d75B0c5D8C66c4Cd4B7, _value=2903000000000000000 ) => ( True )
      File 1 of 3: Router
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
      import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
      import "./interfaces/IDiamondLoupe.sol";
      import "./interfaces/IDiamondCut.sol";
      import "./interfaces/IERC173.sol";
      import "./libraries/LibDiamond.sol";
      contract Router {
          struct DiamondArgs {
              address owner;
          }
          constructor(
              IDiamondCut.FacetCut[] memory _diamondCut,
              DiamondArgs memory _args
          ) {
              LibDiamond.diamondCut(_diamondCut, address(0), new bytes(0));
              LibDiamond.setContractOwner(_args.owner);
              LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
              // adding ERC165 data
              ds.supportedInterfaces[type(IERC165).interfaceId] = true;
              ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
              ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
              ds.supportedInterfaces[type(IERC173).interfaceId] = true;
          }
          // Find facet for function that is called and execute the
          // function if a facet is found and return any value.
          fallback() external payable {
              LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
              address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;
              require(facet != address(0), "Diamond: Function does not exist");
              assembly {
                  calldatacopy(0, 0, calldatasize())
                  let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
                  returndatacopy(0, 0, returndatasize())
                  switch result
                  case 0 {
                      revert(0, returndatasize())
                  }
                  default {
                      return(0, returndatasize())
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(
              address sender,
              address recipient,
              uint256 amount
          ) external returns (bool);
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[EIP].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      // A loupe is a small magnifying glass used to look at diamonds.
      // These functions look at diamonds
      interface IDiamondLoupe {
          /// These functions are expected to be called frequently
          /// by tools.
          struct Facet {
              address facetAddress;
              bytes4[] functionSelectors;
          }
          /// @notice Gets all facet addresses and their four byte function selectors.
          /// @return facets_ Facet
          function facets() external view returns (Facet[] memory facets_);
          /// @notice Gets all the function selectors supported by a specific facet.
          /// @param _facet The facet address.
          /// @return facetFunctionSelectors_
          function facetFunctionSelectors(address _facet)
              external
              view
              returns (bytes4[] memory facetFunctionSelectors_);
          /// @notice Get all the facet addresses used by a diamond.
          /// @return facetAddresses_
          function facetAddresses()
              external
              view
              returns (address[] memory facetAddresses_);
          /// @notice Gets the facet that supports the given selector.
          /// @dev If facet is not found return address(0).
          /// @param _functionSelector The function selector.
          /// @return facetAddress_ The facet address.
          function facetAddress(bytes4 _functionSelector)
              external
              view
              returns (address facetAddress_);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      interface IDiamondCut {
          enum FacetCutAction {
              Add,
              Replace,
              Remove
          }
          // Add=0, Replace=1, Remove=2
          struct FacetCut {
              address facetAddress;
              FacetCutAction action;
              bytes4[] functionSelectors;
          }
          /// @notice Add/replace/remove any number of functions and optionally execute
          ///         a function with delegatecall
          /// @param _diamondCut Contains the facet addresses and function selectors
          /// @param _init The address of the contract or facet to execute _calldata
          /// @param _calldata A function call, including function selector and arguments
          ///                  _calldata is executed with delegatecall on _init
          function diamondCut(
              FacetCut[] calldata _diamondCut,
              address _init,
              bytes calldata _calldata
          ) external;
          event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      /// @title ERC-173 Contract Ownership Standard
      ///  Note: the ERC-165 identifier for this interface is 0x7f5828d0
      /* is ERC165 */
      interface IERC173 {
          /// @dev This emits when ownership of a contract changes.
          event OwnershipTransferred(
              address indexed previousOwner,
              address indexed newOwner
          );
          /// @notice Get the address of the owner
          /// @return owner_ The address of the owner.
          function owner() external view returns (address owner_);
          /// @notice Set the address of the new owner of the contract
          /// @dev Set _newOwner to address(0) to renounce any ownership.
          /// @param _newOwner The address of the new owner of the contract
          function transferOwnership(address _newOwner) external;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "../interfaces/IDiamondCut.sol";
      library LibDiamond {
          bytes32 constant DIAMOND_STORAGE_POSITION =
              keccak256("diamond.standard.diamond.storage");
          struct FacetAddressAndPosition {
              address facetAddress;
              uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
          }
          struct FacetFunctionSelectors {
              bytes4[] functionSelectors;
              uint16 facetAddressPosition; // position of facetAddress in facetAddresses array
          }
          struct DiamondStorage {
              // maps function selector to the facet address and
              // the position of the selector in the facetFunctionSelectors.selectors array
              mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
              // maps facet addresses to function selectors
              mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
              // facet addresses
              address[] facetAddresses;
              // Used to query if a contract implements an interface.
              // Used to implement ERC-165.
              mapping(bytes4 => bool) supportedInterfaces;
              // owner of the contract
              address contractOwner;
          }
          function diamondStorage()
              internal
              pure
              returns (DiamondStorage storage ds)
          {
              bytes32 position = DIAMOND_STORAGE_POSITION;
              assembly {
                  ds.slot := position
              }
          }
          event OwnershipTransferred(
              address indexed previousOwner,
              address indexed newOwner
          );
          function setContractOwner(address _newOwner) internal {
              DiamondStorage storage ds = diamondStorage();
              address previousOwner = ds.contractOwner;
              ds.contractOwner = _newOwner;
              emit OwnershipTransferred(previousOwner, _newOwner);
          }
          function contractOwner() internal view returns (address contractOwner_) {
              contractOwner_ = diamondStorage().contractOwner;
          }
          function enforceIsContractOwner() internal view {
              require(
                  msg.sender == diamondStorage().contractOwner,
                  "LibDiamond: Must be contract owner"
              );
          }
          event DiamondCut(
              IDiamondCut.FacetCut[] _diamondCut,
              address _init,
              bytes _calldata
          );
          // Internal function version of diamondCut
          function diamondCut(
              IDiamondCut.FacetCut[] memory _diamondCut,
              address _init,
              bytes memory _calldata
          ) internal {
              for (
                  uint256 facetIndex;
                  facetIndex < _diamondCut.length;
                  facetIndex++
              ) {
                  IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
                  if (action == IDiamondCut.FacetCutAction.Add) {
                      addFunctions(
                          _diamondCut[facetIndex].facetAddress,
                          _diamondCut[facetIndex].functionSelectors
                      );
                  } else if (action == IDiamondCut.FacetCutAction.Replace) {
                      replaceFunctions(
                          _diamondCut[facetIndex].facetAddress,
                          _diamondCut[facetIndex].functionSelectors
                      );
                  } else if (action == IDiamondCut.FacetCutAction.Remove) {
                      removeFunctions(
                          _diamondCut[facetIndex].facetAddress,
                          _diamondCut[facetIndex].functionSelectors
                      );
                  } else {
                      revert("LibDiamondCut: Incorrect FacetCutAction");
                  }
              }
              emit DiamondCut(_diamondCut, _init, _calldata);
              initializeDiamondCut(_init, _calldata);
          }
          function addFunctions(
              address _facetAddress,
              bytes4[] memory _functionSelectors
          ) internal {
              require(
                  _functionSelectors.length > 0,
                  "LibDiamondCut: No selectors in facet to cut"
              );
              DiamondStorage storage ds = diamondStorage();
              // uint16 selectorCount = uint16(diamondStorage().selectors.length);
              require(
                  _facetAddress != address(0),
                  "LibDiamondCut: Add facet can't be address(0)"
              );
              uint16 selectorPosition = uint16(
                  ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
              );
              // add new facet address if it does not exist
              if (selectorPosition == 0) {
                  enforceHasContractCode(
                      _facetAddress,
                      "LibDiamondCut: New facet has no code"
                  );
                  ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition = uint16(ds.facetAddresses.length);
                  ds.facetAddresses.push(_facetAddress);
              }
              for (
                  uint256 selectorIndex;
                  selectorIndex < _functionSelectors.length;
                  selectorIndex++
              ) {
                  bytes4 selector = _functionSelectors[selectorIndex];
                  address oldFacetAddress = ds
                      .selectorToFacetAndPosition[selector]
                      .facetAddress;
                  require(
                      oldFacetAddress == address(0),
                      "LibDiamondCut: Can't add function that already exists"
                  );
                  addFunction(ds, selector, selectorPosition, _facetAddress);
                  selectorPosition++;
              }
          }
          function replaceFunctions(
              address _facetAddress,
              bytes4[] memory _functionSelectors
          ) internal {
              require(
                  _functionSelectors.length > 0,
                  "LibDiamondCut: No selectors in facet to cut"
              );
              DiamondStorage storage ds = diamondStorage();
              require(
                  _facetAddress != address(0),
                  "LibDiamondCut: Add facet can't be address(0)"
              );
              uint16 selectorPosition = uint16(
                  ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
              );
              // add new facet address if it does not exist
              if (selectorPosition == 0) {
                  enforceHasContractCode(
                      _facetAddress,
                      "LibDiamondCut: New facet has no code"
                  );
                  ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition = uint16(ds.facetAddresses.length);
                  ds.facetAddresses.push(_facetAddress);
              }
              for (
                  uint256 selectorIndex;
                  selectorIndex < _functionSelectors.length;
                  selectorIndex++
              ) {
                  bytes4 selector = _functionSelectors[selectorIndex];
                  address oldFacetAddress = ds
                      .selectorToFacetAndPosition[selector]
                      .facetAddress;
                  require(
                      oldFacetAddress != _facetAddress,
                      "LibDiamondCut: Can't replace function with same function"
                  );
                  removeFunction(ds, oldFacetAddress, selector);
                  // add function
                  addFunction(ds, selector, selectorPosition, _facetAddress);
                  selectorPosition++;
              }
          }
          function removeFunctions(
              address _facetAddress,
              bytes4[] memory _functionSelectors
          ) internal {
              require(
                  _functionSelectors.length > 0,
                  "LibDiamondCut: No selectors in facet to cut"
              );
              DiamondStorage storage ds = diamondStorage();
              // if function does not exist then do nothing and return
              require(
                  _facetAddress == address(0),
                  "LibDiamondCut: Remove facet address must be address(0)"
              );
              for (
                  uint256 selectorIndex;
                  selectorIndex < _functionSelectors.length;
                  selectorIndex++
              ) {
                  bytes4 selector = _functionSelectors[selectorIndex];
                  address oldFacetAddress = ds
                      .selectorToFacetAndPosition[selector]
                      .facetAddress;
                  removeFunction(ds, oldFacetAddress, selector);
              }
          }
          function addFunction(
              DiamondStorage storage ds,
              bytes4 _selector,
              uint16 _selectorPosition,
              address _facetAddress
          ) internal {
              ds
                  .selectorToFacetAndPosition[_selector]
                  .functionSelectorPosition = _selectorPosition;
              ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(
                  _selector
              );
              ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
          }
          function removeFunction(
              DiamondStorage storage ds,
              address _facetAddress,
              bytes4 _selector
          ) internal {
              require(
                  _facetAddress != address(0),
                  "LibDiamondCut: Can't remove function that doesn't exist"
              );
              // an immutable function is a function defined directly in a diamond
              require(
                  _facetAddress != address(this),
                  "LibDiamondCut: Can't remove immutable function"
              );
              // replace selector with last selector, then delete last selector
              uint256 selectorPosition = ds
                  .selectorToFacetAndPosition[_selector]
                  .functionSelectorPosition;
              uint256 lastSelectorPosition = ds
                  .facetFunctionSelectors[_facetAddress]
                  .functionSelectors
                  .length - 1;
              // if not the same then replace _selector with lastSelector
              if (selectorPosition != lastSelectorPosition) {
                  bytes4 lastSelector = ds
                      .facetFunctionSelectors[_facetAddress]
                      .functionSelectors[lastSelectorPosition];
                  ds.facetFunctionSelectors[_facetAddress].functionSelectors[
                          selectorPosition
                      ] = lastSelector;
                  ds
                      .selectorToFacetAndPosition[lastSelector]
                      .functionSelectorPosition = uint16(selectorPosition);
              }
              // delete the last selector
              ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
              delete ds.selectorToFacetAndPosition[_selector];
              // if no more selectors for facet address then delete the facet address
              if (lastSelectorPosition == 0) {
                  // replace facet address with last facet address and delete last facet address
                  uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
                  uint256 facetAddressPosition = ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition;
                  if (facetAddressPosition != lastFacetAddressPosition) {
                      address lastFacetAddress = ds.facetAddresses[
                          lastFacetAddressPosition
                      ];
                      ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                      ds
                          .facetFunctionSelectors[lastFacetAddress]
                          .facetAddressPosition = uint16(facetAddressPosition);
                  }
                  ds.facetAddresses.pop();
                  delete ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition;
              }
          }
          function initializeDiamondCut(address _init, bytes memory _calldata)
              internal
          {
              if (_init == address(0)) {
                  require(
                      _calldata.length == 0,
                      "LibDiamondCut: _init is address(0) but_calldata is not empty"
                  );
              } else {
                  require(
                      _calldata.length > 0,
                      "LibDiamondCut: _calldata is empty but _init is not address(0)"
                  );
                  if (_init != address(this)) {
                      enforceHasContractCode(
                          _init,
                          "LibDiamondCut: _init address has no code"
                      );
                  }
                  (bool success, bytes memory error) = _init.delegatecall(_calldata);
                  if (!success) {
                      if (error.length > 0) {
                          // bubble up the error
                          revert(string(error));
                      } else {
                          revert("LibDiamondCut: _init function reverted");
                      }
                  }
              }
          }
          function enforceHasContractCode(
              address _contract,
              string memory _errorMessage
          ) internal view {
              uint256 contractSize;
              assembly {
                  contractSize := extcodesize(_contract)
              }
              require(contractSize > 0, _errorMessage);
          }
      }
      

      File 2 of 3: StandardToken
      pragma solidity ^0.4.21;
      
      /**
       * @title ERC20Basic
       * @dev Simpler version of ERC20 interface
       * @dev see https://github.com/ethereum/EIPs/issues/179
       */
      contract ERC20Basic {
        function totalSupply() public view returns (uint256);
        function balanceOf(address who) public view returns (uint256);
        function transfer(address to, uint256 value) public returns (bool);
        event Transfer(address indexed from, address indexed to, uint256 value);
      }
      
      /**
       * @title SafeMath
       * @dev Math operations with safety checks that throw on error
       */
      library SafeMath {
      
        /**
         * @dev Multiplies two numbers, throws on overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
          if (a == 0) {
            return 0;
          }
          uint256 c = a * b;
          assert(c / a == b);
          return c;
        }
      
        /**
         * @dev Integer division of two numbers, truncating the quotient.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
          // assert(b > 0); // Solidity automatically throws when dividing by 0
          uint256 c = a / b;
          // assert(a == b * c + a % b); // There is no case in which this doesn't hold
          return c;
        }
      
        /**
         * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
          assert(b <= a);
          return a - b;
        }
      
        /**
         * @dev Adds two numbers, throws on overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
          uint256 c = a + b;
          assert(c >= a);
          return c;
        }
      }
      
      /**
       * @title Basic token
       * @dev Basic version of StandardToken, with no allowances.
       */
      contract BasicToken is ERC20Basic {
        using SafeMath for uint256;
      
        mapping(address => uint256) balances;
      
        uint256 totalSupply_ = 45467000000000000000000000;
      
        /**
        * @dev total number of tokens in existence
        */
        function totalSupply() public view returns (uint256) {
          return totalSupply_;
        }
      
        /**
        * @dev transfer token for a specified address
        * @param _to The address to transfer to.
        * @param _value The amount to be transferred.
        */
        function transfer(address _to, uint256 _value) public returns (bool) {
          require(_to != address(0));
          require(_value <= balances[msg.sender]);
      
          // SafeMath.sub will throw if there is not enough balance.
          balances[msg.sender] = balances[msg.sender].sub(_value);
          balances[_to] = balances[_to].add(_value);
          emit Transfer(msg.sender, _to, _value);
          return true;
        }
      
        /**
        * @dev Gets the balance of the specified address.
        * @param _owner The address to query the the balance of.
        * @return An uint256 representing the amount owned by the passed address.
        */
        function balanceOf(address _owner) public view returns (uint256 balance) {
          return balances[_owner];
        }
      
      }
      
      /**
       * @title ERC20 interface
       * @dev see https://github.com/ethereum/EIPs/issues/20
       */
      contract ERC20 is ERC20Basic {
        function allowance(address owner, address spender) public view returns (uint256);
        function transferFrom(address from, address to, uint256 value) public returns (bool);
        function approve(address spender, uint256 value) public returns (bool);
        event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      
      /**
       * @title Standard ERC20 token
       *
       * @dev Implementation of the basic standard token.
       * @dev https://github.com/ethereum/EIPs/issues/20
       * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
       */
      contract StandardToken is ERC20, BasicToken {
      
        // Name of the token
        string constant public name = "Quant";
        // Token abbreviation
        string constant public symbol = "QNT";
        // Decimal places
        uint8 constant public decimals = 18;
        // Zeros after the point
        uint256 constant public DECIMAL_ZEROS = 1000000000000000000;
      
        mapping (address => mapping (address => uint256)) internal allowed;
      
        address public crowdsale;
      
        modifier onlyCrowdsale() {
          require(msg.sender == crowdsale);
          _;
        }
      
        function StandardToken(address _crowdsale) public {
          require(_crowdsale != address(0));
          crowdsale = _crowdsale;
        }
      
        function mint(address _address, uint256 _value) public onlyCrowdsale {
          balances[_address] = balances[_address].add(_value);
          emit Transfer(0, _address, _value);
        }
      
        /**
         * @dev Transfer tokens from one address to another
         * @param _from address The address which you want to send tokens from
         * @param _to address The address which you want to transfer to
         * @param _value uint256 the amount of tokens to be transferred
         */
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
          require(_to != address(0));
          require(_value <= balances[_from]);
          require(_value <= allowed[_from][msg.sender]);
      
          balances[_from] = balances[_from].sub(_value);
          balances[_to] = balances[_to].add(_value);
          allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
          emit Transfer(_from, _to, _value);
          return true;
        }
      
        /**
         * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
         *
         * 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
         * @param _spender The address which will spend the funds.
         * @param _value The amount of tokens to be spent.
         */
        function approve(address _spender, uint256 _value) public returns (bool) {
          allowed[msg.sender][_spender] = _value;
          emit Approval(msg.sender, _spender, _value);
          return true;
        }
      
        /**
         * @dev Function to check the amount of tokens that an owner allowed to a spender.
         * @param _owner address The address which owns the funds.
         * @param _spender address The address which will spend the funds.
         * @return A uint256 specifying the amount of tokens still available for the spender.
         */
        function allowance(address _owner, address _spender) public view returns (uint256) {
          return allowed[_owner][_spender];
        }
      
        /**
         * @dev Increase the amount of tokens that an owner allowed to a spender.
         *
         * approve should be called when allowed[_spender] == 0. To increment
         * allowed value is better to use this function to avoid 2 calls (and wait until
         * the first transaction is mined)
         * From MonolithDAO Token.sol
         * @param _spender The address which will spend the funds.
         * @param _addedValue The amount of tokens to increase the allowance by.
         */
        function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
          allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
          emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
          return true;
        }
      
        /**
         * @dev Decrease the amount of tokens that an owner allowed to a spender.
         *
         * approve should be called when allowed[_spender] == 0. To decrement
         * allowed value is better to use this function to avoid 2 calls (and wait until
         * the first transaction is mined)
         * From MonolithDAO Token.sol
         * @param _spender The address which will spend the funds.
         * @param _subtractedValue The amount of tokens to decrease the allowance by.
         */
        function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
          uint oldValue = allowed[msg.sender][_spender];
          if (_subtractedValue > oldValue) {
            allowed[msg.sender][_spender] = 0;
          } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
          }
          emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
          return true;
        }
      
      }

      File 3 of 3: RouterFacet
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
      import "../WrappedToken.sol";
      import "../interfaces/IERC2612Permit.sol";
      import "../interfaces/IRouter.sol";
      import "../libraries/LibDiamond.sol";
      import "../libraries/LibFeeCalculator.sol";
      import "../libraries/LibRouter.sol";
      import "../libraries/LibGovernance.sol";
      contract RouterFacet is IRouter {
          using SafeERC20 for IERC20;
          /// @notice Constructs the Router contract instance
          function initRouter() external override {
              LibRouter.Storage storage rs = LibRouter.routerStorage();
              require(!rs.initialized, "RouterFacet: already initialized");
              rs.initialized = true;
          }
          /// @param _ethHash The ethereum signed message hash
          /// @return Whether this hash has already been used for a mint/unlock transaction
          function hashesUsed(bytes32 _ethHash)
              external
              view
              override
              returns (bool)
          {
              LibRouter.Storage storage rs = LibRouter.routerStorage();
              return rs.hashesUsed[_ethHash];
          }
          /// @return The count of native tokens in the set
          function nativeTokensCount() external view override returns (uint256) {
              return LibRouter.nativeTokensCount();
          }
          /// @return The address of the native token at a given index
          function nativeTokenAt(uint256 _index)
              external
              view
              override
              returns (address)
          {
              return LibRouter.nativeTokenAt(_index);
          }
          /// @notice Transfers `amount` native tokens to the router contract.
          ///        The router must be authorised to transfer the native token.
          /// @param _targetChain The target chain for the bridging operation
          /// @param _nativeToken The token to be bridged
          /// @param _amount The amount of tokens to bridge
          /// @param _receiver The address of the receiver on the target chain
          function lock(
              uint256 _targetChain,
              address _nativeToken,
              uint256 _amount,
              bytes memory _receiver
          ) public override whenNotPaused onlyNativeToken(_nativeToken) {
              IERC20(_nativeToken).safeTransferFrom(
                  msg.sender,
                  address(this),
                  _amount
              );
              uint256 serviceFee = LibFeeCalculator.distributeRewards(
                  _nativeToken,
                  _amount
              );
              emit Lock(_targetChain, _nativeToken, _receiver, _amount, serviceFee);
          }
          /// @notice Locks the provided amount of nativeToken using an EIP-2612 permit and initiates a bridging transaction
          /// @param _targetChain The chain to bridge the tokens to
          /// @param _nativeToken The native token to bridge
          /// @param _amount The amount of nativeToken to lock and bridge
          /// @param _deadline The deadline for the provided permit
          /// @param _v The recovery id of the permit's ECDSA signature
          /// @param _r The first output of the permit's ECDSA signature
          /// @param _s The second output of the permit's ECDSA signature
          function lockWithPermit(
              uint256 _targetChain,
              address _nativeToken,
              uint256 _amount,
              bytes memory _receiver,
              uint256 _deadline,
              uint8 _v,
              bytes32 _r,
              bytes32 _s
          ) external override {
              IERC2612Permit(_nativeToken).permit(
                  msg.sender,
                  address(this),
                  _amount,
                  _deadline,
                  _v,
                  _r,
                  _s
              );
              lock(_targetChain, _nativeToken, _amount, _receiver);
          }
          /// @notice Transfers `amount` native tokens to the `receiver` address.
          ///         Must be authorised by the configured supermajority threshold of `signatures` from the `members` set.
          /// @param _sourceChain The chainId of the chain that we're bridging from
          /// @param _transactionId The transaction ID + log index in the source chain
          /// @param _nativeToken The address of the native token
          /// @param _amount The amount to transfer
          /// @param _receiver The address reveiving the tokens
          /// @param _signatures The array of signatures from the members, authorising the operation
          function unlock(
              uint256 _sourceChain,
              bytes memory _transactionId,
              address _nativeToken,
              uint256 _amount,
              address _receiver,
              bytes[] calldata _signatures
          ) external override whenNotPaused onlyNativeToken(_nativeToken) {
              LibGovernance.validateSignaturesLength(_signatures.length);
              bytes32 ethHash = computeMessage(
                  _sourceChain,
                  block.chainid,
                  _transactionId,
                  _nativeToken,
                  _receiver,
                  _amount
              );
              LibRouter.Storage storage rs = LibRouter.routerStorage();
              require(
                  !rs.hashesUsed[ethHash],
                  "RouterFacet: transaction already submitted"
              );
              validateAndStoreTx(ethHash, _signatures);
              uint256 serviceFee = LibFeeCalculator.distributeRewards(
                  _nativeToken,
                  _amount
              );
              uint256 transferAmount = _amount - serviceFee;
              IERC20(_nativeToken).safeTransfer(_receiver, transferAmount);
              emit Unlock(
                  _sourceChain,
                  _transactionId,
                  _nativeToken,
                  transferAmount,
                  _receiver,
                  serviceFee
              );
          }
          /// @notice Burns `amount` of `wrappedToken` initializes a bridging transaction to the target chain
          /// @param _targetChain The target chain to which the wrapped asset will be transferred
          /// @param _wrappedToken The address of the wrapped token
          /// @param _amount The amount of `wrappedToken` to burn
          /// @param _receiver The address of the receiver on the target chain
          function burn(
              uint256 _targetChain,
              address _wrappedToken,
              uint256 _amount,
              bytes memory _receiver
          ) public override whenNotPaused {
              WrappedToken(_wrappedToken).burnFrom(msg.sender, _amount);
              emit Burn(_targetChain, _wrappedToken, _amount, _receiver);
          }
          /// @notice Burns `amount` of `wrappedToken` using an EIP-2612 permit and initializes a bridging transaction to the target chain
          /// @param _targetChain The target chain to which the wrapped asset will be transferred
          /// @param _wrappedToken The address of the wrapped token
          /// @param _amount The amount of `wrappedToken` to burn
          /// @param _receiver The address of the receiver on the target chain
          /// @param _deadline The deadline of the provided permit
          /// @param _v The recovery id of the permit's ECDSA signature
          /// @param _r The first output of the permit's ECDSA signature
          /// @param _s The second output of the permit's ECDSA signature
          function burnWithPermit(
              uint256 _targetChain,
              address _wrappedToken,
              uint256 _amount,
              bytes memory _receiver,
              uint256 _deadline,
              uint8 _v,
              bytes32 _r,
              bytes32 _s
          ) external override {
              WrappedToken(_wrappedToken).permit(
                  msg.sender,
                  address(this),
                  _amount,
                  _deadline,
                  _v,
                  _r,
                  _s
              );
              burn(_targetChain, _wrappedToken, _amount, _receiver);
          }
          /// @notice Mints `amount` wrapped tokens to the `receiver` address.
          ///         Must be authorised by the configured supermajority threshold of `signatures` from the `members` set.
          /// @param _sourceChain ID of the source chain
          /// @param _transactionId The source transaction ID + log index
          /// @param _wrappedToken The address of the wrapped token on the current chain
          /// @param _amount The desired minting amount
          /// @param _receiver The address of the receiver on this chain
          /// @param _signatures The array of signatures from the members, authorising the operation
          function mint(
              uint256 _sourceChain,
              bytes memory _transactionId,
              address _wrappedToken,
              address _receiver,
              uint256 _amount,
              bytes[] calldata _signatures
          ) external override whenNotPaused {
              LibGovernance.validateSignaturesLength(_signatures.length);
              bytes32 ethHash = computeMessage(
                  _sourceChain,
                  block.chainid,
                  _transactionId,
                  _wrappedToken,
                  _receiver,
                  _amount
              );
              LibRouter.Storage storage rs = LibRouter.routerStorage();
              require(
                  !rs.hashesUsed[ethHash],
                  "RouterFacet: transaction already submitted"
              );
              validateAndStoreTx(ethHash, _signatures);
              WrappedToken(_wrappedToken).mint(_receiver, _amount);
              emit Mint(
                  _sourceChain,
                  _transactionId,
                  _wrappedToken,
                  _amount,
                  _receiver
              );
          }
          /// @notice Deploys a wrapped version of `nativeToken` to the current chain
          /// @param _sourceChain The chain where `nativeToken` is originally deployed to
          /// @param _nativeToken The address of the token
          /// @param _tokenParams The name/symbol/decimals to use for the wrapped version of `nativeToken`
          function deployWrappedToken(
              uint256 _sourceChain,
              bytes memory _nativeToken,
              WrappedTokenParams memory _tokenParams
          ) external override {
              require(
                  bytes(_tokenParams.name).length > 0,
                  "RouterFacet: empty wrapped token name"
              );
              require(
                  bytes(_tokenParams.symbol).length > 0,
                  "RouterFacet: empty wrapped token symbol"
              );
              require(
                  _tokenParams.decimals > 0,
                  "RouterFacet: invalid wrapped token decimals"
              );
              LibDiamond.enforceIsContractOwner();
              WrappedToken t = new WrappedToken(
                  _tokenParams.name,
                  _tokenParams.symbol,
                  _tokenParams.decimals
              );
              emit WrappedTokenDeployed(_sourceChain, _nativeToken, address(t));
          }
          /// @notice Updates a native token, which will be used for lock/unlock.
          /// @param _nativeToken The native token address
          /// @param _serviceFee The amount of fee, which will be taken upon lock/unlock execution
          /// @param _status Whether the token will be added or removed
          function updateNativeToken(
              address _nativeToken,
              uint256 _serviceFee,
              bool _status
          ) external override {
              require(_nativeToken != address(0), "RouterFacet: zero address");
              LibDiamond.enforceIsContractOwner();
              LibRouter.updateNativeToken(_nativeToken, _status);
              LibFeeCalculator.setServiceFee(_nativeToken, _serviceFee);
              emit NativeTokenUpdated(_nativeToken, _serviceFee, _status);
          }
          /// @notice Validates the signatures and the data and saves the transaction
          /// @param _ethHash The hashed data
          /// @param _signatures The array of signatures from the members, authorising the operation
          function validateAndStoreTx(bytes32 _ethHash, bytes[] calldata _signatures)
              internal
          {
              LibRouter.Storage storage rs = LibRouter.routerStorage();
              LibGovernance.validateSignatures(_ethHash, _signatures);
              rs.hashesUsed[_ethHash] = true;
          }
          /// @notice Computes the bytes32 ethereum signed message hash for signatures
          /// @param _sourceChain The chain where the bridge transaction was initiated from
          /// @param _targetChain The target chain of the bridge transaction.
          ///                     Should always be the current chainId.
          /// @param _transactionId The transaction ID of the bridge transaction
          /// @param _token The address of the token on this chain
          /// @param _receiver The receiving address on the current chain
          /// @param _amount The amount of `_token` that is being bridged
          function computeMessage(
              uint256 _sourceChain,
              uint256 _targetChain,
              bytes memory _transactionId,
              address _token,
              address _receiver,
              uint256 _amount
          ) internal pure returns (bytes32) {
              bytes32 hashedData = keccak256(
                  abi.encode(
                      _sourceChain,
                      _targetChain,
                      _transactionId,
                      _token,
                      _receiver,
                      _amount
                  )
              );
              return ECDSA.toEthSignedMessageHash(hashedData);
          }
          modifier onlyNativeToken(address _nativeToken) {
              require(
                  LibRouter.containsNativeToken(_nativeToken),
                  "RouterFacet: native token not found"
              );
              _;
          }
          /// Modifier to make a function callable only when the contract is not paused
          modifier whenNotPaused() {
              LibGovernance.enforceNotPaused();
              _;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../IERC20.sol";
      import "../../../utils/Address.sol";
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using Address for address;
          function safeTransfer(
              IERC20 token,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
          function safeTransferFrom(
              IERC20 token,
              address from,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
          /**
           * @dev Deprecated. This function has issues similar to the ones found in
           * {IERC20-approve}, and its usage is discouraged.
           *
           * Whenever possible, use {safeIncreaseAllowance} and
           * {safeDecreaseAllowance} instead.
           */
          function safeApprove(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              // safeApprove should only be called when setting an initial allowance,
              // or when resetting it to zero. To increase and decrease it, use
              // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
              require(
                  (value == 0) || (token.allowance(address(this), spender) == 0),
                  "SafeERC20: approve from non-zero to non-zero allowance"
              );
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
          function safeIncreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              uint256 newAllowance = token.allowance(address(this), spender) + value;
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
          }
          function safeDecreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              unchecked {
                  uint256 oldAllowance = token.allowance(address(this), spender);
                  require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                  uint256 newAllowance = oldAllowance - value;
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
              }
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
              // the target address contains contract code and also asserts for success in the low-level call.
              bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
              if (returndata.length > 0) {
                  // Return data is optional
                  require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "@openzeppelin/contracts/access/Ownable.sol";
      import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
      import "@openzeppelin/contracts/security/Pausable.sol";
      contract WrappedToken is ERC20Permit, Pausable, Ownable {
          uint8 private immutable _decimals;
          /**
           *  @notice Construct a new WrappedToken contract
           *  @param _tokenName The EIP-20 token name
           *  @param _tokenSymbol The EIP-20 token symbol
           *  @param decimals_ The The EIP-20 decimals
           */
          constructor(
              string memory _tokenName,
              string memory _tokenSymbol,
              uint8 decimals_
          ) ERC20(_tokenName, _tokenSymbol) ERC20Permit(_tokenName) {
              _decimals = decimals_;
          }
          /**
           * @notice Mints `_amount` of tokens to the `_account` address
           * @param _account The address to which the tokens will be minted
           * @param _amount The _amount to be minted
           */
          function mint(address _account, uint256 _amount) public onlyOwner {
              super._mint(_account, _amount);
          }
          /**
           * @notice Burns `_amount` of tokens from the `_account` address
           * @param _account The address from which the tokens will be burned
           * @param _amount The _amount to be burned
           */
          function burnFrom(address _account, uint256 _amount) public onlyOwner {
              uint256 currentAllowance = allowance(_account, _msgSender());
              require(
                  currentAllowance >= _amount,
                  "ERC20: burn amount exceeds allowance"
              );
              unchecked {
                  _approve(_account, _msgSender(), currentAllowance - _amount);
              }
              _burn(_account, _amount);
          }
          /// @notice Pauses the contract
          function pause() public onlyOwner {
              super._pause();
          }
          /// @notice Unpauses the contract
          function unpause() public onlyOwner {
              super._unpause();
          }
          function _beforeTokenTransfer(
              address from,
              address to,
              uint256 _amount
          ) internal virtual override {
              super._beforeTokenTransfer(from, to, _amount);
              require(!paused(), "WrappedToken: token transfer while paused");
          }
          function decimals() public view virtual override returns (uint8) {
              return _decimals;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      /**
       * @dev Interface of the ERC2612 standard as defined in the EIP.
       *
       * Adds the {permit} method, which can be used to change one's
       * {IERC20-allowance} without having to send a transaction, by signing a
       * message. This allows users to spend tokens without having to hold Ether.
       *
       * See https://eips.ethereum.org/EIPS/eip-2612.
       */
      interface IERC2612Permit {
          /**
           * @dev Sets `_amount` 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:
           *
           * - `_owner` cannot be the zero address.
           * - `_spender` cannot be the zero address.
           * - `_deadline` must be a timestamp in the future.
           * - `_v`, `_r` and `_s` must be a valid `secp256k1` signature from `_owner`
           * over the EIP712-formatted function arguments.
           * - the signature must use ``_owner``'s current nonce (see {nonces}).
           *
           * For more information on the signature format, see the
           * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
           * section].
           */
          function permit(
              address _owner,
              address _spender,
              uint256 _amount,
              uint256 _deadline,
              uint8 _v,
              bytes32 _r,
              bytes32 _s
          ) external;
          /**
           * @dev Returns the current ERC2612 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);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "../libraries/LibRouter.sol";
      struct WrappedTokenParams {
          string name;
          string symbol;
          uint8 decimals;
      }
      interface IRouter {
          /// @notice An event emitted once a Lock transaction is executed
          event Lock(
              uint256 targetChain,
              address token,
              bytes receiver,
              uint256 amount,
              uint256 serviceFee
          );
          /// @notice An event emitted once a Burn transaction is executed
          event Burn(
              uint256 targetChain,
              address token,
              uint256 amount,
              bytes receiver
          );
          /// @notice An event emitted once an Unlock transaction is executed
          event Unlock(
              uint256 sourceChain,
              bytes transactionId,
              address token,
              uint256 amount,
              address receiver,
              uint256 serviceFee
          );
          /// @notice An even emitted once a Mint transaction is executed
          event Mint(
              uint256 sourceChain,
              bytes transactionId,
              address token,
              uint256 amount,
              address receiver
          );
          /// @notice An event emitted once a new wrapped token is deployed by the contract
          event WrappedTokenDeployed(
              uint256 sourceChain,
              bytes nativeToken,
              address wrappedToken
          );
          /// @notice An event emitted once a native token is updated
          event NativeTokenUpdated(address token, uint256 serviceFee, bool status);
          function initRouter() external;
          function hashesUsed(bytes32 _ethHash) external view returns (bool);
          function nativeTokensCount() external view returns (uint256);
          function nativeTokenAt(uint256 _index) external view returns (address);
          function lock(
              uint256 _targetChain,
              address _nativeToken,
              uint256 _amount,
              bytes memory _receiver
          ) external;
          function lockWithPermit(
              uint256 _targetChain,
              address _nativeToken,
              uint256 _amount,
              bytes memory _receiver,
              uint256 _deadline,
              uint8 _v,
              bytes32 _r,
              bytes32 _s
          ) external;
          function unlock(
              uint256 _sourceChain,
              bytes memory _transactionId,
              address _nativeToken,
              uint256 _amount,
              address _receiver,
              bytes[] calldata _signatures
          ) external;
          function burn(
              uint256 _targetChain,
              address _wrappedToken,
              uint256 _amount,
              bytes memory _receiver
          ) external;
          function burnWithPermit(
              uint256 _targetChain,
              address _wrappedToken,
              uint256 _amount,
              bytes memory _receiver,
              uint256 _deadline,
              uint8 _v,
              bytes32 _r,
              bytes32 _s
          ) external;
          function mint(
              uint256 _sourceChain,
              bytes memory _transactionId,
              address _wrappedToken,
              address _receiver,
              uint256 _amount,
              bytes[] calldata _signatures
          ) external;
          function deployWrappedToken(
              uint256 _sourceChain,
              bytes memory _nativeToken,
              WrappedTokenParams memory _tokenParams
          ) external;
          function updateNativeToken(
              address _nativeToken,
              uint256 _serviceFee,
              bool _status
          ) external;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "../interfaces/IDiamondCut.sol";
      library LibDiamond {
          bytes32 constant DIAMOND_STORAGE_POSITION =
              keccak256("diamond.standard.diamond.storage");
          struct FacetAddressAndPosition {
              address facetAddress;
              uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
          }
          struct FacetFunctionSelectors {
              bytes4[] functionSelectors;
              uint16 facetAddressPosition; // position of facetAddress in facetAddresses array
          }
          struct DiamondStorage {
              // maps function selector to the facet address and
              // the position of the selector in the facetFunctionSelectors.selectors array
              mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
              // maps facet addresses to function selectors
              mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
              // facet addresses
              address[] facetAddresses;
              // Used to query if a contract implements an interface.
              // Used to implement ERC-165.
              mapping(bytes4 => bool) supportedInterfaces;
              // owner of the contract
              address contractOwner;
          }
          function diamondStorage()
              internal
              pure
              returns (DiamondStorage storage ds)
          {
              bytes32 position = DIAMOND_STORAGE_POSITION;
              assembly {
                  ds.slot := position
              }
          }
          event OwnershipTransferred(
              address indexed previousOwner,
              address indexed newOwner
          );
          function setContractOwner(address _newOwner) internal {
              DiamondStorage storage ds = diamondStorage();
              address previousOwner = ds.contractOwner;
              ds.contractOwner = _newOwner;
              emit OwnershipTransferred(previousOwner, _newOwner);
          }
          function contractOwner() internal view returns (address contractOwner_) {
              contractOwner_ = diamondStorage().contractOwner;
          }
          function enforceIsContractOwner() internal view {
              require(
                  msg.sender == diamondStorage().contractOwner,
                  "LibDiamond: Must be contract owner"
              );
          }
          event DiamondCut(
              IDiamondCut.FacetCut[] _diamondCut,
              address _init,
              bytes _calldata
          );
          // Internal function version of diamondCut
          function diamondCut(
              IDiamondCut.FacetCut[] memory _diamondCut,
              address _init,
              bytes memory _calldata
          ) internal {
              for (
                  uint256 facetIndex;
                  facetIndex < _diamondCut.length;
                  facetIndex++
              ) {
                  IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
                  if (action == IDiamondCut.FacetCutAction.Add) {
                      addFunctions(
                          _diamondCut[facetIndex].facetAddress,
                          _diamondCut[facetIndex].functionSelectors
                      );
                  } else if (action == IDiamondCut.FacetCutAction.Replace) {
                      replaceFunctions(
                          _diamondCut[facetIndex].facetAddress,
                          _diamondCut[facetIndex].functionSelectors
                      );
                  } else if (action == IDiamondCut.FacetCutAction.Remove) {
                      removeFunctions(
                          _diamondCut[facetIndex].facetAddress,
                          _diamondCut[facetIndex].functionSelectors
                      );
                  } else {
                      revert("LibDiamondCut: Incorrect FacetCutAction");
                  }
              }
              emit DiamondCut(_diamondCut, _init, _calldata);
              initializeDiamondCut(_init, _calldata);
          }
          function addFunctions(
              address _facetAddress,
              bytes4[] memory _functionSelectors
          ) internal {
              require(
                  _functionSelectors.length > 0,
                  "LibDiamondCut: No selectors in facet to cut"
              );
              DiamondStorage storage ds = diamondStorage();
              // uint16 selectorCount = uint16(diamondStorage().selectors.length);
              require(
                  _facetAddress != address(0),
                  "LibDiamondCut: Add facet can't be address(0)"
              );
              uint16 selectorPosition = uint16(
                  ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
              );
              // add new facet address if it does not exist
              if (selectorPosition == 0) {
                  enforceHasContractCode(
                      _facetAddress,
                      "LibDiamondCut: New facet has no code"
                  );
                  ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition = uint16(ds.facetAddresses.length);
                  ds.facetAddresses.push(_facetAddress);
              }
              for (
                  uint256 selectorIndex;
                  selectorIndex < _functionSelectors.length;
                  selectorIndex++
              ) {
                  bytes4 selector = _functionSelectors[selectorIndex];
                  address oldFacetAddress = ds
                      .selectorToFacetAndPosition[selector]
                      .facetAddress;
                  require(
                      oldFacetAddress == address(0),
                      "LibDiamondCut: Can't add function that already exists"
                  );
                  addFunction(ds, selector, selectorPosition, _facetAddress);
                  selectorPosition++;
              }
          }
          function replaceFunctions(
              address _facetAddress,
              bytes4[] memory _functionSelectors
          ) internal {
              require(
                  _functionSelectors.length > 0,
                  "LibDiamondCut: No selectors in facet to cut"
              );
              DiamondStorage storage ds = diamondStorage();
              require(
                  _facetAddress != address(0),
                  "LibDiamondCut: Add facet can't be address(0)"
              );
              uint16 selectorPosition = uint16(
                  ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
              );
              // add new facet address if it does not exist
              if (selectorPosition == 0) {
                  enforceHasContractCode(
                      _facetAddress,
                      "LibDiamondCut: New facet has no code"
                  );
                  ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition = uint16(ds.facetAddresses.length);
                  ds.facetAddresses.push(_facetAddress);
              }
              for (
                  uint256 selectorIndex;
                  selectorIndex < _functionSelectors.length;
                  selectorIndex++
              ) {
                  bytes4 selector = _functionSelectors[selectorIndex];
                  address oldFacetAddress = ds
                      .selectorToFacetAndPosition[selector]
                      .facetAddress;
                  require(
                      oldFacetAddress != _facetAddress,
                      "LibDiamondCut: Can't replace function with same function"
                  );
                  removeFunction(ds, oldFacetAddress, selector);
                  // add function
                  addFunction(ds, selector, selectorPosition, _facetAddress);
                  selectorPosition++;
              }
          }
          function removeFunctions(
              address _facetAddress,
              bytes4[] memory _functionSelectors
          ) internal {
              require(
                  _functionSelectors.length > 0,
                  "LibDiamondCut: No selectors in facet to cut"
              );
              DiamondStorage storage ds = diamondStorage();
              // if function does not exist then do nothing and return
              require(
                  _facetAddress == address(0),
                  "LibDiamondCut: Remove facet address must be address(0)"
              );
              for (
                  uint256 selectorIndex;
                  selectorIndex < _functionSelectors.length;
                  selectorIndex++
              ) {
                  bytes4 selector = _functionSelectors[selectorIndex];
                  address oldFacetAddress = ds
                      .selectorToFacetAndPosition[selector]
                      .facetAddress;
                  removeFunction(ds, oldFacetAddress, selector);
              }
          }
          function addFunction(
              DiamondStorage storage ds,
              bytes4 _selector,
              uint16 _selectorPosition,
              address _facetAddress
          ) internal {
              ds
                  .selectorToFacetAndPosition[_selector]
                  .functionSelectorPosition = _selectorPosition;
              ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(
                  _selector
              );
              ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
          }
          function removeFunction(
              DiamondStorage storage ds,
              address _facetAddress,
              bytes4 _selector
          ) internal {
              require(
                  _facetAddress != address(0),
                  "LibDiamondCut: Can't remove function that doesn't exist"
              );
              // an immutable function is a function defined directly in a diamond
              require(
                  _facetAddress != address(this),
                  "LibDiamondCut: Can't remove immutable function"
              );
              // replace selector with last selector, then delete last selector
              uint256 selectorPosition = ds
                  .selectorToFacetAndPosition[_selector]
                  .functionSelectorPosition;
              uint256 lastSelectorPosition = ds
                  .facetFunctionSelectors[_facetAddress]
                  .functionSelectors
                  .length - 1;
              // if not the same then replace _selector with lastSelector
              if (selectorPosition != lastSelectorPosition) {
                  bytes4 lastSelector = ds
                      .facetFunctionSelectors[_facetAddress]
                      .functionSelectors[lastSelectorPosition];
                  ds.facetFunctionSelectors[_facetAddress].functionSelectors[
                          selectorPosition
                      ] = lastSelector;
                  ds
                      .selectorToFacetAndPosition[lastSelector]
                      .functionSelectorPosition = uint16(selectorPosition);
              }
              // delete the last selector
              ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
              delete ds.selectorToFacetAndPosition[_selector];
              // if no more selectors for facet address then delete the facet address
              if (lastSelectorPosition == 0) {
                  // replace facet address with last facet address and delete last facet address
                  uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
                  uint256 facetAddressPosition = ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition;
                  if (facetAddressPosition != lastFacetAddressPosition) {
                      address lastFacetAddress = ds.facetAddresses[
                          lastFacetAddressPosition
                      ];
                      ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                      ds
                          .facetFunctionSelectors[lastFacetAddress]
                          .facetAddressPosition = uint16(facetAddressPosition);
                  }
                  ds.facetAddresses.pop();
                  delete ds
                      .facetFunctionSelectors[_facetAddress]
                      .facetAddressPosition;
              }
          }
          function initializeDiamondCut(address _init, bytes memory _calldata)
              internal
          {
              if (_init == address(0)) {
                  require(
                      _calldata.length == 0,
                      "LibDiamondCut: _init is address(0) but_calldata is not empty"
                  );
              } else {
                  require(
                      _calldata.length > 0,
                      "LibDiamondCut: _calldata is empty but _init is not address(0)"
                  );
                  if (_init != address(this)) {
                      enforceHasContractCode(
                          _init,
                          "LibDiamondCut: _init address has no code"
                      );
                  }
                  (bool success, bytes memory error) = _init.delegatecall(_calldata);
                  if (!success) {
                      if (error.length > 0) {
                          // bubble up the error
                          revert(string(error));
                      } else {
                          revert("LibDiamondCut: _init function reverted");
                      }
                  }
              }
          }
          function enforceHasContractCode(
              address _contract,
              string memory _errorMessage
          ) internal view {
              uint256 contractSize;
              assembly {
                  contractSize := extcodesize(_contract)
              }
              require(contractSize > 0, _errorMessage);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "./LibGovernance.sol";
      library LibFeeCalculator {
          bytes32 constant STORAGE_POSITION = keccak256("fee.calculator.storage");
          /// @notice Represents a fee calculator per token
          struct FeeCalculator {
              // The current service fee in percentage. Range is between 0 and Storage.precision
              uint256 serviceFeePercentage;
              // Total fees accrued since contract deployment
              uint256 feesAccrued;
              // Total fees accrued up to the last point a member claimed rewards
              uint256 previousAccrued;
              // Accumulates rewards on a per-member basis
              uint256 accumulator;
              // Total rewards claimed per member
              mapping(address => uint256) claimedRewardsPerAccount;
          }
          struct Storage {
              bool initialized;
              // Precision for every calculator's fee percentage.
              uint256 precision;
              // A mapping consisting of all token fee calculators
              mapping(address => FeeCalculator) nativeTokenFeeCalculators;
          }
          function feeCalculatorStorage() internal pure returns (Storage storage ds) {
              bytes32 position = STORAGE_POSITION;
              assembly {
                  ds.slot := position
              }
          }
          /// @return The current precision for service fee calculations of tokens
          function precision() internal view returns (uint256) {
              LibFeeCalculator.Storage storage fcs = feeCalculatorStorage();
              return fcs.precision;
          }
          /// @notice Sets the initial claimed rewards for new members for a given token
          /// @param _account The address of the new member
          /// @param _token The list of tokens
          function addNewMember(address _account, address _token) internal {
              LibFeeCalculator.Storage storage fcs = feeCalculatorStorage();
              FeeCalculator storage fc = fcs.nativeTokenFeeCalculators[_token];
              accrue(fc);
              fc.claimedRewardsPerAccount[_account] = fc.accumulator;
          }
          /// @notice Accumulate fees for token and claim reward for claimer
          /// @param _claimer The address of the claimer
          /// @param _token The target token
          /// @return The claimable amount
          function claimReward(address _claimer, address _token)
              internal
              returns (uint256)
          {
              LibFeeCalculator.Storage storage fcs = feeCalculatorStorage();
              FeeCalculator storage fc = fcs.nativeTokenFeeCalculators[_token];
              accrue(fc);
              uint256 claimableAmount = fc.accumulator -
                  fc.claimedRewardsPerAccount[_claimer];
              fc.claimedRewardsPerAccount[_claimer] = fc.accumulator;
              return claimableAmount;
          }
          /// @notice Distributes service fee for given token
          /// @param _token The target token
          /// @param _amount The amount to which the service fee will be calculated
          /// @return serviceFee The calculated service fee
          function distributeRewards(address _token, uint256 _amount)
              internal
              returns (uint256)
          {
              LibFeeCalculator.Storage storage fcs = feeCalculatorStorage();
              FeeCalculator storage fc = fcs.nativeTokenFeeCalculators[_token];
              uint256 serviceFee = (_amount * fc.serviceFeePercentage) /
                  fcs.precision;
              fc.feesAccrued = fc.feesAccrued + serviceFee;
              return serviceFee;
          }
          /// @notice Sets service fee for a token
          /// @param _token The target token
          /// @param _serviceFeePercentage The service fee percentage to be set
          function setServiceFee(address _token, uint256 _serviceFeePercentage)
              internal
          {
              LibFeeCalculator.Storage storage fcs = feeCalculatorStorage();
              require(
                  _serviceFeePercentage < fcs.precision,
                  "LibFeeCalculator: service fee percentage exceeds or equal to precision"
              );
              FeeCalculator storage ntfc = fcs.nativeTokenFeeCalculators[_token];
              ntfc.serviceFeePercentage = _serviceFeePercentage;
          }
          /// @notice Accrues fees to a fee calculator
          /// @param _fc The fee calculator
          /// @return The updated accumulator
          function accrue(FeeCalculator storage _fc) internal returns (uint256) {
              uint256 members = LibGovernance.membersCount();
              uint256 amount = (_fc.feesAccrued - _fc.previousAccrued) / members;
              _fc.previousAccrued += amount * members;
              _fc.accumulator = _fc.accumulator + amount;
              return _fc.accumulator;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
      library LibRouter {
          using EnumerableSet for EnumerableSet.AddressSet;
          bytes32 constant STORAGE_POSITION = keccak256("router.storage");
          struct Storage {
              bool initialized;
              // Storage for usability of given ethereum signed messages.
              // ethereumSignedMessage => true/false
              mapping(bytes32 => bool) hashesUsed;
              // Stores all supported native Tokens on this chain
              EnumerableSet.AddressSet nativeTokens;
          }
          function routerStorage() internal pure returns (Storage storage ds) {
              bytes32 position = STORAGE_POSITION;
              assembly {
                  ds.slot := position
              }
          }
          function updateNativeToken(address _nativeToken, bool _status) internal {
              Storage storage rs = routerStorage();
              if (_status) {
                  require(
                      rs.nativeTokens.add(_nativeToken),
                      "LibRouter: native token already added"
                  );
              } else {
                  require(
                      rs.nativeTokens.remove(_nativeToken),
                      "LibRouter: native token not found"
                  );
              }
          }
          /// @notice Returns the count of native token
          function nativeTokensCount() internal view returns (uint256) {
              Storage storage rs = routerStorage();
              return rs.nativeTokens.length();
          }
          /// @notice Returns the address of the native token at a given index
          function nativeTokenAt(uint256 _index) internal view returns (address) {
              Storage storage rs = routerStorage();
              return rs.nativeTokens.at(_index);
          }
          /// @notice Returns true/false depending on whether a given native token is found
          function containsNativeToken(address _nativeToken)
              internal
              view
              returns (bool)
          {
              Storage storage rs = routerStorage();
              return rs.nativeTokens.contains(_nativeToken);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
      import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
      library LibGovernance {
          using EnumerableSet for EnumerableSet.AddressSet;
          bytes32 constant STORAGE_POSITION = keccak256("governance.storage");
          struct Storage {
              bool initialized;
              // Set of active validators
              EnumerableSet.AddressSet membersSet;
              // A 1:1 map of active validators -> validator admin
              mapping(address => address) membersAdmins;
              // Precision for calculation of minimum amount of members signatures required
              uint256 precision;
              // Percentage for minimum amount of members signatures required
              uint256 percentage;
              // Admin of the contract
              address admin;
              // used to restrict certain functionality in case of an emergency stop
              bool paused;
          }
          function governanceStorage() internal pure returns (Storage storage gs) {
              bytes32 position = STORAGE_POSITION;
              assembly {
                  gs.slot := position
              }
          }
          /// @return Returns the admin
          function admin() internal view returns (address) {
              return governanceStorage().admin;
          }
          /// @return Returns true if the contract is paused, and false otherwise
          function paused() internal view returns (bool) {
              return governanceStorage().paused;
          }
          /// @return The current percentage for minimum amount of members signatures
          function percentage() internal view returns (uint256) {
              Storage storage gs = governanceStorage();
              return gs.percentage;
          }
          /// @return The current precision for minimum amount of members signatures
          function precision() internal view returns (uint256) {
              Storage storage gs = governanceStorage();
              return gs.precision;
          }
          function enforceNotPaused() internal view {
              require(!governanceStorage().paused, "LibGovernance: paused");
          }
          function enforcePaused() internal view {
              require(governanceStorage().paused, "LibGovernance: not paused");
          }
          function updateAdmin(address _newAdmin) internal {
              Storage storage ds = governanceStorage();
              ds.admin = _newAdmin;
          }
          function pause() internal {
              enforceNotPaused();
              Storage storage ds = governanceStorage();
              ds.paused = true;
          }
          function unpause() internal {
              enforcePaused();
              Storage storage ds = governanceStorage();
              ds.paused = false;
          }
          function updateMembersPercentage(uint256 _newPercentage) internal {
              Storage storage gs = governanceStorage();
              require(_newPercentage != 0, "LibGovernance: percentage must not be 0");
              require(
                  _newPercentage < gs.precision,
                  "LibGovernance: percentage must be less than precision"
              );
              gs.percentage = _newPercentage;
          }
          /// @notice Adds/removes a validator from the member set
          function updateMember(address _account, bool _status) internal {
              Storage storage gs = governanceStorage();
              if (_status) {
                  require(
                      gs.membersSet.add(_account),
                      "LibGovernance: Account already added"
                  );
              } else if (!_status) {
                  require(
                      LibGovernance.membersCount() > 1,
                      "LibGovernance: contract would become memberless"
                  );
                  require(
                      gs.membersSet.remove(_account),
                      "LibGovernance: Account is not a member"
                  );
              }
          }
          function updateMemberAdmin(address _account, address _admin) internal {
              governanceStorage().membersAdmins[_account] = _admin;
          }
          /// @notice Returns true/false depending on whether a given address is member or not
          function isMember(address _member) internal view returns (bool) {
              Storage storage gs = governanceStorage();
              return gs.membersSet.contains(_member);
          }
          /// @notice Returns the count of the members
          function membersCount() internal view returns (uint256) {
              Storage storage gs = governanceStorage();
              return gs.membersSet.length();
          }
          /// @notice Returns the address of a member at a given index
          function memberAt(uint256 _index) internal view returns (address) {
              Storage storage gs = governanceStorage();
              return gs.membersSet.at(_index);
          }
          /// @notice Returns the admin of the member
          function memberAdmin(address _account) internal view returns (address) {
              Storage storage gs = governanceStorage();
              return gs.membersAdmins[_account];
          }
          /// @notice Checks if the provided amount of signatures is enough for submission
          function hasValidSignaturesLength(uint256 _n) internal view returns (bool) {
              Storage storage gs = governanceStorage();
              uint256 members = gs.membersSet.length();
              if (_n > members) {
                  return false;
              }
              uint256 mulMembersPercentage = members * gs.percentage;
              uint256 requiredSignaturesLength = mulMembersPercentage / gs.precision;
              if (mulMembersPercentage % gs.precision != 0) {
                  requiredSignaturesLength++;
              }
              return _n >= requiredSignaturesLength;
          }
          /// @notice Validates the provided signatures length
          function validateSignaturesLength(uint256 _n) internal view {
              require(
                  hasValidSignaturesLength(_n),
                  "LibGovernance: Invalid number of signatures"
              );
          }
          /// @notice Validates the provided signatures against the member set
          function validateSignatures(bytes32 _ethHash, bytes[] calldata _signatures)
              internal
              view
          {
              address[] memory signers = new address[](_signatures.length);
              for (uint256 i = 0; i < _signatures.length; i++) {
                  address signer = ECDSA.recover(_ethHash, _signatures[i]);
                  require(isMember(signer), "LibGovernance: invalid signer");
                  for (uint256 j = 0; j < i; j++) {
                      require(
                          signer != signers[j],
                          "LibGovernance: duplicate signatures"
                      );
                  }
                  signers[i] = signer;
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(
              address sender,
              address recipient,
              uint256 amount
          ) external returns (bool);
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^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;
              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");
              (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");
              (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");
              (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");
              (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
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * By default, the owner account will be the one that deploys the contract. This
       * can later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor() {
              _setOwner(_msgSender());
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              require(owner() == _msgSender(), "Ownable: caller is not the owner");
              _;
          }
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _setOwner(address(0));
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              _setOwner(newOwner);
          }
          function _setOwner(address newOwner) private {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "./draft-IERC20Permit.sol";
      import "../ERC20.sol";
      import "../../../utils/cryptography/draft-EIP712.sol";
      import "../../../utils/cryptography/ECDSA.sol";
      import "../../../utils/Counters.sol";
      /**
       * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
       * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
       *
       * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
       * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
       * need to send a transaction, and thus is not required to hold Ether at all.
       *
       * _Available since v3.4._
       */
      abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
          using Counters for Counters.Counter;
          mapping(address => Counters.Counter) private _nonces;
          // solhint-disable-next-line var-name-mixedcase
          bytes32 private immutable _PERMIT_TYPEHASH =
              keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
          /**
           * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
           *
           * It's a good idea to use the same `name` that is defined as the ERC20 token name.
           */
          constructor(string memory name) EIP712(name, "1") {}
          /**
           * @dev See {IERC20Permit-permit}.
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) public virtual override {
              require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
              bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
              bytes32 hash = _hashTypedDataV4(structHash);
              address signer = ECDSA.recover(hash, v, r, s);
              require(signer == owner, "ERC20Permit: invalid signature");
              _approve(owner, spender, value);
          }
          /**
           * @dev See {IERC20Permit-nonces}.
           */
          function nonces(address owner) public view virtual override returns (uint256) {
              return _nonces[owner].current();
          }
          /**
           * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view override returns (bytes32) {
              return _domainSeparatorV4();
          }
          /**
           * @dev "Consume a nonce": return the current value and increment.
           *
           * _Available since v4.1._
           */
          function _useNonce(address owner) internal virtual returns (uint256 current) {
              Counters.Counter storage nonce = _nonces[owner];
              current = nonce.current();
              nonce.increment();
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../utils/Context.sol";
      /**
       * @dev Contract module which allows children to implement an emergency stop
       * mechanism that can be triggered by an authorized account.
       *
       * This module is used through inheritance. It will make available the
       * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
       * the functions of your contract. Note that they will not be pausable by
       * simply including this module, only once the modifiers are put in place.
       */
      abstract contract Pausable is Context {
          /**
           * @dev Emitted when the pause is triggered by `account`.
           */
          event Paused(address account);
          /**
           * @dev Emitted when the pause is lifted by `account`.
           */
          event Unpaused(address account);
          bool private _paused;
          /**
           * @dev Initializes the contract in unpaused state.
           */
          constructor() {
              _paused = false;
          }
          /**
           * @dev Returns true if the contract is paused, and false otherwise.
           */
          function paused() public view virtual returns (bool) {
              return _paused;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          modifier whenNotPaused() {
              require(!paused(), "Pausable: paused");
              _;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          modifier whenPaused() {
              require(paused(), "Pausable: not paused");
              _;
          }
          /**
           * @dev Triggers stopped state.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          function _pause() internal virtual whenNotPaused {
              _paused = true;
              emit Paused(_msgSender());
          }
          /**
           * @dev Returns to normal state.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          function _unpause() internal virtual whenPaused {
              _paused = false;
              emit Unpaused(_msgSender());
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /*
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
       * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
       *
       * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
       * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
       * need to send a transaction, and thus is not required to hold Ether at all.
       */
      interface IERC20Permit {
          /**
           * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
           * given ``owner``'s signed approval.
           *
           * IMPORTANT: The same issues {IERC20-approve} has related to transaction
           * ordering also apply here.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `deadline` must be a timestamp in the future.
           * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
           * over the EIP712-formatted function arguments.
           * - the signature must use ``owner``'s current nonce (see {nonces}).
           *
           * For more information on the signature format, see the
           * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
           * section].
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
          /**
           * @dev Returns the current nonce for `owner`. This value must be
           * included whenever a signature is generated for {permit}.
           *
           * Every successful call to {permit} increases ``owner``'s nonce by one. This
           * prevents a signature from being used multiple times.
           */
          function nonces(address owner) external view returns (uint256);
          /**
           * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view returns (bytes32);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "./IERC20.sol";
      import "./extensions/IERC20Metadata.sol";
      import "../../utils/Context.sol";
      /**
       * @dev Implementation of the {IERC20} interface.
       *
       * This implementation is agnostic to the way tokens are created. This means
       * that a supply mechanism has to be added in a derived contract using {_mint}.
       * For a generic mechanism see {ERC20PresetMinterPauser}.
       *
       * TIP: For a detailed writeup see our guide
       * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
       * to implement supply mechanisms].
       *
       * We have followed general OpenZeppelin guidelines: functions revert instead
       * of returning `false` on failure. This behavior is nonetheless conventional
       * and does not conflict with the expectations of ERC20 applications.
       *
       * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
       * This allows applications to reconstruct the allowance for all accounts just
       * by listening to said events. Other implementations of the EIP may not emit
       * these events, as it isn't required by the specification.
       *
       * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
       * functions have been added to mitigate the well-known issues around setting
       * allowances. See {IERC20-approve}.
       */
      contract ERC20 is Context, IERC20, IERC20Metadata {
          mapping(address => uint256) private _balances;
          mapping(address => mapping(address => uint256)) private _allowances;
          uint256 private _totalSupply;
          string private _name;
          string private _symbol;
          /**
           * @dev Sets the values for {name} and {symbol}.
           *
           * The default value of {decimals} is 18. To select a different value for
           * {decimals} you should overload it.
           *
           * All two of these values are immutable: they can only be set once during
           * construction.
           */
          constructor(string memory name_, string memory symbol_) {
              _name = name_;
              _symbol = symbol_;
          }
          /**
           * @dev Returns the name of the token.
           */
          function name() public view virtual override returns (string memory) {
              return _name;
          }
          /**
           * @dev Returns the symbol of the token, usually a shorter version of the
           * name.
           */
          function symbol() public view virtual override returns (string memory) {
              return _symbol;
          }
          /**
           * @dev Returns the number of decimals used to get its user representation.
           * For example, if `decimals` equals `2`, a balance of `505` tokens should
           * be displayed to a user as `5,05` (`505 / 10 ** 2`).
           *
           * Tokens usually opt for a value of 18, imitating the relationship between
           * Ether and Wei. This is the value {ERC20} uses, unless this function is
           * overridden;
           *
           * NOTE: This information is only used for _display_ purposes: it in
           * no way affects any of the arithmetic of the contract, including
           * {IERC20-balanceOf} and {IERC20-transfer}.
           */
          function decimals() public view virtual override returns (uint8) {
              return 18;
          }
          /**
           * @dev See {IERC20-totalSupply}.
           */
          function totalSupply() public view virtual override returns (uint256) {
              return _totalSupply;
          }
          /**
           * @dev See {IERC20-balanceOf}.
           */
          function balanceOf(address account) public view virtual override returns (uint256) {
              return _balances[account];
          }
          /**
           * @dev See {IERC20-transfer}.
           *
           * Requirements:
           *
           * - `recipient` cannot be the zero address.
           * - the caller must have a balance of at least `amount`.
           */
          function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
              _transfer(_msgSender(), recipient, amount);
              return true;
          }
          /**
           * @dev See {IERC20-allowance}.
           */
          function allowance(address owner, address spender) public view virtual override returns (uint256) {
              return _allowances[owner][spender];
          }
          /**
           * @dev See {IERC20-approve}.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           */
          function approve(address spender, uint256 amount) public virtual override returns (bool) {
              _approve(_msgSender(), spender, amount);
              return true;
          }
          /**
           * @dev See {IERC20-transferFrom}.
           *
           * Emits an {Approval} event indicating the updated allowance. This is not
           * required by the EIP. See the note at the beginning of {ERC20}.
           *
           * Requirements:
           *
           * - `sender` and `recipient` cannot be the zero address.
           * - `sender` must have a balance of at least `amount`.
           * - the caller must have allowance for ``sender``'s tokens of at least
           * `amount`.
           */
          function transferFrom(
              address sender,
              address recipient,
              uint256 amount
          ) public virtual override returns (bool) {
              _transfer(sender, recipient, amount);
              uint256 currentAllowance = _allowances[sender][_msgSender()];
              require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
              unchecked {
                  _approve(sender, _msgSender(), currentAllowance - amount);
              }
              return true;
          }
          /**
           * @dev Atomically increases the allowance granted to `spender` by the caller.
           *
           * This is an alternative to {approve} that can be used as a mitigation for
           * problems described in {IERC20-approve}.
           *
           * Emits an {Approval} event indicating the updated allowance.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           */
          function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
              _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
              return true;
          }
          /**
           * @dev Atomically decreases the allowance granted to `spender` by the caller.
           *
           * This is an alternative to {approve} that can be used as a mitigation for
           * problems described in {IERC20-approve}.
           *
           * Emits an {Approval} event indicating the updated allowance.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `spender` must have allowance for the caller of at least
           * `subtractedValue`.
           */
          function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
              uint256 currentAllowance = _allowances[_msgSender()][spender];
              require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
              unchecked {
                  _approve(_msgSender(), spender, currentAllowance - subtractedValue);
              }
              return true;
          }
          /**
           * @dev Moves `amount` of tokens from `sender` to `recipient`.
           *
           * This internal function is equivalent to {transfer}, and can be used to
           * e.g. implement automatic token fees, slashing mechanisms, etc.
           *
           * Emits a {Transfer} event.
           *
           * Requirements:
           *
           * - `sender` cannot be the zero address.
           * - `recipient` cannot be the zero address.
           * - `sender` must have a balance of at least `amount`.
           */
          function _transfer(
              address sender,
              address recipient,
              uint256 amount
          ) internal virtual {
              require(sender != address(0), "ERC20: transfer from the zero address");
              require(recipient != address(0), "ERC20: transfer to the zero address");
              _beforeTokenTransfer(sender, recipient, amount);
              uint256 senderBalance = _balances[sender];
              require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
              unchecked {
                  _balances[sender] = senderBalance - amount;
              }
              _balances[recipient] += amount;
              emit Transfer(sender, recipient, amount);
              _afterTokenTransfer(sender, recipient, amount);
          }
          /** @dev Creates `amount` tokens and assigns them to `account`, increasing
           * the total supply.
           *
           * Emits a {Transfer} event with `from` set to the zero address.
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           */
          function _mint(address account, uint256 amount) internal virtual {
              require(account != address(0), "ERC20: mint to the zero address");
              _beforeTokenTransfer(address(0), account, amount);
              _totalSupply += amount;
              _balances[account] += amount;
              emit Transfer(address(0), account, amount);
              _afterTokenTransfer(address(0), account, amount);
          }
          /**
           * @dev Destroys `amount` tokens from `account`, reducing the
           * total supply.
           *
           * Emits a {Transfer} event with `to` set to the zero address.
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           * - `account` must have at least `amount` tokens.
           */
          function _burn(address account, uint256 amount) internal virtual {
              require(account != address(0), "ERC20: burn from the zero address");
              _beforeTokenTransfer(account, address(0), amount);
              uint256 accountBalance = _balances[account];
              require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
              unchecked {
                  _balances[account] = accountBalance - amount;
              }
              _totalSupply -= amount;
              emit Transfer(account, address(0), amount);
              _afterTokenTransfer(account, address(0), amount);
          }
          /**
           * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
           *
           * This internal function is equivalent to `approve`, and can be used to
           * e.g. set automatic allowances for certain subsystems, etc.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `owner` cannot be the zero address.
           * - `spender` cannot be the zero address.
           */
          function _approve(
              address owner,
              address spender,
              uint256 amount
          ) internal virtual {
              require(owner != address(0), "ERC20: approve from the zero address");
              require(spender != address(0), "ERC20: approve to the zero address");
              _allowances[owner][spender] = amount;
              emit Approval(owner, spender, amount);
          }
          /**
           * @dev Hook that is called before any transfer of tokens. This includes
           * minting and burning.
           *
           * Calling conditions:
           *
           * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
           * will be transferred to `to`.
           * - when `from` is zero, `amount` tokens will be minted for `to`.
           * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
           * - `from` and `to` are never both zero.
           *
           * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
           */
          function _beforeTokenTransfer(
              address from,
              address to,
              uint256 amount
          ) internal virtual {}
          /**
           * @dev Hook that is called after any transfer of tokens. This includes
           * minting and burning.
           *
           * Calling conditions:
           *
           * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
           * has been transferred to `to`.
           * - when `from` is zero, `amount` tokens have been minted for `to`.
           * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
           * - `from` and `to` are never both zero.
           *
           * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
           */
          function _afterTokenTransfer(
              address from,
              address to,
              uint256 amount
          ) internal virtual {}
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "./ECDSA.sol";
      /**
       * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
       *
       * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
       * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
       * they need in their contracts using a combination of `abi.encode` and `keccak256`.
       *
       * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
       * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
       * ({_hashTypedDataV4}).
       *
       * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
       * the chain id to protect against replay attacks on an eventual fork of the chain.
       *
       * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
       * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
       *
       * _Available since v3.4._
       */
      abstract contract EIP712 {
          /* solhint-disable var-name-mixedcase */
          // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
          // invalidate the cached domain separator if the chain id changes.
          bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
          uint256 private immutable _CACHED_CHAIN_ID;
          bytes32 private immutable _HASHED_NAME;
          bytes32 private immutable _HASHED_VERSION;
          bytes32 private immutable _TYPE_HASH;
          /* solhint-enable var-name-mixedcase */
          /**
           * @dev Initializes the domain separator and parameter caches.
           *
           * The meaning of `name` and `version` is specified in
           * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
           *
           * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
           * - `version`: the current major version of the signing domain.
           *
           * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
           * contract upgrade].
           */
          constructor(string memory name, string memory version) {
              bytes32 hashedName = keccak256(bytes(name));
              bytes32 hashedVersion = keccak256(bytes(version));
              bytes32 typeHash = keccak256(
                  "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
              );
              _HASHED_NAME = hashedName;
              _HASHED_VERSION = hashedVersion;
              _CACHED_CHAIN_ID = block.chainid;
              _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
              _TYPE_HASH = typeHash;
          }
          /**
           * @dev Returns the domain separator for the current chain.
           */
          function _domainSeparatorV4() internal view returns (bytes32) {
              if (block.chainid == _CACHED_CHAIN_ID) {
                  return _CACHED_DOMAIN_SEPARATOR;
              } else {
                  return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
              }
          }
          function _buildDomainSeparator(
              bytes32 typeHash,
              bytes32 nameHash,
              bytes32 versionHash
          ) private view returns (bytes32) {
              return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
          }
          /**
           * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
           * function returns the hash of the fully encoded EIP712 message for this domain.
           *
           * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
           *
           * ```solidity
           * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
           *     keccak256("Mail(address to,string contents)"),
           *     mailTo,
           *     keccak256(bytes(mailContents))
           * )));
           * address signer = ECDSA.recover(digest, signature);
           * ```
           */
          function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
              return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
       *
       * These functions can be used to verify that a message was signed by the holder
       * of the private keys of a given address.
       */
      library ECDSA {
          /**
           * @dev Returns the address that signed a hashed message (`hash`) with
           * `signature`. This address can then be used for verification purposes.
           *
           * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
           * this function rejects them by requiring the `s` value to be in the lower
           * half order, and the `v` value to be either 27 or 28.
           *
           * IMPORTANT: `hash` _must_ be the result of a hash operation for the
           * verification to be secure: it is possible to craft signatures that
           * recover to arbitrary addresses for non-hashed data. A safe way to ensure
           * this is by receiving a hash of the original message (which may otherwise
           * be too long), and then calling {toEthSignedMessageHash} on it.
           *
           * Documentation for signature generation:
           * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
           * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
           */
          function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
              // Check the signature length
              // - case 65: r,s,v signature (standard)
              // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
              if (signature.length == 65) {
                  bytes32 r;
                  bytes32 s;
                  uint8 v;
                  // ecrecover takes the signature parameters, and the only way to get them
                  // currently is to use assembly.
                  assembly {
                      r := mload(add(signature, 0x20))
                      s := mload(add(signature, 0x40))
                      v := byte(0, mload(add(signature, 0x60)))
                  }
                  return recover(hash, v, r, s);
              } else if (signature.length == 64) {
                  bytes32 r;
                  bytes32 vs;
                  // ecrecover takes the signature parameters, and the only way to get them
                  // currently is to use assembly.
                  assembly {
                      r := mload(add(signature, 0x20))
                      vs := mload(add(signature, 0x40))
                  }
                  return recover(hash, r, vs);
              } else {
                  revert("ECDSA: invalid signature length");
              }
          }
          /**
           * @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately.
           *
           * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
           *
           * _Available since v4.2._
           */
          function recover(
              bytes32 hash,
              bytes32 r,
              bytes32 vs
          ) internal pure returns (address) {
              bytes32 s;
              uint8 v;
              assembly {
                  s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
                  v := add(shr(255, vs), 27)
              }
              return recover(hash, v, r, s);
          }
          /**
           * @dev Overload of {ECDSA-recover} that receives the `v`, `r` and `s` signature fields separately.
           */
          function recover(
              bytes32 hash,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) internal pure returns (address) {
              // 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.
              require(
                  uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
                  "ECDSA: invalid signature 's' value"
              );
              require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");
              // If the signature is valid (and not malleable), return the signer address
              address signer = ecrecover(hash, v, r, s);
              require(signer != address(0), "ECDSA: invalid signature");
              return signer;
          }
          /**
           * @dev Returns an Ethereum Signed Message, created from a `hash`. This
           * produces hash corresponding to the one signed with the
           * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
           * JSON-RPC method as part of EIP-191.
           *
           * See {recover}.
           */
          function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
              // 32 is the length in bytes of hash,
              // enforced by the type signature above
              return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
      32", hash));
          }
          /**
           * @dev Returns an Ethereum Signed Typed Data, created from a
           * `domainSeparator` and a `structHash`. This produces hash corresponding
           * to the one signed with the
           * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
           * JSON-RPC method as part of EIP-712.
           *
           * See {recover}.
           */
          function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
              return keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Counters
       * @author Matt Condon (@shrugs)
       * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
       * of elements in a mapping, issuing ERC721 ids, or counting request ids.
       *
       * Include with `using Counters for Counters.Counter;`
       */
      library Counters {
          struct Counter {
              // This variable should never be directly accessed by users of the library: interactions must be restricted to
              // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
              // this feature: see https://github.com/ethereum/solidity/issues/4637
              uint256 _value; // default: 0
          }
          function current(Counter storage counter) internal view returns (uint256) {
              return counter._value;
          }
          function increment(Counter storage counter) internal {
              unchecked {
                  counter._value += 1;
              }
          }
          function decrement(Counter storage counter) internal {
              uint256 value = counter._value;
              require(value > 0, "Counter: decrement overflow");
              unchecked {
                  counter._value = value - 1;
              }
          }
          function reset(Counter storage counter) internal {
              counter._value = 0;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../IERC20.sol";
      /**
       * @dev Interface for the optional metadata functions from the ERC20 standard.
       *
       * _Available since v4.1._
       */
      interface IERC20Metadata is IERC20 {
          /**
           * @dev Returns the name of the token.
           */
          function name() external view returns (string memory);
          /**
           * @dev Returns the symbol of the token.
           */
          function symbol() external view returns (string memory);
          /**
           * @dev Returns the decimals places of the token.
           */
          function decimals() external view returns (uint8);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Library for managing
       * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
       * types.
       *
       * Sets have the following properties:
       *
       * - Elements are added, removed, and checked for existence in constant time
       * (O(1)).
       * - Elements are enumerated in O(n). No guarantees are made on the ordering.
       *
       * ```
       * contract Example {
       *     // Add the library methods
       *     using EnumerableSet for EnumerableSet.AddressSet;
       *
       *     // Declare a set state variable
       *     EnumerableSet.AddressSet private mySet;
       * }
       * ```
       *
       * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
       * and `uint256` (`UintSet`) are supported.
       */
      library EnumerableSet {
          // To implement this library for multiple types with as little code
          // repetition as possible, we write it in terms of a generic Set type with
          // bytes32 values.
          // The Set implementation uses private functions, and user-facing
          // implementations (such as AddressSet) are just wrappers around the
          // underlying Set.
          // This means that we can only create new EnumerableSets for types that fit
          // in bytes32.
          struct Set {
              // Storage of set values
              bytes32[] _values;
              // Position of the value in the `values` array, plus 1 because index 0
              // means a value is not in the set.
              mapping(bytes32 => uint256) _indexes;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function _add(Set storage set, bytes32 value) private returns (bool) {
              if (!_contains(set, value)) {
                  set._values.push(value);
                  // The value is stored at length-1, but we add 1 to all indexes
                  // and use 0 as a sentinel value
                  set._indexes[value] = set._values.length;
                  return true;
              } else {
                  return false;
              }
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function _remove(Set storage set, bytes32 value) private returns (bool) {
              // We read and store the value's index to prevent multiple reads from the same storage slot
              uint256 valueIndex = set._indexes[value];
              if (valueIndex != 0) {
                  // Equivalent to contains(set, value)
                  // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                  // the array, and then remove the last element (sometimes called as 'swap and pop').
                  // This modifies the order of the array, as noted in {at}.
                  uint256 toDeleteIndex = valueIndex - 1;
                  uint256 lastIndex = set._values.length - 1;
                  if (lastIndex != toDeleteIndex) {
                      bytes32 lastvalue = set._values[lastIndex];
                      // Move the last value to the index where the value to delete is
                      set._values[toDeleteIndex] = lastvalue;
                      // Update the index for the moved value
                      set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
                  }
                  // Delete the slot where the moved value was stored
                  set._values.pop();
                  // Delete the index for the deleted slot
                  delete set._indexes[value];
                  return true;
              } else {
                  return false;
              }
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function _contains(Set storage set, bytes32 value) private view returns (bool) {
              return set._indexes[value] != 0;
          }
          /**
           * @dev Returns the number of values on the set. O(1).
           */
          function _length(Set storage set) private view returns (uint256) {
              return set._values.length;
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function _at(Set storage set, uint256 index) private view returns (bytes32) {
              return set._values[index];
          }
          // Bytes32Set
          struct Bytes32Set {
              Set _inner;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
              return _add(set._inner, value);
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
              return _remove(set._inner, value);
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
              return _contains(set._inner, value);
          }
          /**
           * @dev Returns the number of values in the set. O(1).
           */
          function length(Bytes32Set storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
              return _at(set._inner, index);
          }
          // AddressSet
          struct AddressSet {
              Set _inner;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(AddressSet storage set, address value) internal returns (bool) {
              return _add(set._inner, bytes32(uint256(uint160(value))));
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(AddressSet storage set, address value) internal returns (bool) {
              return _remove(set._inner, bytes32(uint256(uint160(value))));
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(AddressSet storage set, address value) internal view returns (bool) {
              return _contains(set._inner, bytes32(uint256(uint160(value))));
          }
          /**
           * @dev Returns the number of values in the set. O(1).
           */
          function length(AddressSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function at(AddressSet storage set, uint256 index) internal view returns (address) {
              return address(uint160(uint256(_at(set._inner, index))));
          }
          // UintSet
          struct UintSet {
              Set _inner;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(UintSet storage set, uint256 value) internal returns (bool) {
              return _add(set._inner, bytes32(value));
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(UintSet storage set, uint256 value) internal returns (bool) {
              return _remove(set._inner, bytes32(value));
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(UintSet storage set, uint256 value) internal view returns (bool) {
              return _contains(set._inner, bytes32(value));
          }
          /**
           * @dev Returns the number of values on the set. O(1).
           */
          function length(UintSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function at(UintSet storage set, uint256 index) internal view returns (uint256) {
              return uint256(_at(set._inner, index));
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.3;
      interface IDiamondCut {
          enum FacetCutAction {
              Add,
              Replace,
              Remove
          }
          // Add=0, Replace=1, Remove=2
          struct FacetCut {
              address facetAddress;
              FacetCutAction action;
              bytes4[] functionSelectors;
          }
          /// @notice Add/replace/remove any number of functions and optionally execute
          ///         a function with delegatecall
          /// @param _diamondCut Contains the facet addresses and function selectors
          /// @param _init The address of the contract or facet to execute _calldata
          /// @param _calldata A function call, including function selector and arguments
          ///                  _calldata is executed with delegatecall on _init
          function diamondCut(
              FacetCut[] calldata _diamondCut,
              address _init,
              bytes calldata _calldata
          ) external;
          event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
      }