> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/zkp2p/zkp2p-contracts/llms.txt
> Use this file to discover all available pages before exploring further.

# Escrow Contract

> Deposit management, liquidity locking, and intent lifecycle in the Escrow contract

## 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.

<Info>
  Each deposit can support multiple payment methods (Venmo, PayPal, Wise, etc.), each with its own verification requirements and supported currencies.
</Info>

## 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 (from `contracts/interfaces/IEscrow.sol:24`):

```solidity theme={null}
struct Deposit {
    address depositor;                  // Address of depositor
    address delegate;                   // Address that can manage this deposit (address(0) if no delegate)
    IERC20 token;                       // Address of deposit token
    Range intentAmountRange;            // Range of take amount per intent
    // Deposit state
    bool acceptingIntents;              // True if the deposit is accepting intents
    uint256 remainingDeposits;          // Amount of liquidity immediately available to lock
    uint256 outstandingIntentAmount;    // Amount of outstanding intents (may include expired intents)
    // Intent guardian
    address intentGuardian;             // Address that can extend intent expiry times
    // Retention behavior
    bool retainOnEmpty;                 // If true, do not auto-close/sweep when empty; keep config for reuse
}
```

<Note>
  **Delegate**: An optional address that can manage deposit parameters (conversion rates, intent ranges, payment methods) on behalf of the depositor.
</Note>

### Intent Struct

Each intent locked against a deposit is tracked with this struct (from `contracts/interfaces/IEscrow.sol:12`):

```solidity theme={null}
struct Intent {
    bytes32 intentHash;     // Unique identifier for the intent
    uint256 amount;         // Amount locked
    uint256 timestamp;      // When this intent was created
    uint256 expiryTime;     // When this intent expires
}
```

### Payment Method Data

Deposits can support multiple payment methods. Each has its own configuration (from `contracts/interfaces/IEscrow.sol:44`):

```solidity theme={null}
struct DepositPaymentMethodData {
    address intentGatingService;    // Public key of gating service that will verify intents
    bytes32 payeeDetails;          // Payee details, hash of payee details
    bytes data;                    // Verification Data: Additional data used for payment verification
}
```

<Tip>
  The `payeeDetails` field stores a **hash** of the depositor's payment account ID (e.g., Venmo username hash) to preserve privacy on-chain.
</Tip>

## Deposit Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Created: createDeposit()
    Created --> Accepting: acceptingIntents=true
    Accepting --> Locked: lockFunds() (orchestrator)
    Locked --> Accepting: unlockFunds() (cancelled intent)
    Locked --> Fulfilled: unlockAndTransferFunds() (fulfilled intent)
    Accepting --> Paused: setAcceptingIntents(false)
    Paused --> Accepting: setAcceptingIntents(true)
    Accepting --> Withdrawn: withdrawDeposit()
    Withdrawn --> Closed: No outstanding intents
    Withdrawn --> Retained: retainOnEmpty=true
    Closed --> [*]
```

## Creating a Deposit

Depositors create liquidity pools by calling `createDeposit()` with comprehensive configuration (from `contracts/Escrow.sol:139`):

```solidity theme={null}
function createDeposit(CreateDepositParams calldata _params) external whenNotPaused
```

**CreateDepositParams** includes:

* `token`: ERC20 token address
* `amount`: Initial deposit amount
* `intentAmountRange`: Min/max amounts per intent
* `paymentMethods`: Array of supported payment method hashes
* `paymentMethodData`: Verification data for each payment method
* `currencies`: Supported currencies and min conversion rates for each method
* `delegate`: Optional management delegate
* `intentGuardian`: Optional address that can extend intent expiry
* `retainOnEmpty`: 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

Each payment method has independent `payeeDetails` (the depositor's account ID for that service).

## Liquidity Management

### Adding Funds

Anyone can add funds to an existing deposit (from `contracts/Escrow.sol:187`):

```solidity theme={null}
function addFunds(uint256 _depositId, uint256 _amount) external whenNotPaused
```

Funds are added to `remainingDeposits`, making them immediately available for new intents.

### Removing Funds

Only the depositor can remove funds (from `contracts/Escrow.sol:213`):

```solidity theme={null}
function removeFunds(uint256 _depositId, uint256 _amount) external nonReentrant whenNotPaused
```

<Warning>
  If `remainingDeposits` is insufficient, the function automatically prunes expired intents to reclaim liquidity before attempting removal.
</Warning>

### Intent Amount Range

The `intentAmountRange` (min/max) controls the size of intents accepted:

```solidity theme={null}
struct Range {
    uint256 min;    // Minimum value
    uint256 max;    // Maximum value
}
```

Depositors can update this range via `setIntentRange()` (from `contracts/Escrow.sol:352`).

## Intent Lifecycle on Escrow

### Locking Funds

When an intent is signaled on the Orchestrator, it calls `lockFunds()` (from `contracts/Escrow.sol:557`):

```solidity theme={null}
function lockFunds(
    uint256 _depositId, 
    bytes32 _intentHash,
    uint256 _amount
) external nonReentrant onlyOrchestrator
```

**The function**:

1. Validates deposit state (`acceptingIntents == true`)
2. Checks amount is within `intentAmountRange`
3. Prunes expired intents if needed to free liquidity
4. Moves amount from `remainingDeposits` to `outstandingIntentAmount`
5. Stores the intent with expiry time (`block.timestamp + intentExpirationPeriod`)
6. Emits `FundsLocked` event

### Unlocking Funds (Cancel)

When an intent is cancelled, the Orchestrator calls `unlockFunds()` (from `contracts/Escrow.sol:620`):

```solidity theme={null}
function unlockFunds(uint256 _depositId, bytes32 _intentHash) 
    external 
    nonReentrant
    onlyOrchestrator
