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.
x402Escrow
API
Contract: x402Escrow
Solidity: v0.8.22+
License: MIT
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.
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.
struct EscrowView {
address client;
uint256 amount;
uint256 refundAt;
bool canRefund;
uint256 timeUntilRefund;
}
Functions
initialize
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
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
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
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
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
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
event Deposited(bytes32 indexed escrowId, address indexed client, uint256 amount);
Emitted when USDC is locked via settle().
Released
event Released(
bytes32 indexed escrowId,
address indexed facilitator,
uint256 toFacilitator,
uint256 toClient
);
Emitted when an escrow is settled via release().
Refunded
event Refunded(bytes32 indexed escrowId, address indexed client, uint256 amount);
Emitted when an escrow is refunded via refundAfterTimeout().
TimeoutUpdated
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. |