Skip to content
This repository was archived by the owner on May 19, 2026. It is now read-only.

Commit ffc80af

Browse files
committed
spec: address review feedback
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
1 parent 2fbf148 commit ffc80af

4 files changed

Lines changed: 30 additions & 44 deletions

File tree

specs/schemes/deferred/scheme_deferred_evm.md

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
## Summary
44

55
The `deferred` scheme on EVM chains uses `EIP-712` signed vouchers to represent payment commitments from a buyer to a seller. Before issuing vouchers, the buyer deposits funds—denominated in a specific `ERC-20` token—into an on-chain escrow earmarked for the seller. Each voucher authorizes a payment against that escrow balance, and explicitly specifies the asset being used.
6-
Sellers can collect and aggregate these signed messages over time, choosing when to redeem them on-chain and settling the total amount in a single transaction.
6+
Sellers can collect and aggregate these signed messages over time, choosing when to redeem them on-chain and settling the total amount in a single transaction. The funds in the escrow contract are subject to a thawing period when withdrawing, this gives sellers guarantee they will be able to redeem in time.
7+
Interactions with the escrow contract for the buyer (depositing, thawing and withdrawing funds) are all performed via signed authorizations to remove the need for gas and blockchain access. These authorizations are executed and translated into on-chain actions by the facilitator.
78
This design enables efficient, asset-flexible micropayments without incurring prohibitive gas costs for every interaction.
89

910
## `X-Payment` header payload
@@ -25,7 +26,6 @@ The `payload` field of the `X-PAYMENT` header must contain the following fields:
2526
- `nonce`: Incremented with each aggregation (uint256)
2627
- `escrow`: Address of the escrow contract (address)
2728
- `chainId`: Network chain ID (uint256)
28-
- `expiry`: Expiration timestamp after which voucher cannot be collected (uint64)
2929

3030
Example:
3131

@@ -41,8 +41,7 @@ Example:
4141
"timestamp": 1740673000,
4242
"nonce": 3,
4343
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
44-
"chainId": 84532,
45-
"expiry": 1740759400
44+
"chainId": 84532
4645
}
4746
}
4847
```
@@ -65,16 +64,17 @@ Full `X-PAYMENT` header (without deposit authorization):
6564
"timestamp": 1740673000,
6665
"nonce": 3,
6766
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
68-
"chainId": 84532,
69-
"expiry": 1740759400
67+
"chainId": 84532
7068
}
7169
}
7270
}
7371
```
7472

7573
### Deposit Authorization Fields (optional)
7674

77-
The `depositAuthorization` object enables gasless escrow deposits by allowing the facilitator to execute deposits on behalf of the buyer. This is particularly useful for first-time buyers or when escrow balance needs to be topped up. The structure consists of two parts:
75+
The `depositAuthorization` object enables gasless escrow deposits by allowing the facilitator to execute deposits on behalf of the buyer. This is particularly useful for first-time buyers or when escrow balance needs to be topped up. Note that only assets implementing ERC-2612 permit extension are supported for gasless deposits.
76+
77+
The structure consists of two parts:
7878

7979
**Required:**
8080
- `depositAuthorization`: EIP-712 signed authorization for the escrow contract
@@ -87,7 +87,7 @@ The `depositAuthorization` object enables gasless escrow deposits by allowing th
8787
- `signature`: EIP-712 signature of the deposit authorization (bytes)
8888

