Supplier Payment Escrow

What it does:
Holds payments in escrow for suppliers and releases funds automatically once predefined conditions (delivery, inspection, approval) are met.

Why it matters:
Reduces payment disputes, ensures trust between buyers and suppliers, and provides transparent, auditable escrow transactions.

How it works:

  • Buyer deposits payment into escrow on-chain

  • Supplier fulfills delivery or service obligations

  • Escrow conditions are verified (shipment confirmation, inspection, approval)

  • Payment is automatically released to the supplier upon fulfillment

  • Partial payments or milestone-based releases are supported

  • Disputes can be handled via multi-signature or arbitration rules

  • Integrates with Supply Chain Traceability, Cold Chain Monitoring, and Automated Trade Finance

      // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title SupplierPaymentEscrow
 * @author Nam
 * @notice Holds and releases payments to suppliers based on fulfillment conditions
 */
contract SupplierPaymentEscrow is Ownable {

    struct Escrow {
        address payable buyer;
        address payable supplier;
        uint256 amount;
        bool delivered;
        bool approved;
        bool released;
    }

    mapping(uint256 => Escrow) public escrows;
    uint256 public escrowCount;

    mapping(address => bool) public inspectors;

    // -------------------- EVENTS --------------------

    event EscrowCreated(uint256 indexed escrowId, address buyer, address supplier, uint256 amount);
    event DeliveryConfirmed(uint256 indexed escrowId);
    event ApprovalGranted(uint256 indexed escrowId, address inspector);
    event PaymentReleased(uint256 indexed escrowId, uint256 amount);
    event InspectorApproved(address inspector);

    // -------------------- INSPECTOR MANAGEMENT --------------------

    function approveInspector(address _inspector) external onlyOwner {
        inspectors[_inspector] = true;
        emit InspectorApproved(_inspector);
    }

    function revokeInspector(address _inspector) external onlyOwner {
        inspectors[_inspector] = false;
    }

    // -------------------- ESCROW CREATION --------------------

    function createEscrow(address payable _supplier) external payable {
        require(msg.value > 0, "Payment required");

        escrowCount += 1;
        escrows[escrowCount] = Escrow({
            buyer: payable(msg.sender),
            supplier: _supplier,
            amount: msg.value,
            delivered: false,
            approved: false,
            released: false
        });

        emit EscrowCreated(escrowCount, msg.sender, _supplier, msg.value);
    }

    // -------------------- DELIVERY & APPROVAL --------------------

    function confirmDelivery(uint256 _escrowId) external {
        Escrow storage e = escrows[_escrowId];
        require(msg.sender == e.supplier, "Only supplier can confirm delivery");
        require(!e.delivered, "Already confirmed");

        e.delivered = true;
        emit DeliveryConfirmed(_escrowId);
    }

    function approveDelivery(uint256 _escrowId) external {
        require(inspectors[msg.sender], "Not an authorized inspector");

        Escrow storage e = escrows[_escrowId];
        require(e.delivered, "Delivery not confirmed");
        require(!e.approved, "Already approved");

        e.approved = true;
        emit ApprovalGranted(_escrowId, msg.sender);
    }

    // -------------------- PAYMENT RELEASE --------------------

    function releasePayment(uint256 _escrowId) external {
        Escrow storage e = escrows[_escrowId];
        require(e.delivered && e.approved, "Conditions not met");
        require(!e.released, "Payment already released");

        e.released = true;
        e.supplier.transfer(e.amount);

        emit PaymentReleased(_escrowId, e.amount);
    }
}