@absol-labs/agent 0.10.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.
Files changed (331) hide show
  1. package/README.md +106 -30
  2. package/dist/capability/invocation-capability.d.ts +20 -8
  3. package/dist/capability/invocation-capability.d.ts.map +1 -1
  4. package/dist/capability/invocation-capability.js.map +1 -1
  5. package/dist/capability/probe-capability.d.ts +225 -0
  6. package/dist/capability/probe-capability.d.ts.map +1 -0
  7. package/dist/capability/probe-capability.js +248 -0
  8. package/dist/capability/probe-capability.js.map +1 -0
  9. package/dist/cli/args.d.ts +11 -0
  10. package/dist/cli/args.d.ts.map +1 -1
  11. package/dist/cli/args.js +23 -0
  12. package/dist/cli/args.js.map +1 -1
  13. package/dist/cli/commands/claim.d.ts.map +1 -1
  14. package/dist/cli/commands/claim.js +21 -5
  15. package/dist/cli/commands/claim.js.map +1 -1
  16. package/dist/cli/commands/close.d.ts.map +1 -1
  17. package/dist/cli/commands/close.js +51 -7
  18. package/dist/cli/commands/close.js.map +1 -1
  19. package/dist/cli/commands/invoke.d.ts +2 -0
  20. package/dist/cli/commands/invoke.d.ts.map +1 -1
  21. package/dist/cli/commands/invoke.js +3 -2
  22. package/dist/cli/commands/invoke.js.map +1 -1
  23. package/dist/cli/commands/mcp.d.ts.map +1 -1
  24. package/dist/cli/commands/mcp.js +15 -2
  25. package/dist/cli/commands/mcp.js.map +1 -1
  26. package/dist/cli/commands/open.d.ts.map +1 -1
  27. package/dist/cli/commands/open.js +121 -15
  28. package/dist/cli/commands/open.js.map +1 -1
  29. package/dist/cli/commands/pay.d.ts +19 -0
  30. package/dist/cli/commands/pay.d.ts.map +1 -0
  31. package/dist/cli/commands/pay.js +355 -0
  32. package/dist/cli/commands/pay.js.map +1 -0
  33. package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
  34. package/dist/cli/commands/reclaim-unverified.js +15 -6
  35. package/dist/cli/commands/reclaim-unverified.js.map +1 -1
  36. package/dist/cli/commands/reclaim.d.ts +23 -2
  37. package/dist/cli/commands/reclaim.d.ts.map +1 -1
  38. package/dist/cli/commands/reclaim.js +200 -21
  39. package/dist/cli/commands/reclaim.js.map +1 -1
  40. package/dist/cli/commands/refund.d.ts +13 -0
  41. package/dist/cli/commands/refund.d.ts.map +1 -0
  42. package/dist/cli/commands/refund.js +224 -0
  43. package/dist/cli/commands/refund.js.map +1 -0
  44. package/dist/cli/commands/status.d.ts.map +1 -1
  45. package/dist/cli/commands/status.js +10 -1
  46. package/dist/cli/commands/status.js.map +1 -1
  47. package/dist/cli/commands/streams.js +9 -13
  48. package/dist/cli/commands/streams.js.map +1 -1
  49. package/dist/cli/commands/watch.d.ts.map +1 -1
  50. package/dist/cli/commands/watch.js +2 -1
  51. package/dist/cli/commands/watch.js.map +1 -1
  52. package/dist/cli/config.d.ts +44 -26
  53. package/dist/cli/config.d.ts.map +1 -1
  54. package/dist/cli/config.js +88 -38
  55. package/dist/cli/config.js.map +1 -1
  56. package/dist/cli/deps.d.ts +86 -7
  57. package/dist/cli/deps.d.ts.map +1 -1
  58. package/dist/cli/deps.js +102 -16
  59. package/dist/cli/deps.js.map +1 -1
  60. package/dist/cli/errors.d.ts.map +1 -1
  61. package/dist/cli/errors.js +21 -1
  62. package/dist/cli/errors.js.map +1 -1
  63. package/dist/cli/escape-hatch.d.ts +6 -4
  64. package/dist/cli/escape-hatch.d.ts.map +1 -1
  65. package/dist/cli/escape-hatch.js +6 -2
  66. package/dist/cli/escape-hatch.js.map +1 -1
  67. package/dist/cli/listings.d.ts +18 -0
  68. package/dist/cli/listings.d.ts.map +1 -1
  69. package/dist/cli/listings.js +22 -12
  70. package/dist/cli/listings.js.map +1 -1
  71. package/dist/cli/preflight.d.ts +20 -14
  72. package/dist/cli/preflight.d.ts.map +1 -1
  73. package/dist/cli/preflight.js +34 -20
  74. package/dist/cli/preflight.js.map +1 -1
  75. package/dist/cli/privy.d.ts +83 -0
  76. package/dist/cli/privy.d.ts.map +1 -0
  77. package/dist/cli/privy.js +232 -0
  78. package/dist/cli/privy.js.map +1 -0
  79. package/dist/cli/reclaimability.d.ts +82 -0
  80. package/dist/cli/reclaimability.d.ts.map +1 -0
  81. package/dist/cli/reclaimability.js +80 -0
  82. package/dist/cli/reclaimability.js.map +1 -0
  83. package/dist/cli/run.d.ts +2 -1
  84. package/dist/cli/run.d.ts.map +1 -1
  85. package/dist/cli/run.js +40 -11
  86. package/dist/cli/run.js.map +1 -1
  87. package/dist/cli/scan-range.d.ts +2 -2
  88. package/dist/cli/scan-range.js +2 -2
  89. package/dist/cli/spend-policy.d.ts +60 -0
  90. package/dist/cli/spend-policy.d.ts.map +1 -0
  91. package/dist/cli/spend-policy.js +65 -0
  92. package/dist/cli/spend-policy.js.map +1 -0
  93. package/dist/cli/status.d.ts +3 -1
  94. package/dist/cli/status.d.ts.map +1 -1
  95. package/dist/cli/status.js +15 -3
  96. package/dist/cli/status.js.map +1 -1
  97. package/dist/cli/wallet.d.ts +109 -40
  98. package/dist/cli/wallet.d.ts.map +1 -1
  99. package/dist/cli/wallet.js +109 -44
  100. package/dist/cli/wallet.js.map +1 -1
  101. package/dist/discovery/rate-band.d.ts +74 -0
  102. package/dist/discovery/rate-band.d.ts.map +1 -0
  103. package/dist/discovery/rate-band.js +114 -0
  104. package/dist/discovery/rate-band.js.map +1 -0
  105. package/dist/escrow-generation.d.ts +81 -0
  106. package/dist/escrow-generation.d.ts.map +1 -0
  107. package/dist/escrow-generation.js +76 -0
  108. package/dist/escrow-generation.js.map +1 -0
  109. package/dist/frameworks/agentkit.d.ts +8 -4
  110. package/dist/frameworks/agentkit.d.ts.map +1 -1
  111. package/dist/frameworks/agentkit.js +27 -10
  112. package/dist/frameworks/agentkit.js.map +1 -1
  113. package/dist/frameworks/eliza.d.ts +3 -3
  114. package/dist/frameworks/eliza.d.ts.map +1 -1
  115. package/dist/frameworks/eliza.js +15 -6
  116. package/dist/frameworks/eliza.js.map +1 -1
  117. package/dist/frameworks/langchain.d.ts.map +1 -1
  118. package/dist/frameworks/langchain.js +8 -0
  119. package/dist/frameworks/langchain.js.map +1 -1
  120. package/dist/gateway/caller-auth-gateway.d.ts +91 -4
  121. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
  122. package/dist/gateway/caller-auth-gateway.js +184 -7
  123. package/dist/gateway/caller-auth-gateway.js.map +1 -1
  124. package/dist/gateway/http-server.d.ts +121 -1
  125. package/dist/gateway/http-server.d.ts.map +1 -1
  126. package/dist/gateway/http-server.js +474 -5
  127. package/dist/gateway/http-server.js.map +1 -1
  128. package/dist/gateway/probe-auth.d.ts +112 -0
  129. package/dist/gateway/probe-auth.d.ts.map +1 -0
  130. package/dist/gateway/probe-auth.js +127 -0
  131. package/dist/gateway/probe-auth.js.map +1 -0
  132. package/dist/gateway/signed-rate-bounds.d.ts +51 -0
  133. package/dist/gateway/signed-rate-bounds.d.ts.map +1 -0
  134. package/dist/gateway/signed-rate-bounds.js +94 -0
  135. package/dist/gateway/signed-rate-bounds.js.map +1 -0
  136. package/dist/gateway/x402-opener-mode.d.ts +215 -0
  137. package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
  138. package/dist/gateway/x402-opener-mode.js +639 -0
  139. package/dist/gateway/x402-opener-mode.js.map +1 -0
  140. package/dist/index.d.ts +11 -5
  141. package/dist/index.d.ts.map +1 -1
  142. package/dist/index.js +15 -5
  143. package/dist/index.js.map +1 -1
  144. package/dist/mandates/env.d.ts +3 -2
  145. package/dist/mandates/env.d.ts.map +1 -1
  146. package/dist/mandates/env.js +3 -2
  147. package/dist/mandates/env.js.map +1 -1
  148. package/dist/mcp/server.d.ts +100 -0
  149. package/dist/mcp/server.d.ts.map +1 -1
  150. package/dist/mcp/server.js +719 -39
  151. package/dist/mcp/server.js.map +1 -1
  152. package/dist/mcp/service-invoker.d.ts +97 -0
  153. package/dist/mcp/service-invoker.d.ts.map +1 -0
  154. package/dist/mcp/service-invoker.js +167 -0
  155. package/dist/mcp/service-invoker.js.map +1 -0
  156. package/dist/mcp/x402-tools.d.ts +104 -0
  157. package/dist/mcp/x402-tools.d.ts.map +1 -0
  158. package/dist/mcp/x402-tools.js +434 -0
  159. package/dist/mcp/x402-tools.js.map +1 -0
  160. package/dist/network.d.ts +119 -0
  161. package/dist/network.d.ts.map +1 -0
  162. package/dist/network.js +199 -0
  163. package/dist/network.js.map +1 -0
  164. package/dist/sdk/invoke.d.ts +23 -4
  165. package/dist/sdk/invoke.d.ts.map +1 -1
  166. package/dist/sdk/invoke.js +71 -10
  167. package/dist/sdk/invoke.js.map +1 -1
  168. package/dist/wallet/autonomous-wallet-broker.d.ts +3 -0
  169. package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -1
  170. package/dist/wallet/autonomous-wallet-broker.js +27 -23
  171. package/dist/wallet/autonomous-wallet-broker.js.map +1 -1
  172. package/dist/wallet/autonomous-wallet-protocol.d.ts +8 -2
  173. package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -1
  174. package/dist/wallet/autonomous-wallet-protocol.js +9 -2
  175. package/dist/wallet/autonomous-wallet-protocol.js.map +1 -1
  176. package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
  177. package/dist/wallet/autonomous-wallet.js +3 -2
  178. package/dist/wallet/autonomous-wallet.js.map +1 -1
  179. package/dist/wallet/broker-escrows.d.ts +222 -0
  180. package/dist/wallet/broker-escrows.d.ts.map +1 -0
  181. package/dist/wallet/broker-escrows.js +36 -0
  182. package/dist/wallet/broker-escrows.js.map +1 -0
  183. package/dist/wallet/lifecycle.d.ts +21 -5
  184. package/dist/wallet/lifecycle.d.ts.map +1 -1
  185. package/dist/wallet/lifecycle.js +32 -12
  186. package/dist/wallet/lifecycle.js.map +1 -1
  187. package/dist/wallet/privy-broker-server.d.ts.map +1 -1
  188. package/dist/wallet/privy-broker-server.js +31 -26
  189. package/dist/wallet/privy-broker-server.js.map +1 -1
  190. package/dist/wallet/privy-session-broker.d.ts +14 -5
  191. package/dist/wallet/privy-session-broker.d.ts.map +1 -1
  192. package/dist/wallet/privy-session-broker.js +29 -17
  193. package/dist/wallet/privy-session-broker.js.map +1 -1
  194. package/dist/wallet/privy-session-provider.d.ts +3 -1
  195. package/dist/wallet/privy-session-provider.d.ts.map +1 -1
  196. package/dist/wallet/privy-session-provider.js +5 -3
  197. package/dist/wallet/privy-session-provider.js.map +1 -1
  198. package/dist/wallet/provider.d.ts.map +1 -1
  199. package/dist/wallet/provider.js +15 -8
  200. package/dist/wallet/provider.js.map +1 -1
  201. package/dist/x402/facilitator.d.ts +42 -17
  202. package/dist/x402/facilitator.d.ts.map +1 -1
  203. package/dist/x402/facilitator.js +49 -33
  204. package/dist/x402/facilitator.js.map +1 -1
  205. package/dist/x402-buyer/guarded-fetch.d.ts +51 -0
  206. package/dist/x402-buyer/guarded-fetch.d.ts.map +1 -0
  207. package/dist/x402-buyer/guarded-fetch.js +147 -0
  208. package/dist/x402-buyer/guarded-fetch.js.map +1 -0
  209. package/dist/x402-buyer/index.d.ts +10 -0
  210. package/dist/x402-buyer/index.d.ts.map +1 -0
  211. package/dist/x402-buyer/index.js +10 -0
  212. package/dist/x402-buyer/index.js.map +1 -0
  213. package/dist/x402-buyer/pay.d.ts +135 -0
  214. package/dist/x402-buyer/pay.d.ts.map +1 -0
  215. package/dist/x402-buyer/pay.js +336 -0
  216. package/dist/x402-buyer/pay.js.map +1 -0
  217. package/dist/x402-opener/abi.d.ts +684 -0
  218. package/dist/x402-opener/abi.d.ts.map +1 -0
  219. package/dist/x402-opener/abi.js +880 -0
  220. package/dist/x402-opener/abi.js.map +1 -0
  221. package/dist/x402-opener/facilitator-entry.d.ts +3 -0
  222. package/dist/x402-opener/facilitator-entry.d.ts.map +1 -0
  223. package/dist/x402-opener/facilitator-entry.js +37 -0
  224. package/dist/x402-opener/facilitator-entry.js.map +1 -0
  225. package/dist/x402-opener/facilitator-server.d.ts +180 -0
  226. package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
  227. package/dist/x402-opener/facilitator-server.js +696 -0
  228. package/dist/x402-opener/facilitator-server.js.map +1 -0
  229. package/dist/x402-opener/index.d.ts +14 -0
  230. package/dist/x402-opener/index.d.ts.map +1 -0
  231. package/dist/x402-opener/index.js +14 -0
  232. package/dist/x402-opener/index.js.map +1 -0
  233. package/dist/x402-opener/listing-resolver.d.ts +55 -0
  234. package/dist/x402-opener/listing-resolver.d.ts.map +1 -0
  235. package/dist/x402-opener/listing-resolver.js +125 -0
  236. package/dist/x402-opener/listing-resolver.js.map +1 -0
  237. package/dist/x402-opener/refund-relay.d.ts +240 -0
  238. package/dist/x402-opener/refund-relay.d.ts.map +1 -0
  239. package/dist/x402-opener/refund-relay.js +1240 -0
  240. package/dist/x402-opener/refund-relay.js.map +1 -0
  241. package/dist/x402-opener/relayer-queue.d.ts +14 -0
  242. package/dist/x402-opener/relayer-queue.d.ts.map +1 -0
  243. package/dist/x402-opener/relayer-queue.js +18 -0
  244. package/dist/x402-opener/relayer-queue.js.map +1 -0
  245. package/dist/x402-opener/scheme.d.ts +217 -0
  246. package/dist/x402-opener/scheme.d.ts.map +1 -0
  247. package/dist/x402-opener/scheme.js +749 -0
  248. package/dist/x402-opener/scheme.js.map +1 -0
  249. package/dist/x402-opener/terms.d.ts +105 -0
  250. package/dist/x402-opener/terms.d.ts.map +1 -0
  251. package/dist/x402-opener/terms.js +212 -0
  252. package/dist/x402-opener/terms.js.map +1 -0
  253. package/dist/zktls/reclaim.d.ts +2 -2
  254. package/docs/agent-layer.md +13 -8
  255. package/docs/autonomous-privy-wallet.md +188 -0
  256. package/docs/cli.md +342 -53
  257. package/docs/langchain.md +5 -0
  258. package/docs/mcp-hosted.md +4 -3
  259. package/docs/mcp-reference.md +245 -0
  260. package/docs/probe-capability.md +191 -0
  261. package/docs/quickstart.md +54 -5
  262. package/docs/threat-model.md +24 -3
  263. package/docs/x402.md +681 -0
  264. package/package.json +19 -6
  265. package/src/capability/invocation-capability.ts +17 -1
  266. package/src/capability/probe-capability.ts +355 -0
  267. package/src/cli/args.ts +29 -0
  268. package/src/cli/commands/claim.ts +31 -5
  269. package/src/cli/commands/close.ts +56 -7
  270. package/src/cli/commands/invoke.ts +6 -2
  271. package/src/cli/commands/mcp.ts +18 -2
  272. package/src/cli/commands/open.ts +151 -14
  273. package/src/cli/commands/pay.ts +442 -0
  274. package/src/cli/commands/reclaim-unverified.ts +24 -6
  275. package/src/cli/commands/reclaim.ts +274 -19
  276. package/src/cli/commands/refund.ts +277 -0
  277. package/src/cli/commands/status.ts +17 -1
  278. package/src/cli/commands/streams.ts +11 -15
  279. package/src/cli/commands/watch.ts +7 -1
  280. package/src/cli/config.ts +139 -52
  281. package/src/cli/deps.ts +189 -25
  282. package/src/cli/errors.ts +24 -1
  283. package/src/cli/escape-hatch.ts +19 -5
  284. package/src/cli/listings.ts +43 -10
  285. package/src/cli/preflight.ts +36 -21
  286. package/src/cli/privy.ts +398 -0
  287. package/src/cli/reclaimability.ts +154 -0
  288. package/src/cli/run.ts +54 -11
  289. package/src/cli/scan-range.ts +2 -2
  290. package/src/cli/spend-policy.ts +139 -0
  291. package/src/cli/status.ts +14 -1
  292. package/src/cli/wallet.ts +189 -58
  293. package/src/discovery/rate-band.ts +172 -0
  294. package/src/escrow-generation.ts +135 -0
  295. package/src/frameworks/agentkit.ts +45 -11
  296. package/src/frameworks/eliza.ts +27 -5
  297. package/src/frameworks/langchain.ts +14 -0
  298. package/src/gateway/caller-auth-gateway.ts +336 -13
  299. package/src/gateway/http-server.ts +690 -7
  300. package/src/gateway/probe-auth.ts +191 -0
  301. package/src/gateway/signed-rate-bounds.ts +164 -0
  302. package/src/gateway/x402-opener-mode.ts +974 -0
  303. package/src/index.ts +112 -14
  304. package/src/mandates/env.ts +3 -2
  305. package/src/mcp/server.ts +973 -44
  306. package/src/mcp/service-invoker.ts +285 -0
  307. package/src/mcp/x402-tools.ts +621 -0
  308. package/src/network.ts +302 -0
  309. package/src/sdk/invoke.ts +96 -17
  310. package/src/wallet/autonomous-wallet-broker.ts +46 -20
  311. package/src/wallet/autonomous-wallet-protocol.ts +11 -2
  312. package/src/wallet/autonomous-wallet.ts +4 -2
  313. package/src/wallet/broker-escrows.ts +66 -0
  314. package/src/wallet/lifecycle.ts +53 -18
  315. package/src/wallet/privy-broker-server.ts +35 -25
  316. package/src/wallet/privy-session-broker.ts +58 -25
  317. package/src/wallet/privy-session-provider.ts +7 -3
  318. package/src/wallet/provider.ts +20 -15
  319. package/src/x402/facilitator.ts +85 -46
  320. package/src/x402-buyer/guarded-fetch.ts +213 -0
  321. package/src/x402-buyer/index.ts +9 -0
  322. package/src/x402-buyer/pay.ts +517 -0
  323. package/src/x402-opener/abi.ts +881 -0
  324. package/src/x402-opener/facilitator-entry.ts +45 -0
  325. package/src/x402-opener/facilitator-server.ts +1014 -0
  326. package/src/x402-opener/index.ts +13 -0
  327. package/src/x402-opener/listing-resolver.ts +202 -0
  328. package/src/x402-opener/refund-relay.ts +1743 -0
  329. package/src/x402-opener/relayer-queue.ts +18 -0
  330. package/src/x402-opener/scheme.ts +1133 -0
  331. package/src/x402-opener/terms.ts +300 -0