```

This returns the locked amount to `remainingDeposits`.

### Unlocking & Transferring Funds (Fulfill)

When an intent is fulfilled, the Orchestrator calls `unlockAndTransferFunds()` (from `contracts/Escrow.sol:651`):

```solidity theme={null}
function unlockAndTransferFunds(
    uint256 _depositId, 
    bytes32 _intentHash,
    uint256 _transferAmount,   // May be less than intent amount (partial fulfillment)
    address _to                 // Orchestrator address
) external nonReentrant onlyOrchestrator
```

<Info>
  **Partial Fulfillment**: The `_transferAmount` can be less than the original intent amount. The difference is returned to `remainingDeposits`.
</Info>

## Intent Expiration

Intents have a configurable expiration period (default 5 days max per `MAX_TOTAL_INTENT_EXPIRATION_PERIOD` at line 42).

### Automatic Expiry Pruning

Expired intents are automatically pruned when:

* `lockFunds()` needs more liquidity
* `removeFunds()` is called
* `withdrawDeposit()` is called
* Anyone calls `pruneExpiredIntents()` (from `contracts/Escrow.sol:533`)

### Extending Expiry

The `intentGuardian` (if set) can extend intent expiry via `extendIntentExpiry()` (from `contracts/Escrow.sol:702`):

```solidity theme={null}
function extendIntentExpiry(
    uint256 _depositId, 
    bytes32 _intentHash,
    uint256 _additionalTime
) external
```

This is useful when off-chain payment is delayed but legitimate.

## 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

**Delegate cannot**:

* Withdraw funds (only depositor)
* Change the delegate itself (only depositor)

```solidity theme={null}
// Set delegate (contracts/Escrow.sol:286)
function setDelegate(uint256 _depositId, address _delegate) external whenNotPaused

// Remove delegate (contracts/Escrow.sol:301)
function removeDelegate(uint256 _depositId) external whenNotPaused
```

## Dust Collection

When a deposit's `remainingDeposits` 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

<Note>
  Set `retainOnEmpty = true` to prevent auto-closure and keep the deposit configuration for future reuse.
</Note>

## Payment Method & Currency Management

### Adding Payment Methods

Depositors can add new payment methods after creation (from `contracts/Escrow.sol:381`):

```solidity theme={null}
function addPaymentMethods(
    uint256 _depositId,
    bytes32[] calldata _paymentMethods,
    DepositPaymentMethodData[] calldata _paymentMethodData,
    Currency[][] calldata _currencies
) external whenNotPaused onlyDepositorOrDelegate(_depositId)
```

### Toggling Payment Methods

Payment methods can be deactivated without deletion (from `contracts/Escrow.sol:404`):

```solidity theme={null}
function setPaymentMethodActive(
    uint256 _depositId,
    bytes32 _paymentMethod,
    bool _isActive
) external whenNotPaused onlyDepositorOrDelegate(_depositId)
```

### Managing Currencies

Each payment method can support multiple currencies with independent min conversion rates:

```solidity theme={null}
struct Currency {
    bytes32 code;                  // Currency code (keccak256 hash)
    uint256 minConversionRate;     // Minimum rate in preciseUnits (1e18)
}
```

Functions:

* `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

```solidity theme={null}
event DepositReceived(uint256 indexed depositId, address indexed depositor, ...)
event FundsLocked(uint256 indexed depositId, bytes32 indexed intentHash, uint256 amount, uint256 expiryTime)
event FundsUnlocked(uint256 indexed depositId, bytes32 indexed intentHash, uint256 amount)
event FundsUnlockedAndTransferred(uint256 indexed depositId, bytes32 indexed intentHash, ...)
event DepositClosed(uint256 depositId, address depositor)
event DustCollected(uint256 indexed depositId, uint256 dustAmount, address indexed dustRecipient)
```

## Security Features

<CardGroup cols={2}>
  <Card title="Reentrancy Protection" icon="shield">
    All state-changing functions use `nonReentrant` modifier from OpenZeppelin
  </Card>

  <Card title="Pausability" icon="pause">
    Owner can pause deposit creation/modification while leaving withdrawals active
  </Card>

  <Card title="Intent Limits" icon="gauge">
    `maxIntentsPerDeposit` prevents gas DOS attacks on withdrawal
  </Card>

  <Card title="Expiry Enforcement" icon="clock">
    Intents automatically expire after `intentExpirationPeriod`
  </Card>
</CardGroup>

## Related Contracts

* [Orchestrator](/concepts/orchestrator) - Signals intents and coordinates fulfillment
* [Payment Verification](/concepts/payment-verification) - Verifies off-chain payment proofs
* [Registry System](/concepts/registry-system) - Payment verifier and currency validation
