> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fortytwo.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Contract Reference

> Complete API reference for x402Escrow: functions, events, errors, and storage types.

<Badge color="gray">x402Escrow</Badge>
<Badge color="green">API</Badge>

**Contract**: `x402Escrow`<br />
**Solidity**: `v0.8.22+`<br />
**License**: MIT<br />
**Inheritance**: Initializable, UUPSUpgradeable, Ownable2StepUpgradeable, AccessControlUpgradeable, ReentrancyGuard

## Constants

| Name               | Type      | Value                           | Description                                |
| ------------------ | --------- | ------------------------------- | ------------------------------------------ |
| `VERSION`          | `uint256` | `1`                             | Contract version for upgrade tracking.     |
| `FACILITATOR_ROLE` | `bytes32` | `keccak256("FACILITATOR_ROLE")` | Role identifier for facilitator addresses. |

## State Variables

| Name            | Type                         | Visibility | Description                                                  |
| --------------- | ---------------------------- | ---------- | ------------------------------------------------------------ |
| `usdc`          | `address`                    | `public`   | USDC token address, set once at initialization.              |
| `timeoutSecs`   | `uint256`                    | `public`   | Default timeout for new escrows (seconds). Range: 300–86400. |
| `activeEscrows` | `mapping(bytes32 => Escrow)` | `public`   | Active escrows indexed by escrow ID.                         |

## Types

### Escrow (Internal Storage)

Packed into a single 32-byte storage slot.

```solidity theme={null}
struct Escrow {
    address client;    // 20 bytes — depositor address
    uint40  refundAt;  // 5 bytes  — timestamp when refund becomes available
    uint56  amount;    // 7 bytes  — USDC locked (up to ~72B USDC)
}
```

### EscrowView (Returned by getEscrow)

Full-width types for off-chain consumption.

```solidity theme={null}
struct EscrowView {
    address client;
    uint256 amount;
    uint256 refundAt;
    bool    canRefund;
    uint256 timeUntilRefund;
}
```

## Functions

### initialize

```solidity theme={null}
function initialize(
    address _usdc,
    address _facilitator,
    address _admin,
    address _owner
) external initializer
```

Initializes the proxy. Can only be called once.

**Parameters**

| Name           | Type      | Description                                       |
| -------------- | --------- | ------------------------------------------------- |
| `_usdc`        | `address` | USDC token address. Must be a contract.           |
| `_facilitator` | `address` | Initial facilitator. Receives `FACILITATOR_ROLE`. |
| `_admin`       | `address` | Initial admin. Receives `DEFAULT_ADMIN_ROLE`.     |
| `_owner`       | `address` | Contract owner. Authorizes UUPS upgrades.         |

**Reverts**

* `ZeroAddress()` — if any parameter is `address(0)`.
* `NotContract()` — if `_usdc` has no code.

### settle

```solidity theme={null}
function settle(
    address client,
    uint256 maxAmount,
    uint256 validAfter,
    uint256 validBefore,
    bytes32 nonce,
    uint8 v,
    bytes32 r,
    bytes32 s
) external onlyRole(FACILITATOR_ROLE) nonReentrant returns (bytes32 escrowId)
```

Locks USDC in escrow using the client's EIP-3009 signed authorization.

**Parameters**

| Name          | Type                          | Description                                           |
| ------------- | ----------------------------- | ----------------------------------------------------- |
| `client`      | `address`                     | Client wallet that signed the authorization.          |
| `maxAmount`   | `uint256`                     | Maximum USDC to lock (6 decimals). Must fit `uint56`. |
| `validAfter`  | `uint256`                     | Earliest timestamp the authorization can be used.     |
| `validBefore` | `uint256`                     | Latest timestamp the authorization can be used.       |
| `nonce`       | `bytes32`                     | Unique nonce for this authorization.                  |
| `v`, `r`, `s` | `uint8`, `bytes32`, `bytes32` | Client's ECDSA signature.                             |

**Returns**

| Name       | Type      | Description                                  |
| ---------- | --------- | -------------------------------------------- |
| `escrowId` | `bytes32` | `keccak256(abi.encodePacked(client, nonce))` |

**Reverts**

* `InvalidAmount()` — if `maxAmount` is zero or exceeds `type(uint56).max`.
* `NotYetValid()` — if `block.timestamp < validAfter`.
* `TimeoutExpired()` — if `block.timestamp >= validBefore`.
* `EscrowAlreadyExists()` — if an active escrow with this ID already exists.
* `TransferMismatch()` — if the actual USDC received differs from `maxAmount`.

**Emits**

* `Deposited(escrowId, client, maxAmount)`

### release

```solidity theme={null}
function release(
    bytes32 escrowId,
    uint256 facilitatorAmount
) external onlyRole(FACILITATOR_ROLE) nonReentrant
```

Settles an active escrow. Pays the facilitator and refunds the remainder to the client.

**Parameters**