@@ -1,6 +1,7 @@
1
1
  import { privateKeyToAccount } from "viem/accounts";
2
2
  import { resolveAgentWallet } from "../wallet/provider.js";
3
3
  import { configError } from "./errors.js";
4
+ import { PRIVY_ENV_VARS, PRIVY_SESSION_ENV_VARS, PRIVY_WALLET_KEY_ENV, resolvePrivyCliWallet, } from "./privy.js";
4
5
  /**
5
6
  * The ONLY place the CLI resolves a signing wallet.
6
7
  *
@@ -12,35 +13,36 @@ import { configError } from "./errors.js";
12
13
  *
13
14
  * ## Resolution order (first match wins, checked in this order)
14
15
  *
15
- * 1. `METRIK_AGENT_PRIVATE_KEY` — a raw Base Sepolia test key.
16
+ * 1. `METRIK_AGENT_PRIVATE_KEY` — a raw testnet key.
16
17
  * 2. The `CDP_*` / `METRIK_AGENT_CDP_*` quartet — a Coinbase CDP Server Wallet
17
18
  * v2 account, resolved through this package's own `resolveAgentWallet()`.
19
+ * 3. The `METRIK_AGENT_PRIVY_*` variables — a Privy wallet reached through a
20
+ * broker, either agent-owned (`METRIK_AGENT_PRIVY_WALLET_KEY`) or a
21
+ * user-owned broker session. See `./privy.ts`.
18
22
  *
19
- * The order matches `parseAgentWalletEnv()` (the MCP server's resolution), so
20
- * one environment configures every surface the same way. It is checked in a
21
- * FIXED order rather than "whichever is configured", because an environment
22
- * carrying both is ambiguous about which address funds the stream — and that
23
- * ambiguity is a fund-moving one. When both are present the private key wins
24
- * and `resolveCliWallet` says so on stderr rather than silently picking.
23
+ * The first two match `parseAgentWalletEnv()` (the MCP server's resolution), so
24
+ * one environment configures those surfaces the same way. The order is FIXED
25
+ * rather than "whichever is configured", because an environment carrying two is
26
+ * ambiguous about which address funds the stream — and that ambiguity is a
27
+ * fund-moving one. When more than one is present the earlier entry wins and
28
+ * `resolveCliWallet` says so on stderr rather than silently picking.
25
29
  *
26
- * ## Why CDP is wired and Privy is not
30
+ * ## What is different about Privy
27
31
  *
28
- * CDP is the only wallet path in this package with live CI evidence
29
- * (`scripts/e2e-cdp.ts` drives the full journey against the real Base Sepolia
30
- * escrow), and its account signs LOCALLY — `toAccount(cdpServerAccount)` is a
31
- * viem local account, so it drops straight into the CLI's existing
32
- * `http(rpcUrl)` transport with no other change.
32
+ * A private key and a CDP account both sign LOCALLY: `privateKeyToAccount()`
33
+ * and `toAccount(cdpServerAccount)` are viem local accounts, so they drop
34
+ * straight into the CLI's `http(rpcUrl)` transport with no other change.
33
35
  *
34
- * Privy does not. Both Privy adapters in `src/wallet/` produce a JSON-RPC
35
- * account with no `signTransaction`: they sign and broadcast by sending
36
- * `eth_sendTransaction` / `eth_signTypedData_v4` to a provider, so they need the
37
- * wallet client's TRANSPORT to be that provider rather than a plain RPC. Wiring
38
- * that into the CLI is not a matter of reading three more variables — it
39
- * changes the transport for every fund-moving command, and `metrik invoke`
40
- * additionally requires a local signer (`InvokeOptions.buyer: LocalAccount`).
41
- * `assertLocalSigner` below therefore REFUSES a non-local account with that
42
- * fact, instead of accepting one and failing later inside viem. See
43
- * `docs/cli.md` § Wallet.
36
+ * Privy does not. Its account is a JSON-RPC account with no `signTransaction`:
37
+ * it signs and broadcasts by sending `eth_sendTransaction` /
38
+ * `eth_signTypedData_v4` to a provider, so the wallet client's TRANSPORT must
39
+ * be that provider rather than a plain RPC. That is what {@link CliWallet.transport}
40
+ * carries, and the only reason this file knows Privy exists. The signer check
41
+ * below is therefore about CAPABILITY, not about locality: it refuses an
42
+ * account that genuinely cannot sign, and refuses a non-local account only on
43
+ * the paths that broadcast through `--rpc-url`.
44
+ *
45
+ * See `docs/cli.md` § Wallet.
44
46
  */
