arc402-cli 0.9.19 → 0.10.0
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 +41 -2
- package/dist/abis.d.ts +1 -0
- package/dist/abis.d.ts.map +1 -1
- package/dist/abis.js +45 -14
- package/dist/abis.js.map +1 -1
- package/dist/bundler.d.ts +1 -1
- package/dist/bundler.d.ts.map +1 -1
- package/dist/bundler.js +61 -27
- package/dist/bundler.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -5
- package/dist/client.js.map +1 -1
- package/dist/coinbase-smart-wallet.js +4 -1
- package/dist/coinbase-smart-wallet.js.map +1 -1
- package/dist/commands/accept.js +28 -25
- package/dist/commands/accept.js.map +1 -1
- package/dist/commands/agent-handshake.js +18 -15
- package/dist/commands/agent-handshake.js.map +1 -1
- package/dist/commands/agent.js +104 -98
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/agreements.js +98 -62
- package/dist/commands/agreements.js.map +1 -1
- package/dist/commands/arbitrator.js +81 -45
- package/dist/commands/arbitrator.js.map +1 -1
- package/dist/commands/arena-handshake.d.ts.map +1 -1
- package/dist/commands/arena-handshake.js +35 -53
- package/dist/commands/arena-handshake.js.map +1 -1
- package/dist/commands/arena.js +18 -12
- package/dist/commands/arena.js.map +1 -1
- package/dist/commands/backup.js +36 -30
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/cancel.js +18 -15
- package/dist/commands/cancel.js.map +1 -1
- package/dist/commands/channel.js +81 -45
- package/dist/commands/channel.js.map +1 -1
- package/dist/commands/coldstart.js +34 -31
- package/dist/commands/coldstart.js.map +1 -1
- package/dist/commands/compute.d.ts +14 -0
- package/dist/commands/compute.d.ts.map +1 -0
- package/dist/commands/compute.js +466 -0
- package/dist/commands/compute.js.map +1 -0
- package/dist/commands/config.js +30 -24
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contract-interaction.js +15 -12
- package/dist/commands/contract-interaction.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +135 -98
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/deliver.js +76 -37
- package/dist/commands/deliver.js.map +1 -1
- package/dist/commands/discover.js +27 -24
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/dispute.js +110 -104
- package/dist/commands/dispute.js.map +1 -1
- package/dist/commands/doctor.js +55 -16
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/endpoint.js +95 -56
- package/dist/commands/endpoint.js.map +1 -1
- package/dist/commands/feed.js +18 -11
- package/dist/commands/feed.js.map +1 -1
- package/dist/commands/hire.js +40 -37
- package/dist/commands/hire.js.map +1 -1
- package/dist/commands/migrate.js +33 -30
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/negotiate.d.ts.map +1 -1
- package/dist/commands/negotiate.js +36 -34
- package/dist/commands/negotiate.js.map +1 -1
- package/dist/commands/openshell.js +104 -68
- package/dist/commands/openshell.js.map +1 -1
- package/dist/commands/owner.js +20 -17
- package/dist/commands/owner.js.map +1 -1
- package/dist/commands/policy.js +43 -41
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/relay.d.ts.map +1 -1
- package/dist/commands/relay.js +51 -18
- package/dist/commands/relay.js.map +1 -1
- package/dist/commands/remediate.js +23 -20
- package/dist/commands/remediate.js.map +1 -1
- package/dist/commands/reputation.js +27 -25
- package/dist/commands/reputation.js.map +1 -1
- package/dist/commands/setup.js +104 -65
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/trust.js +20 -17
- package/dist/commands/trust.js.map +1 -1
- package/dist/commands/verify.js +21 -18
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +645 -679
- package/dist/commands/wallet.js.map +1 -1
- package/dist/commands/watch.js +36 -33
- package/dist/commands/watch.js.map +1 -1
- package/dist/commands/watchtower.js +73 -37
- package/dist/commands/watchtower.js.map +1 -1
- package/dist/commands/workroom.d.ts.map +1 -1
- package/dist/commands/workroom.js +282 -143
- package/dist/commands/workroom.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +71 -22
- package/dist/config.js.map +1 -1
- package/dist/daemon/compute-metering.d.ts +61 -0
- package/dist/daemon/compute-metering.d.ts.map +1 -0
- package/dist/daemon/compute-metering.js +299 -0
- package/dist/daemon/compute-metering.js.map +1 -0
- package/dist/daemon/compute-session.d.ts +100 -0
- package/dist/daemon/compute-session.d.ts.map +1 -0
- package/dist/daemon/compute-session.js +231 -0
- package/dist/daemon/compute-session.js.map +1 -0
- package/dist/daemon/config.d.ts +19 -1
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +90 -16
- package/dist/daemon/config.js.map +1 -1
- package/dist/daemon/credentials.d.ts +24 -0
- package/dist/daemon/credentials.d.ts.map +1 -0
- package/dist/daemon/credentials.js +80 -0
- package/dist/daemon/credentials.js.map +1 -0
- package/dist/daemon/delivery-client.d.ts +35 -0
- package/dist/daemon/delivery-client.d.ts.map +1 -0
- package/dist/daemon/delivery-client.js +231 -0
- package/dist/daemon/delivery-client.js.map +1 -0
- package/dist/daemon/file-delivery.d.ts +98 -0
- package/dist/daemon/file-delivery.d.ts.map +1 -0
- package/dist/daemon/file-delivery.js +461 -0
- package/dist/daemon/file-delivery.js.map +1 -0
- package/dist/daemon/hire-listener.d.ts +3 -3
- package/dist/daemon/hire-listener.d.ts.map +1 -1
- package/dist/daemon/hire-listener.js +47 -13
- package/dist/daemon/hire-listener.js.map +1 -1
- package/dist/daemon/index.d.ts +2 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +526 -53
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/job-lifecycle.d.ts +1 -1
- package/dist/daemon/job-lifecycle.d.ts.map +1 -1
- package/dist/daemon/job-lifecycle.js +51 -11
- package/dist/daemon/job-lifecycle.js.map +1 -1
- package/dist/daemon/notify.d.ts +1 -1
- package/dist/daemon/notify.d.ts.map +1 -1
- package/dist/daemon/notify.js +53 -19
- package/dist/daemon/notify.js.map +1 -1
- package/dist/daemon/token-metering.js +47 -8
- package/dist/daemon/token-metering.js.map +1 -1
- package/dist/daemon/userops.d.ts +2 -2
- package/dist/daemon/userops.d.ts.map +1 -1
- package/dist/daemon/userops.js +27 -23
- package/dist/daemon/userops.js.map +1 -1
- package/dist/daemon/wallet-monitor.d.ts +1 -1
- package/dist/daemon/wallet-monitor.d.ts.map +1 -1
- package/dist/daemon/wallet-monitor.js +12 -8
- package/dist/daemon/wallet-monitor.js.map +1 -1
- package/dist/daemon/worker-executor.d.ts +71 -0
- package/dist/daemon/worker-executor.d.ts.map +1 -0
- package/dist/daemon/worker-executor.js +382 -0
- package/dist/daemon/worker-executor.js.map +1 -0
- package/dist/drain-v4.js +64 -26
- package/dist/drain-v4.js.map +1 -1
- package/dist/endpoint-config.js +63 -20
- package/dist/endpoint-config.js.map +1 -1
- package/dist/endpoint-notify.d.ts.map +1 -1
- package/dist/endpoint-notify.js +49 -15
- package/dist/endpoint-notify.js.map +1 -1
- package/dist/index.js +50 -18
- package/dist/index.js.map +1 -1
- package/dist/openshell-runtime.d.ts.map +1 -1
- package/dist/openshell-runtime.js +82 -38
- package/dist/openshell-runtime.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +85 -78
- package/dist/program.js.map +1 -1
- package/dist/repl.js +31 -25
- package/dist/repl.js.map +1 -1
- package/dist/signing.js +6 -3
- package/dist/signing.js.map +1 -1
- package/dist/telegram-notify.js +40 -3
- package/dist/telegram-notify.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +56 -89
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Footer.js +7 -4
- package/dist/tui/Footer.js.map +1 -1
- package/dist/tui/Header.d.ts +1 -1
- package/dist/tui/Header.d.ts.map +1 -1
- package/dist/tui/Header.js +14 -9
- package/dist/tui/Header.js.map +1 -1
- package/dist/tui/InputLine.d.ts +2 -1
- package/dist/tui/InputLine.d.ts.map +1 -1
- package/dist/tui/InputLine.js +47 -97
- package/dist/tui/InputLine.js.map +1 -1
- package/dist/tui/Viewport.d.ts +1 -2
- package/dist/tui/Viewport.d.ts.map +1 -1
- package/dist/tui/Viewport.js +26 -6
- package/dist/tui/Viewport.js.map +1 -1
- package/dist/tui/WalletConnectPairing.js +19 -16
- package/dist/tui/WalletConnectPairing.js.map +1 -1
- package/dist/tui/components/Button.js +9 -6
- package/dist/tui/components/Button.js.map +1 -1
- package/dist/tui/components/CeremonyView.js +8 -5
- package/dist/tui/components/CeremonyView.js.map +1 -1
- package/dist/tui/components/CompletionDropdown.js +9 -6
- package/dist/tui/components/CompletionDropdown.js.map +1 -1
- package/dist/tui/components/ConfirmPrompt.js +8 -5
- package/dist/tui/components/ConfirmPrompt.js.map +1 -1
- package/dist/tui/components/CustomTextInput.js +14 -11
- package/dist/tui/components/CustomTextInput.js.map +1 -1
- package/dist/tui/components/InteractiveTable.js +12 -9
- package/dist/tui/components/InteractiveTable.js.map +1 -1
- package/dist/tui/components/StepSpinner.js +13 -10
- package/dist/tui/components/StepSpinner.js.map +1 -1
- package/dist/tui/components/Toast.js +12 -8
- package/dist/tui/components/Toast.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +21 -28
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/useChat.js +19 -13
- package/dist/tui/useChat.js.map +1 -1
- package/dist/tui/useCommand.d.ts +2 -3
- package/dist/tui/useCommand.d.ts.map +1 -1
- package/dist/tui/useCommand.js +24 -100
- package/dist/tui/useCommand.js.map +1 -1
- package/dist/tui/useNotifications.js +8 -5
- package/dist/tui/useNotifications.js.map +1 -1
- package/dist/tui/useScroll.d.ts.map +1 -1
- package/dist/tui/useScroll.js +12 -15
- package/dist/tui/useScroll.js.map +1 -1
- package/dist/ui/banner.d.ts +0 -12
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +19 -35
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/colors.js +19 -13
- package/dist/ui/colors.js.map +1 -1
- package/dist/ui/format.js +14 -6
- package/dist/ui/format.js.map +1 -1
- package/dist/ui/qr-render.js +11 -4
- package/dist/ui/qr-render.js.map +1 -1
- package/dist/ui/rpc-fallback.js +11 -6
- package/dist/ui/rpc-fallback.js.map +1 -1
- package/dist/ui/spinner.js +12 -6
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/tree.js +6 -3
- package/dist/ui/tree.js.map +1 -1
- package/dist/utils/format.js +41 -27
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/hash.js +42 -4
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/time.js +6 -2
- package/dist/utils/time.js.map +1 -1
- package/dist/wallet-router.d.ts +1 -1
- package/dist/wallet-router.d.ts.map +1 -1
- package/dist/wallet-router.js +19 -12
- package/dist/wallet-router.js.map +1 -1
- package/dist/walletconnect-session.d.ts +1 -1
- package/dist/walletconnect-session.d.ts.map +1 -1
- package/dist/walletconnect-session.js +11 -6
- package/dist/walletconnect-session.js.map +1 -1
- package/dist/walletconnect.d.ts +5 -6
- package/dist/walletconnect.d.ts.map +1 -1
- package/dist/walletconnect.js +35 -32
- package/dist/walletconnect.js.map +1 -1
- package/package.json +11 -10
- package/INK6-UX-SPEC.md +0 -446
- package/MIGRATION-SPEC.md +0 -108
- package/TUI-SPEC.md +0 -214
- package/scripts/authorize-machine-key.ts +0 -43
- package/scripts/drain-wallet.ts +0 -149
- package/scripts/execute-spend-only.ts +0 -81
- package/scripts/register-agent-userop.ts +0 -186
- package/src/abis.ts +0 -187
- package/src/bundler.ts +0 -235
- package/src/client.ts +0 -36
- package/src/coinbase-smart-wallet.ts +0 -51
- package/src/commands/accept.ts +0 -64
- package/src/commands/agent-handshake.ts +0 -72
- package/src/commands/agent.ts +0 -691
- package/src/commands/agreements.ts +0 -350
- package/src/commands/arbitrator.ts +0 -180
- package/src/commands/arena-handshake.ts +0 -274
- package/src/commands/arena.ts +0 -122
- package/src/commands/backup.ts +0 -117
- package/src/commands/cancel.ts +0 -35
- package/src/commands/channel.ts +0 -218
- package/src/commands/coldstart.ts +0 -165
- package/src/commands/config.ts +0 -68
- package/src/commands/contract-interaction.ts +0 -166
- package/src/commands/daemon.ts +0 -1054
- package/src/commands/deliver.ts +0 -148
- package/src/commands/discover.ts +0 -350
- package/src/commands/dispute.ts +0 -375
- package/src/commands/doctor.ts +0 -172
- package/src/commands/endpoint.ts +0 -620
- package/src/commands/feed.ts +0 -229
- package/src/commands/hire.ts +0 -245
- package/src/commands/migrate.ts +0 -177
- package/src/commands/negotiate.ts +0 -272
- package/src/commands/openshell.ts +0 -1055
- package/src/commands/owner.ts +0 -35
- package/src/commands/policy.ts +0 -263
- package/src/commands/relay.ts +0 -277
- package/src/commands/remediate.ts +0 -24
- package/src/commands/reputation.ts +0 -79
- package/src/commands/setup.ts +0 -343
- package/src/commands/trust.ts +0 -27
- package/src/commands/verify.ts +0 -91
- package/src/commands/wallet.ts +0 -3548
- package/src/commands/watch.ts +0 -220
- package/src/commands/watchtower.ts +0 -248
- package/src/commands/workroom.ts +0 -963
- package/src/config.ts +0 -220
- package/src/daemon/config.ts +0 -344
- package/src/daemon/hire-listener.ts +0 -226
- package/src/daemon/index.ts +0 -1089
- package/src/daemon/job-lifecycle.ts +0 -215
- package/src/daemon/notify.ts +0 -297
- package/src/daemon/token-metering.ts +0 -183
- package/src/daemon/userops.ts +0 -119
- package/src/daemon/wallet-monitor.ts +0 -90
- package/src/drain-v4.ts +0 -159
- package/src/endpoint-config.ts +0 -83
- package/src/endpoint-notify.ts +0 -134
- package/src/index.ts +0 -74
- package/src/openshell-runtime.ts +0 -281
- package/src/program.ts +0 -88
- package/src/repl.ts +0 -178
- package/src/signing.ts +0 -28
- package/src/telegram-notify.ts +0 -88
- package/src/tui/App.tsx +0 -263
- package/src/tui/Footer.tsx +0 -18
- package/src/tui/Header.tsx +0 -45
- package/src/tui/InputLine.tsx +0 -243
- package/src/tui/Viewport.tsx +0 -51
- package/src/tui/WalletConnectPairing.tsx +0 -114
- package/src/tui/components/Button.tsx +0 -38
- package/src/tui/components/CeremonyView.tsx +0 -39
- package/src/tui/components/CompletionDropdown.tsx +0 -56
- package/src/tui/components/ConfirmPrompt.tsx +0 -36
- package/src/tui/components/CustomTextInput.tsx +0 -132
- package/src/tui/components/InteractiveTable.tsx +0 -106
- package/src/tui/components/StepSpinner.tsx +0 -84
- package/src/tui/components/Toast.tsx +0 -59
- package/src/tui/index.tsx +0 -90
- package/src/tui/useChat.ts +0 -103
- package/src/tui/useCommand.ts +0 -238
- package/src/tui/useNotifications.ts +0 -28
- package/src/tui/useScroll.ts +0 -69
- package/src/ui/banner.ts +0 -78
- package/src/ui/colors.ts +0 -30
- package/src/ui/format.ts +0 -78
- package/src/ui/qr-render.ts +0 -92
- package/src/ui/rpc-fallback.ts +0 -59
- package/src/ui/spinner.ts +0 -56
- package/src/ui/tree.ts +0 -16
- package/src/utils/format.ts +0 -48
- package/src/utils/hash.ts +0 -5
- package/src/utils/time.ts +0 -15
- package/src/wallet-router.ts +0 -178
- package/src/walletconnect-session.ts +0 -27
- package/src/walletconnect.ts +0 -309
- package/test/time.test.js +0 -11
- package/tsconfig.json +0 -33
package/TUI-SPEC.md
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
# ARC-402 TUI Specification — Ink-based Terminal UI
|
|
2
|
-
|
|
3
|
-
**Date:** 2026-03-22
|
|
4
|
-
**Status:** Ready for implementation
|
|
5
|
-
**Pattern:** Fixed header/footer with scrollable viewport (split-pane TUI)
|
|
6
|
-
**Library:** Ink (React for CLIs) — same architecture as Claude Code
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Architecture
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
┌─────────────────────────────────────────────────┐
|
|
14
|
-
│ HEADER (fixed, 8-10 rows) │
|
|
15
|
-
│ ┌─────────────────────────────────────────────┐ │
|
|
16
|
-
│ │ ██████╗ ██████╗ ██████╗ ... │ │
|
|
17
|
-
│ │ agent-to-agent arcing · v0.7.3 │ │
|
|
18
|
-
│ │ ◈ ──────────────────────────────────────── │ │
|
|
19
|
-
│ │ Network Base Mainnet Wallet 0xA34B.. │ │
|
|
20
|
-
│ └─────────────────────────────────────────────┘ │
|
|
21
|
-
├─────────────────────────────────────────────────┤
|
|
22
|
-
│ VIEWPORT (scrollable, fills remaining space) │
|
|
23
|
-
│ │
|
|
24
|
-
│ ◈ arc402 > wallet status │
|
|
25
|
-
│ ├ Address 0xA34B...a5dc │
|
|
26
|
-
│ ├ ETH 0.002 ETH │
|
|
27
|
-
│ └ Trust 100 Restricted │
|
|
28
|
-
│ │
|
|
29
|
-
│ ◈ arc402 > shake send --to 0xa9e0... │
|
|
30
|
-
│ ◈ Submitting handshake... │
|
|
31
|
-
│ ✓ Handshake sent — tx 0xabc1... │
|
|
32
|
-
│ │
|
|
33
|
-
│ ◈ arc402 > doctor │
|
|
34
|
-
│ ├ Config ✓ │
|
|
35
|
-
│ ├ RPC ✓ Base Mainnet │
|
|
36
|
-
│ └ Daemon ✗ Not running │
|
|
37
|
-
│ │
|
|
38
|
-
├─────────────────────────────────────────────────┤
|
|
39
|
-
│ FOOTER (fixed, 1-2 rows) │
|
|
40
|
-
│ ◈ arc402 > _ │
|
|
41
|
-
└─────────────────────────────────────────────────┘
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Component Tree (Ink/React)
|
|
47
|
-
|
|
48
|
-
```tsx
|
|
49
|
-
<App>
|
|
50
|
-
<Box flexDirection="column" height="100%">
|
|
51
|
-
|
|
52
|
-
{/* HEADER — fixed height, never scrolls */}
|
|
53
|
-
<Header
|
|
54
|
-
version={version}
|
|
55
|
-
network={config.network}
|
|
56
|
-
wallet={config.walletContractAddress}
|
|
57
|
-
balance={balance}
|
|
58
|
-
/>
|
|
59
|
-
|
|
60
|
-
<Box borderStyle="single" borderTop borderBottom={false} borderLeft={false} borderRight={false}>
|
|
61
|
-
<Text dimColor>─</Text>
|
|
62
|
-
</Box>
|
|
63
|
-
|
|
64
|
-
{/* VIEWPORT — flexGrow, scrollable */}
|
|
65
|
-
<Viewport
|
|
66
|
-
lines={outputBuffer}
|
|
67
|
-
scrollOffset={scrollOffset}
|
|
68
|
-
/>
|
|
69
|
-
|
|
70
|
-
{/* FOOTER — fixed height, input pinned */}
|
|
71
|
-
<Footer>
|
|
72
|
-
<InputLine
|
|
73
|
-
value={inputValue}
|
|
74
|
-
onChange={setInputValue}
|
|
75
|
-
onSubmit={handleCommand}
|
|
76
|
-
history={history}
|
|
77
|
-
/>
|
|
78
|
-
</Footer>
|
|
79
|
-
|
|
80
|
-
</Box>
|
|
81
|
-
</App>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Components
|
|
87
|
-
|
|
88
|
-
### `<Header />`
|
|
89
|
-
- Renders the ASCII art banner (cyan)
|
|
90
|
-
- Version from package.json
|
|
91
|
-
- Network, wallet (truncated), balance
|
|
92
|
-
- Fixed height: exactly `bannerLines.length + 3` rows
|
|
93
|
-
- Never re-renders unless config changes
|
|
94
|
-
|
|
95
|
-
### `<Viewport />`
|
|
96
|
-
- `flexGrow: 1` — fills all remaining terminal rows
|
|
97
|
-
- Maintains an internal `outputBuffer: string[]`
|
|
98
|
-
- Renders a window slice: `buffer.slice(scrollOffset, scrollOffset + viewportHeight)`
|
|
99
|
-
- Scroll up/down with Page Up/Page Down or mouse wheel
|
|
100
|
-
- Auto-scrolls to bottom when new output arrives (unless user scrolled up)
|
|
101
|
-
- Supports ANSI colors in output lines (chalk passes through)
|
|
102
|
-
|
|
103
|
-
### `<Footer />`
|
|
104
|
-
- Fixed height: 1 row (or 2 with status bar)
|
|
105
|
-
- Contains `<InputLine />`
|
|
106
|
-
- Prompt: `◈ arc402 > ` (◈ cyan, arc402 dim, > white)
|
|
107
|
-
|
|
108
|
-
### `<InputLine />`
|
|
109
|
-
- Uses `ink-text-input` for text input with cursor
|
|
110
|
-
- Up/down arrow: command history navigation
|
|
111
|
-
- Tab: command completion
|
|
112
|
-
- Enter: dispatch command
|
|
113
|
-
- Ctrl+C: graceful exit
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## Behavior
|
|
118
|
-
|
|
119
|
-
### Command Dispatch
|
|
120
|
-
1. User types command + Enter
|
|
121
|
-
2. Command + output appended to `outputBuffer` as: `◈ arc402 > {command}` then output lines
|
|
122
|
-
3. Commander parses and executes (stdout/stderr captured and routed to viewport)
|
|
123
|
-
4. Viewport auto-scrolls to bottom
|
|
124
|
-
5. Input line clears, cursor returns
|
|
125
|
-
|
|
126
|
-
### Stdout/Stderr Capture
|
|
127
|
-
- During command execution, monkey-patch `process.stdout.write` and `process.stderr.write`
|
|
128
|
-
- Route all output to `outputBuffer` instead of raw terminal
|
|
129
|
-
- Restore after command completes
|
|
130
|
-
- This ensures spinners, tree output, console.log all render in the viewport
|
|
131
|
-
|
|
132
|
-
### Scroll Behavior
|
|
133
|
-
- **Auto-scroll:** viewport stays at bottom as new lines arrive
|
|
134
|
-
- **Manual scroll:** Page Up / Page Down moves viewport
|
|
135
|
-
- **Scroll indicator:** if not at bottom, show `↓ more` in bottom-right
|
|
136
|
-
- **Return to bottom:** any new command output snaps back to bottom
|
|
137
|
-
|
|
138
|
-
### Chat Integration
|
|
139
|
-
- Non-command input detected → POST to OpenClaw gateway
|
|
140
|
-
- Response streamed line-by-line into viewport
|
|
141
|
-
- Prefixed with `◈ ` in dim
|
|
142
|
-
|
|
143
|
-
### Resize Handling
|
|
144
|
-
- Listen for `SIGWINCH`
|
|
145
|
-
- Recalculate viewport height
|
|
146
|
-
- Re-render (Ink handles this natively)
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## Dependencies
|
|
151
|
-
|
|
152
|
-
```json
|
|
153
|
-
{
|
|
154
|
-
"ink": "^4.0.0",
|
|
155
|
-
"ink-text-input": "^5.0.0",
|
|
156
|
-
"react": "^18.0.0"
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
~150KB total. Well-maintained. Same stack as Claude Code.
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## File Structure
|
|
165
|
-
|
|
166
|
-
```
|
|
167
|
-
cli/src/
|
|
168
|
-
tui/
|
|
169
|
-
App.tsx — root component
|
|
170
|
-
Header.tsx — banner + status
|
|
171
|
-
Viewport.tsx — scrollable output area
|
|
172
|
-
Footer.tsx — input line wrapper
|
|
173
|
-
InputLine.tsx — text input with history + completion
|
|
174
|
-
useCommand.ts — hook: dispatch to commander, capture output
|
|
175
|
-
useChat.ts — hook: OpenClaw gateway chat
|
|
176
|
-
useScroll.ts — hook: scroll state management
|
|
177
|
-
index.tsx — render <App /> with Ink
|
|
178
|
-
repl.ts — KEEP as fallback for --print mode and non-TTY
|
|
179
|
-
index.ts — route: TTY → tui/, non-TTY/--print → repl.ts
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## Migration Plan
|
|
185
|
-
|
|
186
|
-
1. Keep existing `repl.ts` as fallback (--print mode, piped input)
|
|
187
|
-
2. New `tui/` directory with Ink components
|
|
188
|
-
3. `index.ts` checks: if TTY and no --print → launch Ink TUI, else → use simple REPL
|
|
189
|
-
4. All existing commands unchanged — only the rendering layer changes
|
|
190
|
-
5. `repl.ts` simplified back to basic readline (no ANSI tricks)
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## Exit Behavior
|
|
195
|
-
|
|
196
|
-
- Ctrl+C → `\x1b[?1049l` (leave alternate screen) → show goodbye → exit
|
|
197
|
-
- All terminal state restored on exit (cursor visible, normal scroll, etc.)
|
|
198
|
-
- Alternate screen means the TUI disappears on exit, revealing the original terminal — clean
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
## What This Does NOT Change
|
|
203
|
-
|
|
204
|
-
- Command implementations (wallet.ts, agent.ts, etc.) — untouched
|
|
205
|
-
- Config system — untouched
|
|
206
|
-
- Daemon — untouched
|
|
207
|
-
- SDKs — untouched
|
|
208
|
-
- One-shot mode (`arc402 wallet deploy` without REPL) — untouched
|
|
209
|
-
|
|
210
|
-
Only the interactive shell rendering layer changes.
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
*Build this exactly as specified. The spec is the contract.*
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { ethers } from "ethers";
|
|
2
|
-
import { loadConfig } from "../src/config";
|
|
3
|
-
import { connectPhoneWallet, sendTransactionWithSession } from "../src/walletconnect";
|
|
4
|
-
|
|
5
|
-
const WALLET = "0xC3207bFe22cba39AeC4e8540c97c29B028103c7F";
|
|
6
|
-
const HOT_KEY = "0x747024C2e59C523E3B1621A4b3F92366C1E28A30";
|
|
7
|
-
const CHAIN_ID = 8453;
|
|
8
|
-
|
|
9
|
-
async function main() {
|
|
10
|
-
const config = loadConfig();
|
|
11
|
-
const iface = new ethers.Interface(["function authorizeMachineKey(address key) external"]);
|
|
12
|
-
|
|
13
|
-
const tx = {
|
|
14
|
-
to: WALLET,
|
|
15
|
-
data: iface.encodeFunctionData("authorizeMachineKey", [HOT_KEY]),
|
|
16
|
-
value: "0x0",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const tgOpts = {
|
|
20
|
-
botToken: config.telegramBotToken!,
|
|
21
|
-
chatId: config.telegramChatId!,
|
|
22
|
-
threadId: config.telegramThreadId,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
console.log(`Authorizing hot key ${HOT_KEY} as machine key on ${WALLET}\n`);
|
|
26
|
-
|
|
27
|
-
const { client, session, account } = await connectPhoneWallet(
|
|
28
|
-
config.walletConnectProjectId!,
|
|
29
|
-
CHAIN_ID,
|
|
30
|
-
config,
|
|
31
|
-
{
|
|
32
|
-
telegramOpts: tgOpts,
|
|
33
|
-
prompt: "⛓ BASE — authorizeMachineKey (one-time). After this the hot key runs autonomously.",
|
|
34
|
-
}
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
console.log("Connected:", account);
|
|
38
|
-
const hash = await sendTransactionWithSession(client, session, account, CHAIN_ID, tx);
|
|
39
|
-
console.log("✅ Done:", hash);
|
|
40
|
-
process.exit(0);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
main().catch(e => { console.error(e.message ?? e); process.exit(1); });
|
package/scripts/drain-wallet.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* drain-wallet.ts
|
|
3
|
-
* Drain all ETH from the ARC402Wallet contract to the deployer wallet.
|
|
4
|
-
* Uses WalletConnect — sends MetaMask approval button to Telegram.
|
|
5
|
-
*
|
|
6
|
-
* Flow:
|
|
7
|
-
* 1. Read wallet balance
|
|
8
|
-
* 2. Build openContext + attest + executeSpend calldata
|
|
9
|
-
* 3. Connect via WalletConnect (sends Telegram button)
|
|
10
|
-
* 4. Send all 3 txs sequentially for owner approval
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { ethers } from "ethers";
|
|
14
|
-
import { loadConfig } from "../src/config";
|
|
15
|
-
import { connectPhoneWallet, sendTransactionWithSession } from "../src/walletconnect";
|
|
16
|
-
|
|
17
|
-
const DEPLOYER = "0x59A32A792d0f25B0E0a4A4aFbFDf514b94B102fB";
|
|
18
|
-
const WALLET = "0xC3207bFe22cba39AeC4e8540c97c29B028103c7F";
|
|
19
|
-
const RPC = "https://base-mainnet.g.alchemy.com/v2/YIA2uRCsFI-j5pqH-aRzflrACSlV1Qrs";
|
|
20
|
-
const CHAIN_ID = 8453;
|
|
21
|
-
|
|
22
|
-
const WALLET_ABI = [
|
|
23
|
-
"function openContext(bytes32 contextId, string calldata taskType) external",
|
|
24
|
-
"function closeContext() external",
|
|
25
|
-
"function attest(bytes32 attestationId, string calldata action, string calldata reason, address recipient, uint256 amount, address token, uint256 expiresAt) external returns (bytes32)",
|
|
26
|
-
"function executeSpend(address payable recipient, uint256 amount, string calldata category, bytes32 attestationId) external",
|
|
27
|
-
"function contextOpen() external view returns (bool)",
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
async function main() {
|
|
31
|
-
const config = loadConfig();
|
|
32
|
-
|
|
33
|
-
const balance = await new ethers.JsonRpcProvider(RPC).getBalance(WALLET);
|
|
34
|
-
|
|
35
|
-
if (balance === 0n) {
|
|
36
|
-
console.log("Wallet is already empty.");
|
|
37
|
-
process.exit(0);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Reserve gas for 3 transactions (~300k gas @ ~0.01 gwei = ~0.003 ETH buffer)
|
|
41
|
-
const gasReserve = ethers.parseEther("0.0001");
|
|
42
|
-
const sendAmount = balance - gasReserve;
|
|
43
|
-
|
|
44
|
-
if (sendAmount <= 0n) {
|
|
45
|
-
console.log(`Balance too low to drain safely: ${ethers.formatEther(balance)} ETH`);
|
|
46
|
-
process.exit(0);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
console.log(`\nDraining ${ethers.formatEther(sendAmount)} ETH from wallet contract`);
|
|
50
|
-
console.log(` From: ${WALLET}`);
|
|
51
|
-
console.log(` To: ${DEPLOYER}\n`);
|
|
52
|
-
|
|
53
|
-
const iface = new ethers.Interface(WALLET_ABI);
|
|
54
|
-
|
|
55
|
-
const contextId = ethers.keccak256(ethers.toUtf8Bytes(`drain-${Date.now()}`));
|
|
56
|
-
const attestId = ethers.keccak256(ethers.toUtf8Bytes(`attest-${Date.now()}`));
|
|
57
|
-
const expiresAt = Math.floor(Date.now() / 1000) + 3600; // 1 hour
|
|
58
|
-
|
|
59
|
-
// Close any existing open context first (from prior partial run)
|
|
60
|
-
const provider = new ethers.JsonRpcProvider(RPC);
|
|
61
|
-
const contextOpenRaw = await provider.call({ to: WALLET, data: iface.encodeFunctionData("contextOpen") });
|
|
62
|
-
const contextAlreadyOpen = ethers.AbiCoder.defaultAbiCoder().decode(["bool"], contextOpenRaw)[0];
|
|
63
|
-
|
|
64
|
-
const txCloseContext = contextAlreadyOpen ? {
|
|
65
|
-
to: WALLET,
|
|
66
|
-
data: iface.encodeFunctionData("closeContext"),
|
|
67
|
-
value: "0x0",
|
|
68
|
-
} : null;
|
|
69
|
-
|
|
70
|
-
const txOpenContext = {
|
|
71
|
-
to: WALLET,
|
|
72
|
-
data: iface.encodeFunctionData("openContext", [contextId, "drain"]),
|
|
73
|
-
value: "0x0",
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const txAttest = {
|
|
77
|
-
to: WALLET,
|
|
78
|
-
data: iface.encodeFunctionData("attest", [
|
|
79
|
-
attestId,
|
|
80
|
-
"drain",
|
|
81
|
-
"drain to deployer",
|
|
82
|
-
DEPLOYER,
|
|
83
|
-
sendAmount,
|
|
84
|
-
ethers.ZeroAddress,
|
|
85
|
-
expiresAt,
|
|
86
|
-
]),
|
|
87
|
-
value: "0x0",
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const txSpend = {
|
|
91
|
-
to: WALLET,
|
|
92
|
-
data: iface.encodeFunctionData("executeSpend", [
|
|
93
|
-
DEPLOYER,
|
|
94
|
-
sendAmount,
|
|
95
|
-
"drain",
|
|
96
|
-
attestId,
|
|
97
|
-
]),
|
|
98
|
-
value: "0x0",
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const tgOpts = {
|
|
102
|
-
botToken: config.telegramBotToken!,
|
|
103
|
-
chatId: config.telegramChatId!,
|
|
104
|
-
threadId: config.telegramThreadId,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
console.log("Connecting WalletConnect — fresh session, Base network enforced...\n");
|
|
108
|
-
|
|
109
|
-
const { client, session, account } = await connectPhoneWallet(
|
|
110
|
-
config.walletConnectProjectId!,
|
|
111
|
-
CHAIN_ID,
|
|
112
|
-
config,
|
|
113
|
-
{
|
|
114
|
-
telegramOpts: tgOpts,
|
|
115
|
-
prompt: `⛓ BASE NETWORK ONLY\nApprove drain of ${ethers.formatEther(sendAmount)} ETH → deployer wallet\n\n⚠️ Make sure MetaMask is on BASE before approving`,
|
|
116
|
-
}
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
console.log(`\nConnected: ${account}`);
|
|
120
|
-
|
|
121
|
-
let txCount = 1;
|
|
122
|
-
const total = (txCloseContext ? 4 : 3);
|
|
123
|
-
|
|
124
|
-
if (txCloseContext) {
|
|
125
|
-
console.log(`Sending tx ${txCount++}/${total}: closeContext (cleaning up prior run)...`);
|
|
126
|
-
const hClose = await sendTransactionWithSession(client, session, account, CHAIN_ID, txCloseContext);
|
|
127
|
-
console.log(` ✓ ${hClose}`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
console.log(`Sending tx ${txCount++}/${total}: openContext...`);
|
|
131
|
-
const h1 = await sendTransactionWithSession(client, session, account, CHAIN_ID, txOpenContext);
|
|
132
|
-
console.log(` ✓ ${h1}`);
|
|
133
|
-
|
|
134
|
-
console.log(`Sending tx ${txCount++}/${total}: attest...`);
|
|
135
|
-
const h2 = await sendTransactionWithSession(client, session, account, CHAIN_ID, txAttest);
|
|
136
|
-
console.log(` ✓ ${h2}`);
|
|
137
|
-
|
|
138
|
-
console.log(`Sending tx ${txCount++}/${total}: executeSpend...`);
|
|
139
|
-
const h3 = await sendTransactionWithSession(client, session, account, CHAIN_ID, txSpend);
|
|
140
|
-
console.log(` ✓ ${h3}`);
|
|
141
|
-
|
|
142
|
-
console.log(`\n✅ Done. ${ethers.formatEther(sendAmount)} ETH sent to deployer.`);
|
|
143
|
-
process.exit(0);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
main().catch(e => {
|
|
147
|
-
console.error(e.message ?? e);
|
|
148
|
-
process.exit(1);
|
|
149
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* execute-spend-only.ts
|
|
3
|
-
* Send ONLY the executeSpend tx — context and attest already confirmed on-chain.
|
|
4
|
-
* Uses the attestation ID from the last successful attest tx.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { ethers } from "ethers";
|
|
8
|
-
import { loadConfig } from "../src/config";
|
|
9
|
-
import { connectPhoneWallet, sendTransactionWithSession } from "../src/walletconnect";
|
|
10
|
-
|
|
11
|
-
const DEPLOYER = "0x59A32A792d0f25B0E0a4A4aFbFDf514b94B102fB";
|
|
12
|
-
const WALLET = "0xC3207bFe22cba39AeC4e8540c97c29B028103c7F";
|
|
13
|
-
const RPC = "https://base-mainnet.g.alchemy.com/v2/YIA2uRCsFI-j5pqH-aRzflrACSlV1Qrs";
|
|
14
|
-
const CHAIN_ID = 8453;
|
|
15
|
-
|
|
16
|
-
// Attest tx was: 0x28dbff33aa65b0617c4f25810f06f76bfcf0a430f461b...
|
|
17
|
-
// Recover attestId from the drain script's timestamp-based keccak
|
|
18
|
-
// The attest tx confirmed — we need to recover the attestId used.
|
|
19
|
-
// Re-derive it: the script used `attest-${Date.now()}` at time of that run.
|
|
20
|
-
// Instead, read it from the IntentAttestation contract by checking events.
|
|
21
|
-
|
|
22
|
-
const INTENT_ATTEST_ABI = [
|
|
23
|
-
"event AttestationCreated(bytes32 indexed attestationId, address indexed wallet, address recipient, uint256 amount, address token)",
|
|
24
|
-
"function verify(bytes32 attestationId, address wallet, address recipient, uint256 amount, address token) external view returns (bool)",
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
const WALLET_ABI = [
|
|
28
|
-
"function executeSpend(address payable recipient, uint256 amount, string calldata category, bytes32 attestationId) external",
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const INTENT_ATTEST_ADDR = "0x7ad8db6C5f394542E8e9658F86C85cC99Cf6D460";
|
|
32
|
-
|
|
33
|
-
async function main() {
|
|
34
|
-
const config = loadConfig();
|
|
35
|
-
const provider = new ethers.JsonRpcProvider(RPC);
|
|
36
|
-
|
|
37
|
-
// Find the most recent AttestationCreated event for this wallet → DEPLOYER
|
|
38
|
-
const attestContract = new ethers.Contract(INTENT_ATTEST_ADDR, INTENT_ATTEST_ABI, provider);
|
|
39
|
-
const block = await provider.getBlockNumber();
|
|
40
|
-
// Hardcoded from confirmed attest tx 0x28dbff33...c17
|
|
41
|
-
const attestId = "0x9d8bdb5f551f63e986e5d0c980fd68f4e445b9f7902f71226ec08ce24bceebb0";
|
|
42
|
-
const amount = ethers.parseEther("0.00015");
|
|
43
|
-
|
|
44
|
-
console.log(`Found attestation: ${attestId}`);
|
|
45
|
-
console.log(`Amount: ${ethers.formatEther(amount)} ETH`);
|
|
46
|
-
console.log(`Sending executeSpend → ${DEPLOYER}\n`);
|
|
47
|
-
|
|
48
|
-
const iface = new ethers.Interface(WALLET_ABI);
|
|
49
|
-
const txSpend = {
|
|
50
|
-
to: WALLET,
|
|
51
|
-
data: iface.encodeFunctionData("executeSpend", [DEPLOYER, amount, "drain", attestId]),
|
|
52
|
-
value: "0x0",
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const tgOpts = {
|
|
56
|
-
botToken: config.telegramBotToken!,
|
|
57
|
-
chatId: config.telegramChatId!,
|
|
58
|
-
threadId: config.telegramThreadId,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const { client, session, account } = await connectPhoneWallet(
|
|
62
|
-
config.walletConnectProjectId!,
|
|
63
|
-
CHAIN_ID,
|
|
64
|
-
config,
|
|
65
|
-
{
|
|
66
|
-
telegramOpts: tgOpts,
|
|
67
|
-
prompt: `⛓ BASE ONLY — Final tx: executeSpend ${ethers.formatEther(amount)} ETH → deployer\n\n⚠️ Keep MetaMask on Base and approve`,
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
console.log(`Connected: ${account}`);
|
|
72
|
-
console.log("Sending executeSpend...");
|
|
73
|
-
const hash = await sendTransactionWithSession(client, session, account, CHAIN_ID, txSpend);
|
|
74
|
-
console.log(`\n✅ Done: ${hash}`);
|
|
75
|
-
process.exit(0);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
main().catch(e => {
|
|
79
|
-
console.error(e.message ?? e);
|
|
80
|
-
process.exit(1);
|
|
81
|
-
});
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* register-agent-userop.ts
|
|
3
|
-
* Register GigaBrain in AgentRegistry via ERC-4337 UserOperation.
|
|
4
|
-
* Machine key signs → Pimlico bundler → EntryPoint executes → wallet is msg.sender.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { ethers } from "ethers";
|
|
8
|
-
import { loadConfig } from "../src/config";
|
|
9
|
-
import { BundlerClient, buildUserOp } from "../src/bundler";
|
|
10
|
-
import { ARC402_WALLET_EXECUTE_ABI, AGENT_REGISTRY_ABI } from "../src/abis";
|
|
11
|
-
|
|
12
|
-
const ENTRY_POINT = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
13
|
-
const CHAIN_ID = 8453;
|
|
14
|
-
|
|
15
|
-
// EntryPoint v0.7 nonce getter ABI
|
|
16
|
-
const EP_ABI = [
|
|
17
|
-
"function getNonce(address sender, uint192 key) external view returns (uint256)",
|
|
18
|
-
"function depositTo(address account) external payable",
|
|
19
|
-
"function balanceOf(address account) external view returns (uint256)",
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
async function main() {
|
|
23
|
-
const config = loadConfig();
|
|
24
|
-
if (!config.walletContractAddress) throw new Error("walletContractAddress not in config");
|
|
25
|
-
if (!config.privateKey) throw new Error("privateKey not in config");
|
|
26
|
-
|
|
27
|
-
const provider = new ethers.JsonRpcProvider(config.rpcUrl);
|
|
28
|
-
const machineKey = new ethers.Wallet(config.privateKey, provider);
|
|
29
|
-
const walletAddress = config.walletContractAddress;
|
|
30
|
-
|
|
31
|
-
const agentRegistryAddress =
|
|
32
|
-
config.agentRegistryV2Address ??
|
|
33
|
-
"0xD5c2851B00090c92Ba7F4723FB548bb30C9B6865";
|
|
34
|
-
|
|
35
|
-
console.log("Wallet: ", walletAddress);
|
|
36
|
-
console.log("Machine key: ", machineKey.address);
|
|
37
|
-
console.log("AgentRegistry: ", agentRegistryAddress);
|
|
38
|
-
|
|
39
|
-
// ── 1. Check ETH balance ───────────────────────────────────────────────────
|
|
40
|
-
const balance = await provider.getBalance(walletAddress);
|
|
41
|
-
console.log("Wallet balance: ", ethers.formatEther(balance), "ETH");
|
|
42
|
-
if (balance < ethers.parseEther("0.0005")) {
|
|
43
|
-
throw new Error("Wallet balance too low — need at least 0.0005 ETH");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ── 2. Get nonce from EntryPoint ───────────────────────────────────────────
|
|
47
|
-
const ep = new ethers.Contract(ENTRY_POINT, EP_ABI, provider);
|
|
48
|
-
const nonce: bigint = await ep.getNonce(walletAddress, 0);
|
|
49
|
-
console.log("Nonce: ", nonce.toString());
|
|
50
|
-
|
|
51
|
-
// ── 3. Encode AgentRegistry.register() calldata ───────────────────────────
|
|
52
|
-
const registryIface = new ethers.Interface(AGENT_REGISTRY_ABI);
|
|
53
|
-
const registerCalldata = registryIface.encodeFunctionData("register", [
|
|
54
|
-
"GigaBrain", // name
|
|
55
|
-
[], // capabilities (empty for now)
|
|
56
|
-
"ai.assistant", // serviceType
|
|
57
|
-
"https://gigabrain.arc402.xyz", // endpoint
|
|
58
|
-
"", // metadataURI
|
|
59
|
-
]);
|
|
60
|
-
|
|
61
|
-
// ── 4. Encode ARC402Wallet.executeContractCall() — this is the UserOp callData ──
|
|
62
|
-
const walletIface = new ethers.Interface(ARC402_WALLET_EXECUTE_ABI);
|
|
63
|
-
const userOpCallData = walletIface.encodeFunctionData("executeContractCall", [{
|
|
64
|
-
target: agentRegistryAddress,
|
|
65
|
-
data: registerCalldata,
|
|
66
|
-
value: BigInt(0),
|
|
67
|
-
minReturnValue: BigInt(0),
|
|
68
|
-
maxApprovalAmount: BigInt(0),
|
|
69
|
-
approvalToken: ethers.ZeroAddress,
|
|
70
|
-
}]);
|
|
71
|
-
|
|
72
|
-
console.log("UserOp callData built ✓");
|
|
73
|
-
|
|
74
|
-
// ── 5. Build UserOp — fetch live gas price from Pimlico ───────────────────
|
|
75
|
-
// Declare bundlerUrl here so it's available for gas price fetch AND sending
|
|
76
|
-
const bundlerUrl = (config as unknown as Record<string, unknown>)["bundlerUrl"] as string | undefined ?? "https://public.pimlico.io/v2/8453/rpc";
|
|
77
|
-
const gasPriceRes = await fetch(bundlerUrl, {
|
|
78
|
-
method: "POST",
|
|
79
|
-
headers: { "Content-Type": "application/json" },
|
|
80
|
-
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "pimlico_getUserOperationGasPrice", params: [] }),
|
|
81
|
-
});
|
|
82
|
-
const gasPriceJson = await gasPriceRes.json() as { result?: { fast?: { maxFeePerGas: string; maxPriorityFeePerGas: string } } };
|
|
83
|
-
const fast = gasPriceJson.result?.fast;
|
|
84
|
-
if (!fast) throw new Error("Could not fetch gas price from bundler");
|
|
85
|
-
console.log("Gas price (fast): maxFee=", fast.maxFeePerGas, "maxPriority=", fast.maxPriorityFeePerGas);
|
|
86
|
-
|
|
87
|
-
const userOp = await buildUserOp(userOpCallData, walletAddress, nonce, config);
|
|
88
|
-
// Override with bundler-recommended gas prices
|
|
89
|
-
userOp.maxFeePerGas = fast.maxFeePerGas;
|
|
90
|
-
userOp.maxPriorityFeePerGas = fast.maxPriorityFeePerGas;
|
|
91
|
-
// Bump callGasLimit — executeContractCall + AgentRegistry.register needs ~330k
|
|
92
|
-
userOp.callGasLimit = ethers.toBeHex(500_000);
|
|
93
|
-
userOp.verificationGasLimit = ethers.toBeHex(200_000);
|
|
94
|
-
|
|
95
|
-
// ── 6. Sign UserOp with machine key ───────────────────────────────────────
|
|
96
|
-
// ERC-4337 v0.7: hash = keccak256(abi.encode(userOpHash, entryPoint, chainId))
|
|
97
|
-
// where userOpHash = keccak256(packed(userOp fields))
|
|
98
|
-
const packedFields = ethers.AbiCoder.defaultAbiCoder().encode(
|
|
99
|
-
["address","uint256","bytes32","bytes32","bytes32","uint256","bytes32","bytes32"],
|
|
100
|
-
[
|
|
101
|
-
userOp.sender,
|
|
102
|
-
BigInt(userOp.nonce),
|
|
103
|
-
ethers.keccak256(ethers.concat(
|
|
104
|
-
userOp.factory ? [userOp.factory, userOp.factoryData ?? "0x"] : []
|
|
105
|
-
)),
|
|
106
|
-
ethers.keccak256(userOp.callData),
|
|
107
|
-
ethers.concat([
|
|
108
|
-
ethers.zeroPadValue(ethers.toBeHex(userOp.callGasLimit), 16),
|
|
109
|
-
ethers.zeroPadValue(ethers.toBeHex(userOp.verificationGasLimit), 16),
|
|
110
|
-
]),
|
|
111
|
-
BigInt(userOp.preVerificationGas),
|
|
112
|
-
ethers.concat([
|
|
113
|
-
ethers.zeroPadValue(ethers.toBeHex(userOp.maxPriorityFeePerGas), 16),
|
|
114
|
-
ethers.zeroPadValue(ethers.toBeHex(userOp.maxFeePerGas), 16),
|
|
115
|
-
]),
|
|
116
|
-
ethers.keccak256(
|
|
117
|
-
userOp.paymaster
|
|
118
|
-
? ethers.concat([
|
|
119
|
-
userOp.paymaster,
|
|
120
|
-
ethers.zeroPadValue(ethers.toBeHex(userOp.paymasterVerificationGasLimit ?? "0x0"), 16),
|
|
121
|
-
ethers.zeroPadValue(ethers.toBeHex(userOp.paymasterPostOpGasLimit ?? "0x0"), 16),
|
|
122
|
-
userOp.paymasterData ?? "0x",
|
|
123
|
-
])
|
|
124
|
-
: "0x"
|
|
125
|
-
),
|
|
126
|
-
]
|
|
127
|
-
);
|
|
128
|
-
const userOpHash = ethers.keccak256(
|
|
129
|
-
ethers.AbiCoder.defaultAbiCoder().encode(
|
|
130
|
-
["bytes32","address","uint256"],
|
|
131
|
-
[
|
|
132
|
-
ethers.keccak256(packedFields),
|
|
133
|
-
ENTRY_POINT,
|
|
134
|
-
CHAIN_ID,
|
|
135
|
-
]
|
|
136
|
-
)
|
|
137
|
-
);
|
|
138
|
-
console.log("UserOp hash: ", userOpHash);
|
|
139
|
-
|
|
140
|
-
// validateUserOp uses toEthSignedMessageHash — sign the eth-prefixed hash
|
|
141
|
-
const signature = await machineKey.signMessage(ethers.getBytes(userOpHash));
|
|
142
|
-
userOp.signature = signature;
|
|
143
|
-
console.log("Signed ✓");
|
|
144
|
-
|
|
145
|
-
// ── 7. Send to bundler ─────────────────────────────────────────────────────
|
|
146
|
-
const bundler = new BundlerClient(bundlerUrl, ENTRY_POINT, CHAIN_ID);
|
|
147
|
-
|
|
148
|
-
console.log("Sending UserOperation to bundler...");
|
|
149
|
-
let opHash: string;
|
|
150
|
-
try {
|
|
151
|
-
opHash = await bundler.sendUserOperation(userOp);
|
|
152
|
-
} catch (e) {
|
|
153
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
154
|
-
throw new Error(`Bundler rejected UserOp: ${msg}`);
|
|
155
|
-
}
|
|
156
|
-
console.log("UserOp hash: ", opHash);
|
|
157
|
-
console.log("Waiting for confirmation (up to 60s)...");
|
|
158
|
-
|
|
159
|
-
const receipt = await bundler.getUserOperationReceipt(opHash);
|
|
160
|
-
if (!receipt.success) {
|
|
161
|
-
throw new Error(`UserOp failed on-chain. Tx: ${receipt.receipt.transactionHash}`);
|
|
162
|
-
}
|
|
163
|
-
console.log("✓ AgentRegistry.register() confirmed");
|
|
164
|
-
console.log(" Tx:", receipt.receipt.transactionHash);
|
|
165
|
-
|
|
166
|
-
// ── 8. Claim subdomain ─────────────────────────────────────────────────────
|
|
167
|
-
console.log("\nClaiming gigabrain.arc402.xyz...");
|
|
168
|
-
const res = await fetch("https://api.arc402.xyz/register-subdomain", {
|
|
169
|
-
method: "POST",
|
|
170
|
-
headers: { "Content-Type": "application/json" },
|
|
171
|
-
body: JSON.stringify({
|
|
172
|
-
subdomain: "gigabrain",
|
|
173
|
-
walletAddress,
|
|
174
|
-
tunnelTarget: "https://gigabrain.arc402.xyz",
|
|
175
|
-
}),
|
|
176
|
-
});
|
|
177
|
-
const body = await res.json() as Record<string, unknown>;
|
|
178
|
-
if (!res.ok) {
|
|
179
|
-
console.error("✗ Subdomain claim failed:", body["error"] ?? body);
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
console.log("✓ Subdomain claimed:", body["subdomain"]);
|
|
183
|
-
console.log("\nAll done. GigaBrain is registered and live.");
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
main().catch(e => { console.error(e); process.exit(1); });
|