@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/wallet.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
*
|
|
25
25
|
* ## Resolution order (first match wins, checked in this order)
|
|
26
26
|
*
|
|
27
|
-
* 1. `METRIK_AGENT_PRIVATE_KEY` — a raw
|
|
27
|
+
* 1. `METRIK_AGENT_PRIVATE_KEY` — a raw testnet key.
|
|
28
28
|
* 2. The `CDP_*` / `METRIK_AGENT_CDP_*` quartet — a Coinbase CDP Server Wallet
|
|
29
29
|
* v2 account, resolved through this package's own `resolveAgentWallet()`.
|
|
30
30
|
* 3. The `METRIK_AGENT_PRIVY_*` variables — a Privy wallet reached through a
|
|
@@ -76,12 +76,25 @@ export {
|
|
|
76
76
|
* signs an EIP-712 invocation capability and broadcasts NOTHING; telling its
|
|
77
77
|
* caller "this command signs a transaction" was simply false.
|
|
78
78
|
*/
|
|
79
|
-
export type KeyPurpose =
|
|
79
|
+
export type KeyPurpose =
|
|
80
|
+
| "transaction"
|
|
81
|
+
| "capability"
|
|
82
|
+
| "payer-close"
|
|
83
|
+
| "x402-payment";
|
|
80
84
|
|
|
81
85
|
const PURPOSE_TEXT: Record<KeyPurpose, string> = {
|
|
82
86
|
transaction: "signs a transaction",
|
|
83
87
|
capability:
|
|
84
88
|
"signs an off-chain EIP-712 invocation capability (no transaction is broadcast)",
|
|
89
|
+
// `metrik refund --close`: the x402 payer signs the opener's EIP-712 `Close`
|
|
90
|
+
// message and the relay broadcasts it, paying the gas. It is NOT an
|
|
91
|
+
// invocation capability, and the key needs no funds at all.
|
|
92
|
+
"payer-close":
|
|
93
|
+
"signs the payer's off-chain EIP-712 Close message (the refund relay broadcasts it and pays the gas)",
|
|
94
|
+
// `metrik pay`: the payer signs an EIP-3009 TransferWithAuthorization and the
|
|
95
|
+
// seller's facilitator settles it. The payer broadcasts nothing.
|
|
96
|
+
"x402-payment":
|
|
97
|
+
"signs an EIP-3009 USDC authorization that the seller's facilitator settles (the payer broadcasts no transaction and needs no gas)",
|
|
85
98
|
};
|
|
86
99
|
|
|
87
100
|
/** Which environment configured the signer, for output and for error text. */
|
|
@@ -122,10 +135,33 @@ export interface CliWallet {
|
|
|
122
135
|
readonly readSpendPolicy?: () => Promise<PrivySpendPolicy>;
|
|
123
136
|
}
|
|
124
137
|
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
138
|
+
const ENV_ONLY =
|
|
139
|
+
"All are read from the environment only — never pass a credential as a command-line flag.";
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* How to configure the wallet a purpose needs. "Funded" is said only where a
|
|
143
|
+
* transaction is broadcast: an off-chain signature costs nothing, and telling
|
|
144
|
+
* someone to fund a key for one sends them to a faucet for no reason.
|
|
145
|
+
*/
|
|
146
|
+
function walletHint(purpose: KeyPurpose): string {
|
|
147
|
+
if (purpose === "x402-payment") {
|
|
148
|
+
return (
|
|
149
|
+
`export ${PRIVATE_KEY_ENV}=0x… (a testnet key holding USDC; no ETH needed), or configure a Coinbase CDP wallet with ` +
|
|
150
|
+
`${CDP_ENV_VARS.join(", ")}. A Privy wallet cannot pay x402: its broker does not sign EIP-3009. ${ENV_ONLY}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
if (purpose === "payer-close") {
|
|
154
|
+
return (
|
|
155
|
+
`export ${PRIVATE_KEY_ENV}=0x… (the key that paid; it needs no ETH or USDC), or configure the paying Coinbase CDP wallet with ` +
|
|
156
|
+
`${CDP_ENV_VARS.join(", ")}. A Privy wallet cannot sign the Close. ${ENV_ONLY}`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return (
|
|
160
|
+
`export ${PRIVATE_KEY_ENV}=0x… (${purpose === "transaction" ? "a funded testnet key" : "a testnet key; it needs no funds for this"}), configure a Coinbase CDP wallet with ` +
|
|
161
|
+
`${CDP_ENV_VARS.join(", ")}, or configure a Privy wallet with ${PRIVY_WALLET_KEY_ENV} (agent-owned) or ` +
|
|
162
|
+
`${PRIVY_SESSION_ENV_VARS.join(", ")} (broker session). ${ENV_ONLY}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
129
165
|
|
|
130
166
|
export interface ResolveCliWalletOptions {
|
|
131
167
|
readonly purpose?: KeyPurpose;
|
|
@@ -159,9 +195,10 @@ export async function resolveCliWallet(
|
|
|
159
195
|
): Promise<CliWallet> {
|
|
160
196
|
const wallet = await optionalCliWallet(env, options);
|
|
161
197
|
if (wallet === null) {
|
|
198
|
+
const purpose = options.purpose ?? "transaction";
|
|
162
199
|
throw configError(
|
|
163
|
-
`this command ${PURPOSE_TEXT[
|
|
164
|
-
|
|
200
|
+
`this command ${PURPOSE_TEXT[purpose]} and needs a wallet: none of ${PRIVATE_KEY_ENV}, the CDP variables or the Privy variables are set`,
|
|
201
|
+
walletHint(purpose),
|
|
165
202
|
);
|
|
166
203
|
}
|
|
167
204
|
return wallet;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { formatUnits } from "viem";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
rateOutsideBounds,
|
|
5
|
+
SignedRateBoundsError,
|
|
6
|
+
verifySignedRateBounds,
|
|
7
|
+
type SignedRateBounds,
|
|
8
|
+
} from "../gateway/signed-rate-bounds.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The buyer-side twin of the gateway's signed-rate check.
|
|
12
|
+
*
|
|
13
|
+
* `StreamEscrowV2.openStream` accepts any non-zero `ratePerSecond`; the band a
|
|
14
|
+
* seller will actually SERVE lives in its operator-signed descriptor
|
|
15
|
+
* (`commercial.minRatePerSecond` / `maxRatePerSecond`), and the seller's
|
|
16
|
+
* capability gateway answers every request on an out-of-band stream with
|
|
17
|
+
* `403 stream-rate-out-of-bounds`. Opening such a stream locks the buyer's
|
|
18
|
+
* deposit in a stream that can never be served, so every buyer surface that
|
|
19
|
+
* takes a caller-chosen rate checks it against the SAME band, with the SAME
|
|
20
|
+
* verification ({@link verifySignedRateBounds}), before anything is broadcast.
|
|
21
|
+
*
|
|
22
|
+
* Nothing here is a second signature implementation: the bounds come only out
|
|
23
|
+
* of `verifySignedRateBounds`, which re-derives the serviceRef from the signed
|
|
24
|
+
* content and recovers the operator's EIP-712 signature.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** A listing as discovery hands it over: the serviceRef and its signed record. */
|
|
28
|
+
export interface RateBandListing {
|
|
29
|
+
readonly serviceRef: string;
|
|
30
|
+
readonly signed: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The operator-signed rate band of a verified listing.
|
|
35
|
+
*
|
|
36
|
+
* - `null`: the listing is a legacy service BINDING, which carries no
|
|
37
|
+
* commercial terms, so the operator signed no band and there is nothing to
|
|
38
|
+
* enforce (the gateway enforces none either).
|
|
39
|
+
* - a {@link SignedRateBounds}: the descriptor verified. Either bound may still
|
|
40
|
+
* be `null` when the operator signed only one side, or none.
|
|
41
|
+
*
|
|
42
|
+
* Throws {@link SignedRateBoundsError} when the record IS a descriptor but does
|
|
43
|
+
* not verify, or verifies for a different serviceRef than the listing claims.
|
|
44
|
+
* Callers must treat that as a refusal: a band that cannot be verified is not a
|
|
45
|
+
* band that can be assumed absent.
|
|
46
|
+
*/
|
|
47
|
+
export async function listingRateBand(
|
|
48
|
+
listing: RateBandListing,
|
|
49
|
+
): Promise<SignedRateBounds | null> {
|
|
50
|
+
const signed = listing.signed;
|
|
51
|
+
if (
|
|
52
|
+
typeof signed !== "object" ||
|
|
53
|
+
signed === null ||
|
|
54
|
+
!("descriptor" in signed)
|
|
55
|
+
) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const bounds = await verifySignedRateBounds(signed);
|
|
59
|
+
if (bounds.serviceRef !== listing.serviceRef.toLowerCase()) {
|
|
60
|
+
throw new SignedRateBoundsError(
|
|
61
|
+
`the signed descriptor verifies for serviceRef ${bounds.serviceRef}, not the listed ${listing.serviceRef}`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return bounds;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** `0.0001` for `100n` — USDC has 6 decimals. */
|
|
68
|
+
function usdc(atomic: bigint): string {
|
|
69
|
+
return formatUnits(atomic, 6);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The signed band in both units, e.g. `100..10000 atomic/s (0.0001..0.01
|
|
74
|
+
* USDC/s)`. A one-sided band reads `at least 100 atomic/s (…)` /
|
|
75
|
+
* `at most 10000 atomic/s (…)`.
|
|
76
|
+
*/
|
|
77
|
+
export function describeRateBand(bounds: SignedRateBounds): string {
|
|
78
|
+
const { minRatePerSecond: min, maxRatePerSecond: max } = bounds;
|
|
79
|
+
if (min !== null && max !== null) {
|
|
80
|
+
return `${min}..${max} atomic/s (${usdc(min)}..${usdc(max)} USDC/s)`;
|
|
81
|
+
}
|
|
82
|
+
if (min !== null) {
|
|
83
|
+
return `at least ${min} atomic/s (${usdc(min)} USDC/s)`;
|
|
84
|
+
}
|
|
85
|
+
if (max !== null) {
|
|
86
|
+
return `at most ${max} atomic/s (${usdc(max)} USDC/s)`;
|
|
87
|
+
}
|
|
88
|
+
return "any rate (the operator signed no bounds)";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* `undefined` when `rate` is inside the operator-signed band (bounds are
|
|
93
|
+
* inclusive, exactly as the gateway applies them), otherwise an actionable
|
|
94
|
+
* refusal naming the band in atomic units and USDC. `rateLabel` is how the
|
|
95
|
+
* caller supplied the rate (`--rate`, `ratePerSecondUsdc`).
|
|
96
|
+
*/
|
|
97
|
+
export function rateBandRefusal(
|
|
98
|
+
rate: bigint,
|
|
99
|
+
bounds: SignedRateBounds,
|
|
100
|
+
rateLabel: string,
|
|
101
|
+
): string | undefined {
|
|
102
|
+
const outside = rateOutsideBounds(rate, bounds);
|
|
103
|
+
if (outside === undefined) return undefined;
|
|
104
|
+
return `the operator signed rates ${describeRateBand(bounds)}; ${rateLabel} ${rate} (${usdc(rate)} USDC/s) would be refused by the service's gateway (${outside}), so the stream could never be served. Nothing was broadcast.`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Outcome of {@link checkListedRateBand}: `ok: false` is a refusal, and its
|
|
109
|
+
* `message` is safe to hand straight back to the caller.
|
|
110
|
+
*/
|
|
111
|
+
export type ListedRateBandCheck =
|
|
112
|
+
| {
|
|
113
|
+
readonly ok: true;
|
|
114
|
+
/** `unlisted`: no verified listing, so no operator-signed band exists. */
|
|
115
|
+
readonly band: "in-band" | "no-band-signed" | "unlisted";
|
|
116
|
+
}
|
|
117
|
+
| { readonly ok: false; readonly message: string };
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Discover the serviceRef's verified listing(s) and check `rate` against every
|
|
121
|
+
* operator-signed band among them, for a surface that has no listing in hand.
|
|
122
|
+
*
|
|
123
|
+
* Fail closed: a registry that cannot be read means a signed band may exist and
|
|
124
|
+
* is unknown, so it is a refusal — never a pass. A serviceRef with no verified
|
|
125
|
+
* listing has no signed band to violate, and is allowed (these surfaces never
|
|
126
|
+
* required a listing to hire).
|
|
127
|
+
*/
|
|
128
|
+
export async function checkListedRateBand(
|
|
129
|
+
discover: () => Promise<readonly RateBandListing[]>,
|
|
130
|
+
serviceRef: string,
|
|
131
|
+
rate: bigint,
|
|
132
|
+
rateLabel: string,
|
|
133
|
+
): Promise<ListedRateBandCheck> {
|
|
134
|
+
let listings: readonly RateBandListing[];
|
|
135
|
+
try {
|
|
136
|
+
listings = await discover();
|
|
137
|
+
} catch (error) {
|
|
138
|
+
return {
|
|
139
|
+
ok: false,
|
|
140
|
+
message: `refusing to hire: the service registry could not be read (${error instanceof Error ? error.message : String(error)}), so the operator-signed rate band for ${serviceRef} cannot be checked and the stream might never be served. Nothing was spent — retry when the registry answers.`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const wanted = serviceRef.toLowerCase();
|
|
144
|
+
const matches = listings.filter(
|
|
145
|
+
(listing) => listing.serviceRef.toLowerCase() === wanted,
|
|
146
|
+
);
|
|
147
|
+
if (matches.length === 0) return { ok: true, band: "unlisted" };
|
|
148
|
+
let signedAny = false;
|
|
149
|
+
for (const listing of matches) {
|
|
150
|
+
let bounds: SignedRateBounds | null;
|
|
151
|
+
try {
|
|
152
|
+
bounds = await listingRateBand(listing);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (error instanceof SignedRateBoundsError) {
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
message: `refusing to hire: the listing's operator-signed rate band could not be verified (${error.message}). Nothing was spent.`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
if (bounds === null) continue;
|
|
163
|
+
signedAny = true;
|
|
164
|
+
const refusal = rateBandRefusal(rate, bounds, rateLabel);
|
|
165
|
+
if (refusal !== undefined) {
|
|
166
|
+
return { ok: false, message: `refusing to hire: ${refusal}` };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return { ok: true, band: signedAny ? "in-band" : "no-band-signed" };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { SignedRateBoundsError };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { findDeployment } from "@absol-labs/sdk";
|
|
2
|
+
import type { Address, Hex } from "viem";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Escrow-generation-specific rules, driven by the SDK network registry's
|
|
6
|
+
* `escrow.generation` (metrik-agent#121).
|
|
7
|
+
*
|
|
8
|
+
* Today the registry knows only `v2` (`StreamEscrowV2`). `StreamEscrowV3`
|
|
9
|
+
* changes one rule the agent reasons about: the buyer's no-proof escape hatch.
|
|
10
|
+
*
|
|
11
|
+
* - **V2**: `reclaimUnverified` opens at `expiresAt + escapeGraceSeconds`.
|
|
12
|
+
* Closing early does NOT bring it forward.
|
|
13
|
+
* - **V3**: it opens at `min(expiresAt, closedAt) + escapeGraceSeconds`, and the
|
|
14
|
+
* escrow exposes `escapeHatchReadyAt(bytes32)` to read it directly. Where a
|
|
15
|
+
* chain read is available it is preferred over re-deriving the formula.
|
|
16
|
+
*
|
|
17
|
+
* An unknown generation is refused, never guessed: a wrong readiness answer
|
|
18
|
+
* either sends a buyer a guaranteed revert or tells them to wait when they need
|
|
19
|
+
* not. (V3 also restricts `recordProven` to the stream's operator or an active
|
|
20
|
+
* oracle signer; no agent or relay path calls it on a buyer's behalf.)
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** Escrow generations whose escape-hatch rule this package implements. */
|
|
24
|
+
export type KnownEscrowGeneration = "v2" | "v3";
|
|
25
|
+
|
|
26
|
+
export class UnsupportedEscrowGenerationError extends Error {
|
|
27
|
+
readonly generation: string;
|
|
28
|
+
|
|
29
|
+
constructor(generation: string) {
|
|
30
|
+
super(
|
|
31
|
+
`escrow generation "${generation}" is not one this package knows the escape-hatch rule for (known: v2, v3)`,
|
|
32
|
+
);
|
|
33
|
+
this.name = "UnsupportedEscrowGenerationError";
|
|
34
|
+
this.generation = generation;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function known(generation: string): KnownEscrowGeneration {
|
|
39
|
+
if (generation === "v2" || generation === "v3") return generation;
|
|
40
|
+
throw new UnsupportedEscrowGenerationError(generation);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The generation of `escrow` on `chainId`, from the network registry. An escrow
|
|
45
|
+
* the registry does not record is treated as V2 — the generation every
|
|
46
|
+
* unregistered, explicitly configured Metrik deployment speaks today.
|
|
47
|
+
*/
|
|
48
|
+
export function escrowGenerationFor(
|
|
49
|
+
chainId: number,
|
|
50
|
+
escrow: Address,
|
|
51
|
+
): KnownEscrowGeneration {
|
|
52
|
+
return known(
|
|
53
|
+
// The generation of THIS deployment (current or legacy), not of the
|
|
54
|
+
// network's current escrow.
|
|
55
|
+
findDeployment(chainId, escrow)?.deployment.escrow.generation ?? "v2",
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The second the no-proof escape hatch opens, by formula. `closedAt` is `0`
|
|
61
|
+
* while the stream is open.
|
|
62
|
+
*/
|
|
63
|
+
export function escapeHatchReadyAtFormula(
|
|
64
|
+
generation: string,
|
|
65
|
+
stream: { readonly expiresAt: bigint; readonly closedAt: bigint },
|
|
66
|
+
graceSeconds: bigint,
|
|
67
|
+
): bigint {
|
|
68
|
+
switch (known(generation)) {
|
|
69
|
+
case "v2":
|
|
70
|
+
return stream.expiresAt + graceSeconds;
|
|
71
|
+
case "v3": {
|
|
72
|
+
const stop =
|
|
73
|
+
stream.closedAt > 0n && stream.closedAt < stream.expiresAt
|
|
74
|
+
? stream.closedAt
|
|
75
|
+
: stream.expiresAt;
|
|
76
|
+
return stop + graceSeconds;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* `StreamEscrowV3.escapeHatchReadyAt(bytes32)`. A one-function fragment until
|
|
83
|
+
* the SDK ships the V3 ABI; replace it with the SDK's export then.
|
|
84
|
+
*/
|
|
85
|
+
export const streamEscrowV3EscapeHatchAbi = [
|
|
86
|
+
{
|
|
87
|
+
type: "function",
|
|
88
|
+
name: "escapeHatchReadyAt",
|
|
89
|
+
stateMutability: "view",
|
|
90
|
+
inputs: [{ name: "streamId", type: "bytes32" }],
|
|
91
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
92
|
+
},
|
|
93
|
+
] as const;
|
|
94
|
+
|
|
95
|
+
/** The minimal read surface {@link readEscapeHatchReadyAt} needs. */
|
|
96
|
+
export interface EscapeHatchReader {
|
|
97
|
+
readContract(args: {
|
|
98
|
+
readonly address: Address;
|
|
99
|
+
readonly abi: typeof streamEscrowV3EscapeHatchAbi;
|
|
100
|
+
readonly functionName: "escapeHatchReadyAt";
|
|
101
|
+
readonly args: readonly [Hex];
|
|
102
|
+
}): Promise<bigint>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The escape-hatch second for one stream: V3 reads the escrow's own view (and
|
|
107
|
+
* falls back to the V3 formula if that read fails); V2 uses its formula.
|
|
108
|
+
*/
|
|
109
|
+
export async function readEscapeHatchReadyAt(input: {
|
|
110
|
+
readonly generation: string;
|
|
111
|
+
readonly reader: EscapeHatchReader;
|
|
112
|
+
readonly escrow: Address;
|
|
113
|
+
readonly streamId: Hex;
|
|
114
|
+
readonly stream: { readonly expiresAt: bigint; readonly closedAt: bigint };
|
|
115
|
+
readonly graceSeconds: bigint;
|
|
116
|
+
}): Promise<bigint> {
|
|
117
|
+
const generation = known(input.generation);
|
|
118
|
+
if (generation === "v3") {
|
|
119
|
+
try {
|
|
120
|
+
return await input.reader.readContract({
|
|
121
|
+
address: input.escrow,
|
|
122
|
+
abi: streamEscrowV3EscapeHatchAbi,
|
|
123
|
+
functionName: "escapeHatchReadyAt",
|
|
124
|
+
args: [input.streamId],
|
|
125
|
+
});
|
|
126
|
+
} catch {
|
|
127
|
+
// Fall through to the V3 formula: the same rule the view implements.
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return escapeHatchReadyAtFormula(
|
|
131
|
+
generation,
|
|
132
|
+
input.stream,
|
|
133
|
+
input.graceSeconds,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
@@ -2,6 +2,7 @@ import "reflect-metadata";
|
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
4
|
HireComputeResult,
|
|
5
|
+
MetrikNetwork,
|
|
5
6
|
StreamProofClientConfig,
|
|
6
7
|
} from "@absol-labs/sdk";
|
|
7
8
|
import {
|
|
@@ -19,7 +20,13 @@ import {
|
|
|
19
20
|
type DiscoverServicesOptions,
|
|
20
21
|
type ServiceListing,
|
|
21
22
|
} from "../discovery/registry.js";
|
|
23
|
+
import { checkListedRateBand } from "../discovery/rate-band.js";
|
|
22
24
|
import { checkMandate, type SignedSpendMandate } from "../mandates/mandate.js";
|
|
25
|
+
import {
|
|
26
|
+
defaultNetwork,
|
|
27
|
+
describeAllowedNetworks,
|
|
28
|
+
requireNetworkForChainId,
|
|
29
|
+
} from "../network.js";
|
|
23
30
|
import {
|
|
24
31
|
isCheckpointStream,
|
|
25
32
|
MandateDeniedError,
|
|
@@ -34,10 +41,17 @@ import {
|
|
|
34
41
|
} from "../sdk/client.js";
|
|
35
42
|
|
|
36
43
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
44
|
+
* The default settlement chain id: the registry's default network. A provider
|
|
45
|
+
* may be configured for any REGISTERED TESTNET network instead; every action
|
|
46
|
+
* fails closed on a network the registry does not know, on a mainnet, and on a
|
|
47
|
+
* wallet whose network differs from the configured one.
|
|
39
48
|
*/
|
|
40
|
-
export const
|
|
49
|
+
export const METRIK_AGENTKIT_DEFAULT_CHAIN_ID: number =
|
|
50
|
+
defaultNetwork().chain.id;
|
|
51
|
+
|
|
52
|
+
/** @deprecated Use {@link METRIK_AGENTKIT_DEFAULT_CHAIN_ID}; this is the registry's default network, read from the SDK registry. */
|
|
53
|
+
export const METRIK_BASE_SEPOLIA_CHAIN_ID: number =
|
|
54
|
+
METRIK_AGENTKIT_DEFAULT_CHAIN_ID;
|
|
41
55
|
|
|
42
56
|
const addressSchema = z
|
|
43
57
|
.string()
|
|
@@ -159,7 +173,7 @@ export interface MetrikActionProviderConfig {
|
|
|
159
173
|
* agent's construction — the LLM never supplies or edits it.
|
|
160
174
|
*/
|
|
161
175
|
readonly signedMandate: SignedSpendMandate;
|
|
162
|
-
/** Settlement chain id. Defaults to
|
|
176
|
+
/** Settlement chain id. Defaults to the registry's default network; a chain the registry does not know as a testnet fails closed. */
|
|
163
177
|
readonly chainId?: number;
|
|
164
178
|
/** Injected Metrik client (test path). Mutually exclusive with `sdkConfig`. */
|
|
165
179
|
readonly agentClient?: MetrikAgentKitClient;
|
|
@@ -232,6 +246,7 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
|
|
|
232
246
|
readonly #resolver: Partial<MetrikMandateStateResolver>;
|
|
233
247
|
readonly #now: () => number;
|
|
234
248
|
readonly #chainId: number;
|
|
249
|
+
readonly #network: MetrikNetwork;
|
|
235
250
|
readonly #discover: (
|
|
236
251
|
opts?: DiscoverServicesOptions,
|
|
237
252
|
) => Promise<ServiceListing[]>;
|
|
@@ -239,11 +254,17 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
|
|
|
239
254
|
constructor(config: MetrikActionProviderConfig) {
|
|
240
255
|
super("metrik", []);
|
|
241
256
|
|
|
242
|
-
this.#chainId = config.chainId ??
|
|
243
|
-
|
|
244
|
-
|
|
257
|
+
this.#chainId = config.chainId ?? METRIK_AGENTKIT_DEFAULT_CHAIN_ID;
|
|
258
|
+
try {
|
|
259
|
+
this.#network = requireNetworkForChainId(
|
|
260
|
+
this.#chainId,
|
|
261
|
+
{ testnetOnly: true },
|
|
262
|
+
"chainId",
|
|
263
|
+
);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
// Fail closed: only a registered testnet network settles.
|
|
245
266
|
throw new MetrikActionProviderConfigError(
|
|
246
|
-
`unsupported chainId ${this.#chainId}: Metrik settles only on
|
|
267
|
+
`unsupported chainId ${this.#chainId}: Metrik settles only on registered testnet networks (${describeAllowedNetworks({ testnetOnly: true })}) — ${error instanceof Error ? error.message : String(error)}`,
|
|
247
268
|
);
|
|
248
269
|
}
|
|
249
270
|
|
|
@@ -361,6 +382,19 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
|
|
|
361
382
|
throw new MandateDeniedError(decision.reason ?? "mandate-expired");
|
|
362
383
|
}
|
|
363
384
|
|
|
385
|
+
// The rate must sit inside the band the operator SIGNED, or the seller's
|
|
386
|
+
// gateway refuses every request on the stream while the deposit stays
|
|
387
|
+
// escrowed. Fails closed when the registry cannot be read.
|
|
388
|
+
const band = await checkListedRateBand(
|
|
389
|
+
() => this.#discover(),
|
|
390
|
+
serviceRef,
|
|
391
|
+
ratePerSecondUsdc,
|
|
392
|
+
"ratePerSecondUsdc",
|
|
393
|
+
);
|
|
394
|
+
if (!band.ok) {
|
|
395
|
+
throw new Error(band.message);
|
|
396
|
+
}
|
|
397
|
+
|
|
364
398
|
const result = await this.#client.openVerifiedStream({
|
|
365
399
|
operator,
|
|
366
400
|
serviceRef,
|
|
@@ -375,7 +409,7 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
|
|
|
375
409
|
|
|
376
410
|
const urlLine = args.publicUrl ? ` Endpoint: ${args.publicUrl}.` : "";
|
|
377
411
|
return (
|
|
378
|
-
`Hired verified service via Metrik. Stream ${result.streamId} opened on
|
|
412
|
+
`Hired verified service via Metrik. Stream ${result.streamId} opened on ${this.#network.name} (escrow ${result.handle.escrow}). ` +
|
|
379
413
|
`Escrowed ${formatUsdc(budgetUsdc)} USDC at ${formatUsdc(ratePerSecondUsdc)} USDC/sec to operator ${operator} for service ${serviceRef}, ` +
|
|
380
414
|
`max ${maxDurationSeconds}s. Payment accrues only for oracle-verified delivery; unspent USDC is reclaimable.${urlLine} ` +
|
|
381
415
|
`tx=${result.txHash}${result.approveTxHash ? ` approve=${result.approveTxHash}` : ""}`
|
|
@@ -457,7 +491,7 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
|
|
|
457
491
|
}
|
|
458
492
|
|
|
459
493
|
supportsNetwork(network: Network): boolean {
|
|
460
|
-
// Fail closed: EVM
|
|
494
|
+
// Fail closed: the configured EVM network only.
|
|
461
495
|
return (
|
|
462
496
|
network.protocolFamily === "evm" &&
|
|
463
497
|
network.chainId === String(this.#chainId)
|
|
@@ -468,7 +502,7 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
|
|
|
468
502
|
const network = walletProvider.getNetwork();
|
|
469
503
|
if (!this.supportsNetwork(network)) {
|
|
470
504
|
throw new MetrikActionProviderConfigError(
|
|
471
|
-
`unsupported network ${network.protocolFamily}:${network.chainId ?? "unknown"}: Metrik requires
|
|
505
|
+
`unsupported network ${network.protocolFamily}:${network.chainId ?? "unknown"}: Metrik requires ${this.#network.name} (evm:${this.#chainId})`,
|
|
472
506
|
);
|
|
473
507
|
}
|
|
474
508
|
}
|
package/src/frameworks/eliza.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type DiscoverServicesOptions,
|
|
14
14
|
type ServiceListing,
|
|
15
15
|
} from "../discovery/registry.js";
|
|
16
|
+
import { checkListedRateBand } from "../discovery/rate-band.js";
|
|
16
17
|
import { checkMandate, type SignedSpendMandate } from "../mandates/mandate.js";
|
|
17
18
|
import {
|
|
18
19
|
isCheckpointStream,
|
|
@@ -23,12 +24,14 @@ import {
|
|
|
23
24
|
type StreamStatusView,
|
|
24
25
|
type VerifiedStreamAgentOpener,
|
|
25
26
|
} from "../sdk/client.js";
|
|
27
|
+
import { defaultNetwork } from "../network.js";
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
+
* The settlement chain id the Eliza plugin's examples and defaults use: the
|
|
31
|
+
* registry's default network, read from the `@absol-labs/sdk` network registry.
|
|
30
32
|
*/
|
|
31
|
-
export const METRIK_ELIZA_SETTLEMENT_CHAIN_ID =
|
|
33
|
+
export const METRIK_ELIZA_SETTLEMENT_CHAIN_ID: number =
|
|
34
|
+
defaultNetwork().chain.id;
|
|
32
35
|
|
|
33
36
|
const addressSchema = z
|
|
34
37
|
.string()
|
|
@@ -195,7 +198,12 @@ export function createMetrikElizaPlugin(
|
|
|
195
198
|
"Mandate-gated Metrik actions for hiring, monitoring, reclaiming, and closing verified service streams on Base. x402 proves the payment, Metrik proves the delivery.",
|
|
196
199
|
actions: [
|
|
197
200
|
createDiscoverAction(options.discoverServices ?? defaultDiscoverServices),
|
|
198
|
-
createHireAction(
|
|
201
|
+
createHireAction(
|
|
202
|
+
options.agentClient,
|
|
203
|
+
resolver,
|
|
204
|
+
now,
|
|
205
|
+
options.discoverServices ?? defaultDiscoverServices,
|
|
206
|
+
),
|
|
199
207
|
createStatusAction(options.agentClient),
|
|
200
208
|
createReclaimAction(options.agentClient, resolver, now),
|
|
201
209
|
createCloseAction(options.agentClient, resolver, now),
|
|
@@ -277,6 +285,7 @@ function createHireAction(
|
|
|
277
285
|
agentClient: MetrikElizaClient,
|
|
278
286
|
resolver: MetrikElizaMandateStateResolver,
|
|
279
287
|
now: () => number,
|
|
288
|
+
discover: (opts?: DiscoverServicesOptions) => Promise<ServiceListing[]>,
|
|
280
289
|
): Action {
|
|
281
290
|
return {
|
|
282
291
|
name: "HIRE_VERIFIED_SERVICE",
|
|
@@ -328,6 +337,19 @@ function createHireAction(
|
|
|
328
337
|
);
|
|
329
338
|
}
|
|
330
339
|
|
|
340
|
+
// The rate must sit inside the band the operator SIGNED, or the
|
|
341
|
+
// seller's gateway refuses every request on the stream while the
|
|
342
|
+
// deposit stays escrowed. Fails closed when the registry cannot be read.
|
|
343
|
+
const band = await checkListedRateBand(
|
|
344
|
+
() => discover(),
|
|
345
|
+
input.serviceRef,
|
|
346
|
+
BigInt(input.ratePerSecondUsdc),
|
|
347
|
+
"ratePerSecondUsdc",
|
|
348
|
+
);
|
|
349
|
+
if (!band.ok) {
|
|
350
|
+
return await failureResult(band.message, callback);
|
|
351
|
+
}
|
|
352
|
+
|
|
331
353
|
const result = await agentClient.openVerifiedStream({
|
|
332
354
|
operator: input.operator as `0x${string}`,
|
|
333
355
|
serviceRef: input.serviceRef as `0x${string}`,
|
|
@@ -507,7 +529,7 @@ function createExamples(action: MetrikElizaActionName): ActionExample[][] {
|
|
|
507
529
|
const exampleMandate = {
|
|
508
530
|
mandateId: `0x${"55".repeat(32)}`,
|
|
509
531
|
owner: "0x1111111111111111111111111111111111111111",
|
|
510
|
-
chainId:
|
|
532
|
+
chainId: METRIK_ELIZA_SETTLEMENT_CHAIN_ID,
|
|
511
533
|
issuedAt: 1_900_000_000,
|
|
512
534
|
mandate: {
|
|
513
535
|
maxPerStreamUsdc: "100000000",
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type DiscoverServicesOptions,
|
|
8
8
|
type ServiceListing,
|
|
9
9
|
} from "../discovery/registry.js";
|
|
10
|
+
import { checkListedRateBand } from "../discovery/rate-band.js";
|
|
10
11
|
import { checkMandate, type SignedSpendMandate } from "../mandates/mandate.js";
|
|
11
12
|
import {
|
|
12
13
|
isCheckpointStream,
|
|
@@ -206,6 +207,19 @@ export function createLangChainVerifiedStreamTools(
|
|
|
206
207
|
throw new Error(`mandate denied: ${decision.reason ?? "unknown"}`);
|
|
207
208
|
}
|
|
208
209
|
|
|
210
|
+
// The rate must sit inside the band the operator SIGNED, or the
|
|
211
|
+
// seller's gateway refuses every request on the stream while the
|
|
212
|
+
// deposit stays escrowed. Fails closed when the registry cannot be read.
|
|
213
|
+
const band = await checkListedRateBand(
|
|
214
|
+
() => discoverImpl(),
|
|
215
|
+
input.serviceRef,
|
|
216
|
+
BigInt(input.ratePerSecondUsdc),
|
|
217
|
+
"ratePerSecondUsdc",
|
|
218
|
+
);
|
|
219
|
+
if (!band.ok) {
|
|
220
|
+
throw new Error(band.message);
|
|
221
|
+
}
|
|
222
|
+
|
|
209
223
|
const result = await options.agentClient.openVerifiedStream({
|
|
210
224
|
operator: input.operator as `0x${string}`,
|
|
211
225
|
serviceRef: input.serviceRef as `0x${string}`,
|