Advertisement
xpppppppaicyber

escrow.sol

Jun 15th, 2025
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.19;
  3.  
  4. import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
  5. import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
  6. import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
  7. import "@openzeppelin/contracts/security/Pausable.sol";
  8. import "@openzeppelin/contracts/access/Ownable.sol";
  9. import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
  10.  
  11. /**
  12.  * @title SecureUSDCEscrow
  13.  * @dev Ultra-secure escrow contract for USDC transactions with comprehensive security features
  14.  * @author AI Assistant
  15.  */
  16. contract SecureUSDCEscrow is ReentrancyGuard, Pausable, Ownable {
  17.     using SafeERC20 for IERC20;
  18.     using ECDSA for bytes32;
  19.  
  20.     // USDC contract address - configurable for different networks
  21.     IERC20 public immutable USDC;
  22.    
  23.     // Network-specific USDC addresses
  24.     address public constant ETHEREUM_USDC = 0xA0b86a33E6441f8952F865F7cD0b06de36B24B61;
  25.     address public constant BASE_USDC = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913;
  26.     address public constant POLYGON_USDC = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174;
  27.     address public constant ARBITRUM_USDC = 0xaf88d065e77c8cC2239327C5EDb3A432268e5831;
  28.    
  29.     // Maximum escrow duration (90 days)
  30.     uint256 public constant MAX_ESCROW_DURATION = 90 days;
  31.    
  32.     // Minimum escrow amount (1 USDC)
  33.     uint256 public constant MIN_ESCROW_AMOUNT = 1e6; // USDC has 6 decimals
  34.    
  35.     // Maximum escrow amount (1M USDC)
  36.     uint256 public constant MAX_ESCROW_AMOUNT = 1e12; // 1M USDC with 6 decimals
  37.    
  38.     // Fee percentage (0.5% = 50 basis points)
  39.     uint256 public feePercentage = 50;
  40.     uint256 public constant MAX_FEE_PERCENTAGE = 500; // 5% max fee
  41.    
  42.     // Emergency timeout (7 days after escrow expiry)
  43.     uint256 public constant EMERGENCY_TIMEOUT = 7 days;
  44.  
  45.     enum EscrowStatus {
  46.         ACTIVE,
  47.         COMPLETED,
  48.         REFUNDED,
  49.         DISPUTED,
  50.         EMERGENCY_WITHDRAWN
  51.     }
  52.  
  53.     struct EscrowData {
  54.         address depositor;
  55.         address beneficiary;
  56.         address arbiter;
  57.         uint256 amount;
  58.         uint256 fee;
  59.         uint256 createdAt;
  60.         uint256 expiresAt;
  61.         EscrowStatus status;
  62.         string description;
  63.         bytes32 conditionsHash; // Hash of conditions for verification
  64.         bool depositorApproved;
  65.         bool beneficiaryApproved;
  66.         bool arbiterApproved;
  67.     }
  68.  
  69.     // Mappings
  70.     mapping(uint256 => EscrowData) public escrows;
  71.     mapping(address => bool) public authorizedArbiters;
  72.     mapping(address => uint256[]) public userEscrows;
  73.     mapping(bytes32 => bool) public usedSignatures;
  74.    
  75.     // State variables
  76.     uint256 public nextEscrowId = 1;
  77.     uint256 public totalEscrowValue;
  78.     address public feeRecipient;
  79.     bool public emergencyMode;
  80.    
  81.     // Events
  82.     event EscrowCreated(
  83.         uint256 indexed escrowId,
  84.         address indexed depositor,
  85.         address indexed beneficiary,
  86.         address arbiter,
  87.         uint256 amount,
  88.         uint256 expiresAt,
  89.         string description
  90.     );
  91.    
  92.     event EscrowCompleted(uint256 indexed escrowId, address indexed beneficiary, uint256 amount);
  93.     event EscrowRefunded(uint256 indexed escrowId, address indexed depositor, uint256 amount);
  94.     event EscrowDisputed(uint256 indexed escrowId, address indexed disputer);
  95.     event ApprovalGiven(uint256 indexed escrowId, address indexed approver, string role);
  96.     event ArbiterDecision(uint256 indexed escrowId, address indexed arbiter, bool releaseTobeneficiary);
  97.     event EmergencyWithdrawal(uint256 indexed escrowId, address indexed recipient, uint256 amount);
  98.     event FeeUpdated(uint256 oldFee, uint256 newFee);
  99.     event ArbiterAuthorized(address indexed arbiter, bool authorized);
  100.     event NetworkSupported(string network, address usdcAddress);
  101.  
  102.     // Modifiers
  103.     modifier validEscrow(uint256 _escrowId) {
  104.         require(_escrowId > 0 && _escrowId < nextEscrowId, "Invalid escrow ID");
  105.         _;
  106.     }
  107.    
  108.     modifier onlyParticipant(uint256 _escrowId) {
  109.         EscrowData storage escrow = escrows[_escrowId];
  110.         require(
  111.             msg.sender == escrow.depositor ||
  112.             msg.sender == escrow.beneficiary ||
  113.             msg.sender == escrow.arbiter,
  114.             "Not authorized"
  115.         );
  116.         _;
  117.     }
  118.    
  119.     modifier onlyActiveEscrow(uint256 _escrowId) {
  120.         require(escrows[_escrowId].status == EscrowStatus.ACTIVE, "Escrow not active");
  121.         _;
  122.     }
  123.    
  124.     modifier notExpired(uint256 _escrowId) {
  125.         require(block.timestamp <= escrows[_escrowId].expiresAt, "Escrow expired");
  126.         _;
  127.     }
  128.  
  129.     constructor(address _feeRecipient, address _usdcAddress) {
  130.         require(_feeRecipient != address(0), "Invalid fee recipient");
  131.         require(_usdcAddress != address(0), "Invalid USDC address");
  132.        
  133.         // Validate USDC address is one of the supported networks
  134.         require(
  135.             _usdcAddress == ETHEREUM_USDC ||
  136.             _usdcAddress == BASE_USDC ||
  137.             _usdcAddress == POLYGON_USDC ||
  138.             _usdcAddress == ARBITRUM_USDC,
  139.             "Unsupported USDC address"
  140.         );
  141.        
  142.         feeRecipient = _feeRecipient;
  143.         USDC = IERC20(_usdcAddress);
  144.     }
  145.  
  146.     /**
  147.      * @dev Create a new escrow with comprehensive validation
  148.      */
  149.     function createEscrow(
  150.         address _beneficiary,
  151.         address _arbiter,
  152.         uint256 _amount,
  153.         uint256 _duration,
  154.         string calldata _description,
  155.         bytes32 _conditionsHash
  156.     ) external nonReentrant whenNotPaused returns (uint256) {
  157.         // Input validation
  158.         require(_beneficiary != address(0), "Invalid beneficiary");
  159.         require(_arbiter != address(0), "Invalid arbiter");
  160.         require(authorizedArbiters[_arbiter], "Arbiter not authorized");
  161.         require(_amount >= MIN_ESCROW_AMOUNT && _amount <= MAX_ESCROW_AMOUNT, "Invalid amount");
  162.         require(_duration > 0 && _duration <= MAX_ESCROW_DURATION, "Invalid duration");
  163.         require(bytes(_description).length > 0, "Description required");
  164.         require(_conditionsHash != bytes32(0), "Conditions hash required");
  165.        
  166.         // Ensure unique participants
  167.         require(_beneficiary != msg.sender, "Cannot be own beneficiary");
  168.         require(_arbiter != msg.sender && _arbiter != _beneficiary, "Arbiter conflicts");
  169.  
  170.         // Calculate fee
  171.         uint256 fee = (_amount * feePercentage) / 10000;
  172.         uint256 totalRequired = _amount + fee;
  173.  
  174.         // Transfer tokens from depositor
  175.         USDC.safeTransferFrom(msg.sender, address(this), totalRequired);
  176.  
  177.         uint256 escrowId = nextEscrowId++;
  178.         uint256 expiresAt = block.timestamp + _duration;
  179.  
  180.         // Create escrow
  181.         escrows[escrowId] = EscrowData({
  182.             depositor: msg.sender,
  183.             beneficiary: _beneficiary,
  184.             arbiter: _arbiter,
  185.             amount: _amount,
  186.             fee: fee,
  187.             createdAt: block.timestamp,
  188.             expiresAt: expiresAt,
  189.             status: EscrowStatus.ACTIVE,
  190.             description: _description,
  191.             conditionsHash: _conditionsHash,
  192.             depositorApproved: false,
  193.             beneficiaryApproved: false,
  194.             arbiterApproved: false
  195.         });
  196.  
  197.         // Update state
  198.         userEscrows[msg.sender].push(escrowId);
  199.         userEscrows[_beneficiary].push(escrowId);
  200.         totalEscrowValue += _amount;
  201.  
  202.         emit EscrowCreated(escrowId, msg.sender, _beneficiary, _arbiter, _amount, expiresAt, _description);
  203.        
  204.         return escrowId;
  205.     }
  206.  
  207.     /**
  208.      * @dev Approve escrow completion (multi-signature approach)
  209.      */
  210.     function approveEscrow(uint256 _escrowId)
  211.         external
  212.         validEscrow(_escrowId)
  213.         onlyParticipant(_escrowId)
  214.         onlyActiveEscrow(_escrowId)
  215.         notExpired(_escrowId)
  216.         nonReentrant
  217.     {
  218.         EscrowData storage escrow = escrows[_escrowId];
  219.        
  220.         if (msg.sender == escrow.depositor) {
  221.             require(!escrow.depositorApproved, "Already approved");
  222.             escrow.depositorApproved = true;
  223.             emit ApprovalGiven(_escrowId, msg.sender, "depositor");
  224.         } else if (msg.sender == escrow.beneficiary) {
  225.             require(!escrow.beneficiaryApproved, "Already approved");
  226.             escrow.beneficiaryApproved = true;
  227.             emit ApprovalGiven(_escrowId, msg.sender, "beneficiary");
  228.         } else if (msg.sender == escrow.arbiter) {
  229.             require(!escrow.arbiterApproved, "Already approved");
  230.             escrow.arbiterApproved = true;
  231.             emit ApprovalGiven(_escrowId, msg.sender, "arbiter");
  232.         }
  233.  
  234.         // Check if escrow can be completed (require 2 out of 3 approvals)
  235.         uint256 approvals = 0;
  236.         if (escrow.depositorApproved) approvals++;
  237.         if (escrow.beneficiaryApproved) approvals++;
  238.         if (escrow.arbiterApproved) approvals++;
  239.  
  240.         if (approvals >= 2) {
  241.             _completeEscrow(_escrowId);
  242.         }
  243.     }
  244.  
  245.     /**
  246.      * @dev Complete escrow and release funds to beneficiary
  247.      */
  248.     function _completeEscrow(uint256 _escrowId) internal {
  249.         EscrowData storage escrow = escrows[_escrowId];
  250.         escrow.status = EscrowStatus.COMPLETED;
  251.         totalEscrowValue -= escrow.amount;
  252.  
  253.         // Transfer funds
  254.         USDC.safeTransfer(escrow.beneficiary, escrow.amount);
  255.         if (escrow.fee > 0) {
  256.             USDC.safeTransfer(feeRecipient, escrow.fee);
  257.         }
  258.  
  259.         emit EscrowCompleted(_escrowId, escrow.beneficiary, escrow.amount);
  260.     }
  261.  
  262.     /**
  263.      * @dev Refund escrow to depositor (after expiry or by arbiter decision)
  264.      */
  265.     function refundEscrow(uint256 _escrowId)
  266.         external
  267.         validEscrow(_escrowId)
  268.         onlyActiveEscrow(_escrowId)
  269.         nonReentrant
  270.     {
  271.         EscrowData storage escrow = escrows[_escrowId];
  272.        
  273.         require(
  274.             msg.sender == escrow.arbiter ||
  275.             (msg.sender == escrow.depositor && block.timestamp > escrow.expiresAt),
  276.             "Not authorized to refund"
  277.         );
  278.  
  279.         escrow.status = EscrowStatus.REFUNDED;
  280.         totalEscrowValue -= escrow.amount;
  281.  
  282.         // Refund amount to depositor, fee to fee recipient
  283.         USDC.safeTransfer(escrow.depositor, escrow.amount);
  284.         if (escrow.fee > 0) {
  285.             USDC.safeTransfer(feeRecipient, escrow.fee);
  286.         }
  287.  
  288.         emit EscrowRefunded(_escrowId, escrow.depositor, escrow.amount);
  289.     }
  290.  
  291.     /**
  292.      * @dev Raise a dispute (only depositor or beneficiary)
  293.      */
  294.     function raiseDispute(uint256 _escrowId)
  295.         external
  296.         validEscrow(_escrowId)
  297.         onlyActiveEscrow(_escrowId)
  298.         notExpired(_escrowId)
  299.     {
  300.         EscrowData storage escrow = escrows[_escrowId];
  301.         require(
  302.             msg.sender == escrow.depositor || msg.sender == escrow.beneficiary,
  303.             "Only parties can dispute"
  304.         );
  305.        
  306.         escrow.status = EscrowStatus.DISPUTED;
  307.         emit EscrowDisputed(_escrowId, msg.sender);
  308.     }
  309.  
  310.     /**
  311.      * @dev Arbiter decision for disputed escrow
  312.      */
  313.     function resolveDispute(uint256 _escrowId, bool _releaseToBeneficiary)
  314.         external
  315.         validEscrow(_escrowId)
  316.         nonReentrant
  317.     {
  318.         EscrowData storage escrow = escrows[_escrowId];
  319.         require(msg.sender == escrow.arbiter, "Only arbiter can resolve");
  320.         require(escrow.status == EscrowStatus.DISPUTED, "Not disputed");
  321.  
  322.         totalEscrowValue -= escrow.amount;
  323.  
  324.         if (_releaseToBeneficiary) {
  325.             escrow.status = EscrowStatus.COMPLETED;
  326.             USDC.safeTransfer(escrow.beneficiary, escrow.amount);
  327.             emit EscrowCompleted(_escrowId, escrow.beneficiary, escrow.amount);
  328.         } else {
  329.             escrow.status = EscrowStatus.REFUNDED;
  330.             USDC.safeTransfer(escrow.depositor, escrow.amount);
  331.             emit EscrowRefunded(_escrowId, escrow.depositor, escrow.amount);
  332.         }
  333.  
  334.         // Arbiter gets the fee for resolution
  335.         if (escrow.fee > 0) {
  336.             USDC.safeTransfer(escrow.arbiter, escrow.fee);
  337.         }
  338.  
  339.         emit ArbiterDecision(_escrowId, msg.sender, _releaseToBeneficiary);
  340.     }
  341.  
  342.     /**
  343.      * @dev Emergency withdrawal after timeout (7 days post-expiry)
  344.      */
  345.     function emergencyWithdraw(uint256 _escrowId)
  346.         external
  347.         validEscrow(_escrowId)
  348.         onlyActiveEscrow(_escrowId)
  349.         nonReentrant
  350.     {
  351.         EscrowData storage escrow = escrows[_escrowId];
  352.         require(
  353.             msg.sender == escrow.depositor || msg.sender == escrow.beneficiary,
  354.             "Not authorized"
  355.         );
  356.         require(
  357.             block.timestamp > escrow.expiresAt + EMERGENCY_TIMEOUT,
  358.             "Emergency timeout not reached"
  359.         );
  360.  
  361.         escrow.status = EscrowStatus.EMERGENCY_WITHDRAWN;
  362.         totalEscrowValue -= escrow.amount;
  363.  
  364.         // Return to depositor in emergency
  365.         USDC.safeTransfer(escrow.depositor, escrow.amount + escrow.fee);
  366.  
  367.         emit EmergencyWithdrawal(_escrowId, escrow.depositor, escrow.amount);
  368.     }
  369.  
  370.     /**
  371.      * @dev Signature-based approval for gasless transactions
  372.      */
  373.     function approveWithSignature(
  374.         uint256 _escrowId,
  375.         bytes calldata _signature,
  376.         uint256 _nonce,
  377.         uint256 _deadline
  378.     ) external validEscrow(_escrowId) onlyActiveEscrow(_escrowId) nonReentrant {
  379.         require(block.timestamp <= _deadline, "Signature expired");
  380.        
  381.         bytes32 hash = keccak256(abi.encodePacked(
  382.             "APPROVE_ESCROW",
  383.             _escrowId,
  384.             _nonce,
  385.             _deadline,
  386.             address(this)
  387.         ));
  388.        
  389.         bytes32 messageHash = hash.toEthSignedMessageHash();
  390.         require(!usedSignatures[messageHash], "Signature already used");
  391.        
  392.         address signer = messageHash.recover(_signature);
  393.         EscrowData storage escrow = escrows[_escrowId];
  394.        
  395.         require(
  396.             signer == escrow.depositor ||
  397.             signer == escrow.beneficiary ||
  398.             signer == escrow.arbiter,
  399.             "Invalid signature"
  400.         );
  401.  
  402.         usedSignatures[messageHash] = true;
  403.  
  404.         // Apply approval logic similar to approveEscrow
  405.         if (signer == escrow.depositor) {
  406.             require(!escrow.depositorApproved, "Already approved");
  407.             escrow.depositorApproved = true;
  408.             emit ApprovalGiven(_escrowId, signer, "depositor");
  409.         } else if (signer == escrow.beneficiary) {
  410.             require(!escrow.beneficiaryApproved, "Already approved");
  411.             escrow.beneficiaryApproved = true;
  412.             emit ApprovalGiven(_escrowId, signer, "beneficiary");
  413.         } else if (signer == escrow.arbiter) {
  414.             require(!escrow.arbiterApproved, "Already approved");
  415.             escrow.arbiterApproved = true;
  416.             emit ApprovalGiven(_escrowId, signer, "arbiter");
  417.         }
  418.  
  419.         // Check completion
  420.         uint256 approvals = 0;
  421.         if (escrow.depositorApproved) approvals++;
  422.         if (escrow.beneficiaryApproved) approvals++;
  423.         if (escrow.arbiterApproved) approvals++;
  424.  
  425.         if (approvals >= 2) {
  426.             _completeEscrow(_escrowId);
  427.         }
  428.     }
  429.  
  430.     // Admin functions
  431.     function setFeePercentage(uint256 _feePercentage) external onlyOwner {
  432.         require(_feePercentage <= MAX_FEE_PERCENTAGE, "Fee too high");
  433.         uint256 oldFee = feePercentage;
  434.         feePercentage = _feePercentage;
  435.         emit FeeUpdated(oldFee, _feePercentage);
  436.     }
  437.  
  438.     function setFeeRecipient(address _feeRecipient) external onlyOwner {
  439.         require(_feeRecipient != address(0), "Invalid address");
  440.         feeRecipient = _feeRecipient;
  441.     }
  442.  
  443.     function authorizeArbiter(address _arbiter, bool _authorized) external onlyOwner {
  444.         require(_arbiter != address(0), "Invalid address");
  445.         authorizedArbiters[_arbiter] = _authorized;
  446.         emit ArbiterAuthorized(_arbiter, _authorized);
  447.     }
  448.  
  449.     function pause() external onlyOwner {
  450.         _pause();
  451.     }
  452.  
  453.     function unpause() external onlyOwner {
  454.         _unpause();
  455.     }
  456.  
  457.     function setEmergencyMode(bool _emergencyMode) external onlyOwner {
  458.         emergencyMode = _emergencyMode;
  459.     }
  460.  
  461.     // View functions
  462.     function getEscrow(uint256 _escrowId) external view validEscrow(_escrowId) returns (EscrowData memory) {
  463.         return escrows[_escrowId];
  464.     }
  465.  
  466.     function getUserEscrows(address _user) external view returns (uint256[] memory) {
  467.         return userEscrows[_user];
  468.     }
  469.  
  470.     function getEscrowCount() external view returns (uint256) {
  471.         return nextEscrowId - 1;
  472.     }
  473.  
  474.     function isEscrowExpired(uint256 _escrowId) external view validEscrow(_escrowId) returns (bool) {
  475.         return block.timestamp > escrows[_escrowId].expiresAt;
  476.     }
  477.  
  478.     function canEmergencyWithdraw(uint256 _escrowId) external view validEscrow(_escrowId) returns (bool) {
  479.         return block.timestamp > escrows[_escrowId].expiresAt + EMERGENCY_TIMEOUT;
  480.     }
  481.  
  482.     function getApprovalStatus(uint256 _escrowId) external view validEscrow(_escrowId) returns (
  483.         bool depositorApproved,
  484.         bool beneficiaryApproved,
  485.         bool arbiterApproved,
  486.         uint256 totalApprovals
  487.     ) {
  488.         EscrowData storage escrow = escrows[_escrowId];
  489.         depositorApproved = escrow.depositorApproved;
  490.         beneficiaryApproved = escrow.beneficiaryApproved;
  491.         arbiterApproved = escrow.arbiterApproved;
  492.        
  493.         totalApprovals = 0;
  494.         if (depositorApproved) totalApprovals++;
  495.         if (beneficiaryApproved) totalApprovals++;
  496.         if (arbiterApproved) totalApprovals++;
  497.     }
  498.  
  499.     /**
  500.      * @dev Get supported network information
  501.      */
  502.     function getSupportedNetworks() external pure returns (
  503.         string[] memory networks,
  504.         address[] memory addresses
  505.     ) {
  506.         networks = new string[](4);
  507.         addresses = new address[](4);
  508.        
  509.         networks[0] = "Ethereum";
  510.         addresses[0] = ETHEREUM_USDC;
  511.        
  512.         networks[1] = "Base";
  513.         addresses[1] = BASE_USDC;
  514.        
  515.         networks[2] = "Polygon";
  516.         addresses[2] = POLYGON_USDC;
  517.        
  518.         networks[3] = "Arbitrum";
  519.         addresses[3] = ARBITRUM_USDC;
  520.     }
  521. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement