@haven_ai/sdk 0.7.0-alpha.0 → 0.8.1-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/dist/edge.d.cts CHANGED
@@ -1,8 +1,177 @@
1
- import { cg as DelegationForHashing } from './base64-_seD1uw8.cjs';
2
- export { U as AgentPaymentFailureCode, Y as AgentPaymentNextAction, ch as CAVEAT_ENFORCERS, ci as CAVEAT_TYPEHASH, cj as DELEGATION_MANAGER, ck as DELEGATION_TYPEHASH, cl as DIRECT_PAYMENT_CHAIN_IDS, ac as DIRECT_SIGN_CONTEXT_VERSION, ad as ENTRY_POINT_V07, cm as EXECUTE_ABI, af as HAVEN_CLIENT_HEADER, ag as HAVEN_CONNECTOR_CHANNEL, ah as HAVEN_MINIMUM_NODE_VERSION, cn as HYBRID_DELEGATOR_IMPLEMENTATION, an as HavenApiError, a as HavenClientUpdate, I as HavenError, ar as HavenSigningError, at as HavenTypedDataRefusedError, au as HavenUnsupportedSignerVersionError, av as HavenUserOpBindingError, co as MAX_SETTLEMENT_WINDOW_SECONDS, ax as MAX_TASK_BUDGET_TTL_SECONDS, aC as NextStep, aE as NextStepHandoff, aG as NextStepTarget, aO as ROOT_AUTHORITY, aR as SIGNER_UPDATE_FALLBACK, cp as SIMPLE_FACTORY_ADDRESS, aW as SettlementChildExpectation, cq as SettlementChildTypedData, aX as SignerRefusalCode, j as SweepAuthorization, a$ as SweepExpectedAuth, b3 as TASK_SIGN_CONTEXT_VERSION, b5 as TYPED_DATA_NOT_ALLOWED, b6 as TaskBudgetCloseExpectation, b7 as TaskChildExpectation, b8 as TaskChildTypedData, bc as X402ExpectedAuth, bg as X402PaymentOption, X as X402PaymentRequired, bs as assertBoundDirectPaymentUserOp, cr as assertFundingLegPaysDelegate, cs as assertOwnSettlementChild, bt as assertOwnTaskBudgetCloseUserOp, bu as assertOwnTaskChild, bv as assertUserOpTypedDataBinding, bw as buildSweepAuthorizationMessage, bx as buildSweepTypedData, by as buildX402ExpectedMessage, ct as chainIdForNetwork, bA as connectorRerunCommand, bC as connectorUpgradeCommand, bD as createNextStepBuilder, bE as decodeBase64Json, bH as deriveDelegateAccountAddress, bI as encodeBase64Json, bL as hashDelegation, bM as havenClientIdentity, bP as isPackedUserOperationTypedData, cu as isSettlementChildTypedData, bQ as isSupportedNodeVersion, bS as isTaskChildTypedData, bU as packedUserOperationHash, bY as readClientUpdate, c3 as selectStandardPaymentOption, c8 as toStandardPaymentRequirements, c9 as unsupportedNodeVersionMessage, cb as verifySettlementChild, cd as x402AuthorizationAmount, cf as x402V2PaymentEnvelope } from './base64-_seD1uw8.cjs';
1
+ import { av as HavenSigningError, ck as DelegationForHashing } from './base64-BjxHPgtC.cjs';
2
+ export { Z as AgentPaymentFailureCode, a0 as AgentPaymentNextAction, cl as CAVEAT_ENFORCERS, cm as CAVEAT_TYPEHASH, cn as DELEGATION_MANAGER, co as DELEGATION_TYPEHASH, cp as DIRECT_PAYMENT_CHAIN_IDS, ag as DIRECT_SIGN_CONTEXT_VERSION, ah as ENTRY_POINT_V07, cq as EXECUTE_ABI, aj as HAVEN_CLIENT_HEADER, ak as HAVEN_CONNECTOR_CHANNEL, al as HAVEN_MINIMUM_NODE_VERSION, cr as HYBRID_DELEGATOR_IMPLEMENTATION, ar as HavenApiError, a as HavenClientUpdate, M as HavenError, ax as HavenTypedDataRefusedError, ay as HavenUnsupportedSignerVersionError, az as HavenUserOpBindingError, cs as MAX_SETTLEMENT_WINDOW_SECONDS, aB as MAX_TASK_BUDGET_TTL_SECONDS, aG as NextStep, aI as NextStepHandoff, aK as NextStepTarget, aS as ROOT_AUTHORITY, aV as SIGNER_UPDATE_FALLBACK, ct as SIMPLE_FACTORY_ADDRESS, a_ as SettlementChildExpectation, cu as SettlementChildTypedData, a$ as SignerRefusalCode, j as SweepAuthorization, b3 as SweepExpectedAuth, b7 as TASK_SIGN_CONTEXT_VERSION, b9 as TYPED_DATA_NOT_ALLOWED, ba as TaskBudgetCloseExpectation, bb as TaskChildExpectation, bc as TaskChildTypedData, bg as X402ExpectedAuth, bk as X402PaymentOption, X as X402PaymentRequired, bw as assertBoundDirectPaymentUserOp, cv as assertFundingLegPaysDelegate, cw as assertOwnSettlementChild, bx as assertOwnTaskBudgetCloseUserOp, by as assertOwnTaskChild, bz as assertUserOpTypedDataBinding, bA as buildSweepAuthorizationMessage, bB as buildSweepTypedData, bC as buildX402ExpectedMessage, cx as chainIdForNetwork, bE as connectorRerunCommand, bG as connectorUpgradeCommand, bH as createNextStepBuilder, bI as decodeBase64Json, bL as deriveDelegateAccountAddress, bM as encodeBase64Json, bP as hashDelegation, bQ as havenClientIdentity, bT as isPackedUserOperationTypedData, cy as isSettlementChildTypedData, bU as isSupportedNodeVersion, bW as isTaskChildTypedData, bY as packedUserOperationHash, c0 as readClientUpdate, c7 as selectStandardPaymentOption, cc as toStandardPaymentRequirements, cd as unsupportedNodeVersionMessage, cf as verifySettlementChild, ch as x402AuthorizationAmount, cj as x402V2PaymentEnvelope } from './base64-BjxHPgtC.cjs';
3
3
  import { Hex, Address } from 'viem';
4
4
  import 'x402/types';
5
5
 
