Overview
The Escrow contract is the liquidity hub of the zkp2p protocol. It holds depositor funds, manages deposit configurations, and coordinates with the Orchestrator to lock/unlock liquidity as intents progress through their lifecycle.Each deposit can support multiple payment methods (Venmo, PayPal, Wise, etc.), each with its own verification requirements and supported currencies.
Key Responsibilities
- Deposit Management: Create and manage deposits with flexible intent ranges
- Liquidity Locking: Lock funds when intents are signaled, release when fulfilled or cancelled
- Payment Method Configuration: Support multiple payment services with independent verification data
- Intent Expiry: Track and reclaim liquidity from expired intents
- Dust Collection: Automatically close small deposits and sweep remainder to protocol
Core Data Structures
Deposit Struct
Every deposit created on the Escrow is represented by this struct (fromcontracts/interfaces/IEscrow.sol:24):
Delegate: An optional address that can manage deposit parameters (conversion rates, intent ranges, payment methods) on behalf of the depositor.
Intent Struct
Each intent locked against a deposit is tracked with this struct (fromcontracts/interfaces/IEscrow.sol:12):
Payment Method Data
Deposits can support multiple payment methods. Each has its own configuration (fromcontracts/interfaces/IEscrow.sol:44):
Deposit Lifecycle
Creating a Deposit
Depositors create liquidity pools by callingcreateDeposit() with comprehensive configuration (from contracts/Escrow.sol:139):
token: ERC20 token addressamount: Initial deposit amountintentAmountRange: Min/max amounts per intentpaymentMethods: Array of supported payment method hashespaymentMethodData: Verification data for each payment methodcurrencies: Supported currencies and min conversion rates for each methoddelegate: Optional management delegateintentGuardian: Optional address that can extend intent expiryretainOnEmpty: Whether to keep deposit config when balance reaches zero
Example: Multi-Currency Deposit
A depositor might configure:- Venmo: USD only, min rate 1.0
- Wise: USD, EUR, GBP with different conversion rates
- PayPal: USD, EUR
payeeDetails (the depositor’s account ID for that service).
Liquidity Management
Adding Funds
Anyone can add funds to an existing deposit (fromcontracts/Escrow.sol:187):
remainingDeposits, making them immediately available for new intents.
Removing Funds
Only the depositor can remove funds (fromcontracts/Escrow.sol:213):
Intent Amount Range
TheintentAmountRange (min/max) controls the size of intents accepted:
setIntentRange() (from contracts/Escrow.sol:352).
Intent Lifecycle on Escrow
Locking Funds
When an intent is signaled on the Orchestrator, it callslockFunds() (from contracts/Escrow.sol:557):
- Validates deposit state (
acceptingIntents == true) - Checks amount is within
intentAmountRange - Prunes expired intents if needed to free liquidity
- Moves amount from
remainingDepositstooutstandingIntentAmount - Stores the intent with expiry time (
block.timestamp + intentExpirationPeriod) - Emits
FundsLockedevent
Unlocking Funds (Cancel)
When an intent is cancelled, the Orchestrator callsunlockFunds() (from contracts/Escrow.sol:620):
remainingDeposits.
Unlocking & Transferring Funds (Fulfill)
When an intent is fulfilled, the Orchestrator callsunlockAndTransferFunds() (from contracts/Escrow.sol:651):
Partial Fulfillment: The
_transferAmount can be less than the original intent amount. The difference is returned to remainingDeposits.Intent Expiration
Intents have a configurable expiration period (default 5 days max perMAX_TOTAL_INTENT_EXPIRATION_PERIOD at line 42).
Automatic Expiry Pruning
Expired intents are automatically pruned when:lockFunds()needs more liquidityremoveFunds()is calledwithdrawDeposit()is called- Anyone calls
pruneExpiredIntents()(fromcontracts/Escrow.sol:533)
Extending Expiry
TheintentGuardian (if set) can extend intent expiry via extendIntentExpiry() (from contracts/Escrow.sol:702):
Delegate System
Depositors can assign a delegate to manage deposit parameters without transferring ownership. Delegate can:- Update conversion rates (
setCurrencyMinRate) - Update intent ranges (
setIntentRange) - Add/remove payment methods and currencies
- Toggle accepting intents state
- Set retention behavior
- Withdraw funds (only depositor)
- Change the delegate itself (only depositor)
Dust Collection
When a deposit’sremainingDeposits falls below dustThreshold (max 1 USDC, see line 41) and has no outstanding intents:
- Deposit is automatically closed
- Remaining balance is swept to
dustRecipient - All payment method and currency data is deleted
Set
retainOnEmpty = true to prevent auto-closure and keep the deposit configuration for future reuse.Payment Method & Currency Management
Adding Payment Methods
Depositors can add new payment methods after creation (fromcontracts/Escrow.sol:381):
Toggling Payment Methods
Payment methods can be deactivated without deletion (fromcontracts/Escrow.sol:404):
Managing Currencies
Each payment method can support multiple currencies with independent min conversion rates:addCurrencies(): Add new currencies to a payment method (line 430)setCurrencyMinRate(): Update min conversion rate (line 324)deactivateCurrency(): Set conversion rate to 0 (line 458)
State Variables
| Variable | Description | Location |
|---|---|---|
orchestrator | Orchestrator contract reference | Line 47 |
paymentVerifierRegistry | Payment verifier registry | Line 48 |
chainId | Immutable chain identifier | Line 49 |
depositCounter | Incrementing deposit ID counter | Line 78 |
dustRecipient | Receives dust from closed deposits | Line 80 |
dustThreshold | Threshold below which deposits are dust | Line 81 |
maxIntentsPerDeposit | Max concurrent intents (prevents DOS) | Line 82 |
intentExpirationPeriod | How long intents remain valid | Line 83 |
Access Control
Owner (Governance)
- Set orchestrator address
- Update payment verifier registry
- Configure dust parameters
- Set max intents per deposit
- Set intent expiration period
- Pause/unpause deposit operations
Depositor
- Create deposits
- Withdraw deposits
- Remove funds
- Set delegate
- Remove delegate
Depositor OR Delegate
- Update conversion rates
- Update intent ranges
- Add/remove payment methods
- Add/remove currencies
- Toggle accepting intents state
- Set retention behavior
Orchestrator Only
- Lock funds
- Unlock funds
- Unlock and transfer funds
Intent Guardian Only
- Extend intent expiry
Key Events
Security Features
Reentrancy Protection
All state-changing functions use
nonReentrant modifier from OpenZeppelinPausability
Owner can pause deposit creation/modification while leaving withdrawals active
Intent Limits
maxIntentsPerDeposit prevents gas DOS attacks on withdrawalExpiry Enforcement
Intents automatically expire after
intentExpirationPeriodRelated Contracts
- Orchestrator - Signals intents and coordinates fulfillment
- Payment Verification - Verifies off-chain payment proofs
- Registry System - Payment verifier and currency validation