45
47
  export const PRIVATE_KEY_ENV = "METRIK_AGENT_PRIVATE_KEY";
46
48
  /** Every environment variable the CDP path reads. Named in errors, never printed. */
@@ -50,26 +52,41 @@ export const CDP_ENV_VARS = [
50
52
  "CDP_WALLET_SECRET",
51
53
  "METRIK_AGENT_CDP_OWNER_NAME",
52
54
  ];
55
+ export { PRIVY_ENV_VARS, PRIVY_SESSION_ENV_VARS, PRIVY_WALLET_KEY_ENV, } from "./privy.js";
53
56
  const PURPOSE_TEXT = {
54
57
  transaction: "signs a transaction",
55
58
  capability: "signs an off-chain EIP-712 invocation capability (no transaction is broadcast)",
56
59
  };
57
- const WALLET_HINT = `export ${PRIVATE_KEY_ENV}=0x… (a funded Base Sepolia test key), or configure a Coinbase CDP wallet with ` +
58
- `${CDP_ENV_VARS.join(", ")}. Both are read from the environment only — never pass a credential as a command-line flag.`;
60
+ const WALLET_HINT = `export ${PRIVATE_KEY_ENV}=0x… (a funded testnet key), configure a Coinbase CDP wallet with ` +
61
+ `${CDP_ENV_VARS.join(", ")}, or configure a Privy wallet with ${PRIVY_WALLET_KEY_ENV} (agent-owned) or ` +
62
+ `${PRIVY_SESSION_ENV_VARS.join(", ")} (broker session). All are read from the environment only — never pass a credential as a command-line flag.`;
59
63
  /**
60
64
  * Resolves the signing wallet, or throws an actionable configuration error.
61
65
  *
62
- * `note` receives one line when the environment is ambiguous (both wallet
63
- * sources configured). It is optional so `resolveCliWallet` stays usable from a
64
- * context with no printer; commands always pass `out.note`.
66
+ * `note` receives one line when the environment is ambiguous (more than one
67
+ * wallet source configured). It is optional so `resolveCliWallet` stays usable
68
+ * from a context with no printer; commands always pass `out.note`.
65
69
  */
