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);
}
}