creation_sourcecode: // https://noderun.io
  // https://twitter.com/noderunAI
  // https://t.me/noderunAI
  
  pragma solidity >=0.5.0;
  
  interface RReceiverV2 {
      /**
       * @dev Called by the OFT contract when tokens are received from source chain.
       * @param _srcChainId The chain id of the source chain.
       * @param _srcAddress The address of the OFT token contract on the source chain.
       * @param _nonce The nonce of the transaction on the source chain.
       * @param _from The address of the account who calls the sendAndCall() on the source chain.
       * @param _amount The amount of tokens to transfer.
       * @param _payload Additional data with no specified format.
       */
      function onOFTReceived(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes32 _from, uint _amount, bytes calldata _payload) external;
  }
  
  // File: @openzeppelin/contracts/utils/introspection/IERC165.sol
  
  
  // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
  
  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);
  }
  
  // File: @openzeppelin/contracts/utils/introspection/ERC165.sol
  
  
  // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
  
  pragma solidity ^0.8.0;
  
  
  /**
   * @dev Implementation of the {IERC165} interface.
   *
   * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
   * for the additional interface id that will be supported. For example:
   *
   * ```solidity
   * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
   *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
   * }
   * ```
   *
   * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
   */
  abstract contract ERC165 is IERC165 {
      /**
       * @dev See {IERC165-supportsInterface}.
       */
      function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
          return interfaceId == type(IERC165).interfaceId;
      }
  }
  
  // File: contracts/NodeRun/token/oft/v2/interfaces/ICommonOFT.sol
  
  
  
  pragma solidity >=0.5.0;
  
  
  /**
   * @dev Interface of the R core standard
   */
  interface ICommonOFT is IERC165 {
  
      struct LzCallParams {
          address payable refundAddress;
          address zroPaymentAddress;
          bytes adapterParams;
      }
  
      /**
       * @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
       * _dstChainId - L0 defined chain id to send tokens too
       * _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
       * _amount - amount of the tokens to transfer
       * _useZro - indicates to use zro to pay L0 fees
       * _adapterParam - flexible bytes array to indicate messaging adapter services in L0
       */
      function estimateSendFee(uint16 _dstChainId, bytes32 _toAddress, uint _amount, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);
  
      function estimateSendAndCallFee(uint16 _dstChainId, bytes32 _toAddress, uint _amount, bytes calldata _payload, uint64 _dstGasForCall, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);
  
      /**
       * @dev returns the circulating amount of tokens on current chain
       */
      function circulatingSupply() external view returns (uint);
  
      /**
       * @dev returns the address of the ERC20 token
       */
      function token() external view returns (address);
  }
  
  // File: contracts/NodeRun/token/oft/v2/interfaces/RV2.sol
  
  
  
  pragma solidity >=0.5.0;
  
  
  /**
   * @dev Interface of the R core standard
   */
  interface RV2 is ICommonOFT {
  
      /**
       * @dev send `_amount` amount of token to (`_dstChainId`, `_toAddress`) from `_from`
       * `_from` the owner of token
       * `_dstChainId` the destination chain identifier
       * `_toAddress` can be any size depending on the `dstChainId`.
       * `_amount` the quantity of tokens in wei
       * `_refundAddress` the address NodeRun refunds if too much message fee is sent
       * `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (NodeRun Token)
       * `_adapterParams` is a flexible bytes array to indicate messaging adapter services
       */
      function sendFrom(address _from, uint16 _dstChainId, bytes32 _toAddress, uint _amount, LzCallParams calldata _callParams) external payable;
  
      function sendAndCall(address _from, uint16 _dstChainId, bytes32 _toAddress, uint _amount, bytes calldata _payload, uint64 _dstGasForCall, LzCallParams calldata _callParams) external payable;
  }
  
  // File: contracts/NodeRun/libraries/ExcessivelySafeCall.sol
  
  
  pragma solidity >=0.7.6;
  
  library ExcessivelySafeCall {
      uint constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
  
      /// @notice Use when you _really_ really _really_ don't trust the called
      /// contract. This prevents the called contract from causing reversion of
      /// the caller in as many ways as we can.
      /// @dev The main difference between this and a solidity low-level call is
      /// that we limit the number of bytes that the callee can cause to be
      /// copied to caller memory. This prevents stupid things like malicious
      /// contracts returning 10,000,000 bytes causing a local OOG when copying
      /// to memory.
      /// @param _target The address to call
      /// @param _gas The amount of gas to forward to the remote contract
      /// @param _maxCopy The maximum number of bytes of returndata to copy
      /// to memory.
      /// @param _calldata The data to send to the remote contract
      /// @return success and returndata, as `.call()`. Returndata is capped to
      /// `_maxCopy` bytes.
      function excessivelySafeCall(
          address _target,
          uint _gas,
          uint16 _maxCopy,
          bytes memory _calldata
      ) internal returns (bool, bytes memory) {
          // set up for assembly call
          uint _toCopy;
          bool _success;
          bytes memory _returnData = new bytes(_maxCopy);
          // dispatch message to recipient
          // by assembly calling "handle" function
          // we call via assembly to avoid memcopying a very large returndata
          // returned by a malicious contract
          assembly {
              _success := call(
                  _gas, // gas
                  _target, // recipient
                  0, // ether value
                  add(_calldata, 0x20), // inloc
                  mload(_calldata), // inlen
                  0, // outloc
                  0 // outlen
              )
              // limit our copy to 256 bytes
              _toCopy := returndatasize()
              if gt(_toCopy, _maxCopy) {
                  _toCopy := _maxCopy
              }
              // Store the length of the copied bytes
              mstore(_returnData, _toCopy)
              // copy the bytes from returndata[0:_toCopy]
              returndatacopy(add(_returnData, 0x20), 0, _toCopy)
          }
          return (_success, _returnData);
      }
  
      /// @notice Use when you _really_ really _really_ don't trust the called
      /// contract. This prevents the called contract from causing reversion of
      /// the caller in as many ways as we can.
      /// @dev The main difference between this and a solidity low-level call is
      /// that we limit the number of bytes that the callee can cause to be
      /// copied to caller memory. This prevents stupid things like malicious
      /// contracts returning 10,000,000 bytes causing a local OOG when copying
      /// to memory.
      /// @param _target The address to call
      /// @param _gas The amount of gas to forward to the remote contract
      /// @param _maxCopy The maximum number of bytes of returndata to copy
      /// to memory.
      /// @param _calldata The data to send to the remote contract
      /// @return success and returndata, as `.call()`. Returndata is capped to
      /// `_maxCopy` bytes.
      function excessivelySafeStaticCall(
          address _target,
          uint _gas,
          uint16 _maxCopy,
          bytes memory _calldata
      ) internal view returns (bool, bytes memory) {
          // set up for assembly call
          uint _toCopy;
          bool _success;
          bytes memory _returnData = new bytes(_maxCopy);
          // dispatch message to recipient
          // by assembly calling "handle" function
          // we call via assembly to avoid memcopying a very large returndata
          // returned by a malicious contract
          assembly {
              _success := staticcall(
                  _gas, // gas
                  _target, // recipient
                  add(_calldata, 0x20), // inloc
                  mload(_calldata), // inlen
                  0, // outloc
                  0 // outlen
              )
              // limit our copy to 256 bytes
              _toCopy := returndatasize()
              if gt(_toCopy, _maxCopy) {
                  _toCopy := _maxCopy
              }
              // Store the length of the copied bytes
              mstore(_returnData, _toCopy)
              // copy the bytes from returndata[0:_toCopy]
              returndatacopy(add(_returnData, 0x20), 0, _toCopy)
          }
          return (_success, _returnData);
      }
  
      /**
       * @notice Swaps function selectors in encoded contract calls
       * @dev Allows reuse of encoded calldata for functions with identical
       * argument types but different names. It simply swaps out the first 4 bytes
       * for the new selector. This function modifies memory in place, and should
       * only be used with caution.
       * @param _newSelector The new 4-byte selector
       * @param _buf The encoded contract args
       */
      function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {
          require(_buf.length >= 4);
          uint _mask = LOW_28_MASK;
          assembly {
              // load the first word of
              let _word := mload(add(_buf, 0x20))
              // mask out the top 4 bytes
              // /x
              _word := and(_word, _mask)
              _word := or(_newSelector, _word)
              mstore(add(_buf, 0x20), _word)
          }
      }
  }
  
  // File: contracts/NodeRun/libraries/BytesLib.sol
  
  
  /*
   * @title Solidity Bytes Arrays Utils
   * @author Gonçalo Sá <goncalo.sa@consensys.net>
   *
   * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
   *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
   */
  pragma solidity >=0.8.0 <0.9.0;
  
  library BytesLib {
      function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
          bytes memory tempBytes;
  
          assembly {
              // Get a location of some free memory and store it in tempBytes as
              // Solidity does for memory variables.
              tempBytes := mload(0x40)
  
              // Store the length of the first bytes array at the beginning of
              // the memory for tempBytes.
              let length := mload(_preBytes)
              mstore(tempBytes, length)
  
              // Maintain a memory counter for the current write location in the
              // temp bytes array by adding the 32 bytes for the array length to
              // the starting location.
              let mc := add(tempBytes, 0x20)
              // Stop copying when the memory counter reaches the length of the
              // first bytes array.
              let end := add(mc, length)
  
              for {
                  // Initialize a copy counter to the start of the _preBytes data,
                  // 32 bytes into its memory.
                  let cc := add(_preBytes, 0x20)
              } lt(mc, end) {
                  // Increase both counters by 32 bytes each iteration.
                  mc := add(mc, 0x20)
                  cc := add(cc, 0x20)
              } {
                  // Write the _preBytes data into the tempBytes memory 32 bytes
                  // at a time.
                  mstore(mc, mload(cc))
              }
  
              // Add the length of _postBytes to the current length of tempBytes
              // and store it as the new length in the first 32 bytes of the
              // tempBytes memory.
              length := mload(_postBytes)
              mstore(tempBytes, add(length, mload(tempBytes)))
  
              // Move the memory counter back from a multiple of 0x20 to the
              // actual end of the _preBytes data.
              mc := end
              // Stop copying when the memory counter reaches the new combined
              // length of the arrays.
              end := add(mc, length)
  
              for {
                  let cc := add(_postBytes, 0x20)
              } lt(mc, end) {
                  mc := add(mc, 0x20)
                  cc := add(cc, 0x20)
              } {
                  mstore(mc, mload(cc))
              }
  
              // Update the free-memory pointer by padding our last write location
              // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
              // next 32 byte block, then round down to the nearest multiple of
              // 32. If the sum of the length of the two arrays is zero then add
              // one before rounding down to leave a blank 32 bytes (the length block with 0).
              mstore(
                  0x40,
                  and(
                      add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                      not(31) // Round down to the nearest 32 bytes.
                  )
              )
          }
  
          return tempBytes;
      }
  
      function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
          assembly {
              // Read the first 32 bytes of _preBytes storage, which is the length
              // of the array. (We don't need to use the offset into the slot
              // because arrays use the entire slot.)
              let fslot := sload(_preBytes.slot)
              // Arrays of 31 bytes or less have an even value in their slot,
              // while longer arrays have an odd value. The actual length is
              // the slot divided by two for odd values, and the lowest order
              // byte divided by two for even values.
              // If the slot is even, bitwise and the slot with 255 and divide by
              // two to get the length. If the slot is odd, bitwise and the slot
              // with -1 and divide by two.
              let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
              let mlength := mload(_postBytes)
              let newlength := add(slength, mlength)
              // slength can contain both the length and contents of the array
              // if length < 32 bytes so let's prepare for that
              // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
              switch add(lt(slength, 32), lt(newlength, 32))
              case 2 {
                  // Since the new array still fits in the slot, we just need to
                  // update the contents of the slot.
                  // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                  sstore(
                      _preBytes.slot,
                      // all the modifications to the slot are inside this
                      // next block
                      add(
                          // we can just add to the slot contents because the
                          // bytes we want to change are the LSBs
                          fslot,
                          add(
                              mul(
                                  div(
                                      // load the bytes from memory
                                      mload(add(_postBytes, 0x20)),
                                      // zero all bytes to the right
                                      exp(0x100, sub(32, mlength))
                                  ),
                                  // and now shift left the number of bytes to
                                  // leave space for the length in the slot
                                  exp(0x100, sub(32, newlength))
                              ),
                              // increase length by the double of the memory
                              // bytes length
                              mul(mlength, 2)
                          )
                      )
                  )
              }
              case 1 {
                  // The stored value fits in the slot, but the combined value
                  // will exceed it.
                  // get the keccak hash to get the contents of the array
                  mstore(0x0, _preBytes.slot)
                  let sc := add(keccak256(0x0, 0x20), div(slength, 32))
  
                  // save new length
                  sstore(_preBytes.slot, add(mul(newlength, 2), 1))
  
                  // The contents of the _postBytes array start 32 bytes into
                  // the structure. Our first read should obtain the `submod`
                  // bytes that can fit into the unused space in the last word
                  // of the stored array. To get this, we read 32 bytes starting
                  // from `submod`, so the data we read overlaps with the array
                  // contents by `submod` bytes. Masking the lowest-order
                  // `submod` bytes allows us to add that value directly to the
                  // stored value.
  
                  let submod := sub(32, slength)
                  let mc := add(_postBytes, submod)
                  let end := add(_postBytes, mlength)
                  let mask := sub(exp(0x100, submod), 1)
  
                  sstore(sc, add(and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask)))
  
                  for {
                      mc := add(mc, 0x20)
                      sc := add(sc, 1)
                  } lt(mc, end) {
                      sc := add(sc, 1)
                      mc := add(mc, 0x20)
                  } {
                      sstore(sc, mload(mc))
                  }
  
                  mask := exp(0x100, sub(mc, end))
  
                  sstore(sc, mul(div(mload(mc), mask), mask))
              }
              default {
                  // get the keccak hash to get the contents of the array
                  mstore(0x0, _preBytes.slot)
                  // Start copying to the last used word of the stored array.
                  let sc := add(keccak256(0x0, 0x20), div(slength, 32))
  
                  // save new length
                  sstore(_preBytes.slot, add(mul(newlength, 2), 1))
  
                  // Copy over the first `submod` bytes of the new data as in
                  // case 1 above.
                  let slengthmod := mod(slength, 32)
                  let mlengthmod := mod(mlength, 32)
                  let submod := sub(32, slengthmod)
                  let mc := add(_postBytes, submod)
                  let end := add(_postBytes, mlength)
                  let mask := sub(exp(0x100, submod), 1)
  
                  sstore(sc, add(sload(sc), and(mload(mc), mask)))
  
                  for {
                      sc := add(sc, 1)
                      mc := add(mc, 0x20)
                  } lt(mc, end) {
                      sc := add(sc, 1)
                      mc := add(mc, 0x20)
                  } {
                      sstore(sc, mload(mc))
                  }
  
                  mask := exp(0x100, sub(mc, end))
  
                  sstore(sc, mul(div(mload(mc), mask), mask))
              }
          }
      }
  
      function slice(
          bytes memory _bytes,
          uint _start,
          uint _length
      ) internal pure returns (bytes memory) {
          require(_length + 31 >= _length, "slice_overflow");
          require(_bytes.length >= _start + _length, "slice_outOfBounds");
  
          bytes memory tempBytes;
  
          assembly {
              switch iszero(_length)
              case 0 {
                  // Get a location of some free memory and store it in tempBytes as
                  // Solidity does for memory variables.
                  tempBytes := mload(0x40)
  
                  // The first word of the slice result is potentially a partial
                  // word read from the original array. To read it, we calculate
                  // the length of that partial word and start copying that many
                  // bytes into the array. The first word we copy will start with
                  // data we don't care about, but the last `lengthmod` bytes will
                  // land at the beginning of the contents of the new array. When
                  // we're done copying, we overwrite the full first word with
                  // the actual length of the slice.
                  let lengthmod := and(_length, 31)
  
                  // The multiplication in the next line is necessary
                  // because when slicing multiples of 32 bytes (lengthmod == 0)
                  // the following copy loop was copying the origin's length
                  // and then ending prematurely not copying everything it should.
                  let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                  let end := add(mc, _length)
  
                  for {
                      // The multiplication in the next line has the same exact purpose
                      // as the one above.
                      let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                  } lt(mc, end) {
                      mc := add(mc, 0x20)
                      cc := add(cc, 0x20)
                  } {
                      mstore(mc, mload(cc))
                  }
  
                  mstore(tempBytes, _length)
  
                  //update free-memory pointer
                  //allocating the array padded to 32 bytes like the compiler does now
                  mstore(0x40, and(add(mc, 31), not(31)))
              }
              //if we want a zero-length slice let's just return a zero-length array
              default {
                  tempBytes := mload(0x40)
                  //zero out the 32 bytes slice we are about to return
                  //we need to do it because Solidity does not garbage collect
                  mstore(tempBytes, 0)
  
                  mstore(0x40, add(tempBytes, 0x20))
              }
          }
  
          return tempBytes;
      }
  
      function toAddress(bytes memory _bytes, uint _start) internal pure returns (address) {
          require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
          address tempAddress;
  
          assembly {
              tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
          }
  
          return tempAddress;
      }
  
      function toUint8(bytes memory _bytes, uint _start) internal pure returns (uint8) {
          require(_bytes.length >= _start + 1, "toUint8_outOfBounds");
          uint8 tempUint;
  
          assembly {
              tempUint := mload(add(add(_bytes, 0x1), _start))
          }
  
          return tempUint;
      }
  
      function toUint16(bytes memory _bytes, uint _start) internal pure returns (uint16) {
          require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
          uint16 tempUint;
  
          assembly {
              tempUint := mload(add(add(_bytes, 0x2), _start))
          }
  
          return tempUint;
      }
  
      function toUint32(bytes memory _bytes, uint _start) internal pure returns (uint32) {
          require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
          uint32 tempUint;
  
          assembly {
              tempUint := mload(add(add(_bytes, 0x4), _start))
          }
  
          return tempUint;
      }
  
      function toUint64(bytes memory _bytes, uint _start) internal pure returns (uint64) {
          require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
          uint64 tempUint;
  
          assembly {
              tempUint := mload(add(add(_bytes, 0x8), _start))
          }
  
          return tempUint;
      }
  
      function toUint96(bytes memory _bytes, uint _start) internal pure returns (uint96) {
          require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
          uint96 tempUint;
  
          assembly {
              tempUint := mload(add(add(_bytes, 0xc), _start))
          }
  
          return tempUint;
      }
  
      function toUint128(bytes memory _bytes, uint _start) internal pure returns (uint128) {
          require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
          uint128 tempUint;
  
          assembly {
              tempUint := mload(add(add(_bytes, 0x10), _start))
          }
  
          return tempUint;
      }
  
      function toUint256(bytes memory _bytes, uint _start) internal pure returns (uint) {
          require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
          uint tempUint;
  
          assembly {
              tempUint := mload(add(add(_bytes, 0x20), _start))
          }
  
          return tempUint;
      }
  
      function toBytes32(bytes memory _bytes, uint _start) internal pure returns (bytes32) {
          require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
          bytes32 tempBytes32;
  
          assembly {
              tempBytes32 := mload(add(add(_bytes, 0x20), _start))
          }
  
          return tempBytes32;
      }
  
      function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
          bool success = true;
  
          assembly {
              let length := mload(_preBytes)
  
              // if lengths don't match the arrays are not equal
              switch eq(length, mload(_postBytes))
              case 1 {
                  // cb is a circuit breaker in the for loop since there's
                  //  no said feature for inline assembly loops
                  // cb = 1 - don't breaker
                  // cb = 0 - break
                  let cb := 1
  
                  let mc := add(_preBytes, 0x20)
                  let end := add(mc, length)
  
                  for {
                      let cc := add(_postBytes, 0x20)
                      // the next line is the loop condition:
                      // while(uint256(mc < end) + cb == 2)
                  } eq(add(lt(mc, end), cb), 2) {
                      mc := add(mc, 0x20)
                      cc := add(cc, 0x20)
                  } {
                      // if any of these checks fails then arrays are not equal
                      if iszero(eq(mload(mc), mload(cc))) {
                          // unsuccess:
                          success := 0
                          cb := 0
                      }
                  }
              }
              default {
                  // unsuccess:
                  success := 0
              }
          }
  
          return success;
      }
  
      function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
          bool success = true;
  
          assembly {
              // we know _preBytes_offset is 0
              let fslot := sload(_preBytes.slot)
              // Decode the length of the stored array like in concatStorage().
              let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
              let mlength := mload(_postBytes)
  
              // if lengths don't match the arrays are not equal
              switch eq(slength, mlength)
              case 1 {
                  // slength can contain both the length and contents of the array
                  // if length < 32 bytes so let's prepare for that
                  // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                  if iszero(iszero(slength)) {
                      switch lt(slength, 32)
                      case 1 {
                          // blank the last byte which is the length
                          fslot := mul(div(fslot, 0x100), 0x100)
  
                          if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                              // unsuccess:
                              success := 0
                          }
                      }
                      default {
                          // cb is a circuit breaker in the for loop since there's
                          //  no said feature for inline assembly loops
                          // cb = 1 - don't breaker
                          // cb = 0 - break
                          let cb := 1
  
                          // get the keccak hash to get the contents of the array
                          mstore(0x0, _preBytes.slot)
                          let sc := keccak256(0x0, 0x20)
  
                          let mc := add(_postBytes, 0x20)
                          let end := add(mc, mlength)
  
                          // the next line is the loop condition:
                          // while(uint256(mc < end) + cb == 2)
                          for {
  
                          } eq(add(lt(mc, end), cb), 2) {
                              sc := add(sc, 1)
                              mc := add(mc, 0x20)
                          } {
                              if iszero(eq(sload(sc), mload(mc))) {
                                  // unsuccess:
                                  success := 0
                                  cb := 0
                              }
                          }
                      }
                  }
              }
              default {
                  // unsuccess:
                  success := 0
              }
          }
  
          return success;
      }
  }
  
  // File: contracts/NodeRun/lzApp/interfaces/INodeRunUserApplicationConfig.sol
  
  
  
  pragma solidity >=0.5.0;
  
  interface INodeRunUserApplicationConfig {
      // @notice set the configuration of the NodeRun messaging library of the specified version
      // @param _version - messaging library version
      // @param _chainId - the chainId for the pending config change
      // @param _configType - type of configuration. every messaging library has its own convention.
      // @param _config - configuration in the bytes. can encode arbitrary content.
      function setConfig(
          uint16 _version,
          uint16 _chainId,
          uint _configType,
          bytes calldata _config
      ) external;
  
      // @notice set the send() NodeRun messaging library version to _version
      // @param _version - new messaging library version
      function setSendVersion(uint16 _version) external;
  
      // @notice set the lzReceive() NodeRun messaging library version to _version
      // @param _version - new messaging library version
      function setReceiveVersion(uint16 _version) external;
  
      // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
      // @param _srcChainId - the chainId of the source chain
      // @param _srcAddress - the contract address of the source contract at the source chain
      function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
  }
  
  // File: contracts/NodeRun/lzApp/interfaces/INodeRunEndpoint.sol
  
  
  
  pragma solidity >=0.5.0;
  
  
  interface INodeRunEndpoint is INodeRunUserApplicationConfig {
      // @notice send a NodeRun message to the specified address at a NodeRun endpoint.
      // @param _dstChainId - the destination chain identifier
      // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
      // @param _payload - a custom bytes payload to send to the destination contract
      // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
      // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
      // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
      function send(
          uint16 _dstChainId,
          bytes calldata _destination,
          bytes calldata _payload,
          address payable _refundAddress,
          address _zroPaymentAddress,
          bytes calldata _adapterParams
      ) external payable;
  
      // @notice used by the messaging library to publish verified payload
      // @param _srcChainId - the source chain identifier
      // @param _srcAddress - the source contract (as bytes) at the source chain
      // @param _dstAddress - the address on destination chain
      // @param _nonce - the unbound message ordering nonce
      // @param _gasLimit - the gas limit for external contract execution
      // @param _payload - verified payload to send to the destination contract
      function receivePayload(
          uint16 _srcChainId,
          bytes calldata _srcAddress,
          address _dstAddress,
          uint64 _nonce,
          uint _gasLimit,
          bytes calldata _payload
      ) external;
  
      // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain
      // @param _srcChainId - the source chain identifier
      // @param _srcAddress - the source chain contract address
      function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);
  
      // @notice get the outboundNonce from this source chain which, consequently, is always an EVM
      // @param _srcAddress - the source chain contract address
      function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);
  
      // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
      // @param _dstChainId - the destination chain identifier
      // @param _userApplication - the user app address on this EVM chain
      // @param _payload - the custom message to send over NodeRun
      // @param _payInZRO - if false, user app pays the protocol fee in native token
      // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
      function estimateFees(
          uint16 _dstChainId,
          address _userApplication,
          bytes calldata _payload,
          bool _payInZRO,
          bytes calldata _adapterParam
      ) external view returns (uint nativeFee, uint zroFee);
  
      // @notice get this Endpoint's immutable source identifier
      function getChainId() external view returns (uint16);
  
      // @notice the interface to retry failed message on this Endpoint destination
      // @param _srcChainId - the source chain identifier
      // @param _srcAddress - the source chain contract address
      // @param _payload - the payload to be retried
      function retryPayload(
          uint16 _srcChainId,
          bytes calldata _srcAddress,
          bytes calldata _payload
      ) external;
  
      // @notice query if any STORED payload (message blocking) at the endpoint.
      // @param _srcChainId - the source chain identifier
      // @param _srcAddress - the source chain contract address
      function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);
  
      // @notice query if the _libraryAddress is valid for sending msgs.
      // @param _userApplication - the user app address on this EVM chain
      function getSendLibraryAddress(address _userApplication) external view returns (address);
  
      // @notice query if the _libraryAddress is valid for receiving msgs.
      // @param _userApplication - the user app address on this EVM chain
      function getReceiveLibraryAddress(address _userApplication) external view returns (address);
  
      // @notice query if the non-reentrancy guard for send() is on
      // @return true if the guard is on. false otherwise
      function isSendingPayload() external view returns (bool);
  
      // @notice query if the non-reentrancy guard for receive() is on
      // @return true if the guard is on. false otherwise
      function isReceivingPayload() external view returns (bool);
  
      // @notice get the configuration of the NodeRun messaging library of the specified version
      // @param _version - messaging library version
      // @param _chainId - the chainId for the pending config change
      // @param _userApplication - the contract address of the user application
      // @param _configType - type of configuration. every messaging library has its own convention.
      function getConfig(
          uint16 _version,
          uint16 _chainId,
          address _userApplication,
          uint _configType
      ) external view returns (bytes memory);
  
      // @notice get the send() NodeRun messaging library version
      // @param _userApplication - the contract address of the user application
      function getSendVersion(address _userApplication) external view returns (uint16);
  
      // @notice get the lzReceive() NodeRun messaging library version
      // @param _userApplication - the contract address of the user application
      function getReceiveVersion(address _userApplication) external view returns (uint16);
  }
  
  // File: contracts/NodeRun/lzApp/interfaces/INodeRunReceiver.sol
  
  
  
  pragma solidity >=0.5.0;
  
  interface INodeRunReceiver {
      // @notice NodeRun endpoint will invoke this function to deliver the message on the destination
      // @param _srcChainId - the source endpoint identifier
      // @param _srcAddress - the source sending contract address from the source chain
      // @param _nonce - the ordered message nonce
      // @param _payload - the signed payload is the UA bytes has encoded to be sent
      function lzReceive(
          uint16 _srcChainId,
          bytes calldata _srcAddress,
          uint64 _nonce,
          bytes calldata _payload
      ) external;
  }
  
  // File: @openzeppelin/contracts/utils/Context.sol
  
  
  // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Provides information about the current execution context, including the
   * sender of the transaction and its data. While these are generally available
   * via msg.sender and msg.data, they should not be accessed in such a direct
   * manner, since when dealing with meta-transactions the account sending and
   * paying for execution may not be the actual sender (as far as an application
   * is concerned).
   *
   * This contract is only required for intermediate, library-like contracts.
   */
  abstract contract Context {
      function _msgSender() internal view virtual returns (address) {
          return msg.sender;
      }
  
      function _msgData() internal view virtual returns (bytes calldata) {
          return msg.data;
      }
  }
  
  // File: @openzeppelin/contracts/access/Ownable.sol
  
  
  // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
  
  pragma solidity ^0.8.0;
  
  
  /**
   * @dev Contract module which provides a basic access control mechanism, where
   * there is an account (an owner) that can be granted exclusive access to
   * specific functions.
   *
   * By default, the owner account will be the one that deploys the contract. This
   * can later be changed with {transferOwnership}.
   *
   * This module is used through inheritance. It will make available the modifier
   * `onlyOwner`, which can be applied to your functions to restrict their use to
   * the owner.
   */
  abstract contract Ownable is Context {
      address private _owner;
  
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  
      /**
       * @dev Initializes the contract setting the deployer as the initial owner.
       */
      constructor() {
          _transferOwnership(_msgSender());
      }
  
      /**
       * @dev Throws if called by any account other than the owner.
       */
      modifier onlyOwner() {
          _checkOwner();
          _;
      }
  
      /**
       * @dev Returns the address of the current owner.
       */
      function owner() public view virtual returns (address) {
          return _owner;
      }
  
      /**
       * @dev Throws if the sender is not the owner.
       */
      function _checkOwner() internal view virtual {
          require(owner() == _msgSender(), "Ownable: caller is not the owner");
      }
  
      /**
       * @dev Leaves the contract without owner. It will not be possible to call
       * `onlyOwner` functions. Can only be called by the current owner.
       *
       * NOTE: Renouncing ownership will leave the contract without an owner,
       * thereby disabling any functionality that is only available to the owner.
       */
      function renounceOwnership() public virtual onlyOwner {
          _transferOwnership(address(0));
      }
  
      /**
       * @dev Transfers ownership of the contract to a new account (`newOwner`).
       * Can only be called by the current owner.
       */
      function transferOwnership(address newOwner) public virtual onlyOwner {
          require(newOwner != address(0), "Ownable: new owner is the zero address");
          _transferOwnership(newOwner);
      }
  
      /**
       * @dev Transfers ownership of the contract to a new account (`newOwner`).
       * Internal function without access restriction.
       */
      function _transferOwnership(address newOwner) internal virtual {
          address oldOwner = _owner;
          _owner = newOwner;
          emit OwnershipTransferred(oldOwner, newOwner);
      }
  }
  
  // File: contracts/NodeRun/lzApp/LzApp.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  
  
  
  
  /*
   * a generic LzReceiver implementation
   */
  abstract contract LzApp is Ownable, INodeRunReceiver, INodeRunUserApplicationConfig {
      using BytesLib for bytes;
  
      // ua can not send payload larger than this by default, but it can be changed by the ua owner
      uint public constant DEFAULT_PAYLOAD_SIZE_LIMIT = 10000;
  
      INodeRunEndpoint public immutable lzEndpoint;
      mapping(uint16 => bytes) public trustedRemoteLookup;
      mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;
      mapping(uint16 => uint) public payloadSizeLimitLookup;
      address public precrime;
  
      event SetPrecrime(address precrime);
      event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
      event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
      event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);
  
      constructor(address _endpoint) {
          lzEndpoint = INodeRunEndpoint(_endpoint);
      }
  
      function lzReceive(
          uint16 _srcChainId,
          bytes calldata _srcAddress,
          uint64 _nonce,
          bytes calldata _payload
      ) public virtual override {
          // lzReceive must be called by the endpoint for security
          require(_msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller");
  
          bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];
          // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.
          require(
              _srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote),
              "LzApp: invalid source sending contract"
          );
  
          _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
      }
  
      // abstract function - the default behaviour of NodeRun is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging
      function _blockingLzReceive(
          uint16 _srcChainId,
          bytes memory _srcAddress,
          uint64 _nonce,
          bytes memory _payload
      ) internal virtual;
  
      function _lzSend(
          uint16 _dstChainId,
          bytes memory _payload,
          address payable _refundAddress,
          address _zroPaymentAddress,
          bytes memory _adapterParams,
          uint _nativeFee
      ) internal virtual {
          bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];
          require(trustedRemote.length != 0, "LzApp: destination chain is not a trusted source");
          _checkPayloadSize(_dstChainId, _payload.length);
          lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
      }
  
      function _checkGasLimit(
          uint16 _dstChainId,
          uint16 _type,
          bytes memory _adapterParams,
          uint _extraGas
      ) internal view virtual {
          uint providedGasLimit = _getGasLimit(_adapterParams);
          uint minGasLimit = minDstGasLookup[_dstChainId][_type];
          require(minGasLimit > 0, "LzApp: minGasLimit not set");
          require(providedGasLimit >= minGasLimit + _extraGas, "LzApp: gas limit is too low");
      }
  
      function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {
          require(_adapterParams.length >= 34, "LzApp: invalid adapterParams");
          assembly {
              gasLimit := mload(add(_adapterParams, 34))
          }
      }
  
      function _checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internal view virtual {
          uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId];
          if (payloadSizeLimit == 0) {
              // use default if not set
              payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;
          }
          require(_payloadSize <= payloadSizeLimit, "LzApp: payload size is too large");
      }
  
      //---------------------------UserApplication config----------------------------------------
      function getConfig(
          uint16 _version,
          uint16 _chainId,
          address,
          uint _configType
      ) external view returns (bytes memory) {
          return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);
      }
  
      // generic config for NodeRun user Application
      function setConfig(
          uint16 _version,
          uint16 _chainId,
          uint _configType,
          bytes calldata _config
      ) external override onlyOwner {
          lzEndpoint.setConfig(_version, _chainId, _configType, _config);
      }
  
      function setSendVersion(uint16 _version) external override onlyOwner {
          lzEndpoint.setSendVersion(_version);
      }
  
      function setReceiveVersion(uint16 _version) external override onlyOwner {
          lzEndpoint.setReceiveVersion(_version);
      }
  
      function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {
          lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
      }
  
      // _path = abi.encodePacked(remoteAddress, localAddress)
      // this function set the trusted path for the cross-chain communication
      function setTrustedRemote(uint16 _remoteChainId, bytes calldata _path) external onlyOwner {
          trustedRemoteLookup[_remoteChainId] = _path;
          emit SetTrustedRemote(_remoteChainId, _path);
      }
  
      function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external onlyOwner {
          trustedRemoteLookup[_remoteChainId] = abi.encodePacked(_remoteAddress, address(this));
          emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);
      }
  
      function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) {
          bytes memory path = trustedRemoteLookup[_remoteChainId];
          require(path.length != 0, "LzApp: no trusted path record");
          return path.slice(0, path.length - 20); // the last 20 bytes should be address(this)
      }
  
      function setPrecrime(address _precrime) external onlyOwner {
          precrime = _precrime;
          emit SetPrecrime(_precrime);
      }
  
      function setMinDstGas(
          uint16 _dstChainId,
          uint16 _packetType,
          uint _minGas
      ) external onlyOwner {
          minDstGasLookup[_dstChainId][_packetType] = _minGas;
          emit SetMinDstGas(_dstChainId, _packetType, _minGas);
      }
  
      // if the size is 0, it means default size limit
      function setPayloadSizeLimit(uint16 _dstChainId, uint _size) external onlyOwner {
          payloadSizeLimitLookup[_dstChainId] = _size;
      }
  
      //--------------------------- VIEW FUNCTION ----------------------------------------
      function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {
          bytes memory trustedSource = trustedRemoteLookup[_srcChainId];
          return keccak256(trustedSource) == keccak256(_srcAddress);
      }
  }
  
  // File: contracts/NodeRun/lzApp/NonblockingLzApp.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  
  /*
   * the default NodeRun messaging behaviour is blocking, i.e. any failed message will block the channel
   * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking
   * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)
   */
  abstract contract NonblockingLzApp is LzApp {
      using ExcessivelySafeCall for address;
  
      constructor(address _endpoint) LzApp(_endpoint) {}
  
      mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages;
  
      event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);
      event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);
  
      // overriding the virtual function in LzReceiver
      function _blockingLzReceive(
          uint16 _srcChainId,
          bytes memory _srcAddress,
          uint64 _nonce,
          bytes memory _payload
      ) internal virtual override {
          (bool success, bytes memory reason) = address(this).excessivelySafeCall(
              gasleft(),
              150,
              abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload)
          );
          if (!success) {
              _storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason);
          }
      }
  
      function _storeFailedMessage(
          uint16 _srcChainId,
          bytes memory _srcAddress,
          uint64 _nonce,
          bytes memory _payload,
          bytes memory _reason
      ) internal virtual {
          failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);
          emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);
      }
  
      function nonblockingLzReceive(
          uint16 _srcChainId,
          bytes calldata _srcAddress,
          uint64 _nonce,
          bytes calldata _payload
      ) public virtual {
          // only internal transaction
          require(_msgSender() == address(this), "NonblockingLzApp: caller must be LzApp");
          _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
      }
  
      //@notice override this function
      function _nonblockingLzReceive(
          uint16 _srcChainId,
          bytes memory _srcAddress,
          uint64 _nonce,
          bytes memory _payload
      ) internal virtual;
  
      function retryMessage(
          uint16 _srcChainId,
          bytes calldata _srcAddress,
          uint64 _nonce,
          bytes calldata _payload
      ) public payable virtual {
          // assert there is message to retry
          bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];
          require(payloadHash != bytes32(0), "NonblockingLzApp: no stored message");
          require(keccak256(_payload) == payloadHash, "NonblockingLzApp: invalid payload");
          // clear the stored message
          failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0);
          // execute the message. revert if it fails again
          _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
          emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash);
      }
  }
  
  // File: contracts/NodeRun/token/oft/v2/OFTCoreV2.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  
  
  
  abstract contract OFTCoreV2 is NonblockingLzApp {
      using BytesLib for bytes;
      using ExcessivelySafeCall for address;
  
      uint public constant NO_EXTRA_GAS = 0;
  
      // packet type
      uint8 public constant PT_SEND = 0;
      uint8 public constant PT_SEND_AND_CALL = 1;
  
      uint8 public immutable sharedDecimals;
  
      mapping(uint16 => mapping(bytes => mapping(uint64 => bool))) public creditedPackets;
  
      /**
       * @dev Emitted when `_amount` tokens are moved from the `_sender` to (`_dstChainId`, `_toAddress`)
       * `_nonce` is the outbound nonce
       */
      event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes32 indexed _toAddress, uint _amount);
  
      /**
       * @dev Emitted when `_amount` tokens are received from `_srcChainId` into the `_toAddress` on the local chain.
       * `_nonce` is the inbound nonce.
       */
      event ReceiveFromChain(uint16 indexed _srcChainId, address indexed _to, uint _amount);
  
      event CallOFTReceivedSuccess(uint16 indexed _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _hash);
  
      event NonContractAddress(address _address);
  
      // _sharedDecimals should be the minimum decimals on all chains
      constructor(uint8 _sharedDecimals, address _lzEndpoint) NonblockingLzApp(_lzEndpoint) {
          sharedDecimals = _sharedDecimals;
      }
  
      /************************************************************************
       * public functions
       ************************************************************************/
      function callOnOFTReceived(
          uint16 _srcChainId,
          bytes calldata _srcAddress,
          uint64 _nonce,
          bytes32 _from,
          address _to,
          uint _amount,
          bytes calldata _payload,
          uint _gasForCall
      ) public virtual {
          require(_msgSender() == address(this), "OFTCore: caller must be OFTCore");
  
          // send
          _amount = _transferFrom(address(this), _to, _amount);
          emit ReceiveFromChain(_srcChainId, _to, _amount);
  
          // call
          RReceiverV2(_to).onOFTReceived{gas: _gasForCall}(_srcChainId, _srcAddress, _nonce, _from, _amount, _payload);
      }
  
      /************************************************************************
       * internal functions
       ************************************************************************/
      function _estimateSendFee(
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          bool _useZro,
          bytes memory _adapterParams
      ) internal view virtual returns (uint nativeFee, uint zroFee) {
          // mock the payload for sendFrom()
          bytes memory payload = _encodeSendPayload(_toAddress, _ld2sd(_amount));
          return lzEndpoint.estimateFees(_dstChainId, address(this), payload, _useZro, _adapterParams);
      }
  
      function _estimateSendAndCallFee(
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          bytes memory _payload,
          uint64 _dstGasForCall,
          bool _useZro,
          bytes memory _adapterParams
      ) internal view virtual returns (uint nativeFee, uint zroFee) {
          // mock the payload for sendAndCall()
          bytes memory payload = _encodeSendAndCallPayload(msg.sender, _toAddress, _ld2sd(_amount), _payload, _dstGasForCall);
          return lzEndpoint.estimateFees(_dstChainId, address(this), payload, _useZro, _adapterParams);
      }
  
      function _nonblockingLzReceive(
          uint16 _srcChainId,
          bytes memory _srcAddress,
          uint64 _nonce,
          bytes memory _payload
      ) internal virtual override {
          uint8 packetType = _payload.toUint8(0);
  
          if (packetType == PT_SEND) {
              _sendAck(_srcChainId, _srcAddress, _nonce, _payload);
          } else if (packetType == PT_SEND_AND_CALL) {
              _sendAndCallAck(_srcChainId, _srcAddress, _nonce, _payload);
          } else {
              revert("OFTCore: unknown packet type");
          }
      }
  
      function _send(
          address _from,
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          address payable _refundAddress,
          address _zroPaymentAddress,
          bytes memory _adapterParams
      ) internal virtual returns (uint amount) {
          _checkGasLimit(_dstChainId, PT_SEND, _adapterParams, NO_EXTRA_GAS);
  
          (amount, ) = _removeDust(_amount);
          amount = _debitFrom(_from, _dstChainId, _toAddress, amount); // amount returned should not have dust
          require(amount > 0, "OFTCore: amount too small");
  
          bytes memory lzPayload = _encodeSendPayload(_toAddress, _ld2sd(amount));
          _lzSend(_dstChainId, lzPayload, _refundAddress, _zroPaymentAddress, _adapterParams, msg.value);
  
          emit SendToChain(_dstChainId, _from, _toAddress, amount);
      }
  
      function _sendAck(
          uint16 _srcChainId,
          bytes memory,
          uint64,
          bytes memory _payload
      ) internal virtual {
          (address to, uint64 amountSD) = _decodeSendPayload(_payload);
          if (to == address(0)) {
              to = address(0xdead);
          }
  
          uint amount = _sd2ld(amountSD);
          amount = _creditTo(_srcChainId, to, amount);
  
          emit ReceiveFromChain(_srcChainId, to, amount);
      }
  
      function _sendAndCall(
          address _from,
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          bytes memory _payload,
          uint64 _dstGasForCall,
          address payable _refundAddress,
          address _zroPaymentAddress,
          bytes memory _adapterParams
      ) internal virtual returns (uint amount) {
          _checkGasLimit(_dstChainId, PT_SEND_AND_CALL, _adapterParams, _dstGasForCall);
  
          (amount, ) = _removeDust(_amount);
          amount = _debitFrom(_from, _dstChainId, _toAddress, amount);
          require(amount > 0, "OFTCore: amount too small");
  
          // encode the msg.sender into the payload instead of _from
          bytes memory lzPayload = _encodeSendAndCallPayload(msg.sender, _toAddress, _ld2sd(amount), _payload, _dstGasForCall);
          _lzSend(_dstChainId, lzPayload, _refundAddress, _zroPaymentAddress, _adapterParams, msg.value);
  
          emit SendToChain(_dstChainId, _from, _toAddress, amount);
      }
  
      function _sendAndCallAck(
          uint16 _srcChainId,
          bytes memory _srcAddress,
          uint64 _nonce,
          bytes memory _payload
      ) internal virtual {
          (bytes32 from, address to, uint64 amountSD, bytes memory payloadForCall, uint64 gasForCall) = _decodeSendAndCallPayload(_payload);
  
          bool credited = creditedPackets[_srcChainId][_srcAddress][_nonce];
          uint amount = _sd2ld(amountSD);
  
          // credit to this contract first, and then transfer to receiver only if callOnOFTReceived() succeeds
          if (!credited) {
              amount = _creditTo(_srcChainId, address(this), amount);
              creditedPackets[_srcChainId][_srcAddress][_nonce] = true;
          }
  
          if (!_isContract(to)) {
              emit NonContractAddress(to);
              return;
          }
  
          // workaround for stack too deep
          uint16 srcChainId = _srcChainId;
          bytes memory srcAddress = _srcAddress;
          uint64 nonce = _nonce;
          bytes memory payload = _payload;
          bytes32 from_ = from;
          address to_ = to;
          uint amount_ = amount;
          bytes memory payloadForCall_ = payloadForCall;
  
          // no gas limit for the call if retry
          uint gas = credited ? gasleft() : gasForCall;
          (bool success, bytes memory reason) = address(this).excessivelySafeCall(
              gasleft(),
              150,
              abi.encodeWithSelector(this.callOnOFTReceived.selector, srcChainId, srcAddress, nonce, from_, to_, amount_, payloadForCall_, gas)
          );
  
          if (success) {
              bytes32 hash = keccak256(payload);
              emit CallOFTReceivedSuccess(srcChainId, srcAddress, nonce, hash);
          } else {
              // store the failed message into the nonblockingLzApp
              _storeFailedMessage(srcChainId, srcAddress, nonce, payload, reason);
          }
      }
  
      function _isContract(address _account) internal view returns (bool) {
          return _account.code.length > 0;
      }
  
      function _ld2sd(uint _amount) internal view virtual returns (uint64) {
          uint amountSD = _amount / _ld2sdRate();
          require(amountSD <= type(uint64).max, "OFTCore: amountSD overflow");
          return uint64(amountSD);
      }
  
      function _sd2ld(uint64 _amountSD) internal view virtual returns (uint) {
          return _amountSD * _ld2sdRate();
      }
  
      function _removeDust(uint _amount) internal view virtual returns (uint amountAfter, uint dust) {
          dust = _amount % _ld2sdRate();
          amountAfter = _amount - dust;
      }
  
      function _encodeSendPayload(bytes32 _toAddress, uint64 _amountSD) internal view virtual returns (bytes memory) {
          return abi.encodePacked(PT_SEND, _toAddress, _amountSD);
      }
  
      function _decodeSendPayload(bytes memory _payload) internal view virtual returns (address to, uint64 amountSD) {
          require(_payload.toUint8(0) == PT_SEND && _payload.length == 41, "OFTCore: invalid payload");
  
          to = _payload.toAddress(13); // drop the first 12 bytes of bytes32
          amountSD = _payload.toUint64(33);
      }
  
      function _encodeSendAndCallPayload(
          address _from,
          bytes32 _toAddress,
          uint64 _amountSD,
          bytes memory _payload,
          uint64 _dstGasForCall
      ) internal view virtual returns (bytes memory) {
          return abi.encodePacked(PT_SEND_AND_CALL, _toAddress, _amountSD, _addressToBytes32(_from), _dstGasForCall, _payload);
      }
  
      function _decodeSendAndCallPayload(bytes memory _payload)
          internal
          view
          virtual
          returns (
              bytes32 from,
              address to,
              uint64 amountSD,
              bytes memory payload,
              uint64 dstGasForCall
          )
      {
          require(_payload.toUint8(0) == PT_SEND_AND_CALL, "OFTCore: invalid payload");
  
          to = _payload.toAddress(13); // drop the first 12 bytes of bytes32
          amountSD = _payload.toUint64(33);
          from = _payload.toBytes32(41);
          dstGasForCall = _payload.toUint64(73);
          payload = _payload.slice(81, _payload.length - 81);
      }
  
      function _addressToBytes32(address _address) internal pure virtual returns (bytes32) {
          return bytes32(uint(uint160(_address)));
      }
  
      function _debitFrom(
          address _from,
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount
      ) internal virtual returns (uint);
  
      function _creditTo(
          uint16 _srcChainId,
          address _toAddress,
          uint _amount
      ) internal virtual returns (uint);
  
      function _transferFrom(
          address _from,
          address _to,
          uint _amount
      ) internal virtual returns (uint);
  
      function _ld2sdRate() internal view virtual returns (uint);
  }
  
  // File: contracts/NodeRun/token/oft/v2/BaseOFTV2.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  
  
  abstract contract BaseOFTV2 is OFTCoreV2, ERC165, RV2 {
      constructor(uint8 _sharedDecimals, address _lzEndpoint) OFTCoreV2(_sharedDecimals, _lzEndpoint) {}
  
      /************************************************************************
       * public functions
       ************************************************************************/
      function sendFrom(
          address _from,
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          LzCallParams calldata _callParams
      ) public payable virtual override {
          _send(_from, _dstChainId, _toAddress, _amount, _callParams.refundAddress, _callParams.zroPaymentAddress, _callParams.adapterParams);
      }
  
      function sendAndCall(
          address _from,
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          bytes calldata _payload,
          uint64 _dstGasForCall,
          LzCallParams calldata _callParams
      ) public payable virtual override {
          _sendAndCall(
              _from,
              _dstChainId,
              _toAddress,
              _amount,
              _payload,
              _dstGasForCall,
              _callParams.refundAddress,
              _callParams.zroPaymentAddress,
              _callParams.adapterParams
          );
      }
  
      /************************************************************************
       * public view functions
       ************************************************************************/
      function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
          return interfaceId == type(RV2).interfaceId || super.supportsInterface(interfaceId);
      }
  
      function estimateSendFee(
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          bool _useZro,
          bytes calldata _adapterParams
      ) public view virtual override returns (uint nativeFee, uint zroFee) {
          return _estimateSendFee(_dstChainId, _toAddress, _amount, _useZro, _adapterParams);
      }
  
      function estimateSendAndCallFee(
          uint16 _dstChainId,
          bytes32 _toAddress,
          uint _amount,
          bytes calldata _payload,
          uint64 _dstGasForCall,
          bool _useZro,
          bytes calldata _adapterParams
      ) public view virtual override returns (uint nativeFee, uint zroFee) {
          return _estimateSendAndCallFee(_dstChainId, _toAddress, _amount, _payload, _dstGasForCall, _useZro, _adapterParams);
      }
  
      function circulatingSupply() public view virtual override returns (uint);
  
      function token() public view virtual override returns (address);
  }
  
  // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
  
  
  // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Interface of the ERC20 standard as defined in the EIP.
   */
  interface IERC20 {
      /**
       * @dev Emitted when `value` tokens are moved from one account (`from`) to
       * another (`to`).
       *
       * Note that `value` may be zero.
       */
      event Transfer(address indexed from, address indexed to, uint256 value);
  
      /**
       * @dev Emitted when the allowance of a `spender` for an `owner` is set by
       * a call to {approve}. `value` is the new allowance.
       */
      event Approval(address indexed owner, address indexed spender, uint256 value);
  
      /**
       * @dev Returns the amount of tokens in existence.
       */
      function totalSupply() external view returns (uint256);
  
      /**
       * @dev Returns the amount of tokens owned by `account`.
       */
      function balanceOf(address account) external view returns (uint256);
  
      /**
       * @dev Moves `amount` tokens from the caller's account to `to`.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transfer(address to, uint256 amount) external returns (bool);
  
      /**
       * @dev Returns the remaining number of tokens that `spender` will be
       * allowed to spend on behalf of `owner` through {transferFrom}. This is
       * zero by default.
       *
       * This value changes when {approve} or {transferFrom} are called.
       */
      function allowance(address owner, address spender) external view returns (uint256);
  
      /**
       * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * IMPORTANT: Beware that changing an allowance with this method brings the risk
       * that someone may use both the old and the new allowance by unfortunate
       * transaction ordering. One possible solution to mitigate this race
       * condition is to first reduce the spender's allowance to 0 and set the
       * desired value afterwards:
       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
       *
       * Emits an {Approval} event.
       */
      function approve(address spender, uint256 amount) external returns (bool);
  
      /**
       * @dev Moves `amount` tokens from `from` to `to` using the
       * allowance mechanism. `amount` is then deducted from the caller's
       * allowance.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transferFrom(address from, address to, uint256 amount) external returns (bool);
  }
  
  // File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
  
  
  // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
  
  pragma solidity ^0.8.0;
  
  
  /**
   * @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);
  }
  
  // File: @openzeppelin/contracts/token/ERC20/ERC20.sol
  
  
  // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
  
  pragma solidity ^0.8.0;
  
  
  
  
  /**
   * @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.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
   * to implement supply mechanisms].
   *
   * The default value of {decimals} is 18. To change this, you should override
   * this function so it returns a different value.
   *
   * We have followed general OpenZeppelin Contracts guidelines: functions revert
   * instead returning `false` on failure. This behavior is nonetheless
   * conventional and does not conflict with the expectations of ERC20
   * applications.
   *
   * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
   * This allows applications to reconstruct the allowance for all accounts just
   * by listening to said events. Other implementations of the EIP may not emit
   * these events, as it isn't required by the specification.
   *
   * 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}.
       *
       * 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 default value returned by this function, unless
       * it's overridden.
       *
       * NOTE: This information is only used for _display_ purposes: it in
       * no way affects any of the arithmetic of the contract, including
       * {IERC20-balanceOf} and {IERC20-transfer}.
       */
      function decimals() public view virtual 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:
       *
       * - `to` cannot be the zero address.
       * - the caller must have a balance of at least `amount`.
       */
      function transfer(address to, uint256 amount) public virtual override returns (bool) {
          address owner = _msgSender();
          _transfer(owner, to, 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}.
       *
       * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
       * `transferFrom`. This is semantically equivalent to an infinite approval.
       *
       * Requirements:
       *
       * - `spender` cannot be the zero address.
       */
      function approve(address spender, uint256 amount) public virtual override returns (bool) {
          address owner = _msgSender();
          _approve(owner, 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}.
       *
       * NOTE: Does not update the allowance if the current allowance
       * is the maximum `uint256`.
       *
       * Requirements:
       *
       * - `from` and `to` cannot be the zero address.
       * - `from` must have a balance of at least `amount`.
       * - the caller must have allowance for ``from``'s tokens of at least
       * `amount`.
       */
      function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
          address spender = _msgSender();
          _spendAllowance(from, spender, amount);
          _transfer(from, to, 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) {
          address owner = _msgSender();
          _approve(owner, spender, allowance(owner, 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) {
          address owner = _msgSender();
          uint256 currentAllowance = allowance(owner, spender);
          require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
          unchecked {
              _approve(owner, spender, currentAllowance - subtractedValue);
          }
  
          return true;
      }
  
      /**
       * @dev Moves `amount` of tokens from `from` to `to`.
       *
       * This internal function is equivalent to {transfer}, and can be used to
       * e.g. implement automatic token fees, slashing mechanisms, etc.
       *
       * Emits a {Transfer} event.
       *
       * Requirements:
       *
       * - `from` cannot be the zero address.
       * - `to` cannot be the zero address.
       * - `from` must have a balance of at least `amount`.
       */
      function _transfer(address from, address to, uint256 amount) internal virtual {
          require(from != address(0), "ERC20: transfer from the zero address");
          require(to != address(0), "ERC20: transfer to the zero address");
  
          _beforeTokenTransfer(from, to, amount);
  
          uint256 fromBalance = _balances[from];
          require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
          unchecked {
              _balances[from] = fromBalance - amount;
              // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
              // decrementing then incrementing.
              _balances[to] += amount;
          }
  
          emit Transfer(from, to, amount);
  
          _afterTokenTransfer(from, to, 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;
          unchecked {
              // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
              _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;
              // Overflow not possible: amount <= accountBalance <= totalSupply.
              _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 Updates `owner` s allowance for `spender` based on spent `amount`.
       *
       * Does not update the allowance amount in case of infinite allowance.
       * Revert if not enough allowance is available.
       *
       * Might emit an {Approval} event.
       */
      function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
          uint256 currentAllowance = allowance(owner, spender);
          if (currentAllowance != type(uint256).max) {
              require(currentAllowance >= amount, "ERC20: insufficient allowance");
              unchecked {
                  _approve(owner, spender, currentAllowance - 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 {}
  }
  
  // File: contracts/NodeRun/token/oft/v2/OFTV2.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  
  contract OFTV2 is BaseOFTV2, ERC20 {
      uint internal immutable ld2sdRate;
  
      constructor(
          string memory _name,
          string memory _symbol,
          uint8 _sharedDecimals,
          address _lzEndpoint
      ) ERC20(_name, _symbol) BaseOFTV2(_sharedDecimals, _lzEndpoint) {
          uint8 decimals = decimals();
          require(_sharedDecimals <= decimals, "OFT: sharedDecimals must be <= decimals");
          ld2sdRate = 10**(decimals - _sharedDecimals);
      }
  
      /************************************************************************
       * public functions
       ************************************************************************/
      function circulatingSupply() public view virtual override returns (uint) {
          return totalSupply();
      }
  
      function token() public view virtual override returns (address) {
          return address(this);
      }
  
      /************************************************************************
       * internal functions
       ************************************************************************/
      function _debitFrom(
          address _from,
          uint16,
          bytes32,
          uint _amount
      ) internal virtual override returns (uint) {
          address spender = _msgSender();
          if (_from != spender) _spendAllowance(_from, spender, _amount);
          _burn(_from, _amount);
          return _amount;
      }
  
      function _creditTo(
          uint16,
          address _toAddress,
          uint _amount
      ) internal virtual override returns (uint) {
          _mint(_toAddress, _amount);
          return _amount;
      }
  
      function _transferFrom(
          address _from,
          address _to,
          uint _amount
      ) internal virtual override returns (uint) {
          address spender = _msgSender();
          // if transfer from this contract, no need to check allowance
          if (_from != address(this) && _from != spender) _spendAllowance(_from, spender, _amount);
          _transfer(_from, _to, _amount);
          return _amount;
      }
  
      function _ld2sdRate() internal view virtual override returns (uint) {
          return ld2sdRate;
      }
  }
  
  
  pragma solidity ^0.8.19;
  
  contract NODERUN is OFTV2 {
      IUniswapV2Router02 immutable uniswapV2Router;
      uint256 maxTxAmount;
      uint256 public buyTax = 5;
      uint256 public sellTax = 5;
      uint256 minAmountToSwapTaxes;
      uint256 maxWalletAmount;
      uint256 launchedAt;
      uint256 public buys;
      uint256 buysBeforeSells = 25;
  
      bool launchTax;
      bool taxesEnabled = true;
      bool limitsEnabled = true;
      bool inSwapAndLiq;
      bool public tradingAllowed;
  
      address public taxWallet;
      address public immutable uniswapV2Pair;
  
      mapping(address => bool) public _isExcludedFromFees;
  
      modifier lockTheSwap() {
          inSwapAndLiq = true;
          _;
          inSwapAndLiq = false;
      }
  
      constructor()
          OFTV2(
              "NODERUN AI",
              "R",
              8,
              0x2ADD736c06ab4529923388f6748a6c160E1d7774
          )
      {
          _mint(owner(), 10_000_000 * 10 ** 18);
          IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(
              0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
          );
          address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
              .createPair(address(this), _uniswapV2Router.WETH());
  
          uniswapV2Router = _uniswapV2Router;
          uniswapV2Pair = _uniswapV2Pair;
  
          minAmountToSwapTaxes = (totalSupply() * 3) / 1000;
          maxWalletAmount = (totalSupply() * 2) / 100;
          maxTxAmount = totalSupply() / 100;
  
          _isExcludedFromFees[owner()] = true;
          _isExcludedFromFees[msg.sender] = true;
          _isExcludedFromFees[taxWallet] = true;
          _isExcludedFromFees[address(this)] = true;
          _isExcludedFromFees[address(_uniswapV2Pair)] = true;
  
          taxWallet = 0x2ADD736c06ab4529923388f6748a6c160E1d7774;
      }
  
      function _transfer(
          address from,
          address to,
          uint256 amount
      ) internal override {
          require(amount > 0, "ERC20: transfer must be greater than 0");
  
          if (!tradingAllowed) {
              require(from == owner() || to == owner(), "Trading not active yet");
          }
  
          uint256 taxAmount;
  
          if (launchTax) {
              setTax(block.number);
          }
  
          if (from == uniswapV2Pair && !_isExcludedFromFees[to]) {
              require(
                  balanceOf(to) + amount <= maxWalletAmount,
                  "Max Wallet In Effect"
              );
              require(amount <= maxTxAmount, "Max Tx in effect");
              if (taxesEnabled) {
                  taxAmount = (amount * buyTax) / 100;
              }
  
              buys++;
          }
  
          if (to == uniswapV2Pair && !_isExcludedFromFees[from]) {
              require(amount <= maxTxAmount, "Max Tx in effect");
              if (taxesEnabled) {
                  taxAmount = (amount * sellTax) / 100;
              }
          }
  
          uint256 contractTokenBalance = balanceOf(address(this));
  
          bool overMinTokenBalance = contractTokenBalance >= minAmountToSwapTaxes;
  
          if (
              overMinTokenBalance &&
              !inSwapAndLiq &&
              from != uniswapV2Pair &&
              !_isExcludedFromFees[from] &&
              buys > buysBeforeSells
          ) {
              swapAndSend(minAmountToSwapTaxes);
          }
  
          if (taxAmount > 0) {
              uint256 userAmount = amount - taxAmount;
              super._transfer(from, address(this), taxAmount);
              super._transfer(from, to, userAmount);
          } else {
              super._transfer(from, to, amount);
          }
      }
  
      function swapAndSend(uint256 _contractTokenBalance) internal lockTheSwap {
          // generate the uniswap pair path of token -> weth
          address[] memory path = new address[](2);
          path[0] = address(this);
          path[1] = uniswapV2Router.WETH();
  
          _approve(
              address(this),
              address(uniswapV2Router),
              _contractTokenBalance
          );
  
          // make the swap
          uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
              _contractTokenBalance,
              0, // accept any amount of ETH
              path,
              taxWallet,
              block.timestamp
          );
      }
  
      function setTax(uint256 _block) public {
          if (launchedAt == _block) {
              buyTax = 50;
              sellTax = 50;
          } else if (launchedAt + 1 >= _block) {
              buyTax = 35;
              sellTax = 35;
          } else if (launchedAt + 5 >= _block) {
              buyTax = 30;
              sellTax = 30;
          } else if (launchedAt + 11 >= _block) {
              buyTax = 25;
              sellTax = 25;
          } else if (launchedAt + 24 >= _block) {
              buyTax = 20;
              sellTax = 20;
          }
      }
  
      function changetaxWallet(address _newtaxWallet) external onlyOwner {
          taxWallet = _newtaxWallet;
      }
  
      function removeLaunchTax(
          uint256 _newBuyTaxPercent,
          uint256 _newSellTaxPercent
      ) external onlyOwner {
          require(
              _newBuyTaxPercent <= 10 && _newSellTaxPercent <= 10,
              "Cannot set taxes above 10"
          );
          buyTax = _newBuyTaxPercent;
          sellTax = _newSellTaxPercent;
          launchTax = false;
      }
  
      function excludeFromFees(
          address _address,
          bool _isExcluded
      ) external onlyOwner {
          _isExcludedFromFees[_address] = _isExcluded;
      }
  
      function updateMaxWalletAmount(
          uint256 newMaxWalletAmount
      ) external onlyOwner {
          maxWalletAmount = newMaxWalletAmount;
      }
  
      function updateMaxTxAmount(uint256 _newAmount) external onlyOwner {
          maxTxAmount = _newAmount;
      }
  
      function changeMinAmountToSwapTaxes(
          uint256 newMinAmount
      ) external onlyOwner {
          require(newMinAmount > 0, "Cannot set to zero");
          minAmountToSwapTaxes = newMinAmount;
      }
  
      function enableTaxes(bool _enable) external onlyOwner {
          taxesEnabled = _enable;
      }
  
      function start() external onlyOwner {
          require(!tradingAllowed, "Trading not paused");
          tradingAllowed = true;
          launchedAt = block.number;
          launchTax = true;
      }
  
      function toggleLimits(bool _limitsEnabed) external onlyOwner {
          limitsEnabled = _limitsEnabed;
      }
  
      function manualSwap(uint256 _amount) external onlyOwner {
          swapAndSend(_amount);
      }
  }
  
  interface IUniswapV2Factory {
      event PairCreated(
          address indexed token0,
          address indexed token1,
          address pair,
          uint
      );
  
      function feeTo() external view returns (address);
  
      function feeToSetter() external view returns (address);
  
      function getPair(
          address tokenA,
          address tokenB
      ) external view returns (address pair);
  
      function allPairs(uint) external view returns (address pair);
  
      function allPairsLength() external view returns (uint);
  
      function createPair(
          address tokenA,
          address tokenB
      ) external returns (address pair);
  
      function setFeeTo(address) external;
  
      function setFeeToSetter(address) external;
  }
  
  interface IUniswapV2Pair {
      event Approval(address indexed owner, address indexed spender, uint value);
      event Transfer(address indexed from, address indexed to, uint value);
  
      function name() external pure returns (string memory);
  
      function symbol() external pure returns (string memory);
  
      function decimals() external pure returns (uint8);
  
      function totalSupply() external view returns (uint);
  
      function balanceOf(address owner) external view returns (uint);
  
      function allowance(
          address owner,
          address spender
      ) external view returns (uint);
  
      function approve(address spender, uint value) external returns (bool);
  
      function transfer(address to, uint value) external returns (bool);
  
      function transferFrom(
          address from,
          address to,
          uint value
      ) external returns (bool);
  
      function DOMAIN_SEPARATOR() external view returns (bytes32);
  
      function PERMIT_TYPEHASH() external pure returns (bytes32);
  
      function nonces(address owner) external view returns (uint);
  
      function permit(
          address owner,
          address spender,
          uint value,
          uint deadline,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) external;
  
      event Mint(address indexed sender, uint amount0, uint amount1);
      event Burn(
          address indexed sender,
          uint amount0,
          uint amount1,
          address indexed to
      );
      event Swap(
          address indexed sender,
          uint amount0In,
          uint amount1In,
          uint amount0Out,
          uint amount1Out,
          address indexed to
      );
      event Sync(uint112 reserve0, uint112 reserve1);
  
      function MINIMUM_LIQUIDITY() external pure returns (uint);
  
      function factory() external view returns (address);
  
      function token0() external view returns (address);
  
      function token1() external view returns (address);
  
      function getReserves()
          external
          view
          returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
  
      function price0CumulativeLast() external view returns (uint);
  
      function price1CumulativeLast() external view returns (uint);
  
      function kLast() external view returns (uint);
  
      function mint(address to) external returns (uint liquidity);
  
      function burn(address to) external returns (uint amount0, uint amount1);
  
      function swap(
          uint amount0Out,
          uint amount1Out,
          address to,
          bytes calldata data
      ) external;
  
      function skim(address to) external;
  
      function sync() external;
  
      function initialize(address, address) external;
  }
  
  interface IUniswapV2Router01 {
      function factory() external pure returns (address);
  
      function WETH() external pure returns (address);
  
      function addLiquidity(
          address tokenA,
          address tokenB,
          uint amountADesired,
          uint amountBDesired,
          uint amountAMin,
          uint amountBMin,
          address to,
          uint deadline
      ) external returns (uint amountA, uint amountB, uint liquidity);
  
      function addLiquidityETH(
          address token,
          uint amountTokenDesired,
          uint amountTokenMin,
          uint amountETHMin,
          address to,
          uint deadline
      )
          external
          payable
          returns (uint amountToken, uint amountETH, uint liquidity);
  
      function removeLiquidity(
          address tokenA,
          address tokenB,
          uint liquidity,
          uint amountAMin,
          uint amountBMin,
          address to,
          uint deadline
      ) external returns (uint amountA, uint amountB);
  
      function removeLiquidityETH(
          address token,
          uint liquidity,
          uint amountTokenMin,
          uint amountETHMin,
          address to,
          uint deadline
      ) external returns (uint amountToken, uint amountETH);
  
      function removeLiquidityWithPermit(
          address tokenA,
          address tokenB,
          uint liquidity,
          uint amountAMin,
          uint amountBMin,
          address to,
          uint deadline,
          bool approveMax,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) external returns (uint amountA, uint amountB);
  
      function removeLiquidityETHWithPermit(
          address token,
          uint liquidity,
          uint amountTokenMin,
          uint amountETHMin,
          address to,
          uint deadline,
          bool approveMax,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) external returns (uint amountToken, uint amountETH);
  
      function swapExactTokensForTokens(
          uint amountIn,
          uint amountOutMin,
          address[] calldata path,
          address to,
          uint deadline
      ) external returns (uint[] memory amounts);
  
      function swapTokensForExactTokens(
          uint amountOut,
          uint amountInMax,
          address[] calldata path,
          address to,
          uint deadline
      ) external returns (uint[] memory amounts);
  
      function swapExactETHForTokens(
          uint amountOutMin,
          address[] calldata path,
          address to,
          uint deadline
      ) external payable returns (uint[] memory amounts);
  
      function swapTokensForExactETH(
          uint amountOut,
          uint amountInMax,
          address[] calldata path,
          address to,
          uint deadline
      ) external returns (uint[] memory amounts);
  
      function swapExactTokensForETH(
          uint amountIn,
          uint amountOutMin,
          address[] calldata path,
          address to,
          uint deadline
      ) external returns (uint[] memory amounts);
  
      function swapETHForExactTokens(
          uint amountOut,
          address[] calldata path,
          address to,
          uint deadline
      ) external payable returns (uint[] memory amounts);
  
      function quote(
          uint amountA,
          uint reserveA,
          uint reserveB
      ) external pure returns (uint amountB);
  
      function getAmountOut(
          uint amountIn,
          uint reserveIn,
          uint reserveOut
      ) external pure returns (uint amountOut);
  
      function getAmountIn(
          uint amountOut,
          uint reserveIn,
          uint reserveOut
      ) external pure returns (uint amountIn);
  
      function getAmountsOut(
          uint amountIn,
          address[] calldata path
      ) external view returns (uint[] memory amounts);
  
      function getAmountsIn(
          uint amountOut,
          address[] calldata path
      ) external view returns (uint[] memory amounts);
  }
  
  interface IUniswapV2Router02 is IUniswapV2Router01 {
      function removeLiquidityETHSupportingFeeOnTransferTokens(
          address token,
          uint liquidity,
          uint amountTokenMin,
          uint amountETHMin,
          address to,
          uint deadline
      ) external returns (uint amountETH);
  
      function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
          address token,
          uint liquidity,
          uint amountTokenMin,
          uint amountETHMin,
          address to,
          uint deadline,
          bool approveMax,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) external returns (uint amountETH);
  
      function swapExactTokensForTokensSupportingFeeOnTransferTokens(
          uint amountIn,
          uint amountOutMin,
          address[] calldata path,
          address to,
          uint deadline
      ) external;
  
      function swapExactETHForTokensSupportingFeeOnTransferTokens(
          uint amountOutMin,
          address[] calldata path,
          address to,
          uint deadline
      ) external payable;
  
      function swapExactTokensForETHSupportingFeeOnTransferTokens(
          uint amountIn,
          uint amountOutMin,
          address[] calldata path,
          address to,
          uint deadline
      ) external;
  }