@towns-labs/wallet 7.2.0 → 7.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +266 -305
- package/dist/cli.js +447 -306
- package/dist/session-daemon.js +16 -0
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,74 +1,64 @@
|
|
|
1
|
-
#
|
|
1
|
+
# tw — Towns Wallet CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Your keys. Your account. No signup. No login. Just run it.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Run with bunx
|
|
5
|
+
`tw` is a local-first CLI for managing smart accounts, session keys, and on-chain permissions on Towns Protocol. It works for humans at the terminal and for agents over `--json` or `--mcp`.
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
bunx @towns-labs/wallet --help
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
---
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
## Quick Start
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
Create an account and send USDC in under a minute:
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
```bash
|
|
18
|
+
# 1. Create a local account (interactive password prompt)
|
|
19
|
+
tw account create --profile main
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- Default: human-readable text
|
|
21
|
+
# 2. Fund it
|
|
22
|
+
tw address --qr --amount 100
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
# 3. Send USDC
|
|
25
|
+
tw account send 10 vitalik.eth
|
|
26
|
+
```
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
# Show all commands
|
|
29
|
-
tw --help
|
|
28
|
+
No custody service. No API key. Everything runs locally with encrypted keystores.
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
tw account create --help
|
|
30
|
+
---
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
tw --llms
|
|
32
|
+
## How It Works
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
tw --mcp
|
|
34
|
+
`tw` manages a local keystore that holds your root key and session keys. Your root key creates and controls your on-chain smart account. Session keys are scoped signers — they can send transactions through the Towns relayer without exposing your root key.
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
tw
|
|
36
|
+
```text
|
|
37
|
+
~/.config/towns/tw/profiles/<env>/<profile>/default.keystore.json
|
|
38
|
+
~/.config/towns/tw/profiles/<env>/<profile>/sessions/<session-name>.json
|
|
42
39
|
```
|
|
43
40
|
|
|
44
|
-
|
|
41
|
+
For agents, the session daemon keeps decrypted keys in memory for a bounded duration so automated workflows can sign without prompting for a password on every call.
|
|
45
42
|
|
|
46
|
-
|
|
43
|
+
---
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
## Commands
|
|
46
|
+
|
|
47
|
+
### Account
|
|
51
48
|
|
|
52
|
-
Create a
|
|
49
|
+
#### `account create` — Create a new account
|
|
53
50
|
|
|
54
51
|
```bash
|
|
55
52
|
tw account create --profile agent
|
|
56
53
|
```
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```text
|
|
61
|
-
~/.config/towns/tw/profiles/<env>/<profile>/default.keystore.json
|
|
62
|
-
~/.config/towns/tw/profiles/<env>/<profile>/sessions/<session-name>.json
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Resume a previously created profile:
|
|
55
|
+
Resume a previously interrupted flow:
|
|
66
56
|
|
|
67
57
|
```bash
|
|
68
58
|
tw account create --resume --profile agent
|
|
69
59
|
```
|
|
70
60
|
|
|
71
|
-
Non-interactive
|
|
61
|
+
Non-interactive (stdin password + JSON):
|
|
72
62
|
|
|
73
63
|
```bash
|
|
74
64
|
echo "my-password" | tw account create --password-stdin --json
|
|
@@ -80,461 +70,446 @@ Use an explicit keystore path:
|
|
|
80
70
|
tw account create --keystore-path ~/.config/towns/tw/profiles/prod/team/default.keystore.json
|
|
81
71
|
```
|
|
82
72
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
Export metadata only (safe default):
|
|
73
|
+
#### `account status` — Check readiness
|
|
86
74
|
|
|
87
75
|
```bash
|
|
88
|
-
tw account
|
|
76
|
+
tw account status --profile agent --json
|
|
89
77
|
```
|
|
90
78
|
|
|
91
|
-
|
|
79
|
+
#### `account balance` — Check USDC balance
|
|
92
80
|
|
|
93
81
|
```bash
|
|
94
|
-
tw account
|
|
82
|
+
tw account balance --profile agent
|
|
83
|
+
tw account balance --profile agent --chain polygon
|
|
95
84
|
```
|
|
96
85
|
|
|
97
|
-
|
|
86
|
+
#### `account address` — Print root address
|
|
98
87
|
|
|
99
88
|
```bash
|
|
100
|
-
tw account
|
|
89
|
+
tw account address --profile agent
|
|
101
90
|
```
|
|
102
91
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
Print the main/root account address:
|
|
92
|
+
#### `account send` — Send USDC
|
|
106
93
|
|
|
107
94
|
```bash
|
|
108
|
-
tw account
|
|
95
|
+
tw account send 1 0x1111111111111111111111111111111111111111
|
|
96
|
+
tw account send 2.5 vitalik.eth --chain base
|
|
97
|
+
tw account send 10 treasury --chain polygon --json
|
|
109
98
|
```
|
|
110
99
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
`tw address` is a root alias for `tw account address` with optional funding display helpers.
|
|
114
|
-
|
|
115
|
-
Print address + default funding context (USDC on Base):
|
|
100
|
+
Use a specific local session (without changing active session):
|
|
116
101
|
|
|
117
102
|
```bash
|
|
118
|
-
tw
|
|
103
|
+
tw account send 1 0x... --profile agent --session worker-2
|
|
119
104
|
```
|
|
120
105
|
|
|
121
|
-
|
|
106
|
+
Use a portable session file (no root keystore required):
|
|
122
107
|
|
|
123
108
|
```bash
|
|
124
|
-
tw
|
|
109
|
+
tw account send 1 0x... --chain base --session-file ./worker-1.session.json
|
|
125
110
|
```
|
|
126
111
|
|
|
127
|
-
|
|
112
|
+
`--session` and `--session-file` are mutually exclusive.
|
|
113
|
+
|
|
114
|
+
#### `account swap` — Swap tokens on the same chain
|
|
115
|
+
|
|
116
|
+
Powered by [relay.link](https://relay.link). Interactive confirmation by default.
|
|
128
117
|
|
|
129
118
|
```bash
|
|
130
|
-
tw
|
|
119
|
+
tw account swap --from ETH --to USDC --amount 0.1 --chain base
|
|
120
|
+
tw account swap --from USDC --to ETH --amount 50 --chain base --yes --json
|
|
131
121
|
```
|
|
132
122
|
|
|
133
|
-
|
|
123
|
+
#### `account bridge` — Bridge tokens cross-chain
|
|
134
124
|
|
|
135
125
|
```bash
|
|
136
|
-
tw
|
|
126
|
+
tw account bridge --token USDC --amount 100 --to-chain polygon
|
|
127
|
+
tw account bridge --token ETH --amount 0.5 --to-chain base --recipient 0x... --yes --json
|
|
137
128
|
```
|
|
138
129
|
|
|
139
|
-
|
|
130
|
+
#### `account delegate` — Delegate on additional chains
|
|
140
131
|
|
|
141
|
-
|
|
132
|
+
If your account was created on Base and you need it on Polygon:
|
|
142
133
|
|
|
143
134
|
```bash
|
|
144
|
-
tw account
|
|
135
|
+
echo "my-password" | tw account delegate --chain polygon --profile agent --password-stdin
|
|
145
136
|
```
|
|
146
137
|
|
|
147
|
-
|
|
138
|
+
#### `account history` — Relayer call history
|
|
148
139
|
|
|
149
140
|
```bash
|
|
150
|
-
tw account
|
|
141
|
+
tw account history --profile agent
|
|
142
|
+
tw account history --address 0x... --limit 10 --offset 20
|
|
143
|
+
tw account history --chain base,polygon --json
|
|
151
144
|
```
|
|
152
145
|
|
|
153
|
-
|
|
146
|
+
`--limit` defaults to 20 (max 100). `offset + limit` must be <= 1000.
|
|
154
147
|
|
|
155
|
-
|
|
148
|
+
#### `account export` — Export metadata or private keys
|
|
156
149
|
|
|
157
150
|
```bash
|
|
158
|
-
tw account
|
|
151
|
+
tw account export --profile agent --json
|
|
152
|
+
tw account export --profile agent --show-private
|
|
159
153
|
```
|
|
160
154
|
|
|
161
|
-
|
|
155
|
+
#### `account nonce` — Read account nonce
|
|
162
156
|
|
|
163
157
|
```bash
|
|
164
|
-
tw account
|
|
158
|
+
tw account nonce --profile agent
|
|
165
159
|
```
|
|
166
160
|
|
|
167
|
-
|
|
161
|
+
#### `account update password` — Rotate keystore password
|
|
168
162
|
|
|
169
163
|
```bash
|
|
170
|
-
tw account
|
|
164
|
+
tw account update password --profile agent
|
|
165
|
+
printf "old\nnew\n" | tw account update password --current-password-stdin --new-password-stdin --json
|
|
171
166
|
```
|
|
172
167
|
|
|
173
|
-
|
|
168
|
+
---
|
|
174
169
|
|
|
175
|
-
|
|
176
|
-
tw account send 1 0x1111111111111111111111111111111111111111 --profile agent --session worker-2
|
|
177
|
-
```
|
|
170
|
+
### Address
|
|
178
171
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
Get paginated relayer call history for an EOA. By default this uses your local profile root EOA from keystore:
|
|
172
|
+
`tw address` is a top-level shortcut for showing your funding address with optional payment helpers.
|
|
182
173
|
|
|
183
174
|
```bash
|
|
184
|
-
tw
|
|
175
|
+
tw address
|
|
176
|
+
tw address --link --amount 100
|
|
177
|
+
tw address --qr --amount 100
|
|
185
178
|
```
|
|
186
179
|
|
|
187
|
-
|
|
180
|
+
Custom token:
|
|
188
181
|
|
|
189
182
|
```bash
|
|
190
|
-
tw
|
|
183
|
+
tw address --token 0x... --amount 1 --decimals 18 --link
|
|
191
184
|
```
|
|
192
185
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
tw account history --chain base,polygon --json
|
|
197
|
-
```
|
|
186
|
+
---
|
|
198
187
|
|
|
199
|
-
|
|
188
|
+
### Session Keys
|
|
200
189
|
|
|
201
|
-
|
|
202
|
-
- `--offset` defaults to `0`
|
|
203
|
-
- `offset + limit` must be `<= 1000`
|
|
204
|
-
- History queries are EOA-based (root EOA), not delegated account address
|
|
190
|
+
Session keys are scoped signers that can act on behalf of your account without exposing the root key.
|
|
205
191
|
|
|
206
|
-
|
|
192
|
+
#### `session create` — Create and authorize a session key
|
|
207
193
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
```text
|
|
211
|
-
~/.config/towns/tw/contacts.json
|
|
194
|
+
```bash
|
|
195
|
+
echo "my-password" | tw session create worker-1 --profile agent --password-stdin --json
|
|
212
196
|
```
|
|
213
197
|
|
|
214
|
-
|
|
198
|
+
Create and activate immediately:
|
|
215
199
|
|
|
216
200
|
```bash
|
|
217
|
-
tw
|
|
218
|
-
tw contacts add treasury 0x1111111111111111111111111111111111111111
|
|
201
|
+
echo "my-password" | tw session create worker-2 --profile agent --activate --password-stdin
|
|
219
202
|
```
|
|
220
203
|
|
|
221
|
-
|
|
204
|
+
Grant full wildcard access:
|
|
222
205
|
|
|
223
206
|
```bash
|
|
224
|
-
tw
|
|
225
|
-
tw contacts show vitalik --json
|
|
207
|
+
echo "my-password" | tw session create worker-admin --profile agent --full-access --password-stdin
|
|
226
208
|
```
|
|
227
209
|
|
|
228
|
-
|
|
210
|
+
`--full-access` is mutually exclusive with `--target`, `--selector`, `--spend-limit`, `--spend-limit-raw`, and `--spend-period`. Omitting both `--target` and `--selector` uses wildcard call permissions by default.
|
|
211
|
+
|
|
212
|
+
Resume an interrupted flow:
|
|
229
213
|
|
|
230
214
|
```bash
|
|
231
|
-
tw
|
|
232
|
-
tw contacts rename vitalik vitalik-main
|
|
233
|
-
tw contacts remove vitalik-main
|
|
215
|
+
echo "my-password" | tw session create worker-1 --profile agent --resume --password-stdin --json
|
|
234
216
|
```
|
|
235
217
|
|
|
236
|
-
|
|
218
|
+
Create a session and initialize agent messaging in one step:
|
|
237
219
|
|
|
238
220
|
```bash
|
|
239
|
-
tw
|
|
240
|
-
tw contacts import ./contacts.json --json
|
|
241
|
-
tw contacts import ./contacts.json --force --json
|
|
221
|
+
echo "my-password" | tw session create alice --profile agent --agent --password-stdin
|
|
242
222
|
```
|
|
243
223
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
- `importedCount`
|
|
247
|
-
- `skippedInvalidCount`
|
|
248
|
-
- `skippedConflictCount`
|
|
249
|
-
- `overwrittenCount`
|
|
250
|
-
|
|
251
|
-
Send via alias:
|
|
224
|
+
#### `session list` — List local sessions
|
|
252
225
|
|
|
253
226
|
```bash
|
|
254
|
-
tw
|
|
227
|
+
tw session list --profile agent --json
|
|
228
|
+
tw session list --profile agent --on-chain --json
|
|
255
229
|
```
|
|
256
230
|
|
|
257
|
-
|
|
231
|
+
#### `session rotate` — Rotate the active session
|
|
258
232
|
|
|
259
|
-
|
|
260
|
-
|
|
233
|
+
```bash
|
|
234
|
+
echo "my-password" | tw session rotate --profile agent --password-stdin --json
|
|
235
|
+
echo "my-password" | tw session rotate --profile agent --new-name worker-3 --password-stdin
|
|
236
|
+
echo "my-password" | tw session rotate --profile agent --resume --password-stdin --json
|
|
237
|
+
```
|
|
261
238
|
|
|
262
|
-
|
|
239
|
+
#### `session revoke` — Revoke a session on-chain
|
|
263
240
|
|
|
264
241
|
```bash
|
|
265
|
-
tw
|
|
266
|
-
|
|
242
|
+
echo "my-password" | tw session revoke worker-1 --profile agent --password-stdin --json
|
|
243
|
+
echo "my-password" | tw session revoke worker-2 --profile agent --force --password-stdin
|
|
244
|
+
echo "my-password" | tw session revoke worker-2 --profile agent --resume --password-stdin --json
|
|
267
245
|
```
|
|
268
246
|
|
|
269
|
-
`--
|
|
270
|
-
|
|
271
|
-
## Account Status
|
|
247
|
+
Agent sessions require `--force` and clean up local channel bindings as part of revocation.
|
|
272
248
|
|
|
273
|
-
|
|
249
|
+
#### `session export` — Export as portable file
|
|
274
250
|
|
|
275
251
|
```bash
|
|
276
|
-
|
|
252
|
+
TW_PASSWORD="my-password" TW_EXPORT_PASSWORD="export-password" \
|
|
253
|
+
tw session export worker-1 --profile agent --output ./worker-1.session.json
|
|
277
254
|
```
|
|
278
255
|
|
|
279
|
-
|
|
256
|
+
Or via stdin:
|
|
280
257
|
|
|
281
258
|
```bash
|
|
282
|
-
tw
|
|
259
|
+
echo "export-password" | tw session export worker-1 --profile agent \
|
|
260
|
+
--output ./worker-1.session.json --export-password-stdin
|
|
283
261
|
```
|
|
284
262
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
Rotate local keystore encryption password (interactive):
|
|
263
|
+
#### `session import` — Import a portable session
|
|
288
264
|
|
|
289
265
|
```bash
|
|
290
|
-
tw
|
|
266
|
+
tw session import ./worker-1.session.json --profile worker-1
|
|
291
267
|
```
|
|
292
268
|
|
|
293
|
-
|
|
269
|
+
Creates a session-only profile that can execute `account send` but cannot run manager commands requiring a root keystore.
|
|
294
270
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### Session Daemon
|
|
298
274
|
|
|
299
|
-
|
|
275
|
+
The daemon holds decrypted session keys in memory so automated workflows can sign without re-entering passwords.
|
|
300
276
|
|
|
301
|
-
|
|
277
|
+
#### `session start` — Start the daemon
|
|
302
278
|
|
|
303
279
|
```bash
|
|
304
|
-
|
|
280
|
+
tw session start --json
|
|
281
|
+
tw session start --foreground --json
|
|
305
282
|
```
|
|
306
283
|
|
|
307
|
-
|
|
284
|
+
Idempotent — if already running, returns the active pid/socket.
|
|
285
|
+
|
|
286
|
+
#### `session unlock` — Load a key into daemon memory
|
|
308
287
|
|
|
309
288
|
```bash
|
|
310
|
-
echo "my-password" | tw session
|
|
289
|
+
echo "my-password" | tw session unlock worker-1 --profile agent --password-stdin --duration 15m --json
|
|
311
290
|
```
|
|
312
291
|
|
|
313
|
-
|
|
292
|
+
Key material stays in daemon memory only; encrypted files remain unchanged.
|
|
293
|
+
|
|
294
|
+
#### `session lock` — Remove a key from daemon memory
|
|
314
295
|
|
|
315
296
|
```bash
|
|
316
|
-
|
|
297
|
+
tw session lock worker-1 --json
|
|
317
298
|
```
|
|
318
299
|
|
|
319
|
-
|
|
300
|
+
#### `session status` — Check daemon health
|
|
320
301
|
|
|
321
302
|
```bash
|
|
322
|
-
|
|
303
|
+
tw session status --json
|
|
323
304
|
```
|
|
324
305
|
|
|
325
|
-
|
|
326
|
-
Omitting both `--target` and `--selector` uses wildcard call permissions by default; you do not need to pass magic wildcard values.
|
|
327
|
-
`--spend-limit` accepts human USDC amounts (for example `10` = `10 USDC`). Use `--spend-limit-raw` for base units.
|
|
328
|
-
|
|
329
|
-
## Session List
|
|
330
|
-
|
|
331
|
-
List local sessions:
|
|
306
|
+
#### `session stop` — Shut down the daemon
|
|
332
307
|
|
|
333
308
|
```bash
|
|
334
|
-
tw session
|
|
309
|
+
tw session stop --json
|
|
335
310
|
```
|
|
336
311
|
|
|
337
|
-
|
|
312
|
+
---
|
|
338
313
|
|
|
339
|
-
|
|
340
|
-
tw session list --profile agent --on-chain --json
|
|
341
|
-
```
|
|
314
|
+
### Permissions
|
|
342
315
|
|
|
343
|
-
|
|
316
|
+
Fine-grained on-chain permission rules for session keys.
|
|
344
317
|
|
|
345
|
-
|
|
318
|
+
#### `permissions list` — List keys and their permissions
|
|
346
319
|
|
|
347
320
|
```bash
|
|
348
|
-
|
|
349
|
-
tw session export worker-1 --profile agent --output ./worker-1.session.json
|
|
321
|
+
tw permissions list --profile agent --json
|
|
350
322
|
```
|
|
351
323
|
|
|
352
|
-
|
|
324
|
+
#### `permissions show` — Show rules for a specific key
|
|
353
325
|
|
|
354
326
|
```bash
|
|
355
|
-
|
|
356
|
-
|
|
327
|
+
tw permissions show agent-key --profile agent --json
|
|
328
|
+
tw permissions show --key-hash 0xaaa... --profile agent --json
|
|
357
329
|
```
|
|
358
330
|
|
|
359
|
-
|
|
331
|
+
#### `permissions grant` — Grant a permission rule
|
|
360
332
|
|
|
361
|
-
|
|
333
|
+
Wildcard call permission:
|
|
362
334
|
|
|
363
335
|
```bash
|
|
364
|
-
tw
|
|
336
|
+
echo "my-password" | tw permissions grant agent-key --type call --target any --selector any --profile agent --password-stdin --json
|
|
365
337
|
```
|
|
366
338
|
|
|
367
|
-
|
|
339
|
+
Daily USDC spend limit:
|
|
368
340
|
|
|
369
341
|
```bash
|
|
370
|
-
|
|
342
|
+
echo "my-password" | tw permissions grant agent-key --type spend --token USDC --spend-limit 100 --period day --profile agent --password-stdin --json
|
|
371
343
|
```
|
|
372
344
|
|
|
373
|
-
|
|
345
|
+
Use `--spend-limit-raw` for base units instead of human amounts.
|
|
374
346
|
|
|
375
|
-
|
|
347
|
+
#### `permissions revoke` — Revoke permission rules
|
|
376
348
|
|
|
377
|
-
|
|
349
|
+
Revoke a single rule:
|
|
378
350
|
|
|
379
351
|
```bash
|
|
380
|
-
echo "my-password" | tw
|
|
352
|
+
echo "my-password" | tw permissions revoke agent-key --rule call:0x...:0xa9059cbb --profile agent --password-stdin --json
|
|
381
353
|
```
|
|
382
354
|
|
|
383
|
-
|
|
355
|
+
Revoke all rules for a key:
|
|
384
356
|
|
|
385
357
|
```bash
|
|
386
|
-
echo "my-password" | tw
|
|
358
|
+
echo "my-password" | tw permissions revoke agent-key --all --profile agent --password-stdin --json
|
|
387
359
|
```
|
|
388
360
|
|
|
389
|
-
|
|
390
|
-
Omitting both `--target` and `--selector` uses wildcard call permissions by default; you do not need to pass magic wildcard values.
|
|
391
|
-
`--spend-limit` accepts human USDC amounts (for example `10` = `10 USDC`). Use `--spend-limit-raw` for base units.
|
|
361
|
+
---
|
|
392
362
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
```bash
|
|
396
|
-
echo "my-password" | tw session rotate --profile agent --resume --password-stdin --json
|
|
397
|
-
```
|
|
363
|
+
### Escrow
|
|
398
364
|
|
|
399
|
-
|
|
365
|
+
USDC escrow: lock funds as buyer with a seller and oracle; settle (oracle signs) or refund after deadline.
|
|
400
366
|
|
|
401
|
-
|
|
367
|
+
#### `escrow create` — Create a new USDC escrow
|
|
402
368
|
|
|
403
369
|
```bash
|
|
404
|
-
|
|
370
|
+
tw escrow create 50 0x1111111111111111111111111111111111111111 \
|
|
371
|
+
--oracle 0x2222222222222222222222222222222222222222 --deadline 24h
|
|
372
|
+
tw escrow create 100 0x... --oracle 0x... --deadline 2d --chain base --env prod --json
|
|
405
373
|
```
|
|
406
374
|
|
|
407
|
-
|
|
375
|
+
- **Amount** and **seller** are positional; **oracle** and **deadline** are required options.
|
|
376
|
+
- **Deadline**: relative (`1h`, `2d`, `30m`, `1w`) or unix timestamp. After deadline, anyone can call `escrow refund`.
|
|
377
|
+
- Optional **salt** (hex, up to 12 bytes) for unique escrow IDs on repeated orders.
|
|
378
|
+
- Uses session key (daemon or direct) to sign; supports `--session-file` like `account send`.
|
|
408
379
|
|
|
409
|
-
|
|
410
|
-
echo "my-password" | tw session revoke worker-2 --profile agent --force --password-stdin
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
Idempotent retry/cleanup when already revoked on-chain:
|
|
380
|
+
#### `escrow status` — Check on-chain status
|
|
414
381
|
|
|
415
382
|
```bash
|
|
416
|
-
|
|
383
|
+
tw escrow status 0x<64 hex chars> --env prod
|
|
384
|
+
tw escrow status 0x... --chain base --json
|
|
417
385
|
```
|
|
418
386
|
|
|
419
|
-
|
|
387
|
+
Escrow ID must be the full 32-byte hex (0x + 64 hex chars), e.g. from `escrow create` output.
|
|
420
388
|
|
|
421
|
-
|
|
389
|
+
#### `escrow settle` — Settle (release USDC to seller)
|
|
422
390
|
|
|
423
|
-
|
|
391
|
+
Oracle signs a settlement; any account can submit the signed settlement via relayer.
|
|
424
392
|
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
|
|
393
|
+
```bash
|
|
394
|
+
TW_ORACLE_PRIVATE_KEY=0x... tw escrow settle 0x<escrowId> \
|
|
395
|
+
--settlement-id 0x<orderId> --oracle 0x2222... --profile agent
|
|
428
396
|
```
|
|
429
397
|
|
|
430
|
-
|
|
398
|
+
Or with pre-signed signature (oracle signs offline):
|
|
431
399
|
|
|
432
400
|
```bash
|
|
433
|
-
|
|
434
|
-
TW_PASSWORD="my-password" tw agent create bob --profile agent
|
|
401
|
+
tw escrow settle 0x<escrowId> --settlement-id 0x... --oracle 0x... --signature 0x... --profile agent
|
|
435
402
|
```
|
|
436
403
|
|
|
437
|
-
|
|
404
|
+
Settlement ID is the bytes32 order ID used at creation (see create output or `escrow status`).
|
|
438
405
|
|
|
439
|
-
|
|
440
|
-
TW_PASSWORD="my-password" tw agent list --profile agent --json
|
|
441
|
-
```
|
|
406
|
+
#### `escrow refund` — Refund to buyer after deadline
|
|
442
407
|
|
|
443
|
-
|
|
408
|
+
Permissionless: after the escrow deadline, anyone can trigger refund to the buyer.
|
|
444
409
|
|
|
445
410
|
```bash
|
|
446
|
-
|
|
411
|
+
tw escrow refund 0x<escrowId> --profile agent
|
|
412
|
+
tw escrow refund 0x<escrowId> --env prod --json
|
|
447
413
|
```
|
|
448
414
|
|
|
449
|
-
|
|
415
|
+
---
|
|
450
416
|
|
|
451
|
-
|
|
452
|
-
- `secret` — the shared rendezvous secret, returned only when the binding is first created
|
|
417
|
+
### Contacts
|
|
453
418
|
|
|
454
|
-
|
|
419
|
+
Store recipient aliases so you never have to copy-paste addresses.
|
|
455
420
|
|
|
456
|
-
```
|
|
457
|
-
|
|
421
|
+
```text
|
|
422
|
+
~/.config/towns/tw/contacts.json
|
|
458
423
|
```
|
|
459
424
|
|
|
460
|
-
Send to a named channel:
|
|
461
|
-
|
|
462
425
|
```bash
|
|
463
|
-
|
|
426
|
+
tw contacts add vitalik vitalik.eth
|
|
427
|
+
tw contacts add treasury 0x1111111111111111111111111111111111111111
|
|
428
|
+
tw contacts list --json
|
|
429
|
+
tw contacts show vitalik --json
|
|
430
|
+
tw contacts update vitalik 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
431
|
+
tw contacts rename vitalik vitalik-main
|
|
432
|
+
tw contacts remove vitalik-main
|
|
464
433
|
```
|
|
465
434
|
|
|
466
|
-
|
|
435
|
+
Export and import:
|
|
467
436
|
|
|
468
437
|
```bash
|
|
469
|
-
|
|
438
|
+
tw contacts export --json
|
|
439
|
+
tw contacts import ./contacts.json --json
|
|
440
|
+
tw contacts import ./contacts.json --force --json
|
|
470
441
|
```
|
|
471
442
|
|
|
472
|
-
|
|
443
|
+
Import returns `importedCount`, `skippedInvalidCount`, `skippedConflictCount`, and `overwrittenCount`.
|
|
444
|
+
|
|
445
|
+
Send via alias:
|
|
473
446
|
|
|
474
447
|
```bash
|
|
475
|
-
|
|
448
|
+
tw account send 10 vitalik
|
|
476
449
|
```
|
|
477
450
|
|
|
478
|
-
|
|
451
|
+
ENS safety: if ENS re-resolves to a different address than stored, send aborts and requires `tw contacts update`.
|
|
479
452
|
|
|
480
|
-
|
|
481
|
-
TW_PASSWORD="my-password" tw agent listen --from bob --stream 77aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --profile agent
|
|
482
|
-
```
|
|
453
|
+
---
|
|
483
454
|
|
|
484
|
-
|
|
455
|
+
### Agents
|
|
485
456
|
|
|
486
|
-
|
|
487
|
-
|
|
457
|
+
Agents are session-key-backed Towns identities with their own encryption device and named channel bindings. Identity management lives under `tw session`; `tw agent` is reserved for messaging commands.
|
|
458
|
+
|
|
459
|
+
```text
|
|
460
|
+
~/.config/towns/tw/profiles/<env>/<profile>/sessions/<name>.json
|
|
461
|
+
~/.config/towns/tw/profiles/<env>/<profile>/agent-channels.json
|
|
488
462
|
```
|
|
489
463
|
|
|
490
|
-
|
|
464
|
+
#### `session create --agent` / `agent init` / `session list`
|
|
491
465
|
|
|
492
466
|
```bash
|
|
493
|
-
TW_PASSWORD="my-password" tw
|
|
467
|
+
TW_PASSWORD="my-password" tw session create alice --profile agent --agent
|
|
468
|
+
TW_PASSWORD="my-password" tw session create bob --profile agent
|
|
469
|
+
TW_PASSWORD="my-password" tw agent init bob --profile agent
|
|
470
|
+
TW_PASSWORD="my-password" tw session list --profile agent --json
|
|
494
471
|
```
|
|
495
472
|
|
|
496
|
-
|
|
473
|
+
`tw session list` includes a `kind` field (`session` or `agent`). Revoke agent identities with `tw session revoke <name> --force`.
|
|
497
474
|
|
|
498
|
-
|
|
475
|
+
Migration note: legacy `agent-<name>.json` files are no longer loaded. Rename them to `<name>.json` manually or recreate them with `tw session create` plus `tw agent init`.
|
|
499
476
|
|
|
500
|
-
|
|
477
|
+
#### `agent connect` — Create or bind a named channel
|
|
501
478
|
|
|
502
|
-
|
|
503
|
-
tw account create --profile agent
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
2. Create two agents:
|
|
479
|
+
First side creates the channel and returns the shared secret:
|
|
507
480
|
|
|
508
481
|
```bash
|
|
509
|
-
TW_PASSWORD="my-password" tw agent
|
|
510
|
-
TW_PASSWORD="my-password" tw agent create bob --profile agent
|
|
482
|
+
TW_PASSWORD="my-password" tw agent connect --from alice --channel art --to bob --profile agent
|
|
511
483
|
```
|
|
512
484
|
|
|
513
|
-
|
|
485
|
+
Second side binds using that secret:
|
|
514
486
|
|
|
515
487
|
```bash
|
|
516
|
-
TW_PASSWORD="my-password" tw agent connect --from
|
|
488
|
+
TW_PASSWORD="my-password" tw agent connect --from bob --channel art --secret "<shared-secret>" --to alice --profile agent
|
|
517
489
|
```
|
|
518
490
|
|
|
519
|
-
|
|
491
|
+
#### `agent send` — Send a message
|
|
492
|
+
|
|
493
|
+
To a named channel:
|
|
520
494
|
|
|
521
495
|
```bash
|
|
522
|
-
TW_PASSWORD="my-password" tw agent
|
|
496
|
+
TW_PASSWORD="my-password" tw agent send --from alice --channel art "hello from alice" --profile agent
|
|
523
497
|
```
|
|
524
498
|
|
|
525
|
-
|
|
499
|
+
To a raw stream ID:
|
|
526
500
|
|
|
527
501
|
```bash
|
|
528
|
-
TW_PASSWORD="my-password" tw agent
|
|
502
|
+
TW_PASSWORD="my-password" tw agent send --from alice 77aaa... "debug message" --profile agent
|
|
529
503
|
```
|
|
530
504
|
|
|
531
|
-
|
|
505
|
+
#### `agent listen` — Listen for messages
|
|
532
506
|
|
|
533
507
|
```bash
|
|
534
|
-
TW_PASSWORD="my-password" tw agent
|
|
508
|
+
TW_PASSWORD="my-password" tw agent listen --from bob --channel art --profile agent
|
|
509
|
+
TW_PASSWORD="my-password" tw agent listen --from bob --stream 77aaa... --profile agent
|
|
535
510
|
```
|
|
536
511
|
|
|
537
|
-
|
|
512
|
+
Messages arrive as NDJSON:
|
|
538
513
|
|
|
539
514
|
```json
|
|
540
515
|
{
|
|
@@ -547,85 +522,71 @@ TW_PASSWORD="my-password" tw agent send --from alice --channel art "hello from a
|
|
|
547
522
|
}
|
|
548
523
|
```
|
|
549
524
|
|
|
550
|
-
|
|
525
|
+
#### `agent channels` — Inspect bindings
|
|
551
526
|
|
|
552
527
|
```bash
|
|
553
|
-
TW_PASSWORD="my-password" tw agent channels --from alice --profile agent
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
For a single-command live verification, run the built-in smoke script:
|
|
557
|
-
|
|
558
|
-
```bash
|
|
559
|
-
cd packages/wallet
|
|
560
|
-
TW_PASSWORD="my-password" bun run smoke:agent
|
|
528
|
+
TW_PASSWORD="my-password" tw agent channels --from alice --profile agent --json
|
|
561
529
|
```
|
|
562
530
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
List all on-chain keys with summarized call/spend permissions:
|
|
531
|
+
#### Agent Quickstart
|
|
566
532
|
|
|
567
533
|
```bash
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
534
|
+
# Create profile + two agent sessions
|
|
535
|
+
tw account create --profile agent
|
|
536
|
+
TW_PASSWORD="pw" tw session create alice --profile agent --agent
|
|
537
|
+
TW_PASSWORD="pw" tw session create bob --profile agent
|
|
538
|
+
TW_PASSWORD="pw" tw agent init bob --profile agent
|
|
572
539
|
|
|
573
|
-
|
|
540
|
+
# Alice creates a channel → copy the returned secret
|
|
541
|
+
TW_PASSWORD="pw" tw agent connect --from alice --channel art --to bob --profile agent
|
|
574
542
|
|
|
575
|
-
|
|
576
|
-
tw
|
|
577
|
-
```
|
|
543
|
+
# Bob binds with that secret
|
|
544
|
+
TW_PASSWORD="pw" tw agent connect --from bob --channel art --secret "<secret>" --to alice --profile agent
|
|
578
545
|
|
|
579
|
-
|
|
546
|
+
# Terminal 1: listen
|
|
547
|
+
TW_PASSWORD="pw" tw agent listen --from bob --channel art --profile agent
|
|
580
548
|
|
|
581
|
-
|
|
582
|
-
tw
|
|
549
|
+
# Terminal 2: send
|
|
550
|
+
TW_PASSWORD="pw" tw agent send --from alice --channel art "hello" --profile agent
|
|
583
551
|
```
|
|
584
552
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
Grant wildcard call permission:
|
|
553
|
+
Smoke test:
|
|
588
554
|
|
|
589
555
|
```bash
|
|
590
|
-
|
|
556
|
+
cd packages/wallet
|
|
557
|
+
TW_PASSWORD="my-password" bun run smoke:agent
|
|
591
558
|
```
|
|
592
559
|
|
|
593
|
-
|
|
560
|
+
---
|
|
594
561
|
|
|
595
|
-
|
|
596
|
-
echo "my-password" | tw permissions grant agent-key --type spend --token USDC --spend-limit 100 --period day --profile agent --password-stdin --json
|
|
597
|
-
```
|
|
562
|
+
## Agent & Automation Integration
|
|
598
563
|
|
|
599
|
-
|
|
564
|
+
Every command supports `--json` for machine-readable output. Treat JSON output schemas as the stable contract.
|
|
600
565
|
|
|
601
566
|
```bash
|
|
602
|
-
|
|
567
|
+
tw <command> --json
|
|
603
568
|
```
|
|
604
569
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
Revoke one rule by stable rule id:
|
|
608
|
-
|
|
609
|
-
```bash
|
|
610
|
-
echo "my-password" | tw permissions revoke agent-key --rule call:0x2222222222222222222222222222222222222222:0xa9059cbb --profile agent --password-stdin --json
|
|
611
|
-
```
|
|
570
|
+
### Password Automation
|
|
612
571
|
|
|
613
|
-
|
|
572
|
+
Use `TW_PASSWORD` to skip interactive prompts:
|
|
614
573
|
|
|
615
574
|
```bash
|
|
616
|
-
|
|
575
|
+
TW_PASSWORD="my-password" tw session list --profile agent --json
|
|
617
576
|
```
|
|
618
577
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
Use `TW_PASSWORD` for non-interactive flows:
|
|
578
|
+
Or pipe via stdin for commands that accept `--password-stdin`:
|
|
622
579
|
|
|
623
580
|
```bash
|
|
624
|
-
|
|
581
|
+
echo "my-password" | tw session rotate --profile agent --password-stdin --json
|
|
625
582
|
```
|
|
626
583
|
|
|
627
|
-
|
|
584
|
+
### Discovery
|
|
628
585
|
|
|
629
586
|
```bash
|
|
630
|
-
|
|
587
|
+
tw --help # All commands
|
|
588
|
+
tw account send --help # Command-specific help
|
|
589
|
+
tw --llms # Machine-readable command manifest
|
|
590
|
+
tw --mcp # Run as MCP server
|
|
591
|
+
tw --version # Version
|
|
631
592
|
```
|