6
+ /**
7
+ * The x402 buyer-side tax declaration (#3427, wg-tax #5 §2.2
8
+ * `buyer-side-tax-declaration.md`).
9
+ *
10
+ * The agent's own payment key — the same delegate EOA that signs the
11
+ * EIP-3009 payment authorization — signs the §2.1 declaration content, and
12
+ * the signed declaration travels to the SELLER ONLY, as
13
+ * `X-Tax-Declaration: <base64url(JSON)>` on the paid merchant retry
14
+ * (`MerchantCompletion.retryRequest`). It never reaches Haven or any
15
+ * facilitator, and it is never part of the payment payload.
16
+ *
17
+ * Why this lives on the edge (`docs/architecture/07-edge-signer.md`, #3283's
18
+ * shared-guard rule): the declaration MUST be signed by the key that signs
19
+ * the payment authorization (§2.2), and on the EIP-3009 bridge that key is
20
+ * held by this local SDK process. The builder therefore lives in
21
+ * `@haven_ai/sdk/edge` beside the other signing guards, and every property
22
+ * the threat model requires is enforced HERE, not by callers:
23
+ *
24
+ * - The EIP-712 typed data is built LOCALLY from the §2.1 fields. Typed data
25
+ * is never accepted from Haven — the wire content is validated to exactly
26
+ * the five §2.1 fields, and anything else (including a `principalId` or
27
+ * `principalAttributionHash` arriving pre-set) is REFUSED, never stripped
28
+ * and continued. A polluted declaration aborts the payment loudly rather
29
+ * than being silently laundered into a signature.
30
+ * - `principalId = did:pkh:<CAIP-2 network>:<delegate EOA>` — the chain
31
+ * comes from the ACCEPTED payment option's `network` (§6.6.5 Equality),
32
+ * never from configuration. An alias (`base`) is resolved through the same
33
+ * `chainIdForNetwork` map the settlement child uses; a network with no
34
+ * chain id refuses, so an unknown chain cannot mint a mis-scoped
35
+ * principal.
36
+ * - `principalAttributionHash = "sha-256:<hex>"` over the JCS-canonical bytes
37
+ * of `{ principalId }` (§6.6.2, §6.6.5 Effect).
38
+ *
39
+ * Residual accepted by the owner (issue threat model, 2026-09-28): Haven
40
+ * supplies `jurisdiction`, `taxableStatus` and `taxId`, so a compromised
41
+ * Haven could produce a declaration with a wrong VAT number. Nothing moves
42
+ * funds, the seller checks the VAT number in VIES, and the values are the
43
+ * owner's own onboarding data. The SDK logs the `taxId` it signs (stderr, so
44
+ * an MCP stdio session's JSON-RPC framing on stdout is untouched).
45
+ */
46
+ /**
47
+ * PROVISIONAL EIP-712 domain (wg-tax PR #5 §2.2: the domain and types
48
+ * "remain to be defined"). No chainId and no salt: the declaration is
49
+ * portable across the settlement networks a seller may accept, and the
50
+ * principal is already chain-scoped by `principalId`. Recorded in the PR
51
+ * body for the working group; changing these constants changes every
52
+ * signature produced, so they are pinned by the fixed-vector tests.
53
+ */
54
+ declare const TAX_DECLARATION_DOMAIN: {
55
+ readonly name: "x402 Tax Declaration";
56
+ readonly version: "1";
57
+ };
58
+ /** The declaration's EIP-712 primary type name. */
59
+ declare const TAX_DECLARATION_PRIMARY_TYPE = "TaxDeclaration";
60
+ /**
61
+ * PROVISIONAL typed-data types for the signed §2.1 declaration plus the two
62
+ * locally computed principal fields. Field order here is the ABI encoding
63
+ * order of every signature produced by this module.
64
+ */
65
+ declare const TAX_DECLARATION_TYPES: {
66
+ readonly TaxDeclaration: readonly [{
67
+ readonly name: "version";
68
+ readonly type: "string";
69
+ }, {
70
+ readonly name: "jurisdiction";
71
+ readonly type: "string";
72
+ }, {
73
+ readonly name: "taxableStatus";
74
+ readonly type: "string";
75
+ }, {
76
+ readonly name: "taxId";
77
+ readonly type: "string";
78
+ }, {
79
+ readonly name: "validUntil";
80
+ readonly type: "uint256";
81
+ }, {
82
+ readonly name: "principalId";
83
+ readonly type: "string";
84
+ }, {
85
+ readonly name: "principalAttributionHash";
86
+ readonly type: "string";
87
+ }];
88
+ };
89
+ /** The x402 header this module's output is serialised into. */
90
+ declare const X_TAX_DECLARATION_HEADER = "X-Tax-Declaration";
91
+ /**
92
+ * The §2.1 unsigned content exactly as `#3426`'s content endpoint emits it
93
+ * (`GET /agents/:id/tax-declaration`, `{ available: true, declaration }`).
94
+ */
95
+ interface TaxDeclarationContent {
96
+ /** §2.1 version discriminator, e.g. `x402-tax-1`. */
97
+ version: string;
98
+ /** ISO 3166-1 alpha-2 country code. */
99
+ jurisdiction: string;
100
+ /** §2.1's closed enumeration, e.g. `TAXABLE_PERSON`. */
101
+ taxableStatus: string;
102
+ /** The owner's VAT number, normalised by the backend. */
103
+ taxId: string;
104
+ /** Integer milliseconds — the declaration's validity bound. */
105
+ validUntil: number;
106
+ }
107
+ /** The signed declaration object carried (base64url-encoded) in the header. */
108
+ interface SignedTaxDeclaration extends TaxDeclarationContent {
109
+ /** `did:pkh:<CAIP-2 network>:<delegate EOA>` — computed locally. */
110
+ principalId: string;
111
+ /** `sha-256:<hex>` over the JCS bytes of `{ principalId }`. */
112
+ principalAttributionHash: string;
113
+ }
114
+ interface SignedTaxDeclarationResult {
115
+ declaration: SignedTaxDeclaration;
116
+ /** EIP-712 signature (65-byte `r‖s‖v`, 27/28) over the typed declaration. */
117
+ signature: string;
118
+ }
119
+ /** `sha-256:<hex>` over the UTF-8 JCS bytes of `{ principalId }` (§6.6.2). */
120
+ declare function principalAttributionHash(principalId: string): string;
121
+ /**
122
+ * `did:pkh:<CAIP-2 network>:<address>` from the accepted option's `network`.
123
+ *
124
+ * The chain comes from the settlement's network — a `eip155:<n>` value passes
125
+ * through verbatim, the x402 aliases (`base`, `base-sepolia`) resolve through
126
+ * the same `chainIdForNetwork` map the settlement child uses, and anything
127
+ * else refuses: a network this SDK cannot name cannot produce a principal
128
+ * that names its own chain.
129
+ */
130
+ declare function taxPrincipalId(network: string, delegateAddress: string): string;
131
+ /**
132
+ * Build the EIP-712 typed data for the §2.1 content LOCALLY, set the two
133
+ * principal fields, and sign with the delegate key.
134
+ *
135
+ * The caller passes the raw content from `#3426`'s endpoint (parsed JSON) —
136
+ * `validateContent` refuses anything beyond the five §2.1 fields before any
137
+ * principal is computed or any byte is signed. The signature recovers to the
138
+ * delegate EOA (pinned by the sign+recover test), which is the §2.2
139
+ * requirement: the declaration signer is the payment authorizer.
140
+ */
141
+ declare function buildSignedTaxDeclaration(input: {
142
+ /** The UNSIGNED §2.1 content from #3426's endpoint — `declaration` field of the response. */
143
+ content: unknown;
144
+ /** The ACCEPTED payment option's network — the only chain source (§6.6.5). */
145
+ network: string;
146
+ /** The agent's delegate key — the same key that signs the EIP-3009 authorization. */
147
+ delegateKey: string;
148
+ }): SignedTaxDeclarationResult;
149
+ /**
150
+ * Recompute the EIP-712 digest for a signed declaration and check the
151
+ * signature recovers to `expectedAddress` — the seller-side verification
152
+ * this SDK runs on itself in tests, kept next to the builder so the digest
153
+ * rule cannot drift from the signing one.
154
+ */
155
+ declare function verifyTaxDeclarationSignature(declaration: SignedTaxDeclaration, signature: string, expectedAddress: string): boolean;
156
+ /**
157
+ * The base64url(JSON) header value for the paid merchant retry. The JSON is
158
+ * the signed declaration object with the `signature` field alongside — one
159
+ * object, so the seller decodes, re-derives the digest from the known
160
+ * provisional domain/types, and recovers the signer.
161
+ */
162
+ declare function encodeTaxDeclarationHeader(result: SignedTaxDeclarationResult): string;
163
+ /**
164
+ * A refused declaration: the content was not exactly the locally built shape
165
+ * (a pre-set principal field, an unknown field, a malformed value) or the
166
+ * settlement network could not be named. Extends `HavenSigningError` so the
167
+ * existing signing-error handling catches it; the `code` lets callers tell
168
+ * the refusal apart from a key problem.
169
+ */
170
+ declare class TaxDeclarationRefusedError extends HavenSigningError {
171
+ readonly code = "TAX_DECLARATION_REFUSED";
172
+ constructor(message: string);
173
+ }
174
+
6
175
  declare function addressFromKey(privateKey: string): string;
7
176
  declare function signHash(privateKey: string, hash: string): string;
8
177
  declare function verifySignature(hash: string, signature: string, expectedAddress: string): boolean;
@@ -219,4 +388,4 @@ declare function assertOwnSubBudgetCloseUserOp(typedData: Record<string, unknown
219
388
  delegationHash: string;
220
389
  }, delegateAddress: string): void;
221
390
 
222
- export { DELEGATION_TUPLE_COMPONENTS, DelegationForHashing, ERC20_PERIOD_TRANSFER_ENFORCER, REDEEM_DELEGATIONS_ABI, SINGLE_DEFAULT_MODE, type SubBudgetChildExpectation, type SubBudgetChildTypedData, addressFromKey, assertOwnSubBudgetChild, assertOwnSubBudgetCloseUserOp, assertRedeemsOwnBudgetDelegation, hashSubBudgetDelegation, signHash, verifySignature };
391
+ export { DELEGATION_TUPLE_COMPONENTS, DelegationForHashing, ERC20_PERIOD_TRANSFER_ENFORCER, HavenSigningError, REDEEM_DELEGATIONS_ABI, SINGLE_DEFAULT_MODE, type SignedTaxDeclaration, type SignedTaxDeclarationResult, type SubBudgetChildExpectation, type SubBudgetChildTypedData, TAX_DECLARATION_DOMAIN, TAX_DECLARATION_PRIMARY_TYPE, TAX_DECLARATION_TYPES, type TaxDeclarationContent, TaxDeclarationRefusedError, X_TAX_DECLARATION_HEADER, addressFromKey, assertOwnSubBudgetChild, assertOwnSubBudgetCloseUserOp, assertRedeemsOwnBudgetDelegation, buildSignedTaxDeclaration, encodeTaxDeclarationHeader, hashSubBudgetDelegation, principalAttributionHash, signHash, taxPrincipalId, verifySignature, verifyTaxDeclarationSignature };
package/dist/edge.d.ts CHANGED
@@ -1,8 +1,177 @@
1
- import { cg as DelegationForHashing } from './base64-_seD1uw8.js';
2
- export { U as AgentPaymentFailureCode, Y as AgentPaymentNextAction, ch as CAVEAT_ENFORCERS, ci as CAVEAT_TYPEHASH, cj as DELEGATION_MANAGER, ck as DELEGATION_TYPEHASH, cl as DIRECT_PAYMENT_CHAIN_IDS, ac as DIRECT_SIGN_CONTEXT_VERSION, ad as ENTRY_POINT_V07, cm as EXECUTE_ABI, af as HAVEN_CLIENT_HEADER, ag as HAVEN_CONNECTOR_CHANNEL, ah as HAVEN_MINIMUM_NODE_VERSION, cn as HYBRID_DELEGATOR_IMPLEMENTATION, an as HavenApiError, a as HavenClientUpdate, I as HavenError, ar as HavenSigningError, at as HavenTypedDataRefusedError, au as HavenUnsupportedSignerVersionError, av as HavenUserOpBindingError, co as MAX_SETTLEMENT_WINDOW_SECONDS, ax as MAX_TASK_BUDGET_TTL_SECONDS, aC as NextStep, aE as NextStepHandoff, aG as NextStepTarget, aO as ROOT_AUTHORITY, aR as SIGNER_UPDATE_FALLBACK, cp as SIMPLE_FACTORY_ADDRESS, aW as SettlementChildExpectation, cq as SettlementChildTypedData, aX as SignerRefusalCode, j as SweepAuthorization, a$ as SweepExpectedAuth, b3 as TASK_SIGN_CONTEXT_VERSION, b5 as TYPED_DATA_NOT_ALLOWED, b6 as TaskBudgetCloseExpectation, b7 as TaskChildExpectation, b8 as TaskChildTypedData, bc as X402ExpectedAuth, bg as X402PaymentOption, X as X402PaymentRequired, bs as assertBoundDirectPaymentUserOp, cr as assertFundingLegPaysDelegate, cs as assertOwnSettlementChild, bt as assertOwnTaskBudgetCloseUserOp, bu as assertOwnTaskChild, bv as assertUserOpTypedDataBinding, bw as buildSweepAuthorizationMessage, bx as buildSweepTypedData, by as buildX402ExpectedMessage, ct as chainIdForNetwork, bA as connectorRerunCommand, bC as connectorUpgradeCommand, bD as createNextStepBuilder, bE as decodeBase64Json, bH as deriveDelegateAccountAddress, bI as encodeBase64Json, bL as hashDelegation, bM as havenClientIdentity, bP as isPackedUserOperationTypedData, cu as isSettlementChildTypedData, bQ as isSupportedNodeVersion, bS as isTaskChildTypedData, bU as packedUserOperationHash, bY as readClientUpdate, c3 as selectStandardPaymentOption, c8 as toStandardPaymentRequirements, c9 as unsupportedNodeVersionMessage, cb as verifySettlementChild, cd as x402AuthorizationAmount, cf as x402V2PaymentEnvelope } from './base64-_seD1uw8.js';
1
+ import { av as HavenSigningError, ck as DelegationForHashing } from './base64-BjxHPgtC.js';
2
+ export { Z as AgentPaymentFailureCode, a0 as AgentPaymentNextAction, cl as CAVEAT_ENFORCERS, cm as CAVEAT_TYPEHASH, cn as DELEGATION_MANAGER, co as DELEGATION_TYPEHASH, cp as DIRECT_PAYMENT_CHAIN_IDS, ag as DIRECT_SIGN_CONTEXT_VERSION, ah as ENTRY_POINT_V07, cq as EXECUTE_ABI, aj as HAVEN_CLIENT_HEADER, ak as HAVEN_CONNECTOR_CHANNEL, al as HAVEN_MINIMUM_NODE_VERSION, cr as HYBRID_DELEGATOR_IMPLEMENTATION, ar as HavenApiError, a as HavenClientUpdate, M as HavenError, ax as HavenTypedDataRefusedError, ay as HavenUnsupportedSignerVersionError, az as HavenUserOpBindingError, cs as MAX_SETTLEMENT_WINDOW_SECONDS, aB as MAX_TASK_BUDGET_TTL_SECONDS, aG as NextStep, aI as NextStepHandoff, aK as NextStepTarget, aS as ROOT_AUTHORITY, aV as SIGNER_UPDATE_FALLBACK, ct as SIMPLE_FACTORY_ADDRESS, a_ as SettlementChildExpectation, cu as SettlementChildTypedData, a$ as SignerRefusalCode, j as SweepAuthorization, b3 as SweepExpectedAuth, b7 as TASK_SIGN_CONTEXT_VERSION, b9 as TYPED_DATA_NOT_ALLOWED, ba as TaskBudgetCloseExpectation, bb as TaskChildExpectation, bc as TaskChildTypedData, bg as X402ExpectedAuth, bk as X402PaymentOption, X as X402PaymentRequired, bw as assertBoundDirectPaymentUserOp, cv as assertFundingLegPaysDelegate, cw as assertOwnSettlementChild, bx as assertOwnTaskBudgetCloseUserOp, by as assertOwnTaskChild, bz as assertUserOpTypedDataBinding, bA as buildSweepAuthorizationMessage, bB as buildSweepTypedData, bC as buildX402ExpectedMessage, cx as chainIdForNetwork, bE as connectorRerunCommand, bG as connectorUpgradeCommand, bH as createNextStepBuilder, bI as decodeBase64Json, bL as deriveDelegateAccountAddress, bM as encodeBase64Json, bP as hashDelegation, bQ as havenClientIdentity, bT as isPackedUserOperationTypedData, cy as isSettlementChildTypedData, bU as isSupportedNodeVersion, bW as isTaskChildTypedData, bY as packedUserOperationHash, c0 as readClientUpdate, c7 as selectStandardPaymentOption, cc as toStandardPaymentRequirements, cd as unsupportedNodeVersionMessage, cf as verifySettlementChild, ch as x402AuthorizationAmount, cj as x402V2PaymentEnvelope } from './base64-BjxHPgtC.js';
3
3
  import { Hex, Address } from 'viem';