66
70
  export async function resolveCliWallet(env, options = {}) {
67
71
  const wallet = await optionalCliWallet(env, options);
68
72
  if (wallet === null) {
69
- throw configError(`this command ${PURPOSE_TEXT[options.purpose ?? "transaction"]} and needs a wallet: neither ${PRIVATE_KEY_ENV} nor the CDP variables are set`, WALLET_HINT);
73
+ throw configError(`this command ${PURPOSE_TEXT[options.purpose ?? "transaction"]} and needs a wallet: none of ${PRIVATE_KEY_ENV}, the CDP variables or the Privy variables are set`, WALLET_HINT);
70
74
  }
71
75
  return wallet;
72
76
  }
77
+ /** True for both Privy shapes, which reach their key through a broker. */
78
+ export function isPrivyWalletSource(source) {
79
+ return source === "privy-autonomous" || source === "privy-session";
80
+ }
81
+ /**
82
+ * Whether this wallet's ceiling is enforced somewhere the CLI cannot reach.
83
+ *
84
+ * The one question every fund-moving command asks before deciding whether to
85
+ * self-sign a `SpendMandate`. See `./spend-policy.ts`.
86
+ */
87
+ export function isPolicyEnforced(wallet) {
88
+ return wallet.readSpendPolicy !== undefined;
89
+ }
73
90
  /**
74
91
  * The same resolution, but "nothing configured" is not an error. Used by
75
92
  * look-before-you-leap paths (`open --dry-run`, `streams --address`) that
@@ -79,14 +96,19 @@ export async function resolveCliWallet(env, options = {}) {
79
96
  * A wallet that is PARTIALLY configured is still an error here: "you set three
80
97
  * of the four CDP variables" and "you configured no wallet" are different
81
98
  * facts, and rendering the first as the second sends the reader looking in the
82
- * wrong place.
99
+ * wrong place. The same rule applies to a partial Privy setup.
83
100
  */