8989
**Optional:**
90-
- `permit`: EIP-2612 permit for the ERC-20 token (if token supports permits)
90+
- `permit`: EIP-2612 permit for the ERC-20 token
9191
- `owner`: Token owner address (address)
9292
- `spender`: Escrow contract address (address)
9393
- `value`: Token amount to approve (uint256)
@@ -116,8 +116,7 @@ Example `X-PAYMENT` header with deposit authorization:
116116
"timestamp": 1740673000,
117117
"nonce": 3,
118118
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
119-
"chainId": 84532,
120-
"expiry": 1740759400
119+
"chainId": 84532
121120
},
122121
"depositAuthorization": {
123122
"permit": {
@@ -156,6 +155,8 @@ The `extra` object in the "Payment Required Response" should contain the followi
156155
- `balance`: Current escrow balance in atomic token units
157156
- `assetAllowance`: Current token allowance for the escrow contract
158157
- `assetPermitNonce`: Current permit nonce for the token contract
158+
- `assetDomainName`: EIP-712 domain name for the asset
159+
- `assetDomainVersion`: EIP-712 domain version for the asset
159160
- `facilitator`: Address of the facilitator managing the escrow
160161

161162
### For New Vouchers (`type: "new"`)
@@ -193,6 +194,8 @@ The `extra` object in the "Payment Required Response" should contain the followi
193194
"balance": "5000000",
194195
"assetAllowance": "5000000",
195196
"assetPermitNonce": "0",
197+
"assetDomainName": "USDC",
198+
"assetDomainVersion": "2",
196199
"facilitator": "https://facilitator.com"
197200
},
198201
"signature": "0x3a2f7e3b6c1d8e9c0f64f8724e5cfb8bfe9a3cdb1ad6e4a876f7d418e47e96b11a23346a1b0e60c8d3a4c4fd0150a244ab4b0e6d6c5fa4103f8fa8fd2870a3c81b",
@@ -205,8 +208,7 @@ The `extra` object in the "Payment Required Response" should contain the followi
205208
"timestamp": 1740673000,
206209
"nonce": 3,
207210
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
208-
"chainId": 84532,
209-
"expiry": 1740759400
211+
"chainId": 84532
210212
}
211213
}
212214
}
@@ -233,10 +235,7 @@ The following steps are required to verify a deferred payment:
233235
5. **Escrow balance check**:
234236
- Verify the `buyer` has enough of the `asset` (ERC20 token) in the escrow to cover the valueAggregate in the `payload.voucher`
235237
- Verify `id` has not been already collected in the escrow, or if it has, that the new balance is greater than what was already paid (in which case the difference will be paid)
236-
6. **Expiry validation**:
237-
- Verify the voucher has not expired by checking that the current timestamp is less than or equal to `expiry`
238-
- Verify `paymentPayload.voucher.expiry` and `paymentPayload.voucher.timestamp` dates make sense
239-
7. **Deposit authorization validation** (if present):
238+
6. **Deposit authorization validation** (if present):
240239
- Verify the `depositAuthorization.depositAuthorization.signature` is a valid EIP-712 signature
241240
- Verify `depositAuthorization.depositAuthorization.buyer` matches `paymentPayload.voucher.buyer`
242241
- Verify `depositAuthorization.depositAuthorization.seller` matches `paymentPayload.voucher.seller`
@@ -250,7 +249,7 @@ The following steps are required to verify a deferred payment:
250249
- Verify `permit.spender` matches the escrow contract address
251250
- Verify `permit.value` is sufficient to cover the deposit amount
252251
- Verify `permit.deadline` has not passed
253-
8. **Transaction simulation** (optional but recommended):
252+
7. **Transaction simulation** (optional but recommended):
254253
- Simulate the voucher collection to ensure the transaction would succeed on-chain
255254

256255
## Deposit Authorization Execution

specs/schemes/deferred/scheme_deferred_evm_escrow_contract.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The contract manages deposits, withdrawals, and voucher redemption:
1515
- **Vouchers**: Off-chain signed promises to pay that aggregate over time
1616
- **Collection**: Sellers redeem vouchers against escrow balances
1717
- **Withdrawal**: Buyers can withdraw unused funds after a thawing period
18-
- **Authorization**: EIP-712 signed operations for gasless interactions (designed for x402 Facilitators to be able to abstract escrow management actions from buyers)
18+
- **Authorizations**: EIP-712 signed operations for gasless interactions (designed for x402 Facilitators to be able to abstract escrow management actions from buyers)
1919

2020
## Data Structures
2121

@@ -42,7 +42,6 @@ struct Voucher {
4242
uint256 nonce; // Incremented with each aggregation
4343
address escrow; // This contract's address
4444
uint256 chainId; // Network chain ID
45-
uint64 expiry; // Expiration timestamp
4645
}
4746
```
4847

@@ -86,6 +85,10 @@ Escrow Contract → transfer(asset, amount) → Seller
8685
Buyer → thaw(seller, asset, amount) → Escrow Contract
8786
[wait THAWING_PERIOD]
8887
Buyer → withdraw(seller, asset) → Escrow Contract
88+
89+
OR
90+
91+
Buyer → flushWithAuthorization(auth) → Escrow Contract
8992
```
9093

