Decentralized Marketplace Escrow
What it does:
Holds payments in escrow for marketplace transactions and releases funds to sellers only when buyers confirm receipt or predefined conditions are met.
Why it matters:
Protects buyers from fraud, ensures sellers are paid upon fulfillment, reduces disputes, and provides transparent, auditable escrow transactions.
How it works:
-
Buyers deposit payment into the escrow contract when making a purchase
-
Sellers fulfill the order (digital or physical goods)
-
Buyer confirms receipt or smart contract verifies delivery via integration (e.g., Supply Chain Traceability)
-
Payment is released automatically to the seller
-
Partial payments, refunds, or dispute handling can be managed via multi-signature or arbitration
-
Integrates with on-chain marketplaces, logistics tracking, and reputation systems
-
Public dashboards allow monitoring of escrowed funds and transaction status
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title MarketplaceEscrow
* @author Nam
* @notice Holds payments in escrow for marketplace transactions and releases upon fulfillment
*/
contract MarketplaceEscrow is Ownable {
struct Escrow {
address payable buyer;
address payable seller;
uint256 amount;
bool delivered;
bool released;
bool refunded;
}
mapping(uint256 => Escrow) public escrows;
uint256 public escrowCount;
mapping(address => bool) public authorizedArbiters;
// -------------------- EVENTS --------------------
event EscrowCreated(uint256 indexed escrowId, address buyer, address seller, uint256 amount);
event DeliveryConfirmed(uint256 indexed escrowId);
event PaymentReleased(uint256 indexed escrowId, uint256 amount);
event RefundIssued(uint256 indexed escrowId, uint256 amount);
event ArbiterApproved(address arbiter);
// -------------------- ARBITER MANAGEMENT --------------------
function approveArbiter(address _arbiter) external onlyOwner {
authorizedArbiters[_arbiter] = true;
emit ArbiterApproved(_arbiter);
}
function revokeArbiter(address _arbiter) external onlyOwner {
authorizedArbiters[_arbiter] = false;
}
// -------------------- ESCROW CREATION --------------------
function createEscrow(address payable _seller) external payable {
require(msg.value > 0, "Payment required");
escrowCount += 1;
escrows[escrowCount] = Escrow({
buyer: payable(msg.sender),
seller: _seller,
amount: msg.value,
delivered: false,
released: false,
refunded: false
});
emit EscrowCreated(escrowCount, msg.sender, _seller, msg.value);
}
// -------------------- DELIVERY CONFIRMATION --------------------
function confirmDelivery(uint256 _escrowId) external {
Escrow storage e = escrows[_escrowId];
require(msg.sender == e.buyer, "Only buyer can confirm delivery");
require(!e.delivered, "Already confirmed");
e.delivered = true;
emit DeliveryConfirmed(_escrowId);
}
// -------------------- PAYMENT RELEASE --------------------
function releasePayment(uint256 _escrowId) external {
Escrow storage e = escrows[_escrowId];
require(e.delivered, "Delivery not confirmed");
require(!e.released, "Payment already released");
e.released = true;
e.seller.transfer(e.amount);
emit PaymentReleased(_escrowId, e.amount);
}
// -------------------- REFUNDS / DISPUTES --------------------
function issueRefund(uint256 _escrowId) external {
require(authorizedArbiters[msg.sender], "Not authorized arbiter");
Escrow storage e = escrows[_escrowId];
require(!e.released, "Payment already released");
require(!e.refunded, "Already refunded");
e.refunded = true;
e.buyer.transfer(e.amount);
emit RefundIssued(_escrowId, e.amount);
}
}