Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ struct Allowance {
}
```

- Timestamps order operations across chains
- Most recent timestamp takes precedence in expiration updates
- Prevents cross-chain race conditions
- Critical for async allowance updates
- Timestamp precedence governs the `expiration` field only: the most recent signed timestamp wins, so an out-of-order expiration update cannot overwrite a newer one
- Amount changes are NOT ordered by timestamp. Each Increase adds its `amountDelta` unconditionally, and each Decrease subtracts unconditionally, regardless of timestamp order
- Replay protection comes from the per-salt (non-sequential) nonce, not from timestamps — a given signed operation can only be executed once
- Critical for keeping expiration consistent across chains during async allowance updates

### Account Locking

Expand Down
2 changes: 1 addition & 1 deletion docs/api/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -744,5 +744,5 @@ This approach:
- **Chain ID Validation**: Verify chain IDs to prevent cross-chain replay
- **Witness Data Verification**: Validate witness data before taking action
- **Account Locking**: Understand implications of locked state
- **Timestamp Ordering**: Be aware of timestamp-based operation ordering
- **Timestamp Ordering**: Timestamp precedence orders `expiration` updates only; amount deltas apply unconditionally and replay is prevented by per-salt nonces
- **Allowance Management**: Monitor allowance changes across chains
2 changes: 1 addition & 1 deletion docs/api/data-structures.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct Allowance {

- **amount**: The quantity of tokens approved for spending
- **expiration**: Unix timestamp when the allowance becomes invalid
- **timestamp**: Last update timestamp, used for ordering operations across chains
- **timestamp**: Timestamp of the last update; used for cross-chain precedence on the `expiration` field only (the most recent timestamp wins). It does not order amount changes — amount deltas apply unconditionally per operation.

### NoncesToInvalidate

Expand Down
6 changes: 3 additions & 3 deletions docs/api/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ event Permit(
**Use cases:**
- Track allowance changes
- Monitor spending permissions
- Track operation ordering by timestamp
- Track expiration-update precedence by timestamp

### Approval

Expand Down Expand Up @@ -176,7 +176,7 @@ When using Permit3 across multiple chains, the same events are emitted on each c

1. **Common salt/nonce**: The same salt is used across all chains for a single logical operation
2. **Unique chainId**: Each `ChainPermits` structure contains the specific chainId
3. **Consistent timestamp**: Operations use the same timestamp across chains for ordering
3. **Consistent timestamp**: Operations use the same timestamp across chains so that `expiration` updates resolve consistently (the most recent timestamp wins). This timestamp orders expiration updates only, not amount changes.

This allows applications to correlate related events across different blockchains by matching salt, owner, and timestamp values.

Expand All @@ -188,6 +188,6 @@ Permit3 events are designed to be easily indexed by subgraphs and monitoring ser
- Index events by `owner` to track all operations for a specific user
- Index by `token` to monitor activity for specific tokens
- Index by `salt` to identify cross-chain operations
- Use `timestamp` to determine operation ordering
- Use `timestamp` to determine the precedence of `expiration` updates (note: it does not order amount changes)

This enables comprehensive analytics and monitoring of cross-chain token permissions.
24 changes: 13 additions & 11 deletions docs/concepts/allowance-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,17 @@ The most common mode, using `modeOrExpiration` as the expiration timestamp.

## Timestamp Management

The timestamp field serves a critical role in the allowance system, especially for cross-chain operations.
The timestamp field serves a critical role in the allowance system, especially for cross-chain operations. Its precedence rule governs the `expiration` field only — it does **not** order amount changes.

### Purpose

1. **Operation Ordering**: Ensures operations are applied in the correct order, even when transactions are confirmed out of order
1. **Expiration Ordering**: Ensures the `expiration` value is applied in the correct order, so a stale (older-timestamp) expiration update cannot overwrite a newer one, even when transactions are confirmed out of order

2. **Cross-Chain Consistency**: Allows the same logical operation to be synchronized across multiple chains
2. **Cross-Chain Consistency**: Allows the same logical expiration update to be synchronized across multiple chains by signing it with the same timestamp

3. **Race Condition Prevention**: Prevents allowance race conditions in asynchronous environments
3. **Expiration Race Condition Prevention**: Prevents the stored `expiration` from being clobbered by an out-of-order update in asynchronous environments

> **Important:** Timestamp precedence applies to expiration only. Amount changes are applied unconditionally per operation — every Increase adds its `amountDelta` and every Decrease subtracts, regardless of timestamp order. Replay protection (executing the same signed operation twice) is provided by the per-salt, non-sequential nonce, not by timestamps. See [Nonce Management](nonce-management.md).

### Example Scenario

Expand All @@ -161,9 +163,10 @@ Even though the confirmations happen at different times, both operations use the

### Rules

- Allowance updates that change timestamps are only applied if the operation timestamp is > the stored timestamp
- This applies to increases only. Lock operations always execute regardless of timestamp, while unlock operations require a newer timestamp only when unlocking a locked state. Decreases preserve existing timestamps without checking them
- The `expiration` (and stored `timestamp`) is updated only if the operation timestamp is > the stored timestamp; an Increase carrying an older timestamp leaves the existing expiration untouched
- The `amountDelta` on an Increase is applied unconditionally and *before* the timestamp comparison, so the allowance amount grows even when the timestamp is older than the stored one
- For allowance increases, the highest expiration time is kept when the timestamps are equal
- Lock operations always execute regardless of timestamp, while unlock operations require a newer timestamp only when unlocking a locked state. Decreases subtract unconditionally and preserve the existing timestamp without checking it

## Account Locking

Expand Down Expand Up @@ -202,12 +205,11 @@ Permit3 provides time-bound permissions through expiration timestamps.
- Expiration only applies to allowances, not to locked states
- When increasing an allowance with multiple operations that have the same timestamp, the maximum expiration is used

### Operation Priority
### Expiration Update Priority

The priority of operations is:
1. Timestamp (higher is more recent)
2. Expiration (longer is preferred)
3. Amount (more restrictive takes precedence for decreases, more permissive for increases)
The precedence rules below decide which **expiration** value sticks; they do not order amount changes (amounts are always applied unconditionally):
1. Timestamp (higher is more recent) — a newer timestamp replaces the stored expiration
2. Expiration (longer is preferred) — when timestamps are equal, the larger expiration wins

## Integration with EIP-712 Signatures

Expand Down
8 changes: 4 additions & 4 deletions docs/concepts/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,10 @@ Permit3 implements several security features:
- Prevents cross-chain replay attacks
- Works with witness functionality

5. **Timestamp Ordering**:
- Operations ordered by timestamp across chains
- Prevents race conditions in cross-chain operations
- Critical for asynchronous allowance updates
5. **Timestamp-Ordered Expirations**:
- Timestamps order `expiration` updates across chains, not amount changes
- Prevents a stale expiration update from clobbering a newer one
- Amount deltas apply unconditionally; replay is prevented by per-salt nonces, not timestamps

<a id="gas-optimization"></a>
## Gas Optimization
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/cross-chain-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ Sophisticated nonce handling prevents replay attacks:

### 4. **Additional Security Best Practices**
- **Deadline Validation**: Set reasonable deadlines to limit the window of vulnerability
- **Timestamp Ordering**: Be aware of timestamp-based operation ordering across chains
- **Timestamp Ordering**: Be aware that timestamp precedence orders `expiration` updates across chains only — amount changes apply unconditionally and replay is prevented by per-salt nonces
- **Proof Verification**: Ensure proofs correctly link chain-specific permits to the root hash
- **Witness validation**: When using witness data, ensure proper validation on each chain
Comment on lines 362 to 366

Expand Down
Loading