// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract NEscrow is Ownable { enum EscrowStatus { Created, Released, Refunded } struct Escrow { address sender; address recipient; uint256 amount; EscrowStatus status; uint256 refundTimestamp; } IERC20 public navisToken; mapping(bytes32 => Escrow) public escrows; event EscrowCreated(bytes32 indexed escrowId, address indexed sender, address indexed recipient, uint256 amount); event EscrowReleased(bytes32 indexed escrowId, address indexed sender, address indexed recipient, uint256 amount); event EscrowRefunded(bytes32 indexed escrowId, address indexed sender, address indexed recipient, uint256 amount); constructor(address _navisToken) { navisToken = IERC20(_navisToken); } modifier onlyParticipants(bytes32 escrowId) { Escrow storage escrow = escrows[escrowId]; require(escrow.sender == msg.sender || escrow.recipient == msg.sender, "Not a participant"); _; } modifier escrowNotReleased(bytes32 escrowId) { require(escrows[escrowId].status != EscrowStatus.Released, "Escrow already released"); _; } modifier escrowNotRefunded(bytes32 escrowId) { require(escrows[escrowId].status != EscrowStatus.Refunded, "Escrow already refunded"); _; } function createEscrow(bytes32 escrowId, address recipient, uint256 amount) external { require(recipient != address(0), "Invalid recipient address"); require(amount > 0, "Amount must be greater than zero"); Escrow storage escrow = escrows[escrowId]; require(escrow.status == EscrowStatus.Created, "Escrow already exists"); // Transfer NAVIS tokens to the escrow contract require(navisToken.transferFrom(msg.sender, address(this), amount), "Transfer failed"); escrow.sender = msg.sender; escrow.recipient = recipient; escrow.amount = amount; escrow.status = EscrowStatus.Created; emit EscrowCreated(escrowId, msg.sender, recipient, amount); } function releaseEscrow(bytes32 escrowId) external onlyParticipants(escrowId) escrowNotReleased(escrowId) { Escrow storage escrow = escrows[escrowId]; // Transfer NAVIS tokens to the recipient require(navisToken.transfer(escrow.recipient, escrow.amount), "Transfer failed"); escrow.status = EscrowStatus.Released; emit EscrowReleased(escrowId, escrow.sender, escrow.recipient, escrow.amount); } function refundEscrow(bytes32 escrowId) external onlyParticipants(escrowId) escrowNotRefunded(escrowId) { Escrow storage escrow = escrows[escrowId]; // Check if the refund timestamp has passed require(block.timestamp >= escrow.refundTimestamp, "Refund not allowed before the specified timestamp"); // Transfer NAVIS tokens back to the sender require(navisToken.transfer(escrow.sender, escrow.amount), "Transfer failed"); escrow.status = EscrowStatus.Refunded; emit EscrowRefunded(escrowId, escrow.sender, escrow.recipient, escrow.amount); } function setRefundTimestamp(bytes32 escrowId, uint256 newRefundTimestamp) external onlyOwner { Escrow storage escrow = escrows[escrowId]; require(escrow.status == EscrowStatus.Created, "Refund timestamp can only be set for Created escrows"); escrow.refundTimestamp = newRefundTimestamp; } function getEscrowDetails(bytes32 escrowId) external view returns (Escrow memory) { return escrows[escrowId]; } }