9194
## Verification
@@ -95,9 +98,8 @@ To verify a payment in the `deferred` scheme:
9598
1. **Signature Validation**: Verify the voucher signature using EIP-712 and ERC-1271
9699
2. **Contract Verification**: Ensure `voucher.escrow` matches the expected contract address
97100
3. **Chain Verification**: Ensure `voucher.chainId` matches the current network
98-
4. **Expiry Check**: Verify `block.timestamp <= voucher.expiry`
99-
5. **Balance Check**: Verify escrow account has sufficient balance for collection
100-
6. **Aggregation Validation**: Ensure `voucher.valueAggregate >= previous_collections`
101+
4. **Balance Check**: Verify escrow account has sufficient balance for collection
102+
5. **Aggregation Validation**: Ensure `voucher.valueAggregate >= previous_collections`
101103

102104
## Settlement
103105

specs/schemes/deferred/scheme_deferred_evm_facilitator.md

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ GET /buyers/0x209693Bc6afc0C5328bA36FaF03C514EF312287C?seller=0xA1c7Bf3d421e8A54
4343
"timestamp": 1740673000,
4444
"nonce": 2,
4545
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
46-
"chainId": 84532,
47-
"expiry": 1740759400,
46+
"chainId": 84532
4847
"signature": "0x3a2f7e3b..."
4948
}
5049
}
@@ -94,8 +93,7 @@ If the payment payload contains a `depositAuthorization`, the facilitator must e
9493
"timestamp": 1740673100,
9594
"nonce": 3,
9695
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
97-
"chainId": 84532,
98-
"expiry": 1740759400
96+
"chainId": 84532
9997
}
10098
}
10199
},
@@ -118,8 +116,7 @@ If the payment payload contains a `depositAuthorization`, the facilitator must e
118116
"timestamp": 1740673000,
119117
"nonce": 2,
120118
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
121-
"chainId": 84532,
122-
"expiry": 1740759400
119+
"chainId": 84532
123120
}
124121
}
125122
}
@@ -144,8 +141,7 @@ If the payment payload contains a `depositAuthorization`, the facilitator must e
144141
"timestamp": 1740673000,
145142
"nonce": 1,
146143
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
147-
"chainId": 84532,
148-
"expiry": 1740759400
144+
"chainId": 84532
149145
},
150146
"depositAuthorization": {
151147
"permit": {
@@ -201,8 +197,7 @@ If the payment payload contains a `depositAuthorization`, the facilitator must e
201197
"timestamp": 1740673100,
202198
"nonce": 3,
203199
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
204-
"chainId": 84532,
205-
"expiry": 1740759400,
200+
"chainId": 84532
206201
"signature": "0x4b3f8e..."
207202
}
208203
```
@@ -329,14 +324,6 @@ Verifies a voucher's validity without settling it.
329324
}
330325
```
331326

332-
**Response (200 OK - Invalid):**
333-
```json
334-
{
335-
"valid": false,
336-
"reason": "Voucher expired"
337-
}
338-
```
339-
340327
### GET /vouchers/:id/:nonce/collections
341328

342329
Retrieves settlement history for a voucher.
@@ -384,8 +371,7 @@ Returns the most suitable voucher for aggregation between a buyer-seller pair.
384371
"timestamp": 1740673000,
385372
"nonce": 2,
386373
"escrow": "0x7cB1A5A2a2C9e91B76914C0A7b7Fb3AefF3BCA27",
387-
"chainId": 84532,
388-
"expiry": 1740759400
374+
"chainId": 84532
389375
},
390376
"signature": "0x3a2f7e3b..."
391377
}

specs/schemes/deferred/scheme_deferred_evm_voucher_store.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Summary
44

5-
The Voucher Store is a critical component of the X402 `deferred` payment scheme that manages the persistence and retrieval of signed payment vouchers and their settlement records. It serves as the data layer for sellers and facilitators to track off-chain payment obligations and their eventual on-chain settlements.
5+
The Voucher Store is a critical component of the x402 `deferred` payment scheme that manages the persistence and retrieval of signed payment vouchers and their settlement records. It serves as the data layer for sellers and facilitators to track off-chain payment obligations and their eventual on-chain settlements.
66

77
This specification defines the interface and requirements for implementing a voucher store in the deferred EVM payment system, ensuring consistent behavior across different implementations (in-memory, database-backed, etc.).
88

@@ -31,7 +31,6 @@ A voucher contains the following fields:
3131
| `nonce` | uint256 | Incremented with each aggregation |
3232
| `escrow` | address | Address of the escrow contract |
3333
| `chainId` | uint256 | Network chain ID |
34-
| `expiry` | uint64 | Expiration timestamp |
3534
| `signature` | bytes | EIP-712 signature of the voucher |
3635

3736
### Collection Structure

0 commit comments

Comments
 (0)