@absol-labs/agent 0.11.0 → 0.12.0-rc.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 +42 -50
- package/dist/capability/invocation-capability.d.ts +2 -2
- package/dist/capability/probe-capability.d.ts +225 -0
- package/dist/capability/probe-capability.d.ts.map +1 -0
- package/dist/capability/probe-capability.js +248 -0
- package/dist/capability/probe-capability.js.map +1 -0
- package/dist/cli/args.d.ts +11 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +23 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/claim.js +1 -1
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts.map +1 -1
- package/dist/cli/commands/close.js +35 -3
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/invoke.d.ts +2 -0
- package/dist/cli/commands/invoke.d.ts.map +1 -1
- package/dist/cli/commands/invoke.js +2 -2
- package/dist/cli/commands/invoke.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +15 -2
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/open.d.ts.map +1 -1
- package/dist/cli/commands/open.js +58 -4
- package/dist/cli/commands/open.js.map +1 -1
- package/dist/cli/commands/pay.d.ts +19 -0
- package/dist/cli/commands/pay.d.ts.map +1 -0
- package/dist/cli/commands/pay.js +355 -0
- package/dist/cli/commands/pay.js.map +1 -0
- package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
- package/dist/cli/commands/reclaim-unverified.js +3 -2
- package/dist/cli/commands/reclaim-unverified.js.map +1 -1
- package/dist/cli/commands/reclaim.d.ts +23 -2
- package/dist/cli/commands/reclaim.d.ts.map +1 -1
- package/dist/cli/commands/reclaim.js +184 -16
- package/dist/cli/commands/reclaim.js.map +1 -1
- package/dist/cli/commands/refund.d.ts +13 -0
- package/dist/cli/commands/refund.d.ts.map +1 -0
- package/dist/cli/commands/refund.js +224 -0
- package/dist/cli/commands/refund.js.map +1 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +10 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/streams.js +8 -12
- package/dist/cli/commands/streams.js.map +1 -1
- package/dist/cli/commands/watch.d.ts.map +1 -1
- package/dist/cli/commands/watch.js +2 -1
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/cli/config.d.ts +44 -26
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +88 -38
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/deps.d.ts +33 -0
- package/dist/cli/deps.d.ts.map +1 -1
- package/dist/cli/deps.js +37 -1
- package/dist/cli/deps.js.map +1 -1
- package/dist/cli/errors.d.ts.map +1 -1
- package/dist/cli/errors.js +21 -1
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/escape-hatch.d.ts +6 -4
- package/dist/cli/escape-hatch.d.ts.map +1 -1
- package/dist/cli/escape-hatch.js +6 -2
- package/dist/cli/escape-hatch.js.map +1 -1
- package/dist/cli/listings.d.ts +18 -0
- package/dist/cli/listings.d.ts.map +1 -1
- package/dist/cli/listings.js +22 -12
- package/dist/cli/listings.js.map +1 -1
- package/dist/cli/preflight.d.ts +20 -14
- package/dist/cli/preflight.d.ts.map +1 -1
- package/dist/cli/preflight.js +34 -20
- package/dist/cli/preflight.js.map +1 -1
- package/dist/cli/privy.d.ts.map +1 -1
- package/dist/cli/privy.js +4 -2
- package/dist/cli/privy.js.map +1 -1
- package/dist/cli/reclaimability.d.ts +82 -0
- package/dist/cli/reclaimability.d.ts.map +1 -0
- package/dist/cli/reclaimability.js +80 -0
- package/dist/cli/reclaimability.js.map +1 -0
- package/dist/cli/run.d.ts +2 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +40 -11
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/scan-range.d.ts +2 -2
- package/dist/cli/scan-range.js +2 -2
- package/dist/cli/status.d.ts +3 -1
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +15 -3
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/wallet.d.ts +1 -1
- package/dist/cli/wallet.js +2 -2
- package/dist/cli/wallet.js.map +1 -1
- package/dist/discovery/rate-band.d.ts +74 -0
- package/dist/discovery/rate-band.d.ts.map +1 -0
- package/dist/discovery/rate-band.js +114 -0
- package/dist/discovery/rate-band.js.map +1 -0
- package/dist/escrow-generation.d.ts +81 -0
- package/dist/escrow-generation.d.ts.map +1 -0
- package/dist/escrow-generation.js +76 -0
- package/dist/escrow-generation.js.map +1 -0
- package/dist/frameworks/agentkit.d.ts +8 -4
- package/dist/frameworks/agentkit.d.ts.map +1 -1
- package/dist/frameworks/agentkit.js +27 -10
- package/dist/frameworks/agentkit.js.map +1 -1
- package/dist/frameworks/eliza.d.ts +3 -3
- package/dist/frameworks/eliza.d.ts.map +1 -1
- package/dist/frameworks/eliza.js +15 -6
- package/dist/frameworks/eliza.js.map +1 -1
- package/dist/frameworks/langchain.d.ts.map +1 -1
- package/dist/frameworks/langchain.js +8 -0
- package/dist/frameworks/langchain.js.map +1 -1
- package/dist/gateway/caller-auth-gateway.d.ts +83 -31
- package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
- package/dist/gateway/caller-auth-gateway.js +180 -27
- package/dist/gateway/caller-auth-gateway.js.map +1 -1
- package/dist/gateway/http-server.d.ts +111 -44
- package/dist/gateway/http-server.d.ts.map +1 -1
- package/dist/gateway/http-server.js +439 -155
- package/dist/gateway/http-server.js.map +1 -1
- package/dist/gateway/probe-auth.d.ts +112 -0
- package/dist/gateway/probe-auth.d.ts.map +1 -0
- package/dist/gateway/probe-auth.js +127 -0
- package/dist/gateway/probe-auth.js.map +1 -0
- package/dist/gateway/signed-rate-bounds.d.ts +51 -0
- package/dist/gateway/signed-rate-bounds.d.ts.map +1 -0
- package/dist/gateway/signed-rate-bounds.js +94 -0
- package/dist/gateway/signed-rate-bounds.js.map +1 -0
- package/dist/gateway/x402-opener-mode.d.ts +215 -0
- package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
- package/dist/gateway/x402-opener-mode.js +639 -0
- package/dist/gateway/x402-opener-mode.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +52 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +228 -37
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/x402-tools.d.ts +104 -0
- package/dist/mcp/x402-tools.d.ts.map +1 -0
- package/dist/mcp/x402-tools.js +434 -0
- package/dist/mcp/x402-tools.js.map +1 -0
- package/dist/network.d.ts +119 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +199 -0
- package/dist/network.js.map +1 -0
- package/dist/sdk/invoke.d.ts +4 -0
- package/dist/sdk/invoke.d.ts.map +1 -1
- package/dist/sdk/invoke.js +2 -5
- package/dist/sdk/invoke.js.map +1 -1
- package/dist/wallet/autonomous-wallet-broker.d.ts +3 -0
- package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet-broker.js +27 -23
- package/dist/wallet/autonomous-wallet-broker.js.map +1 -1
- package/dist/wallet/autonomous-wallet-protocol.d.ts +8 -2
- package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet-protocol.js +9 -2
- package/dist/wallet/autonomous-wallet-protocol.js.map +1 -1
- package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet.js +3 -2
- package/dist/wallet/autonomous-wallet.js.map +1 -1
- package/dist/wallet/broker-escrows.d.ts +222 -0
- package/dist/wallet/broker-escrows.d.ts.map +1 -0
- package/dist/wallet/broker-escrows.js +36 -0
- package/dist/wallet/broker-escrows.js.map +1 -0
- package/dist/wallet/lifecycle.d.ts +21 -5
- package/dist/wallet/lifecycle.d.ts.map +1 -1
- package/dist/wallet/lifecycle.js +32 -12
- package/dist/wallet/lifecycle.js.map +1 -1
- package/dist/wallet/privy-broker-server.d.ts.map +1 -1
- package/dist/wallet/privy-broker-server.js +31 -26
- package/dist/wallet/privy-broker-server.js.map +1 -1
- package/dist/wallet/privy-session-broker.d.ts +14 -5
- package/dist/wallet/privy-session-broker.d.ts.map +1 -1
- package/dist/wallet/privy-session-broker.js +29 -17
- package/dist/wallet/privy-session-broker.js.map +1 -1
- package/dist/wallet/privy-session-provider.d.ts +3 -1
- package/dist/wallet/privy-session-provider.d.ts.map +1 -1
- package/dist/wallet/privy-session-provider.js +5 -3
- package/dist/wallet/privy-session-provider.js.map +1 -1
- package/dist/wallet/provider.d.ts.map +1 -1
- package/dist/wallet/provider.js +15 -8
- package/dist/wallet/provider.js.map +1 -1
- package/dist/x402/facilitator.d.ts +3 -30
- package/dist/x402/facilitator.d.ts.map +1 -1
- package/dist/x402/facilitator.js +0 -27
- package/dist/x402/facilitator.js.map +1 -1
- package/dist/x402-buyer/guarded-fetch.d.ts +51 -0
- package/dist/x402-buyer/guarded-fetch.d.ts.map +1 -0
- package/dist/x402-buyer/guarded-fetch.js +147 -0
- package/dist/x402-buyer/guarded-fetch.js.map +1 -0
- package/dist/x402-buyer/index.d.ts +10 -0
- package/dist/x402-buyer/index.d.ts.map +1 -0
- package/dist/x402-buyer/index.js +10 -0
- package/dist/x402-buyer/index.js.map +1 -0
- package/dist/x402-buyer/pay.d.ts +135 -0
- package/dist/x402-buyer/pay.d.ts.map +1 -0
- package/dist/x402-buyer/pay.js +336 -0
- package/dist/x402-buyer/pay.js.map +1 -0
- package/dist/x402-opener/abi.d.ts +684 -0
- package/dist/x402-opener/abi.d.ts.map +1 -0
- package/dist/x402-opener/abi.js +880 -0
- package/dist/x402-opener/abi.js.map +1 -0
- package/dist/x402-opener/facilitator-entry.d.ts +3 -0
- package/dist/x402-opener/facilitator-entry.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-entry.js +37 -0
- package/dist/x402-opener/facilitator-entry.js.map +1 -0
- package/dist/x402-opener/facilitator-server.d.ts +180 -0
- package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-server.js +696 -0
- package/dist/x402-opener/facilitator-server.js.map +1 -0
- package/dist/x402-opener/index.d.ts +14 -0
- package/dist/x402-opener/index.d.ts.map +1 -0
- package/dist/x402-opener/index.js +14 -0
- package/dist/x402-opener/index.js.map +1 -0
- package/dist/x402-opener/listing-resolver.d.ts +55 -0
- package/dist/x402-opener/listing-resolver.d.ts.map +1 -0
- package/dist/x402-opener/listing-resolver.js +125 -0
- package/dist/x402-opener/listing-resolver.js.map +1 -0
- package/dist/x402-opener/refund-relay.d.ts +240 -0
- package/dist/x402-opener/refund-relay.d.ts.map +1 -0
- package/dist/x402-opener/refund-relay.js +1240 -0
- package/dist/x402-opener/refund-relay.js.map +1 -0
- package/dist/x402-opener/relayer-queue.d.ts +14 -0
- package/dist/x402-opener/relayer-queue.d.ts.map +1 -0
- package/dist/x402-opener/relayer-queue.js +18 -0
- package/dist/x402-opener/relayer-queue.js.map +1 -0
- package/dist/x402-opener/scheme.d.ts +217 -0
- package/dist/x402-opener/scheme.d.ts.map +1 -0
- package/dist/x402-opener/scheme.js +749 -0
- package/dist/x402-opener/scheme.js.map +1 -0
- package/dist/x402-opener/terms.d.ts +105 -0
- package/dist/x402-opener/terms.d.ts.map +1 -0
- package/dist/x402-opener/terms.js +212 -0
- package/dist/x402-opener/terms.js.map +1 -0
- package/dist/zktls/reclaim.d.ts +2 -2
- package/dist/zktls/t2-delivery-proof.d.ts +6 -6
- package/docs/agent-layer.md +3 -2
- package/docs/autonomous-privy-wallet.md +188 -0
- package/docs/cli.md +184 -31
- package/docs/langchain.md +5 -0
- package/docs/mcp-reference.md +75 -5
- package/docs/probe-capability.md +191 -0
- package/docs/quickstart.md +36 -1
- package/docs/threat-model.md +20 -0
- package/docs/x402.md +628 -595
- package/package.json +19 -17
- package/src/capability/probe-capability.ts +355 -0
- package/src/cli/args.ts +29 -0
- package/src/cli/commands/claim.ts +1 -1
- package/src/cli/commands/close.ts +36 -3
- package/src/cli/commands/invoke.ts +5 -2
- package/src/cli/commands/mcp.ts +18 -2
- package/src/cli/commands/open.ts +75 -4
- package/src/cli/commands/pay.ts +442 -0
- package/src/cli/commands/reclaim-unverified.ts +8 -2
- package/src/cli/commands/reclaim.ts +252 -14
- package/src/cli/commands/refund.ts +277 -0
- package/src/cli/commands/status.ts +17 -1
- package/src/cli/commands/streams.ts +10 -14
- package/src/cli/commands/watch.ts +7 -1
- package/src/cli/config.ts +139 -52
- package/src/cli/deps.ts +74 -1
- package/src/cli/errors.ts +24 -1
- package/src/cli/escape-hatch.ts +19 -5
- package/src/cli/listings.ts +43 -10
- package/src/cli/preflight.ts +36 -21
- package/src/cli/privy.ts +4 -2
- package/src/cli/reclaimability.ts +154 -0
- package/src/cli/run.ts +54 -11
- package/src/cli/scan-range.ts +2 -2
- package/src/cli/status.ts +14 -1
- package/src/cli/wallet.ts +2 -2
- package/src/discovery/rate-band.ts +172 -0
- package/src/escrow-generation.ts +135 -0
- package/src/frameworks/agentkit.ts +45 -11
- package/src/frameworks/eliza.ts +27 -5
- package/src/frameworks/langchain.ts +14 -0
- package/src/gateway/caller-auth-gateway.ts +320 -68
- package/src/gateway/http-server.ts +629 -220
- package/src/gateway/probe-auth.ts +191 -0
- package/src/gateway/signed-rate-bounds.ts +164 -0
- package/src/gateway/x402-opener-mode.ts +974 -0
- package/src/index.ts +82 -19
- package/src/mcp/server.ts +319 -42
- package/src/mcp/x402-tools.ts +621 -0
- package/src/network.ts +302 -0
- package/src/sdk/invoke.ts +6 -5
- package/src/wallet/autonomous-wallet-broker.ts +46 -20
- package/src/wallet/autonomous-wallet-protocol.ts +11 -2
- package/src/wallet/autonomous-wallet.ts +4 -2
- package/src/wallet/broker-escrows.ts +66 -0
- package/src/wallet/lifecycle.ts +53 -18
- package/src/wallet/privy-broker-server.ts +35 -25
- package/src/wallet/privy-session-broker.ts +58 -25
- package/src/wallet/privy-session-provider.ts +7 -3
- package/src/wallet/provider.ts +20 -15
- package/src/x402/facilitator.ts +3 -43
- package/src/x402-buyer/guarded-fetch.ts +213 -0
- package/src/x402-buyer/index.ts +9 -0
- package/src/x402-buyer/pay.ts +517 -0
- package/src/x402-opener/abi.ts +881 -0
- package/src/x402-opener/facilitator-entry.ts +45 -0
- package/src/x402-opener/facilitator-server.ts +1014 -0
- package/src/x402-opener/index.ts +13 -0
- package/src/x402-opener/listing-resolver.ts +202 -0
- package/src/x402-opener/refund-relay.ts +1743 -0
- package/src/x402-opener/relayer-queue.ts +18 -0
- package/src/x402-opener/scheme.ts +1133 -0
- package/src/x402-opener/terms.ts +300 -0
- package/dist/gateway/x402-mode.d.ts +0 -123
- package/dist/gateway/x402-mode.d.ts.map +0 -1
- package/dist/gateway/x402-mode.js +0 -212
- package/dist/gateway/x402-mode.js.map +0 -1
- package/dist/x402/delivery-oracle.d.ts +0 -108
- package/dist/x402/delivery-oracle.d.ts.map +0 -1
- package/dist/x402/delivery-oracle.js +0 -174
- package/dist/x402/delivery-oracle.js.map +0 -1
- package/dist/x402/facilitator-server-entry.d.ts +0 -3
- package/dist/x402/facilitator-server-entry.d.ts.map +0 -1
- package/dist/x402/facilitator-server-entry.js +0 -27
- package/dist/x402/facilitator-server-entry.js.map +0 -1
- package/dist/x402/facilitator-server.d.ts +0 -73
- package/dist/x402/facilitator-server.d.ts.map +0 -1
- package/dist/x402/facilitator-server.js +0 -305
- package/dist/x402/facilitator-server.js.map +0 -1
- package/dist/x402/payment-requirements.d.ts +0 -106
- package/dist/x402/payment-requirements.d.ts.map +0 -1
- package/dist/x402/payment-requirements.js +0 -138
- package/dist/x402/payment-requirements.js.map +0 -1
- package/dist/x402/relayer.d.ts +0 -41
- package/dist/x402/relayer.d.ts.map +0 -1
- package/dist/x402/relayer.js +0 -64
- package/dist/x402/relayer.js.map +0 -1
- package/dist/x402/resource-index.d.ts +0 -75
- package/dist/x402/resource-index.d.ts.map +0 -1
- package/dist/x402/resource-index.js +0 -126
- package/dist/x402/resource-index.js.map +0 -1
- package/dist/x402/verified-delivery-facilitator.d.ts +0 -285
- package/dist/x402/verified-delivery-facilitator.d.ts.map +0 -1
- package/dist/x402/verified-delivery-facilitator.js +0 -423
- package/dist/x402/verified-delivery-facilitator.js.map +0 -1
- package/src/gateway/x402-mode.ts +0 -350
- package/src/x402/delivery-oracle.ts +0 -285
- package/src/x402/facilitator-server-entry.ts +0 -35
- package/src/x402/facilitator-server.ts +0 -445
- package/src/x402/payment-requirements.ts +0 -231
- package/src/x402/relayer.ts +0 -122
- package/src/x402/resource-index.ts +0 -228
- package/src/x402/verified-delivery-facilitator.ts +0 -744
package/src/cli/listings.ts
CHANGED
|
@@ -18,6 +18,30 @@ export async function resolveListing(
|
|
|
18
18
|
serviceRef: `0x${string}`,
|
|
19
19
|
options: { readonly required: boolean },
|
|
20
20
|
): Promise<ServiceListing | null> {
|
|
21
|
+
return (await resolveListingRecord(context, serviceRef, options)).listing;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* What {@link resolveListing} found, including the verified signed record of a
|
|
26
|
+
* matching row even when that row is not usable as a listing (no signed
|
|
27
|
+
* invocation URL) — `open` still has to read the operator-signed rate band off
|
|
28
|
+
* it — and whether the registry was unreachable (the only case in which a
|
|
29
|
+
* signed band may exist and be unknown).
|
|
30
|
+
*/
|
|
31
|
+
export interface ListingRecordResolution {
|
|
32
|
+
readonly listing: ServiceListing | null;
|
|
33
|
+
readonly record: {
|
|
34
|
+
readonly serviceRef: string;
|
|
35
|
+
readonly signed: ServiceListing["signed"];
|
|
36
|
+
} | null;
|
|
37
|
+
readonly registryUnreachable: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function resolveListingRecord(
|
|
41
|
+
context: CommandContext,
|
|
42
|
+
serviceRef: `0x${string}`,
|
|
43
|
+
options: { readonly required: boolean },
|
|
44
|
+
): Promise<ListingRecordResolution> {
|
|
21
45
|
const { config, out, deps } = context;
|
|
22
46
|
let services;
|
|
23
47
|
try {
|
|
@@ -32,7 +56,7 @@ export async function resolveListing(
|
|
|
32
56
|
out.note(
|
|
33
57
|
`warning: the registry at ${config.registryUrl} is unreachable; continuing without a verified listing.`,
|
|
34
58
|
);
|
|
35
|
-
return null;
|
|
59
|
+
return { listing: null, record: null, registryUnreachable: true };
|
|
36
60
|
}
|
|
37
61
|
throw new CliError(
|
|
38
62
|
`the service registry at ${config.registryUrl} could not be read`,
|
|
@@ -45,7 +69,9 @@ export async function resolveListing(
|
|
|
45
69
|
(service) => service.serviceRef.toLowerCase() === wanted,
|
|
46
70
|
);
|
|
47
71
|
if (match === undefined) {
|
|
48
|
-
if (!options.required)
|
|
72
|
+
if (!options.required) {
|
|
73
|
+
return { listing: null, record: null, registryUnreachable: false };
|
|
74
|
+
}
|
|
49
75
|
throw new CliError(
|
|
50
76
|
`no verified listing in the registry matches serviceRef ${serviceRef}`,
|
|
51
77
|
{
|
|
@@ -54,8 +80,11 @@ export async function resolveListing(
|
|
|
54
80
|
},
|
|
55
81
|
);
|
|
56
82
|
}
|
|
83
|
+
const record = { serviceRef: match.serviceRef, signed: match.signed };
|
|
57
84
|
if (match.accessUrl === null) {
|
|
58
|
-
if (!options.required)
|
|
85
|
+
if (!options.required) {
|
|
86
|
+
return { listing: null, record, registryUnreachable: false };
|
|
87
|
+
}
|
|
59
88
|
throw new CliError(
|
|
60
89
|
`listing ${serviceRef} carries no signed invocation URL`,
|
|
61
90
|
{
|
|
@@ -66,12 +95,16 @@ export async function resolveListing(
|
|
|
66
95
|
}
|
|
67
96
|
|
|
68
97
|
return {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
98
|
+
listing: {
|
|
99
|
+
serviceRef: match.serviceRef,
|
|
100
|
+
operator: match.operator,
|
|
101
|
+
publicUrl: match.publicUrl,
|
|
102
|
+
access: match.access,
|
|
103
|
+
accessUrl: match.accessUrl,
|
|
104
|
+
signed: match.signed,
|
|
105
|
+
category: match.category,
|
|
106
|
+
},
|
|
107
|
+
record,
|
|
108
|
+
registryUnreachable: false,
|
|
76
109
|
};
|
|
77
110
|
}
|
package/src/cli/preflight.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
+
import type { MetrikNetwork } from "@absol-labs/sdk";
|
|
2
|
+
|
|
3
|
+
import { gasFundingHint, usdcFundingHint } from "../network.js";
|
|
1
4
|
import { formatUsdc } from "./amounts.js";
|
|
2
5
|
import { CliError } from "./errors.js";
|
|
3
6
|
import type { CliReadClient } from "./deps.js";
|
|
4
7
|
|
|
5
|
-
/** Where a Base Sepolia test wallet gets its gas. */
|
|
6
|
-
export const BASE_SEPOLIA_FAUCET_URL =
|
|
7
|
-
"https://www.alchemy.com/faucets/base-sepolia";
|
|
8
|
-
|
|
9
|
-
/** Where a Base Sepolia test wallet gets the USDC it escrows. */
|
|
10
|
-
export const CIRCLE_USDC_FAUCET_URL = "https://faucet.circle.com";
|
|
11
|
-
|
|
12
8
|
/**
|
|
13
9
|
* Refuse to broadcast from a wallet that cannot pay for gas.
|
|
14
10
|
*
|
|
@@ -16,20 +12,29 @@ export const CIRCLE_USDC_FAUCET_URL = "https://faucet.circle.com";
|
|
|
16
12
|
* phrasing — `USDC approve transaction failed: Execution reverted with reason:
|
|
17
13
|
* gas required exceeds allowance (0)` — which reads like a USDC allowance
|
|
18
14
|
* problem and sends the reader looking at approvals. The actual fact is "this
|
|
19
|
-
* address holds no
|
|
15
|
+
* address holds no gas", and it is knowable with one read before anything is
|
|
20
16
|
* signed.
|
|
21
17
|
*
|
|
18
|
+
* The gas token is read from the network's registry metadata, never assumed to
|
|
19
|
+
* be ETH. Where gas IS the settlement token (`gasToken.isSettlementToken`),
|
|
20
|
+
* there is only one balance: the USDC balance is the gas balance, so that is
|
|
21
|
+
* the one read.
|
|
22
|
+
*
|
|
22
23
|
* Deliberately only a ZERO check, not an estimate: predicting the gas a hire
|
|
23
|
-
* will cost means simulating it, and a wallet with a little
|
|
24
|
+
* will cost means simulating it, and a wallet with a little gas that still runs
|
|
24
25
|
* short should get the real revert rather than a guess from this CLI.
|
|
25
26
|
*/
|
|
26
27
|
export async function assertCanPayGas(
|
|
27
28
|
read: CliReadClient,
|
|
28
29
|
address: `0x${string}`,
|
|
30
|
+
network: MetrikNetwork,
|
|
29
31
|
): Promise<void> {
|
|
32
|
+
const gasIsUsdc = network.gasToken.isSettlementToken;
|
|
30
33
|
let balance: bigint;
|
|
31
34
|
try {
|
|
32
|
-
balance =
|
|
35
|
+
balance = gasIsUsdc
|
|
36
|
+
? await read.usdcBalance(address)
|
|
37
|
+
: await read.nativeBalance(address);
|
|
33
38
|
} catch {
|
|
34
39
|
// A balance read is a courtesy, not a gate. If the RPC will not answer it,
|
|
35
40
|
// let the command proceed and fail with the real error.
|
|
@@ -38,10 +43,12 @@ export async function assertCanPayGas(
|
|
|
38
43
|
if (balance > 0n) return;
|
|
39
44
|
|
|
40
45
|
throw new CliError(
|
|
41
|
-
`wallet ${address} has 0
|
|
46
|
+
`wallet ${address} has 0 ${network.gasToken.symbol} on ${network.name}, so it cannot pay for gas`,
|
|
42
47
|
{
|
|
43
48
|
exitCode: 3,
|
|
44
|
-
hint:
|
|
49
|
+
hint: gasIsUsdc
|
|
50
|
+
? `${gasFundingHint(network)}, then re-run. (On ${network.name} gas is paid in USDC, the same balance a stream is escrowed from.)`
|
|
51
|
+
: `${gasFundingHint(network)}, then re-run. (Gas is ${network.gasToken.symbol}; the stream itself is escrowed in USDC, which is a separate balance.)`,
|
|
45
52
|
},
|
|
46
53
|
);
|
|
47
54
|
}
|
|
@@ -49,12 +56,16 @@ export async function assertCanPayGas(
|
|
|
49
56
|
/**
|
|
50
57
|
* Refuse to broadcast a hire the wallet cannot fund.
|
|
51
58
|
*
|
|
52
|
-
* The sibling of `assertCanPayGas`, for the OTHER balance.
|
|
53
|
-
*
|
|
54
|
-
* that passes the gas check can still hold no USDC at all.
|
|
55
|
-
* `open` path sends the USDC approval FIRST — which succeeds,
|
|
56
|
-
* an amount you do not hold is legal — and then reverts
|
|
57
|
-
* having already spent gas to learn something that was
|
|
59
|
+
* The sibling of `assertCanPayGas`, for the OTHER balance. On a network whose
|
|
60
|
+
* gas token is not USDC, gas and deposit are separate balances on separate
|
|
61
|
+
* tokens, so a wallet that passes the gas check can still hold no USDC at all.
|
|
62
|
+
* Without this the `open` path sends the USDC approval FIRST — which succeeds,
|
|
63
|
+
* because approving an amount you do not hold is legal — and then reverts
|
|
64
|
+
* inside `transferFrom`, having already spent gas to learn something that was
|
|
65
|
+
* one `balanceOf` away.
|
|
66
|
+
*
|
|
67
|
+
* Where gas IS USDC there is one balance, and it must cover the deposit AND
|
|
68
|
+
* leave something for gas, so the check is strict (`balance > budget`).
|
|
58
69
|
*
|
|
59
70
|
* Deliberately NOT an allowance check. The CLI's own open path grants the
|
|
60
71
|
* bounded approval it needs (`approveTxHash` in the result), so a missing
|
|
@@ -66,7 +77,9 @@ export async function assertCanFundStream(
|
|
|
66
77
|
read: CliReadClient,
|
|
67
78
|
address: `0x${string}`,
|
|
68
79
|
budgetUsdc: bigint,
|
|
80
|
+
network: MetrikNetwork,
|
|
69
81
|
): Promise<void> {
|
|
82
|
+
const gasIsUsdc = network.gasToken.isSettlementToken;
|
|
70
83
|
let balance: bigint;
|
|
71
84
|
try {
|
|
72
85
|
balance = await read.usdcBalance(address);
|
|
@@ -76,13 +89,15 @@ export async function assertCanFundStream(
|
|
|
76
89
|
// the real error surface.
|
|
77
90
|
return;
|
|
78
91
|
}
|
|
79
|
-
if (balance >= budgetUsdc) return;
|
|
92
|
+
if (gasIsUsdc ? balance > budgetUsdc : balance >= budgetUsdc) return;
|
|
80
93
|
|
|
81
94
|
throw new CliError(
|
|
82
|
-
`wallet ${address} holds ${formatUsdc(balance)} but --budget is ${formatUsdc(budgetUsdc)}`,
|
|
95
|
+
`wallet ${address} holds ${formatUsdc(balance)} but --budget is ${formatUsdc(budgetUsdc)}${gasIsUsdc ? " (plus gas, which is also USDC here)" : ""}`,
|
|
83
96
|
{
|
|
84
97
|
exitCode: 3,
|
|
85
|
-
hint:
|
|
98
|
+
hint: gasIsUsdc
|
|
99
|
+
? `the deposit and the gas are both USDC on ${network.name} — ${usdcFundingHint(network)}, then re-run.`
|
|
100
|
+
: `the deposit is escrowed in USDC — ${usdcFundingHint(network)}, then re-run. (Gas is a separate ${network.gasToken.symbol} balance.)`,
|
|
86
101
|
},
|
|
87
102
|
);
|
|
88
103
|
}
|
package/src/cli/privy.ts
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
type AutonomousWalletRecord,
|
|
19
19
|
} from "../wallet/autonomous-wallet.js";
|
|
20
20
|
import { createPrivySessionProvider } from "../wallet/privy-session-provider.js";
|
|
21
|
+
import { PRIVY_BROKER_CHAIN_ID } from "../wallet/privy-session-broker.js";
|
|
22
|
+
import { defaultNetwork } from "../network.js";
|
|
21
23
|
import {
|
|
22
24
|
createPrivyEmbeddedAccount,
|
|
23
25
|
type PrivyEip1193Provider,
|
|
@@ -357,12 +359,12 @@ async function embeddedAccount(
|
|
|
357
359
|
appId,
|
|
358
360
|
address,
|
|
359
361
|
provider,
|
|
360
|
-
chainId:
|
|
362
|
+
chainId: PRIVY_BROKER_CHAIN_ID,
|
|
361
363
|
});
|
|
362
364
|
} catch (error) {
|
|
363
365
|
throw configError(
|
|
364
366
|
`the Privy wallet could not be prepared: ${describe(error)}`,
|
|
365
|
-
`check ${PRIVY_ENV_VARS.join(", ")}. Metrik Privy wallets are
|
|
367
|
+
`check ${PRIVY_ENV_VARS.join(", ")}. Metrik Privy wallets are on the broker's network only (${defaultNetwork().name}, chain ${PRIVY_BROKER_CHAIN_ID}).`,
|
|
366
368
|
);
|
|
367
369
|
}
|
|
368
370
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { StreamV2 } from "@absol-labs/sdk";
|
|
2
|
+
|
|
3
|
+
import { formatDuration } from "./amounts.js";
|
|
4
|
+
import { formatTimestamp, readChainNow } from "./escape-hatch.js";
|
|
5
|
+
import { settlementCoverage } from "./status.js";
|
|
6
|
+
import type { CliReadClient } from "./deps.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Why a proof-based reclaim cannot go through right now, read from chain state
|
|
10
|
+
* rather than decoded out of a revert.
|
|
11
|
+
*
|
|
12
|
+
* `metrik reclaim` used to learn this only by sending the simulation and
|
|
13
|
+
* reading what came back. That works exactly as well as the endpoint's revert
|
|
14
|
+
* data does, and on the public Base Sepolia RPC it frequently does not work at
|
|
15
|
+
* all: an already-reclaimed stream, a stream that is still running, and a
|
|
16
|
+
* stream whose stop time is not checkpointed yet ALL came back as
|
|
17
|
+
*
|
|
18
|
+
* reclaim simulation failed: Execution reverted for an unknown reason.
|
|
19
|
+
*
|
|
20
|
+
* Three different situations, three completely different next actions — you
|
|
21
|
+
* already have the money / close it first / wait ~20 seconds — and one message
|
|
22
|
+
* that distinguishes none of them. Worse, the retry loop keys off the same
|
|
23
|
+
* undecoded revert, so the wait that this command advertises never engaged.
|
|
24
|
+
*
|
|
25
|
+
* Every one of these conditions is a pure function of state the CLI already
|
|
26
|
+
* reads elsewhere (`getStreamV2`, `latestCheckpointCheckedAt`, the chain clock,
|
|
27
|
+
* and {@link settlementCoverage}, which `metrik status` has always used to
|
|
28
|
+
* decide the same question). So the condition is named from that state, before
|
|
29
|
+
* a transaction is built, the way `reclaim-unverified` has always named
|
|
30
|
+
* "already reclaimed". No revert data required.
|
|
31
|
+
*/
|
|
32
|
+
export type ReclaimBlocker =
|
|
33
|
+
/** `AlreadyReclaimed()` / `NothingToReclaim()`: the money is already back. */
|
|
34
|
+
| { readonly kind: "reclaimed" }
|
|
35
|
+
/** `StreamNotReclaimable()`: neither closed nor expired, so the clock runs. */
|
|
36
|
+
| {
|
|
37
|
+
readonly kind: "running";
|
|
38
|
+
readonly expiresAt: number;
|
|
39
|
+
readonly secondsRemaining: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `SettlementWindowOpen()`: the stream has stopped but no checkpoint reaches
|
|
43
|
+
* its stop time yet. The ONLY one of the three that is a wait rather than a
|
|
44
|
+
* refusal — the oracle publishes roughly every 15-22s.
|
|
45
|
+
*/
|
|
46
|
+
| {
|
|
47
|
+
readonly kind: "awaiting-checkpoint";
|
|
48
|
+
readonly stopAt: number;
|
|
49
|
+
readonly coveredUpTo: number | null;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The blocker implied by this state, or `null` when nothing in the state blocks
|
|
54
|
+
* a reclaim. Pure, so every branch is testable without an RPC — the same reason
|
|
55
|
+
* {@link settlementCoverage} is.
|
|
56
|
+
*
|
|
57
|
+
* Order matters and follows the escrow: a reclaimed stream is terminal, a
|
|
58
|
+
* running stream cannot be reclaimed at any settlement state, and only then
|
|
59
|
+
* does checkpoint coverage decide.
|
|
60
|
+
*/
|
|
61
|
+
export function classifyReclaimBlocker(
|
|
62
|
+
stream: Pick<StreamV2, "status" | "closedAt" | "expiresAt" | "reclaimed">,
|
|
63
|
+
latestCheckpointCheckedAt: number | null,
|
|
64
|
+
nowSeconds: number,
|
|
65
|
+
): ReclaimBlocker | null {
|
|
66
|
+
if (stream.reclaimed) return { kind: "reclaimed" };
|
|
67
|
+
if (stream.status !== "closed" && nowSeconds < stream.expiresAt) {
|
|
68
|
+
return {
|
|
69
|
+
kind: "running",
|
|
70
|
+
expiresAt: stream.expiresAt,
|
|
71
|
+
secondsRemaining: stream.expiresAt - nowSeconds,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const coverage = settlementCoverage(
|
|
75
|
+
stream,
|
|
76
|
+
latestCheckpointCheckedAt,
|
|
77
|
+
nowSeconds,
|
|
78
|
+
);
|
|
79
|
+
if (coverage.pending && coverage.stopAt !== null) {
|
|
80
|
+
return {
|
|
81
|
+
kind: "awaiting-checkpoint",
|
|
82
|
+
stopAt: coverage.stopAt,
|
|
83
|
+
coveredUpTo: coverage.coveredUpTo,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Read the state the classifier needs and name the blocker.
|
|
91
|
+
*
|
|
92
|
+
* **Fails open.** A read that does not answer returns `null` — "nothing known
|
|
93
|
+
* to block this" — never a refusal. Refusing to return a buyer's money because
|
|
94
|
+
* a load-balanced endpoint would not answer a view call is the one outcome this
|
|
95
|
+
* command must never produce; the transaction itself remains the authority.
|
|
96
|
+
*/
|
|
97
|
+
export async function readReclaimBlocker(
|
|
98
|
+
read: Pick<
|
|
99
|
+
CliReadClient,
|
|
100
|
+
"getStreamV2" | "latestCheckpointCheckedAt" | "latestBlockTimestamp"
|
|
101
|
+
>,
|
|
102
|
+
streamId: `0x${string}`,
|
|
103
|
+
fallbackNowSeconds: number,
|
|
104
|
+
): Promise<ReclaimBlocker | null> {
|
|
105
|
+
const stream = await read.getStreamV2(streamId).catch(() => null);
|
|
106
|
+
if (stream === null) return null;
|
|
107
|
+
const now = await readChainNow(read, fallbackNowSeconds);
|
|
108
|
+
const latestCheckpointCheckedAt = await read
|
|
109
|
+
.latestCheckpointCheckedAt()
|
|
110
|
+
.catch(() => null);
|
|
111
|
+
return classifyReclaimBlocker(stream, latestCheckpointCheckedAt, now.seconds);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The refusal for a blocker that will not clear on its own, as message + hint.
|
|
116
|
+
*
|
|
117
|
+
* `awaiting-checkpoint` has no entry here on purpose: it clears by itself, so
|
|
118
|
+
* it is narrated by {@link describeAwaitingCheckpoint} and waited out, never
|
|
119
|
+
* raised as an error.
|
|
120
|
+
*/
|
|
121
|
+
export function describeTerminalBlocker(
|
|
122
|
+
blocker: ReclaimBlocker,
|
|
123
|
+
streamId: `0x${string}`,
|
|
124
|
+
): { readonly message: string; readonly hint: string } | null {
|
|
125
|
+
if (blocker.kind === "reclaimed") {
|
|
126
|
+
return {
|
|
127
|
+
message:
|
|
128
|
+
"this stream has already been reclaimed — there is nothing left to take back",
|
|
129
|
+
hint: `check where it went: metrik status ${streamId}`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (blocker.kind === "running") {
|
|
133
|
+
return {
|
|
134
|
+
message: `the stream is still running, so there is nothing to reclaim yet — the meter stops at ${formatTimestamp(
|
|
135
|
+
blocker.expiresAt,
|
|
136
|
+
)}, in ${formatDuration(blocker.secondsRemaining)}`,
|
|
137
|
+
hint: `stop the clock first — \`metrik close ${streamId}\`, or re-run this command with --close-first — or wait for it to expire. (If you closed it moments ago, the RPC endpoint may not have caught up yet: re-run this command.)`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** The wait, named: what stopped, how far the oracle has published. */
|
|
144
|
+
export function describeAwaitingCheckpoint(
|
|
145
|
+
blocker: Extract<ReclaimBlocker, { kind: "awaiting-checkpoint" }>,
|
|
146
|
+
): string {
|
|
147
|
+
const covered =
|
|
148
|
+
blocker.coveredUpTo === null
|
|
149
|
+
? "how far the oracle has published could not be read"
|
|
150
|
+
: `the oracle has published only to ${formatTimestamp(blocker.coveredUpTo)}`;
|
|
151
|
+
return `the stream stopped at ${formatTimestamp(
|
|
152
|
+
blocker.stopAt,
|
|
153
|
+
)} and ${covered}. Reclaim reverts until a checkpoint reaches the stop time — the oracle publishes roughly every 15-22s, so this waits.`;
|
|
154
|
+
}
|
package/src/cli/run.ts
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
assertKnownFlags,
|
|
3
|
+
booleanFlag,
|
|
4
|
+
jsonOutputRequested,
|
|
5
|
+
parseArgs,
|
|
6
|
+
} from "./args.js";
|
|
2
7
|
import {
|
|
3
8
|
CONFIG_FLAGS,
|
|
4
9
|
GLOBAL_FLAGS,
|
|
5
|
-
|
|
10
|
+
CLI_NETWORK_POLICY,
|
|
6
11
|
resolveConfig,
|
|
7
12
|
} from "./config.js";
|
|
13
|
+
import { describeAllowedNetworks } from "../network.js";
|
|
8
14
|
import { CliError, describeError, usageError } from "./errors.js";
|
|
9
15
|
import { createPrinter, type CliStreams } from "./output.js";
|
|
10
16
|
import { startHeartbeat } from "./progress.js";
|
|
11
17
|
import { defaultCliDependencies, type CliDependencies } from "./deps.js";
|
|
12
18
|
import { packageVersion } from "./version.js";
|
|
13
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
CDP_ENV_VARS,
|
|
21
|
+
PRIVATE_KEY_ENV,
|
|
22
|
+
PRIVY_SESSION_ENV_VARS,
|
|
23
|
+
PRIVY_WALLET_KEY_ENV,
|
|
24
|
+
} from "./wallet.js";
|
|
14
25
|
import type { CommandSpec } from "./context.js";
|
|
15
26
|
|
|
16
27
|
import { claimCommand } from "./commands/claim.js";
|
|
@@ -19,15 +30,39 @@ import { discoverCommand } from "./commands/discover.js";
|
|
|
19
30
|
import { invokeCommand } from "./commands/invoke.js";
|
|
20
31
|
import { mcpCommand } from "./commands/mcp.js";
|
|
21
32
|
import { openCommand } from "./commands/open.js";
|
|
33
|
+
import { payCommand } from "./commands/pay.js";
|
|
22
34
|
import { reclaimCommand } from "./commands/reclaim.js";
|
|
35
|
+
import { refundCommand } from "./commands/refund.js";
|
|
23
36
|
import { reclaimUnverifiedCommand } from "./commands/reclaim-unverified.js";
|
|
24
37
|
import { statusCommand } from "./commands/status.js";
|
|
25
38
|
import { streamsCommand } from "./commands/streams.js";
|
|
26
39
|
import { watchCommand } from "./commands/watch.js";
|
|
27
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Every wallet source, named in the order they are resolved. Privy shipped in
|
|
43
|
+
* 0.11.0 as resolution step 3 and worked, but appeared in no user-facing text
|
|
44
|
+
* at all — so the only way to learn the CLI could use it was to read the
|
|
45
|
+
* source or the docs. An external reviewer running the published package
|
|
46
|
+
* concluded it did not exist.
|
|
47
|
+
*/
|
|
48
|
+
const WALLET_SOURCES =
|
|
49
|
+
`${PRIVATE_KEY_ENV}, ${CDP_ENV_VARS.join(" + ")}, ` +
|
|
50
|
+
`or ${PRIVY_WALLET_KEY_ENV} (Privy; or a broker session via ${PRIVY_SESSION_ENV_VARS.join(" + ")}).`;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Said in the help, not only discovered at runtime. `claim` is the OPERATOR's
|
|
54
|
+
* side and a Privy broker policy allowlists BUYER actions only, so a Privy
|
|
55
|
+
* wallet cannot sign one — the broker refuses, and the client cannot raise its
|
|
56
|
+
* own ceiling. The command already warns when it runs; someone choosing a
|
|
57
|
+
* wallet needs it before that.
|
|
58
|
+
*/
|
|
59
|
+
const PRIVY_CLAIM_NOTE =
|
|
60
|
+
"`metrik claim` does NOT work on a Privy wallet: the broker's transaction allowlist is buyer-only. Claim with the operator's own key.";
|
|
61
|
+
|
|
28
62
|
/**
|
|
29
63
|
* The command surface, in the order the product loop runs:
|
|
30
|
-
* discover -> open -> invoke -> watch/status -> close ->
|
|
64
|
+
* discover -> open (or pay, over x402) -> invoke -> watch/status -> close ->
|
|
65
|
+
* reclaim (or refund, through an x402 seller's gasless relay), then the
|
|
31
66
|
* operator's own redemption (`claim`) and the buyer's last-resort exit
|
|
32
67
|
* (`reclaim-unverified`). `streams` (which of them are mine?) sits inside that
|
|
33
68
|
* loop; `mcp` (run the same loop from an MCP host) sits after it.
|
|
@@ -35,12 +70,14 @@ import { watchCommand } from "./commands/watch.js";
|
|
|
35
70
|
export const COMMANDS: readonly CommandSpec[] = [
|
|
36
71
|
discoverCommand,
|
|
37
72
|
openCommand,
|
|
73
|
+
payCommand,
|
|
38
74
|
statusCommand,
|
|
39
75
|
streamsCommand,
|
|
40
76
|
watchCommand,
|
|
41
77
|
invokeCommand,
|
|
42
78
|
closeCommand,
|
|
43
79
|
reclaimCommand,
|
|
80
|
+
refundCommand,
|
|
44
81
|
reclaimUnverifiedCommand,
|
|
45
82
|
claimCommand,
|
|
46
83
|
mcpCommand,
|
|
@@ -69,7 +106,7 @@ export async function runCli(options: RunCliOptions): Promise<number> {
|
|
|
69
106
|
let json = false;
|
|
70
107
|
try {
|
|
71
108
|
const args = parseArgs(options.argv);
|
|
72
|
-
json =
|
|
109
|
+
json = jsonOutputRequested(args);
|
|
73
110
|
const out = createPrinter(streams, json);
|
|
74
111
|
|
|
75
112
|
// `--version` is checked before the bare-invocation help branch: `metrik
|
|
@@ -160,12 +197,13 @@ export function renderHelp(commandName?: string): string {
|
|
|
160
197
|
...(command.signs
|
|
161
198
|
? [
|
|
162
199
|
"",
|
|
163
|
-
`Broadcasts a transaction. Requires a wallet in the environment: ${
|
|
200
|
+
`Broadcasts a transaction. Requires a wallet in the environment: ${WALLET_SOURCES}`,
|
|
201
|
+
...(command.name === "claim" ? [PRIVY_CLAIM_NOTE] : []),
|
|
164
202
|
]
|
|
165
203
|
: command.requiresKey === true
|
|
166
204
|
? [
|
|
167
205
|
"",
|
|
168
|
-
`Broadcasts nothing, but signs an off-chain EIP-712 capability, so it requires a wallet in the environment: ${
|
|
206
|
+
`Broadcasts nothing, but signs an off-chain EIP-712 capability, so it requires a wallet in the environment: ${WALLET_SOURCES}`,
|
|
169
207
|
]
|
|
170
208
|
: []),
|
|
171
209
|
].join("\n");
|
|
@@ -194,16 +232,21 @@ export function renderHelp(commandName?: string): string {
|
|
|
194
232
|
" --json machine-readable output on stdout",
|
|
195
233
|
" --help this text, or `metrik <command> --help`",
|
|
196
234
|
"",
|
|
197
|
-
"Settlement flags (all default to
|
|
198
|
-
" --chain-id --rpc-url --escrow --usdc --oracle-url --registry-url",
|
|
235
|
+
"Settlement flags (all default to the selected network's registry entry):",
|
|
236
|
+
" --network --chain-id --rpc-url --escrow --usdc --oracle-url --registry-url",
|
|
237
|
+
" --network takes a registry id, chain id or CAIP-2 id (env METRIK_NETWORK).",
|
|
199
238
|
"",
|
|
200
239
|
"Wallet (read from the environment only; never accepted as a flag):",
|
|
201
|
-
` ${PRIVATE_KEY_ENV} a
|
|
240
|
+
` ${PRIVATE_KEY_ENV} a testnet key. Checked first.`,
|
|
202
241
|
` ${CDP_ENV_VARS.join(", ")}`,
|
|
203
242
|
" a Coinbase CDP Server Wallet v2 account. Used when no private key is set.",
|
|
243
|
+
` ${PRIVY_WALLET_KEY_ENV}`,
|
|
244
|
+
" a Privy wallet you provisioned, reached through a broker. Checked third.",
|
|
245
|
+
` A broker session instead: ${PRIVY_SESSION_ENV_VARS.join(", ")}.`,
|
|
246
|
+
` ${PRIVY_CLAIM_NOTE}`,
|
|
204
247
|
" A credential on the command line lands in shell history; these never are.",
|
|
205
248
|
"",
|
|
206
|
-
`TESTNET ONLY: this CLI refuses any chain outside ${
|
|
249
|
+
`TESTNET ONLY: this CLI refuses any chain outside the registered testnets: ${describeAllowedNetworks(CLI_NETWORK_POLICY)},`,
|
|
207
250
|
"and re-checks the chain id the RPC actually serves before signing. There is no override.",
|
|
208
251
|
].join("\n");
|
|
209
252
|
}
|
package/src/cli/scan-range.ts
CHANGED
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
* `buyer` and `operator` are INDEXED on `StreamOpened`, so a per-wallet scan is
|
|
20
20
|
* a server-side topic filter whose response is tiny regardless of range. What
|
|
21
21
|
* public RPCs cap is the per-call BLOCK RANGE, and a topic filter does not lift
|
|
22
|
-
* it:
|
|
22
|
+
* it: the public RPC answers a wider range with `-32614 "eth_getLogs is
|
|
23
23
|
* limited to a 10,000 range"`. So the page size is the cap, not a guess below
|
|
24
24
|
* it.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* getLogs page size. The window is `chunk + 1` blocks (bounds inclusive), so
|
|
29
|
-
* 9 999 is the largest page
|
|
29
|
+
* 9 999 is the largest page the public RPC accepts.
|
|
30
30
|
*/
|
|
31
31
|
export const LOG_SCAN_CHUNK = 9_999n;
|
|
32
32
|
|
package/src/cli/status.ts
CHANGED
|
@@ -126,6 +126,8 @@ export async function readStreamReport(
|
|
|
126
126
|
read: CliReadClient,
|
|
127
127
|
streamId: `0x${string}`,
|
|
128
128
|
nowSeconds: number,
|
|
129
|
+
/** The escrow's generation (decides the escape-hatch rule). Default `v2`. */
|
|
130
|
+
escrowGeneration = "v2",
|
|
129
131
|
): Promise<StreamReport> {
|
|
130
132
|
const stream = await read.getStreamV2(streamId);
|
|
131
133
|
|
|
@@ -164,6 +166,7 @@ export async function readStreamReport(
|
|
|
164
166
|
stream,
|
|
165
167
|
await read.escapeGraceSeconds(),
|
|
166
168
|
now.seconds,
|
|
169
|
+
escrowGeneration,
|
|
167
170
|
);
|
|
168
171
|
} catch {
|
|
169
172
|
escapeHatch = null;
|
|
@@ -208,6 +211,11 @@ export function streamReportJson(report: StreamReport): unknown {
|
|
|
208
211
|
status: stream.status,
|
|
209
212
|
reclaimed: stream.reclaimed,
|
|
210
213
|
buyer: stream.buyer,
|
|
214
|
+
// An x402 stream's `buyer` is the X402StreamOpener contract, not the
|
|
215
|
+
// person who paid; `payer` is who any refund goes to.
|
|
216
|
+
opener: stream.opener ?? null,
|
|
217
|
+
payer: stream.payer ?? stream.buyer,
|
|
218
|
+
boughtVia: (stream.opener ?? null) === null ? "wallet" : "x402-opener",
|
|
211
219
|
operator: stream.operator,
|
|
212
220
|
serviceRef: stream.serviceRef,
|
|
213
221
|
deposit: stream.deposit,
|
|
@@ -275,7 +283,12 @@ export function streamReportRows(
|
|
|
275
283
|
"status",
|
|
276
284
|
stream.reclaimed ? `${stream.status} (reclaimed)` : stream.status,
|
|
277
285
|
],
|
|
278
|
-
|
|
286
|
+
...(stream.opener === null || stream.opener === undefined
|
|
287
|
+
? ([["buyer", stream.buyer]] as const)
|
|
288
|
+
: ([
|
|
289
|
+
["buyer", `${stream.buyer} (x402 opener contract)`],
|
|
290
|
+
["payer", `${stream.payer} (refunds go here)`],
|
|
291
|
+
] as const)),
|
|
279
292
|
["operator", stream.operator],
|
|
280
293
|
["serviceRef", stream.serviceRef],
|
|
281
294
|
["deposit", formatUsdc(stream.deposit)],
|
package/src/cli/wallet.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
*
|
|
25
25
|
* ## Resolution order (first match wins, checked in this order)
|
|
26
26
|
*
|
|
27
|
-
* 1. `METRIK_AGENT_PRIVATE_KEY` — a raw
|
|
27
|
+
* 1. `METRIK_AGENT_PRIVATE_KEY` — a raw testnet key.
|
|
28
28
|
* 2. The `CDP_*` / `METRIK_AGENT_CDP_*` quartet — a Coinbase CDP Server Wallet
|
|
29
29
|
* v2 account, resolved through this package's own `resolveAgentWallet()`.
|
|
30
30
|
* 3. The `METRIK_AGENT_PRIVY_*` variables — a Privy wallet reached through a
|
|
@@ -123,7 +123,7 @@ export interface CliWallet {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
const WALLET_HINT =
|
|
126
|
-
`export ${PRIVATE_KEY_ENV}=0x… (a funded
|
|
126
|
+
`export ${PRIVATE_KEY_ENV}=0x… (a funded testnet key), configure a Coinbase CDP wallet with ` +
|
|
127
127
|
`${CDP_ENV_VARS.join(", ")}, or configure a Privy wallet with ${PRIVY_WALLET_KEY_ENV} (agent-owned) or ` +
|
|
128
128
|
`${PRIVY_SESSION_ENV_VARS.join(", ")} (broker session). All are read from the environment only — never pass a credential as a command-line flag.`;
|
|
129
129
|
|