4
4
  import 'x402/types';
5
5
 
6
+ /**
7
+ * The x402 buyer-side tax declaration (#3427, wg-tax #5 §2.2
8
+ * `buyer-side-tax-declaration.md`).
9
+ *
10
+ * The agent's own payment key — the same delegate EOA that signs the
11
+ * EIP-3009 payment authorization — signs the §2.1 declaration content, and
12
+ * the signed declaration travels to the SELLER ONLY, as
13
+ * `X-Tax-Declaration: <base64url(JSON)>` on the paid merchant retry
14
+ * (`MerchantCompletion.retryRequest`). It never reaches Haven or any
15
+ * facilitator, and it is never part of the payment payload.
16
+ *
17
+ * Why this lives on the edge (`docs/architecture/07-edge-signer.md`, #3283's
18
+ * shared-guard rule): the declaration MUST be signed by the key that signs
19
+ * the payment authorization (§2.2), and on the EIP-3009 bridge that key is
20
+ * held by this local SDK process. The builder therefore lives in
21
+ * `@haven_ai/sdk/edge` beside the other signing guards, and every property
22
+ * the threat model requires is enforced HERE, not by callers:
23
+ *
24
+ * - The EIP-712 typed data is built LOCALLY from the §2.1 fields. Typed data
25
+ * is never accepted from Haven — the wire content is validated to exactly
26
+ * the five §2.1 fields, and anything else (including a `principalId` or
27
+ * `principalAttributionHash` arriving pre-set) is REFUSED, never stripped
28
+ * and continued. A polluted declaration aborts the payment loudly rather
29
+ * than being silently laundered into a signature.
30
+ * - `principalId = did:pkh:<CAIP-2 network>:<delegate EOA>` — the chain
31
+ * comes from the ACCEPTED payment option's `network` (§6.6.5 Equality),
32
+ * never from configuration. An alias (`base`) is resolved through the same
33
+ * `chainIdForNetwork` map the settlement child uses; a network with no
34
+ * chain id refuses, so an unknown chain cannot mint a mis-scoped
35
+ * principal.
36
+ * - `principalAttributionHash = "sha-256:<hex>"` over the JCS-canonical bytes
37
+ * of `{ principalId }` (§6.6.2, §6.6.5 Effect).
38
+ *
39
+ * Residual accepted by the owner (issue threat model, 2026-09-28): Haven
40
+ * supplies `jurisdiction`, `taxableStatus` and `taxId`, so a compromised
41
+ * Haven could produce a declaration with a wrong VAT number. Nothing moves
42
+ * funds, the seller checks the VAT number in VIES, and the values are the
43
+ * owner's own onboarding data. The SDK logs the `taxId` it signs (stderr, so
44
+ * an MCP stdio session's JSON-RPC framing on stdout is untouched).
45
+ */
46
+ /**
47
+ * PROVISIONAL EIP-712 domain (wg-tax PR #5 §2.2: the domain and types
48
+ * "remain to be defined"). No chainId and no salt: the declaration is
49
+ * portable across the settlement networks a seller may accept, and the
50
+ * principal is already chain-scoped by `principalId`. Recorded in the PR
51
+ * body for the working group; changing these constants changes every
52
+ * signature produced, so they are pinned by the fixed-vector tests.
53
+ */
54
+ declare const TAX_DECLARATION_DOMAIN: {
55
+ readonly name: "x402 Tax Declaration";
56
+ readonly version: "1";
57
+ };
58
+ /** The declaration's EIP-712 primary type name. */
59
+ declare const TAX_DECLARATION_PRIMARY_TYPE = "TaxDeclaration";
60
+ /**
61
+ * PROVISIONAL typed-data types for the signed §2.1 declaration plus the two
62
+ * locally computed principal fields. Field order here is the ABI encoding
63
+ * order of every signature produced by this module.
64
+ */
65
+ declare const TAX_DECLARATION_TYPES: {
66
+ readonly TaxDeclaration: readonly [{
67
+ readonly name: "version";
68
+ readonly type: "string";
69
+ }, {
70
+ readonly name: "jurisdiction";
71
+ readonly type: "string";
72
+ }, {
73
+ readonly name: "taxableStatus";
74
+ readonly type: "string";
75
+ }, {
76
+ readonly name: "taxId";
77
+ readonly type: "string";
78
+ }, {
79
+ readonly name: "validUntil";
80
+ readonly type: "uint256";
81
+ }, {
82
+ readonly name: "principalId";
83
+ readonly type: "string";
84
+ }, {
85
+ readonly name: "principalAttributionHash";
86
+ readonly type: "string";
87
+ }];
88
+ };
89
+ /** The x402 header this module's output is serialised into. */
90
+ declare const X_TAX_DECLARATION_HEADER = "X-Tax-Declaration";
91
+ /**
92
+ * The §2.1 unsigned content exactly as `#3426`'s content endpoint emits it
93
+ * (`GET /agents/:id/tax-declaration`, `{ available: true, declaration }`).
94
+ */
95
+ interface TaxDeclarationContent {
96
+ /** §2.1 version discriminator, e.g. `x402-tax-1`. */
97
+ version: string;
98
+ /** ISO 3166-1 alpha-2 country code. */
99
+ jurisdiction: string;
100
+ /** §2.1's closed enumeration, e.g. `TAXABLE_PERSON`. */
101
+ taxableStatus: string;
102
+ /** The owner's VAT number, normalised by the backend. */
103
+ taxId: string;
104
+ /** Integer milliseconds — the declaration's validity bound. */
105
+ validUntil: number;
106
+ }
107
+ /** The signed declaration object carried (base64url-encoded) in the header. */
108
+ interface SignedTaxDeclaration extends TaxDeclarationContent {
109
+ /** `did:pkh:<CAIP-2 network>:<delegate EOA>` — computed locally. */
110
+ principalId: string;
111
+ /** `sha-256:<hex>` over the JCS bytes of `{ principalId }`. */
112
+ principalAttributionHash: string;
113
+ }
114
+ interface SignedTaxDeclarationResult {
115
+ declaration: SignedTaxDeclaration;
116
+ /** EIP-712 signature (65-byte `r‖s‖v`, 27/28) over the typed declaration. */
117
+ signature: string;
118
+ }
119
+ /** `sha-256:<hex>` over the UTF-8 JCS bytes of `{ principalId }` (§6.6.2). */
120
+ declare function principalAttributionHash(principalId: string): string;
121
+ /**
122
+ * `did:pkh:<CAIP-2 network>:<address>` from the accepted option's `network`.
123
+ *
124
+ * The chain comes from the settlement's network — a `eip155:<n>` value passes
125
+ * through verbatim, the x402 aliases (`base`, `base-sepolia`) resolve through
126
+ * the same `chainIdForNetwork` map the settlement child uses, and anything
127
+ * else refuses: a network this SDK cannot name cannot produce a principal
128
+ * that names its own chain.
129
+ */
130
+ declare function taxPrincipalId(network: string, delegateAddress: string): string;
131
+ /**
132
+ * Build the EIP-712 typed data for the §2.1 content LOCALLY, set the two
133
+ * principal fields, and sign with the delegate key.
134
+ *
135
+ * The caller passes the raw content from `#3426`'s endpoint (parsed JSON) —
136
+ * `validateContent` refuses anything beyond the five §2.1 fields before any
137
+ * principal is computed or any byte is signed. The signature recovers to the
138
+ * delegate EOA (pinned by the sign+recover test), which is the §2.2
139
+ * requirement: the declaration signer is the payment authorizer.
140
+ */
141
+ declare function buildSignedTaxDeclaration(input: {
142
+ /** The UNSIGNED §2.1 content from #3426's endpoint — `declaration` field of the response. */
143
+ content: unknown;
144
+ /** The ACCEPTED payment option's network — the only chain source (§6.6.5). */
145
+ network: string;
146
+ /** The agent's delegate key — the same key that signs the EIP-3009 authorization. */
147
+ delegateKey: string;
148
+ }): SignedTaxDeclarationResult;
149
+ /**
150
+ * Recompute the EIP-712 digest for a signed declaration and check the
151
+ * signature recovers to `expectedAddress` — the seller-side verification
152
+ * this SDK runs on itself in tests, kept next to the builder so the digest
153
+ * rule cannot drift from the signing one.
154
+ */
155
+ declare function verifyTaxDeclarationSignature(declaration: SignedTaxDeclaration, signature: string, expectedAddress: string): boolean;
156
+ /**
157
+ * The base64url(JSON) header value for the paid merchant retry. The JSON is
158
+ * the signed declaration object with the `signature` field alongside — one
159
+ * object, so the seller decodes, re-derives the digest from the known
160
+ * provisional domain/types, and recovers the signer.
161
+ */
162
+ declare function encodeTaxDeclarationHeader(result: SignedTaxDeclarationResult): string;
163
+ /**
164
+ * A refused declaration: the content was not exactly the locally built shape
165
+ * (a pre-set principal field, an unknown field, a malformed value) or the
166
+ * settlement network could not be named. Extends `HavenSigningError` so the
167
+ * existing signing-error handling catches it; the `code` lets callers tell
168
+ * the refusal apart from a key problem.
169
+ */
170
+ declare class TaxDeclarationRefusedError extends HavenSigningError {
171
+ readonly code = "TAX_DECLARATION_REFUSED";
172
+ constructor(message: string);
173
+ }
174
+
6
175
  declare function addressFromKey(privateKey: string): string;
