@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/config.ts
CHANGED
|
@@ -1,76 +1,97 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
BASE_SEPOLIA_USDC,
|
|
4
|
-
DEFAULT_ORACLE_BASE_URL,
|
|
5
|
-
DEFAULT_PUBLIC_REGISTRY_URL,
|
|
6
|
-
} from "@absol-labs/sdk";
|
|
7
|
-
import { isAddress, getAddress } from "viem";
|
|
8
|
-
import { baseSepolia } from "viem/chains";
|
|
1
|
+
import type { MetrikNetwork } from "@absol-labs/sdk";
|
|
2
|
+
import { isAddress, getAddress, type Chain } from "viem";
|
|
9
3
|
|
|
4
|
+
import {
|
|
5
|
+
allowedNetworks,
|
|
6
|
+
describeAllowedNetworks,
|
|
7
|
+
registeredDeployment,
|
|
8
|
+
METRIK_NETWORK_ENV,
|
|
9
|
+
resolveAgentNetwork,
|
|
10
|
+
UnsupportedNetworkError,
|
|
11
|
+
} from "../network.js";
|
|
10
12
|
import { CliError, configError, usageError } from "./errors.js";
|
|
11
13
|
import { stringFlag, integerFlag, type ParsedArgs } from "./args.js";
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
|
-
* TESTNET ONLY — the
|
|
16
|
+
* TESTNET ONLY — the CLI settles only on registered networks the SDK registry
|
|
17
|
+
* marks `testnet: true`.
|
|
15
18
|
*
|
|
16
19
|
* Metrik's escrow moves real USDC the moment it is pointed at a mainnet chain,
|
|
17
20
|
* and this CLI signs with a raw private key read from the environment. So the
|
|
18
|
-
* chain is an allowlist, not a default:
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
21
|
+
* chain is an allowlist, not a default: a chain the registry does not know, or
|
|
22
|
+
* one it knows as a mainnet, is refused outright, with no override flag. There
|
|
23
|
+
* is deliberately no `--allow-mainnet` — an escape hatch that re-enables real
|
|
24
|
+
* funds would defeat the guarantee.
|
|
22
25
|
*
|
|
23
|
-
* The allowlist is enforced TWICE: once against the configured/declared
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
26
|
+
* The allowlist is enforced TWICE: once against the configured/declared network,
|
|
27
|
+
* and again against the chain id the RPC endpoint actually reports before any
|
|
28
|
+
* fund-moving command signs anything (see `assertTestnetRpc`). The second check
|
|
29
|
+
* is what stops a testnet `--chain-id` paired with a mainnet `--rpc-url`.
|
|
27
30
|
*/
|
|
28
|
-
export const
|
|
31
|
+
export const CLI_NETWORK_POLICY = { testnetOnly: true } as const;
|
|
32
|
+
|
|
33
|
+
/** Chain ids of every registered testnet this CLI will settle against. */
|
|
34
|
+
export function testnetChainIds(): number[] {
|
|
35
|
+
return allowedNetworks(CLI_NETWORK_POLICY).map((network) => network.chain.id);
|
|
36
|
+
}
|
|
29
37
|
|
|
30
38
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* Verified against Base Sepolia on 2026-09-17: `eth_getLogs` for this single
|
|
35
|
-
* block returns 6 escrow logs (the deployment's own events). History is
|
|
36
|
-
* immutable, so that is a stable known answer forever, which is what lets the
|
|
37
|
-
* same block serve as the log-retention canary in `metrik streams`.
|
|
38
|
-
*
|
|
39
|
-
* It is tied to that ONE address. A run pointed at a different `--escrow` has
|
|
40
|
-
* no anchor and must be given `--from-block`, rather than silently scanning
|
|
41
|
-
* from a block that means nothing for it.
|
|
39
|
+
* @deprecated Snapshot of {@link testnetChainIds} at import time. A network
|
|
40
|
+
* registered later is not in it; call `testnetChainIds()` instead.
|
|
42
41
|
*/
|
|
43
|
-
export const
|
|
42
|
+
export const TESTNET_CHAIN_IDS: readonly number[] = testnetChainIds();
|
|
44
43
|
|
|
45
44
|
export interface CliConfig {
|
|
46
|
-
|
|
45
|
+
/** The registered network this run settles on (from the SDK registry). */
|
|
46
|
+
readonly network: MetrikNetwork;
|
|
47
|
+
readonly chain: Chain;
|
|
47
48
|
readonly chainId: number;
|
|
48
49
|
readonly rpcUrl: string;
|
|
49
50
|
readonly escrow: `0x${string}`;
|
|
50
51
|
readonly usdc: `0x${string}`;
|
|
51
52
|
readonly oracleBaseUrl: string;
|
|
52
53
|
readonly registryUrl: string;
|
|
54
|
+
/**
|
|
55
|
+
* Set ONLY for an `--escrow` the registry does not record, from the explicit
|
|
56
|
+
* `--escrow-generation`: the SDK then opts out of its code-hash pin
|
|
57
|
+
* (`allowUnregisteredEscrow`). A registered escrow's generation comes from
|
|
58
|
+
* the registry.
|
|
59
|
+
*/
|
|
60
|
+
readonly unregisteredEscrowGeneration?: "v2" | "v3";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The block the configured escrow was deployed at — the anchor of every escrow
|
|
65
|
+
* log scan — or `undefined` when the escrow is not the network's registered
|
|
66
|
+
* escrow (a run pointed at a different `--escrow` has no anchor and must be
|
|
67
|
+
* given `--from-block`, rather than silently scanning from a block that means
|
|
68
|
+
* nothing for it).
|
|
69
|
+
*/
|
|
70
|
+
export function escrowDeployBlock(config: CliConfig): bigint | undefined {
|
|
71
|
+
return registeredDeployment(config.network, config.escrow)?.escrow
|
|
72
|
+
.deployBlock;
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
/**
|
|
56
|
-
* Resolves settlement configuration from flags, then env, then the
|
|
57
|
-
*
|
|
76
|
+
* Resolves settlement configuration from flags, then env, then the network's
|
|
77
|
+
* registry defaults — so `metrik discover` works with nothing configured at
|
|
58
78
|
* all, while every value stays overridable.
|
|
79
|
+
*
|
|
80
|
+
* The network is selected by `--network` / `METRIK_NETWORK` (registry id,
|
|
81
|
+
* chain id or CAIP-2 id) or by `--chain-id` / `METRIK_AGENT_CHAIN_ID`; giving
|
|
82
|
+
* both is allowed only when they agree.
|
|
59
83
|
*/
|
|
60
84
|
export function resolveConfig(
|
|
61
85
|
args: ParsedArgs,
|
|
62
86
|
env: NodeJS.ProcessEnv,
|
|
63
87
|
): CliConfig {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
parseEnvChainId(env.METRIK_AGENT_CHAIN_ID) ??
|
|
67
|
-
baseSepolia.id;
|
|
68
|
-
assertTestnetChainId(chainId, "the configured chain id");
|
|
88
|
+
const network = resolveCliNetwork(args, env);
|
|
89
|
+
const chainId = network.chain.id;
|
|
69
90
|
|
|
70
91
|
const rpcUrl =
|
|
71
92
|
stringFlag(args, "rpc-url") ??
|
|
72
93
|
env.METRIK_AGENT_RPC_URL ??
|
|
73
|
-
|
|
94
|
+
network.rpcUrls[0];
|
|
74
95
|
if (rpcUrl === undefined || !isHttpUrl(rpcUrl)) {
|
|
75
96
|
throw configError(
|
|
76
97
|
`RPC URL must be an http(s) URL (got "${rpcUrl ?? "undefined"}")`,
|
|
@@ -78,35 +99,101 @@ export function resolveConfig(
|
|
|
78
99
|
);
|
|
79
100
|
}
|
|
80
101
|
|
|
102
|
+
const escrow = resolveAddress(
|
|
103
|
+
stringFlag(args, "escrow") ?? env.METRIK_AGENT_ESCROW,
|
|
104
|
+
network.escrow.address,
|
|
105
|
+
"escrow",
|
|
106
|
+
);
|
|
107
|
+
const declared = (
|
|
108
|
+
stringFlag(args, "escrow-generation") ?? env.METRIK_AGENT_ESCROW_GENERATION
|
|
109
|
+
)
|
|
110
|
+
?.trim()
|
|
111
|
+
.toLowerCase();
|
|
112
|
+
if (declared !== undefined && declared !== "v2" && declared !== "v3") {
|
|
113
|
+
throw configError(
|
|
114
|
+
`--escrow-generation must be "v2" or "v3" (got "${declared}")`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
const deployment = registeredDeployment(network, escrow);
|
|
118
|
+
if (deployment === undefined && declared === undefined) {
|
|
119
|
+
throw configError(
|
|
120
|
+
`escrow ${escrow} is not a registered deployment of ${network.name}`,
|
|
121
|
+
`the SDK pins registered escrows by code hash; for your own deployment pass --escrow-generation v2|v3 (it then only checks the interface, which any contract can fake). Registered: ${[network.escrow, ...network.legacy.map((d) => d.escrow)].map((e) => `${e.address} (${e.generation})`).join(", ")}.`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (
|
|
125
|
+
deployment !== undefined &&
|
|
126
|
+
declared !== undefined &&
|
|
127
|
+
declared !== deployment.escrow.generation
|
|
128
|
+
) {
|
|
129
|
+
throw configError(
|
|
130
|
+
`--escrow-generation ${declared} contradicts the registry: ${escrow} is the ${deployment.escrow.generation} escrow`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
81
134
|
return {
|
|
82
|
-
|
|
135
|
+
network,
|
|
136
|
+
chain: network.chain,
|
|
83
137
|
chainId,
|
|
84
138
|
rpcUrl,
|
|
85
|
-
escrow
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
),
|
|
139
|
+
escrow,
|
|
140
|
+
...(deployment === undefined
|
|
141
|
+
? { unregisteredEscrowGeneration: declared as "v2" | "v3" }
|
|
142
|
+
: {}),
|
|
90
143
|
usdc: resolveAddress(
|
|
91
144
|
stringFlag(args, "usdc") ?? env.METRIK_AGENT_USDC,
|
|
92
|
-
|
|
145
|
+
network.usdc.address,
|
|
93
146
|
"usdc",
|
|
94
147
|
),
|
|
95
148
|
oracleBaseUrl: resolveHttpUrl(
|
|
96
149
|
stringFlag(args, "oracle-url") ?? env.METRIK_AGENT_ORACLE_URL,
|
|
97
|
-
|
|
150
|
+
network.oracleBaseUrl,
|
|
98
151
|
"oracle-url",
|
|
99
152
|
),
|
|
100
153
|
registryUrl: resolveHttpUrl(
|
|
101
154
|
stringFlag(args, "registry-url") ?? env.METRIK_AGENT_REGISTRY_URL,
|
|
102
|
-
|
|
155
|
+
network.publicRegistryUrl ?? `${network.oracleBaseUrl}/listings`,
|
|
103
156
|
"registry-url",
|
|
104
157
|
),
|
|
105
158
|
};
|
|
106
159
|
}
|
|
107
160
|
|
|
161
|
+
function resolveCliNetwork(
|
|
162
|
+
args: ParsedArgs,
|
|
163
|
+
env: NodeJS.ProcessEnv,
|
|
164
|
+
): MetrikNetwork {
|
|
165
|
+
const chainId =
|
|
166
|
+
integerFlag(args, "chain-id") ?? parseEnvChainId(env.METRIK_AGENT_CHAIN_ID);
|
|
167
|
+
const selector = stringFlag(args, "network") ?? env[METRIK_NETWORK_ENV];
|
|
168
|
+
if (chainId !== undefined)
|
|
169
|
+
assertTestnetChainId(chainId, "the configured chain id");
|
|
170
|
+
let network: MetrikNetwork;
|
|
171
|
+
try {
|
|
172
|
+
network = resolveAgentNetwork(
|
|
173
|
+
selector !== undefined && selector.trim().length > 0 ? selector : chainId,
|
|
174
|
+
CLI_NETWORK_POLICY,
|
|
175
|
+
);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (error instanceof UnsupportedNetworkError) {
|
|
178
|
+
throw configError(
|
|
179
|
+
`refusing to run against network "${error.selector}": it is not a supported testnet`,
|
|
180
|
+
`${error.message}. There is no override flag.`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
if (chainId !== undefined && chainId !== network.chain.id) {
|
|
186
|
+
throw configError(
|
|
187
|
+
`--chain-id ${chainId} does not match --network ${network.id} (chain ${network.chain.id})`,
|
|
188
|
+
"give one of them, or make them agree.",
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return network;
|
|
192
|
+
}
|
|
108
193
|
/** Flags every command accepts for settlement configuration. */
|
|
109
194
|
export const CONFIG_FLAGS: readonly string[] = [
|
|
195
|
+
"network",
|
|
196
|
+
"escrow-generation",
|
|
110
197
|
"chain-id",
|
|
111
198
|
"rpc-url",
|
|
112
199
|
"escrow",
|
|
@@ -119,12 +206,12 @@ export const CONFIG_FLAGS: readonly string[] = [
|
|
|
119
206
|
export const GLOBAL_FLAGS: readonly string[] = ["json", "help"];
|
|
120
207
|
|
|
121
208
|
export function assertTestnetChainId(chainId: number, source: string): void {
|
|
122
|
-
if (
|
|
209
|
+
if (testnetChainIds().includes(chainId)) return;
|
|
123
210
|
throw configError(
|
|
124
211
|
`refusing to run against chain ${chainId}: ${source} is not a supported testnet`,
|
|
125
|
-
`this CLI signs with a raw private key and settles real value, so it is testnet-only. Supported: ${
|
|
126
|
-
|
|
127
|
-
)}
|
|
212
|
+
`this CLI signs with a raw private key and settles real value, so it is testnet-only. Supported (registered testnets): ${describeAllowedNetworks(
|
|
213
|
+
CLI_NETWORK_POLICY,
|
|
214
|
+
)}. There is no override flag.`,
|
|
128
215
|
);
|
|
129
216
|
}
|
|
130
217
|
|
package/src/cli/context.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ParsedArgs } from "./args.js";
|
|
|
2
2
|
import type { CliConfig } from "./config.js";
|
|
3
3
|
import type { CliDependencies } from "./deps.js";
|
|
4
4
|
import type { Printer } from "./output.js";
|
|
5
|
+
import type { ProgressActivity } from "./progress.js";
|
|
5
6
|
|
|
6
7
|
/** Everything a command needs, assembled once by the runner. */
|
|
7
8
|
export interface CommandContext {
|
|
@@ -10,6 +11,12 @@ export interface CommandContext {
|
|
|
10
11
|
readonly env: NodeJS.ProcessEnv;
|
|
11
12
|
readonly out: Printer;
|
|
12
13
|
readonly deps: CliDependencies;
|
|
14
|
+
/**
|
|
15
|
+
* The runner's heartbeat. A command in a deliberate, announced retry or poll
|
|
16
|
+
* names it here so the heartbeat says what it is waiting for. Optional so a
|
|
17
|
+
* command can be driven without the runner (tests); absent means no-op.
|
|
18
|
+
*/
|
|
19
|
+
readonly progress?: ProgressActivity;
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
export interface CommandSpec {
|
|
@@ -26,5 +33,14 @@ export interface CommandSpec {
|
|
|
26
33
|
* `signs`, since everything that broadcasts obviously needs a key.
|
|
27
34
|
*/
|
|
28
35
|
readonly requiresKey?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Replaces the generic wallet paragraph of `--help` (and the tag in the
|
|
38
|
+
* command list) when "Broadcasts a transaction" / "needs a key" would be
|
|
39
|
+
* false for this command — e.g. `pay`, whose payer signs an EIP-3009
|
|
40
|
+
* authorization and broadcasts nothing, and cannot use a Privy wallet.
|
|
41
|
+
*/
|
|
42
|
+
readonly walletHelp?: { readonly tag: string; readonly text: string };
|
|
43
|
+
/** How a flag is shown in `--help`, when `--<name>` alone would mislead. */
|
|
44
|
+
readonly flagHelp?: Readonly<Record<string, string>>;
|
|
29
45
|
readonly run: (context: CommandContext) => Promise<void>;
|
|
30
46
|
}
|
package/src/cli/deps.ts
CHANGED
|
@@ -31,6 +31,11 @@ import {
|
|
|
31
31
|
type ReclaimVerifiedStreamResult,
|
|
32
32
|
} from "../sdk/client.js";
|
|
33
33
|
import type { SignedSpendMandate } from "../mandates/mandate.js";
|
|
34
|
+
import type {
|
|
35
|
+
PayX402WithMandateInput,
|
|
36
|
+
PayX402WithMandateResult,
|
|
37
|
+
} from "../x402-buyer/pay.js";
|
|
38
|
+
import type { RefundClient } from "@absol-labs/sdk/x402";
|
|
34
39
|
|
|
35
40
|
import type { CliConfig } from "./config.js";
|
|
36
41
|
import type { CliSignerAccount } from "./wallet.js";
|
|
@@ -65,6 +70,19 @@ export interface CliReadClient {
|
|
|
65
70
|
): Promise<bigint>;
|
|
66
71
|
/** Live protocol fee, read from the escrow rather than hardcoded. */
|
|
67
72
|
protocolFeeBps(): Promise<number>;
|
|
73
|
+
/**
|
|
74
|
+
* StreamEscrowV3 only: the stream's on-chain proven high-water
|
|
75
|
+
* (`provenCumulativeOf`). Both V3 buyer exits settle the operator at no less
|
|
76
|
+
* than this, and the operator can redeem it with `claimProven` — so it is the
|
|
77
|
+
* part of the operator's verified earnings the no-proof escape hatch can NOT
|
|
78
|
+
* take. Never called against a V2 escrow, which has no such view.
|
|
79
|
+
*
|
|
80
|
+
* Optional so an embedder's existing read client keeps compiling; a client
|
|
81
|
+
* without it is treated as "proven high-water unknown", which the CLI reports
|
|
82
|
+
* as worst case (nothing protected), never as protected.
|
|
83
|
+
*/
|
|
84
|
+
provenCumulativeOf?(streamId: `0x${string}`): Promise<bigint>;
|
|
85
|
+
|
|
68
86
|
/**
|
|
69
87
|
* `StreamEscrowV2.escapeGraceSeconds` (public immutable). The buyer's no-proof
|
|
70
88
|
* escape hatch unlocks at `expiresAt + escapeGraceSeconds`, so this is half of
|
|
@@ -197,6 +215,16 @@ export interface CliWriteClient {
|
|
|
197
215
|
claimStream(
|
|
198
216
|
input: CliStreamActionInput,
|
|
199
217
|
): Promise<StreamProofTransactionResult>;
|
|
218
|
+
/**
|
|
219
|
+
* Operator-only, StreamEscrowV3 only: redeem the stream's on-chain proven
|
|
220
|
+
* high-water (`claimProven`) WITHOUT a fresh Merkle proof — the only way to
|
|
221
|
+
* collect proven value whose checkpoint root has rotated out of the retained
|
|
222
|
+
* set. Optional so an embedder's existing write client keeps compiling; the
|
|
223
|
+
* CLI refuses, rather than falls back to a proof claim, when it is absent.
|
|
224
|
+
*/
|
|
225
|
+
claimProvenStream?(
|
|
226
|
+
input: CliStreamActionInput,
|
|
227
|
+
): Promise<StreamProofTransactionResult>;
|
|
200
228
|
}
|
|
201
229
|
|
|
202
230
|
/**
|
|
@@ -212,6 +240,32 @@ export interface CreateWriteClientOptions {
|
|
|
212
240
|
readonly transport?: Transport;
|
|
213
241
|
}
|
|
214
242
|
|
|
243
|
+
/**
|
|
244
|
+
* The buyer side of x402 (`metrik pay` / `metrik refund`). Behind the injectable
|
|
245
|
+
* surface like every other side effect, and loaded lazily by default so a CLI
|
|
246
|
+
* run that never pays over x402 never imports `@x402/*`.
|
|
247
|
+
*/
|
|
248
|
+
export interface CliX402 {
|
|
249
|
+
/** Mandate-gated `payWithX402` (see `../x402-buyer/pay.ts`). */
|
|
250
|
+
readonly pay: (
|
|
251
|
+
input: PayX402WithMandateInput,
|
|
252
|
+
) => Promise<PayX402WithMandateResult>;
|
|
253
|
+
/**
|
|
254
|
+
* The SDK's `refundClient`, bound to ONE stream and verifying every relay
|
|
255
|
+
* "success" against the chain this CLI is configured for.
|
|
256
|
+
*/
|
|
257
|
+
readonly refundClient: (
|
|
258
|
+
config: CliConfig,
|
|
259
|
+
target: {
|
|
260
|
+
readonly refundUrl: string;
|
|
261
|
+
readonly streamId: `0x${string}`;
|
|
262
|
+
readonly opener?: `0x${string}`;
|
|
263
|
+
readonly maxAttempts?: number;
|
|
264
|
+
readonly maxDelayMs?: number;
|
|
265
|
+
},
|
|
266
|
+
) => Promise<RefundClient>;
|
|
267
|
+
}
|
|
268
|
+
|
|
215
269
|
export interface CliDependencies {
|
|
216
270
|
readonly createReadClient: (config: CliConfig) => CliReadClient;
|
|
217
271
|
/**
|
|
@@ -236,6 +290,8 @@ export interface CliDependencies {
|
|
|
236
290
|
readonly createInvokeStreamReader: (config: CliConfig) => InvokeStreamReader;
|
|
237
291
|
readonly nowSeconds: () => number;
|
|
238
292
|
readonly sleep: (ms: number) => Promise<void>;
|
|
293
|
+
/** Optional so an embedder's existing dependency object keeps compiling. */
|
|
294
|
+
readonly x402?: CliX402;
|
|
239
295
|
}
|
|
240
296
|
|
|
241
297
|
/**
|
|
@@ -256,13 +312,29 @@ const STREAM_OPENED_EVENT = getAbiItem({
|
|
|
256
312
|
* with nothing on screen. Bounding it here bounds every read and every
|
|
257
313
|
* simulation the SDK performs, in one place.
|
|
258
314
|
*/
|
|
259
|
-
function rpcTransport(config: CliConfig) {
|
|
315
|
+
export function rpcTransport(config: CliConfig) {
|
|
260
316
|
return http(config.rpcUrl, {
|
|
261
317
|
timeout: RPC_TIMEOUT_MS,
|
|
262
318
|
retryCount: RPC_RETRY_COUNT,
|
|
263
319
|
});
|
|
264
320
|
}
|
|
265
321
|
|
|
322
|
+
/**
|
|
323
|
+
* An `--escrow` the registry does not record was declared with
|
|
324
|
+
* `--escrow-generation`: the only case the SDK may skip its code-hash pin.
|
|
325
|
+
*/
|
|
326
|
+
function unregisteredEscrowOptions(config: CliConfig): {
|
|
327
|
+
readonly allowUnregisteredEscrow?: true;
|
|
328
|
+
readonly escrowGeneration?: "v2" | "v3";
|
|
329
|
+
} {
|
|
330
|
+
return config.unregisteredEscrowGeneration === undefined
|
|
331
|
+
? {}
|
|
332
|
+
: {
|
|
333
|
+
allowUnregisteredEscrow: true,
|
|
334
|
+
escrowGeneration: config.unregisteredEscrowGeneration,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
266
338
|
/** Shared `MetrikClient` construction: one escrow, declared as V2 on both keys. */
|
|
267
339
|
function createMetrikClient(
|
|
268
340
|
config: CliConfig,
|
|
@@ -281,6 +353,7 @@ function createMetrikClient(
|
|
|
281
353
|
usdc: config.usdc,
|
|
282
354
|
oracleBaseUrl: config.oracleBaseUrl,
|
|
283
355
|
settlementTarget: { chainId: config.chainId, escrow: config.escrow },
|
|
356
|
+
...unregisteredEscrowOptions(config),
|
|
284
357
|
...(account === undefined ? {} : { account }),
|
|
285
358
|
});
|
|
286
359
|
}
|
|
@@ -309,6 +382,11 @@ export const defaultCliDependencies: CliDependencies = {
|
|
|
309
382
|
async reclaimableForV2(streamId, cumulativeAmount) {
|
|
310
383
|
return await metrik.reclaimableForV2(streamId, cumulativeAmount);
|
|
311
384
|
},
|
|
385
|
+
async provenCumulativeOf(streamId) {
|
|
386
|
+
// The SDK refuses this (before any RPC) on a client whose escrow is not
|
|
387
|
+
// V3, so a V2 escrow can never be read through the V3 ABI here.
|
|
388
|
+
return await metrik.provenCumulativeOf(streamId);
|
|
389
|
+
},
|
|
312
390
|
async nativeBalance(address) {
|
|
313
391
|
return await metrik.publicClient.getBalance({ address });
|
|
314
392
|
},
|
|
@@ -416,6 +494,7 @@ export const defaultCliDependencies: CliDependencies = {
|
|
|
416
494
|
usdc: config.usdc,
|
|
417
495
|
oracleBaseUrl: config.oracleBaseUrl,
|
|
418
496
|
settlementTarget: { chainId: config.chainId, escrow: config.escrow },
|
|
497
|
+
...unregisteredEscrowOptions(config),
|
|
419
498
|
...(account === null ? {} : { account }),
|
|
420
499
|
};
|
|
421
500
|
// The mandate-gated agent client owns every fund-moving call; the raw SDK
|
|
@@ -480,6 +559,15 @@ export const defaultCliDependencies: CliDependencies = {
|
|
|
480
559
|
if (signedMandate === null) return await metrik.claim(input.streamId);
|
|
481
560
|
return await agentClient.claimStream({ ...input, signedMandate });
|
|
482
561
|
},
|
|
562
|
+
async claimProvenStream({ signedMandate, ...input }) {
|
|
563
|
+
if (signedMandate === null) {
|
|
564
|
+
return await metrik.claimProven(input.streamId);
|
|
565
|
+
}
|
|
566
|
+
return await agentClient.claimProvenStream({
|
|
567
|
+
...input,
|
|
568
|
+
signedMandate,
|
|
569
|
+
});
|
|
570
|
+
},
|
|
483
571
|
};
|
|
484
572
|
},
|
|
485
573
|
async discover(options) {
|
|
@@ -506,6 +594,28 @@ export const defaultCliDependencies: CliDependencies = {
|
|
|
506
594
|
nowSeconds() {
|
|
507
595
|
return Math.floor(Date.now() / 1000);
|
|
508
596
|
},
|
|
597
|
+
x402: {
|
|
598
|
+
async pay(input) {
|
|
599
|
+
const { payX402WithMandate } = await import("../x402-buyer/pay.js");
|
|
600
|
+
return await payX402WithMandate(input);
|
|
601
|
+
},
|
|
602
|
+
async refundClient(config, target) {
|
|
603
|
+
const { refundClient } = await import("@absol-labs/sdk/x402");
|
|
604
|
+
return refundClient(target.refundUrl, {
|
|
605
|
+
streamId: target.streamId,
|
|
606
|
+
...(target.opener === undefined ? {} : { opener: target.opener }),
|
|
607
|
+
// Every relay "success" is checked against the receipt on THIS chain.
|
|
608
|
+
verifyWith: createMetrikClient(config),
|
|
609
|
+
expectedChainId: config.chainId,
|
|
610
|
+
...(target.maxAttempts === undefined
|
|
611
|
+
? {}
|
|
612
|
+
: { maxAttempts: target.maxAttempts }),
|
|
613
|
+
...(target.maxDelayMs === undefined
|
|
614
|
+
? {}
|
|
615
|
+
: { maxDelayMs: target.maxDelayMs }),
|
|
616
|
+
});
|
|
617
|
+
},
|
|
618
|
+
},
|
|
509
619
|
async sleep(ms) {
|
|
510
620
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
511
621
|
},
|
package/src/cli/errors.ts
CHANGED
|
@@ -76,6 +76,28 @@ function namesTheRevert(line: string): boolean {
|
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Links that state the OUTCOME rather than open a sentence the next link
|
|
81
|
+
* completes — so the trailing "…and it reverted" carries nothing.
|
|
82
|
+
*
|
|
83
|
+
* `metrik status <a stream id that does not exist>` used to print
|
|
84
|
+
*
|
|
85
|
+
* stream 0x…: does not exist on the escrow: The contract function
|
|
86
|
+
* "getStream" reverted.
|
|
87
|
+
*
|
|
88
|
+
* The first link is the whole answer; the tail is viem restating that a revert
|
|
89
|
+
* is how the escrow says so. Contrast "reclaim simulation failed", which is a
|
|
90
|
+
* PREFIX — dropping the boilerplate after it would leave a failure with no
|
|
91
|
+
* stated reason at all, which is why the one-boilerplate rule exists.
|
|
92
|
+
*/
|
|
93
|
+
const STATES_THE_OUTCOME: readonly RegExp[] = [
|
|
94
|
+
/\bdoes not exist on the escrow\b/,
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
function statesTheOutcome(line: string): boolean {
|
|
98
|
+
return STATES_THE_OUTCOME.some((pattern) => pattern.test(line));
|
|
99
|
+
}
|
|
100
|
+
|
|
79
101
|
function isBoilerplate(line: string): boolean {
|
|
80
102
|
return VIEM_BOILERPLATE.some((pattern) => pattern.test(line));
|
|
81
103
|
}
|
|
@@ -108,7 +130,8 @@ export function stripRedundantBoilerplate(
|
|
|
108
130
|
chain: readonly string[],
|
|
109
131
|
): readonly string[] {
|
|
110
132
|
const decoded = chain.some(
|
|
111
|
-
(line) =>
|
|
133
|
+
(line) =>
|
|
134
|
+
(namesTheRevert(line) || statesTheOutcome(line)) && !isBoilerplate(line),
|
|
112
135
|
);
|
|
113
136
|
let keptBoilerplate = false;
|
|
114
137
|
const kept = chain.filter((line, index) => {
|
package/src/cli/escape-hatch.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { StreamV2 } from "@absol-labs/sdk";
|
|
2
2
|
|
|
3
|
+
import { escapeHatchReadyAtFormula } from "../escrow-generation.js";
|
|
4
|
+
|
|
3
5
|
import { formatDuration } from "./amounts.js";
|
|
4
6
|
import type { CliReadClient } from "./deps.js";
|
|
5
7
|
|
|
@@ -17,9 +19,11 @@ import type { CliReadClient } from "./deps.js";
|
|
|
17
19
|
* — and `escapeGraceSeconds` is a public immutable on the escrow, so readiness
|
|
18
20
|
* is fully computable before a single wei of gas is spent.
|
|
19
21
|
*
|
|
20
|
-
* Note which timestamp the escrow uses
|
|
21
|
-
*
|
|
22
|
-
*
|
|
22
|
+
* Note which timestamp the escrow uses, which depends on its GENERATION (the
|
|
23
|
+
* SDK registry's `escrow.generation`; see `../escrow-generation.ts`): V2 uses
|
|
24
|
+
* `expiresAt`, NEVER `closedAt` — closing early does not bring the hatch
|
|
25
|
+
* forward, and the CLI must not imply that it does. V3 opens it at
|
|
26
|
+
* `min(expiresAt, closedAt) + escapeGraceSeconds`.
|
|
23
27
|
*/
|
|
24
28
|
export interface EscapeHatchWindow {
|
|
25
29
|
/** `escapeGraceSeconds` as read from the escrow. */
|
|
@@ -32,11 +36,21 @@ export interface EscapeHatchWindow {
|
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
export function escapeHatchWindow(
|
|
35
|
-
stream: Pick<StreamV2, "expiresAt"
|
|
39
|
+
stream: Pick<StreamV2, "expiresAt"> & Partial<Pick<StreamV2, "closedAt">>,
|
|
36
40
|
graceSeconds: number,
|
|
37
41
|
nowSeconds: number,
|
|
42
|
+
generation = "v2",
|
|
38
43
|
): EscapeHatchWindow {
|
|
39
|
-
const readyAt =
|
|
44
|
+
const readyAt = Number(
|
|
45
|
+
escapeHatchReadyAtFormula(
|
|
46
|
+
generation,
|
|
47
|
+
{
|
|
48
|
+
expiresAt: BigInt(stream.expiresAt),
|
|
49
|
+
closedAt: BigInt(stream.closedAt ?? 0),
|
|
50
|
+
},
|
|
51
|
+
BigInt(graceSeconds),
|
|
52
|
+
),
|
|
53
|
+
);
|
|
40
54
|
const secondsRemaining = readyAt - nowSeconds;
|
|
41
55
|
return {
|
|
42
56
|
graceSeconds,
|
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
|
}
|