Skip to content

Commit d0778e8

Browse files
critesjoshclaude
andcommitted
Update streaming payments README for public registry architecture
- Document public stream registry design vs previous private notes approach - Update privacy model: stream metadata public, token balances private - Update function signatures (cancel_stream now takes stream_id, unvested_amount) - Add design rationale explaining why public registry was chosen - Update storage architecture documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 820eabb commit d0778e8

1 file changed

Lines changed: 33 additions & 22 deletions

File tree

streaming-payments/README.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
# Streaming Payments Contract
22

3-
A private streaming payments contract for Aztec that enables:
3+
A streaming payments contract for Aztec that enables:
44
- Salary streaming
55
- Token vesting
66
- Subscription payments
77

8-
All with full privacy - amounts, schedules, and participant identities remain hidden.
8+
Token balances remain private while stream metadata is stored publicly for both parties to access.
99

1010
## Features
1111

1212
- **Linear Vesting**: Tokens unlock linearly from start to end time
1313
- **Cliff Period**: Optional cliff before which no tokens can be withdrawn
14-
- **Private Streams**: Stream details stored in private notes
14+
- **Public Stream Registry**: Stream parameters stored publicly so both sender and recipient can interact
15+
- **Private Token Balances**: Actual token amounts remain in private balances
1516
- **Cancellation**: Sender can cancel and reclaim unvested tokens
1617
- **Partial Withdrawals**: Recipient can withdraw any unlocked amount
1718
- **Full Token Integration**: Uses the defi-wonderland/aztec-standards Token contract
@@ -22,24 +23,24 @@ All with full privacy - amounts, schedules, and participant identities remain hi
2223

2324
```
2425
Storage:
25-
├── token: PublicImmutable<AztecAddress> # Token contract address
26-
└── streams: Map<Field, Map<AztecAddress, Owned<PrivateMutable<StreamNote>>>>
26+
├── token: PublicImmutable<AztecAddress> # Token contract address
27+
└── streams: Map<Field, PublicMutable<StreamData>> # Public stream registry
2728
```
2829

29-
### StreamNote
30+
### StreamData
3031

31-
Each stream is represented as a private note containing:
32+
Each stream is stored publicly with the following fields:
3233

3334
| Field | Type | Description |
3435
|-------|------|-------------|
35-
| stream_id | Field | Unique identifier |
36-
| sender | AztecAddress | Stream creator |
36+
| sender | AztecAddress | Stream creator (can cancel) |
37+
| recipient | AztecAddress | Token recipient |
3738
| total_amount | u128 | Total tokens to stream |
3839
| start_time | u64 | When streaming begins |
3940
| end_time | u64 | When fully vested |
4041
| cliff_time | u64 | No withdrawals before this |
4142
| claimed_amount | u128 | Already withdrawn |
42-
| owner | AztecAddress | Recipient (note owner) |
43+
| cancelled | bool | Whether stream was cancelled |
4344

4445
### Key Functions
4546

@@ -48,22 +49,30 @@ Each stream is represented as a private note containing:
4849
| `constructor(token)` | public | Initialize with token address |
4950
| `create_stream(...)` | private | Create a new stream (requires authwit) |
5051
| `withdraw(stream_id, amount)` | private | Withdraw unlocked tokens |
51-
| `cancel_stream(stream_id, recipient, unvested)` | private | Cancel and reclaim unvested |
52+
| `cancel_stream(stream_id, unvested_amount)` | private | Cancel and reclaim unvested |
5253
| `get_stream_info(...)` | utility | View stream details |
5354
| `get_withdrawable(...)` | utility | Calculate withdrawable amount |
5455
| `get_unvested(...)` | utility | Calculate unvested amount |
5556

56-
## Privacy Properties
57+
## Privacy Model
5758

5859
**Private** (hidden from observers):
59-
- Total stream amounts
60-
- Vesting schedules
61-
- Sender and recipient identities
62-
- Withdrawal amounts and timing
60+
- Token balances (sender's source, recipient's destination)
61+
- Individual withdrawal/cancellation amounts going to private balances
6362

6463
**Public** (visible on-chain):
65-
- Stream existence (via nullifiers)
66-
- Token contract address
64+
- Stream existence and parameters
65+
- Sender and recipient addresses
66+
- Vesting schedule (start, end, cliff times)
67+
- Total stream amount
68+
- Claimed amount and cancellation status
69+
70+
### Design Rationale
71+
72+
The public stream registry approach was chosen because:
73+
1. **Both parties need access**: The sender needs to cancel, the recipient needs to withdraw
74+
2. **Note ownership limitation**: In Aztec, only the note owner can nullify their notes
75+
3. **Practical privacy**: For most use cases (payroll, vesting), stream existence isn't secret - what matters is keeping actual balances private
6776

6877
## Usage
6978

@@ -148,7 +157,9 @@ npm test
148157

149158
7. **Cancel** (optional): Sender cancels and reclaims unvested tokens
150159
```
151-
cancel_stream(stream_id, recipient, unvested_amount)
160+
// First query unvested amount
161+
let unvested = get_unvested(stream_id, current_time)
162+
cancel_stream(stream_id, unvested)
152163
```
153164

154165
## Linear Vesting Formula
@@ -200,8 +211,8 @@ streaming-payments/
200211
│ ├── Nargo.toml # Contract dependencies
201212
│ └── src/
202213
│ ├── main.nr # Main contract
203-
│ ├── stream_note.nr # StreamNote type
204-
│ └── lib.nr # Pure functions + tests
214+
│ ├── lib.nr # StreamData type + pure functions + tests
215+
│ └── stream_note.nr # Legacy StreamNote type (unused)
205216
├── scripts/
206217
│ └── setup-token.sh # Setup script
207218
├── tests/
@@ -221,4 +232,4 @@ streaming-payments/
221232

222233
- **Token Contract**: For actual token transfers
223234
- **Crowdfunding**: Similar time-based private payments
224-
- **Private Voting**: Uses similar note replacement patterns
235+
- **Private Voting**: Uses similar public/private hybrid patterns

0 commit comments

Comments
 (0)