@haven_ai/sdk 0.5.0-alpha.1 → 0.7.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.
@@ -28,6 +28,9 @@ function connectorRerunCommand(args, options) {
28
28
  const command = `npx ${flags}${connectorSpec(channel)}`;
29
29
  return args ? `${command} ${args}` : command;
30
30
  }
31
+ function connectorUpgradeCommand(options) {
32
+ return connectorRerunCommand("--doctor", { channel: options?.channel, npxFlags: "-y" });
33
+ }
31
34
 
32
35
  // src/types.ts
33
36
  var DEFAULT_CONFIRMATION_TIMEOUT_MS = 9e4;
@@ -73,7 +76,21 @@ var AgentPaymentPhase = {
73
76
  * agent should stop, tell the user, and wait for the sweep flow to reclaim
74
77
  * the funds.
75
78
  */
76
- FundedButUnsettled: "funded_but_unsettled"
79
+ FundedButUnsettled: "funded_but_unsettled",
80
+ /**
81
+ * #3420: TERMINAL — a `submitted` erc7710 x402 intent whose settlement
82
+ * window AND the sweep's last attribution chance have both passed with no
83
+ * verified evidence. The sweep's tick (120s) only ever confirms a
84
+ * transaction mined inside the payment's own settlement window (the child
85
+ * delegation's on-chain `timestamp` caveat, plus the verifier's 120s
86
+ * clock-skew allowance), so once authorize + window + skew is behind the
87
+ * payment, no poll — and no sweep tick — can ever change the answer.
88
+ * The paired `next_action` is `stop_and_tell_user`: tell the user the goods
89
+ * were delivered but Haven holds no verified settlement evidence; reporting
90
+ * a real settlement hash (`haven_report_settlement_evidence`) still works
91
+ * at any age.
92
+ */
93
+ DeliveredUnverified: "delivered_unverified"
77
94
  };