84
101
  export async function optionalCliWallet(env, options = {}) {
85
102
  const privateKeyAccount = optionalCliAccount(env);
86
103
  const cdpConfigured = CDP_ENV_VARS.some((name) => isSet(env[name]));
104
+ const privyConfigured = PRIVY_ENV_VARS.some((name) => isSet(env[name]));
87
105
  if (privateKeyAccount !== null) {
88
- if (cdpConfigured) {
89
- options.note?.(`warning: both ${PRIVATE_KEY_ENV} and CDP wallet variables are set; using ${PRIVATE_KEY_ENV} (${privateKeyAccount.address}). Unset it to sign with the CDP wallet.`);
106
+ const shadowed = [
107
+ ...(cdpConfigured ? ["CDP"] : []),
108
+ ...(privyConfigured ? ["Privy"] : []),
109
+ ];
110
+ if (shadowed.length > 0) {
111
+ options.note?.(`warning: both ${PRIVATE_KEY_ENV} and ${shadowed.join(" and ")} wallet variables are set; using ${PRIVATE_KEY_ENV} (${privateKeyAccount.address}). Unset it to sign with the ${shadowed[0]} wallet.`);
90
112
  }
91
113
  return {
92
114
  source: "private-key",
@@ -94,8 +116,29 @@ export async function optionalCliWallet(env, options = {}) {
94
116
  description: `${privateKeyAccount.address} (from ${PRIVATE_KEY_ENV})`,
95
117
  };
96
118
  }
97
- if (!cdpConfigured)
119
+ if (cdpConfigured) {
120
+ if (privyConfigured) {
121
+ options.note?.("warning: both CDP and Privy wallet variables are set; using the CDP wallet. Unset the CDP variables to sign with the Privy wallet.");
122
+ }
123
+ return await resolveCdpWallet(env);
124
+ }
125
+ if (!privyConfigured)
98
126
  return null;
127
+ const privy = await resolvePrivyCliWallet(env, options);
128
+ // Unreachable: `privyConfigured` is exactly the condition under which
129
+ // `resolvePrivyCliWallet` returns non-null or throws. Kept so a future change
130
+ // to either predicate fails loudly here rather than as a null deref.
131
+ if (privy === null)
132
+ return null;
133
+ return {
134
+ source: privy.source,
135
+ account: assertCliSigner(privy.account, privy.source),
136
+ transport: privy.transport,
137
+ description: privy.description,
138
+ readSpendPolicy: privy.readSpendPolicy,
139
+ };
140
+ }
141
+ async function resolveCdpWallet(env) {
99
142
  const missing = CDP_ENV_VARS.filter((name) => !isSet(env[name]));
100
143
  if (missing.length > 0) {
101
144
  throw configError(`the CDP wallet is partially configured: ${missing.join(", ")} ${missing.length === 1 ? "is" : "are"} not set`, `a CDP wallet needs all of ${CDP_ENV_VARS.join(", ")}. Set the missing one${missing.length === 1 ? "" : "s"}, or unset the others and use ${PRIVATE_KEY_ENV} instead.`);
@@ -130,7 +173,7 @@ export async function optionalCliWallet(env, options = {}) {
130
173
  }
131
174
  return {
132
175
  source: "cdp",
133
- account: assertLocalSigner(account, "cdp"),
176
+ account: assertCliSigner(account, "cdp"),
134
177
  description: `${account.address} (CDP account "${ownerName}")`,
135
178
  };
136
179
  }
@@ -148,17 +191,39 @@ export function optionalCliAccount(env) {
148
191
  return privateKeyToAccount(raw);
149
192
  }
150
193
  /**
151
- * Every CLI signing path needs a LOCAL signer: fund-moving commands broadcast
152
- * through `http(--rpc-url)`, which cannot sign, and `invoke` needs a
153
- * `LocalAccount` to sign the EIP-712 capability. A JSON-RPC account (Privy's
154
- * adapters) would type-check as an `Account` and then fail somewhere inside
155
- * viem with a message about a missing method, so it is rejected here with the
156
- * actual reason.
194
+ * Whether this wallet source broadcasts through the CLI's own
195
+ * `http(--rpc-url)` transport, and therefore needs an account that can produce
196
+ * a signed raw transaction by itself.
197
+ */
198
+ function broadcastsLocally(source) {
199
+ return source === "private-key" || source === "cdp";
200
+ }
201
+ /**
202
+ * Refuses an account that genuinely cannot sign — and nothing else.
203
+ *
204
+ * Two distinct capabilities are checked, because two distinct things fail:
205
+ *
206
+ * - `signTypedData` is needed by EVERY command. Fund-moving commands self-sign
207
+ * an EIP-712 `SpendMandate`; `invoke` signs an EIP-712
208
+ * `InvocationCapability`. Without it the run dies at the first signature
209
+ * with a `TypeError` from inside viem.
210
+ * - A LOCAL account is needed only where the CLI broadcasts through
211
+ * `http(--rpc-url)`, which cannot sign. A Privy account is deliberately NOT
212
+ * local: its provider is the transport and performs `eth_sendTransaction`
213
+ * itself, so demanding locality there would reject a wallet that works.
214
+ *
215
+ * The earlier version of this guard collapsed both into "must be local", which
216
+ * is why Privy was refused. Deleting the guard outright was not the fix: it
217
+ * exists so a broken wallet fails here, named, instead of deep inside viem.
157
218
  */
158
- function assertLocalSigner(account, source) {
159
- if (account.type === "local")
160
- return account;
161
- throw configError(`the ${source} wallet returned a ${account.type} account, which cannot sign locally`, "the CLI broadcasts through --rpc-url and signs EIP-712 capabilities in-process, so it needs a local signer.");
219
+ export function assertCliSigner(account, source) {
220
+ if (typeof account.signTypedData !== "function") {
221
+ throw configError(`the ${source} wallet (${account.address}) cannot sign EIP-712 typed data`, "every command signs typed data: fund-moving commands self-sign a spend mandate, and `invoke` signs an invocation capability.");
222
+ }
223
+ if (broadcastsLocally(source) && account.type !== "local") {
224
+ throw configError(`the ${source} wallet returned a ${account.type} account, which cannot sign locally`, "this wallet source broadcasts through --rpc-url, which cannot sign, so it needs a local signer.");
225
+ }
226
+ return account;
162
227
  }
163
228
  function isSet(value) {
164
229
  return value !== undefined && value.length > 0;
@@ -1 +1 @@
1
- {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../../src/cli/wallet.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../../src/cli/wallet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import { SignedRateBoundsError, type SignedRateBounds } from "../gateway/signed-rate-bounds.js";
2
+ /**
3
+ * The buyer-side twin of the gateway's signed-rate check.
4
+ *
5
+ * `StreamEscrowV2.openStream` accepts any non-zero `ratePerSecond`; the band a
6
+ * seller will actually SERVE lives in its operator-signed descriptor
7
+ * (`commercial.minRatePerSecond` / `maxRatePerSecond`), and the seller's
8
+ * capability gateway answers every request on an out-of-band stream with
9
+ * `403 stream-rate-out-of-bounds`. Opening such a stream locks the buyer's
10
+ * deposit in a stream that can never be served, so every buyer surface that
11
+ * takes a caller-chosen rate checks it against the SAME band, with the SAME
12
+ * verification ({@link verifySignedRateBounds}), before anything is broadcast.
13
+ *
14
+ * Nothing here is a second signature implementation: the bounds come only out
15
+ * of `verifySignedRateBounds`, which re-derives the serviceRef from the signed
16
+ * content and recovers the operator's EIP-712 signature.
17
+ */
18
+ /** A listing as discovery hands it over: the serviceRef and its signed record. */
19
+ export interface RateBandListing {
20
+ readonly serviceRef: string;
21
+ readonly signed: unknown;
22
+ }
23
+ /**
24
+ * The operator-signed rate band of a verified listing.
25
+ *
26
+ * - `null`: the listing is a legacy service BINDING, which carries no
27
+ * commercial terms, so the operator signed no band and there is nothing to
28
+ * enforce (the gateway enforces none either).
29
+ * - a {@link SignedRateBounds}: the descriptor verified. Either bound may still
30
+ * be `null` when the operator signed only one side, or none.
31
+ *
32
+ * Throws {@link SignedRateBoundsError} when the record IS a descriptor but does
33
+ * not verify, or verifies for a different serviceRef than the listing claims.
34
+ * Callers must treat that as a refusal: a band that cannot be verified is not a
35
+ * band that can be assumed absent.
36
+ */
37
+ export declare function listingRateBand(listing: RateBandListing): Promise<SignedRateBounds | null>;
38
+ /**
39
+ * The signed band in both units, e.g. `100..10000 atomic/s (0.0001..0.01
40
+ * USDC/s)`. A one-sided band reads `at least 100 atomic/s (…)` /
41
+ * `at most 10000 atomic/s (…)`.
42
+ */
43
+ export declare function describeRateBand(bounds: SignedRateBounds): string;
44
+ /**
45
+ * `undefined` when `rate` is inside the operator-signed band (bounds are
46
+ * inclusive, exactly as the gateway applies them), otherwise an actionable
47
+ * refusal naming the band in atomic units and USDC. `rateLabel` is how the
48
+ * caller supplied the rate (`--rate`, `ratePerSecondUsdc`).
49
+ */
50
+ export declare function rateBandRefusal(rate: bigint, bounds: SignedRateBounds, rateLabel: string): string | undefined;
51
+ /**
52
+ * Outcome of {@link checkListedRateBand}: `ok: false` is a refusal, and its
53
+ * `message` is safe to hand straight back to the caller.
54
+ */
55
+ export type ListedRateBandCheck = {
56
+ readonly ok: true;
57
+ /** `unlisted`: no verified listing, so no operator-signed band exists. */
58
+ readonly band: "in-band" | "no-band-signed" | "unlisted";
59
+ } | {
60
+ readonly ok: false;
61
+ readonly message: string;
62
+ };
63
+ /**
64
+ * Discover the serviceRef's verified listing(s) and check `rate` against every
65
+ * operator-signed band among them, for a surface that has no listing in hand.
66
+ *
67
+ * Fail closed: a registry that cannot be read means a signed band may exist and
68
+ * is unknown, so it is a refusal — never a pass. A serviceRef with no verified
69
+ * listing has no signed band to violate, and is allowed (these surfaces never
70
+ * required a listing to hire).
71
+ */
72
+ export declare function checkListedRateBand(discover: () => Promise<readonly RateBandListing[]>, serviceRef: string, rate: bigint, rateLabel: string): Promise<ListedRateBandCheck>;
73
+ export { SignedRateBoundsError };
74
+ //# sourceMappingURL=rate-band.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-band.d.ts","sourceRoot":"","sources":["../../src/discovery/rate-band.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,qBAAqB,EAErB,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAC;AAE1C;;;;;;;;;;;;;;;GAeG;AAEH,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAgBlC;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAYjE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAIpB;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,gBAAgB,GAAG,UAAU,CAAC;CAC1D,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,EACnD,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC,CAqC9B;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,114 @@
1
+ import { formatUnits } from "viem";
2
+ import { rateOutsideBounds, SignedRateBoundsError, verifySignedRateBounds, } from "../gateway/signed-rate-bounds.js";
3
+ /**
4
+ * The operator-signed rate band of a verified listing.
5
+ *
6
+ * - `null`: the listing is a legacy service BINDING, which carries no
7
+ * commercial terms, so the operator signed no band and there is nothing to
8
+ * enforce (the gateway enforces none either).
9
+ * - a {@link SignedRateBounds}: the descriptor verified. Either bound may still
10
+ * be `null` when the operator signed only one side, or none.
11
+ *
12
+ * Throws {@link SignedRateBoundsError} when the record IS a descriptor but does
13
+ * not verify, or verifies for a different serviceRef than the listing claims.
14
+ * Callers must treat that as a refusal: a band that cannot be verified is not a
15
+ * band that can be assumed absent.
16
+ */
17
+ export async function listingRateBand(listing) {
18
+ const signed = listing.signed;
19
+ if (typeof signed !== "object" ||
20
+ signed === null ||
21
+ !("descriptor" in signed)) {
22
+ return null;
23
+ }
24
+ const bounds = await verifySignedRateBounds(signed);
25
+ if (bounds.serviceRef !== listing.serviceRef.toLowerCase()) {
26
+ throw new SignedRateBoundsError(`the signed descriptor verifies for serviceRef ${bounds.serviceRef}, not the listed ${listing.serviceRef}`);
27
+ }
28
+ return bounds;
29
+ }
30
+ /** `0.0001` for `100n` — USDC has 6 decimals. */
31
+ function usdc(atomic) {
32
+ return formatUnits(atomic, 6);
33
+ }
34
+ /**
35
+ * The signed band in both units, e.g. `100..10000 atomic/s (0.0001..0.01
36
+ * USDC/s)`. A one-sided band reads `at least 100 atomic/s (…)` /
37
+ * `at most 10000 atomic/s (…)`.
38
+ */
39
+ export function describeRateBand(bounds) {
40
+ const { minRatePerSecond: min, maxRatePerSecond: max } = bounds;
41
+ if (min !== null && max !== null) {
42
+ return `${min}..${max} atomic/s (${usdc(min)}..${usdc(max)} USDC/s)`;
43
+ }
44
+ if (min !== null) {
45
+ return `at least ${min} atomic/s (${usdc(min)} USDC/s)`;
46
+ }
47
+ if (max !== null) {
48
+ return `at most ${max} atomic/s (${usdc(max)} USDC/s)`;
49
+ }
50
+ return "any rate (the operator signed no bounds)";
51
+ }
52
+ /**
53
+ * `undefined` when `rate` is inside the operator-signed band (bounds are
54
+ * inclusive, exactly as the gateway applies them), otherwise an actionable
55
+ * refusal naming the band in atomic units and USDC. `rateLabel` is how the
56
+ * caller supplied the rate (`--rate`, `ratePerSecondUsdc`).
57
+ */
58
+ export function rateBandRefusal(rate, bounds, rateLabel) {
59
+ const outside = rateOutsideBounds(rate, bounds);
60
+ if (outside === undefined)
61
+ return undefined;
62
+ 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.`;
63
+ }
64
+ /**
65
+ * Discover the serviceRef's verified listing(s) and check `rate` against every
66
+ * operator-signed band among them, for a surface that has no listing in hand.
67
+ *
68
+ * Fail closed: a registry that cannot be read means a signed band may exist and
69
+ * is unknown, so it is a refusal — never a pass. A serviceRef with no verified
70
+ * listing has no signed band to violate, and is allowed (these surfaces never
71
+ * required a listing to hire).
72
+ */
73
+ export async function checkListedRateBand(discover, serviceRef, rate, rateLabel) {
74
+ let listings;
75
+ try {
76
+ listings = await discover();
77
+ }
78
+ catch (error) {
79
+ return {
80
+ ok: false,
81
+ 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.`,
82
+ };
83
+ }
84
+ const wanted = serviceRef.toLowerCase();
85
+ const matches = listings.filter((listing) => listing.serviceRef.toLowerCase() === wanted);
86
+ if (matches.length === 0)
87
+ return { ok: true, band: "unlisted" };
88
+ let signedAny = false;
89
+ for (const listing of matches) {
90
+ let bounds;
91
+ try {
92
+ bounds = await listingRateBand(listing);
93
+ }
94
+ catch (error) {
95
+ if (error instanceof SignedRateBoundsError) {
96
+ return {
97
+ ok: false,
98
+ message: `refusing to hire: the listing's operator-signed rate band could not be verified (${error.message}). Nothing was spent.`,
99
+ };
100
+ }
101
+ throw error;
102
+ }
103
+ if (bounds === null)
104
+ continue;
105
+ signedAny = true;
106
+ const refusal = rateBandRefusal(rate, bounds, rateLabel);
107
+ if (refusal !== undefined) {
108
+ return { ok: false, message: `refusing to hire: ${refusal}` };
109
+ }
110
+ }
111
+ return { ok: true, band: signedAny ? "in-band" : "no-band-signed" };
112
+ }
113
+ export { SignedRateBoundsError };
114
+ //# sourceMappingURL=rate-band.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-band.js","sourceRoot":"","sources":["../../src/discovery/rate-band.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import type { Address, Hex } from "viem";
2
+ /**
3
+ * Escrow-generation-specific rules, driven by the SDK network registry's
4
+ * `escrow.generation` (metrik-agent#121).
5
+ *
6
+ * Today the registry knows only `v2` (`StreamEscrowV2`). `StreamEscrowV3`
7
+ * changes one rule the agent reasons about: the buyer's no-proof escape hatch.
8
+ *
9
+ * - **V2**: `reclaimUnverified` opens at `expiresAt + escapeGraceSeconds`.
10
+ * Closing early does NOT bring it forward.
11
+ * - **V3**: it opens at `min(expiresAt, closedAt) + escapeGraceSeconds`, and the
12
+ * escrow exposes `escapeHatchReadyAt(bytes32)` to read it directly. Where a
13
+ * chain read is available it is preferred over re-deriving the formula.
14
+ *
15
+ * An unknown generation is refused, never guessed: a wrong readiness answer
16
+ * either sends a buyer a guaranteed revert or tells them to wait when they need
17
+ * not. (V3 also restricts `recordProven` to the stream's operator or an active
18
+ * oracle signer; no agent or relay path calls it on a buyer's behalf.)
19
+ */
20
+ /** Escrow generations whose escape-hatch rule this package implements. */
21
+ export type KnownEscrowGeneration = "v2" | "v3";
22
+ export declare class UnsupportedEscrowGenerationError extends Error {
23
+ readonly generation: string;
24
+ constructor(generation: string);
25
+ }
26
+ /**
27
+ * The generation of `escrow` on `chainId`, from the network registry. An escrow
28
+ * the registry does not record is treated as V2 — the generation every
29
+ * unregistered, explicitly configured Metrik deployment speaks today.
30
+ */
31
+ export declare function escrowGenerationFor(chainId: number, escrow: Address): KnownEscrowGeneration;
32
+ /**
33
+ * The second the no-proof escape hatch opens, by formula. `closedAt` is `0`
34
+ * while the stream is open.
35
+ */
36
+ export declare function escapeHatchReadyAtFormula(generation: string, stream: {
37
+ readonly expiresAt: bigint;
38
+ readonly closedAt: bigint;
39
+ }, graceSeconds: bigint): bigint;
40
+ /**
41
+ * `StreamEscrowV3.escapeHatchReadyAt(bytes32)`. A one-function fragment until
42
+ * the SDK ships the V3 ABI; replace it with the SDK's export then.
43
+ */
44
+ export declare const streamEscrowV3EscapeHatchAbi: readonly [{
45
+ readonly type: "function";
46
+ readonly name: "escapeHatchReadyAt";
47
+ readonly stateMutability: "view";
48
+ readonly inputs: readonly [{
49
+ readonly name: "streamId";
50
+ readonly type: "bytes32";
51
+ }];
52
+ readonly outputs: readonly [{
53
+ readonly name: "";
54
+ readonly type: "uint256";
55
+ }];
56
+ }];
57
+ /** The minimal read surface {@link readEscapeHatchReadyAt} needs. */
58
+ export interface EscapeHatchReader {
59
+ readContract(args: {
60
+ readonly address: Address;
61
+ readonly abi: typeof streamEscrowV3EscapeHatchAbi;
62
+ readonly functionName: "escapeHatchReadyAt";
63
+ readonly args: readonly [Hex];
64
+ }): Promise<bigint>;
65
+ }
66
+ /**
67
+ * The escape-hatch second for one stream: V3 reads the escrow's own view (and
68
+ * falls back to the V3 formula if that read fails); V2 uses its formula.
69
+ */
70
+ export declare function readEscapeHatchReadyAt(input: {
71
+ readonly generation: string;
72
+ readonly reader: EscapeHatchReader;
73
+ readonly escrow: Address;
74
+ readonly streamId: Hex;
75
+ readonly stream: {
76
+ readonly expiresAt: bigint;
77
+ readonly closedAt: bigint;
78
+ };
79
+ readonly graceSeconds: bigint;
80
+ }): Promise<bigint>;
81
+ //# sourceMappingURL=escrow-generation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escrow-generation.d.ts","sourceRoot":"","sources":["../src/escrow-generation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEzC;;;;;;;;;;;;;;;;;GAiBG;AAEH,0EAA0E;AAC1E,MAAM,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,UAAU,EAAE,MAAM;CAO/B;AAOD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,GACd,qBAAqB,CAMvB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EACjE,YAAY,EAAE,MAAM,GACnB,MAAM,CAYR;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;EAQ/B,CAAC;AAEX,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,IAAI,EAAE;QACjB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;QAC1B,QAAQ,CAAC,GAAG,EAAE,OAAO,4BAA4B,CAAC;QAClD,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;QAC5C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;KAC/B,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBlB"}
@@ -0,0 +1,76 @@
1
+ import { findDeployment } from "@absol-labs/sdk";
2
+ export class UnsupportedEscrowGenerationError extends Error {
3
+ generation;
4
+ constructor(generation) {
5
+ super(`escrow generation "${generation}" is not one this package knows the escape-hatch rule for (known: v2, v3)`);
6
+ this.name = "UnsupportedEscrowGenerationError";
7
+ this.generation = generation;
8
+ }
9
+ }
10
+ function known(generation) {
11
+ if (generation === "v2" || generation === "v3")
12
+ return generation;
13
+ throw new UnsupportedEscrowGenerationError(generation);
14
+ }
15
+ /**
16
+ * The generation of `escrow` on `chainId`, from the network registry. An escrow
17
+ * the registry does not record is treated as V2 — the generation every
18
+ * unregistered, explicitly configured Metrik deployment speaks today.
19
+ */
20
+ export function escrowGenerationFor(chainId, escrow) {
21
+ return known(
22
+ // The generation of THIS deployment (current or legacy), not of the
23
+ // network's current escrow.
24
+ findDeployment(chainId, escrow)?.deployment.escrow.generation ?? "v2");
25
+ }
26
+ /**
27
+ * The second the no-proof escape hatch opens, by formula. `closedAt` is `0`
28
+ * while the stream is open.
29
+ */
30
+ export function escapeHatchReadyAtFormula(generation, stream, graceSeconds) {
31
+ switch (known(generation)) {
32
+ case "v2":
33
+ return stream.expiresAt + graceSeconds;
34
+ case "v3": {
35
+ const stop = stream.closedAt > 0n && stream.closedAt < stream.expiresAt
36
+ ? stream.closedAt
37
+ : stream.expiresAt;
38
+ return stop + graceSeconds;
39
+ }
40
+ }
41
+ }
42
+ /**
43
+ * `StreamEscrowV3.escapeHatchReadyAt(bytes32)`. A one-function fragment until
44
+ * the SDK ships the V3 ABI; replace it with the SDK's export then.
45
+ */
46
+ export const streamEscrowV3EscapeHatchAbi = [
47
+ {
48
+ type: "function",
49
+ name: "escapeHatchReadyAt",
50
+ stateMutability: "view",
51
+ inputs: [{ name: "streamId", type: "bytes32" }],
52
+ outputs: [{ name: "", type: "uint256" }],
53
+ },
54
+ ];
55
+ /**
56
+ * The escape-hatch second for one stream: V3 reads the escrow's own view (and
57
+ * falls back to the V3 formula if that read fails); V2 uses its formula.
58
+ */
59
+ export async function readEscapeHatchReadyAt(input) {
60
+ const generation = known(input.generation);
61
+ if (generation === "v3") {
62
+ try {
63
+ return await input.reader.readContract({
64
+ address: input.escrow,
65
+ abi: streamEscrowV3EscapeHatchAbi,
66
+ functionName: "escapeHatchReadyAt",
67
+ args: [input.streamId],
68
+ });
69
+ }
70
+ catch {
71
+ // Fall through to the V3 formula: the same rule the view implements.
72
+ }
73
+ }
74
+ return escapeHatchReadyAtFormula(generation, input.stream, input.graceSeconds);
75
+ }
76
+ //# sourceMappingURL=escrow-generation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escrow-generation.js","sourceRoot":"","sources":["../src/escrow-generation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAyBjD,MAAM,OAAO,gCAAiC,SAAQ,KAAK;IAChD,UAAU,CAAS;IAE5B,YAAY,UAAkB;QAC5B,KAAK,CACH,sBAAsB,UAAU,2EAA2E,CAC5G,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kCAAkC,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED,SAAS,KAAK,CAAC,UAAkB;IAC/B,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAClE,MAAM,IAAI,gCAAgC,CAAC,UAAU,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,MAAe;IAEf,OAAO,KAAK;IACV,oEAAoE;IACpE,4BAA4B;IAC5B,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,UAAU,IAAI,IAAI,CACtE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAkB,EAClB,MAAiE,EACjE,YAAoB;IAEpB,QAAQ,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1B,KAAK,IAAI;YACP,OAAO,MAAM,CAAC,SAAS,GAAG,YAAY,CAAC;QACzC,KAAK,IAAI,CAAC,CAAC,CAAC;YACV,MAAM,IAAI,GACR,MAAM,CAAC,QAAQ,GAAG,EAAE,IAAI,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,SAAS;gBACxD,CAAC,CAAC,MAAM,CAAC,QAAQ;gBACjB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;YACvB,OAAO,IAAI,GAAG,YAAY,CAAC;QAC7B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,oBAAoB;QAC1B,eAAe,EAAE,MAAM;QACvB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC/C,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KACzC;CACO,CAAC;AAYX;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAO5C;IACC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC;gBACrC,OAAO,EAAE,KAAK,CAAC,MAAM;gBACrB,GAAG,EAAE,4BAA4B;gBACjC,YAAY,EAAE,oBAAoB;gBAClC,IAAI,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;aACvB,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC;IACD,OAAO,yBAAyB,CAC9B,UAAU,EACV,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,YAAY,CACnB,CAAC;AACJ,CAAC"}