@seedhape/core 0.1.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.
Files changed (133) hide show
  1. package/dist/__tests__/acp.test.d.ts +2 -0
  2. package/dist/__tests__/acp.test.d.ts.map +1 -0
  3. package/dist/__tests__/acp.test.js +16 -0
  4. package/dist/__tests__/acp.test.js.map +1 -0
  5. package/dist/__tests__/ap2-official.test.d.ts +2 -0
  6. package/dist/__tests__/ap2-official.test.d.ts.map +1 -0
  7. package/dist/__tests__/ap2-official.test.js +49 -0
  8. package/dist/__tests__/ap2-official.test.js.map +1 -0
  9. package/dist/__tests__/mpp.test.d.ts +2 -0
  10. package/dist/__tests__/mpp.test.d.ts.map +1 -0
  11. package/dist/__tests__/mpp.test.js +42 -0
  12. package/dist/__tests__/mpp.test.js.map +1 -0
  13. package/dist/__tests__/outbound.test.d.ts +2 -0
  14. package/dist/__tests__/outbound.test.d.ts.map +1 -0
  15. package/dist/__tests__/outbound.test.js +23 -0
  16. package/dist/__tests__/outbound.test.js.map +1 -0
  17. package/dist/__tests__/protocols.test.d.ts +2 -0
  18. package/dist/__tests__/protocols.test.d.ts.map +1 -0
  19. package/dist/__tests__/protocols.test.js +16 -0
  20. package/dist/__tests__/protocols.test.js.map +1 -0
  21. package/dist/__tests__/providers.test.d.ts +2 -0
  22. package/dist/__tests__/providers.test.d.ts.map +1 -0
  23. package/dist/__tests__/providers.test.js +41 -0
  24. package/dist/__tests__/providers.test.js.map +1 -0
  25. package/dist/__tests__/reconciliation.test.d.ts +2 -0
  26. package/dist/__tests__/reconciliation.test.d.ts.map +1 -0
  27. package/dist/__tests__/reconciliation.test.js +35 -0
  28. package/dist/__tests__/reconciliation.test.js.map +1 -0
  29. package/dist/__tests__/spending-controls.test.d.ts +2 -0
  30. package/dist/__tests__/spending-controls.test.d.ts.map +1 -0
  31. package/dist/__tests__/spending-controls.test.js +47 -0
  32. package/dist/__tests__/spending-controls.test.js.map +1 -0
  33. package/dist/__tests__/tax-and-policy.test.d.ts +7 -0
  34. package/dist/__tests__/tax-and-policy.test.d.ts.map +1 -0
  35. package/dist/__tests__/tax-and-policy.test.js +389 -0
  36. package/dist/__tests__/tax-and-policy.test.js.map +1 -0
  37. package/dist/__tests__/web-bot-auth.test.d.ts +2 -0
  38. package/dist/__tests__/web-bot-auth.test.d.ts.map +1 -0
  39. package/dist/__tests__/web-bot-auth.test.js +33 -0
  40. package/dist/__tests__/web-bot-auth.test.js.map +1 -0
  41. package/dist/__tests__/x402-solana.test.d.ts +2 -0
  42. package/dist/__tests__/x402-solana.test.d.ts.map +1 -0
  43. package/dist/__tests__/x402-solana.test.js +155 -0
  44. package/dist/__tests__/x402-solana.test.js.map +1 -0
  45. package/dist/acp.d.ts +28 -0
  46. package/dist/acp.d.ts.map +1 -0
  47. package/dist/acp.js +49 -0
  48. package/dist/acp.js.map +1 -0
  49. package/dist/ap2/mandates.d.ts +319 -0
  50. package/dist/ap2/mandates.d.ts.map +1 -0
  51. package/dist/ap2/mandates.js +214 -0
  52. package/dist/ap2/mandates.js.map +1 -0
  53. package/dist/ap2/official.d.ts +156 -0
  54. package/dist/ap2/official.d.ts.map +1 -0
  55. package/dist/ap2/official.js +222 -0
  56. package/dist/ap2/official.js.map +1 -0
  57. package/dist/ap2/policy.d.ts +93 -0
  58. package/dist/ap2/policy.d.ts.map +1 -0
  59. package/dist/ap2/policy.js +216 -0
  60. package/dist/ap2/policy.js.map +1 -0
  61. package/dist/index.d.ts +22 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +22 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/india/fx.d.ts +59 -0
  66. package/dist/india/fx.d.ts.map +1 -0
  67. package/dist/india/fx.js +93 -0
  68. package/dist/india/fx.js.map +1 -0
  69. package/dist/india/vda-tax.d.ts +151 -0
  70. package/dist/india/vda-tax.d.ts.map +1 -0
  71. package/dist/india/vda-tax.js +226 -0
  72. package/dist/india/vda-tax.js.map +1 -0
  73. package/dist/mandate-builder.d.ts +102 -0
  74. package/dist/mandate-builder.d.ts.map +1 -0
  75. package/dist/mandate-builder.js +99 -0
  76. package/dist/mandate-builder.js.map +1 -0
  77. package/dist/mpp.d.ts +53 -0
  78. package/dist/mpp.d.ts.map +1 -0
  79. package/dist/mpp.js +164 -0
  80. package/dist/mpp.js.map +1 -0
  81. package/dist/orchestrator.d.ts +115 -0
  82. package/dist/orchestrator.d.ts.map +1 -0
  83. package/dist/orchestrator.js +351 -0
  84. package/dist/orchestrator.js.map +1 -0
  85. package/dist/postgres-store.d.ts +60 -0
  86. package/dist/postgres-store.d.ts.map +1 -0
  87. package/dist/postgres-store.js +441 -0
  88. package/dist/postgres-store.js.map +1 -0
  89. package/dist/protocols.d.ts +18 -0
  90. package/dist/protocols.d.ts.map +1 -0
  91. package/dist/protocols.js +24 -0
  92. package/dist/protocols.js.map +1 -0
  93. package/dist/reconciliation.d.ts +27 -0
  94. package/dist/reconciliation.d.ts.map +1 -0
  95. package/dist/reconciliation.js +38 -0
  96. package/dist/reconciliation.js.map +1 -0
  97. package/dist/store.d.ts +110 -0
  98. package/dist/store.d.ts.map +1 -0
  99. package/dist/store.js +369 -0
  100. package/dist/store.js.map +1 -0
  101. package/dist/types.d.ts +195 -0
  102. package/dist/types.d.ts.map +1 -0
  103. package/dist/types.js +30 -0
  104. package/dist/types.js.map +1 -0
  105. package/dist/util/canonical.d.ts +9 -0
  106. package/dist/util/canonical.d.ts.map +1 -0
  107. package/dist/util/canonical.js +35 -0
  108. package/dist/util/canonical.js.map +1 -0
  109. package/dist/wallet/provider.d.ts +118 -0
  110. package/dist/wallet/provider.d.ts.map +1 -0
  111. package/dist/wallet/provider.js +160 -0
  112. package/dist/wallet/provider.js.map +1 -0
  113. package/dist/wallet/providers.d.ts +107 -0
  114. package/dist/wallet/providers.d.ts.map +1 -0
  115. package/dist/wallet/providers.js +188 -0
  116. package/dist/wallet/providers.js.map +1 -0
  117. package/dist/web-bot-auth.d.ts +54 -0
  118. package/dist/web-bot-auth.d.ts.map +1 -0
  119. package/dist/web-bot-auth.js +112 -0
  120. package/dist/web-bot-auth.js.map +1 -0
  121. package/dist/x402/client.d.ts +101 -0
  122. package/dist/x402/client.d.ts.map +1 -0
  123. package/dist/x402/client.js +291 -0
  124. package/dist/x402/client.js.map +1 -0
  125. package/dist/x402/outbound.d.ts +15 -0
  126. package/dist/x402/outbound.d.ts.map +1 -0
  127. package/dist/x402/outbound.js +59 -0
  128. package/dist/x402/outbound.js.map +1 -0
  129. package/dist/x402/types.d.ts +80 -0
  130. package/dist/x402/types.d.ts.map +1 -0
  131. package/dist/x402/types.js +2 -0
  132. package/dist/x402/types.js.map +1 -0
  133. package/package.json +29 -0