7
176
  declare function signHash(privateKey: string, hash: string): string;
8
177
  declare function verifySignature(hash: string, signature: string, expectedAddress: string): boolean;
@@ -219,4 +388,4 @@ declare function assertOwnSubBudgetCloseUserOp(typedData: Record<string, unknown
219
388
  delegationHash: string;
220
389
  }, delegateAddress: string): void;
221
390
 
222
- export { DELEGATION_TUPLE_COMPONENTS, DelegationForHashing, ERC20_PERIOD_TRANSFER_ENFORCER, REDEEM_DELEGATIONS_ABI, SINGLE_DEFAULT_MODE, type SubBudgetChildExpectation, type SubBudgetChildTypedData, addressFromKey, assertOwnSubBudgetChild, assertOwnSubBudgetCloseUserOp, assertRedeemsOwnBudgetDelegation, hashSubBudgetDelegation, signHash, verifySignature };
391
+ export { DELEGATION_TUPLE_COMPONENTS, DelegationForHashing, ERC20_PERIOD_TRANSFER_ENFORCER, HavenSigningError, REDEEM_DELEGATIONS_ABI, SINGLE_DEFAULT_MODE, type SignedTaxDeclaration, type SignedTaxDeclarationResult, type SubBudgetChildExpectation, type SubBudgetChildTypedData, TAX_DECLARATION_DOMAIN, TAX_DECLARATION_PRIMARY_TYPE, TAX_DECLARATION_TYPES, type TaxDeclarationContent, TaxDeclarationRefusedError, X_TAX_DECLARATION_HEADER, addressFromKey, assertOwnSubBudgetChild, assertOwnSubBudgetCloseUserOp, assertRedeemsOwnBudgetDelegation, buildSignedTaxDeclaration, encodeTaxDeclarationHeader, hashSubBudgetDelegation, principalAttributionHash, signHash, taxPrincipalId, verifySignature, verifyTaxDeclarationSignature };
package/dist/edge.js CHANGED
@@ -1,56 +1,7 @@
1
- import { hashDelegation, DIRECT_PAYMENT_CHAIN_IDS, assertOwnTaskBudgetCloseUserOp, HavenTypedDataRefusedError } from './chunk-R3RZJJWL.js';
2
- export { CAVEAT_TYPEHASH, DELEGATION_TYPEHASH, DIRECT_PAYMENT_CHAIN_IDS, EXECUTE_ABI, HAVEN_CLIENT_HEADER, HAVEN_MINIMUM_NODE_VERSION, HavenTypedDataRefusedError, MAX_TASK_BUDGET_TTL_SECONDS, TYPED_DATA_NOT_ALLOWED, assertBoundDirectPaymentUserOp, assertFundingLegPaysDelegate, assertOwnSettlementChild, assertOwnTaskBudgetCloseUserOp, assertOwnTaskChild, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, createNextStepBuilder, decodeBase64Json, encodeBase64Json, hashDelegation, havenClientIdentity, isSupportedNodeVersion, isTaskChildTypedData, readClientUpdate, selectStandardPaymentOption, toStandardPaymentRequirements, unsupportedNodeVersionMessage, x402AuthorizationAmount, x402V2PaymentEnvelope } from './chunk-R3RZJJWL.js';
3
- import { HavenSigningError, DELEGATION_MANAGER, deriveDelegateAccountAddress, ROOT_AUTHORITY, CAVEAT_ENFORCERS } from './chunk-NNIT7WAI.js';
4
- export { AgentPaymentFailureCode, AgentPaymentNextAction, CAVEAT_ENFORCERS, DELEGATION_MANAGER, DELEGATION_TUPLE_COMPONENTS, DIRECT_SIGN_CONTEXT_VERSION, ENTRY_POINT_V07, HAVEN_CONNECTOR_CHANNEL, HYBRID_DELEGATOR_IMPLEMENTATION, HavenApiError, HavenError, HavenSigningError, HavenUnsupportedSignerVersionError, HavenUserOpBindingError, MAX_SETTLEMENT_WINDOW_SECONDS, REDEEM_DELEGATIONS_ABI, ROOT_AUTHORITY, SIGNER_UPDATE_FALLBACK, SIMPLE_FACTORY_ADDRESS, SINGLE_DEFAULT_MODE, SignerRefusalCode, TASK_SIGN_CONTEXT_VERSION, assertRedeemsOwnBudgetDelegation, assertUserOpTypedDataBinding, chainIdForNetwork, connectorRerunCommand, connectorUpgradeCommand, deriveDelegateAccountAddress, isPackedUserOperationTypedData, isSettlementChildTypedData, packedUserOperationHash, verifySettlementChild } from './chunk-NNIT7WAI.js';
5
- import { secp256k1 } from '@noble/curves/secp256k1';
6
- import { privateKeyToAddress, publicKeyToAddress } from 'viem/accounts';
7
- import { serializeSignature } from 'viem';
8
-
9
- var HALF_N = BigInt("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0");
10
- function hexBytes(value, bytes, what) {
11
- if (!/^0x[0-9a-fA-F]+$/.test(value) || value.length !== 2 + bytes * 2) {
12
- throw new Error(`${what} must be a 0x-prefixed ${bytes}-byte hex string`);
13
- }
14
- return value.slice(2);
15
- }
16
- function addressFromKey(privateKey) {
17
- try {
18
- return privateKeyToAddress(`0x${hexBytes(privateKey, 32, "private key")}`);
19
- } catch (err) {
20
- throw new HavenSigningError(
21
- `Invalid private key: ${err instanceof Error ? err.message : String(err)}`
22
- );
23
- }
24
- }
25
- function signHash(privateKey, hash) {
26
- try {
27
- const { r, s, recovery } = secp256k1.sign(hexBytes(hash, 32, "hash"), hexBytes(privateKey, 32, "private key"), { lowS: true });
28
- return serializeSignature({
29
- r: `0x${r.toString(16).padStart(64, "0")}`,
30
- s: `0x${s.toString(16).padStart(64, "0")}`,
31
- yParity: recovery
32
- });
33
- } catch (err) {
34
- throw new HavenSigningError(
35
- `Failed to sign hash: ${err instanceof Error ? err.message : String(err)}`
36
- );
37
- }
38
- }
39
- function verifySignature(hash, signature, expectedAddress) {
40
- try {
41
- const sig = hexBytes(signature, 65, "signature");
42
- const hashHex = hexBytes(hash, 32, "hash");
43
- if (BigInt(`0x${sig.slice(64, 128)}`) > HALF_N) return false;
44
- const yParityOrV = Number.parseInt(sig.slice(128), 16);
45
- const recoveryBit = yParityOrV === 0 || yParityOrV === 27 ? 0 : yParityOrV === 1 || yParityOrV === 28 ? 1 : -1;
46
- if (recoveryBit < 0) return false;
47
- const publicKey = secp256k1.Signature.fromCompact(sig.slice(0, 128)).addRecoveryBit(recoveryBit).recoverPublicKey(hashHex).toHex(false);
48
- const recovered = publicKeyToAddress(`0x${publicKey}`);
49
- return recovered.toLowerCase() === expectedAddress.toLowerCase();
50
- } catch {
51
- return false;
52
- }
53
- }
1
+ import { hashDelegation, DIRECT_PAYMENT_CHAIN_IDS, assertOwnTaskBudgetCloseUserOp, HavenTypedDataRefusedError } from './chunk-WDA3IGJP.js';
2
+ export { CAVEAT_TYPEHASH, DELEGATION_TYPEHASH, DIRECT_PAYMENT_CHAIN_IDS, EXECUTE_ABI, HAVEN_CLIENT_HEADER, HAVEN_MINIMUM_NODE_VERSION, HavenTypedDataRefusedError, MAX_TASK_BUDGET_TTL_SECONDS, TAX_DECLARATION_DOMAIN, TAX_DECLARATION_PRIMARY_TYPE, TAX_DECLARATION_TYPES, TYPED_DATA_NOT_ALLOWED, TaxDeclarationRefusedError, X_TAX_DECLARATION_HEADER, addressFromKey, assertBoundDirectPaymentUserOp, assertFundingLegPaysDelegate, assertOwnSettlementChild, assertOwnTaskBudgetCloseUserOp, assertOwnTaskChild, buildSignedTaxDeclaration, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, createNextStepBuilder, decodeBase64Json, encodeBase64Json, encodeTaxDeclarationHeader, hashDelegation, havenClientIdentity, isSupportedNodeVersion, isTaskChildTypedData, principalAttributionHash, readClientUpdate, selectStandardPaymentOption, signHash, taxPrincipalId, toStandardPaymentRequirements, unsupportedNodeVersionMessage, verifySignature, verifyTaxDeclarationSignature, x402AuthorizationAmount, x402V2PaymentEnvelope } from './chunk-WDA3IGJP.js';
3
+ import { DELEGATION_MANAGER, deriveDelegateAccountAddress, ROOT_AUTHORITY, CAVEAT_ENFORCERS } from './chunk-H4APV67M.js';
4
+ export { AgentPaymentFailureCode, AgentPaymentNextAction, CAVEAT_ENFORCERS, DELEGATION_MANAGER, DELEGATION_TUPLE_COMPONENTS, DIRECT_SIGN_CONTEXT_VERSION, ENTRY_POINT_V07, HAVEN_CONNECTOR_CHANNEL, HYBRID_DELEGATOR_IMPLEMENTATION, HavenApiError, HavenError, HavenSigningError, HavenUnsupportedSignerVersionError, HavenUserOpBindingError, MAX_SETTLEMENT_WINDOW_SECONDS, REDEEM_DELEGATIONS_ABI, ROOT_AUTHORITY, SIGNER_UPDATE_FALLBACK, SIMPLE_FACTORY_ADDRESS, SINGLE_DEFAULT_MODE, SignerRefusalCode, TASK_SIGN_CONTEXT_VERSION, assertRedeemsOwnBudgetDelegation, assertUserOpTypedDataBinding, chainIdForNetwork, connectorRerunCommand, connectorUpgradeCommand, deriveDelegateAccountAddress, isPackedUserOperationTypedData, isSettlementChildTypedData, packedUserOperationHash, verifySettlementChild } from './chunk-H4APV67M.js';
54
5
 
