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/src/commands/watch.ts
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { ethers } from "ethers";
|
|
3
|
-
import { loadConfig } from "../config.js";
|
|
4
|
-
import { getClient } from "../client.js";
|
|
5
|
-
import { c } from "../ui/colors.js";
|
|
6
|
-
|
|
7
|
-
// ─── Minimal ABIs for event watching ─────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
const AGENT_REGISTRY_WATCH_ABI = [
|
|
10
|
-
"event AgentRegistered(address indexed wallet, string name, string serviceType, uint256 timestamp)",
|
|
11
|
-
"event AgentUpdated(address indexed wallet, string name, string serviceType)",
|
|
12
|
-
"event AgentDeactivated(address indexed wallet)",
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const SERVICE_AGREEMENT_WATCH_ABI = [
|
|
16
|
-
"event AgreementProposed(uint256 indexed id, address indexed client, address indexed provider, string serviceType, uint256 price, address token, uint256 deadline)",
|
|
17
|
-
"event AgreementAccepted(uint256 indexed id, address indexed provider)",
|
|
18
|
-
"event AgreementFulfilled(uint256 indexed id, address indexed provider, bytes32 deliverablesHash)",
|
|
19
|
-
"event AgreementDisputed(uint256 indexed id, address indexed initiator, string reason)",
|
|
20
|
-
"event AgreementCancelled(uint256 indexed id, address indexed client)",
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
const HANDSHAKE_WATCH_ABI = [
|
|
24
|
-
"event HandshakeSent(uint256 indexed handshakeId, address indexed from, address indexed to, uint8 hsType, address token, uint256 amount, string note, uint256 timestamp)",
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
const DISPUTE_MODULE_WATCH_ABI = [
|
|
28
|
-
"event DisputeRaised(uint256 indexed agreementId, address indexed initiator, string reason)",
|
|
29
|
-
"event DisputeResolved(uint256 indexed agreementId, bool favorProvider, string resolution)",
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const HS_TYPE_LABELS: Record<number, string> = {
|
|
33
|
-
0: "Respected",
|
|
34
|
-
1: "Curious",
|
|
35
|
-
2: "Endorsed",
|
|
36
|
-
3: "Thanked",
|
|
37
|
-
4: "Collaborated",
|
|
38
|
-
5: "Challenged",
|
|
39
|
-
6: "Referred",
|
|
40
|
-
7: "Hello",
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
function shortAddr(addr: string): string {
|
|
44
|
-
return addr.length > 10 ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : addr;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function nowHHMM(): string {
|
|
48
|
-
const d = new Date();
|
|
49
|
-
const h = d.getHours().toString().padStart(2, "0");
|
|
50
|
-
const m = d.getMinutes().toString().padStart(2, "0");
|
|
51
|
-
return `${h}:${m}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function printEvent(label: string, detail: string, status?: "ok" | "warn" | "err"): void {
|
|
55
|
-
const ts = c.dim(`[${nowHHMM()}]`);
|
|
56
|
-
const col = status === "ok" ? c.green : status === "err" ? c.red : status === "warn" ? c.yellow : c.white;
|
|
57
|
-
process.stdout.write(` ${ts} ${col(label)} ${c.dim(detail)}\n`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function registerWatchCommand(program: Command): void {
|
|
61
|
-
program
|
|
62
|
-
.command("watch")
|
|
63
|
-
.description("Watch wallet activity in real-time (live onchain event feed)")
|
|
64
|
-
.action(async () => {
|
|
65
|
-
const config = loadConfig();
|
|
66
|
-
const { provider } = await getClient(config);
|
|
67
|
-
const myWallet = (config.walletContractAddress ?? "").toLowerCase();
|
|
68
|
-
const shortMe = myWallet ? shortAddr(config.walletContractAddress!) : "(no wallet)";
|
|
69
|
-
|
|
70
|
-
const line = "─".repeat(22);
|
|
71
|
-
console.log(`\n ${c.mark} ${c.white("ARC-402 Live Feed")} ${c.dim(line)}`);
|
|
72
|
-
console.log(` ${c.dim("Watching")} ${c.brightCyan(shortMe)} ${c.dim("on")} ${c.dim(config.network)}`);
|
|
73
|
-
console.log(` ${c.dim("Ctrl+C to exit")}\n`);
|
|
74
|
-
|
|
75
|
-
// ── Build contract instances ───────────────────────────────────────────
|
|
76
|
-
|
|
77
|
-
const contractLabels: string[] = [];
|
|
78
|
-
|
|
79
|
-
if (config.agentRegistryAddress) contractLabels.push("AgentRegistry");
|
|
80
|
-
if (config.serviceAgreementAddress) contractLabels.push("ServiceAgreement");
|
|
81
|
-
if (config.handshakeAddress) contractLabels.push("Handshake");
|
|
82
|
-
if (config.disputeModuleAddress) contractLabels.push("DisputeModule");
|
|
83
|
-
|
|
84
|
-
if (contractLabels.length === 0) {
|
|
85
|
-
console.log(` ${c.warning} No contract addresses configured. Run arc402 config init.`);
|
|
86
|
-
process.exit(1);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
console.log(` ${c.dim(`Monitoring ${contractLabels.length} contract${contractLabels.length !== 1 ? "s" : ""}: ${contractLabels.join(", ")}`)}\n`);
|
|
90
|
-
|
|
91
|
-
// ── Helpers ────────────────────────────────────────────────────────────
|
|
92
|
-
|
|
93
|
-
function isMe(addr: string): boolean {
|
|
94
|
-
return myWallet !== "" && addr.toLowerCase() === myWallet;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function fmtAddr(addr: string): string {
|
|
98
|
-
return isMe(addr) ? c.brightCyan("you") : c.dim(shortAddr(addr));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// ── AgentRegistry ──────────────────────────────────────────────────────
|
|
102
|
-
|
|
103
|
-
if (config.agentRegistryAddress) {
|
|
104
|
-
const reg = new ethers.Contract(config.agentRegistryAddress, AGENT_REGISTRY_WATCH_ABI, provider);
|
|
105
|
-
|
|
106
|
-
reg.on("AgentRegistered", (wallet: string, name: string, serviceType: string) => {
|
|
107
|
-
printEvent(`Agent registered: ${name}`, `${fmtAddr(wallet)} ${c.dim(serviceType)}`, "ok");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
reg.on("AgentUpdated", (wallet: string, name: string, serviceType: string) => {
|
|
111
|
-
printEvent(`Agent updated: ${name}`, `${fmtAddr(wallet)} ${c.dim(serviceType)}`);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
reg.on("AgentDeactivated", (wallet: string) => {
|
|
115
|
-
printEvent(`Agent deactivated`, fmtAddr(wallet), "warn");
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ── ServiceAgreement ───────────────────────────────────────────────────
|
|
120
|
-
|
|
121
|
-
if (config.serviceAgreementAddress) {
|
|
122
|
-
const sa = new ethers.Contract(config.serviceAgreementAddress, SERVICE_AGREEMENT_WATCH_ABI, provider);
|
|
123
|
-
|
|
124
|
-
sa.on("AgreementProposed", (id: bigint, client: string, agentProvider: string, serviceType: string) => {
|
|
125
|
-
const involved = isMe(client) || isMe(agentProvider);
|
|
126
|
-
printEvent(
|
|
127
|
-
`Agreement #${id} proposed`,
|
|
128
|
-
`${fmtAddr(client)} → ${fmtAddr(agentProvider)} ${c.dim(serviceType)}`,
|
|
129
|
-
involved ? "ok" : undefined
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
sa.on("AgreementAccepted", (id: bigint, agentProvider: string) => {
|
|
134
|
-
printEvent(`Agreement #${id} → ${c.green("ACCEPTED")}`, fmtAddr(agentProvider));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
sa.on("AgreementFulfilled", (id: bigint, agentProvider: string, deliverablesHash: string) => {
|
|
138
|
-
printEvent(
|
|
139
|
-
`Agreement #${id} → ${c.green("DELIVERED")}`,
|
|
140
|
-
`${fmtAddr(agentProvider)} ${c.dim(deliverablesHash.slice(0, 10) + "...")}`,
|
|
141
|
-
"ok"
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
sa.on("AgreementDisputed", (id: bigint, initiator: string, reason: string) => {
|
|
146
|
-
printEvent(
|
|
147
|
-
`Agreement #${id} → ${c.red("DISPUTED")}`,
|
|
148
|
-
`${fmtAddr(initiator)} ${c.dim(reason.slice(0, 40))}`,
|
|
149
|
-
"err"
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
sa.on("AgreementCancelled", (id: bigint, client: string) => {
|
|
154
|
-
printEvent(`Agreement #${id} → ${c.yellow("CANCELLED")}`, fmtAddr(client), "warn");
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// ── Handshake ──────────────────────────────────────────────────────────
|
|
159
|
-
|
|
160
|
-
if (config.handshakeAddress) {
|
|
161
|
-
const hs = new ethers.Contract(config.handshakeAddress, HANDSHAKE_WATCH_ABI, provider);
|
|
162
|
-
|
|
163
|
-
hs.on("HandshakeSent", (_id: bigint, from: string, to: string, hsType: number, _token: string, _amount: bigint, note: string) => {
|
|
164
|
-
const typeLabel = HS_TYPE_LABELS[hsType] ?? `type ${hsType}`;
|
|
165
|
-
const toMe = isMe(to);
|
|
166
|
-
const noteStr = note ? ` ${c.dim(`(${note.slice(0, 30)})`)}` : "";
|
|
167
|
-
printEvent(
|
|
168
|
-
`Handshake from ${fmtAddr(from)} → ${fmtAddr(to)}`,
|
|
169
|
-
`${c.dim(typeLabel)}${noteStr}`,
|
|
170
|
-
toMe ? "ok" : undefined
|
|
171
|
-
);
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// ── DisputeModule ──────────────────────────────────────────────────────
|
|
176
|
-
|
|
177
|
-
if (config.disputeModuleAddress) {
|
|
178
|
-
const dm = new ethers.Contract(config.disputeModuleAddress, DISPUTE_MODULE_WATCH_ABI, provider);
|
|
179
|
-
|
|
180
|
-
dm.on("DisputeRaised", (agreementId: bigint, initiator: string, reason: string) => {
|
|
181
|
-
printEvent(
|
|
182
|
-
`Dispute raised on #${agreementId}`,
|
|
183
|
-
`${fmtAddr(initiator)} ${c.dim(reason.slice(0, 40))}`,
|
|
184
|
-
"err"
|
|
185
|
-
);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
dm.on("DisputeResolved", (agreementId: bigint, favorProvider: boolean, resolution: string) => {
|
|
189
|
-
printEvent(
|
|
190
|
-
`Dispute #${agreementId} → ${c.green("RESOLVED")}`,
|
|
191
|
-
`${c.dim(favorProvider ? "provider wins" : "client wins")} ${c.dim(resolution.slice(0, 30))}`,
|
|
192
|
-
"ok"
|
|
193
|
-
);
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// ── Block heartbeat (shows feed is alive) ──────────────────────────────
|
|
198
|
-
|
|
199
|
-
let lastBlock = 0;
|
|
200
|
-
provider.on("block", (blockNumber: number) => {
|
|
201
|
-
if (blockNumber > lastBlock) {
|
|
202
|
-
lastBlock = blockNumber;
|
|
203
|
-
if (blockNumber % 10 === 0) {
|
|
204
|
-
process.stdout.write(` ${c.dim(`· block ${blockNumber}`)}\n`);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// ── Clean exit ─────────────────────────────────────────────────────────
|
|
210
|
-
|
|
211
|
-
process.on("SIGINT", () => {
|
|
212
|
-
console.log(`\n ${c.dim("Feed stopped.")}`);
|
|
213
|
-
provider.removeAllListeners();
|
|
214
|
-
process.exit(0);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// Keep process alive
|
|
218
|
-
process.stdin.resume();
|
|
219
|
-
});
|
|
220
|
-
}
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import * as fs from "fs";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import * as os from "os";
|
|
5
|
-
import { loadConfig } from "../config.js";
|
|
6
|
-
import { requireSigner, getClient } from "../client.js";
|
|
7
|
-
import { WatchtowerClient, ChannelClient } from "@arc402/sdk";
|
|
8
|
-
import { c } from '../ui/colors.js';
|
|
9
|
-
import { startSpinner } from '../ui/spinner.js';
|
|
10
|
-
import { renderTree } from '../ui/tree.js';
|
|
11
|
-
import { formatAddress } from '../ui/format.js';
|
|
12
|
-
|
|
13
|
-
const CHANNEL_STATES_DIR = path.join(os.homedir(), ".arc402", "channel-states");
|
|
14
|
-
|
|
15
|
-
function loadStateFile(filePath: string): { [key: string]: unknown; cumulativePayment: bigint; sequenceNumber: number } {
|
|
16
|
-
const raw = fs.readFileSync(filePath, "utf-8");
|
|
17
|
-
const obj = JSON.parse(raw) as Record<string, unknown>;
|
|
18
|
-
return {
|
|
19
|
-
...obj,
|
|
20
|
-
cumulativePayment: BigInt(obj.cumulativePayment as string),
|
|
21
|
-
sequenceNumber: Number(obj.sequenceNumber),
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function registerWatchtowerCommands(program: Command): void {
|
|
26
|
-
const wt = program
|
|
27
|
-
.command("watchtower")
|
|
28
|
-
.description("Watchtower management — register, status, and monitor channels for bad-faith closes");
|
|
29
|
-
|
|
30
|
-
// ─── register ──────────────────────────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
wt.command("register")
|
|
33
|
-
.description("Register this node as a watchtower in the on-chain WatchtowerRegistry")
|
|
34
|
-
.requiredOption("--name <name>", "Watchtower display name")
|
|
35
|
-
.option("--description <desc>", "Short description", "ARC-402 watchtower node")
|
|
36
|
-
.option("--capabilities <caps>", "Comma-separated capability tags", "challenge")
|
|
37
|
-
.option("--json", "JSON output")
|
|
38
|
-
.action(async (opts) => {
|
|
39
|
-
const config = loadConfig();
|
|
40
|
-
if (!config.watchtowerRegistryAddress) throw new Error("watchtowerRegistryAddress missing in config");
|
|
41
|
-
if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
|
|
42
|
-
const { signer } = await requireSigner(config);
|
|
43
|
-
const client = new WatchtowerClient(
|
|
44
|
-
config.watchtowerRegistryAddress,
|
|
45
|
-
config.serviceAgreementAddress,
|
|
46
|
-
signer
|
|
47
|
-
);
|
|
48
|
-
const capabilities = opts.capabilities
|
|
49
|
-
.split(",")
|
|
50
|
-
.map((s: string) => s.trim())
|
|
51
|
-
.filter(Boolean);
|
|
52
|
-
const regSpinner = startSpinner('Registering watchtower…');
|
|
53
|
-
const result = await client.registerWatchtower({
|
|
54
|
-
name: opts.name,
|
|
55
|
-
description: opts.description,
|
|
56
|
-
capabilities,
|
|
57
|
-
});
|
|
58
|
-
if (opts.json || program.opts().json) {
|
|
59
|
-
regSpinner.stop();
|
|
60
|
-
console.log(JSON.stringify(result));
|
|
61
|
-
} else {
|
|
62
|
-
regSpinner.succeed(c.success + c.white(' Registered as watchtower'));
|
|
63
|
-
renderTree([
|
|
64
|
-
{ label: 'Name', value: opts.name },
|
|
65
|
-
{ label: 'Tx', value: result.txHash, last: true },
|
|
66
|
-
]);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// ─── status ────────────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
wt.command("status [address]")
|
|
73
|
-
.description("Check watchtower registration status (defaults to your own address)")
|
|
74
|
-
.option("--json", "JSON output")
|
|
75
|
-
.action(async (address, opts) => {
|
|
76
|
-
const config = loadConfig();
|
|
77
|
-
if (!config.watchtowerRegistryAddress) throw new Error("watchtowerRegistryAddress missing in config");
|
|
78
|
-
if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
|
|
79
|
-
const { provider, address: myAddress } = await getClient(config);
|
|
80
|
-
const client = new WatchtowerClient(
|
|
81
|
-
config.watchtowerRegistryAddress,
|
|
82
|
-
config.serviceAgreementAddress,
|
|
83
|
-
provider
|
|
84
|
-
);
|
|
85
|
-
const target = address ?? myAddress;
|
|
86
|
-
if (!target) {
|
|
87
|
-
console.error("No address provided and no private key configured");
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
const status = await client.getWatchtowerStatus(target);
|
|
91
|
-
if (opts.json || program.opts().json) {
|
|
92
|
-
console.log(JSON.stringify(status, null, 2));
|
|
93
|
-
} else {
|
|
94
|
-
console.log('\n ' + c.mark + c.white(' Watchtower — ' + formatAddress(status.addr)));
|
|
95
|
-
const statusItems: { label: string; value: string; last?: boolean }[] = [
|
|
96
|
-
{ label: 'Name', value: status.name },
|
|
97
|
-
{ label: 'Description', value: status.description },
|
|
98
|
-
{ label: 'Capabilities', value: status.capabilities.join(', ') || '(none)' },
|
|
99
|
-
{ label: 'Active', value: String(status.active) },
|
|
100
|
-
];
|
|
101
|
-
if (status.registeredAt) {
|
|
102
|
-
statusItems.push({ label: 'Registered', value: new Date(status.registeredAt * 1000).toISOString(), last: true });
|
|
103
|
-
} else {
|
|
104
|
-
statusItems[statusItems.length - 1].last = true;
|
|
105
|
-
}
|
|
106
|
-
renderTree(statusItems);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// ─── watch ─────────────────────────────────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
wt.command("watch <channelId>")
|
|
113
|
-
.description("Monitor a session channel for bad-faith closes and auto-submit a challenge")
|
|
114
|
-
.option(
|
|
115
|
-
"--state <path>",
|
|
116
|
-
"Path to latest signed state JSON (defaults to ~/.arc402/channel-states/<channelId>.json)"
|
|
117
|
-
)
|
|
118
|
-
.option("--interval <ms>", "Polling interval in milliseconds", "12000")
|
|
119
|
-
.option("--json", "JSON output")
|
|
120
|
-
.action(async (channelId, opts) => {
|
|
121
|
-
const config = loadConfig();
|
|
122
|
-
if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
|
|
123
|
-
if (!config.watchtowerRegistryAddress) throw new Error("watchtowerRegistryAddress missing in config");
|
|
124
|
-
const { signer, address } = await requireSigner(config);
|
|
125
|
-
|
|
126
|
-
const watchtowerClient = new WatchtowerClient(
|
|
127
|
-
config.watchtowerRegistryAddress,
|
|
128
|
-
config.serviceAgreementAddress,
|
|
129
|
-
signer
|
|
130
|
-
);
|
|
131
|
-
const channelClient = new ChannelClient(config.serviceAgreementAddress, signer);
|
|
132
|
-
|
|
133
|
-
const statePath = opts.state ?? path.join(CHANNEL_STATES_DIR, `${channelId}.json`);
|
|
134
|
-
if (!fs.existsSync(statePath)) {
|
|
135
|
-
console.error(`No state file at ${statePath}`);
|
|
136
|
-
console.error(`Store state first: arc402 channel store-state ${channelId} <state.json>`);
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
const state = loadStateFile(statePath);
|
|
140
|
-
const interval = Math.max(1000, Number(opts.interval));
|
|
141
|
-
|
|
142
|
-
if (!opts.json) {
|
|
143
|
-
console.log(`watching: ${channelId}`);
|
|
144
|
-
console.log(` stored seq: ${state.sequenceNumber}`);
|
|
145
|
-
console.log(` poll interval: ${interval}ms`);
|
|
146
|
-
console.log(` press Ctrl+C to stop`);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
let challenged = false;
|
|
150
|
-
|
|
151
|
-
const poll = async () => {
|
|
152
|
-
if (challenged) return;
|
|
153
|
-
try {
|
|
154
|
-
const ch = await channelClient.getChannelStatus(channelId);
|
|
155
|
-
|
|
156
|
-
if (ch.status === "SETTLED") {
|
|
157
|
-
if (!opts.json) {
|
|
158
|
-
console.log(`[${new Date().toISOString()}] channel settled — stopping watch`);
|
|
159
|
-
}
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (ch.status === "CLOSING" || ch.status === "CHALLENGED") {
|
|
164
|
-
if (ch.lastSequenceNumber < (state.sequenceNumber as number)) {
|
|
165
|
-
if (!opts.json) {
|
|
166
|
-
console.log(
|
|
167
|
-
`[${new Date().toISOString()}] stale close detected ` +
|
|
168
|
-
`(on-chain seq=${ch.lastSequenceNumber}, stored seq=${state.sequenceNumber}) — challenging...`
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
-
const result = await watchtowerClient.submitChallenge(channelId, state as any, address);
|
|
173
|
-
challenged = true;
|
|
174
|
-
if (opts.json) {
|
|
175
|
-
console.log(JSON.stringify({ event: "challenge_submitted", channelId, txHash: result.txHash }));
|
|
176
|
-
} else {
|
|
177
|
-
console.log(' ' + c.success + c.white(' Challenge submitted — tx ' + result.txHash.slice(0, 12) + '...'));
|
|
178
|
-
}
|
|
179
|
-
return;
|
|
180
|
-
} else {
|
|
181
|
-
if (!opts.json) {
|
|
182
|
-
console.log(
|
|
183
|
-
`[${new Date().toISOString()}] channel closing with seq=${ch.lastSequenceNumber} — no challenge needed`
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
} catch (err) {
|
|
189
|
-
if (!opts.json) {
|
|
190
|
-
console.error(`[${new Date().toISOString()}] poll error: ${err}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
setTimeout(poll, interval);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
poll();
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// ─── authorize ─────────────────────────────────────────────────────────────
|
|
200
|
-
|
|
201
|
-
wt.command("authorize <channelId> <watchtower>")
|
|
202
|
-
.description("Authorize a watchtower address to challenge on your behalf for a channel")
|
|
203
|
-
.option("--json", "JSON output")
|
|
204
|
-
.action(async (channelId, watchtower, opts) => {
|
|
205
|
-
const config = loadConfig();
|
|
206
|
-
if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
|
|
207
|
-
if (!config.watchtowerRegistryAddress) throw new Error("watchtowerRegistryAddress missing in config");
|
|
208
|
-
const { signer } = await requireSigner(config);
|
|
209
|
-
const client = new WatchtowerClient(
|
|
210
|
-
config.watchtowerRegistryAddress,
|
|
211
|
-
config.serviceAgreementAddress,
|
|
212
|
-
signer
|
|
213
|
-
);
|
|
214
|
-
const authSpinner = startSpinner('Authorizing watchtower…');
|
|
215
|
-
const result = await client.authorizeWatchtower(channelId, watchtower);
|
|
216
|
-
if (opts.json || program.opts().json) {
|
|
217
|
-
authSpinner.stop();
|
|
218
|
-
console.log(JSON.stringify(result));
|
|
219
|
-
} else {
|
|
220
|
-
authSpinner.succeed(c.success + c.white(' Authorized: ' + formatAddress(watchtower)));
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
// ─── revoke ────────────────────────────────────────────────────────────────
|
|
225
|
-
|
|
226
|
-
wt.command("revoke <channelId> <watchtower>")
|
|
227
|
-
.description("Revoke a watchtower's authorization for a channel")
|
|
228
|
-
.option("--json", "JSON output")
|
|
229
|
-
.action(async (channelId, watchtower, opts) => {
|
|
230
|
-
const config = loadConfig();
|
|
231
|
-
if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
|
|
232
|
-
if (!config.watchtowerRegistryAddress) throw new Error("watchtowerRegistryAddress missing in config");
|
|
233
|
-
const { signer } = await requireSigner(config);
|
|
234
|
-
const client = new WatchtowerClient(
|
|
235
|
-
config.watchtowerRegistryAddress,
|
|
236
|
-
config.serviceAgreementAddress,
|
|
237
|
-
signer
|
|
238
|
-
);
|
|
239
|
-
const revokeSpinner = startSpinner('Revoking watchtower…');
|
|
240
|
-
const result = await client.revokeWatchtower(channelId, watchtower);
|
|
241
|
-
if (opts.json || program.opts().json) {
|
|
242
|
-
revokeSpinner.stop();
|
|
243
|
-
console.log(JSON.stringify(result));
|
|
244
|
-
} else {
|
|
245
|
-
revokeSpinner.succeed(c.success + c.white(' Revoked: ' + formatAddress(watchtower)));
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
}
|