creation_sourcecode: // SPDX-License-Identifier: MIT
  
  pragma solidity ^0.8.20;
  
  library Errors {
      error InsufficientBalance(uint256 balance, uint256 needed);
      error FailedCall();
      error FailedDeployment();
  }
  
  pragma solidity ^0.8.20;
  
  library Address {
  
      error AddressEmptyCode(address target);
      function sendValue(address payable recipient, uint256 amount) internal {
          if (address(this).balance < amount) {
              revert Errors.InsufficientBalance(address(this).balance, amount);
          }
  
          (bool success, ) = recipient.call{value: amount}("");
          if (!success) {
              revert Errors.FailedCall();
          }
      }
      function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCallWithValue(target, data, 0);
      }
  
      function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
          if (address(this).balance < value) {
              revert Errors.InsufficientBalance(address(this).balance, value);
          }
          (bool success, bytes memory returndata) = target.call{value: value}(data);
          return verifyCallResultFromTarget(target, success, returndata);
      }
  
      /**
       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
       * but performing a static call.
       */
      function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
          (bool success, bytes memory returndata) = target.staticcall(data);
          return verifyCallResultFromTarget(target, success, returndata);
      }
  
      /**
       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
       * but performing a delegate call.
       */
      function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
          (bool success, bytes memory returndata) = target.delegatecall(data);
          return verifyCallResultFromTarget(target, success, returndata);
      }
  
      /**
       * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
       * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
       * of an unsuccessful call.
       */
      function verifyCallResultFromTarget(
          address target,
          bool success,
          bytes memory returndata
      ) internal view returns (bytes memory) {
          if (!success) {
              _revert(returndata);
          } else {
              // only check if target is a contract if the call was successful and the return data is empty
              // otherwise we already know that it was a contract
              if (returndata.length == 0 && target.code.length == 0) {
                  revert AddressEmptyCode(target);
              }
              return returndata;
          }
      }
  
      /**
       * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
       * revert reason or with a default {Errors.FailedCall} error.
       */
      function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
          if (!success) {
              _revert(returndata);
          } else {
              return returndata;
          }
      }
  
      /**
       * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
       */
      function _revert(bytes memory returndata) private pure {
          // Look for revert reason and bubble it up if present
          if (returndata.length > 0) {
              // The easiest way to bubble the revert reason is using memory via assembly
              /// @solidity memory-safe-assembly
              assembly {
                  let returndata_size := mload(returndata)
                  revert(add(32, returndata), returndata_size)
              }
          } else {
              revert Errors.FailedCall();
          }
      }
  }
  
  // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
  
  pragma solidity ^0.8.20;
  
  /**
   * @dev Interface of the ERC-165 standard, as defined in the
   * https://eips.ethereum.org/EIPS/eip-165[ERC].
   *
   * 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[ERC 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: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/interfaces/IERC165.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
  
  pragma solidity ^0.8.20;
  
  
  // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
  
  pragma solidity ^0.8.20;
  
  /**
   * @dev Interface of the ERC-20 standard as defined in the ERC.
   */
  interface IERC20 {
      /**
       * @dev Emitted when `value` tokens are moved from one account (`from`) to
       * another (`to`).
       *
       * Note that `value` may be zero.
       */
      event Transfer(address indexed from, address indexed to, uint256 value);
  
      /**
       * @dev Emitted when the allowance of a `spender` for an `owner` is set by
       * a call to {approve}. `value` is the new allowance.
       */
      event Approval(address indexed owner, address indexed spender, uint256 value);
  
      /**
       * @dev Returns the value of tokens in existence.
       */
      function totalSupply() external view returns (uint256);
  
      /**
       * @dev Returns the value of tokens owned by `account`.
       */
      function balanceOf(address account) external view returns (uint256);
  
      /**
       * @dev Moves a `value` amount of tokens from the caller's account to `to`.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transfer(address to, uint256 value) external returns (bool);
  
      /**
       * @dev Returns the remaining number of tokens that `spender` will be
       * allowed to spend on behalf of `owner` through {transferFrom}. This is
       * zero by default.
       *
       * This value changes when {approve} or {transferFrom} are called.
       */
      function allowance(address owner, address spender) external view returns (uint256);
  
      /**
       * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
       * caller's tokens.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * IMPORTANT: Beware that changing an allowance with this method brings the risk
       * that someone may use both the old and the new allowance by unfortunate
       * transaction ordering. One possible solution to mitigate this race
       * condition is to first reduce the spender's allowance to 0 and set the
       * desired value afterwards:
       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
       *
       * Emits an {Approval} event.
       */
      function approve(address spender, uint256 value) external returns (bool);
  
      /**
       * @dev Moves a `value` amount of tokens from `from` to `to` using the
       * allowance mechanism. `value` is then deducted from the caller's
       * allowance.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transferFrom(address from, address to, uint256 value) external returns (bool);
  }
  
  // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/interfaces/IERC20.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
  
  pragma solidity ^0.8.20;
  
  
  // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/interfaces/IERC1363.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol)
  
  pragma solidity ^0.8.20;
  
  
  
  /**
   * @title IERC1363
   * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
   *
   * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
   * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
   */
  interface IERC1363 is IERC20, IERC165 {
      /*
       * Note: the ERC-165 identifier for this interface is 0xb0202a11.
       * 0xb0202a11 ===
       *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
       *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
       *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
       *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
       *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
       *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
       */
  
      /**
       * @dev Moves a `value` amount of tokens from the caller's account to `to`
       * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
       * @param to The address which you want to transfer to.
       * @param value The amount of tokens to be transferred.
       * @return A boolean value indicating whether the operation succeeded unless throwing.
       */
      function transferAndCall(address to, uint256 value) external returns (bool);
  
      /**
       * @dev Moves a `value` amount of tokens from the caller's account to `to`
       * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
       * @param to The address which you want to transfer to.
       * @param value The amount of tokens to be transferred.
       * @param data Additional data with no specified format, sent in call to `to`.
       * @return A boolean value indicating whether the operation succeeded unless throwing.
       */
      function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
  
      /**
       * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
       * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
       * @param from The address which you want to send tokens from.
       * @param to The address which you want to transfer to.
       * @param value The amount of tokens to be transferred.
       * @return A boolean value indicating whether the operation succeeded unless throwing.
       */
      function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
  
      /**
       * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
       * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
       * @param from The address which you want to send tokens from.
       * @param to The address which you want to transfer to.
       * @param value The amount of tokens to be transferred.
       * @param data Additional data with no specified format, sent in call to `to`.
       * @return A boolean value indicating whether the operation succeeded unless throwing.
       */
      function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
  
      /**
       * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
       * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
       * @param spender The address which will spend the funds.
       * @param value The amount of tokens to be spent.
       * @return A boolean value indicating whether the operation succeeded unless throwing.
       */
      function approveAndCall(address spender, uint256 value) external returns (bool);
  
      /**
       * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
       * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
       * @param spender The address which will spend the funds.
       * @param value The amount of tokens to be spent.
       * @param data Additional data with no specified format, sent in call to `spender`.
       * @return A boolean value indicating whether the operation succeeded unless throwing.
       */
      function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
  }
  
  // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
  
  pragma solidity ^0.8.20;
  
  
  
  
  /**
   * @title SafeERC20
   * @dev Wrappers around ERC-20 operations that throw on failure (when the token
   * contract returns false). Tokens that return no value (and instead revert or
   * throw on failure) are also supported, non-reverting calls are assumed to be
   * successful.
   * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
   * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
   */
  library SafeERC20 {
      using Address for address;
  
      /**
       * @dev An operation with an ERC-20 token failed.
       */
      error SafeERC20FailedOperation(address token);
  
      /**
       * @dev Indicates a failed `decreaseAllowance` request.
       */
      error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
  
      /**
       * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
       * non-reverting calls are assumed to be successful.
       */
      function safeTransfer(IERC20 token, address to, uint256 value) internal {
          _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
      }
  
      /**
       * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
       * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
       */
      function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
          _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
      }
  
      /**
       * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
       * non-reverting calls are assumed to be successful.
       */
      function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
          uint256 oldAllowance = token.allowance(address(this), spender);
          forceApprove(token, spender, oldAllowance + value);
      }
  
      /**
       * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
       * value, non-reverting calls are assumed to be successful.
       */
      function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
          unchecked {
              uint256 currentAllowance = token.allowance(address(this), spender);
              if (currentAllowance < requestedDecrease) {
                  revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
              }
              forceApprove(token, spender, currentAllowance - requestedDecrease);
          }
      }
  
      /**
       * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
       * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
       * to be set to zero before setting it to a non-zero value, such as USDT.
       */
      function forceApprove(IERC20 token, address spender, uint256 value) internal {
          bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
  
          if (!_callOptionalReturnBool(token, approvalCall)) {
              _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
              _callOptionalReturn(token, approvalCall);
          }
      }
  
      /**
       * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
       * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
       * targeting contracts.
       *
       * Reverts if the returned value is other than `true`.
       */
      function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
          if (to.code.length == 0) {
              safeTransfer(token, to, value);
          } else if (!token.transferAndCall(to, value, data)) {
              revert SafeERC20FailedOperation(address(token));
          }
      }
  
      /**
       * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
       * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
       * targeting contracts.
       *
       * Reverts if the returned value is other than `true`.
       */
      function transferFromAndCallRelaxed(
          IERC1363 token,
          address from,
          address to,
          uint256 value,
          bytes memory data
      ) internal {
          if (to.code.length == 0) {
              safeTransferFrom(token, from, to, value);
          } else if (!token.transferFromAndCall(from, to, value, data)) {
              revert SafeERC20FailedOperation(address(token));
          }
      }
  
      /**
       * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
       * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
       * targeting contracts.
       *
       * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
       * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
       * once without retrying, and relies on the returned value to be true.
       *
       * Reverts if the returned value is other than `true`.
       */
      function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
          if (to.code.length == 0) {
              forceApprove(token, to, value);
          } else if (!token.approveAndCall(to, value, data)) {
              revert SafeERC20FailedOperation(address(token));
          }
      }
  
      /**
       * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
       * on the return value: the return value is optional (but if data is returned, it must not be false).
       * @param token The token targeted by the call.
       * @param data The call data (encoded using abi.encode or one of its variants).
       */
      function _callOptionalReturn(IERC20 token, bytes memory data) private {
          // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
          // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
          // the target address contains contract code and also asserts for success in the low-level call.
  
          bytes memory returndata = address(token).functionCall(data);
          if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
              revert SafeERC20FailedOperation(address(token));
          }
      }
  
      /**
       * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
       * on the return value: the return value is optional (but if data is returned, it must not be false).
       * @param token The token targeted by the call.
       * @param data The call data (encoded using abi.encode or one of its variants).
       *
       * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
       */
      function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
          // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
          // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
          // and not revert is the subcall reverts.
  
          (bool success, bytes memory returndata) = address(token).call(data);
          return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
      }
  }
  
  // File: rent.sol
  
  /**
   *Submitted for verification at Etherscan.io on 2024-04-12
  */
  
  
  pragma solidity ^0.8.0;
  
  library SafeMath {
      function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
          unchecked {
              uint256 c = a + b;
              if (c < a) return (false, 0);
              return (true, c);
          }
      }
  
      function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
          unchecked {
              if (b > a) return (false, 0);
              return (true, a - b);
          }
      }
  
      function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
          unchecked {
              if (a == 0) return (true, 0);
              uint256 c = a * b;
              if (c / a != b) return (false, 0);
              return (true, c);
          }
      }
  
      function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
          unchecked {
              if (b == 0) return (false, 0);
              return (true, a / b);
          }
      }
      function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
          unchecked {
              if (b == 0) return (false, 0);
              return (true, a % b);
          }
      }
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
          return a + b;
      }
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
          return a - b;
      }
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
          return a * b;
      }
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
          return a / b;
      }
      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
          return a % b;
      }
      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
          unchecked {
              require(b <= a, errorMessage);
              return a - b;
          }
      }
      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
          unchecked {
              require(b > 0, errorMessage);
              return a / b;
          }
      }
      function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
          unchecked {
              require(b > 0, errorMessage);
              return a % b;
          }
      }
  }
  
  pragma solidity ^0.8.0;
  
  abstract contract Context {
      function _msgSender() internal view virtual returns (address) {
          return msg.sender;
      }
  
      function _msgData() internal view virtual returns (bytes calldata) {
          return msg.data;
      }
  }
  
  abstract contract Ownable is Context {
      address private _owner;
  
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  
      constructor() {
          _transferOwnership(_msgSender());
      }
  
      modifier onlyOwner() {
          _checkOwner();
          _;
      }
  
      function owner() public view virtual returns (address) {
          return _owner;
      }
  
      function _checkOwner() internal view virtual {
          require(owner() == _msgSender(), "Ownable: caller is not the owner");
      }
  
      function renounceOwnership() public virtual onlyOwner {
          _transferOwnership(address(0));
      }
  
      function transferOwnership(address newOwner) public virtual onlyOwner {
          require(newOwner != address(0), "Ownable: new owner is the zero address");
          _transferOwnership(newOwner);
      }
  
      function _transferOwnership(address newOwner) internal virtual {
          address oldOwner = _owner;
          _owner = newOwner;
          emit OwnershipTransferred(oldOwner, newOwner);
      }
  }
  
  contract MarginTrading is Ownable {
  
      using SafeMath for uint256;
      address public poolTokenAddress;
      address public operatorWallet;
      using SafeERC20 for IERC20;
  
      struct Order {
          uint256 margin; // token amount in wei
          uint64 leverage; // leverage ex: 5x, 10x 
          uint256 totalFund; // fund with leverage
          address orderOwner;
          address poolTokenAddress_;
          uint256 liquidationUnderlyingAssest;
          bool isActive;
          bool isliquidated;
          uint256 amountunderlineAssest;
          Side side;
          ORDERTYPE orderType; // market , limit 
          uint256 createdAt;
      }
  
      mapping(uint256 => Order) public orders; // orderId => Order
      mapping(address => uint256[]) private userOrderIds;
  
      enum Side {
          LONG,
          SHORT
      }
      enum ORDERTYPE {
          MARKET,
          LIMIT
      }
  
      enum UpdateTicker {
          GREATER,
          LESS
      }
      
      event OrderCreatedEvent(
          uint256  margin,
          uint64  leverage,
          uint256  totalFund,
          address  orderOwner,    
          uint256 liquidationUnderlyingAssest,
          bool isActive, 
          Side side,      
          uint256 createdAt,
          uint256 amountunderlineAssest
      );
  
      event cancelOrderEvent(
          address user,
          uint256 orderId,
          uint256 canceledAt,
          uint256 returnAmount
  
      );
      
      event liquidateUserEvent(
          uint256 orderId,
          uint256 liquidatedAt
  
      );
  
      modifier onlyOperator() {
          require(msg.sender == operatorWallet ," Invalid operator wallet");
          _;
      }
  
      constructor(address _poolTokenAddress, address _operatorWallet) {
          poolTokenAddress=_poolTokenAddress;
          operatorWallet = _operatorWallet;
      }
  
      function createOrder(
          uint256 newOrderId,
          uint256 marginAmount, // in USDT wei
          uint256 underlyingAssets,           // underline assest
          uint8 leverage, // In USDT
          uint256 liquidationUnderlyingAssest,
          Side side,
          ORDERTYPE orderType
      ) 
      external returns(Order memory) {
          userOrderIds[msg.sender].push(newOrderId); // we are assuming the order id will be unique from backend....
          Order storage userDetails = orders[newOrderId];
          require(IERC20(poolTokenAddress).balanceOf(msg.sender) >= marginAmount,"Insufficient token balance");
          IERC20(poolTokenAddress).safeTransferFrom(msg.sender, address(this), marginAmount);
          userDetails.margin= marginAmount;
          userDetails.leverage = leverage;
          userDetails.totalFund = (marginAmount.mul(leverage));
          userDetails.orderOwner = msg.sender;
          userDetails.poolTokenAddress_ = poolTokenAddress;
          userDetails.liquidationUnderlyingAssest = liquidationUnderlyingAssest;
          userDetails.createdAt = block.timestamp;
          userDetails.side = side;
          userDetails.isActive= true;
          userDetails.amountunderlineAssest= underlyingAssets;
          userDetails.orderType = orderType;
          emit OrderCreatedEvent(marginAmount,leverage,(marginAmount.mul(leverage)), msg.sender,liquidationUnderlyingAssest,true,side,block.timestamp,underlyingAssets);
          return(userDetails);
      }
  
      function createOrderForUser(
          address userAddress,
          uint256 newOrderId,
          uint256 marginAmount, // in USDT wei
          uint256 underlyingAssets,           // underline assest
          uint8 leverage, // In USDT
          uint256 liquidationUnderlyingAssest,
          Side side,
          ORDERTYPE orderType
      )
  
      external onlyOperator() returns(Order memory) {
          userOrderIds[msg.sender].push(newOrderId); // we are assuming the order id will be unique from backend....
          Order storage userDetails = orders[newOrderId];
          require(IERC20(poolTokenAddress).balanceOf(userAddress) >= marginAmount,"Insufficient token balance");
          IERC20(poolTokenAddress).safeTransferFrom(userAddress, address(this), marginAmount);
          userDetails.margin= marginAmount;
          userDetails.leverage = leverage;
          userDetails.totalFund = (marginAmount.mul(leverage));
          userDetails.orderOwner = userAddress;
          userDetails.poolTokenAddress_ = poolTokenAddress;
          userDetails.liquidationUnderlyingAssest = liquidationUnderlyingAssest;
          userDetails.createdAt = block.timestamp;
          userDetails.side = side;
          userDetails.isActive= true;
          userDetails.amountunderlineAssest= underlyingAssets;
          userDetails.orderType = orderType;
          emit OrderCreatedEvent(marginAmount,leverage,(marginAmount.mul(leverage)), userAddress,liquidationUnderlyingAssest,true,side,block.timestamp,underlyingAssets);
          return(userDetails);
      }
      
      function cancelOrder(uint256 _orderId, uint256 returnAmount,address userAdress) external onlyOperator() returns (bool){
          require(orders[_orderId].isActive,"this order already deactivated");
          require(!(orders[_orderId].isliquidated),"this order is  liquidated");
          require(orders[_orderId].orderOwner==userAdress,"owner mismatch");
          require(IERC20(poolTokenAddress).balanceOf(address(this))>=returnAmount,"insufficent amount in contract");
          orders[_orderId].isActive=false;
          IERC20(poolTokenAddress).safeTransfer(userAdress, returnAmount);
          emit cancelOrderEvent(userAdress,_orderId,block.timestamp,returnAmount);
          return true;
      }
       
      function liquidateUser(uint256 _orderId) external onlyOperator() returns (bool){
          require(orders[_orderId].isActive,"this order already deactivated");
          require(!(orders[_orderId].isliquidated),"this order is liquidated");
          orders[_orderId].isActive=false;
          orders[_orderId].isliquidated=true;
          emit liquidateUserEvent(_orderId,block.timestamp);
          return true;
     }
  
      /// @notice Function to get user order ids 
      /// @param userAddress The user address 
      function getUserOrderIds(address userAddress) external view returns(uint256[] memory){
          return userOrderIds[userAddress];
      }
      
      /// @notice Function to set the operator wallet
      /// @param _newOperator The new operator wallet
      function setOperatorWallet(address _newOperator) external onlyOwner {
          require(_newOperator != address(0), "Invalid wallet");
          operatorWallet = _newOperator;
      }
  
      function setPoolTokenAddress(address _poolTokenAddress) external onlyOwner returns(bool){
          require(_poolTokenAddress != address(0), "Invalid wallet");
          poolTokenAddress = _poolTokenAddress;
          return true;
      }
       
      /**
      * @dev Allows the owner to drain the remaining ERC20 tokens held by this contract.
      * @notice Transfers all tokens held by this contract to the owner's address.
      * @dev Requires that there are tokens available to drain.
      */ 
      function drainToken() external onlyOwner() {
          uint256 balance = IERC20(poolTokenAddress).balanceOf(address(this));
          require(balance > 0, "No tokens to drain");
          IERC20(poolTokenAddress).safeTransfer(owner(), balance);
      }
  
      /**
      * @dev Allows the owner to drain the remaining Ether (ETH) held by this contract.
      * @notice Transfers all Ether held by this contract to the owner's address.
      */
      function drainETH() external onlyOwner {
          payable(owner()).transfer(address(this).balance);
      }
  
       receive() external payable {}
  }