--- eip: 7753 title: Proof-Based Escrow V2 description: A time-bounded, proof-verified escrow protocol with arbitration support and a 1% configurable protocol fee. author: Opacus Protocol (@bl10buer) discussions-to: https://ethereum-magicians.org/t/erc-7753-proof-based-escrow-v2/23532 status: Draft type: Standards Track category: ERC created: 2026-03-28 requires: 165 --- ## Abstract [ERC-7753](./eip-7753.md) 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 | Name | Value | Description | |---|---|---| | `ESCROW_FEE_BPS` | `100` | Protocol 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 ```solidity enum EscrowStatus { Locked, Released, Refunded, Disputed, Resolved } ``` ### Structs ```solidity 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` ```solidity 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` ```solidity 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` ```solidity 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` ```solidity function disputeEscrow(bytes32 escrowId) external; ``` Callable by either party while status is `Locked`. MUST set `status = Disputed`. MUST emit `EscrowDisputed(escrowId, initiator)`. #### `resolveDispute` ```solidity function resolveDispute(bytes32 escrowId, bool releaseToCounterparty) external; ``` MUST only be callable by the designated arbitrator. MUST emit `EscrowResolved(escrowId, recipient, releaseToCounterparty)`. ### Events ```solidity 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](./eip-165.md) 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](./eip-20.md) (`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 Copyright and related rights waived via [CC0](../LICENSE.md).