55
6
  // src/sub-budget-guards.ts
56
7
  var ERC20_PERIOD_TRANSFER_ENFORCER = "0x474e3Ae7E169e940607cC624Da8A15Eb120139aB";
@@ -251,6 +202,6 @@ function assertOwnSubBudgetCloseUserOp(typedData, expected, delegateAddress) {
251
202
  assertOwnTaskBudgetCloseUserOp(typedData, expected, delegateAddress);
252
203
  }
253
204
 
254
- export { ERC20_PERIOD_TRANSFER_ENFORCER, addressFromKey, assertOwnSubBudgetChild, assertOwnSubBudgetCloseUserOp, hashSubBudgetDelegation, signHash, verifySignature };
205
+ export { ERC20_PERIOD_TRANSFER_ENFORCER, assertOwnSubBudgetChild, assertOwnSubBudgetCloseUserOp, hashSubBudgetDelegation };
255
206
  //# sourceMappingURL=edge.js.map
256
207
  //# sourceMappingURL=edge.js.map
package/dist/edge.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/edge-signing.ts","../src/sub-budget-guards.ts"],"names":[],"mappings":"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","file":"edge.js","sourcesContent":["import { secp256k1 } from '@noble/curves/secp256k1'\nimport { privateKeyToAddress, publicKeyToAddress } from 'viem/accounts'\nimport { serializeSignature, type Hex } from 'viem'\nimport { HavenSigningError } from './types.js'\n\n/**\n * #3173: the three key helpers the edge signer needs, without ethers.\n *\n * `./signer.ts` implements the same three on ethers, and the SDK barrel pulls\n * ethers in for them (and for `provider.ts` / `receipt.ts`). The edge signer\n * already ships viem, and viem signs with `@noble/curves` underneath — these\n * use the same curve library directly, synchronously (viem's own `sign` is\n * async), so `@haven_ai/sdk/edge` stays ethers-free and a signer session stops\n * paying for module init it never uses. Byte-equivalence with the ethers forms\n * is pinned in `edge-signing.test.ts`: same address, same 65-byte `r‖s‖v`\n * serialisation with low-s and v = 27/28, same recovery verdicts, and the same\n * refusals (high-s twin, wrong lengths) — with three stated strict-direction\n * exceptions, see `hexBytes`. Raw ECDSA over the hash — never the EIP-191\n * prefixed digest.\n */\n\n/** secp256k1 order / 2 — a signature with s above this is the malleable twin ethers rejects. */\nconst HALF_N = BigInt('0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0')\n\n/**\n * Stricter than ethers, never looser: the lowercase `0x` prefix and the exact\n * byte length are required. Ethers accepts an uppercase `0X` prefix on a\n * signature and the 64-byte EIP-2098 compact form, and is inconsistent on a\n * private key (`Wallet` accepts unprefixed and refuses `0X`; `SigningKey` does\n * the reverse); every such form is refused here — the divergences are pinned\n * in `edge-signing.test.ts` with ethers control assertions, and every\n * well-formed input is byte-equivalent.\n */\nfunction hexBytes(value: string, bytes: number, what: string): string {\n if (!/^0x[0-9a-fA-F]+$/.test(value) || value.length !== 2 + bytes * 2) {\n throw new Error(`${what} must be a 0x-prefixed ${bytes}-byte hex string`)\n }\n return value.slice(2)\n}\n\nexport function addressFromKey(privateKey: string): string {\n try {\n // Same gate as signHash: a key that derives an address must also sign.\n return privateKeyToAddress(`0x${hexBytes(privateKey, 32, 'private key')}`)\n } catch (err) {\n throw new HavenSigningError(\n `Invalid private key: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\nexport function signHash(privateKey: string, hash: string): string {\n try {\n const { r, s, recovery } = secp256k1.sign(hexBytes(hash, 32, 'hash'), hexBytes(privateKey, 32, 'private key'), { lowS: true })\n // viem serialises the trailing byte from yParity (0/1 → 27/28), the same\n // `v` ethers' `Signature.serialized` writes.\n return serializeSignature({\n r: `0x${r.toString(16).padStart(64, '0')}`,\n s: `0x${s.toString(16).padStart(64, '0')}`,\n yParity: recovery,\n })\n } catch (err) {\n throw new HavenSigningError(\n `Failed to sign hash: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\nexport function verifySignature(hash: string, signature: string, expectedAddress: string): boolean {\n try {\n const sig = hexBytes(signature, 65, 'signature')\n const hashHex = hexBytes(hash, 32, 'hash')\n // Reject the high-s malleable twin, as ethers does — one signature per message.\n if (BigInt(`0x${sig.slice(64, 128)}`) > HALF_N) return false\n const yParityOrV = Number.parseInt(sig.slice(128), 16)\n const recoveryBit = yParityOrV === 0 || yParityOrV === 27 ? 0 : yParityOrV === 1 || yParityOrV === 28 ? 1 : -1\n if (recoveryBit < 0) return false\n const publicKey = secp256k1.Signature.fromCompact(sig.slice(0, 128))\n .addRecoveryBit(recoveryBit)\n .recoverPublicKey(hashHex)\n .toHex(false)\n const recovered = publicKeyToAddress(`0x${publicKey}`)\n return recovered.toLowerCase() === expectedAddress.toLowerCase()\n } catch {\n return false\n }\n}\n","/**\n * Sub-budget child guards (#3330) — the SDK-side local verification the\n * signer runs before its delegate key signs a sub-budget child, mirroring\n * `task-budget-guards.ts`'s `assertOwnTaskChild` for the two-row sub-budget\n * tree. ONE verifier covers BOTH rows, because the same signer (the\n * delegating agent A's own key) signs both:\n *\n * - A's PARENT-CHILD row: `delegate === delegator === A's own account`\n * (self-delegated, the task-child shape class).\n * - B's GRANT row: `delegator === A's own account`, `delegate === B's\n * delegate account` (a real grant to another account).\n *\n * What makes a sub-budget child a sub-budget child (vs a task budget's\n * hard-cap child) is the AMOUNT caveat: an `ERC20PeriodTransferEnforcer`\n * caveat whose terms are `abi.encode(address token, uint256 periodAmount,\n * uint256 periodDuration, uint256 startDate)` — the period-scoped slice of\n * the parent's own period meter, with the parent's periodDuration and\n * startDate reused verbatim. A hard-cap `ERC20TransferAmountEnforcer` caveat\n * is refused: that would be a task budget, which this channel must never\n * sign (two different products, two different sign-context endpoints).\n *\n * Authority, timestamp and recipient-pin checks are byte-for-byte the\n * task-child discipline: authority must equal the declared parent hash and\n * never be ROOT; expiry must be in the future and equal the declared one; a\n * pinned recipient must match exactly, and an unpinned budget must not grow\n * one. Enforcers are the pinned constants from `settlement-child.ts` (no kit\n * dependency) — same reasoning as that file's header documents.\n */\n\nimport { type Address, type Hex } from 'viem'\nimport { HavenTypedDataRefusedError, DIRECT_PAYMENT_CHAIN_IDS } from './direct-payment-guard.js'\nimport { DELEGATION_MANAGER, ROOT_AUTHORITY, CAVEAT_ENFORCERS } from './settlement-child.js'\nimport { deriveDelegateAccountAddress } from './delegate-account.js'\nimport {\n DELEGATION_TYPEHASH,\n CAVEAT_TYPEHASH,\n hashDelegation,\n type DelegationForHashing,\n} from './task-budget-guards.js'\n\n/** The pinned `ERC20PeriodTransferEnforcer` (bytecode-identical on Base + Base Sepolia). */\nexport const ERC20_PERIOD_TRANSFER_ENFORCER = '0x474e3Ae7E169e940607cC624Da8A15Eb120139aB'\n\n/** The pinned `Delegation` EIP-712 domain (cross-checked by task-budget-guards' pin test). */\nconst DELEGATION_DOMAIN_NAME = 'DelegationManager'\nconst DELEGATION_DOMAIN_VERSION = '1'\n\n/** The pinned `types` shape, byte-identical to `task-budget-guards.ts`'s. */\nconst EXPECTED_DELEGATION_TYPES = {\n Caveat: [\n { name: 'enforcer', type: 'address' },\n { name: 'terms', type: 'bytes' },\n ],\n Delegation: [\n { name: 'delegate', type: 'address' },\n { name: 'delegator', type: 'address' },\n { name: 'authority', type: 'bytes32' },\n { name: 'caveats', type: 'Caveat[]' },\n { name: 'salt', type: 'uint256' },\n ],\n} as const\n\nexport interface SubBudgetChildTypedData {\n domain: { name?: string; version?: string; chainId?: number | string; verifyingContract?: string }\n types: Record<string, unknown>\n primaryType: string\n message: Record<string, unknown>\n}\n\nfunction same(a: string | undefined, b: string | undefined): boolean {\n return !!a && !!b && a.toLowerCase() === b.toLowerCase()\n}\n\n/** Byte slice [start, end) of a `0x…` string, as lowercase hex without prefix. */\nfunction sliceTerms(terms: string, start: number, end?: number): string {\n const body = terms.startsWith('0x') ? terms.slice(2).toLowerCase() : terms.toLowerCase()\n return end === undefined ? body.slice(start * 2) : body.slice(start * 2, end * 2)\n}\n\nfunction findCaveat(caveats: Array<{ enforcer: string; terms: string }>, enforcer: string) {\n return caveats.find((c) => same(c.enforcer, enforcer))\n}\n\n/** The struct hash of a sub-budget child — the redemption chain's link value. */\nexport function hashSubBudgetDelegation(delegation: DelegationForHashing): Hex {\n return hashDelegation(delegation)\n}\n\n// The kit's own struct hashes, re-exported verbatim from task-budget-guards'\n// pinned literals so a caller can name them from this module too.\nexport { DELEGATION_TYPEHASH, CAVEAT_TYPEHASH }\n\nexport interface SubBudgetChildExpectation {\n chainId: number\n tokenAddress: string\n /** Per-period amount in atomic units — the child's periodAmount. */\n periodAmountAtomic: string\n /** The PARENT's period duration (seconds), reused verbatim in the caveat. */\n periodDurationSeconds: number\n /** The PARENT's period anchor, reused verbatim in the caveat. */\n startDate: number\n recipientAddress: string | null\n /** unix seconds — the `TimestampEnforcer`'s `beforeThreshold`. */\n expiresAt: number\n /** The hash of the row's parent delegation (`parent_delegation_hash`). */\n parentDelegationHash: string\n /**\n * A's own derived delegate account — the child's `delegator` on BOTH rows.\n */\n delegateAccount: string\n /**\n * The row's own `delegate`: A's account again for the parent-child row,\n * B's delegate account for the grant row. Served in the sign-context's\n * `expected` (read from the stored child JSON, not trusted caller input).\n */\n childDelegateAccount: string\n}\n\nfunction refuseSubBudgetChild(what: string, detail: string): never {\n throw new HavenTypedDataRefusedError(\n `Refusing to sign the sub-budget child: ${what}. ${detail} ` +\n 'This signature opens a slice of the delegating agent budget for another agent, so it is ' +\n 'verified locally against the expectation Haven declared, rather than trusted.',\n )\n}\n\n/**\n * Verify a sub-budget child delegation is EXACTLY what\n * `GET /sub-budgets/:id/sign-context` (purpose `open`) declared, that its\n * `delegator` is this signer's own account, and that its `delegate` is the\n * declared child delegate. Throws `HavenTypedDataRefusedError` (never\n * returns) on any disagreement.\n */\nexport function assertOwnSubBudgetChild(\n typedData: unknown,\n expected: SubBudgetChildExpectation,\n delegateAddress: string,\n now: number = Date.now(),\n): void {\n const td = typedData as SubBudgetChildTypedData\n if (td?.primaryType !== 'Delegation') {\n refuseSubBudgetChild('it is not a Delegation payload', `primaryType was '${String(td?.primaryType)}'.`)\n }\n if (!same(td.domain?.verifyingContract, DELEGATION_MANAGER)) {\n refuseSubBudgetChild(\n 'the EIP-712 domain names an unknown DelegationManager',\n `Expected ${DELEGATION_MANAGER}, got ${td.domain?.verifyingContract}.`,\n )\n }\n if (td.domain?.name !== DELEGATION_DOMAIN_NAME || td.domain?.version !== DELEGATION_DOMAIN_VERSION) {\n refuseSubBudgetChild(\n 'the EIP-712 domain name/version does not match the pinned DelegationManager domain',\n `Expected name '${DELEGATION_DOMAIN_NAME}' version '${DELEGATION_DOMAIN_VERSION}'; got name ` +\n `'${String(td.domain?.name)}' version '${String(td.domain?.version)}'.`,\n )\n }\n if (\n JSON.stringify(td.types?.Caveat) !== JSON.stringify(EXPECTED_DELEGATION_TYPES.Caveat) ||\n JSON.stringify(td.types?.Delegation) !== JSON.stringify(EXPECTED_DELEGATION_TYPES.Delegation)\n ) {\n refuseSubBudgetChild(\n 'its EIP-712 type definitions do not match the pinned Delegation/Caveat shape',\n 'A renamed, reordered, or additional field on Delegation or Caveat could change what the ' +\n 'caveats below mean without changing this check\\'s field-by-field comparisons.',\n )\n }\n const domainChain = Number(td.domain?.chainId)\n if (!Number.isFinite(domainChain) || !DIRECT_PAYMENT_CHAIN_IDS.has(domainChain)) {\n refuseSubBudgetChild(\n 'it is scoped to a chain the delegation rail has no pinned contracts for',\n `Chains with pinned contracts: ${[...DIRECT_PAYMENT_CHAIN_IDS].join(', ')}; the child says ${String(td.domain?.chainId)}.`,\n )\n }\n if (domainChain !== expected.chainId) {\n refuseSubBudgetChild(\n 'it is scoped to the wrong chain',\n `Expected chain ${expected.chainId}; the child says ${td.domain?.chainId}.`,\n )\n }\n\n const ownAccount = deriveDelegateAccountAddress(delegateAddress as Address)\n const delegator = td.message?.delegator\n if (typeof delegator !== 'string' || !same(delegator, ownAccount)) {\n refuseSubBudgetChild(\n \"it is not delegated by this agent's own account\",\n `Expected delegator ${ownAccount}; the child names ${String(delegator)}.`,\n )\n }\n if (!same(delegator, expected.delegateAccount)) {\n refuseSubBudgetChild(\n 'its delegator does not match the account Haven declared',\n `Expected ${expected.delegateAccount}; the child names ${String(delegator)}.`,\n )\n }\n const delegate = td.message?.delegate\n if (typeof delegate !== 'string' || !same(delegate, expected.childDelegateAccount)) {\n refuseSubBudgetChild(\n 'its delegate does not match the declared child delegate',\n `Expected ${expected.childDelegateAccount}; the child names ${String(delegate)}.`,\n )\n }\n\n const authority = td.message?.authority\n if (typeof authority !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(authority)) {\n refuseSubBudgetChild('its authority is not a 32-byte delegation hash', `Got ${String(authority)}.`)\n }\n if (authority.toLowerCase() === ROOT_AUTHORITY) {\n refuseSubBudgetChild(\n 'it is a ROOT delegation, not a re-delegation of the delegating agent budget',\n 'A sub-budget always chains under the delegating agent budget delegation.',\n )\n }\n if (!same(authority, expected.parentDelegationHash)) {\n refuseSubBudgetChild(\n 'it chains under a different parent delegation',\n `Expected authority ${expected.parentDelegationHash}; the child says ${authority}.`,\n )\n }\n\n const caveats = (td.message?.caveats as Array<{ enforcer: string; terms: string }> | undefined) ?? []\n\n // The PERIOD caveat is what makes this a sub-budget — a hard-cap\n // `ERC20TransferAmountEnforcer` caveat is the task-budget shape and is\n // refused on this channel.\n if (findCaveat(caveats, CAVEAT_ENFORCERS.erc20TransferAmount)) {\n refuseSubBudgetChild(\n 'it carries a hard-cap transfer-amount caveat (the task-budget shape)',\n 'A sub-budget is period-scoped: its amount caveat must be an ERC20PeriodTransferEnforcer ' +\n 'caveat slicing the parent period meter, never a lifetime cap.',\n )\n }\n const period = findCaveat(caveats, ERC20_PERIOD_TRANSFER_ENFORCER)\n if (!period) {\n refuseSubBudgetChild(\n 'it has no ERC-20 period-transfer caveat',\n 'Without it the child is not bounded to a per-period amount.',\n )\n }\n // terms = abi.encodePacked(address token, uint256 periodAmount,\n // uint256 periodDuration, uint256 startDate) — the kit's TIGHT packing\n // (20 + 32×3 = 116 bytes, verified against `createDelegation`'s own\n // output), the same layout `task-budget-guards.ts` decodes for the\n // ERC20TransferAmountEnforcer. NOT head/tail-padded words: the address\n // occupies bytes [0,20) and the amount starts at byte 20.\n const token = `0x${sliceTerms(period.terms, 0, 20)}`\n if (!same(token, expected.tokenAddress)) {\n refuseSubBudgetChild('it spends a different token', `Expected ${expected.tokenAddress}, child pins ${token}.`)\n }\n const periodAmount = BigInt(`0x${sliceTerms(period.terms, 20, 52)}`)\n if (periodAmount !== BigInt(expected.periodAmountAtomic)) {\n refuseSubBudgetChild(\n 'the period amount does not match',\n `Expected ${expected.periodAmountAtomic}; the child allows ${periodAmount.toString()}.`,\n )\n }\n const periodDuration = Number(BigInt(`0x${sliceTerms(period.terms, 52, 84)}`))\n if (periodDuration !== expected.periodDurationSeconds) {\n refuseSubBudgetChild(\n 'its period duration does not match the parent window Haven declared',\n `Expected ${expected.periodDurationSeconds}s; the child says ${periodDuration}s. A sub-budget is a ` +\n 'slice of the parent period meter — same window, smaller amount — never a different clock.',\n )\n }\n const startDate = Number(BigInt(`0x${sliceTerms(period.terms, 84, 116)}`))\n if (startDate !== expected.startDate) {\n refuseSubBudgetChild(\n 'its period start does not match the parent anchor Haven declared',\n `Expected ${expected.startDate}; the child says ${startDate}.`,\n )\n }\n\n const timestamp = findCaveat(caveats, CAVEAT_ENFORCERS.timestamp)\n if (!timestamp) {\n refuseSubBudgetChild('it never expires', 'A sub-budget child without a timestamp caveat is open-ended.')\n }\n const beforeThreshold = Number(BigInt(`0x${sliceTerms(timestamp.terms, 16, 32)}`))\n const nowSec = Math.floor(now / 1000)\n if (beforeThreshold <= nowSec) {\n refuseSubBudgetChild('it has already expired', `Expiry ${beforeThreshold} is not in the future.`)\n }\n if (beforeThreshold !== expected.expiresAt) {\n refuseSubBudgetChild(\n 'its expiry does not match what Haven declared',\n `Expected ${expected.expiresAt}; the child says ${beforeThreshold}.`,\n )\n }\n\n const calldata = findCaveat(caveats, CAVEAT_ENFORCERS.allowedCalldata)\n if (expected.recipientAddress) {\n if (!calldata) {\n refuseSubBudgetChild(\n 'it has no recipient pin',\n 'The sub-budget was issued with a pinned recipient, so the child must carry one.',\n )\n }\n const startIndex = BigInt(`0x${sliceTerms(calldata.terms, 0, 32)}`)\n if (startIndex !== 4n) {\n refuseSubBudgetChild(\n 'the recipient pin points at the wrong calldata offset',\n `Expected offset 4, got ${startIndex.toString()}.`,\n )\n }\n const paddedRecipient = sliceTerms(calldata.terms, 32, 64)\n if (paddedRecipient.slice(0, 24) !== '0'.repeat(24)) {\n refuseSubBudgetChild('the pinned recipient is not a plain address', 'Its 32-byte word is not a padded address.')\n }\n const recipient = `0x${paddedRecipient.slice(24)}`\n if (!same(recipient, expected.recipientAddress)) {\n refuseSubBudgetChild(\n 'it pins a different recipient than Haven declared',\n `Expected ${expected.recipientAddress}; the child pins ${recipient}.`,\n )\n }\n } else if (calldata) {\n refuseSubBudgetChild(\n 'it pins a recipient the sub-budget was not issued with',\n 'This sub-budget is open (no recipient pin); the child must not add one.',\n )\n }\n}\n\n/** Close UserOp verification — byte-for-byte the task-budget discipline. */\nexport function assertOwnSubBudgetCloseUserOp(\n typedData: Record<string, unknown>,\n expected: { delegationHash: string },\n delegateAddress: string,\n): void {\n // The close UserOp shape is identical to the task budget's: a\n // disableDelegation(child) call from the agent's own delegate account.\n // Reuse the task-budget verifier — the only expectation that differs is\n // the delegation hash, which is an input here either way. Static import,\n // not lazy: these modules share no init-time cycle.\n assertOwnTaskBudgetCloseUserOp(typedData, expected, delegateAddress)\n}\n\n// The close-UserOp verifier is imported for the re-export above.\nimport { assertOwnTaskBudgetCloseUserOp } from './task-budget-guards.js'\n"]}
1
+ {"version":3,"sources":["../src/sub-budget-guards.ts"],"names":[],"mappings":"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","file":"edge.js","sourcesContent":["/**\n * Sub-budget child guards (#3330) — the SDK-side local verification the\n * signer runs before its delegate key signs a sub-budget child, mirroring\n * `task-budget-guards.ts`'s `assertOwnTaskChild` for the two-row sub-budget\n * tree. ONE verifier covers BOTH rows, because the same signer (the\n * delegating agent A's own key) signs both:\n *\n * - A's PARENT-CHILD row: `delegate === delegator === A's own account`\n * (self-delegated, the task-child shape class).\n * - B's GRANT row: `delegator === A's own account`, `delegate === B's\n * delegate account` (a real grant to another account).\n *\n * What makes a sub-budget child a sub-budget child (vs a task budget's\n * hard-cap child) is the AMOUNT caveat: an `ERC20PeriodTransferEnforcer`\n * caveat whose terms are `abi.encode(address token, uint256 periodAmount,\n * uint256 periodDuration, uint256 startDate)` — the period-scoped slice of\n * the parent's own period meter, with the parent's periodDuration and\n * startDate reused verbatim. A hard-cap `ERC20TransferAmountEnforcer` caveat\n * is refused: that would be a task budget, which this channel must never\n * sign (two different products, two different sign-context endpoints).\n *\n * Authority, timestamp and recipient-pin checks are byte-for-byte the\n * task-child discipline: authority must equal the declared parent hash and\n * never be ROOT; expiry must be in the future and equal the declared one; a\n * pinned recipient must match exactly, and an unpinned budget must not grow\n * one. Enforcers are the pinned constants from `settlement-child.ts` (no kit\n * dependency) — same reasoning as that file's header documents.\n */\n\nimport { type Address, type Hex } from 'viem'\nimport { HavenTypedDataRefusedError, DIRECT_PAYMENT_CHAIN_IDS } from './direct-payment-guard.js'\nimport { DELEGATION_MANAGER, ROOT_AUTHORITY, CAVEAT_ENFORCERS } from './settlement-child.js'\nimport { deriveDelegateAccountAddress } from './delegate-account.js'\nimport {\n DELEGATION_TYPEHASH,\n CAVEAT_TYPEHASH,\n hashDelegation,\n type DelegationForHashing,\n} from './task-budget-guards.js'\n\n/** The pinned `ERC20PeriodTransferEnforcer` (bytecode-identical on Base + Base Sepolia). */\nexport const ERC20_PERIOD_TRANSFER_ENFORCER = '0x474e3Ae7E169e940607cC624Da8A15Eb120139aB'\n\n/** The pinned `Delegation` EIP-712 domain (cross-checked by task-budget-guards' pin test). */\nconst DELEGATION_DOMAIN_NAME = 'DelegationManager'\nconst DELEGATION_DOMAIN_VERSION = '1'\n\n/** The pinned `types` shape, byte-identical to `task-budget-guards.ts`'s. */\nconst EXPECTED_DELEGATION_TYPES = {\n Caveat: [\n { name: 'enforcer', type: 'address' },\n { name: 'terms', type: 'bytes' },\n ],\n Delegation: [\n { name: 'delegate', type: 'address' },\n { name: 'delegator', type: 'address' },\n { name: 'authority', type: 'bytes32' },\n { name: 'caveats', type: 'Caveat[]' },\n { name: 'salt', type: 'uint256' },\n ],\n} as const\n\nexport interface SubBudgetChildTypedData {\n domain: { name?: string; version?: string; chainId?: number | string; verifyingContract?: string }\n types: Record<string, unknown>\n primaryType: string\n message: Record<string, unknown>\n}\n\nfunction same(a: string | undefined, b: string | undefined): boolean {\n return !!a && !!b && a.toLowerCase() === b.toLowerCase()\n}\n\n/** Byte slice [start, end) of a `0x…` string, as lowercase hex without prefix. */\nfunction sliceTerms(terms: string, start: number, end?: number): string {\n const body = terms.startsWith('0x') ? terms.slice(2).toLowerCase() : terms.toLowerCase()\n return end === undefined ? body.slice(start * 2) : body.slice(start * 2, end * 2)\n}\n\nfunction findCaveat(caveats: Array<{ enforcer: string; terms: string }>, enforcer: string) {\n return caveats.find((c) => same(c.enforcer, enforcer))\n}\n\n/** The struct hash of a sub-budget child — the redemption chain's link value. */\nexport function hashSubBudgetDelegation(delegation: DelegationForHashing): Hex {\n return hashDelegation(delegation)\n}\n\n// The kit's own struct hashes, re-exported verbatim from task-budget-guards'\n// pinned literals so a caller can name them from this module too.\nexport { DELEGATION_TYPEHASH, CAVEAT_TYPEHASH }\n\nexport interface SubBudgetChildExpectation {\n chainId: number\n tokenAddress: string\n /** Per-period amount in atomic units — the child's periodAmount. */\n periodAmountAtomic: string\n /** The PARENT's period duration (seconds), reused verbatim in the caveat. */\n periodDurationSeconds: number\n /** The PARENT's period anchor, reused verbatim in the caveat. */\n startDate: number\n recipientAddress: string | null\n /** unix seconds — the `TimestampEnforcer`'s `beforeThreshold`. */\n expiresAt: number\n /** The hash of the row's parent delegation (`parent_delegation_hash`). */\n parentDelegationHash: string\n /**\n * A's own derived delegate account — the child's `delegator` on BOTH rows.\n */\n delegateAccount: string\n /**\n * The row's own `delegate`: A's account again for the parent-child row,\n * B's delegate account for the grant row. Served in the sign-context's\n * `expected` (read from the stored child JSON, not trusted caller input).\n */\n childDelegateAccount: string\n}\n\nfunction refuseSubBudgetChild(what: string, detail: string): never {\n throw new HavenTypedDataRefusedError(\n `Refusing to sign the sub-budget child: ${what}. ${detail} ` +\n 'This signature opens a slice of the delegating agent budget for another agent, so it is ' +\n 'verified locally against the expectation Haven declared, rather than trusted.',\n )\n}\n\n/**\n * Verify a sub-budget child delegation is EXACTLY what\n * `GET /sub-budgets/:id/sign-context` (purpose `open`) declared, that its\n * `delegator` is this signer's own account, and that its `delegate` is the\n * declared child delegate. Throws `HavenTypedDataRefusedError` (never\n * returns) on any disagreement.\n */\nexport function assertOwnSubBudgetChild(\n typedData: unknown,\n expected: SubBudgetChildExpectation,\n delegateAddress: string,\n now: number = Date.now(),\n): void {\n const td = typedData as SubBudgetChildTypedData\n if (td?.primaryType !== 'Delegation') {\n refuseSubBudgetChild('it is not a Delegation payload', `primaryType was '${String(td?.primaryType)}'.`)\n }\n if (!same(td.domain?.verifyingContract, DELEGATION_MANAGER)) {\n refuseSubBudgetChild(\n 'the EIP-712 domain names an unknown DelegationManager',\n `Expected ${DELEGATION_MANAGER}, got ${td.domain?.verifyingContract}.`,\n )\n }\n if (td.domain?.name !== DELEGATION_DOMAIN_NAME || td.domain?.version !== DELEGATION_DOMAIN_VERSION) {\n refuseSubBudgetChild(\n 'the EIP-712 domain name/version does not match the pinned DelegationManager domain',\n `Expected name '${DELEGATION_DOMAIN_NAME}' version '${DELEGATION_DOMAIN_VERSION}'; got name ` +\n `'${String(td.domain?.name)}' version '${String(td.domain?.version)}'.`,\n )\n }\n if (\n JSON.stringify(td.types?.Caveat) !== JSON.stringify(EXPECTED_DELEGATION_TYPES.Caveat) ||\n JSON.stringify(td.types?.Delegation) !== JSON.stringify(EXPECTED_DELEGATION_TYPES.Delegation)\n ) {\n refuseSubBudgetChild(\n 'its EIP-712 type definitions do not match the pinned Delegation/Caveat shape',\n 'A renamed, reordered, or additional field on Delegation or Caveat could change what the ' +\n 'caveats below mean without changing this check\\'s field-by-field comparisons.',\n )\n }\n const domainChain = Number(td.domain?.chainId)\n if (!Number.isFinite(domainChain) || !DIRECT_PAYMENT_CHAIN_IDS.has(domainChain)) {\n refuseSubBudgetChild(\n 'it is scoped to a chain the delegation rail has no pinned contracts for',\n `Chains with pinned contracts: ${[...DIRECT_PAYMENT_CHAIN_IDS].join(', ')}; the child says ${String(td.domain?.chainId)}.`,\n )\n }\n if (domainChain !== expected.chainId) {\n refuseSubBudgetChild(\n 'it is scoped to the wrong chain',\n `Expected chain ${expected.chainId}; the child says ${td.domain?.chainId}.`,\n )\n }\n\n const ownAccount = deriveDelegateAccountAddress(delegateAddress as Address)\n const delegator = td.message?.delegator\n if (typeof delegator !== 'string' || !same(delegator, ownAccount)) {\n refuseSubBudgetChild(\n \"it is not delegated by this agent's own account\",\n `Expected delegator ${ownAccount}; the child names ${String(delegator)}.`,\n )\n }\n if (!same(delegator, expected.delegateAccount)) {\n refuseSubBudgetChild(\n 'its delegator does not match the account Haven declared',\n `Expected ${expected.delegateAccount}; the child names ${String(delegator)}.`,\n )\n }\n const delegate = td.message?.delegate\n if (typeof delegate !== 'string' || !same(delegate, expected.childDelegateAccount)) {\n refuseSubBudgetChild(\n 'its delegate does not match the declared child delegate',\n `Expected ${expected.childDelegateAccount}; the child names ${String(delegate)}.`,\n )\n }\n\n const authority = td.message?.authority\n if (typeof authority !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(authority)) {\n refuseSubBudgetChild('its authority is not a 32-byte delegation hash', `Got ${String(authority)}.`)\n }\n if (authority.toLowerCase() === ROOT_AUTHORITY) {\n refuseSubBudgetChild(\n 'it is a ROOT delegation, not a re-delegation of the delegating agent budget',\n 'A sub-budget always chains under the delegating agent budget delegation.',\n )\n }\n if (!same(authority, expected.parentDelegationHash)) {\n refuseSubBudgetChild(\n 'it chains under a different parent delegation',\n `Expected authority ${expected.parentDelegationHash}; the child says ${authority}.`,\n )\n }\n\n const caveats = (td.message?.caveats as Array<{ enforcer: string; terms: string }> | undefined) ?? []\n\n // The PERIOD caveat is what makes this a sub-budget — a hard-cap\n // `ERC20TransferAmountEnforcer` caveat is the task-budget shape and is\n // refused on this channel.\n if (findCaveat(caveats, CAVEAT_ENFORCERS.erc20TransferAmount)) {\n refuseSubBudgetChild(\n 'it carries a hard-cap transfer-amount caveat (the task-budget shape)',\n 'A sub-budget is period-scoped: its amount caveat must be an ERC20PeriodTransferEnforcer ' +\n 'caveat slicing the parent period meter, never a lifetime cap.',\n )\n }\n const period = findCaveat(caveats, ERC20_PERIOD_TRANSFER_ENFORCER)\n if (!period) {\n refuseSubBudgetChild(\n 'it has no ERC-20 period-transfer caveat',\n 'Without it the child is not bounded to a per-period amount.',\n )\n }\n // terms = abi.encodePacked(address token, uint256 periodAmount,\n // uint256 periodDuration, uint256 startDate) — the kit's TIGHT packing\n // (20 + 32×3 = 116 bytes, verified against `createDelegation`'s own\n // output), the same layout `task-budget-guards.ts` decodes for the\n // ERC20TransferAmountEnforcer. NOT head/tail-padded words: the address\n // occupies bytes [0,20) and the amount starts at byte 20.\n const token = `0x${sliceTerms(period.terms, 0, 20)}`\n if (!same(token, expected.tokenAddress)) {\n refuseSubBudgetChild('it spends a different token', `Expected ${expected.tokenAddress}, child pins ${token}.`)\n }\n const periodAmount = BigInt(`0x${sliceTerms(period.terms, 20, 52)}`)\n if (periodAmount !== BigInt(expected.periodAmountAtomic)) {\n refuseSubBudgetChild(\n 'the period amount does not match',\n `Expected ${expected.periodAmountAtomic}; the child allows ${periodAmount.toString()}.`,\n )\n }\n const periodDuration = Number(BigInt(`0x${sliceTerms(period.terms, 52, 84)}`))\n if (periodDuration !== expected.periodDurationSeconds) {\n refuseSubBudgetChild(\n 'its period duration does not match the parent window Haven declared',\n `Expected ${expected.periodDurationSeconds}s; the child says ${periodDuration}s. A sub-budget is a ` +\n 'slice of the parent period meter — same window, smaller amount — never a different clock.',\n )\n }\n const startDate = Number(BigInt(`0x${sliceTerms(period.terms, 84, 116)}`))\n if (startDate !== expected.startDate) {\n refuseSubBudgetChild(\n 'its period start does not match the parent anchor Haven declared',\n `Expected ${expected.startDate}; the child says ${startDate}.`,\n )\n }\n\n const timestamp = findCaveat(caveats, CAVEAT_ENFORCERS.timestamp)\n if (!timestamp) {\n refuseSubBudgetChild('it never expires', 'A sub-budget child without a timestamp caveat is open-ended.')\n }\n const beforeThreshold = Number(BigInt(`0x${sliceTerms(timestamp.terms, 16, 32)}`))\n const nowSec = Math.floor(now / 1000)\n if (beforeThreshold <= nowSec) {\n refuseSubBudgetChild('it has already expired', `Expiry ${beforeThreshold} is not in the future.`)\n }\n if (beforeThreshold !== expected.expiresAt) {\n refuseSubBudgetChild(\n 'its expiry does not match what Haven declared',\n `Expected ${expected.expiresAt}; the child says ${beforeThreshold}.`,\n )\n }\n\n const calldata = findCaveat(caveats, CAVEAT_ENFORCERS.allowedCalldata)\n if (expected.recipientAddress) {\n if (!calldata) {\n refuseSubBudgetChild(\n 'it has no recipient pin',\n 'The sub-budget was issued with a pinned recipient, so the child must carry one.',\n )\n }\n const startIndex = BigInt(`0x${sliceTerms(calldata.terms, 0, 32)}`)\n if (startIndex !== 4n) {\n refuseSubBudgetChild(\n 'the recipient pin points at the wrong calldata offset',\n `Expected offset 4, got ${startIndex.toString()}.`,\n )\n }\n const paddedRecipient = sliceTerms(calldata.terms, 32, 64)\n if (paddedRecipient.slice(0, 24) !== '0'.repeat(24)) {\n refuseSubBudgetChild('the pinned recipient is not a plain address', 'Its 32-byte word is not a padded address.')\n }\n const recipient = `0x${paddedRecipient.slice(24)}`\n if (!same(recipient, expected.recipientAddress)) {\n refuseSubBudgetChild(\n 'it pins a different recipient than Haven declared',\n `Expected ${expected.recipientAddress}; the child pins ${recipient}.`,\n )\n }\n } else if (calldata) {\n refuseSubBudgetChild(\n 'it pins a recipient the sub-budget was not issued with',\n 'This sub-budget is open (no recipient pin); the child must not add one.',\n )\n }\n}\n\n/** Close UserOp verification — byte-for-byte the task-budget discipline. */\nexport function assertOwnSubBudgetCloseUserOp(\n typedData: Record<string, unknown>,\n expected: { delegationHash: string },\n delegateAddress: string,\n): void {\n // The close UserOp shape is identical to the task budget's: a\n // disableDelegation(child) call from the agent's own delegate account.\n // Reuse the task-budget verifier — the only expectation that differs is\n // the delegation hash, which is an input here either way. Static import,\n // not lazy: these modules share no init-time cycle.\n assertOwnTaskBudgetCloseUserOp(typedData, expected, delegateAddress)\n}\n\n// The close-UserOp verifier is imported for the re-export above.\nimport { assertOwnTaskBudgetCloseUserOp } from './task-budget-guards.js'\n"]}