@haven_ai/sdk 0.10.0-alpha.0 → 0.12.0-alpha.0
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 +45 -9
- package/dist/{base64-CiR5BJhk.d.cts → base64-C5OrJLij.d.ts} +10 -2
- package/dist/{base64-CxkinHPQ.d.ts → base64-COaV1Sis.d.cts} +10 -2
- package/dist/{chunk-6LEXYQ7J.cjs → chunk-4JTLJVBS.cjs} +4 -4
- package/dist/chunk-4JTLJVBS.cjs.map +1 -0
- package/dist/{chunk-MLUWABVT.js → chunk-7M3CIW7W.js} +7 -6
- package/dist/chunk-7M3CIW7W.js.map +1 -0
- package/dist/{chunk-TD2PHUYP.js → chunk-UPEDQLAL.js} +72 -6
- package/dist/chunk-UPEDQLAL.js.map +1 -0
- package/dist/{chunk-22FJ4JQO.cjs → chunk-V2ODMLDD.cjs} +38 -37
- package/dist/chunk-V2ODMLDD.cjs.map +1 -0
- package/dist/{chunk-EWTHDEIW.js → chunk-WFTGZS24.js} +3 -3
- package/dist/chunk-WFTGZS24.js.map +1 -0
- package/dist/{chunk-H37YVYZA.cjs → chunk-ZA3NOSO2.cjs} +73 -5
- package/dist/chunk-ZA3NOSO2.cjs.map +1 -0
- package/dist/edge.cjs +93 -93
- package/dist/edge.d.cts +11 -8
- package/dist/edge.d.ts +11 -8
- package/dist/edge.js +4 -4
- package/dist/index.cjs +866 -475
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -33
- package/dist/index.d.ts +69 -33
- package/dist/index.js +554 -171
- package/dist/index.js.map +1 -1
- package/dist/{receipt-q7ez8Zb2.d.cts → receipt-Dy77vCea.d.cts} +5 -4
- package/dist/{receipt-Cg9a5Seq.d.ts → receipt-DyUInpvF.d.ts} +5 -4
- package/dist/test-support.cjs +21 -21
- package/dist/test-support.d.cts +2 -2
- package/dist/test-support.d.ts +2 -2
- package/dist/test-support.js +2 -2
- package/dist/{types-BKgqzvnk.d.ts → types-CAvsjRKi.d.cts} +209 -12
- package/dist/{types-BKgqzvnk.d.cts → types-CAvsjRKi.d.ts} +209 -12
- package/package.json +1 -1
- package/dist/chunk-22FJ4JQO.cjs.map +0 -1
- package/dist/chunk-6LEXYQ7J.cjs.map +0 -1
- package/dist/chunk-EWTHDEIW.js.map +0 -1
- package/dist/chunk-H37YVYZA.cjs.map +0 -1
- package/dist/chunk-MLUWABVT.js.map +0 -1
- package/dist/chunk-TD2PHUYP.js.map +0 -1
package/README.md
CHANGED
|
@@ -98,11 +98,14 @@ shows up in your Haven dashboard activity feed.
|
|
|
98
98
|
## Step-by-Step API
|
|
99
99
|
|
|
100
100
|
Discovery and listing: `discoverTools({ verified?: 'any' | 'verified' | 'operator' })` returns the merged
|
|
101
|
-
catalog
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
catalog from three sources, each entry with `source`, `domainVerified` and `verifiedPayable`:
|
|
102
|
+
operator-curated rows (`source: 'operator'`), self-submitted directory entries (`'ingestion'`, epic
|
|
103
|
+
#1717), and rows the x402 Bazaar discovery cron wrote (`'bazaar'`, #4245; seller-asserted name and
|
|
104
|
+
description, only where a deployment enables discovery). `verified: 'verified'` (#2978) filters on the
|
|
105
|
+
badge, not the source: it returns any entry, from any source, whose endpoint Haven watched answer a
|
|
106
|
+
live quote probe (`verifiedPayable === true`); `domainVerified` stays true only for directory entries,
|
|
107
|
+
which also proved domain ownership. `verified: 'operator'` filters on provenance alone and returns
|
|
108
|
+
operator-curated rows only. `submitCatalogEntry(resourceUrl)`
|
|
106
109
|
submits a merchant endpoint to the Verified Payable Directory (queue-only; the seller still must prove
|
|
107
110
|
domain ownership before listing),
|
|
108
111
|
and `getCatalogSubmissionStatus(id)` returns coarse status plus the ownership-proof instructions while
|
|
@@ -270,7 +273,7 @@ const response = await haven.payX402Quote(quote)
|
|
|
270
273
|
const data = await response.json()
|
|
271
274
|
```
|
|
272
275
|
|
|
273
|
-
Merchant-verified x402 retries use the
|
|
276
|
+
Merchant-verified x402 retries use the x402 `exact` scheme on Base USDC (`base` / `eip155:8453`, or Base Sepolia `eip155:84532`): the EIP-3009 `authorization` payload on the bridge, or a delegation when the merchant's entry carries `extra.assetTransferMethod: 'erc7710'`. `haven.fetch()` sends the payment under `PAYMENT-SIGNATURE` (the x402 v2 name), and on the EIP-3009 bridge also under `X-PAYMENT` (v1), so a merchant on either version reads it. **On erc7710 it sends the v2 name ALONE**: that payload is always x402 v2, and its header carries a whole delegation chain, so duplicating it overflows the merchant's header limit and the request is refused with HTTP 431. If you build the retry yourself, follow the same rule: `x402RetryHeadersFor(paymentHeader)` returns exactly those headers (#3727). Haven's older tx-hash proof helper remains exported for Haven-native integrations; it is a different payload that happens to have shared the v2 name, and it is not what `haven.fetch()` sends.
|
|
274
277
|
|
|
275
278
|
For standard x402, the `x402-wallet` identity is the agent delegate wallet, because that is the wallet that signs and settles the merchant payment. Integrations that scope access by Haven wallet address should use a Haven-native flow instead of standard merchant x402.
|
|
276
279
|
|
|
@@ -409,6 +412,9 @@ x402 tool-window failures:
|
|
|
409
412
|
expired funding/quote window → PAYMENT_WINDOW_EXPIRED → re-quote with same idempotency_key
|
|
410
413
|
merchant rejection after funding → MERCHANT_REJECTED_AFTER_FUNDING → haven_sweep_delegate (eip3009 only; erc7710: nothing to sweep, follow the message)
|
|
411
414
|
merchant timeout after funding → MERCHANT_UNRESPONSIVE_AFTER_FUNDING → check_status_later; eip3009: retry once, then haven_sweep_delegate; erc7710: no retry, check status after the window, re-quote only if unsettled
|
|
415
|
+
funding confirmation unreadable (eip3009, hosted) → FUNDING_CONFIRMATION_UNKNOWN → check_status_later; merchant not called; once funding shows confirmed, complete ONCE (#4470)
|
|
416
|
+
funding transaction reverted (eip3009, hosted) → FUNDING_REVERTED → stop_and_tell_user; nothing reached the delegate (#4470)
|
|
417
|
+
no answer to a submit (hosted haven_submit, and haven_settle_mcp_tool's erc7710 settle) → NO_ANSWER_OUTCOME_UNKNOWN → check_status_later; never re-submit, never a new payment (#4470)
|
|
412
418
|
```
|
|
413
419
|
|
|
414
420
|
### `phase` reference
|
|
@@ -425,6 +431,8 @@ x402 tool-window failures:
|
|
|
425
431
|
| `rejected` | The payment was rejected and cannot proceed. | yes |
|
|
426
432
|
| `expired` | Payment expired before completion. | yes |
|
|
427
433
|
| `failed` | Haven could not complete the payment. | yes |
|
|
434
|
+
| `insufficient_funds` | Carried by the `delegation_budget_exceeded` refusal — `403` at prepare, or `502` when the budget ran out by the time the payment was signed — with `nextAction: fund_account_or_raise_allowance`. The budget must be raised, or the period reset, before a new payment can succeed. | yes |
|
|
435
|
+
| `funded_but_unsettled` | The EIP-3009 bridge's funding leg confirmed, but the merchant leg has not settled: either the merchant rejected the retry (`nextAction: sweep_stranded_funds`) or no merchant response was ever recorded (`nextAction: retry_original_x402_request`). Follow `nextAction`. | no |
|
|
428
436
|
| `delivered_unverified` | **#3420: terminal.** The merchant delivered, but the settlement window and the sweep's last attribution chance have both passed with no verified on-chain evidence. Polling cannot change this; the only remedy is reporting a real settlement hash (`haven_report_settlement_evidence`). | yes |
|
|
429
437
|
|
|
430
438
|
The merchant settlement leg of x402 (and the MPP retry) is the agent's own request to the merchant — it does not have a Haven `phase`. The payment is `funding_sent` until the agent retries with the payment header (`PAYMENT-SIGNATURE`, plus `X-PAYMENT` on this bridged path) (x402) or the MPP proof header; from Haven's perspective the payment becomes `executed` only after the agent successfully resumes.
|
|
@@ -442,6 +450,8 @@ The merchant settlement leg of x402 (and the MPP retry) is the agent's own reque
|
|
|
442
450
|
| `retry_original_x402_request` | Haven's funding leg confirmed but no merchant response was ever recorded — most often because the process crashed between the funding confirmation and the merchant retry (a 15-minute grace window applies before this fires; a client-reported merchant rejection instead yields `sweep_stranded_funds`). Call `resumeX402Payment()` with the preserved `resumeState`, or rehydrate it first with `getResumeState(payment_id)`. Do not start a new payment for the same purchase. |
|
|
443
451
|
| `stop_and_tell_user` | Stop retrying and tell the user what happened — the payment failed, was rejected, or (#3420) was delivered but its settlement can no longer be verified. |
|
|
444
452
|
| `request_again_if_user_still_wants_it` | The request expired; ask again only if the user still wants the payment. |
|
|
453
|
+
| `retry_with_explicit_context` | #1307: retry the same tool call, passing `merchant_url`, `tool_name`, `arguments` and `mcp_transport` explicitly — the server had no stored context to rehydrate for this payment id. |
|
|
454
|
+
| `fund_account_or_raise_allowance` | Stop and tell the user the agent's budget must be raised (or its period reset) before a new payment can succeed; it rides on the `delegation_budget_exceeded` refusal. An approval will not fix it. |
|
|
445
455
|
| `payment_window_expired` | The x402 funding/quote window expired. Re-quote the same paid MCP tool call with the same `idempotency_key`, then sign the fresh `payload_hash`. |
|
|
446
456
|
| `sweep_stranded_funds` | A funding leg succeeded but the merchant/protocol leg did not settle. Stop retrying and use `haven_sweep_delegate` to recover stranded delegate funds. |
|
|
447
457
|
|
|
@@ -468,8 +478,10 @@ queue**: the queue-and-approve path belonged to the retired Safe rail, which now
|
|
|
468
478
|
answers HTTP 410 at every agent-payment entry point.
|
|
469
479
|
|
|
470
480
|
If an agent requests a payment outside that policy, Haven **declines it before
|
|
471
|
-
any money moves** — during prepare, before
|
|
472
|
-
agent is asked to sign.
|
|
481
|
+
any money moves** — during prepare, before any payment intent is created and
|
|
482
|
+
before the agent is asked to sign. The one row written is the refusal itself,
|
|
483
|
+
in the `payment_refusals` ledger (#2945, migration 086; written through the
|
|
484
|
+
`refuse()` choke point since #3053). `POST /payments` answers `403` when no active delegation
|
|
473
485
|
authorizes that token and recipient, `403 delegation_budget_exceeded` when the
|
|
474
486
|
remaining period budget cannot cover the amount (#3503; the x402 authorize path
|
|
475
487
|
answers the same), and `502` when the on-chain caveat check rejects a
|
|
@@ -606,7 +618,9 @@ For MCP/SSE x402 tools, keep the same MCP session and JSON-RPC payload where the
|
|
|
606
618
|
merchant requires it: initialize, retain `mcp-session-id`, send the original
|
|
607
619
|
`tools/call`, parse the 402 challenge, wait for the funding leg to confirm if
|
|
608
620
|
the payment is bridged, then resume with the same `payment_id` and retry the
|
|
609
|
-
original `tools/call
|
|
621
|
+
original `tools/call` with the headers `x402RetryHeadersFor(paymentHeader)`
|
|
622
|
+
returns — `PAYMENT-SIGNATURE` (x402 v2), plus `X-PAYMENT` (v1) only on the
|
|
623
|
+
EIP-3009 bridge; erc7710 sends the v2 name alone. Use a stable `idempotencyKey` for the
|
|
610
624
|
user intent so fresh merchant quotes or sessions do not become duplicate Haven
|
|
611
625
|
payments.
|
|
612
626
|
|
|
@@ -663,6 +677,28 @@ treat them as proof of purchase rather than retrying:
|
|
|
663
677
|
|
|
664
678
|
See [Idempotency](#idempotency-what-the-key-guarantees-and-what-it-costs).
|
|
665
679
|
|
|
680
|
+
**Why a `HavenApiError` happened is `err.failureCause`, not only its status
|
|
681
|
+
(#4470).** The status alone misleads in two ways, so two causes are marked
|
|
682
|
+
where the SDK creates the error, and every other error leaves the field
|
|
683
|
+
`undefined`:
|
|
684
|
+
|
|
685
|
+
- `{ kind: 'no_answer', method }` — the transport got no usable answer: the
|
|
686
|
+
request timed out (`statusCode` 408), `fetch` threw, or the body was not
|
|
687
|
+
JSON (`statusCode` 0; a gateway's HTML 502 arrives this way). Whether the
|
|
688
|
+
call took effect is unknown. A `GET` may be retried; a `POST` should not
|
|
689
|
+
be — read the payment's status first. A server that answers 408 with a
|
|
690
|
+
JSON body is an answer and carries no cause.
|
|
691
|
+
- `{ kind: 'deterministic' }` — the SDK refused an answer it cannot use (a
|
|
692
|
+
missing field, the wrong shape). A retry gets the same answer, whatever the
|
|
693
|
+
5xx status says. Built with `HavenApiError.deterministic(...)`.
|
|
694
|
+
|
|
695
|
+
The funding wait before a merchant retry has two typed outcomes, both
|
|
696
|
+
`HavenApiError` subclasses: `FundingConfirmationUnknownError` (status 504;
|
|
697
|
+
the confirmation could not be read in time, so funding may have moved — check
|
|
698
|
+
the payment's status) and `FundingRevertedError` (status 502; the funding
|
|
699
|
+
transaction reverted, nothing reached the delegate). Each carries `txHash`,
|
|
700
|
+
`chainId` and a `fundingErrorCode`.
|
|
701
|
+
|
|
666
702
|
## License
|
|
667
703
|
|
|
668
704
|
MIT
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Q as AgentNextStep, Z as AgentPaymentNextAction,
|
|
1
|
+
import { Q as AgentNextStep, Z as AgentPaymentNextAction, aP as X402PaymentOption, aO as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, aq as HavenSigningError } from './types-CAvsjRKi.js';
|
|
2
2
|
import { PaymentRequirements } from 'x402/types';
|
|
3
3
|
import { Hex, Address } from 'viem';
|
|
4
4
|
|
|
@@ -200,7 +200,7 @@ declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): strin
|
|
|
200
200
|
* This SDK's own version. Owned by `scripts/release-bump.mjs`, which rewrites
|
|
201
201
|
* it with the package version on every release — never hand-edit it.
|
|
202
202
|
*/
|
|
203
|
-
declare const SDK_VERSION = "0.
|
|
203
|
+
declare const SDK_VERSION = "0.12.0-alpha.0";
|
|
204
204
|
/** The request header every published Haven client sends. */
|
|
205
205
|
declare const HAVEN_CLIENT_HEADER = "X-Haven-Client";
|
|
206
206
|
/** `<package>/<version>` — the value of {@link HAVEN_CLIENT_HEADER}. */
|
|
@@ -269,6 +269,14 @@ declare function parseNextTool(literal: string): {
|
|
|
269
269
|
interface NextStepTarget<TArgs> {
|
|
270
270
|
role: NextToolServerRole;
|
|
271
271
|
validate: (input: unknown) => string | null;
|
|
272
|
+
/**
|
|
273
|
+
* #4449: the bare tool name to render, when the target-map key is not it.
|
|
274
|
+
* One hosted tool that takes several argument shapes is declared once per
|
|
275
|
+
* shape under `<tool>#<variant>` keys (the signer's `haven_submit#payment`
|
|
276
|
+
* beside `#task_budget` / `#sub_budget`): the key selects the shape, this
|
|
277
|
+
* names the tool. Absent → the key IS the name, which is every other target.
|
|
278
|
+
*/
|
|
279
|
+
name?: string;
|
|
272
280
|
/** Phantom carrier for the argument type; never read at runtime. */
|
|
273
281
|
readonly _args?: TArgs;
|
|
274
282
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Q as AgentNextStep, Z as AgentPaymentNextAction,
|
|
1
|
+
import { Q as AgentNextStep, Z as AgentPaymentNextAction, aP as X402PaymentOption, aO as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, aq as HavenSigningError } from './types-CAvsjRKi.cjs';
|
|
2
2
|
import { PaymentRequirements } from 'x402/types';
|
|
3
3
|
import { Hex, Address } from 'viem';
|
|
4
4
|
|
|
@@ -200,7 +200,7 @@ declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): strin
|
|
|
200
200
|
* This SDK's own version. Owned by `scripts/release-bump.mjs`, which rewrites
|
|
201
201
|
* it with the package version on every release — never hand-edit it.
|
|
202
202
|
*/
|
|
203
|
-
declare const SDK_VERSION = "0.
|
|
203
|
+
declare const SDK_VERSION = "0.12.0-alpha.0";
|
|
204
204
|
/** The request header every published Haven client sends. */
|
|
205
205
|
declare const HAVEN_CLIENT_HEADER = "X-Haven-Client";
|
|
206
206
|
/** `<package>/<version>` — the value of {@link HAVEN_CLIENT_HEADER}. */
|
|
@@ -269,6 +269,14 @@ declare function parseNextTool(literal: string): {
|
|
|
269
269
|
interface NextStepTarget<TArgs> {
|
|
270
270
|
role: NextToolServerRole;
|
|
271
271
|
validate: (input: unknown) => string | null;
|
|
272
|
+
/**
|
|
273
|
+
* #4449: the bare tool name to render, when the target-map key is not it.
|
|
274
|
+
* One hosted tool that takes several argument shapes is declared once per
|
|
275
|
+
* shape under `<tool>#<variant>` keys (the signer's `haven_submit#payment`
|
|
276
|
+
* beside `#task_budget` / `#sub_budget`): the key selects the shape, this
|
|
277
|
+
* names the tool. Absent → the key IS the name, which is every other target.
|
|
278
|
+
*/
|
|
279
|
+
name?: string;
|
|
272
280
|
/** Phantom carrier for the argument type; never read at runtime. */
|
|
273
281
|
readonly _args?: TArgs;
|
|
274
282
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkZA3NOSO2_cjs = require('./chunk-ZA3NOSO2.cjs');
|
|
4
4
|
var ethers = require('ethers');
|
|
5
5
|
var viem = require('viem');
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ function delegationDomainSeparator(chainId) {
|
|
|
18
18
|
viem.keccak256(viem.toBytes("DelegationManager")),
|
|
19
19
|
viem.keccak256(viem.toBytes("1")),
|
|
20
20
|
BigInt(chainId),
|
|
21
|
-
|
|
21
|
+
chunkZA3NOSO2_cjs.DELEGATION_MANAGER
|
|
22
22
|
]
|
|
23
23
|
)
|
|
24
24
|
);
|
|
@@ -102,5 +102,5 @@ function verifyPaymentReceipt(receipt, recover = defaultRecover) {
|
|
|
102
102
|
|
|
103
103
|
exports.RECEIPT_VERSION = RECEIPT_VERSION;
|
|
104
104
|
exports.verifyPaymentReceipt = verifyPaymentReceipt;
|
|
105
|
-
//# sourceMappingURL=chunk-
|
|
106
|
-
//# sourceMappingURL=chunk-
|
|
105
|
+
//# sourceMappingURL=chunk-4JTLJVBS.cjs.map
|
|
106
|
+
//# sourceMappingURL=chunk-4JTLJVBS.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/receipt.ts"],"names":["keccak256","toBytes","encodeAbiParameters","DELEGATION_MANAGER","concatHex","ethers"],"mappings":";;;;;;AA6CO,IAAM,eAAA,GAAkB;AA8E/B,IAAM,+CAAoD,IAAI,GAAA,CAAI,CAAC,IAAA,EAAM,KAAK,CAAC,CAAA;AAE/E,IAAM,sBAAA,GAAyBA,cAAA;AAAA,EAC7BC,aAAQ,oFAAoF;AAC9F,CAAA;AAOA,SAAS,0BAA0B,OAAA,EAAsB;AACvD,EAAA,OAAOD,cAAA;AAAA,IACLE,wBAAA;AAAA,MACE,CAAC,EAAE,IAAA,EAAM,SAAA,IAAa,EAAE,IAAA,EAAM,WAAU,EAAG,EAAE,MAAM,SAAA,EAAU,EAAG,EAAE,IAAA,EAAM,SAAA,IAAa,EAAE,IAAA,EAAM,WAAW,CAAA;AAAA,MACxG;AAAA,QACE,sBAAA;AAAA,QACAF,cAAA,CAAUC,YAAA,CAAQ,mBAAmB,CAAC,CAAA;AAAA,QACtCD,cAAA,CAAUC,YAAA,CAAQ,GAAG,CAAC,CAAA;AAAA,QACtB,OAAO,OAAO,CAAA;AAAA,QACdE;AAAA;AACF;AACF,GACF;AACF;AAGA,SAAS,gBAAA,CAAiB,YAAoB,OAAA,EAAsB;AAClE,EAAA,OAAOH,cAAA,CAAUI,eAAU,CAAC,QAAA,EAAU,0BAA0B,OAAO,CAAA,EAAG,UAAiB,CAAC,CAAC,CAAA;AAC/F;AAGA,SAAS,cAAA,CAAe,MAAc,SAAA,EAA2B;AAC/D,EAAA,OAAOC,aAAA,CAAO,cAAA,CAAe,IAAA,EAAM,SAAS,CAAA;AAC9C;AAEA,IAAM,oBAAA,GAAuB,EAAE,QAAA,EAAU,KAAA,EAAO,QAAQ,sBAAA,EAAuB;AAS/E,SAAS,KAAA,CAAM,QAAA,EAAkB,IAAA,EAAc,SAAA,EAAmB,OAAA,EAAiC;AACjG,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI;AACF,IAAA,SAAA,GAAY,OAAA,CAAQ,MAAM,SAAS,CAAA;AAAA,EACrC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAgB;AAAA,EAC9C;AACA,EAAA,IAAI,SAAA,CAAU,WAAA,EAAY,KAAM,QAAA,CAAS,aAAY,EAAG;AACtD,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,iBAAA,EAAmB,iBAAiB,SAAA,EAAU;AAAA,EAC5E;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,eAAA,EAAiB,SAAA,EAAU;AAChD;AAEA,SAAS,MAAA,CAAO,QAAqB,YAAA,EAAsE;AACzG,EAAA,IAAI,OAAO,EAAA,EAAI;AACb,IAAA,OAAO,EAAE,QAAA,EAAU,IAAA,EAAM,eAAA,EAAiB,MAAA,CAAO,iBAAiB,YAAA,EAAa;AAAA,EACjF;AACA,EAAA,OAAO,OAAO,eAAA,KAAoB,MAAA,GAC9B,EAAE,QAAA,EAAU,KAAA,EAAO,QAAQ,MAAA,CAAO,MAAA,EAAQ,eAAA,EAAiB,MAAA,CAAO,iBAAgB,GAClF,EAAE,UAAU,KAAA,EAAO,MAAA,EAAQ,OAAO,MAAA,EAAO;AAC/C;AAcO,SAAS,oBAAA,CACd,OAAA,EACA,OAAA,GAAqB,cAAA,EACA;AAGrB,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,MAAM,OAAO,oBAAA;AAC5D,EAAA,IAAI,MAAA,GAAS,OAAA;AAYb,EAAA,IAAI,OAAO,MAAA,CAAO,aAAA,KAAkB,QAAA,IAAY,MAAA,CAAO,kBAAkB,IAAA,EAAM;AAC7E,IAAA,IAAI,OAAO,MAAA,CAAO,OAAA,KAAY,QAAA,IAAY,MAAA,CAAO,YAAY,IAAA,EAAM;AACjE,MAAA,OAAO,oBAAA;AAAA,IACT;AACA,IAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,EAClB;AACA,EAAA,IAAI,OAAO,MAAA,CAAO,aAAA,KAAkB,QAAA,IAAY,MAAA,CAAO,kBAAkB,IAAA,EAAM;AAC7E,IAAA,OAAO,oBAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAO,MAAA,CAAO,aAAA;AAMpB,EAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,SAAA,EAAW,iBAAgB,GAAI,IAAA;AAC3D,EAAA,IAAI,OAAO,aAAa,QAAA,IAAY,QAAA,KAAa,MAAM,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,KAAa,EAAA,EAAI;AACtG,IAAA,OAAO,oBAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,KAAc,EAAA,EAAI;AACrD,IAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,mBAAA,EAAoB;AAAA,EACxD;AAEA,EAAA,MAAM,OAAA,GACJ,OAAO,MAAA,CAAO,OAAA,EAAS,YAAY,QAAA,GAAW,MAAA,CAAO,QAAQ,OAAA,GAAU,MAAA;AACzE,EAAA,MAAM,gBAAA,GAAmB,OAAA,KAAY,MAAA,IAAa,4BAAA,CAA6B,IAAI,OAAO,CAAA;AAK1F,EAAA,IAAI,oBAAoB,eAAA,EAAiB;AACvC,IAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,wBAAA,EAAyB;AAAA,EAC7D;AAIA,EAAA,IAAI,oBAAoB,mBAAA,EAAqB;AAC3C,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,wBAAA,EAAyB;AAAA,IAC7D;AACA,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,gBAAA,CAAiB,UAAU,OAAiB,CAAA;AAAA,IACvD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAgB;AAAA,IACpD;AACA,IAAA,OAAO,OAAO,KAAA,CAAM,QAAA,EAAU,QAAQ,SAAA,EAAW,OAAO,GAAG,mBAAmB,CAAA;AAAA,EAChF;AAMA,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,QAAA,EAAU,QAAA,EAAU,WAAW,OAAO,CAAA;AACxD,EAAA,IAAI,GAAA,CAAI,EAAA,EAAI,OAAO,MAAA,CAAO,KAAK,WAAW,CAAA;AAC1C,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,gBAAA,CAAiB,UAAU,OAAiB,CAAA;AAAA,IACvD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,MAAA,CAAO,KAAK,WAAW,CAAA;AAAA,IAChC;AACA,IAAA,MAAM,SAAA,GAAY,KAAA,CAAM,QAAA,EAAU,MAAA,EAAQ,WAAW,OAAO,CAAA;AAC5D,IAAA,IAAI,SAAA,CAAU,EAAA,EAAI,OAAO,MAAA,CAAO,WAAW,mBAAmB,CAAA;AAAA,EAChE;AACA,EAAA,OAAO,MAAA,CAAO,KAAK,WAAW,CAAA;AAChC","file":"chunk-4JTLJVBS.cjs","sourcesContent":["import { ethers } from 'ethers'\nimport { concatHex, encodeAbiParameters, keccak256, toBytes, type Hex } from 'viem'\nimport { DELEGATION_MANAGER } from './settlement-child.js'\nimport type { RawPaymentParties } from './types.js'\n\n/**\n * Verifiable payment receipts.\n *\n * A self-contained bundle for a settled Haven payment whose agent\n * authorisation can be checked offline. What `verifyPaymentReceipt` proves is\n * deliberately narrow: the `payment` block (amount, recipient) is\n * Haven-asserted and is NOT bound by the signature, and `verified: true` never\n * proves the payment settled on-chain — settlement stays an explorer check on\n * `onChain.txHash` / `settlementTxHash`.\n *\n * What `verified: true` means, per scheme:\n *\n * - erc7710 (`authorization.signatureScheme: 'eip712_delegation'`): the bundle\n * carries the settlement child's EIP-712 struct hash as `signHash`. The\n * verifier rebuilds the digest the delegate actually signed —\n * `keccak256(0x1901 ‖ domainSeparator(DelegationManager, chainId) ‖ signHash)`\n * — from the DelegationManager address the SDK pins and the bundle's\n * `onChain.chainId`, never from a value the receipt itself vouches for.\n * `verified: true` means the delegate key signed that settlement delegation\n * (`verifiedOver: 'delegation_digest'`).\n * - direct payments and the eip3009 funding leg\n * (`signatureScheme: 'eip712_userop'`) sign an ERC-4337 user operation the\n * bundle does not carry: they return `not_verifiable_offline` rather than a\n * false accusation.\n * - retired-rail bundles (no scheme) carry a raw-signed `signHash`; the\n * verifier recovers over it directly, then over the delegation digest when\n * the chain allows rebuilding it.\n *\n * Anything that is not a signed bundle — including a `haven_list_receipts`\n * history row, which carries no signature at all — returns\n * `not_a_signed_receipt`. Verification never throws.\n *\n * #3723: the response `GET /payments/{id}/receipt` returns —\n * `{ receipt, verification }` — is accepted AS-IS: when the top level carries\n * no `authorization`, the `.receipt` object inside is verified instead (one\n * level, no recursion). The wrapper's `verification` is never read — it is\n * Haven's own self-check, and trusting it would defeat an offline verifier.\n *\n * This lives in the SDK so agents and users can verify receipts client-side.\n */\nexport const RECEIPT_VERSION = 'haven-receipt-1'\n\nexport interface PaymentReceipt {\n version: typeof RECEIPT_VERSION\n paymentId: string\n payment: {\n token: string\n tokenAddress: string\n amount: string\n amountSek: string | null\n recipient: string\n /** The payer's smart-account address. */\n account: string\n /**\n * #2960: one party vocabulary for \"who paid\", additive alongside `account`\n * above (which is `parties.treasury_account` only). Optional: a server\n * from before #2960 emits neither. Ignored by `verifyPaymentReceipt`,\n * which reads only the bundle's `authorization` and `onChain.chainId`.\n */\n parties?: RawPaymentParties\n chainId: number\n settledAt: string | null\n resourceUrl: string | null\n /**\n * #3770: the paying agent's own evidence-only verdict on what the\n * merchant DELIVERED (`ok` / `unusable` / `partial`, plus a bounded\n * note). Additive and OPTIONAL: a server from before #3770 emits\n * neither, and `null` means the agent has not reported. Ignored by\n * `verifyPaymentReceipt`, which reads only the bundle's `authorization`\n * and `onChain.chainId` — the same rule `parties` follows. Evidence\n * only: it never changes what the\n * payment itself is, and `settled`/amounts are untouched by a report.\n */\n deliveryQuality?: {\n quality: 'ok' | 'unusable' | 'partial'\n note: string | null\n reportedAt: string | null\n } | null\n }\n /** The agent's cryptographic authorisation — what makes the receipt verifiable. */\n authorization: {\n delegate: string\n signHash: string\n signature: string | null\n /**\n * #3418: which digest the delegate signed — selects what offline\n * verification rebuilds. `'eip712_delegation'`: the settlement\n * delegation's EIP-712 digest (erc7710). `'eip712_userop'`: an ERC-4337\n * user-operation digest the bundle does not carry (direct payments, the\n * eip3009 funding leg) — not verifiable offline. Absent on retired-rail\n * bundles and on backends older than #3418, whose `signHash` was signed\n * raw. The value is only a selector: a lying one cannot make a forged\n * signature verify, because recovery must still return `delegate`.\n */\n signatureScheme?: 'eip712_delegation' | 'eip712_userop'\n }\n onChain: {\n txHash: string | null\n chainId: number\n }\n}\n\nexport type ReceiptVerification =\n | { verified: true; recoveredSigner: string; verifiedOver: 'sign_hash' | 'delegation_digest' }\n | {\n verified: false\n reason:\n /** #3418: the input is not a haven-receipt-1 bundle (a haven_list_receipts row, null, undefined, a non-object). */\n | 'not_a_signed_receipt'\n /** #3418: eip712_userop bundle; or a delegation bundle on a chain the SDK pins no DelegationManager for. */\n | 'not_verifiable_offline'\n | 'missing_signature'\n | 'bad_signature'\n | 'signer_mismatch'\n recoveredSigner?: string\n }\n\n/** Chains whose DelegationManager the SDK pins (same address on both — rails/delegation-contracts.ts). */\nconst DELEGATION_MANAGER_CHAIN_IDS: ReadonlySet<number> = new Set([8453, 84532])\n\nconst EIP712_DOMAIN_TYPEHASH = keccak256(\n toBytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),\n)\n\n/**\n * The EIP-712 domain separator of the DelegationManager on `chainId`, rebuilt\n * from the manager's own constants (name/version, fixed in the contract) and\n * the address the SDK pins — never from a value the receipt vouches for.\n */\nfunction delegationDomainSeparator(chainId: number): Hex {\n return keccak256(\n encodeAbiParameters(\n [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes32' }, { type: 'uint256' }, { type: 'address' }],\n [\n EIP712_DOMAIN_TYPEHASH,\n keccak256(toBytes('DelegationManager')),\n keccak256(toBytes('1')),\n BigInt(chainId),\n DELEGATION_MANAGER as Hex,\n ],\n ),\n )\n}\n\n/** The EIP-712 digest over a delegation struct hash (what the delegate signs). */\nfunction delegationDigest(structHash: string, chainId: number): Hex {\n return keccak256(concatHex(['0x1901', delegationDomainSeparator(chainId), structHash as Hex]))\n}\n\n/** Default ECDSA recovery (raw ecrecover over the hash, no message prefix). */\nfunction defaultRecover(hash: string, signature: string): string {\n return ethers.recoverAddress(hash, signature)\n}\n\nconst NOT_A_SIGNED_RECEIPT = { verified: false, reason: 'not_a_signed_receipt' } as const\n\ntype RecoverFn = (hash: string, signature: string) => string\n\ntype MatchResult =\n | { ok: true; recoveredSigner: string }\n | { ok: false; reason: 'bad_signature' | 'signer_mismatch'; recoveredSigner?: string }\n\n/** Recover over one candidate hash and compare the signer with the named delegate. */\nfunction match(delegate: string, hash: string, signature: string, recover: RecoverFn): MatchResult {\n let recovered: string\n try {\n recovered = recover(hash, signature)\n } catch {\n return { ok: false, reason: 'bad_signature' }\n }\n if (recovered.toLowerCase() !== delegate.toLowerCase()) {\n return { ok: false, reason: 'signer_mismatch', recoveredSigner: recovered }\n }\n return { ok: true, recoveredSigner: recovered }\n}\n\nfunction finish(result: MatchResult, verifiedOver: 'sign_hash' | 'delegation_digest'): ReceiptVerification {\n if (result.ok) {\n return { verified: true, recoveredSigner: result.recoveredSigner, verifiedOver }\n }\n return result.recoveredSigner !== undefined\n ? { verified: false, reason: result.reason, recoveredSigner: result.recoveredSigner }\n : { verified: false, reason: result.reason }\n}\n\n/**\n * Verify a receipt's agent authorisation offline: recover the signer and\n * confirm it is the agent delegate, over whichever digest the bundle's scheme\n * names (see the module doc for what that proves — and what it does not).\n * Never throws: anything that is not a signed receipt — a\n * `haven_list_receipts` history row, null, undefined, a non-object — returns\n * `not_a_signed_receipt`. The `{ receipt, verification }` wrapper the receipt\n * endpoint returns is accepted as-is: `.receipt` is verified, and the\n * wrapper's `verification` — Haven's own self-check — is never read. Pure —\n * `recover` is injectable but defaults to\n * standard ECDSA recovery, so this runs anywhere (no Haven backend).\n */\nexport function verifyPaymentReceipt(\n receipt: unknown,\n recover: RecoverFn = defaultRecover,\n): ReceiptVerification {\n // #3418 rule 1: a list row (or any non-bundle) has no authorization object\n // holding string delegate/signHash — answer, never throw.\n if (typeof receipt !== 'object' || receipt === null) return NOT_A_SIGNED_RECEIPT\n let source = receipt as {\n authorization?: unknown\n receipt?: unknown\n onChain?: { chainId?: unknown }\n }\n // #3723: accept the endpoint's response as-is. When the top level carries no\n // `authorization` and `.receipt` is a non-null object, verify the bundle\n // inside the `{ receipt, verification }` wrapper (GET\n // /payments/{id}/receipt, and HavenClient.getReceipt's re-wrap). ONE level\n // only — no recursion — and the wrapper's `verification` is NEVER read: it\n // is Haven's own self-check, and trusting it would defeat an offline\n // verifier. A list row wrapped or bare still answers not_a_signed_receipt.\n if (typeof source.authorization !== 'object' || source.authorization === null) {\n if (typeof source.receipt !== 'object' || source.receipt === null) {\n return NOT_A_SIGNED_RECEIPT\n }\n source = source.receipt as typeof source\n }\n if (typeof source.authorization !== 'object' || source.authorization === null) {\n return NOT_A_SIGNED_RECEIPT\n }\n const auth = source.authorization as {\n delegate?: unknown\n signHash?: unknown\n signature?: unknown\n signatureScheme?: unknown\n }\n const { delegate, signHash, signature, signatureScheme } = auth\n if (typeof delegate !== 'string' || delegate === '' || typeof signHash !== 'string' || signHash === '') {\n return NOT_A_SIGNED_RECEIPT\n }\n if (typeof signature !== 'string' || signature === '') {\n return { verified: false, reason: 'missing_signature' }\n }\n\n const chainId =\n typeof source.onChain?.chainId === 'number' ? source.onChain.chainId : undefined\n const digestVerifiable = chainId !== undefined && DELEGATION_MANAGER_CHAIN_IDS.has(chainId)\n\n // #3418 rule 4: a userop digest needs the full UserOperation, which the\n // bundle does not carry. Return not_verifiable_offline — never\n // signer_mismatch, which would accuse a genuine payment.\n if (signatureScheme === 'eip712_userop') {\n return { verified: false, reason: 'not_verifiable_offline' }\n }\n\n // #3418 rule 3: rebuild the delegation digest from the pinned manager and\n // the bundle's chain id, then recover over it.\n if (signatureScheme === 'eip712_delegation') {\n if (!digestVerifiable) {\n return { verified: false, reason: 'not_verifiable_offline' }\n }\n let digest: string\n try {\n digest = delegationDigest(signHash, chainId as number)\n } catch {\n return { verified: false, reason: 'bad_signature' }\n }\n return finish(match(delegate, digest, signature, recover), 'delegation_digest')\n }\n\n // #3418 rule 5: absent or unknown scheme — retired-rail history (signed raw\n // over signHash) or a backend older than this change. Raw recovery first,\n // then the delegation digest when the chain allows rebuilding it. This is\n // the one remaining ambiguous case, limited to old bundles.\n const raw = match(delegate, signHash, signature, recover)\n if (raw.ok) return finish(raw, 'sign_hash')\n if (digestVerifiable) {\n let digest: string\n try {\n digest = delegationDigest(signHash, chainId as number)\n } catch {\n return finish(raw, 'sign_hash')\n }\n const delegated = match(delegate, digest, signature, recover)\n if (delegated.ok) return finish(delegated, 'delegation_digest')\n }\n return finish(raw, 'sign_hash')\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HavenSigningError, deriveDelegateAccountAddress, DELEGATION_MANAGER, assertRedeemsOwnBudgetDelegation, verifySettlementChild, REDEEM_DELEGATIONS_ABI, chainIdForNetwork, ROOT_AUTHORITY, CAVEAT_ENFORCERS, DELEGATION_TUPLE_COMPONENTS } from './chunk-
|
|
1
|
+
import { HavenSigningError, deriveDelegateAccountAddress, DELEGATION_MANAGER, assertRedeemsOwnBudgetDelegation, verifySettlementChild, REDEEM_DELEGATIONS_ABI, chainIdForNetwork, ROOT_AUTHORITY, CAVEAT_ENFORCERS, DELEGATION_TUPLE_COMPONENTS } from './chunk-UPEDQLAL.js';
|
|
2
2
|
import { decodeFunctionData, encodeFunctionData, encodePacked, recoverTypedDataAddress, serializeSignature, hashTypedData, keccak256, concatHex, toHex, encodeAbiParameters } from 'viem';
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
4
|
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
@@ -780,7 +780,7 @@ function stableStringify2(value) {
|
|
|
780
780
|
}
|
|
781
781
|
|
|
782
782
|
// src/client-identity.ts
|
|
783
|
-
var SDK_VERSION = "0.
|
|
783
|
+
var SDK_VERSION = "0.12.0-alpha.0";
|
|
784
784
|
var HAVEN_CLIENT_HEADER = "X-Haven-Client";
|
|
785
785
|
function havenClientIdentity(pkg, version) {
|
|
786
786
|
return `${pkg}/${version}`;
|
|
@@ -1025,11 +1025,12 @@ function createNextStepBuilder(targets) {
|
|
|
1025
1025
|
if (problem) {
|
|
1026
1026
|
return { ...base, next_tool_omitted_reason: `next_arguments do not parse under ${i.nextTool}: ${problem}` };
|
|
1027
1027
|
}
|
|
1028
|
+
const name = target.name ?? i.nextTool;
|
|
1028
1029
|
return {
|
|
1029
1030
|
...base,
|
|
1030
|
-
next_tool: renderNextTool(target.role,
|
|
1031
|
+
next_tool: renderNextTool(target.role, name),
|
|
1031
1032
|
next_tool_server: NEXT_TOOL_SERVER_NAMES[target.role],
|
|
1032
|
-
next_tool_name:
|
|
1033
|
+
next_tool_name: name,
|
|
1033
1034
|
next_tool_server_role: target.role,
|
|
1034
1035
|
next_arguments: i.nextArguments
|
|
1035
1036
|
};
|
|
@@ -1385,5 +1386,5 @@ function hashDelegation(delegation) {
|
|
|
1385
1386
|
}
|
|
1386
1387
|
|
|
1387
1388
|
export { CAVEAT_TYPEHASH, DEFAULT_NEXT_TOOL_BY_ACTION, DELEGATION_TYPEHASH, DIRECT_PAYMENT_CHAIN_IDS, ERC7710_ASSET_TRANSFER_METHOD, EXECUTE_ABI, HAVEN_CLIENT_HEADER, HAVEN_MINIMUM_NODE_VERSION, HavenTypedDataRefusedError, MAX_TASK_BUDGET_TTL_SECONDS, NEXT_TOOL_SERVER_NAMES, NEXT_TOOL_SERVER_ROLES, SDK_CLIENT_IDENTITY, SDK_VERSION, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, TAX_DECLARATION_DOMAIN, TAX_DECLARATION_PRIMARY_TYPE, TAX_DECLARATION_TYPES, TRANSFER_WITH_AUTHORIZATION_TYPES, TYPED_DATA_NOT_ALLOWED, TaxDeclarationRefusedError, X402PaymentHeaderValidationError, X402_LEGACY_PAYMENT_HEADER_NAME, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_PAYMENT_HEADER_NAME, X402_PAYMENT_HEADER_NAMES, X402_PAYMENT_HEADER_NAMES_SENT, X402_PAYMENT_NONCE_TAG, X402_PAYMENT_REQUIRED_HEADER_NAME, X402_PAYMENT_RESPONSE_HEADER_NAME, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, X_TAX_DECLARATION_HEADER, addressFromKey, assertBoundDirectPaymentUserOp, assertFundingLegPaysDelegate, assertOwnSettlementChild, assertOwnTaskBudgetCloseUserOp, assertOwnTaskChild, buildSignedTaxDeclaration, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, buildX402IdempotencyKey, compareNodeVersions, createNextStepBuilder, decodeBase64Json, decodeBase64Utf8, defaultNextToolFor, deriveX402PaymentNonce, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, encodeTaxDeclarationHeader, hashDelegation, havenClientIdentity, isErc7710Option, isSupportedNodeVersion, isSweepableChain, isTaskChildTypedData, normalizePaymentRequired, parseNextTool, parsePaymentRequired, parsePaymentRequiredResponse, principalAttributionHash, readClientUpdate, renderNextTool, resolveTokenBySymbol, resolveTokenFromAddress, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, sweepUsdcAddress, sweepUsdcDomain, taxPrincipalId, toStandardPaymentRequirements, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifySignature, verifyTaxDeclarationSignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses, x402PaymentHeaderNamesFor, x402PaymentHeaderNamesSent, x402RetryHeadersFor, x402V2PaymentEnvelope };
|
|
1388
|
-
//# sourceMappingURL=chunk-
|
|
1389
|
-
//# sourceMappingURL=chunk-
|
|
1389
|
+
//# sourceMappingURL=chunk-7M3CIW7W.js.map
|
|
1390
|
+
//# sourceMappingURL=chunk-7M3CIW7W.js.map
|