@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
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# `ProbeCapability` — letting the verifier check a gated paid route
|
|
2
|
+
|
|
3
|
+
> **What this changes for you as a seller:** if your listing is `gated`, the
|
|
4
|
+
> Metrik oracle currently cannot call your paid route at all. It can only reach
|
|
5
|
+
> your health route. Adopting `ProbeCapability` is what turns "the health
|
|
6
|
+
> endpoint answered" into "the paid route delivered". It is **opt-in**, and a
|
|
7
|
+
> gateway that does not adopt it is reported by the oracle as **unverifiable**
|
|
8
|
+
> for the paid route — never as passing.
|
|
9
|
+
|
|
10
|
+
## The problem
|
|
11
|
+
|
|
12
|
+
A gated listing's paid route requires an `InvocationCapability` (see
|
|
13
|
+
[`../src/capability/invocation-capability.ts`](../src/capability/invocation-capability.ts))
|
|
14
|
+
signed by **the stream's buyer**: 60s TTL, single-use nonce, bound to one method
|
|
15
|
+
and one path. The gateway recovers that signature and checks it against
|
|
16
|
+
`stream.buyer` on-chain.
|
|
17
|
+
|
|
18
|
+
The oracle is not a buyer. It holds no buyer key and has no stream. So for a
|
|
19
|
+
gated listing there is no credential a regional probe worker could safely
|
|
20
|
+
present, and the paid route goes unprobed by anybody — not remotely, and not
|
|
21
|
+
even by the coordinator.
|
|
22
|
+
|
|
23
|
+
That is a real gap in a claim the product makes. "The seller earns only for
|
|
24
|
+
intervals that verified" must not quietly mean "the health endpoint answered".
|
|
25
|
+
|
|
26
|
+
## The mechanism
|
|
27
|
+
|
|
28
|
+
A second EIP-712 type, `ProbeCapability`, signed by an **oracle signer**:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
ProbeCapability {
|
|
32
|
+
bytes32 serviceRef; // the service being probed
|
|
33
|
+
address oracle; // the minting signer; must equal the recovered signer
|
|
34
|
+
string method; // exactly one HTTP method
|
|
35
|
+
bytes32 pathHash; // keccak256 of exactly one request path
|
|
36
|
+
bytes32 nonce; // single-use
|
|
37
|
+
uint64 expiry; // ~30s
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
EIP-712 domain: `name = "Metrik Probe Capability"`, `version = "1"`, the
|
|
42
|
+
gateway's `chainId`, and `verifyingContract` = the `StreamEscrowV2` the gateway
|
|
43
|
+
already checks streams against. The domain name is deliberately **different**
|
|
44
|
+
from `"Metrik Invocation Capability"`, so a buyer's invocation signature can
|
|
45
|
+
never be replayed as a free probe and vice versa.
|
|
46
|
+
|
|
47
|
+
Transport: base64url in the `x-metrik-probe-capability` request header.
|
|
48
|
+
|
|
49
|
+
### Authority is public, not a shared secret
|
|
50
|
+
|
|
51
|
+
The gateway authorizes the probe iff the recovered signer is in
|
|
52
|
+
`StreamEscrowV2.getOracleSigners()` — a **public `view`** on the escrow. On the
|
|
53
|
+
live Base Sepolia deployment (`0x0f09f36Ccc05A7c9882F438721C08De314dFd46C`) that
|
|
54
|
+
returns three addresses today.
|
|
55
|
+
|
|
56
|
+
This is the whole reason the design beats "give the workers a credential":
|
|
57
|
+
|
|
58
|
+
- **Nothing to distribute.** No API key, no registration, no onboarding call.
|
|
59
|
+
A third-party seller performs the identical on-chain read and reaches the
|
|
60
|
+
identical verdict, with no trust in the oracle's say-so.
|
|
61
|
+
- **Nothing to leak.** The only secret is the oracle coordinator's signing key,
|
|
62
|
+
which never leaves it.
|
|
63
|
+
- **Revocation is already solved.** Remove a signer on the escrow and it stops
|
|
64
|
+
being able to probe within one signer-cache TTL (60s by default).
|
|
65
|
+
|
|
66
|
+
### No signing key leaves the coordinator
|
|
67
|
+
|
|
68
|
+
The oracle coordinator mints **one fresh capability per probe, per vantage** and
|
|
69
|
+
hands the encoded header to the worker alongside the nonce. Workers hold a
|
|
70
|
+
bearer token for the coordinator and nothing else. Compromising every regional
|
|
71
|
+
worker yields no ability to mint a capability, and no ability to probe anything
|
|
72
|
+
the coordinator did not already ask for — the capability is bound to one
|
|
73
|
+
service, one method, one path, one nonce and ~30 seconds.
|
|
74
|
+
|
|
75
|
+
One capability **per vantage**, not one per probe, because the nonce is
|
|
76
|
+
single-use: two vantages sharing a capability would see the second rejected as a
|
|
77
|
+
replay.
|
|
78
|
+
|
|
79
|
+
### A probe never consumes a buyer's budget
|
|
80
|
+
|
|
81
|
+
Three independent reasons, all structural rather than conventional:
|
|
82
|
+
|
|
83
|
+
1. A `ProbeCapability` carries **no `streamId` and no `buyer`**. There is no
|
|
84
|
+
stream identified for it to be billed against.
|
|
85
|
+
2. Accrual is only ever produced by an **oracle checkpoint keyed to a stream**.
|
|
86
|
+
A gateway call produces none, ever — the gateway is an authorizer and proxy,
|
|
87
|
+
not a meter.
|
|
88
|
+
3. In the reference gateway the probe branch is evaluated **first and returns
|
|
89
|
+
unconditionally**, so it can never fall through into the stream branch. An
|
|
90
|
+
authorized probe decision carries only the probe — no `stream`, no
|
|
91
|
+
capability, nothing billable. A test asserts the stream reader is never even
|
|
92
|
+
called.
|
|
93
|
+
|
|
94
|
+
The gateway additionally sets `x-metrik-probe: 1` on the **upstream** request so
|
|
95
|
+
your own metering and analytics can exclude verification traffic. It is
|
|
96
|
+
gateway-asserted: any inbound copy from a client is stripped first, so a paying
|
|
97
|
+
caller cannot mark its own billable request as a probe.
|
|
98
|
+
|
|
99
|
+
### Rate limiting: why 60/minute
|
|
100
|
+
|
|
101
|
+
Without a bound, an oracle-signed capability is a licence to consume your
|
|
102
|
+
service indefinitely for free.
|
|
103
|
+
|
|
104
|
+
The oracle checkpoints every ~15–22 seconds, so **one** vantage probes a given
|
|
105
|
+
service at most ~4 times a minute. T1 multi-vantage fans that out across at most
|
|
106
|
+
9 vantages (the coordinator plus the oracle's 8-worker cap), giving a worst-case
|
|
107
|
+
honest load of **~36 probes/minute**. The default budget is **60 per minute**:
|
|
108
|
+
comfortable headroom for a re-execution sample and clock jitter, while capping
|
|
109
|
+
the free-service surface at one request per second — far below anything
|
|
110
|
+
economically interesting as a way to get the service for nothing.
|
|
111
|
+
|
|
112
|
+
Tune it with `METRIK_GATEWAY_PROBE_MAX_PER_MINUTE`. A useful side effect: since
|
|
113
|
+
every capability is single-use and ~30s-lived, the rate limit is also what
|
|
114
|
+
bounds the replay cache — at most `maxPerMinute × ttl/60` probe nonces live at
|
|
115
|
+
once.
|
|
116
|
+
|
|
117
|
+
### Replay protection reuses the existing cache
|
|
118
|
+
|
|
119
|
+
The probe path calls the **same** `NonceReplayCache` the buyer path uses, so a
|
|
120
|
+
nonce can never be spent once as a probe and once as an invocation. The nonce is
|
|
121
|
+
consumed _before_ the rate-limit check, so a captured capability replayed at
|
|
122
|
+
volume is rejected as a replay rather than eating the honest probe budget, and
|
|
123
|
+
_before_ the on-chain signer read, so a flood cannot amplify into RPC load.
|
|
124
|
+
|
|
125
|
+
## Enabling it
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
METRIK_GATEWAY_PROBE_CAPABILITY=true # off by default
|
|
129
|
+
METRIK_GATEWAY_PROBE_MAX_PER_MINUTE=60 # optional
|
|
130
|
+
METRIK_GATEWAY_PROBE_SIGNER_CACHE_SECONDS=60 # optional
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
There is **no credential to configure**. The signer set is read from the
|
|
134
|
+
`METRIK_GATEWAY_RPC_URL` and escrow the gateway already uses.
|
|
135
|
+
|
|
136
|
+
Not using the reference gateway? Implement the verification in this exact order
|
|
137
|
+
— cheapest and most local first, so an unsigned or replayed flood cannot amplify
|
|
138
|
+
into RPC load:
|
|
139
|
+
|
|
140
|
+
1. Decode the `x-metrik-probe-capability` header; malformed → `403`.
|
|
141
|
+
2. `now >= expiry` → `403`.
|
|
142
|
+
3. Recover the EIP-712 signer; it must equal `capability.oracle` → else `403`.
|
|
143
|
+
4. `capability.method` must equal the request method → else `403`.
|
|
144
|
+
5. `keccak256(path)` must equal `capability.pathHash` (path only — no query, no
|
|
145
|
+
fragment, no trailing slash except root) → else `403`.
|
|
146
|
+
6. `capability.serviceRef` must be one you front → else `403`.
|
|
147
|
+
7. Consume `capability.nonce` single-use → replay is `403`.
|
|
148
|
+
8. Rate-limit → `429`.
|
|
149
|
+
9. `capability.oracle` must be in `getOracleSigners()` → else `403`. If you
|
|
150
|
+
cannot read the set, **deny** (`403`); do not serve on a stale set.
|
|
151
|
+
|
|
152
|
+
Then proxy upstream and **do not meter, bill or settle the call**.
|
|
153
|
+
|
|
154
|
+
## Failure modes, and what each one means to the oracle
|
|
155
|
+
|
|
156
|
+
Every denial is a distinct machine-readable `reason` in the JSON body:
|
|
157
|
+
|
|
158
|
+
| Reason | Status | What it means |
|
|
159
|
+
| ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
|
|
160
|
+
| `probe-not-enabled` | 403 | This gateway has not adopted `ProbeCapability`. The oracle reports the paid route **unverifiable**. |
|
|
161
|
+
| `malformed-probe-capability` | 403 | Header was not a decodable signed capability. |
|
|
162
|
+
| `probe-capability-expired` | 403 | Past `expiry`. |
|
|
163
|
+
| `probe-invalid-signature` | 403 | Signature does not recover to the claimed `oracle`. |
|
|
164
|
+
| `probe-method-mismatch` / `probe-path-mismatch` | 403 | Capability was not minted for this route. |
|
|
165
|
+
| `probe-service-ref-mismatch` | 403 | Minted for another service. |
|
|
166
|
+
| `probe-nonce-replayed` | 403 | Nonce already spent. |
|
|
167
|
+
| `probe-rate-limited` | 429 | Free-probe budget for this window is spent. |
|
|
168
|
+
| `probe-signer-not-authorized` | 403 | Signer is not in `getOracleSigners()`. |
|
|
169
|
+
| `probe-signer-set-unavailable` | 403 | The set could not be read fresh enough. Fail closed. |
|
|
170
|
+
| `ambiguous-probe-mode` | 400 | Request carried a probe capability _and_ a buyer capability or `X-PAYMENT`. Refused rather than guessed. |
|
|
171
|
+
|
|
172
|
+
## Honest limitations
|
|
173
|
+
|
|
174
|
+
- **This is an adoption ask.** We ship the reference implementation because we
|
|
175
|
+
run the reference gateway, but a third-party seller has to adopt it. Until
|
|
176
|
+
they do, their gated paid route stays health-route-only and the oracle says so
|
|
177
|
+
out loud rather than implying coverage it does not have.
|
|
178
|
+
- **A gated seller can stay unverifiable on purpose.** A hostile gateway can
|
|
179
|
+
simply answer `403` to every probe and remain in the "unverifiable" bucket.
|
|
180
|
+
That gains it nothing it does not already have today — under the oracle's
|
|
181
|
+
`strict` enforcement an unverifiable paid route accrues nothing, and under
|
|
182
|
+
`eligible` it is exactly today's health-route-only behaviour, counted and
|
|
183
|
+
surfaced. What it can never do is be counted as _passing_.
|
|
184
|
+
- **Delivery, not correctness.** A passing probe is evidence the paid route
|
|
185
|
+
produced a fresh, spec-conforming response for _this_ challenge. It is not a
|
|
186
|
+
proof the output is correct. See
|
|
187
|
+
[`../../streamproof-protocol/docs/verification-model.md`](https://github.com/Absol-Labs/metrik-protocol/blob/main/docs/verification-model.md).
|
|
188
|
+
- **The signer set is federated today.** All three addresses in
|
|
189
|
+
`getOracleSigners()` are keys held by one process, and one of them operates
|
|
190
|
+
the live listings. `ProbeCapability` inherits that posture exactly — it makes
|
|
191
|
+
the _paid route_ checkable, not the verifier independent.
|
package/docs/quickstart.md
CHANGED
|
@@ -293,6 +293,40 @@ const { reclaimResult } = await agent.reclaimStream({
|
|
|
293
293
|
escape-window rules, and `claimed + fees + reclaimed == deposit` conserves the escrowed
|
|
294
294
|
funds exactly.
|
|
295
295
|
|
|
296
|
+
### 7b. Or pay a seller over x402 (no gas needed)
|
|
297
|
+
|
|
298
|
+
A Metrik x402 seller (an HTTP `402` with an x402 v2 `exact` quote) can be paid in one
|
|
299
|
+
call. The payment opens the same kind of stream — `deposit = price`, earned per verified
|
|
300
|
+
second — and the same spend mandate bounds it before anything is signed:
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
import { defaultNetwork } from "@absol-labs/agent";
|
|
304
|
+
import { payX402WithMandate } from "@absol-labs/agent/x402-buyer";
|
|
305
|
+
|
|
306
|
+
const paid = await payX402WithMandate({
|
|
307
|
+
url: "https://x402.137.23.50.249.sslip.io/transform",
|
|
308
|
+
init: {
|
|
309
|
+
method: "POST",
|
|
310
|
+
headers: { "content-type": "application/json" },
|
|
311
|
+
body: '{"text":"# hi"}',
|
|
312
|
+
},
|
|
313
|
+
signer: account, // USDC only, no ETH
|
|
314
|
+
network: defaultNetwork(),
|
|
315
|
+
signedMandate,
|
|
316
|
+
spentSoFarUsdc: 0n,
|
|
317
|
+
nowSeconds: Math.floor(Date.now() / 1000),
|
|
318
|
+
});
|
|
319
|
+
console.log(paid.metrikStreamOpener); // streamId, opener, refundUrl, deposit, rate
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Getting the unearned part back is not automatic: close, then reclaim, through the seller's
|
|
323
|
+
gasless relay (the `metrik refund` command below, or the SDK's `refundClient`).
|
|
324
|
+
|
|
325
|
+
Full details, including the mandate mapping: [the buyer section](./x402.md).
|
|
326
|
+
|
|
327
|
+
From a terminal: `metrik pay <url> --json '{"text":"# hi"}' --max-amount 0.1`, then
|
|
328
|
+
`metrik refund <streamId> --refund-url <url> --close --reclaim`.
|
|
329
|
+
|
|
296
330
|
---
|
|
297
331
|
|
|
298
332
|
## 8. Five ways to integrate
|
|
@@ -394,4 +428,5 @@ Metrik proves **verified delivery** (responded, correctly-shaped, within SLA to
|
|
|
394
428
|
traffic) — **not output correctness** (that the model's answer is right). Pitch and treat
|
|
395
429
|
it accordingly. The full journey, run live against the real deployed escrow on Base
|
|
396
430
|
Sepolia, is [`scripts/e2e-cdp.ts`](../scripts/e2e-cdp.ts) (`pnpm build:e2e && pnpm
|
|
397
|
-
e2e:cdp`) — the working reference for everything above
|
|
431
|
+
e2e:cdp`) — the working reference for everything above; its x402 leg is
|
|
432
|
+
[`scripts/e2e-x402.ts`](../scripts/e2e-x402.ts) (`pnpm e2e:x402`).
|
package/docs/threat-model.md
CHANGED
|
@@ -22,6 +22,9 @@ In scope:
|
|
|
22
22
|
- the mandate-gated SDK wrapper in [`src/sdk/client.ts`](../src/sdk/client.ts)
|
|
23
23
|
- Metrik `402` verified-stream opens in [`src/x402/facilitator.ts`](../src/x402/facilitator.ts)
|
|
24
24
|
(a Metrik-native challenge flow, not the x402 protocol — see [docs/x402.md](./x402.md))
|
|
25
|
+
- the x402 v2 opener facilitator in [`src/x402-opener/`](../src/x402-opener/) and the
|
|
26
|
+
gateway's x402 v2 mode in [`src/gateway/x402-opener-mode.ts`](../src/gateway/x402-opener-mode.ts)
|
|
27
|
+
(both off by default — see [docs/x402.md](./x402.md))
|
|
25
28
|
- MCP fund-moving tools in [`src/mcp/server.ts`](../src/mcp/server.ts)
|
|
26
29
|
- zkTLS consumer delivery proofs in [`src/zktls/reclaim.ts`](../src/zktls/reclaim.ts)
|
|
27
30
|
- wallet custody in [`src/wallet/provider.ts`](../src/wallet/provider.ts)
|
|
@@ -43,6 +46,23 @@ Out of scope:
|
|
|
43
46
|
| Mandate replay | A previously valid signed mandate is replayed after revocation or outside the intended lifetime. | Mandates are EIP-712 signed over `mandateId`, `owner`, `chainId`, `issuedAt`, expiry, and policy hashes. `checkMandate()` verifies signature, revocation, expiry, then policy. Integrators can revoke by `mandateId` and track cumulative spend. | [`src/mandates/mandate.ts`](../src/mandates/mandate.ts), [`test/mandate.test.ts`](../test/mandate.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts) | Replay protection is only as strong as revocation and cumulative-spend state freshness. The signed payload itself is bound to one chain and one owner, but revocation is local state today. |
|
|
44
47
|
| False or weak delivery evidence | A consumer submits a proof that is validly signed by the zkTLS system but not bound to the intended request or stream context. | The Reclaim adapter re-verifies every proof locally against the exact URL/method/body/match/redaction spec supplied by the caller, and binds the proof context to buyer/stream metadata before returning it. MCP only exposes the public-request subset so secrets do not leak through tool arguments. | [`src/zktls/reclaim.ts`](../src/zktls/reclaim.ts), [`src/x402/facilitator.ts`](../src/x402/facilitator.ts), [`src/mcp/server.ts`](../src/mcp/server.ts), [`test/reclaim.test.ts`](../test/reclaim.test.ts), [`test/x402.test.ts`](../test/x402.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts) | L2 is still consumer-supplied evidence. A malicious consumer can withhold proofs, and settlement must still treat L1/oracle evidence as authoritative on failure, ambiguity, and expiry. |
|
|
45
48
|
|
|
49
|
+
## x402 v2 opener threats
|
|
50
|
+
|
|
51
|
+
The opener path moves a buyer's USDC only under that buyer's own EIP-3009
|
|
52
|
+
signature, so no agent-held key spends and no spend mandate applies; the
|
|
53
|
+
threats are about where the signed payment can end up.
|
|
54
|
+
|
|
55
|
+
| Threat | Mitigation | Code / tests |
|
|
56
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
57
|
+
| A stock x402 facilitator (or anyone holding the signed payload) submits `transferWithAuthorization` to the opener directly, stranding the payment | Only `MetrikOpenerExactScheme` settles, via `deployAndSettle`; its stock verifier gets a signer that cannot broadcast. The gateway refuses to start, and fails closed (503) later, unless the facilitator's `/supported` marker names its exact factory/escrow/token/chain. `PAYMENT-SIGNATURE` is never forwarded upstream. No discovery extension is ever declared. | `src/x402-opener/scheme.ts`, `src/gateway/x402-opener-mode.ts`; `test/x402-opener-gateway.test.ts`, `test/x402-opener.fork.int.test.ts` |
|
|
58
|
+
| A forged or tampered `payTo`, terms or listing redirects funds | `payTo` must equal `factory.predict(terms)` read on-chain (never code/codehash); `(operator, serviceRef)` must resolve to exactly one operator-signed listing via discovery signature verification; amount bounded by `rate × maxDuration` | `test/x402-opener-scheme.test.ts`, `test/x402-opener-config.test.ts` |
|
|
59
|
+
| Success reported without a stream | `settle` returns `success: true` only from a mined receipt carrying the escrow `StreamOpened` (buyer = opener) and the opener `StreamOpenedFor` for this payer/nonce/amount | `test/x402-opener-scheme.test.ts` |
|
|
60
|
+
| One payment buys several served responses (a replayed `PAYMENT-SIGNATURE`) | At most one successful settle per authorization (chain + asset + payer + nonce) per facilitator instance; the gateway refuses an in-flight or settled authorization with `409` before the upstream runs. In-memory, per instance: run one instance | `test/x402-opener-scheme.test.ts`, `test/x402-opener-gateway.test.ts`, `test/x402-opener-regressions.fork.int.test.ts` |
|
|
61
|
+
| Concurrent payers fail on the relayer nonce after being served | Relayer submissions are serialized | same |
|
|
62
|
+
| Dust payments drain relayer gas; unauthenticated `/verify` amplifies RPC load | Minimum amount (default 0.01 USDC, advertised; the gateway refuses a lower price), `/settle` rate limit per token, `/verify` requires the token by default | `test/x402-opener-config.test.ts`, fork regressions |
|
|
63
|
+
| A failed upstream still charges the buyer | The gateway settles only when the upstream status is `< 400`, and a failed settle sends no body | `test/x402-opener-gateway.test.ts`, fork E2E |
|
|
64
|
+
| Relayer key or facilitator token leaks | Env only, never logged or echoed in errors; `/settle` requires the bearer token (constant-time compared) | `src/x402-opener/facilitator-server.ts`; `test/x402-opener-config.test.ts` |
|
|
65
|
+
|
|
46
66
|
## Fund-Moving Paths
|
|
47
67
|
|
|
48
68
|
These are the autonomous fund-moving paths in the current agent layer:
|