EIP.tools

EIP.tools

⚠️ DraftStandards Track: ERC

ERC-7753: Proof-Based Escrow V2

A time-bounded, proof-verified escrow protocol with arbitration support and a 1% configurable protocol fee.

Authors
Created2026-03-28
Discussion Linkhttps://ethereum-magicians.org/t/erc-7753-proof-based-escrow-v2/23532
Requires

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/e5...
Pull Request#1627PR closed (unmerged)

EIP-GPT summary

Contents
AbstractMotivationSpecificationConstantsEnumsStructsMethodscreateEscrowreleaseEscrowrefundEscrowdisputeEscrowresolveDisputeEventsERC-165RationaleBackwards CompatibilityReference ImplementationSecurity ConsiderationsCopyright

Abstract

ERC-7753 extends classical on-chain escrow with proof-of-delivery semantics, time-to-live expiry, and a single-arbitrator dispute system. On createEscrow(), 1 % of the gross amount is immediately collected as a protocol fee; the remaining 99 % is locked until the creator submits a proofHash (delivery confirmation), the counterparty triggers a refund, or an appointed arbitrator resolves a dispute.

Motivation

Existing escrow standards:

  1. Lack a standardised proof structure.
  2. Do not define a TTL-based refund path.
  3. Omit protocol-level fee collection, leaving each implementation to invent its own.

ERC-7753 addresses all three while remaining gas-efficient (custom errors, single storage slot per escrow state transition).

Specification

Constants

NameValueDescription
ESCROW_FEE_BPS100Protocol fee in basis points (1 %)

Note: The address that receives the protocol fee (feeRecipient) is implementation-defined. Implementations MUST make feeRecipient configurable and MUST NOT hardcode a chain-specific address.

Enums

enum EscrowStatus { Locked, Released, Refunded, Disputed, Resolved }

Structs

struct Escrow {
    address  creator;
    address  counterparty;
    address  token;           // address(0) = native ETH
    uint256  grossAmount;
    uint256  feeAmount;       // 1% → treasury
    uint256  netAmount;       // 99% → locked
    bytes32  conditionHash;   // keccak256(description)
    bytes32  proofHash;       // set on release
    EscrowStatus status;
    uint64   createdAt;
    uint64   settledAt;
    uint64   expiresAt;
    string   description;
}

Methods

createEscrow

function createEscrow(
    address counterparty,
    string calldata description,
    address token,
    uint256 gross,
    uint64 ttlSeconds
) external payable returns (bytes32 escrowId);

MUST compute feeAmount = (gross * ESCROW_FEE_BPS) / 10_000 and forward to the implementation-defined fee recipient.
MUST set conditionHash = keccak256(bytes(description)).
MUST emit EscrowCreated(escrowId, creator, counterparty, feeAmount).

releaseEscrow

function releaseEscrow(bytes32 escrowId, bytes32 proofHash) external;

MUST only be callable by escrow.creator.
MUST set status = Released and release netAmount to counterparty.
MUST emit EscrowReleased(escrowId, counterparty, proofHash).

refundEscrow

function refundEscrow(bytes32 escrowId) external;

Callable by counterparty at any time, or by creator after expiresAt.
MUST refund netAmount to creator.
MUST emit EscrowRefunded(escrowId, creator).

disputeEscrow

function disputeEscrow(bytes32 escrowId) external;

Callable by either party while status is Locked.
MUST set status = Disputed.
MUST emit EscrowDisputed(escrowId, initiator).

resolveDispute

function resolveDispute(bytes32 escrowId, bool releaseToCounterparty) external;

MUST only be callable by the designated arbitrator.
MUST emit EscrowResolved(escrowId, recipient, releaseToCounterparty).

Events

event EscrowCreated  (bytes32 indexed escrowId, address indexed creator, address indexed counterparty, uint256 feeAmount);
event EscrowReleased (bytes32 indexed escrowId, address indexed to, bytes32 proofHash);
event EscrowRefunded (bytes32 indexed escrowId, address indexed to);
event EscrowDisputed (bytes32 indexed escrowId, address indexed initiator);
event EscrowResolved (bytes32 indexed escrowId, address indexed recipient, bool releasedToCounterparty);

ERC-165

Compliant contracts MUST implement IERC7753 and MUST return true from supportsInterface for type(IERC7753).interfaceId.

Rationale

  • conditionHash – Binding the escrow to keccak256(description) creates a lightweight commitment without storing arbitrary text on-chain.
  • Asymmetric refund – The counterparty can always trigger a refund (protecting buyers from rug-pull), while the creator can only refund after expiry (protecting sellers from premature cancellation).
  • Single arbitrator – Decentralised arbitration is complex to standardise; a pluggable single-arbitrator model is pragmatic for V2 while leaving room for DAO integration.

Backwards Compatibility

ERC-7753 is a new standard. It does not modify ERC-20 (IERC20) beyond using transfer/transferFrom.

Reference Implementation

See contracts/ERC7753EscrowV2.sol in the Opacus-Standart repository.

Security Considerations

  • Reentrancy – All fund-releasing functions MUST use a reentrancy guard.
  • Arbitrator trust – The arbitrator is a privileged role. Implementations SHOULD use a time-lock or multi-sig.
  • Clock manipulation – TTL-based expiry relies on block.timestamp; attackers cannot manipulate it by more than ~15 seconds on Ethereum mainnet.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth