@absol-labs/agent 0.11.0 → 0.12.0-rc.2
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 +43 -51
- 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.d.ts +32 -0
- package/dist/cli/commands/claim.d.ts.map +1 -1
- package/dist/cli/commands/claim.js +116 -28
- 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 +34 -0
- package/dist/cli/commands/pay.d.ts.map +1 -0
- package/dist/cli/commands/pay.js +479 -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 +204 -20
- package/dist/cli/commands/reclaim.js.map +1 -1
- package/dist/cli/commands/refund.d.ts +31 -0
- package/dist/cli/commands/refund.d.ts.map +1 -0
- package/dist/cli/commands/refund.js +397 -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 +21 -2
- 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 +4 -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/context.d.ts +19 -0
- package/dist/cli/context.d.ts.map +1 -1
- package/dist/cli/deps.d.ts +53 -0
- package/dist/cli/deps.d.ts.map +1 -1
- package/dist/cli/deps.js +51 -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/progress.d.ts +13 -1
- package/dist/cli/progress.d.ts.map +1 -1
- package/dist/cli/progress.js +7 -1
- package/dist/cli/progress.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 +62 -21
- 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 +106 -1
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +325 -44
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/wallet.d.ts +2 -2
- package/dist/cli/wallet.d.ts.map +1 -1
- package/dist/cli/wallet.js +29 -5
- 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 +128 -44
- package/dist/gateway/http-server.d.ts.map +1 -1
- package/dist/gateway/http-server.js +506 -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 +252 -0
- package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
- package/dist/gateway/x402-opener-mode.js +772 -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 +64 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +247 -37
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/x402-tools.d.ts +109 -0
- package/dist/mcp/x402-tools.d.ts.map +1 -0
- package/dist/mcp/x402-tools.js +554 -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/client.d.ts +13 -0
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/client.js +15 -0
- package/dist/sdk/client.js.map +1 -1
- 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 +157 -0
- package/dist/x402-buyer/pay.d.ts.map +1 -0
- package/dist/x402-buyer/pay.js +366 -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 +40 -0
- package/dist/x402-opener/facilitator-entry.js.map +1 -0
- package/dist/x402-opener/facilitator-server.d.ts +209 -0
- package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-server.js +762 -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 +266 -0
- package/dist/x402-opener/refund-relay.d.ts.map +1 -0
- package/dist/x402-opener/refund-relay.js +1341 -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 +296 -0
- package/dist/x402-opener/scheme.d.ts.map +1 -0
- package/dist/x402-opener/scheme.js +1035 -0
- package/dist/x402-opener/scheme.js.map +1 -0
- package/dist/x402-opener/terms.d.ts +165 -0
- package/dist/x402-opener/terms.d.ts.map +1 -0
- package/dist/x402-opener/terms.js +304 -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 +265 -34
- package/docs/langchain.md +5 -0
- package/docs/mcp-reference.md +91 -5
- package/docs/probe-capability.md +191 -0
- package/docs/quickstart.md +39 -4
- package/docs/threat-model.md +20 -0
- package/docs/x402.md +766 -593
- 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 +168 -33
- 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 +584 -0
- package/src/cli/commands/reclaim-unverified.ts +8 -2
- package/src/cli/commands/reclaim.ts +277 -19
- package/src/cli/commands/refund.ts +475 -0
- package/src/cli/commands/status.ts +28 -2
- package/src/cli/commands/streams.ts +10 -14
- package/src/cli/commands/watch.ts +11 -1
- package/src/cli/config.ts +139 -52
- package/src/cli/context.ts +16 -0
- package/src/cli/deps.ts +111 -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/progress.ts +21 -2
- package/src/cli/reclaimability.ts +154 -0
- package/src/cli/run.ts +77 -21
- package/src/cli/scan-range.ts +2 -2
- package/src/cli/status.ts +454 -44
- package/src/cli/wallet.ts +45 -8
- 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 +717 -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 +1171 -0
- package/src/index.ts +82 -19
- package/src/mcp/server.ts +351 -42
- package/src/mcp/x402-tools.ts +785 -0
- package/src/network.ts +302 -0
- package/src/sdk/client.ts +25 -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 +555 -0
- package/src/x402-opener/abi.ts +881 -0
- package/src/x402-opener/facilitator-entry.ts +48 -0
- package/src/x402-opener/facilitator-server.ts +1114 -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 +1873 -0
- package/src/x402-opener/relayer-queue.ts +18 -0
- package/src/x402-opener/scheme.ts +1551 -0
- package/src/x402-opener/terms.ts +453 -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/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
|
}
|
package/src/cli/progress.ts
CHANGED
|
@@ -12,11 +12,24 @@
|
|
|
12
12
|
* "stuck". stderr in BOTH modes, so `--json` stdout stays a single parseable
|
|
13
13
|
* document.
|
|
14
14
|
*/
|
|
15
|
-
export interface Heartbeat {
|
|
15
|
+
export interface Heartbeat extends ProgressActivity {
|
|
16
16
|
/** Stops the ticker. Safe to call more than once. */
|
|
17
17
|
readonly stop: () => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* What a command tells the heartbeat while it waits ON PURPOSE.
|
|
22
|
+
*
|
|
23
|
+
* A tick that says "slow RPC, not a hang" is wrong while the command is in a
|
|
24
|
+
* retry or poll it already announced (`reclaim` waiting for a checkpoint,
|
|
25
|
+
* `attempt 3/12`; `refund` letting the relay's settlement window close): then
|
|
26
|
+
* the honest line is "waiting for X (attempt n/N)", not a guess about a slow
|
|
27
|
+
* endpoint. `null` returns the tick to the generic wording.
|
|
28
|
+
*/
|
|
29
|
+
export interface ProgressActivity {
|
|
30
|
+
readonly setActivity: (activity: string | null) => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
/** Silence before the first tick — below this, a command is simply fast. */
|
|
21
34
|
export const HEARTBEAT_DELAY_MS = 8_000;
|
|
22
35
|
/** Gap between ticks once it has started. */
|
|
@@ -49,12 +62,15 @@ export function startHeartbeat(
|
|
|
49
62
|
const startedAt = now();
|
|
50
63
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
51
64
|
let stopped = false;
|
|
65
|
+
let activity: string | null = null;
|
|
52
66
|
|
|
53
67
|
const tick = (): void => {
|
|
54
68
|
if (stopped) return;
|
|
55
69
|
const elapsed = Math.round((now() - startedAt) / 1000);
|
|
56
70
|
note(
|
|
57
|
-
|
|
71
|
+
activity === null
|
|
72
|
+
? `… still working: ${label} (${elapsed}s elapsed). Slow RPC or oracle, not a hang.`
|
|
73
|
+
: `… still working: ${label} (${elapsed}s elapsed) — ${activity}. This is the announced wait, not a hang.`,
|
|
58
74
|
);
|
|
59
75
|
schedule(intervalMs);
|
|
60
76
|
};
|
|
@@ -66,6 +82,9 @@ export function startHeartbeat(
|
|
|
66
82
|
schedule(delayMs);
|
|
67
83
|
|
|
68
84
|
return {
|
|
85
|
+
setActivity(next) {
|
|
86
|
+
activity = next;
|
|
87
|
+
},
|
|
69
88
|
stop() {
|
|
70
89
|
stopped = true;
|
|
71
90
|
if (timer !== undefined) clearTimer(timer);
|
|
@@ -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,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
JSON_BODY_COMMANDS,
|
|
3
|
+
assertKnownFlags,
|
|
4
|
+
booleanFlag,
|
|
5
|
+
jsonOutputRequested,
|
|
6
|
+
parseArgs,
|
|
7
|
+
} from "./args.js";
|
|
2
8
|
import {
|
|
3
9
|
CONFIG_FLAGS,
|
|
4
10
|
GLOBAL_FLAGS,
|
|
5
|
-
|
|
11
|
+
CLI_NETWORK_POLICY,
|
|
6
12
|
resolveConfig,
|
|
7
13
|
} from "./config.js";
|
|
14
|
+
import { describeAllowedNetworks } from "../network.js";
|
|
8
15
|
import { CliError, describeError, usageError } from "./errors.js";
|
|
9
16
|
import { createPrinter, type CliStreams } from "./output.js";
|
|
10
17
|
import { startHeartbeat } from "./progress.js";
|
|
11
18
|
import { defaultCliDependencies, type CliDependencies } from "./deps.js";
|
|
12
19
|
import { packageVersion } from "./version.js";
|
|
13
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
CDP_ENV_VARS,
|
|
22
|
+
PRIVATE_KEY_ENV,
|
|
23
|
+
PRIVY_SESSION_ENV_VARS,
|
|
24
|
+
PRIVY_WALLET_KEY_ENV,
|
|
25
|
+
} from "./wallet.js";
|
|
14
26
|
import type { CommandSpec } from "./context.js";
|
|
15
27
|
|
|
16
28
|
import { claimCommand } from "./commands/claim.js";
|
|
@@ -19,15 +31,39 @@ import { discoverCommand } from "./commands/discover.js";
|
|
|
19
31
|
import { invokeCommand } from "./commands/invoke.js";
|
|
20
32
|
import { mcpCommand } from "./commands/mcp.js";
|
|
21
33
|
import { openCommand } from "./commands/open.js";
|
|
34
|
+
import { payCommand } from "./commands/pay.js";
|
|
22
35
|
import { reclaimCommand } from "./commands/reclaim.js";
|
|
36
|
+
import { refundCommand } from "./commands/refund.js";
|
|
23
37
|
import { reclaimUnverifiedCommand } from "./commands/reclaim-unverified.js";
|
|
24
38
|
import { statusCommand } from "./commands/status.js";
|
|
25
39
|
import { streamsCommand } from "./commands/streams.js";
|
|
26
40
|
import { watchCommand } from "./commands/watch.js";
|
|
27
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Every wallet source, named in the order they are resolved. Privy shipped in
|
|
44
|
+
* 0.11.0 as resolution step 3 and worked, but appeared in no user-facing text
|
|
45
|
+
* at all — so the only way to learn the CLI could use it was to read the
|
|
46
|
+
* source or the docs. An external reviewer running the published package
|
|
47
|
+
* concluded it did not exist.
|
|
48
|
+
*/
|
|
49
|
+
const WALLET_SOURCES =
|
|
50
|
+
`${PRIVATE_KEY_ENV}, ${CDP_ENV_VARS.join(" + ")}, ` +
|
|
51
|
+
`or ${PRIVY_WALLET_KEY_ENV} (Privy; or a broker session via ${PRIVY_SESSION_ENV_VARS.join(" + ")}).`;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Said in the help, not only discovered at runtime. `claim` is the OPERATOR's
|
|
55
|
+
* side and a Privy broker policy allowlists BUYER actions only, so a Privy
|
|
56
|
+
* wallet cannot sign one — the broker refuses, and the client cannot raise its
|
|
57
|
+
* own ceiling. The command already warns when it runs; someone choosing a
|
|
58
|
+
* wallet needs it before that.
|
|
59
|
+
*/
|
|
60
|
+
const PRIVY_CLAIM_NOTE =
|
|
61
|
+
"`metrik claim` does NOT work on a Privy wallet: the broker's transaction allowlist is buyer-only. Claim with the operator's own key.";
|
|
62
|
+
|
|
28
63
|
/**
|
|
29
64
|
* The command surface, in the order the product loop runs:
|
|
30
|
-
* discover -> open -> invoke -> watch/status -> close ->
|
|
65
|
+
* discover -> open (or pay, over x402) -> invoke -> watch/status -> close ->
|
|
66
|
+
* reclaim (or refund, through an x402 seller's gasless relay), then the
|
|
31
67
|
* operator's own redemption (`claim`) and the buyer's last-resort exit
|
|
32
68
|
* (`reclaim-unverified`). `streams` (which of them are mine?) sits inside that
|
|
33
69
|
* loop; `mcp` (run the same loop from an MCP host) sits after it.
|
|
@@ -35,12 +71,14 @@ import { watchCommand } from "./commands/watch.js";
|
|
|
35
71
|
export const COMMANDS: readonly CommandSpec[] = [
|
|
36
72
|
discoverCommand,
|
|
37
73
|
openCommand,
|
|
74
|
+
payCommand,
|
|
38
75
|
statusCommand,
|
|
39
76
|
streamsCommand,
|
|
40
77
|
watchCommand,
|
|
41
78
|
invokeCommand,
|
|
42
79
|
closeCommand,
|
|
43
80
|
reclaimCommand,
|
|
81
|
+
refundCommand,
|
|
44
82
|
reclaimUnverifiedCommand,
|
|
45
83
|
claimCommand,
|
|
46
84
|
mcpCommand,
|
|
@@ -69,7 +107,7 @@ export async function runCli(options: RunCliOptions): Promise<number> {
|
|
|
69
107
|
let json = false;
|
|
70
108
|
try {
|
|
71
109
|
const args = parseArgs(options.argv);
|
|
72
|
-
json =
|
|
110
|
+
json = jsonOutputRequested(args);
|
|
73
111
|
const out = createPrinter(streams, json);
|
|
74
112
|
|
|
75
113
|
// `--version` is checked before the bare-invocation help branch: `metrik
|
|
@@ -110,7 +148,14 @@ export async function runCli(options: RunCliOptions): Promise<number> {
|
|
|
110
148
|
// exception is a rule someone forgets to apply to the next command.
|
|
111
149
|
const heartbeat = startHeartbeat(out.note, `metrik ${command.name}`);
|
|
112
150
|
try {
|
|
113
|
-
await command.run({
|
|
151
|
+
await command.run({
|
|
152
|
+
args,
|
|
153
|
+
config,
|
|
154
|
+
env,
|
|
155
|
+
out,
|
|
156
|
+
deps,
|
|
157
|
+
progress: heartbeat,
|
|
158
|
+
});
|
|
114
159
|
} finally {
|
|
115
160
|
heartbeat.stop();
|
|
116
161
|
}
|
|
@@ -154,20 +199,25 @@ export function renderHelp(commandName?: string): string {
|
|
|
154
199
|
"",
|
|
155
200
|
command.flags.length === 0
|
|
156
201
|
? "Command flags: (none)"
|
|
157
|
-
: `Command flags: ${command.flags.map((flag) => `--${flag}`).join(" ")}`,
|
|
202
|
+
: `Command flags: ${command.flags.map((flag) => command.flagHelp?.[flag] ?? `--${flag}`).join(" ")}`,
|
|
158
203
|
`Settlement flags: ${CONFIG_FLAGS.map((flag) => `--${flag}`).join(" ")}`,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
: command.requiresKey === true
|
|
204
|
+
JSON_BODY_COMMANDS.has(command.name)
|
|
205
|
+
? "Output flags: --json (bare, with no body; combinable with --json <body>)"
|
|
206
|
+
: "Output flags: --json",
|
|
207
|
+
...(command.walletHelp !== undefined
|
|
208
|
+
? ["", command.walletHelp.text]
|
|
209
|
+
: command.signs
|
|
166
210
|
? [
|
|
167
211
|
"",
|
|
168
|
-
`Broadcasts
|
|
212
|
+
`Broadcasts a transaction. Requires a wallet in the environment: ${WALLET_SOURCES}`,
|
|
213
|
+
...(command.name === "claim" ? [PRIVY_CLAIM_NOTE] : []),
|
|
169
214
|
]
|
|
170
|
-
:
|
|
215
|
+
: command.requiresKey === true
|
|
216
|
+
? [
|
|
217
|
+
"",
|
|
218
|
+
`Broadcasts nothing, but signs an off-chain EIP-712 capability, so it requires a wallet in the environment: ${WALLET_SOURCES}`,
|
|
219
|
+
]
|
|
220
|
+
: []),
|
|
171
221
|
].join("\n");
|
|
172
222
|
}
|
|
173
223
|
|
|
@@ -187,23 +237,29 @@ export function renderHelp(commandName?: string): string {
|
|
|
187
237
|
"Commands:",
|
|
188
238
|
...COMMANDS.map(
|
|
189
239
|
(spec) =>
|
|
190
|
-
` ${spec.name.padEnd(width)} ${spec.summary}${spec.signs ? " [broadcasts a tx]" : spec.requiresKey === true ? " [needs a key]" : ""}`,
|
|
240
|
+
` ${spec.name.padEnd(width)} ${spec.summary}${spec.walletHelp !== undefined ? ` ${spec.walletHelp.tag}` : spec.signs ? " [broadcasts a tx]" : spec.requiresKey === true ? " [needs a key]" : ""}`,
|
|
191
241
|
),
|
|
192
242
|
"",
|
|
193
243
|
"Global flags:",
|
|
194
244
|
" --json machine-readable output on stdout",
|
|
195
245
|
" --help this text, or `metrik <command> --help`",
|
|
196
246
|
"",
|
|
197
|
-
"Settlement flags (all default to
|
|
198
|
-
" --chain-id --rpc-url --escrow --usdc --oracle-url --registry-url",
|
|
247
|
+
"Settlement flags (all default to the selected network's registry entry):",
|
|
248
|
+
" --network --chain-id --rpc-url --escrow --usdc --oracle-url --registry-url",
|
|
249
|
+
" --network takes a registry id, chain id or CAIP-2 id (env METRIK_NETWORK).",
|
|
199
250
|
"",
|
|
200
251
|
"Wallet (read from the environment only; never accepted as a flag):",
|
|
201
|
-
` ${PRIVATE_KEY_ENV} a
|
|
252
|
+
` ${PRIVATE_KEY_ENV} a testnet key. Checked first.`,
|
|
202
253
|
` ${CDP_ENV_VARS.join(", ")}`,
|
|
203
254
|
" a Coinbase CDP Server Wallet v2 account. Used when no private key is set.",
|
|
255
|
+
` ${PRIVY_WALLET_KEY_ENV}`,
|
|
256
|
+
" a Privy wallet you provisioned, reached through a broker. Checked third.",
|
|
257
|
+
` A broker session instead: ${PRIVY_SESSION_ENV_VARS.join(", ")}.`,
|
|
258
|
+
` ${PRIVY_CLAIM_NOTE}`,
|
|
259
|
+
" Nor do `metrik pay` (the broker does not sign EIP-3009) or `metrik refund --close` (nor the opener's Close).",
|
|
204
260
|
" A credential on the command line lands in shell history; these never are.",
|
|
205
261
|
"",
|
|
206
|
-
`TESTNET ONLY: this CLI refuses any chain outside ${
|
|
262
|
+
`TESTNET ONLY: this CLI refuses any chain outside the registered testnets: ${describeAllowedNetworks(CLI_NETWORK_POLICY)},`,
|
|
207
263
|
"and re-checks the chain id the RPC actually serves before signing. There is no override.",
|
|
208
264
|
].join("\n");
|
|
209
265
|
}
|
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
|
|