@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
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import { MetrikClient } from "@absol-labs/sdk";
|
|
2
1
|
import { isAddress, isHex, type Address, type Hex } from "viem";
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
evaluateX402Request,
|
|
6
|
-
X402_PAYMENT_HEADER,
|
|
7
|
-
type AcceptedX402Payment,
|
|
8
|
-
type GatewayX402Mode,
|
|
9
|
-
} from "./x402-mode.js";
|
|
10
|
-
import type { X402PaymentRequiredBody } from "../x402/payment-requirements.js";
|
|
11
3
|
import {
|
|
12
4
|
CAPABILITY_HEADER_NAME,
|
|
13
5
|
decodeCapabilityHeader,
|
|
@@ -17,6 +9,29 @@ import {
|
|
|
17
9
|
type InvocationCapabilityDomainInput,
|
|
18
10
|
type SignedInvocationCapability,
|
|
19
11
|
} from "../capability/invocation-capability.js";
|
|
12
|
+
import {
|
|
13
|
+
decodeProbeCapabilityHeader,
|
|
14
|
+
hashProbePath,
|
|
15
|
+
InvalidProbeCapabilityHeaderError,
|
|
16
|
+
PROBE_CAPABILITY_HEADER_NAME,
|
|
17
|
+
recoverProbeCapabilitySigner,
|
|
18
|
+
type ProbeCapabilityDomainInput,
|
|
19
|
+
type SignedProbeCapability,
|
|
20
|
+
} from "../capability/probe-capability.js";
|
|
21
|
+
import {
|
|
22
|
+
CachedOracleSignerSet,
|
|
23
|
+
createSdkOracleSignerSetReader,
|
|
24
|
+
FixedWindowProbeRateLimiter,
|
|
25
|
+
type GatewayProbeMode,
|
|
26
|
+
type ProbeAuthorization,
|
|
27
|
+
type ProbeRateLimiter,
|
|
28
|
+
} from "./probe-auth.js";
|
|
29
|
+
import { defaultNetwork, readOnlyMetrikClient } from "../network.js";
|
|
30
|
+
import {
|
|
31
|
+
isVerifiedSignedRateBounds,
|
|
32
|
+
rateOutsideBounds,
|
|
33
|
+
type SignedRateBounds,
|
|
34
|
+
} from "./signed-rate-bounds.js";
|
|
20
35
|
|
|
21
36
|
/**
|
|
22
37
|
* Seller-side caller-auth gateway (metrik-agent#63, impl of #62 part 1/2).
|
|
@@ -78,19 +93,43 @@ export type CallerAuthDenialReason =
|
|
|
78
93
|
| "stream-not-funded"
|
|
79
94
|
| "stream-state-stale"
|
|
80
95
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
96
|
+
* The stream's on-chain `ratePerSecond` is outside the operator-SIGNED
|
|
97
|
+
* `minRatePerSecond`/`maxRatePerSecond` of this service's descriptor
|
|
98
|
+
* (metrik-contracts#41: the escrow accepts any non-zero rate, so a buyer
|
|
99
|
+
* calling it directly could otherwise open an underpriced stream and be
|
|
100
|
+
* served). Irreversible: the rate is fixed at open.
|
|
86
101
|
*/
|
|
87
|
-
| "
|
|
102
|
+
| "stream-rate-out-of-bounds"
|
|
88
103
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* path while they believe they paid through the other.
|
|
104
|
+
* Signed rate bounds are configured but the stream view carries no
|
|
105
|
+
* `ratePerSecond`, so the band cannot be checked. Fail closed.
|
|
92
106
|
*/
|
|
93
|
-
| "
|
|
107
|
+
| "stream-rate-unknown"
|
|
108
|
+
/**
|
|
109
|
+
* The request carried an oracle probe capability AND a buyer capability or an
|
|
110
|
+
* `X-PAYMENT` header. Refused rather than guessed: a probe is free and unbilled,
|
|
111
|
+
* a buyer call is neither, and the two must never be conflated.
|
|
112
|
+
*/
|
|
113
|
+
| "ambiguous-probe-mode"
|
|
114
|
+
/**
|
|
115
|
+
* A probe capability was presented but this gateway has probe verification
|
|
116
|
+
* turned off. Distinct from the malformed/invalid reasons: it tells the
|
|
117
|
+
* oracle the paid route is UNVERIFIABLE here, not that it failed.
|
|
118
|
+
*/
|
|
119
|
+
| "probe-not-enabled"
|
|
120
|
+
| "malformed-probe-capability"
|
|
121
|
+
| "probe-capability-expired"
|
|
122
|
+
| "probe-invalid-signature"
|
|
123
|
+
| "probe-method-mismatch"
|
|
124
|
+
| "probe-path-mismatch"
|
|
125
|
+
| "probe-service-ref-mismatch"
|
|
126
|
+
| "probe-nonce-replayed"
|
|
127
|
+
/** The recovered signer is not in the escrow's `getOracleSigners()` set. */
|
|
128
|
+
| "probe-signer-not-authorized"
|
|
129
|
+
/** The signer set could not be read fresh enough to decide. Fail closed. */
|
|
130
|
+
| "probe-signer-set-unavailable"
|
|
131
|
+
/** The free-probe budget for this window is spent. */
|
|
132
|
+
| "probe-rate-limited";
|
|
94
133
|
|
|
95
134
|
/**
|
|
96
135
|
* Default freshness bound for on-chain stream state, in seconds. Base blocks
|
|
@@ -113,7 +152,9 @@ const DENIAL_PRECEDENCE: readonly CallerAuthDenialReason[] = [
|
|
|
113
152
|
"stream-expired",
|
|
114
153
|
"buyer-mismatch",
|
|
115
154
|
"service-ref-mismatch",
|
|
155
|
+
"stream-rate-out-of-bounds",
|
|
116
156
|
"stream-not-funded",
|
|
157
|
+
"stream-rate-unknown",
|
|
117
158
|
"stream-state-stale",
|
|
118
159
|
"stream-not-found",
|
|
119
160
|
];
|
|
@@ -131,28 +172,38 @@ const DENIAL_PRECEDENCE: readonly CallerAuthDenialReason[] = [
|
|
|
131
172
|
const TERMINAL_DENIALS: ReadonlySet<CallerAuthDenialReason> = new Set([
|
|
132
173
|
"stream-not-active",
|
|
133
174
|
"stream-not-funded",
|
|
175
|
+
// `ratePerSecond` is fixed at open and the signed band is this process's
|
|
176
|
+
// configuration, so an out-of-band stream stays out of band.
|
|
177
|
+
"stream-rate-out-of-bounds",
|
|
134
178
|
]);
|
|
135
179
|
|
|
180
|
+
/**
|
|
181
|
+
* A probe carrying an `X-PAYMENT` header is refused as `ambiguous-probe-mode`.
|
|
182
|
+
* This gateway implements no per-call payment mode (the x402 v1 integration was
|
|
183
|
+
* removed in metrik-agent#115), but the refusal is kept deliberately: a probe
|
|
184
|
+
* is free, unbilled verification traffic and must never be mixed with anything
|
|
185
|
+
* that looks like a payment, and keeping it leaves the deployed gateway's
|
|
186
|
+
* behaviour byte-for-byte unchanged.
|
|
187
|
+
*/
|
|
188
|
+
const PAYMENT_HEADER_REFUSED_ON_PROBES = "x-payment";
|
|
189
|
+
|
|
136
190
|
export interface CallerAuthDecision {
|
|
137
191
|
readonly authorized: boolean;
|
|
138
192
|
readonly reason?: CallerAuthDenialReason;
|
|
139
193
|
/** Set only when `authorized === false`. */
|
|
140
|
-
readonly httpStatus?: 400 | 402 | 403;
|
|
194
|
+
readonly httpStatus?: 400 | 402 | 403 | 429;
|
|
141
195
|
/** Set only when `authorized === true` via the Metrik stream path. */
|
|
142
196
|
readonly stream?: GatewayStreamView;
|
|
143
|
-
/** The decoded (but not necessarily valid) capability, when one was present. */
|
|
144
|
-
readonly capability?: SignedInvocationCapability;
|
|
145
197
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
198
|
+
* Set only when `authorized === true` via the ORACLE PROBE path. Mutually
|
|
199
|
+
* exclusive with {@link stream} by construction: the probe branch returns
|
|
200
|
+
* before a stream is ever produced, so an authorized probe can never draw on
|
|
201
|
+
* a stream's budget. It is
|
|
202
|
+
* verification traffic and MUST NOT be metered or billed.
|
|
148
203
|
*/
|
|
149
|
-
readonly
|
|
150
|
-
/**
|
|
151
|
-
|
|
152
|
-
* path. The caller MUST settle it (see `./x402-mode.ts`) — verification alone
|
|
153
|
-
* moves no money.
|
|
154
|
-
*/
|
|
155
|
-
readonly x402Payment?: AcceptedX402Payment;
|
|
204
|
+
readonly probe?: ProbeAuthorization;
|
|
205
|
+
/** The decoded (but not necessarily valid) capability, when one was present. */
|
|
206
|
+
readonly capability?: SignedInvocationCapability;
|
|
156
207
|
}
|
|
157
208
|
|
|
158
209
|
/** The minimal on-chain stream fields the gateway needs to authorize a call. */
|
|
@@ -163,6 +214,13 @@ export interface GatewayStreamView {
|
|
|
163
214
|
readonly claimedCumulative: bigint;
|
|
164
215
|
readonly expiresAt: number;
|
|
165
216
|
readonly status: "active" | "closed";
|
|
217
|
+
/**
|
|
218
|
+
* The stream's contracted `ratePerSecond` (USDC base units per verified
|
|
219
|
+
* second), fixed at open. Required when the gateway enforces operator-signed
|
|
220
|
+
* rate bounds; a view without it is refused (`stream-rate-unknown`) there.
|
|
221
|
+
* The default SDK reader always reports it.
|
|
222
|
+
*/
|
|
223
|
+
readonly ratePerSecond?: bigint;
|
|
166
224
|
/**
|
|
167
225
|
* The chain head this view was observed against. Readers SHOULD report it:
|
|
168
226
|
* when present, the gateway rejects the view outright if the block is older
|
|
@@ -235,11 +293,10 @@ export class UnknownStreamGatewayError extends Error {
|
|
|
235
293
|
export function createSdkStreamReader(options: {
|
|
236
294
|
readonly escrowAddress: Address;
|
|
237
295
|
readonly rpcUrl: string;
|
|
296
|
+
/** Chain of the escrow; must be a registered network. Default: the registry default. */
|
|
297
|
+
readonly chainId?: number;
|
|
238
298
|
}): StreamReader {
|
|
239
|
-
const metrik =
|
|
240
|
-
escrow: options.escrowAddress,
|
|
241
|
-
rpcUrl: options.rpcUrl,
|
|
242
|
-
});
|
|
299
|
+
const metrik = readOnlyMetrikClient(options);
|
|
243
300
|
return {
|
|
244
301
|
async getStream(streamId) {
|
|
245
302
|
try {
|
|
@@ -258,6 +315,7 @@ export function createSdkStreamReader(options: {
|
|
|
258
315
|
claimedCumulative: stream.claimedCumulative,
|
|
259
316
|
expiresAt: stream.expiresAt,
|
|
260
317
|
status: stream.status,
|
|
318
|
+
ratePerSecond: stream.ratePerSecond,
|
|
261
319
|
observedAt: {
|
|
262
320
|
blockNumber: block.number,
|
|
263
321
|
blockTimestamp: Number(block.timestamp),
|
|
@@ -316,7 +374,7 @@ export interface CallerAuthGatewayConfig {
|
|
|
316
374
|
readonly serviceRef: Hex;
|
|
317
375
|
/** Additional service refs accepted during signed-descriptor migrations. */
|
|
318
376
|
readonly serviceRefs?: readonly Hex[];
|
|
319
|
-
/** Chain id for EIP-712 domain separation. Default
|
|
377
|
+
/** Chain id for EIP-712 domain separation and the default readers. Default: the registry's default network. */
|
|
320
378
|
readonly chainId?: number;
|
|
321
379
|
/** Capability header name. Default {@link CAPABILITY_HEADER_NAME}. */
|
|
322
380
|
readonly headerName?: string;
|
|
@@ -349,12 +407,27 @@ export interface CallerAuthGatewayConfig {
|
|
|
349
407
|
/** Injectable clock (unix seconds), for tests. */
|
|
350
408
|
readonly now?: () => number;
|
|
351
409
|
/**
|
|
352
|
-
* Optional
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
410
|
+
* Optional ORACLE PROBE mode. When set, a request carrying a valid
|
|
411
|
+
* oracle-signed `ProbeCapability` is authorized and proxied WITHOUT any
|
|
412
|
+
* stream, payment or metering, so the neutral verifier can exercise this
|
|
413
|
+
* gateway's PAID route even though the listing is gated.
|
|
414
|
+
*
|
|
415
|
+
* OFF by default. A gateway that leaves it unset behaves byte for byte as
|
|
416
|
+
* before and answers a probe with `probe-not-enabled` / `403` — which the
|
|
417
|
+
* oracle reports as UNVERIFIABLE (health-route-only), never as passing.
|
|
418
|
+
*/
|
|
419
|
+
readonly probe?: GatewayProbeMode;
|
|
420
|
+
/**
|
|
421
|
+
* Operator-SIGNED rate bounds to enforce on the capability path, one per
|
|
422
|
+
* served serviceRef (metrik-contracts#41). Each entry must come from
|
|
423
|
+
* {@link verifySignedRateBounds} (or `loadSignedRateBoundsFile`) and name one
|
|
424
|
+
* of this gateway's service refs. A stream whose serviceRef has bounds is
|
|
425
|
+
* served only while its on-chain `ratePerSecond` lies inside them.
|
|
426
|
+
*
|
|
427
|
+
* Unset = no rate enforcement here (the previous behaviour); the reference
|
|
428
|
+
* server warns when it starts without them.
|
|
356
429
|
*/
|
|
357
|
-
readonly
|
|
430
|
+
readonly signedRateBounds?: readonly SignedRateBounds[];
|
|
358
431
|
}
|
|
359
432
|
|
|
360
433
|
export interface CallerAuthRequestInput {
|
|
@@ -380,7 +453,11 @@ export class CallerAuthGateway {
|
|
|
380
453
|
private readonly domain: InvocationCapabilityDomainInput;
|
|
381
454
|
private readonly serviceRefs: ReadonlySet<string>;
|
|
382
455
|
private readonly now: () => number;
|
|
383
|
-
private readonly
|
|
456
|
+
private readonly probeHeaderName: string;
|
|
457
|
+
private readonly probeDomain: ProbeCapabilityDomainInput;
|
|
458
|
+
private readonly probeSigners: CachedOracleSignerSet | undefined;
|
|
459
|
+
private readonly probeRateLimiter: ProbeRateLimiter | undefined;
|
|
460
|
+
private readonly rateBounds: ReadonlyMap<string, SignedRateBounds>;
|
|
384
461
|
|
|
385
462
|
constructor(config: CallerAuthGatewayConfig) {
|
|
386
463
|
if (!isAddress(config.escrowAddress)) {
|
|
@@ -398,7 +475,29 @@ export class CallerAuthGateway {
|
|
|
398
475
|
);
|
|
399
476
|
}
|
|
400
477
|
|
|
478
|
+
const chainId = config.chainId ?? defaultNetwork().chain.id;
|
|
401
479
|
this.serviceRefs = new Set(serviceRefs.map((value) => value.toLowerCase()));
|
|
480
|
+
const rateBounds = new Map<string, SignedRateBounds>();
|
|
481
|
+
for (const bounds of config.signedRateBounds ?? []) {
|
|
482
|
+
if (!isVerifiedSignedRateBounds(bounds)) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
"signedRateBounds entries must come from verifySignedRateBounds() / loadSignedRateBoundsFile(); an unverified object is not operator-signed",
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
const key = bounds.serviceRef.toLowerCase();
|
|
488
|
+
if (!this.serviceRefs.has(key)) {
|
|
489
|
+
throw new Error(
|
|
490
|
+
`signed rate bounds for ${bounds.serviceRef} are not a service ref this gateway serves`,
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
if (rateBounds.has(key)) {
|
|
494
|
+
throw new Error(
|
|
495
|
+
`more than one set of signed rate bounds for ${bounds.serviceRef}`,
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
rateBounds.set(key, bounds);
|
|
499
|
+
}
|
|
500
|
+
this.rateBounds = rateBounds;
|
|
402
501
|
this.headerName = (
|
|
403
502
|
config.headerName ?? CAPABILITY_HEADER_NAME
|
|
404
503
|
).toLowerCase();
|
|
@@ -407,6 +506,7 @@ export class CallerAuthGateway {
|
|
|
407
506
|
createSdkStreamReader({
|
|
408
507
|
escrowAddress: config.escrowAddress,
|
|
409
508
|
rpcUrl: config.rpcUrl as string,
|
|
509
|
+
chainId,
|
|
410
510
|
});
|
|
411
511
|
const corroborating =
|
|
412
512
|
config.corroboratingStreamReaders ??
|
|
@@ -414,6 +514,7 @@ export class CallerAuthGateway {
|
|
|
414
514
|
createSdkStreamReader({
|
|
415
515
|
escrowAddress: config.escrowAddress,
|
|
416
516
|
rpcUrl,
|
|
517
|
+
chainId,
|
|
417
518
|
}),
|
|
418
519
|
);
|
|
419
520
|
if (corroborating.length > MAX_CORROBORATING_STREAM_READERS) {
|
|
@@ -433,11 +534,66 @@ export class CallerAuthGateway {
|
|
|
433
534
|
config.revocationSet ?? new InMemoryStreamRevocationSet();
|
|
434
535
|
this.nonceCache = config.nonceCache ?? new InMemoryNonceReplayCache();
|
|
435
536
|
this.domain = {
|
|
436
|
-
chainId
|
|
537
|
+
chainId,
|
|
437
538
|
verifyingContract: config.escrowAddress,
|
|
438
539
|
};
|
|
439
540
|
this.now = config.now ?? (() => Math.floor(Date.now() / 1000));
|
|
440
|
-
|
|
541
|
+
|
|
542
|
+
// Probe mode shares the chain binding with the invocation domain (same
|
|
543
|
+
// escrow, same chain) but a DIFFERENT EIP-712 domain name, so neither
|
|
544
|
+
// signature is ever valid as the other.
|
|
545
|
+
this.probeDomain = {
|
|
546
|
+
chainId,
|
|
547
|
+
verifyingContract: config.escrowAddress,
|
|
548
|
+
};
|
|
549
|
+
this.probeHeaderName = (
|
|
550
|
+
config.probe?.headerName ?? PROBE_CAPABILITY_HEADER_NAME
|
|
551
|
+
).toLowerCase();
|
|
552
|
+
if (this.probeHeaderName === this.headerName) {
|
|
553
|
+
throw new Error(
|
|
554
|
+
"the probe capability header must differ from the invocation capability header",
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
if (config.probe === undefined) {
|
|
558
|
+
this.probeSigners = undefined;
|
|
559
|
+
this.probeRateLimiter = undefined;
|
|
560
|
+
} else {
|
|
561
|
+
const reader =
|
|
562
|
+
config.probe.signerSetReader ??
|
|
563
|
+
(config.rpcUrl === undefined
|
|
564
|
+
? undefined
|
|
565
|
+
: createSdkOracleSignerSetReader({
|
|
566
|
+
escrowAddress: config.escrowAddress,
|
|
567
|
+
rpcUrl: config.rpcUrl,
|
|
568
|
+
chainId,
|
|
569
|
+
}));
|
|
570
|
+
if (reader === undefined) {
|
|
571
|
+
throw new Error(
|
|
572
|
+
"probe mode requires rpcUrl unless an explicit signerSetReader is supplied",
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
this.probeSigners = new CachedOracleSignerSet(
|
|
576
|
+
reader,
|
|
577
|
+
config.probe.signerCacheSeconds,
|
|
578
|
+
this.now,
|
|
579
|
+
);
|
|
580
|
+
this.probeRateLimiter =
|
|
581
|
+
config.probe.rateLimiter ??
|
|
582
|
+
new FixedWindowProbeRateLimiter(
|
|
583
|
+
config.probe.maxProbesPerMinute,
|
|
584
|
+
this.now,
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/** Lower-cased header name that carries the buyer's invocation capability. */
|
|
590
|
+
get capabilityHeaderName(): string {
|
|
591
|
+
return this.headerName;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/** Lower-cased header name that carries an oracle probe capability. */
|
|
595
|
+
get probeCapabilityHeaderName(): string {
|
|
596
|
+
return this.probeHeaderName;
|
|
441
597
|
}
|
|
442
598
|
|
|
443
599
|
async authorize(
|
|
@@ -447,31 +603,27 @@ export class CallerAuthGateway {
|
|
|
447
603
|
const hasCapabilityHeader =
|
|
448
604
|
headerValue !== undefined && headerValue.length > 0;
|
|
449
605
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
return
|
|
469
|
-
authorized: false,
|
|
470
|
-
reason: "x402-payment-required",
|
|
471
|
-
httpStatus: 402,
|
|
472
|
-
x402PaymentRequired: evaluated.body,
|
|
473
|
-
};
|
|
606
|
+
// ── Oracle probe path ────────────────────────────────────────────────
|
|
607
|
+
// Evaluated FIRST and returning unconditionally, so an authorized probe can
|
|
608
|
+
// never fall through into the stream branch. That ordering is the
|
|
609
|
+
// structural guarantee that a probe consumes no budget: no `stream` is ever
|
|
610
|
+
// produced on this path.
|
|
611
|
+
const probeHeaderValue = lookupHeader(
|
|
612
|
+
request.headers,
|
|
613
|
+
this.probeHeaderName,
|
|
614
|
+
);
|
|
615
|
+
if (probeHeaderValue !== undefined && probeHeaderValue.length > 0) {
|
|
616
|
+
const paymentHeader = lookupHeader(
|
|
617
|
+
request.headers,
|
|
618
|
+
PAYMENT_HEADER_REFUSED_ON_PROBES,
|
|
619
|
+
);
|
|
620
|
+
if (
|
|
621
|
+
hasCapabilityHeader ||
|
|
622
|
+
(paymentHeader !== undefined && paymentHeader.trim().length > 0)
|
|
623
|
+
) {
|
|
624
|
+
return deny("ambiguous-probe-mode", 400);
|
|
474
625
|
}
|
|
626
|
+
return this.authorizeProbe(probeHeaderValue, request);
|
|
475
627
|
}
|
|
476
628
|
|
|
477
629
|
if (!hasCapabilityHeader) {
|
|
@@ -572,6 +724,95 @@ export class CallerAuthGateway {
|
|
|
572
724
|
return { authorized: true, stream: freshestView(views), capability };
|
|
573
725
|
}
|
|
574
726
|
|
|
727
|
+
/**
|
|
728
|
+
* Authorize one oracle probe. Cheapest, most local gates first; the on-chain
|
|
729
|
+
* signer-set read is last so an unsigned or replayed flood cannot amplify
|
|
730
|
+
* into RPC load. Every failure mode is distinct and fail-closed.
|
|
731
|
+
*/
|
|
732
|
+
private async authorizeProbe(
|
|
733
|
+
headerValue: string,
|
|
734
|
+
request: CallerAuthRequestInput,
|
|
735
|
+
): Promise<CallerAuthDecision> {
|
|
736
|
+
const signerSet = this.probeSigners;
|
|
737
|
+
const rateLimiter = this.probeRateLimiter;
|
|
738
|
+
if (signerSet === undefined || rateLimiter === undefined) {
|
|
739
|
+
// Probe mode is off. Say so precisely: the oracle distinguishes
|
|
740
|
+
// "unverifiable here" from "the paid route failed".
|
|
741
|
+
return deny("probe-not-enabled", 403);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
let capability: SignedProbeCapability;
|
|
745
|
+
try {
|
|
746
|
+
capability = decodeProbeCapabilityHeader(headerValue);
|
|
747
|
+
} catch (error) {
|
|
748
|
+
if (error instanceof InvalidProbeCapabilityHeaderError) {
|
|
749
|
+
return deny("malformed-probe-capability", 403);
|
|
750
|
+
}
|
|
751
|
+
throw error;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const nowSeconds = this.now();
|
|
755
|
+
if (nowSeconds >= capability.expiry) {
|
|
756
|
+
return deny("probe-capability-expired", 403);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
let signer: Address;
|
|
760
|
+
try {
|
|
761
|
+
signer = await recoverProbeCapabilitySigner(
|
|
762
|
+
capability,
|
|
763
|
+
this.probeDomain,
|
|
764
|
+
capability.signature as Hex,
|
|
765
|
+
);
|
|
766
|
+
} catch {
|
|
767
|
+
return deny("probe-invalid-signature", 403);
|
|
768
|
+
}
|
|
769
|
+
if (signer.toLowerCase() !== capability.oracle.toLowerCase()) {
|
|
770
|
+
return deny("probe-invalid-signature", 403);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (capability.method.toUpperCase() !== request.method.toUpperCase()) {
|
|
774
|
+
return deny("probe-method-mismatch", 403);
|
|
775
|
+
}
|
|
776
|
+
if (
|
|
777
|
+
hashProbePath(request.path).toLowerCase() !==
|
|
778
|
+
capability.pathHash.toLowerCase()
|
|
779
|
+
) {
|
|
780
|
+
return deny("probe-path-mismatch", 403);
|
|
781
|
+
}
|
|
782
|
+
if (!this.serviceRefs.has(capability.serviceRef.toLowerCase())) {
|
|
783
|
+
return deny("probe-service-ref-mismatch", 403);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Replay BEFORE the budget check: a captured capability replayed at volume
|
|
787
|
+
// must be rejected as a replay, not silently eat the honest probe budget.
|
|
788
|
+
// The SAME nonce cache as the buyer path, so a nonce can never be spent
|
|
789
|
+
// once as a probe and once as an invocation.
|
|
790
|
+
if (!this.nonceCache.consume(capability.nonce as Hex, capability.expiry)) {
|
|
791
|
+
return deny("probe-nonce-replayed", 403);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (!rateLimiter.tryConsume()) {
|
|
795
|
+
return deny("probe-rate-limited", 429);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const signers = await signerSet.resolve();
|
|
799
|
+
if (signers === undefined) {
|
|
800
|
+
return deny("probe-signer-set-unavailable", 403);
|
|
801
|
+
}
|
|
802
|
+
if (!signers.has(signer.toLowerCase())) {
|
|
803
|
+
return deny("probe-signer-not-authorized", 403);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
return {
|
|
807
|
+
authorized: true,
|
|
808
|
+
probe: {
|
|
809
|
+
oracle: signer,
|
|
810
|
+
serviceRef: capability.serviceRef as Hex,
|
|
811
|
+
expiry: capability.expiry,
|
|
812
|
+
},
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
|
|
575
816
|
/** Returns the denial reason this single view produces, or `undefined` if it authorizes. */
|
|
576
817
|
private evaluateView(
|
|
577
818
|
stream: GatewayStreamView,
|
|
@@ -595,6 +836,17 @@ export class CallerAuthGateway {
|
|
|
595
836
|
) {
|
|
596
837
|
return "service-ref-mismatch";
|
|
597
838
|
}
|
|
839
|
+
// Operator-signed price band (metrik-contracts#41). Checked against the
|
|
840
|
+
// STREAM's serviceRef, which equals the capability's by the check above.
|
|
841
|
+
const bounds = this.rateBounds.get(stream.serviceRef.toLowerCase());
|
|
842
|
+
if (bounds !== undefined) {
|
|
843
|
+
if (stream.ratePerSecond === undefined) {
|
|
844
|
+
return "stream-rate-unknown";
|
|
845
|
+
}
|
|
846
|
+
if (rateOutsideBounds(stream.ratePerSecond, bounds) !== undefined) {
|
|
847
|
+
return "stream-rate-out-of-bounds";
|
|
848
|
+
}
|
|
849
|
+
}
|
|
598
850
|
if (stream.status !== "active") {
|
|
599
851
|
return "stream-not-active";
|
|
600
852
|
}
|
|
@@ -640,7 +892,7 @@ function freshestView(views: readonly GatewayStreamView[]): GatewayStreamView {
|
|
|
640
892
|
|
|
641
893
|
function deny(
|
|
642
894
|
reason: CallerAuthDenialReason,
|
|
643
|
-
httpStatus: 400 | 402 | 403,
|
|
895
|
+
httpStatus: 400 | 402 | 403 | 429,
|
|
644
896
|
capability?: SignedInvocationCapability,
|
|
645
897
|
): CallerAuthDecision {
|
|
646
898
|
return {
|