@@ -0,0 +1,226 @@
1
+ /**
2
+ * India VDA tax engine.
3
+ *
4
+ * ⚠️ This is engineering scaffolding, not tax advice. The rates, thresholds and
5
+ * section references below must be reviewed and signed off by a chartered
6
+ * accountant before you go live, and re-checked every Finance Act. In
7
+ * particular: the Income-tax Act, 2025 renumbers the provisions that the
8
+ * Income-tax Act, 1961 called 115BBH and 194S. Section labels are therefore
9
+ * configuration, not constants — see `TaxRuleSet`.
10
+ *
11
+ * Why this module exists at all:
12
+ *
13
+ * Under the Indian VDA regime, spending USDC is a *transfer of a virtual
14
+ * digital asset*, not a payment. That has two consequences most agentic-payment
15
+ * stacks ignore entirely:
16
+ *
17
+ * 1. Every spend realises a capital gain or loss against the INR cost at
18
+ * which that USDC was acquired. Gains are taxed at a flat 30% (plus
19
+ * surcharge and cess) with no deduction other than cost of acquisition,
20
+ * and losses cannot be set off against anything or carried forward. So
21
+ * you must track lots, not just a balance.
22
+ *
23
+ * 2. The payer is the deductor for 1% TDS on the consideration. You cannot
24
+ * withhold 1% out of an on-chain micropayment — the merchant's 402
25
+ * challenge demands an exact amount. The workable pattern is to accrue the
26
+ * liability against a pool funded at onramp time and remit it on the
27
+ * statutory cycle. `TdsAccrual` implements that accrual.
28
+ *
29
+ * A stack that skips this leaves its users with an unreconcilable year-end.
30
+ */
31
+ export const RULES_FY_2026_27_SPECIFIED_PERSON = {
32
+ financialYear: "2026-27",
33
+ vdaGainRateBps: 3000,
34
+ cessBps: 400,
35
+ tdsRateBps: 100,
36
+ tdsThresholdPaise: 5000000n, // ₹50,000
37
+ allowLossSetOff: false,
38
+ labels: {
39
+ gainSection: "115BBH (ITA 1961) / VDA income provisions (ITA 2025)",
40
+ tdsSection: "194S (ITA 1961) / corresponding TDS provision (ITA 2025)",
41
+ tdsFormSpecifiedPerson: "26QE",
42
+ tdsFormOther: "26Q",
43
+ },
44
+ };
45
+ export const RULES_FY_2026_27_OTHER = {
46
+ ...RULES_FY_2026_27_SPECIFIED_PERSON,
47
+ tdsThresholdPaise: 1000000n, // ₹10,000
48
+ };
49
+ export class InsufficientLotsError extends Error {
50
+ shortfall;
51
+ constructor(shortfall) {
52
+ super(`Not enough acquired USDC to account for this disposal; short by ${shortfall} base units. ` +
53
+ `This usually means USDC arrived in the wallet outside a tracked onramp (a direct transfer, ` +
54
+ `a refund, or an airdrop) and needs a manual cost-basis entry.`);
55
+ this.shortfall = shortfall;
56
+ this.name = "InsufficientLotsError";
57
+ }
58
+ }
59
+ /**
60
+ * Consume lots FIFO. Mutates `remaining` on the supplied lots — callers should
61
+ * persist them afterwards inside the same transaction as the spend record.
62
+ */
63
+ export function consumeFifo(lots, quantity, proceedsInrPaise) {
64
+ const ordered = [...lots]
65
+ .filter((l) => l.remaining > 0n)
66
+ .sort((a, b) => a.acquiredAt - b.acquiredAt);
67
+ let outstanding = quantity;
68
+ let cost = 0n;
69
+ const consumptions = [];
70
+ for (const lot of ordered) {
71
+ if (outstanding === 0n)
72
+ break;
73
+ const take = outstanding < lot.remaining ? outstanding : lot.remaining;
74
+ // Proportional cost of the slice. Integer maths throughout; the rounding
75
+ // residue stays with the lot so total cost never drifts above what was paid.
76
+ const sliceCost = (lot.costInrPaise * take) / lot.quantity;
77
+ lot.remaining -= take;
78
+ outstanding -= take;
79
+ cost += sliceCost;
80
+ consumptions.push({ lotId: lot.id, quantity: take, costInrPaise: sliceCost });
81
+ }
82
+ if (outstanding > 0n)
83
+ throw new InsufficientLotsError(outstanding);
84
+ return {
85
+ quantity,
86
+ proceedsInrPaise,
87
+ costInrPaise: cost,
88
+ gainInrPaise: proceedsInrPaise - cost,
89
+ consumptions,
90
+ };
91
+ }
92
+ /**
93
+ * Accrue TDS for one transfer given the FY-to-date cumulative consideration.
94
+ *
95
+ * Threshold semantics: once cumulative consideration in the financial year
96
+ * exceeds the threshold, TDS is due on the whole consideration for the year,
97
+ * not merely the excess. So the transfer that crosses the line carries a
98
+ * catch-up for everything that preceded it.
99
+ */
100
+ export function accrueTds(rules, considerationPaise, priorCumulativePaise, priorTdsPaidPaise) {
101
+ const cumulative = priorCumulativePaise + considerationPaise;
102
+ if (cumulative <= rules.tdsThresholdPaise) {
103
+ return {
104
+ considerationPaise,
105
+ tdsPaise: 0n,
106
+ cumulativeConsiderationPaise: cumulative,
107
+ thresholdCrossed: false,
108
+ catchUpPaise: 0n,
109
+ };
110
+ }
111
+ const totalTdsDue = (cumulative * BigInt(rules.tdsRateBps)) / 10000n;
112
+ const thisTransferTds = (considerationPaise * BigInt(rules.tdsRateBps)) / 10000n;
113
+ const crossed = priorCumulativePaise <= rules.tdsThresholdPaise;
114
+ const catchUp = crossed ? totalTdsDue - priorTdsPaidPaise - thisTransferTds : 0n;
115
+ return {
116
+ considerationPaise,
117
+ tdsPaise: thisTransferTds,
118
+ cumulativeConsiderationPaise: cumulative,
119
+ thresholdCrossed: crossed,
120
+ catchUpPaise: catchUp > 0n ? catchUp : 0n,
121
+ };
122
+ }
123
+ /**
124
+ * Build the FY report. Recomputes disposals from scratch against a copy of the
125
+ * lots so the report is reproducible and never mutates stored state.
126
+ */
127
+ export function buildVdaTaxReport(input) {
128
+ const { rules } = input;
129
+ const lots = input.lots.map((l) => ({ ...l, remaining: l.quantity }));
130
+ const warnings = [];
131
+ const settled = input.spends
132
+ .filter((s) => s.status === "settled")
133
+ .sort((a, b) => a.createdAt - b.createdAt);
134
+ const lines = [];
135
+ let gains = 0n;
136
+ let losses = 0n;
137
+ let consideration = 0n;
138
+ let tdsAccrued = 0n;
139
+ let cumulative = 0n;
140
+ for (const s of settled) {
141
+ let disposal;
142
+ try {
143
+ disposal = consumeFifo(lots, s.amount, s.inrPaise);
144
+ }
145
+ catch (e) {
146
+ if (e instanceof InsufficientLotsError) {
147
+ warnings.push(`Spend ${s.id}: no cost basis available (short ${e.shortfall} base units). ` +
148
+ `Treated as zero cost, which overstates the gain. Add a manual acquisition lot.`);
149
+ disposal = {
150
+ quantity: s.amount,
151
+ proceedsInrPaise: s.inrPaise,
152
+ costInrPaise: 0n,
153
+ gainInrPaise: s.inrPaise,
154
+ consumptions: [],
155
+ };
156
+ }
157
+ else
158
+ throw e;
159
+ }
160
+ const tds = accrueTds(rules, s.inrPaise, cumulative, tdsAccrued);
161
+ cumulative = tds.cumulativeConsiderationPaise;
162
+ const tdsThisLine = tds.tdsPaise + tds.catchUpPaise;
163
+ tdsAccrued += tdsThisLine;
164
+ consideration += s.inrPaise;
165
+ if (disposal.gainInrPaise >= 0n)
166
+ gains += disposal.gainInrPaise;
167
+ else
168
+ losses += -disposal.gainInrPaise;
169
+ lines.push({
170
+ spendId: s.id,
171
+ date: new Date(s.createdAt * 1000).toISOString(),
172
+ counterparty: s.payTo,
173
+ resource: s.resource,
174
+ quantity: s.amount,
175
+ proceedsInrPaise: s.inrPaise,
176
+ costInrPaise: disposal.costInrPaise,
177
+ gainInrPaise: disposal.gainInrPaise,
178
+ tdsPaise: tdsThisLine,
179
+ });
180
+ }
181
+ const taxableBase = rules.allowLossSetOff ? gains - losses : gains;
182
+ const base = taxableBase > 0n ? taxableBase : 0n;
183
+ const taxOnGains = (base * BigInt(rules.vdaGainRateBps)) / 10000n;
184
+ const cess = (taxOnGains * BigInt(rules.cessBps)) / 10000n;
185
+ const totalTax = taxOnGains + cess;
186
+ if (!rules.allowLossSetOff && losses > 0n) {
187
+ warnings.push(`₹${paiseToInr(losses)} of losses are NOT deductible under the VDA regime and cannot be ` +
188
+ `carried forward. They are reported for completeness only.`);
189
+ }
190
+ return {
191
+ financialYear: rules.financialYear,
192
+ rules,
193
+ totalSpends: settled.length,
194
+ totalConsiderationPaise: consideration,
195
+ totalGainsPaise: gains,
196
+ totalLossesPaise: losses,
197
+ netPaise: gains - losses,
198
+ taxOnGainsPaise: taxOnGains,
199
+ cessPaise: cess,
200
+ totalTaxPaise: totalTax,
201
+ tdsAccruedPaise: tdsAccrued,
202
+ balancePayablePaise: totalTax - tdsAccrued > 0n ? totalTax - tdsAccrued : 0n,
203
+ lines,
204
+ warnings,
205
+ };
206
+ }
207
+ // ---------------------------------------------------------------------------
208
+ // Formatting
209
+ // ---------------------------------------------------------------------------
210
+ export function paiseToInr(paise) {
211
+ const neg = paise < 0n;
212
+ const abs = neg ? -paise : paise;
213
+ const rupees = abs / 100n;
214
+ const p = abs % 100n;
215
+ return `${neg ? "-" : ""}${groupIndian(rupees)}.${p.toString().padStart(2, "0")}`;
216
+ }
217
+ /** Indian digit grouping: 1,23,45,678 rather than 12,345,678. */
218
+ function groupIndian(n) {
219
+ const s = n.toString();
220
+ if (s.length <= 3)
221
+ return s;
222
+ const last3 = s.slice(-3);
223
+ const rest = s.slice(0, -3);
224
+ return rest.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + "," + last3;
225
+ }
226
+ //# sourceMappingURL=vda-tax.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vda-tax.js","sourceRoot":"","sources":["../../src/india/vda-tax.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Mandate builder.
3
+ *
4
+ * An agent asking a user to sign an Intent Mandate has one shot at being
5
+ * understood. The typed-data prompt the wallet renders is the only thing
6
+ * standing between the user and a blank cheque, so this builder is opinionated:
7
+ * every mandate has a hard expiry, every mandate has a transaction-count cap,
8
+ * and there is no "unlimited" option.
9
+ */
10
+ import type { Address, AssetRef, Hex, IntentMandate, SignedIntentMandate } from "./types.js";
11
+ export interface MandateSpec {
12
+ subject: Address;
13
+ agent: Address;
14
+ purpose: string;
15
+ /** Human units, e.g. "0.50" USDC. */
16
+ maxPerTransaction: string;
17
+ maxPerPeriod: string;
18
+ period: "hour" | "day" | "week" | "month";
19
+ maxTxPerPeriod: number;
20
+ /** Days until expiry. Capped at 90 — a mandate is not a standing order. */
21
+ validForDays: number;
22
+ allowedHosts?: string[];
23
+ allowedPayTo?: Address[];
24
+ asset: AssetRef;
25
+ chainId: number;
26
+ }
27
+ export declare const MAX_MANDATE_DAYS = 90;
28
+ export declare class MandateValidationError extends Error {
29
+ readonly problems: string[];
30
+ constructor(problems: string[]);
31
+ }
32
+ export declare function buildIntentMandate(spec: MandateSpec): IntentMandate;
33
+ /** Everything a wallet needs to render and sign the mandate. */
34
+ export declare function mandateSigningRequest(m: IntentMandate): {
35
+ hash: `0x${string}`;
36
+ typedData: {
37
+ domain: import("viem").TypedDataDomain;
38
+ types: {
39
+ readonly IntentMandate: readonly [{
40
+ readonly name: "subject";
41
+ readonly type: "address";
42
+ }, {
43
+ readonly name: "agent";
44
+ readonly type: "address";
45
+ }, {
46
+ readonly name: "purpose";
47
+ readonly type: "string";
48
+ }, {
49
+ readonly name: "maxPerTransaction";
50
+ readonly type: "uint256";
51
+ }, {
52
+ readonly name: "maxPerPeriod";
53
+ readonly type: "uint256";
54
+ }, {
55
+ readonly name: "periodSeconds";
56
+ readonly type: "uint64";
57
+ }, {
58
+ readonly name: "maxTxPerPeriod";
59
+ readonly type: "uint32";
60
+ }, {
61
+ readonly name: "allowedPayToRoot";
62
+ readonly type: "bytes32";
63
+ }, {
64
+ readonly name: "allowedHostsRoot";
65
+ readonly type: "bytes32";
66
+ }, {
67
+ readonly name: "asset";
68
+ readonly type: "address";
69
+ }, {
70
+ readonly name: "notBefore";
71
+ readonly type: "uint64";
72
+ }, {
73
+ readonly name: "expiry";
74
+ readonly type: "uint64";
75
+ }, {
76
+ readonly name: "nonce";
77
+ readonly type: "bytes32";
78
+ }];
79
+ };
80
+ primaryType: "IntentMandate";
81
+ message: {
82
+ subject: `0x${string}`;
83
+ agent: `0x${string}`;
84
+ purpose: string;
85
+ maxPerTransaction: bigint;
86
+ maxPerPeriod: bigint;
87
+ periodSeconds: bigint;
88
+ maxTxPerPeriod: number;
89
+ allowedPayToRoot: `0x${string}`;
90
+ allowedHostsRoot: `0x${string}`;
91
+ asset: `0x${string}`;
92
+ notBefore: bigint;
93
+ expiry: bigint;
94
+ nonce: `0x${string}`;
95
+ };
96
+ };
97
+ /** Plain-language summary to show alongside the raw typed data. */
98
+ summary: string;
99
+ };
100
+ export declare function attachSignature(m: IntentMandate, signature: Hex): SignedIntentMandate;
101
+ export declare function describeMandate(m: IntentMandate): string;
102
+ //# sourceMappingURL=mandate-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mandate-builder.d.ts","sourceRoot":"","sources":["../src/mandate-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,GAAG,EACH,aAAa,EACb,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;IACzB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AASD,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE;gBAAlB,QAAQ,EAAE,MAAM,EAAE;CAIxC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,aAAa,CA+CnE;AAED,gEAAgE;AAChE,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAIlD,mEAAmE;;EAGtE;AAED,wBAAgB,eAAe,CAC7B,CAAC,EAAE,aAAa,EAChB,SAAS,EAAE,GAAG,GACb,mBAAmB,CAErB;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAsBxD"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Mandate builder.
3
+ *
4
+ * An agent asking a user to sign an Intent Mandate has one shot at being
5
+ * understood. The typed-data prompt the wallet renders is the only thing
6
+ * standing between the user and a blank cheque, so this builder is opinionated:
7
+ * every mandate has a hard expiry, every mandate has a transaction-count cap,
8
+ * and there is no "unlimited" option.
9
+ */
10
+ import { randomBytes } from "node:crypto";
11
+ import { toHex, parseUnits } from "viem";
12
+ import { hashIntentMandate, intentTypedData } from "./ap2/mandates.js";
13
+ const PERIOD_SECONDS = {
14
+ hour: 3_600,
15
+ day: 86_400,
16
+ week: 604_800,
17
+ month: 2_592_000,
18
+ };
19
+ export const MAX_MANDATE_DAYS = 90;
20
+ export class MandateValidationError extends Error {
21
+ problems;
22
+ constructor(problems) {
23
+ super(problems.join(" "));
24
+ this.problems = problems;
25
+ this.name = "MandateValidationError";
26
+ }
27
+ }
28
+ export function buildIntentMandate(spec) {
29
+ const problems = [];
30
+ const perTx = parseUnits(spec.maxPerTransaction, spec.asset.decimals);
31
+ const perPeriod = parseUnits(spec.maxPerPeriod, spec.asset.decimals);
32
+ if (perTx <= 0n)
33
+ problems.push("maxPerTransaction must be greater than zero.");
34
+ if (perPeriod <= 0n)
35
+ problems.push("maxPerPeriod must be greater than zero.");
36
+ if (perTx > perPeriod) {
37
+ problems.push("maxPerTransaction cannot exceed maxPerPeriod — a single payment would " +
38
+ "exhaust the whole budget, which makes the period cap meaningless.");
39
+ }
40
+ if (spec.maxTxPerPeriod < 1)
41
+ problems.push("maxTxPerPeriod must be at least 1.");
42
+ if (spec.validForDays < 1)
43
+ problems.push("validForDays must be at least 1.");
44
+ if (spec.validForDays > MAX_MANDATE_DAYS) {
45
+ problems.push(`validForDays cannot exceed ${MAX_MANDATE_DAYS}. Long-lived mandates are the ` +
46
+ `main way agentic spend goes wrong; renew instead.`);
47
+ }
48
+ if (!spec.purpose || spec.purpose.trim().length < 8) {
49
+ problems.push("purpose must be a real description — it is what the user reads in the " +
50
+ "signing prompt and what appears in the audit log.");
51
+ }
52
+ if (problems.length)
53
+ throw new MandateValidationError(problems);
54
+ const now = Math.floor(Date.now() / 1000);
55
+ return {
56
+ subject: spec.subject,
57
+ agent: spec.agent,
58
+ purpose: spec.purpose.trim(),
59
+ maxPerTransaction: perTx,
60
+ maxPerPeriod: perPeriod,
61
+ periodSeconds: PERIOD_SECONDS[spec.period],
62
+ maxTxPerPeriod: spec.maxTxPerPeriod,
63
+ allowedPayTo: spec.allowedPayTo ?? [],
64
+ allowedHosts: spec.allowedHosts ?? [],
65
+ asset: spec.asset,
66
+ notBefore: now,
67
+ expiry: now + spec.validForDays * 86_400,
68
+ nonce: toHex(randomBytes(32)),
69
+ chainId: spec.chainId,
70
+ };
71
+ }
72
+ /** Everything a wallet needs to render and sign the mandate. */
73
+ export function mandateSigningRequest(m) {
74
+ return {
75
+ hash: hashIntentMandate(m),
76
+ typedData: intentTypedData(m),
77
+ /** Plain-language summary to show alongside the raw typed data. */
78
+ summary: describeMandate(m),
79
+ };
80
+ }
81
+ export function attachSignature(m, signature) {
82
+ return { mandate: m, hash: hashIntentMandate(m), signature };
83
+ }
84
+ export function describeMandate(m) {
85
+ const unit = (v) => `${(Number(v) / 10 ** m.asset.decimals).toFixed(m.asset.decimals > 4 ? 4 : 2)} ${m.asset.symbol}`;
86
+ const period = Object.entries(PERIOD_SECONDS).find(([, s]) => s === m.periodSeconds)?.[0] ??
87
+ `${m.periodSeconds}s`;
88
+ const scope = m.allowedHosts.length > 0
89
+ ? `only to ${m.allowedHosts.join(", ")}`
90
+ : "to any x402 endpoint";
91
+ const payees = m.allowedPayTo.length > 0
92
+ ? ` and only to the payees ${m.allowedPayTo.join(", ")}`
93
+ : "";
94
+ return (`Authorise the agent at ${m.agent} to spend up to ${unit(m.maxPerTransaction)} per payment, ` +
95
+ `at most ${unit(m.maxPerPeriod)} and ${m.maxTxPerPeriod} payments per ${period}, ${scope}${payees}. ` +
96
+ `Purpose: ${m.purpose}. Expires ${new Date(m.expiry * 1000).toUTCString()}. ` +
97
+ `Revocable at any time.`);
98
+ }
99
+ //# sourceMappingURL=mandate-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mandate-builder.js","sourceRoot":"","sources":["../src/mandate-builder.ts"],"names":[],"mappings":"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"}
package/dist/mpp.d.ts ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * MPP (Machine Payments Protocol) HTTP Authentication Scheme primitives.
3
+ *
4
+ * This module deliberately implements only the provider-neutral wire format.
5
+ * A parsed credential is untrusted input; a payment-method adapter must verify
6
+ * it, enforce the shared spending policy, and settle before fulfillment.
7
+ */
8
+ export type MppChallenge = {
9
+ id: string;
10
+ realm: string;
11
+ method: string;
12
+ intent: string;
13
+ request: Record<string, unknown>;
14
+ expires?: number;
15
+ [key: string]: unknown;
16
+ };
17
+ export type MppCredential = {
18
+ challenge: MppChallenge;
19
+ payload: Record<string, unknown>;
20
+ source?: Record<string, unknown>;
21
+ };
22
+ export type MppReceipt = {
23
+ status: string;
24
+ method: string;
25
+ timestamp: number;
26
+ reference: string;
27
+ [key: string]: unknown;
28
+ };
29
+ /** Serialize a `WWW-Authenticate: Payment ...` challenge. */
30
+ export declare function formatMppChallenge(challenge: MppChallenge): string;
31
+ /** Parse a `WWW-Authenticate: Payment ...` challenge and reject duplicates. */
32
+ export declare function parseMppChallenge(header: string): MppChallenge;
33
+ /** Serialize an MPP `Authorization: Payment <base64url>` credential. */
34
+ export declare function formatMppCredential(credential: MppCredential): string;
35
+ /** Parse an MPP `Authorization: Payment <base64url>` credential. */
36
+ export declare function parseMppCredential(header: string): MppCredential;
37
+ /** Serialize an MPP `Payment-Receipt` response header. */
38
+ export declare function formatMppReceipt(receipt: MppReceipt): string;
39
+ /** Parse an MPP `Payment-Receipt` response header. */
40
+ export declare function parseMppReceipt(header: string): MppReceipt;
41
+ export type MppOutboundResult = {
42
+ response: Response;
43
+ challenge?: MppChallenge;
44
+ receipt?: MppReceipt;
45
+ };
46
+ /**
47
+ * Execute one MPP-protected request. Credential creation is injected so the
48
+ * caller can enforce its own user mandate, budget, and provider policy before
49
+ * producing a payment credential. The transport retries at most once after a
50
+ * valid 402 challenge and never retries an ambiguous response.
51
+ */
52
+ export declare function fetchWithMpp(input: string | URL | Request, init: RequestInit | undefined, createCredential: (challenge: MppChallenge) => Promise<MppCredential>, fetchImpl?: typeof fetch): Promise<MppOutboundResult>;
53
+ //# sourceMappingURL=mpp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mpp.d.ts","sourceRoot":"","sources":["../src/mpp.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AA+CF,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,YAAY,GAAG,MAAM,CAalE;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAuB9D;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,CAGrE;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAMhE;AAED,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAG5D;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAI1D;AAED,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,CAAC,EAAE,YAAY,CAAC;IAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAEvG;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC7B,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,gBAAgB,EAAE,CAAC,SAAS,EAAE,YAAY,KAAK,OAAO,CAAC,aAAa,CAAC,EACrE,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAa5B"}