78
95
  var AgentPaymentNextAction = {
79
96
  /** Sign with the delegate key and submit the payment to Haven. */
@@ -221,7 +238,8 @@ var AgentPaymentPhaseDescriptions = {
221
238
  [AgentPaymentPhase.Expired]: "The payment expired before completion.",
222
239
  [AgentPaymentPhase.Failed]: "Haven could not complete the payment; the agent should stop and surface the failure.",
223
240
  [AgentPaymentPhase.InsufficientFunds]: "Pre-flight check determined the delegate balance plus the remaining on-chain budget cannot cover the requested amount, so no payment was created. The account must be funded or the agent budget raised before retrying.",
224
- [AgentPaymentPhase.FundedButUnsettled]: "Haven's funding leg confirmed on-chain but the merchant rejected the x402 retry. The delegate wallet may hold stranded funds. The agent should stop and wait for the wallet owner to sweep the stranded funds back to the account."
241
+ [AgentPaymentPhase.FundedButUnsettled]: "Haven's funding leg confirmed on-chain but the merchant rejected the x402 retry. The delegate wallet may hold stranded funds. The agent should stop and wait for the wallet owner to sweep the stranded funds back to the account.",
242
+ [AgentPaymentPhase.DeliveredUnverified]: "Terminal: the merchant delivered the goods and the settlement window plus the sweep's last attribution chance have both passed with no verified on-chain evidence. The payment can no longer resolve by polling. Tell the user the goods were delivered but Haven holds no verified settlement evidence for this payment."
225
243
  };
226
244
  var AgentPaymentNextActionDescriptions = {
227
245
  [AgentPaymentNextAction.SignAndSubmitPayment]: "Sign with the delegate key and submit the payment to Haven.",
@@ -356,6 +374,24 @@ var MerchantTimeoutError = class extends HavenApiError {
356
374
  this.name = "MerchantTimeoutError";
357
375
  }
358
376
  };
377
+ var X402Erc7710AlreadySettledError = class extends HavenError {
378
+ constructor(paymentId, txHash, body) {
379
+ super(
380
+ `Payment ${paymentId} already settled on-chain (tx ${txHash}). Nothing was signed and nothing new was charged.`,
381
+ "PAYMENT_ALREADY_SETTLED",
382
+ void 0,
383
+ paymentId
384
+ );
385
+ this.paymentId = paymentId;
386
+ this.txHash = txHash;
387
+ this.body = body;
388
+ this.name = "X402Erc7710AlreadySettledError";
389
+ }
390
+ paymentId;
391
+ txHash;
392
+ body;
393
+ x402ErrorCode = "payment_already_settled";
394
+ };
359
395
  var X402UnexpectedStatusError = class extends HavenApiError {
360
396
  x402ErrorCode = "unexpected_non_402_status";
361
397
  /**
@@ -402,6 +438,19 @@ var HavenPaymentStateError = class extends HavenApiError {
402
438
  return this.state.nextAction;
403
439
  }
404
440
  };
441
+ var X402TaskBudgetMismatchError = class extends HavenError {
442
+ constructor(message, idempotencyKey, entryTaskBudgetId, requestedTaskBudgetId) {
443
+ super(message, "X402_TASK_BUDGET_MISMATCH");
444
+ this.idempotencyKey = idempotencyKey;
445
+ this.entryTaskBudgetId = entryTaskBudgetId;
446
+ this.requestedTaskBudgetId = requestedTaskBudgetId;
447
+ this.name = "X402TaskBudgetMismatchError";
448
+ }
449
+ idempotencyKey;
450
+ entryTaskBudgetId;
451
+ requestedTaskBudgetId;
452
+ x402ErrorCode = "task_budget_mismatch";
453
+ };
405
454
  var HavenSigningError = class extends HavenError {
406
455
  constructor(message) {
407
456
  super(message, "SIGNING_ERROR");
@@ -426,7 +475,7 @@ var SignerRefusalCode = {
426
475
  UnsupportedSweepBindingVersion: "UNSUPPORTED_SWEEP_BINDING_VERSION"
427
476
  };
428
477
  function signerUpdateFallback(channel = HAVEN_CONNECTOR_CHANNEL) {
429
- return `Update @haven_ai/signer by rerunning \`${connectorRerunCommand(void 0, { channel })}\`, which reinstalls the pinned MCP runtime, then retry the same signing call. Nothing was signed or spent \u2014 the quote or payment this version came from is unaffected and does not need to be re-quoted.`;
478
+ return `Update @haven_ai/signer: run \`${connectorUpgradeCommand({ channel })}\` and then the repair line it prints, which reinstalls the pinned MCP runtime, then retry the same signing call. Nothing was signed or spent \u2014 the quote or payment this version came from is unaffected and does not need to be re-quoted.`;
430
479
  }
431
480
  var SIGNER_UPDATE_FALLBACK = signerUpdateFallback();
432
481
  var HavenUnsupportedSignerVersionError = class extends HavenError {
@@ -453,6 +502,7 @@ var HavenTimeoutError = class extends HavenError {
453
502
  }
454
503
  };
455
504
  var DIRECT_SIGN_CONTEXT_VERSION = 1;
505
+ var TASK_SIGN_CONTEXT_VERSION = 1;
456
506
  var EIP712_DOMAIN_FIELDS = [
457
507
  { name: "name", type: "string" },
458
508
  { name: "version", type: "string" },
@@ -595,7 +645,15 @@ var CAVEAT_ENFORCERS = {
595
645
  var MAX_SETTLEMENT_WINDOW_SECONDS = 600;
596
646
  function isSettlementChildTypedData(value) {
597
647
  const td = value;
598
- return !!td && td.primaryType === "Delegation" && typeof td.domain?.verifyingContract === "string" && Array.isArray(td.message?.caveats);
648
+ if (!td || td.primaryType !== "Delegation" || typeof td.domain?.verifyingContract !== "string" || !Array.isArray(td.message?.caveats)) {
649
+ return false;
650
+ }
651
+ const delegate = td.message?.delegate;
652
+ const delegator = td.message?.delegator;
653
+ if (typeof delegate === "string" && typeof delegator === "string" && delegate.toLowerCase() === delegator.toLowerCase()) {
654
+ return false;
655
+ }
656
+ return true;
599
657
  }
600
658
  function same(a, b) {
601
659
  return !!a && !!b && a.toLowerCase() === b.toLowerCase();
@@ -659,6 +717,13 @@ function verifySettlementChild(typedData, expected, now = Date.now()) {
659
717
  `Expected delegator ${expected.delegatorAccount}; the child names ${String(delegator)}.`
660
718
  );
661
719
  }
720
+ const delegate = typedData.message?.delegate;
721
+ if (typeof delegate === "string" && same(delegate, delegator)) {
722
+ refuse2(
723
+ "its delegate is the same account as its delegator (a self-delegation)",
724
+ "A settlement child is always redeemed by a facilitator or left open to any redeemer \u2014 never redeemable only by the account that granted it. This is the shape of a task-budget child, a different typed-data class Haven never signs through this path."
725
+ );
726
+ }
662
727
  }
663
728
  const caveats = typedData.message?.caveats ?? [];
664
729
  if (caveats.length === 0) {
@@ -835,7 +900,7 @@ var REDEEM_DELEGATIONS_ABI = [
835
900
  var SINGLE_DEFAULT_MODE = `0x${"00".repeat(32)}`;
836
901
  function refuse3(detail) {
837
902
  throw new HavenSigningError(
838
- `Refusing to sign: this UserOperation's redeemDelegations call ${detail}. This signer only signs a redemption of a single delegation granted to the agent's own account.`
903
+ `Refusing to sign: this UserOperation's redeemDelegations call ${detail}. This signer only signs one of three shapes: a single grant to the agent's own account, a self-delegated task-budget child redeemed under it (the two-link [task child, budget] chain), or a sub-budget grant redeemed under its parent's self-narrowing (the three-link [sub grant, parent child, budget] chain, #3330).`
839
904
  );
840
905
  }
841
906
  function assertRedeemsOwnBudgetDelegation(redeemCalldata, ownAccount) {
@@ -879,8 +944,10 @@ function assertRedeemsOwnBudgetDelegation(redeemCalldata, ownAccount) {
879
944
  "carries an EMPTY delegation chain \u2014 DelegationManager treats this as self-authorised and runs the paired execution as the account, with no caveat, budget or recipient pin"
880
945
  );
881
946
  }
882
- if (delegations.length !== 1) {
883
- refuse3(`carries a ${delegations.length}-link delegation chain, not the single budget grant Haven emits`);
947
+ if (delegations.length !== 1 && delegations.length !== 2 && delegations.length !== 3) {
948
+ refuse3(
949
+ `carries a ${delegations.length}-link delegation chain, not the single budget grant, the two-link [task child, budget] chain, or the three-link [sub grant, parent child, budget] chain Haven emits`
950
+ );
884
951
  }
885
952
  const reEncodedContext = viem.encodeAbiParameters(DELEGATION_ARRAY_PARAM, [delegations]);
886
953
  if (reEncodedContext.toLowerCase() !== permissionContexts[0].toLowerCase()) {
@@ -892,6 +959,56 @@ function assertRedeemsOwnBudgetDelegation(redeemCalldata, ownAccount) {
892
959
  `is redeemed for delegate ${leaf.delegate}, not this signer's own account (${ownAccount})`
893
960
  );
894
961
  }
962
+ if (delegations.length === 2) {
963
+ if (leaf.delegator.toLowerCase() !== ownAccount.toLowerCase()) {
964
+ refuse3(
965
+ `carries a two-link chain whose leaf is delegated by ${leaf.delegator}, not this signer's own account (${ownAccount}) \u2014 a task-budget child is always self-delegated`
966
+ );
967
+ }
968
+ const budget = delegations[1];
969
+ if (budget.delegate.toLowerCase() !== ownAccount.toLowerCase()) {
970
+ refuse3(
971
+ `carries a two-link chain whose second link delegates to ${budget.delegate}, not this signer's own account (${ownAccount})`
972
+ );
973
+ }
974
+ if (budget.delegator.toLowerCase() === ownAccount.toLowerCase()) {
975
+ refuse3(
976
+ "carries a two-link chain whose budget link is granted by this signer's OWN account \u2014 a real budget delegation always comes from elsewhere"
977
+ );
978
+ }
979
+ return;
980
+ }
981
+ if (delegations.length === 3) {
982
+ if (leaf.delegator.toLowerCase() === ownAccount.toLowerCase()) {
983
+ refuse3(
984
+ "carries a three-link chain whose leaf is delegated by this signer's OWN account \u2014 a sub-budget grant always comes from the delegating agent, never from the sub-agent itself"
985
+ );
986
+ }
987
+ const parentChild = delegations[1];
988
+ const parentAccount = leaf.delegator;
989
+ if (parentChild.delegate.toLowerCase() !== parentAccount.toLowerCase()) {
990
+ refuse3(
991
+ `carries a three-link chain whose middle link delegates to ${parentChild.delegate}, not the delegating agent's account the leaf names as its delegator (${parentAccount})`
992
+ );
993
+ }
994
+ if (parentChild.delegator.toLowerCase() !== parentAccount.toLowerCase()) {
995
+ refuse3(
996
+ `carries a three-link chain whose middle link is delegated by ${parentChild.delegator}, not the delegating agent's own account (${parentAccount}) \u2014 the parent link is a self-delegated narrowing`
997
+ );
998
+ }
999
+ const budget = delegations[2];
1000
+ if (budget.delegate.toLowerCase() !== parentAccount.toLowerCase()) {
1001
+ refuse3(
1002
+ `carries a three-link chain whose budget link delegates to ${budget.delegate}, not the delegating agent's account (${parentAccount})`
1003
+ );
1004
+ }
1005
+ if (budget.delegator.toLowerCase() === parentAccount.toLowerCase()) {
1006
+ refuse3(
1007
+ "carries a three-link chain whose budget link is granted by the delegating agent's OWN account \u2014 a real budget delegation always comes from elsewhere"
1008
+ );
1009
+ }
1010
+ return;
1011
+ }
895
1012
  const root = delegations[delegations.length - 1];
896
1013
  if (root.delegator.toLowerCase() === ownAccount.toLowerCase()) {
897
1014
  refuse3(
@@ -945,13 +1062,17 @@ exports.SIGNER_UPDATE_FALLBACK = SIGNER_UPDATE_FALLBACK;
945
1062
  exports.SIMPLE_FACTORY_ADDRESS = SIMPLE_FACTORY_ADDRESS;
946
1063
  exports.SINGLE_DEFAULT_MODE = SINGLE_DEFAULT_MODE;
947
1064
  exports.SignerRefusalCode = SignerRefusalCode;
1065
+ exports.TASK_SIGN_CONTEXT_VERSION = TASK_SIGN_CONTEXT_VERSION;
948
1066
  exports.X402AlreadySettledError = X402AlreadySettledError;
1067
+ exports.X402Erc7710AlreadySettledError = X402Erc7710AlreadySettledError;
1068
+ exports.X402TaskBudgetMismatchError = X402TaskBudgetMismatchError;
949
1069
  exports.X402UnexpectedStatusError = X402UnexpectedStatusError;
950
1070
  exports.assertRedeemsOwnBudgetDelegation = assertRedeemsOwnBudgetDelegation;
951
1071
  exports.assertUserOpTypedDataBinding = assertUserOpTypedDataBinding;
952
1072
  exports.chainIdForNetwork = chainIdForNetwork;
953
1073
  exports.connectorRerunCommand = connectorRerunCommand;
954
1074
  exports.connectorSpec = connectorSpec;
1075
+ exports.connectorUpgradeCommand = connectorUpgradeCommand;
955
1076
  exports.deriveDelegateAccountAddress = deriveDelegateAccountAddress;
956
1077
  exports.isConnectorChannel = isConnectorChannel;
957
1078
  exports.isPackedUserOperationTypedData = isPackedUserOperationTypedData;
@@ -960,5 +1081,5 @@ exports.packedUserOperationHash = packedUserOperationHash;
960
1081
  exports.resolveConnectorChannel = resolveConnectorChannel;
961
1082
  exports.signerUpdateFallback = signerUpdateFallback;
962
1083
  exports.verifySettlementChild = verifySettlementChild;
963
- //# sourceMappingURL=chunk-JKUIE45B.cjs.map
964
- //# sourceMappingURL=chunk-JKUIE45B.cjs.map
1084
+ //# sourceMappingURL=chunk-3SVPI4LS.cjs.map
1085
+ //# sourceMappingURL=chunk-3SVPI4LS.cjs.map