| Name                | Type      | Description                                                       |
| ------------------- | --------- | ----------------------------------------------------------------- |
| `escrowId`          | `bytes32` | ID of the escrow to release.                                      |
| `facilitatorAmount` | `uint256` | USDC to pay the facilitator. Must be `≤ escrow amount`. Can be 0. |

**Behavior**

* Payment goes to `msg.sender` (the calling facilitator), not a stored address.
* If `facilitatorAmount == 0`, the full amount returns to the client.
* If `facilitatorAmount == escrow.amount`, nothing returns to the client.
* Escrow storage is cleared before transfers.

**Reverts**

* `EscrowNotFound()` — if the escrow does not exist or was already settled/refunded.
* `InvalidAmount()` — if `facilitatorAmount > escrow.amount`.

**Emits**

* `Released(escrowId, msg.sender, facilitatorAmount, clientRefund)`

### refundAfterTimeout

```solidity theme={null}
function refundAfterTimeout(bytes32 escrowId) external nonReentrant
```

Refunds the full escrowed amount to the client after the timeout has passed. **Permissionless** — callable by any address.

**Parameters**

| Name       | Type      | Description                 |
| ---------- | --------- | --------------------------- |
| `escrowId` | `bytes32` | ID of the escrow to refund. |

**Behavior**

* The full amount transfers to the stored `client` address regardless of who calls this function.
* Escrow storage is cleared before the transfer.

**Reverts**

* `EscrowNotFound()` — if the escrow does not exist.
* `TimeoutNotReached()` — if `block.timestamp < escrow.refundAt`.

**Emits**

* `Refunded(escrowId, client, amount)`

### setTimeout

```solidity theme={null}
function setTimeout(uint256 _timeoutSecs) external onlyRole(DEFAULT_ADMIN_ROLE)
```

Updates the default timeout for **new** escrows. Does not affect existing escrows.

**Parameters**

| Name           | Type      | Description                                                               |
| -------------- | --------- | ------------------------------------------------------------------------- |
| `_timeoutSecs` | `uint256` | New timeout in seconds. Must be between 300 (5 min) and 86400 (24 hours). |

**Reverts**

* `InvalidTimeout()` — if outside the valid range.

**Emits**

* `TimeoutUpdated(_timeoutSecs)`

### getEscrow

```solidity theme={null}
function getEscrow(bytes32 escrowId) external view returns (EscrowView memory)
```

Returns the current state of an escrow.

**Parameters**

| Name       | Type      | Description                |
| ---------- | --------- | -------------------------- |
| `escrowId` | `bytes32` | ID of the escrow to query. |

**Returns**: `EscrowView` with:

* `client` — depositor address (zero if the escrow doesn't exist).
* `amount` — USDC locked.
* `refundAt` — timestamp when refund becomes available.
* `canRefund` — `true` if `refundAfterTimeout()` can be called now.
* `timeUntilRefund` — seconds remaining until refund is available (0 if eligible).

## Events

### Deposited

```solidity theme={null}
event Deposited(bytes32 indexed escrowId, address indexed client, uint256 amount);
```

Emitted when USDC is locked via `settle()`.

### Released

```solidity theme={null}
event Released(
    bytes32 indexed escrowId,
    address indexed facilitator,
    uint256 toFacilitator,
    uint256 toClient
);
```

Emitted when an escrow is settled via `release()`.

### Refunded

```solidity theme={null}
event Refunded(bytes32 indexed escrowId, address indexed client, uint256 amount);
```

Emitted when an escrow is refunded via `refundAfterTimeout()`.

### TimeoutUpdated

```solidity theme={null}
event TimeoutUpdated(uint256 newTimeoutSecs);
```

Emitted when the admin changes the default timeout via `setTimeout()`.

## Errors

| Error                   | Thrown by                       | Condition                                                        |
| ----------------------- | ------------------------------- | ---------------------------------------------------------------- |
| `ZeroAddress()`         | `initialize`                    | Any parameter is `address(0)`.                                   |
| `NotContract()`         | `initialize`                    | `_usdc` has no deployed code.                                    |
| `EscrowNotFound()`      | `release`, `refundAfterTimeout` | Escrow does not exist or has already been settled.               |
| `EscrowAlreadyExists()` | `settle`                        | Escrow ID is already active.                                     |
| `TimeoutNotReached()`   | `refundAfterTimeout`            | Current time is before `refundAt`.                               |
| `TimeoutExpired()`      | `settle`                        | EIP-3009 authorization has expired.                              |
| `NotYetValid()`         | `settle`                        | EIP-3009 authorization is not yet valid.                         |
| `InvalidAmount()`       | `settle`, `release`             | Amount is zero, exceeds `uint56`, or exceeds the escrow balance. |
| `InvalidTimeout()`      | `setTimeout`                    | Timeout is outside the \[300, 86400] range.                      |
| `TransferMismatch()`    | `settle`                        | Actual USDC received differs from expected.                      |
