@hazbase/simplicity 0.0.5 → 0.2.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 (61) hide show
  1. package/README.md +140 -1038
  2. package/dist/cli.js +3341 -269
  3. package/dist/client/SimplicityClient.d.ts +91 -290
  4. package/dist/client/SimplicityClient.js +93 -23
  5. package/dist/core/executor.js +67 -92
  6. package/dist/core/lineage.d.ts +18 -0
  7. package/dist/core/lineage.js +30 -0
  8. package/dist/core/outputBinding.d.ts +61 -0
  9. package/dist/core/outputBinding.js +552 -0
  10. package/dist/core/reporting.d.ts +22 -0
  11. package/dist/core/reporting.js +40 -0
  12. package/dist/core/schnorr.d.ts +5 -0
  13. package/dist/core/schnorr.js +46 -0
  14. package/dist/core/types.d.ts +799 -1
  15. package/dist/docs/definitions/bond-anchor.simf +19 -0
  16. package/dist/docs/definitions/bond-definition.json +10 -0
  17. package/dist/docs/definitions/bond-descriptor-bound-settlement-machine.simf +144 -0
  18. package/dist/docs/definitions/bond-issuance-anchor.simf +26 -0
  19. package/dist/docs/definitions/bond-issuance-state-partial-redemption.json +18 -0
  20. package/dist/docs/definitions/bond-issuance-state-redeemed.json +18 -0
  21. package/dist/docs/definitions/bond-issuance-state.json +12 -0
  22. package/dist/docs/definitions/bond-redemption-state-machine.simf +118 -0
  23. package/dist/docs/definitions/bond-redemption-transition.simf +41 -0
  24. package/dist/docs/definitions/bond-script-bound-settlement-machine.simf +142 -0
  25. package/dist/docs/definitions/fund-capital-call-open.simf +82 -0
  26. package/dist/docs/definitions/fund-capital-call-refund-only.simf +67 -0
  27. package/dist/docs/definitions/fund-capital-call-state.json +11 -0
  28. package/dist/docs/definitions/fund-definition.json +8 -0
  29. package/dist/docs/definitions/fund-distribution-claim.simf +57 -0
  30. package/dist/docs/definitions/receivable-definition.json +9 -0
  31. package/dist/docs/definitions/receivable-funding-claim.json +13 -0
  32. package/dist/docs/definitions/receivable-funding-claim.simf +58 -0
  33. package/dist/docs/definitions/receivable-repayment-claim.json +13 -0
  34. package/dist/docs/definitions/receivable-repayment-claim.simf +59 -0
  35. package/dist/docs/definitions/receivable-state-funded.json +20 -0
  36. package/dist/docs/definitions/receivable-state-originated.json +19 -0
  37. package/dist/docs/definitions/receivable-state-repaid.json +20 -0
  38. package/dist/docs/definitions/recursive-delay-direct-next.simf +60 -0
  39. package/dist/docs/definitions/recursive-delay-optional.simf +88 -0
  40. package/dist/docs/definitions/recursive-delay-required.simf +72 -0
  41. package/dist/docs/definitions/recursive-delay.simf +83 -0
  42. package/dist/docs/definitions/recursive-policy-transfer-machine.simf +65 -0
  43. package/dist/domain/bond.d.ts +8649 -720
  44. package/dist/domain/bond.js +1398 -8
  45. package/dist/domain/bondSettlementValidation.d.ts +2 -0
  46. package/dist/domain/bondSettlementValidation.js +28 -0
  47. package/dist/domain/bondValidation.d.ts +37 -1
  48. package/dist/domain/bondValidation.js +137 -11
  49. package/dist/domain/fund.d.ts +2452 -0
  50. package/dist/domain/fund.js +1756 -0
  51. package/dist/domain/fundValidation.d.ts +152 -0
  52. package/dist/domain/fundValidation.js +767 -0
  53. package/dist/domain/policies.d.ts +1064 -0
  54. package/dist/domain/policies.js +1625 -0
  55. package/dist/domain/receivable.d.ts +824 -0
  56. package/dist/domain/receivable.js +1375 -0
  57. package/dist/domain/receivableValidation.d.ts +147 -0
  58. package/dist/domain/receivableValidation.js +831 -0
  59. package/dist/index.d.ts +8 -2
  60. package/dist/index.js +137 -21
  61. package/package.json +20 -2
@@ -0,0 +1,1756 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.define = define;
7
+ exports.verify = verify;
8
+ exports.load = load;
9
+ exports.prepareCapitalCall = prepareCapitalCall;
10
+ exports.verifyCapitalCall = verifyCapitalCall;
11
+ exports.signPositionReceipt = signPositionReceipt;
12
+ exports.verifyPositionReceipt = verifyPositionReceipt;
13
+ exports.verifyPositionReceiptChain = verifyPositionReceiptChain;
14
+ exports.inspectCapitalCallClaim = inspectCapitalCallClaim;
15
+ exports.executeCapitalCallClaim = executeCapitalCallClaim;
16
+ exports.inspectCapitalCallRollover = inspectCapitalCallRollover;
17
+ exports.executeCapitalCallRollover = executeCapitalCallRollover;
18
+ exports.inspectCapitalCallRefund = inspectCapitalCallRefund;
19
+ exports.executeCapitalCallRefund = executeCapitalCallRefund;
20
+ exports.prepareDistribution = prepareDistribution;
21
+ exports.reconcilePosition = reconcilePosition;
22
+ exports.verifyDistribution = verifyDistribution;
23
+ exports.inspectDistributionClaim = inspectDistributionClaim;
24
+ exports.executeDistributionClaim = executeDistributionClaim;
25
+ exports.prepareClosing = prepareClosing;
26
+ exports.verifyClosing = verifyClosing;
27
+ exports.exportEvidence = exportEvidence;
28
+ exports.exportFinalityPayload = exportFinalityPayload;
29
+ const node_fs_1 = require("node:fs");
30
+ const promises_1 = require("node:fs/promises");
31
+ const node_path_1 = __importDefault(require("node:path"));
32
+ const errors_1 = require("../core/errors");
33
+ const summary_1 = require("../core/summary");
34
+ const outputBinding_1 = require("../core/outputBinding");
35
+ const reporting_1 = require("../core/reporting");
36
+ const fundValidation_1 = require("./fundValidation");
37
+ const FUND_VERIFICATION_REPORT_SCHEMA_VERSION = "fund-verification-report/v1";
38
+ const FUND_EVIDENCE_BUNDLE_SCHEMA_VERSION = "fund-evidence-bundle/v1";
39
+ const FUND_FINALITY_PAYLOAD_SCHEMA_VERSION = "fund-finality-payload/v1";
40
+ function resolveValueOrPath(options) {
41
+ if (options.pathValue)
42
+ return { jsonPath: options.pathValue };
43
+ if (options.objectValue !== undefined)
44
+ return { value: options.objectValue };
45
+ return {};
46
+ }
47
+ function resolveFundDocsAsset(filename) {
48
+ const cwdCandidate = node_path_1.default.resolve(process.cwd(), "docs/definitions", filename);
49
+ if ((0, node_fs_1.existsSync)(cwdCandidate))
50
+ return cwdCandidate;
51
+ const bundledCandidate = node_path_1.default.resolve(__dirname, "../docs/definitions", filename);
52
+ if ((0, node_fs_1.existsSync)(bundledCandidate))
53
+ return bundledCandidate;
54
+ return cwdCandidate;
55
+ }
56
+ function satToBtcAmount(sat) {
57
+ return Number((sat / 1e8).toFixed(8));
58
+ }
59
+ function nowIso() {
60
+ return new Date().toISOString();
61
+ }
62
+ function defaultPositionId(capitalCall) {
63
+ return `${capitalCall.fundId}:${capitalCall.lpId}:${capitalCall.callId}`;
64
+ }
65
+ function assertOpenCapitalCall(state) {
66
+ if (state.status !== "OPEN") {
67
+ throw new errors_1.ValidationError("Capital call must be OPEN for claim or rollover execution", {
68
+ code: "FUND_CAPITAL_CALL_NOT_OPEN",
69
+ });
70
+ }
71
+ }
72
+ function assertRefundOnlyCapitalCall(state) {
73
+ if (state.status !== "REFUND_ONLY") {
74
+ throw new errors_1.ValidationError("Capital call must be REFUND_ONLY for refund execution", {
75
+ code: "FUND_CAPITAL_CALL_NOT_REFUND_ONLY",
76
+ });
77
+ }
78
+ }
79
+ function deriveCapitalCallStage(state) {
80
+ if (state.status === "CLAIMED")
81
+ return "claimed";
82
+ if (state.status === "REFUND_ONLY")
83
+ return "refund-only";
84
+ if (state.status === "REFUNDED")
85
+ return "refunded";
86
+ return "open";
87
+ }
88
+ function summarizeFundPayoutDescriptor(descriptor) {
89
+ const canonicalJson = (0, summary_1.stableStringify)({
90
+ receiverAddress: descriptor.receiverAddress,
91
+ nextOutputHash: descriptor.nextOutputHash ?? null,
92
+ nextOutputScriptHash: descriptor.nextOutputScriptHash ?? null,
93
+ amountSat: descriptor.amountSat,
94
+ assetId: descriptor.assetId,
95
+ requestedOutputBindingMode: descriptor.requestedOutputBindingMode ?? descriptor.outputBindingMode,
96
+ outputForm: (0, outputBinding_1.normalizeOutputForm)(descriptor.outputForm),
97
+ rawOutput: (0, outputBinding_1.normalizeOutputRawFields)(descriptor.rawOutput) ?? null,
98
+ feeIndex: descriptor.feeIndex,
99
+ nextOutputIndex: descriptor.nextOutputIndex,
100
+ maxFeeSat: descriptor.maxFeeSat,
101
+ outputBindingMode: descriptor.outputBindingMode,
102
+ });
103
+ return { canonicalJson, hash: (0, summary_1.sha256HexUtf8)(canonicalJson) };
104
+ }
105
+ function validateFundPayoutDescriptor(descriptor) {
106
+ if (!descriptor.receiverAddress || descriptor.receiverAddress.trim().length === 0) {
107
+ throw new errors_1.ValidationError("receiverAddress must be a non-empty string", {
108
+ code: "FUND_PAYOUT_RECEIVER_REQUIRED",
109
+ });
110
+ }
111
+ if (!Number.isInteger(descriptor.amountSat) || descriptor.amountSat <= 0) {
112
+ throw new errors_1.ValidationError("amountSat must be a positive integer", {
113
+ code: "FUND_PAYOUT_AMOUNT_INVALID",
114
+ });
115
+ }
116
+ if (!descriptor.assetId || descriptor.assetId.trim().length === 0) {
117
+ throw new errors_1.ValidationError("assetId must be a non-empty string", {
118
+ code: "FUND_PAYOUT_ASSET_REQUIRED",
119
+ });
120
+ }
121
+ if (!Number.isInteger(descriptor.feeIndex) || descriptor.feeIndex < 0) {
122
+ throw new errors_1.ValidationError("feeIndex must be a non-negative integer", {
123
+ code: "FUND_PAYOUT_FEE_INDEX_INVALID",
124
+ });
125
+ }
126
+ if (!Number.isInteger(descriptor.nextOutputIndex) || descriptor.nextOutputIndex < 0) {
127
+ throw new errors_1.ValidationError("nextOutputIndex must be a non-negative integer", {
128
+ code: "FUND_PAYOUT_NEXT_OUTPUT_INDEX_INVALID",
129
+ });
130
+ }
131
+ if (!Number.isInteger(descriptor.maxFeeSat) || descriptor.maxFeeSat < 0) {
132
+ throw new errors_1.ValidationError("maxFeeSat must be a non-negative integer", {
133
+ code: "FUND_PAYOUT_MAX_FEE_INVALID",
134
+ });
135
+ }
136
+ if (!["none", "script-bound", "descriptor-bound"].includes(descriptor.outputBindingMode)) {
137
+ throw new errors_1.ValidationError("outputBindingMode must be none, script-bound, or descriptor-bound", {
138
+ code: "FUND_PAYOUT_BINDING_MODE_INVALID",
139
+ });
140
+ }
141
+ if (descriptor.requestedOutputBindingMode
142
+ && !["none", "script-bound", "descriptor-bound"].includes(descriptor.requestedOutputBindingMode)) {
143
+ throw new errors_1.ValidationError("requestedOutputBindingMode must be none, script-bound, or descriptor-bound", {
144
+ code: "FUND_PAYOUT_REQUESTED_BINDING_MODE_INVALID",
145
+ });
146
+ }
147
+ if (descriptor.nextOutputHash && !/^[0-9a-f]{64}$/i.test(descriptor.nextOutputHash)) {
148
+ throw new errors_1.ValidationError("nextOutputHash must be a 64-character hex string", {
149
+ code: "FUND_PAYOUT_OUTPUT_HASH_INVALID",
150
+ });
151
+ }
152
+ if (descriptor.nextOutputScriptHash && !/^[0-9a-f]{64}$/i.test(descriptor.nextOutputScriptHash)) {
153
+ throw new errors_1.ValidationError("nextOutputScriptHash must be a 64-character hex string", {
154
+ code: "FUND_PAYOUT_OUTPUT_SCRIPT_HASH_INVALID",
155
+ });
156
+ }
157
+ descriptor.rawOutput = (0, outputBinding_1.normalizeOutputRawFields)(descriptor.rawOutput);
158
+ descriptor.outputForm = (0, outputBinding_1.normalizeOutputForm)(descriptor.outputForm);
159
+ descriptor.requestedOutputBindingMode = descriptor.requestedOutputBindingMode ?? descriptor.outputBindingMode;
160
+ return descriptor;
161
+ }
162
+ function buildFundOutputBindingReport(input) {
163
+ if (!input.descriptor)
164
+ return undefined;
165
+ const runtimeBound = input.descriptor.outputBindingMode !== "none";
166
+ return {
167
+ mode: input.descriptor.outputBindingMode,
168
+ requestedMode: input.descriptor.requestedOutputBindingMode,
169
+ supportedForm: input.supportedForm ?? "unsupported",
170
+ nextReceiverRuntimeCommitted: runtimeBound,
171
+ outputCountRuntimeBound: runtimeBound,
172
+ feeIndexRuntimeBound: runtimeBound,
173
+ nextOutputHashRuntimeBound: input.descriptor.outputBindingMode === "descriptor-bound",
174
+ nextOutputScriptRuntimeBound: input.descriptor.outputBindingMode === "script-bound",
175
+ amountRuntimeBound: input.descriptor.outputBindingMode === "descriptor-bound",
176
+ reasonCode: input.reasonCode
177
+ ?? (input.descriptor.outputBindingMode === "descriptor-bound"
178
+ ? "OK_MANUAL_HASH"
179
+ : input.descriptor.outputBindingMode === "script-bound"
180
+ ? "OK_SCRIPT_BOUND"
181
+ : "OK_NONE"),
182
+ autoDerived: input.autoDerived,
183
+ fallbackReason: input.fallbackReason,
184
+ bindingInputs: input.bindingInputs
185
+ ?? {
186
+ assetId: input.descriptor.assetId,
187
+ assetForm: input.descriptor.outputForm?.assetForm ?? "explicit",
188
+ amountForm: input.descriptor.outputForm?.amountForm ?? "explicit",
189
+ nonceForm: input.descriptor.outputForm?.nonceForm ?? "null",
190
+ rangeProofForm: input.descriptor.outputForm?.rangeProofForm ?? "empty",
191
+ nextAmountSat: input.descriptor.amountSat,
192
+ nextOutputIndex: input.descriptor.nextOutputIndex,
193
+ feeIndex: input.descriptor.feeIndex,
194
+ maxFeeSat: input.descriptor.maxFeeSat,
195
+ },
196
+ };
197
+ }
198
+ async function buildFundPayoutDescriptor(sdk, input) {
199
+ const nextScriptPubKeyHex = await (0, outputBinding_1.getScriptPubKeyHexViaRpc)(sdk, input.receiverAddress);
200
+ const nextOutputScriptHash = (0, outputBinding_1.hashHexBytes)(nextScriptPubKeyHex);
201
+ const requestedBindingMode = input.outputBindingMode ?? "descriptor-bound";
202
+ const outputForm = (0, outputBinding_1.normalizeOutputForm)(input.outputForm);
203
+ const rawOutput = (0, outputBinding_1.normalizeOutputRawFields)(input.rawOutput);
204
+ const rawOutputAnalysis = (0, outputBinding_1.analyzeOutputRawFields)(rawOutput);
205
+ const explicitAssetHex = requestedBindingMode !== "none" && (0, outputBinding_1.isExplicitV1OutputForm)(outputForm)
206
+ ? await (0, outputBinding_1.resolveExplicitAssetHex)(sdk, input.assetId)
207
+ : undefined;
208
+ const autoDerivedNextOutputHash = requestedBindingMode === "descriptor-bound" && !input.nextOutputHash
209
+ ? rawOutputAnalysis.valid && rawOutputAnalysis.normalized
210
+ ? (0, outputBinding_1.computeRawOutputV1Hash)(rawOutputAnalysis.normalized)
211
+ : explicitAssetHex
212
+ ? (0, outputBinding_1.computeExplicitV1OutputHash)({
213
+ assetHex: explicitAssetHex,
214
+ nextAmountSat: input.amountSat,
215
+ nextOutputScriptHash,
216
+ })
217
+ : undefined
218
+ : undefined;
219
+ const nextOutputHash = input.nextOutputHash ?? autoDerivedNextOutputHash;
220
+ const bindingResolution = (0, outputBinding_1.resolveOutputBindingDecision)({
221
+ requestedBindingMode,
222
+ nextOutputHash,
223
+ nextOutputScriptHash,
224
+ autoDerivedNextOutputHash: Boolean(autoDerivedNextOutputHash && !input.nextOutputHash),
225
+ explicitAssetSupported: Boolean(explicitAssetHex),
226
+ outputForm,
227
+ rawOutput,
228
+ });
229
+ const descriptor = validateFundPayoutDescriptor({
230
+ receiverAddress: input.receiverAddress,
231
+ nextOutputHash: bindingResolution.outputBindingMode === "descriptor-bound" ? nextOutputHash : undefined,
232
+ nextOutputScriptHash: bindingResolution.outputBindingMode !== "none" ? nextOutputScriptHash : undefined,
233
+ amountSat: input.amountSat,
234
+ assetId: input.assetId,
235
+ requestedOutputBindingMode: requestedBindingMode,
236
+ outputForm,
237
+ rawOutput,
238
+ feeIndex: input.feeIndex ?? 1,
239
+ nextOutputIndex: input.nextOutputIndex ?? 0,
240
+ maxFeeSat: input.maxFeeSat ?? 100,
241
+ outputBindingMode: bindingResolution.outputBindingMode,
242
+ });
243
+ const bindingInputs = {
244
+ assetId: descriptor.assetId,
245
+ assetForm: descriptor.outputForm?.assetForm ?? "explicit",
246
+ amountForm: descriptor.outputForm?.amountForm ?? "explicit",
247
+ nonceForm: descriptor.outputForm?.nonceForm ?? "null",
248
+ rangeProofForm: descriptor.outputForm?.rangeProofForm ?? "empty",
249
+ nextAmountSat: descriptor.amountSat,
250
+ nextOutputIndex: descriptor.nextOutputIndex,
251
+ feeIndex: descriptor.feeIndex,
252
+ maxFeeSat: descriptor.maxFeeSat,
253
+ ...(rawOutputAnalysis.valid && rawOutputAnalysis.normalized
254
+ ? {
255
+ rawOutputComponents: {
256
+ scriptPubKey: rawOutputAnalysis.normalized.scriptComponentSource,
257
+ rangeProof: rawOutputAnalysis.normalized.rangeProofComponentSource,
258
+ },
259
+ }
260
+ : {}),
261
+ };
262
+ return {
263
+ descriptor,
264
+ summary: summarizeFundPayoutDescriptor(descriptor),
265
+ supportedForm: bindingResolution.supportedForm,
266
+ autoDerivedNextOutputHash: bindingResolution.autoDerived,
267
+ reasonCode: bindingResolution.reasonCode,
268
+ fallbackReason: bindingResolution.fallbackReason,
269
+ bindingInputs,
270
+ };
271
+ }
272
+ function buildBindingModeWitnessValue(mode) {
273
+ return mode === "descriptor-bound" ? "0x01" : mode === "script-bound" ? "0x02" : "0x03";
274
+ }
275
+ function buildClaimWitness(descriptor) {
276
+ return {
277
+ values: {
278
+ ACTION_8: { type: "u8", value: "0x01" },
279
+ EXPECTED_PAYOUT_OUTPUT_HASH: {
280
+ type: "u256",
281
+ value: `0x${descriptor.nextOutputHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
282
+ },
283
+ EXPECTED_PAYOUT_OUTPUT_SCRIPT_HASH: {
284
+ type: "u256",
285
+ value: `0x${descriptor.nextOutputScriptHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
286
+ },
287
+ OUTPUT_BINDING_MODE: {
288
+ type: "u8",
289
+ value: buildBindingModeWitnessValue(descriptor.outputBindingMode),
290
+ },
291
+ },
292
+ };
293
+ }
294
+ function buildRolloverWitness() {
295
+ return {
296
+ values: {
297
+ ACTION_8: { type: "u8", value: "0x02" },
298
+ EXPECTED_PAYOUT_OUTPUT_HASH: {
299
+ type: "u256",
300
+ value: "0x0000000000000000000000000000000000000000000000000000000000000000",
301
+ },
302
+ EXPECTED_PAYOUT_OUTPUT_SCRIPT_HASH: {
303
+ type: "u256",
304
+ value: "0x0000000000000000000000000000000000000000000000000000000000000000",
305
+ },
306
+ OUTPUT_BINDING_MODE: { type: "u8", value: "0x00" },
307
+ },
308
+ };
309
+ }
310
+ function buildRefundWitness(descriptor) {
311
+ return {
312
+ values: {
313
+ EXPECTED_PAYOUT_OUTPUT_HASH: {
314
+ type: "u256",
315
+ value: `0x${descriptor.nextOutputHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
316
+ },
317
+ EXPECTED_PAYOUT_OUTPUT_SCRIPT_HASH: {
318
+ type: "u256",
319
+ value: `0x${descriptor.nextOutputScriptHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
320
+ },
321
+ OUTPUT_BINDING_MODE: {
322
+ type: "u8",
323
+ value: buildBindingModeWitnessValue(descriptor.outputBindingMode),
324
+ },
325
+ },
326
+ };
327
+ }
328
+ function buildDistributionWitness(descriptor) {
329
+ return {
330
+ values: {
331
+ EXPECTED_PAYOUT_OUTPUT_HASH: {
332
+ type: "u256",
333
+ value: `0x${descriptor.nextOutputHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
334
+ },
335
+ EXPECTED_PAYOUT_OUTPUT_SCRIPT_HASH: {
336
+ type: "u256",
337
+ value: `0x${descriptor.nextOutputScriptHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
338
+ },
339
+ OUTPUT_BINDING_MODE: {
340
+ type: "u8",
341
+ value: buildBindingModeWitnessValue(descriptor.outputBindingMode),
342
+ },
343
+ },
344
+ };
345
+ }
346
+ async function loadFundDefinitionDocument(sdk, input) {
347
+ const source = resolveValueOrPath({ pathValue: input.definitionPath, objectValue: input.definitionValue });
348
+ const initial = await sdk.loadDefinition({
349
+ type: "fund-definition",
350
+ id: input.definitionValue?.fundId ?? "FUND-001",
351
+ ...source,
352
+ });
353
+ const value = (0, fundValidation_1.validateFundDefinition)(JSON.parse(initial.canonicalJson));
354
+ const descriptor = await sdk.loadDefinition({
355
+ type: "fund-definition",
356
+ id: value.fundId,
357
+ ...(source.jsonPath ? { jsonPath: source.jsonPath } : { value }),
358
+ });
359
+ return { descriptor, value, summary: (0, fundValidation_1.summarizeFundDefinition)(value) };
360
+ }
361
+ async function loadCapitalCallDocument(sdk, input) {
362
+ const source = resolveValueOrPath({ pathValue: input.capitalCallPath, objectValue: input.capitalCallValue });
363
+ const initial = await sdk.loadStateDocument({
364
+ type: "fund-capital-call",
365
+ id: input.capitalCallValue?.callId ?? "CALL-001",
366
+ ...source,
367
+ });
368
+ const value = (0, fundValidation_1.validateCapitalCallState)(JSON.parse(initial.canonicalJson));
369
+ const descriptor = await sdk.loadStateDocument({
370
+ type: "fund-capital-call",
371
+ id: value.callId,
372
+ ...(source.jsonPath ? { jsonPath: source.jsonPath } : { value }),
373
+ });
374
+ return { descriptor, value, summary: (0, fundValidation_1.summarizeCapitalCallState)(value) };
375
+ }
376
+ async function loadBarePositionReceiptDocument(sdk, input) {
377
+ const source = resolveValueOrPath({ pathValue: input.positionReceiptPath, objectValue: input.positionReceiptValue });
378
+ const initial = await sdk.loadStateDocument({
379
+ type: "fund-position-receipt",
380
+ id: input.positionReceiptValue?.positionId ?? "POSITION-001",
381
+ ...source,
382
+ });
383
+ const value = (0, fundValidation_1.validateLPPositionReceipt)(JSON.parse(initial.canonicalJson));
384
+ const descriptor = await sdk.loadStateDocument({
385
+ type: "fund-position-receipt",
386
+ id: value.positionId,
387
+ ...(source.jsonPath ? { jsonPath: source.jsonPath } : { value }),
388
+ });
389
+ return { descriptor, value, summary: (0, fundValidation_1.summarizeLPPositionReceipt)(value) };
390
+ }
391
+ async function loadPositionReceiptEnvelopeDocument(sdk, input) {
392
+ const source = resolveValueOrPath({ pathValue: input.positionReceiptPath, objectValue: input.positionReceiptValue });
393
+ const initial = await sdk.loadStateDocument({
394
+ type: "fund-position-receipt-envelope",
395
+ id: input.positionReceiptValue?.receipt.positionId ?? "POSITION-001",
396
+ ...source,
397
+ });
398
+ const value = (0, fundValidation_1.validateLPPositionReceiptEnvelope)(JSON.parse(initial.canonicalJson));
399
+ const descriptor = await sdk.loadStateDocument({
400
+ type: "fund-position-receipt-envelope",
401
+ id: value.receipt.positionId,
402
+ ...(source.jsonPath ? { jsonPath: source.jsonPath } : { value }),
403
+ });
404
+ return {
405
+ descriptor,
406
+ value,
407
+ receiptSummary: (0, fundValidation_1.summarizeLPPositionReceipt)(value.receipt),
408
+ envelopeSummary: (0, fundValidation_1.summarizeLPPositionReceiptEnvelope)(value),
409
+ };
410
+ }
411
+ async function loadPositionReceiptEnvelopeChainDocuments(sdk, input) {
412
+ const combinedPaths = [...(input.positionReceiptChainPaths ?? [])];
413
+ const combinedValues = [...(input.positionReceiptChainValues ?? [])];
414
+ const results = [];
415
+ for (const positionReceiptPath of combinedPaths) {
416
+ results.push(await loadPositionReceiptEnvelopeDocument(sdk, { positionReceiptPath }));
417
+ }
418
+ for (const positionReceiptValue of combinedValues) {
419
+ results.push(await loadPositionReceiptEnvelopeDocument(sdk, { positionReceiptValue }));
420
+ }
421
+ return results;
422
+ }
423
+ async function loadDistributionDocument(sdk, input) {
424
+ const source = resolveValueOrPath({ pathValue: input.distributionPath, objectValue: input.distributionValue });
425
+ let value;
426
+ if (source.jsonPath || source.value) {
427
+ const initial = await sdk.loadStateDocument({
428
+ type: "fund-distribution",
429
+ id: input.distributionValue?.distributionId ?? input.distributionId ?? "DIST-001",
430
+ ...source,
431
+ });
432
+ value = (0, fundValidation_1.validateDistributionDescriptor)(JSON.parse(initial.canonicalJson));
433
+ }
434
+ else {
435
+ if (!input.positionReceipt || !input.distributionId || !input.assetId || input.amountSat === undefined || !input.approvedAt) {
436
+ throw new errors_1.ValidationError("distributionPath/distributionValue or positionReceipt + distributionId + assetId + amountSat + approvedAt is required", { code: "FUND_DISTRIBUTION_INPUT_REQUIRED" });
437
+ }
438
+ value = (0, fundValidation_1.buildDistributionDescriptor)({
439
+ distributionId: input.distributionId,
440
+ receipt: input.positionReceipt,
441
+ assetId: input.assetId,
442
+ amountSat: input.amountSat,
443
+ approvedAt: input.approvedAt,
444
+ });
445
+ }
446
+ const descriptor = await sdk.loadStateDocument({
447
+ type: "fund-distribution",
448
+ id: value.distributionId,
449
+ ...(source.jsonPath ? { jsonPath: source.jsonPath } : { value }),
450
+ });
451
+ return { descriptor, value, summary: (0, fundValidation_1.summarizeDistributionDescriptor)(value) };
452
+ }
453
+ async function loadDistributionDocuments(sdk, input) {
454
+ const combinedPaths = [...(input.distributionPaths ?? []), ...(input.distributionPath ? [input.distributionPath] : [])];
455
+ const combinedValues = [...(input.distributionValues ?? []), ...(input.distributionValue ? [input.distributionValue] : [])];
456
+ const results = [];
457
+ for (const distributionPath of combinedPaths)
458
+ results.push(await loadDistributionDocument(sdk, { distributionPath }));
459
+ for (const distributionValue of combinedValues)
460
+ results.push(await loadDistributionDocument(sdk, { distributionValue }));
461
+ return results;
462
+ }
463
+ async function loadClosingDocument(sdk, input) {
464
+ const source = resolveValueOrPath({ pathValue: input.closingPath, objectValue: input.closingValue });
465
+ let value;
466
+ if (source.jsonPath || source.value) {
467
+ const initial = await sdk.loadStateDocument({
468
+ type: "fund-closing",
469
+ id: input.closingValue?.closingId ?? input.closingId ?? "CLOSE-001",
470
+ ...source,
471
+ });
472
+ value = (0, fundValidation_1.validateFundClosingDescriptor)(JSON.parse(initial.canonicalJson));
473
+ }
474
+ else {
475
+ if (!input.positionReceipt || !input.closingId || !input.finalDistributionHashes || !input.closedAt) {
476
+ throw new errors_1.ValidationError("closingPath/closingValue or positionReceipt + closingId + finalDistributionHashes + closedAt is required", { code: "FUND_CLOSING_INPUT_REQUIRED" });
477
+ }
478
+ value = (0, fundValidation_1.buildFundClosingDescriptor)({
479
+ receipt: input.positionReceipt,
480
+ closingId: input.closingId,
481
+ finalDistributionHashes: input.finalDistributionHashes,
482
+ closedAt: input.closedAt,
483
+ closingReason: input.closingReason,
484
+ });
485
+ }
486
+ const descriptor = await sdk.loadStateDocument({
487
+ type: "fund-closing",
488
+ id: value.closingId,
489
+ ...(source.jsonPath ? { jsonPath: source.jsonPath } : { value }),
490
+ });
491
+ return { descriptor, value, summary: (0, fundValidation_1.summarizeFundClosingDescriptor)(value) };
492
+ }
493
+ function buildEmptyFundDefinitionTrust() {
494
+ return {
495
+ artifactMatch: false,
496
+ onChainAnchorPresent: false,
497
+ onChainAnchorVerified: false,
498
+ effectiveMode: "none",
499
+ };
500
+ }
501
+ function buildEmptyFundStateTrust() {
502
+ return {
503
+ artifactMatch: false,
504
+ onChainAnchorPresent: false,
505
+ onChainAnchorVerified: false,
506
+ effectiveMode: "none",
507
+ };
508
+ }
509
+ function buildBaseFundReport(input) {
510
+ return {
511
+ schemaVersion: FUND_VERIFICATION_REPORT_SCHEMA_VERSION,
512
+ ...(0, reporting_1.buildVerificationTrustSections)({
513
+ definitionTrust: input?.definitionTrust,
514
+ stateTrust: input?.stateTrust,
515
+ requireArtifactTrust: input?.requireArtifactTrust,
516
+ emptyDefinitionTrust: buildEmptyFundDefinitionTrust(),
517
+ emptyStateTrust: buildEmptyFundStateTrust(),
518
+ }),
519
+ };
520
+ }
521
+ async function compileOpenCapitalCallContract(sdk, input) {
522
+ return sdk.compileFromFile({
523
+ simfPath: input.simfPath ?? resolveFundDocsAsset("fund-capital-call-open.simf"),
524
+ templateVars: {
525
+ MANAGER_XONLY: input.definition.managerXonly,
526
+ LP_XONLY: input.capitalCall.lpXonly,
527
+ CLAIM_CUTOFF_HEIGHT: input.capitalCall.claimCutoffHeight,
528
+ REFUND_ONLY_SCRIPT_HASH: input.refundOnlyScriptHash,
529
+ CAPITAL_CALL_STAGE: "OPEN",
530
+ },
531
+ definition: {
532
+ type: "fund-definition",
533
+ id: input.definition.fundId,
534
+ value: input.definition,
535
+ anchorMode: "on-chain-constant-committed",
536
+ },
537
+ state: {
538
+ type: "fund-capital-call",
539
+ id: input.capitalCall.callId,
540
+ value: input.capitalCall,
541
+ anchorMode: "on-chain-constant-committed",
542
+ },
543
+ artifactPath: input.artifactPath,
544
+ });
545
+ }
546
+ async function compileRefundOnlyCapitalCallContract(sdk, input) {
547
+ return sdk.compileFromFile({
548
+ simfPath: input.simfPath ?? resolveFundDocsAsset("fund-capital-call-refund-only.simf"),
549
+ templateVars: {
550
+ LP_XONLY: input.capitalCall.lpXonly,
551
+ CAPITAL_CALL_STAGE: "REFUND_ONLY",
552
+ },
553
+ definition: {
554
+ type: "fund-definition",
555
+ id: input.definition.fundId,
556
+ value: input.definition,
557
+ anchorMode: "on-chain-constant-committed",
558
+ },
559
+ state: {
560
+ type: "fund-capital-call",
561
+ id: input.capitalCall.callId,
562
+ value: input.capitalCall,
563
+ anchorMode: "on-chain-constant-committed",
564
+ },
565
+ artifactPath: input.artifactPath,
566
+ });
567
+ }
568
+ async function compileDistributionClaimContract(sdk, input) {
569
+ return sdk.compileFromFile({
570
+ simfPath: input.simfPath ?? resolveFundDocsAsset("fund-distribution-claim.simf"),
571
+ templateVars: {
572
+ LP_XONLY: input.receipt.lpXonly,
573
+ },
574
+ definition: {
575
+ type: "fund-definition",
576
+ id: input.definition.fundId,
577
+ value: input.definition,
578
+ anchorMode: "on-chain-constant-committed",
579
+ },
580
+ state: {
581
+ type: "fund-distribution",
582
+ id: input.distribution.distributionId,
583
+ value: input.distribution,
584
+ anchorMode: "on-chain-constant-committed",
585
+ },
586
+ artifactPath: input.artifactPath,
587
+ });
588
+ }
589
+ async function requireFundArtifact(sdk, input) {
590
+ const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
591
+ if (!artifact) {
592
+ throw new errors_1.ValidationError("artifactPath or artifact is required", { code: "FUND_ARTIFACT_REQUIRED" });
593
+ }
594
+ return artifact;
595
+ }
596
+ async function requireRefundOnlyArtifact(sdk, input) {
597
+ const artifact = input.refundOnlyArtifact
598
+ ?? (input.refundOnlyArtifactPath ? (await sdk.loadArtifact(input.refundOnlyArtifactPath)).artifact : undefined);
599
+ if (!artifact) {
600
+ throw new errors_1.ValidationError("refundOnlyArtifactPath or refundOnlyArtifact is required", {
601
+ code: "FUND_REFUND_ONLY_ARTIFACT_REQUIRED",
602
+ });
603
+ }
604
+ return artifact;
605
+ }
606
+ async function ensureVerifiedEnvelope(definition, envelope) {
607
+ const checks = await (0, fundValidation_1.verifyLPPositionReceiptEnvelope)({
608
+ envelope,
609
+ expectedManagerXonly: definition.managerXonly,
610
+ });
611
+ if (!checks.positionReceiptHashMatch
612
+ || !checks.sequenceMatch
613
+ || !checks.sequenceMonotonic
614
+ || !checks.attestingSignerMatch
615
+ || !checks.attestationVerified) {
616
+ throw new errors_1.ValidationError("Position receipt envelope must be attested and internally consistent", {
617
+ code: "FUND_POSITION_ENVELOPE_VERIFY_FAILED",
618
+ checks,
619
+ });
620
+ }
621
+ return checks;
622
+ }
623
+ async function ensureVerifiedEnvelopeContinuity(definition, envelope, previousEnvelope) {
624
+ const checks = await (0, fundValidation_1.verifyLPPositionReceiptEnvelope)({
625
+ envelope,
626
+ expectedManagerXonly: definition.managerXonly,
627
+ previousEnvelope,
628
+ });
629
+ if (!checks.positionReceiptHashMatch
630
+ || !checks.sequenceMatch
631
+ || !checks.sequenceMonotonic
632
+ || !checks.attestingSignerMatch
633
+ || !checks.attestationVerified) {
634
+ throw new errors_1.ValidationError("Position receipt envelope must be attested and internally consistent", {
635
+ code: "FUND_POSITION_ENVELOPE_VERIFY_FAILED",
636
+ checks,
637
+ });
638
+ }
639
+ if (envelope.receipt.sequence > 0) {
640
+ if (!previousEnvelope) {
641
+ throw new errors_1.ValidationError("sequence>0 receipts require the immediate previous receipt envelope", {
642
+ code: "FUND_PREVIOUS_POSITION_ENVELOPE_REQUIRED",
643
+ checks,
644
+ });
645
+ }
646
+ if (!checks.continuityVerified) {
647
+ throw new errors_1.ValidationError("Position receipt envelope continuity must match the immediate previous envelope", {
648
+ code: "FUND_POSITION_ENVELOPE_CONTINUITY_VERIFY_FAILED",
649
+ checks,
650
+ });
651
+ }
652
+ }
653
+ return checks;
654
+ }
655
+ function buildReceiptTrust(input) {
656
+ return {
657
+ generated: input.generated,
658
+ positionReceiptHash: (0, fundValidation_1.summarizeLPPositionReceipt)(input.envelope.receipt).hash,
659
+ positionStatus: input.envelope.receipt.status,
660
+ attested: true,
661
+ attestationVerified: input.checks.attestationVerified,
662
+ sequence: input.envelope.receipt.sequence,
663
+ sequenceMonotonic: input.checks.sequenceMonotonic && input.checks.sequenceMatch,
664
+ attestingSignerMatch: input.checks.attestingSignerMatch,
665
+ previousEnvelopeProvided: input.checks.previousEnvelopeProvided,
666
+ previousReceiptHashMatch: input.checks.previousReceiptHashMatch,
667
+ previousSequenceMatch: input.checks.previousSequenceMatch,
668
+ continuityVerified: input.checks.continuityVerified,
669
+ };
670
+ }
671
+ function buildReceiptChainTrust(input) {
672
+ const identityConsistent = input.fundConsistent
673
+ && input.positionConsistent
674
+ && input.lpConsistent
675
+ && input.callConsistent
676
+ && input.currencyConsistent
677
+ && input.lpXonlyConsistent
678
+ && input.attestingSignerConsistent;
679
+ return {
680
+ ...(0, reporting_1.buildLineageTrustBase)({
681
+ lineageKind: "receipt-chain",
682
+ chainLength: input.chainLength,
683
+ latestOrdinal: input.latestSequence ?? Math.max(0, input.chainLength - 1),
684
+ allHashLinksVerified: input.allContinuityVerified && input.allPositionReceiptHashMatch,
685
+ identityConsistent,
686
+ fullLineageVerified: input.fullChainVerified,
687
+ }),
688
+ latestSequence: input.latestSequence,
689
+ startsAtGenesis: input.startsAtGenesis,
690
+ latestSequenceCovered: input.latestSequenceCovered,
691
+ sequenceContiguous: input.sequenceContiguous,
692
+ fundConsistent: input.fundConsistent,
693
+ positionConsistent: input.positionConsistent,
694
+ lpConsistent: input.lpConsistent,
695
+ callConsistent: input.callConsistent,
696
+ currencyConsistent: input.currencyConsistent,
697
+ lpXonlyConsistent: input.lpXonlyConsistent,
698
+ attestingSignerConsistent: input.attestingSignerConsistent,
699
+ allPositionReceiptHashMatch: input.allPositionReceiptHashMatch,
700
+ allSequenceMatch: input.allSequenceMatch,
701
+ allSequenceMonotonic: input.allSequenceMonotonic,
702
+ allAttestingSignerMatch: input.allAttestingSignerMatch,
703
+ allAttestationVerified: input.allAttestationVerified,
704
+ allContinuityVerified: input.allContinuityVerified,
705
+ fullChainVerified: input.fullChainVerified,
706
+ };
707
+ }
708
+ function resolveReceiptChainContext(input) {
709
+ const chainEntries = input.chainEntries && input.chainEntries.length > 0
710
+ ? input.chainEntries
711
+ : input.receipt
712
+ ? [
713
+ ...(input.previousEnvelope ? [input.previousEnvelope] : []),
714
+ input.receipt,
715
+ ]
716
+ : [];
717
+ const receipt = input.receipt ?? chainEntries.at(-1);
718
+ if (!receipt) {
719
+ throw new errors_1.ValidationError("position receipt envelope is required", {
720
+ code: "FUND_POSITION_RECEIPT_REQUIRED",
721
+ });
722
+ }
723
+ const latestChainEntry = chainEntries.at(-1);
724
+ if (latestChainEntry && latestChainEntry.envelopeSummary.hash !== receipt.envelopeSummary.hash) {
725
+ throw new errors_1.ValidationError("position receipt chain must end with the provided latest envelope", {
726
+ code: "FUND_POSITION_CHAIN_LATEST_MISMATCH",
727
+ latestEnvelopeHash: receipt.envelopeSummary.hash,
728
+ chainLatestEnvelopeHash: latestChainEntry.envelopeSummary.hash,
729
+ });
730
+ }
731
+ const previousEnvelope = chainEntries.length > 1
732
+ ? chainEntries[chainEntries.length - 2]
733
+ : input.previousEnvelope;
734
+ return {
735
+ receipt,
736
+ previousEnvelope,
737
+ chainEntries,
738
+ };
739
+ }
740
+ async function define(sdk, input) {
741
+ const definition = await loadFundDefinitionDocument(sdk, input);
742
+ return {
743
+ ok: true,
744
+ definition: definition.descriptor,
745
+ definitionValue: definition.value,
746
+ summary: definition.summary,
747
+ };
748
+ }
749
+ async function verify(sdk, input) {
750
+ return define(sdk, input);
751
+ }
752
+ async function load(sdk, input) {
753
+ const result = await define(sdk, input);
754
+ return {
755
+ definition: result.definition,
756
+ definitionValue: result.definitionValue,
757
+ summary: result.summary,
758
+ };
759
+ }
760
+ async function prepareCapitalCall(sdk, input) {
761
+ const definition = await loadFundDefinitionDocument(sdk, input);
762
+ const capitalCall = await loadCapitalCallDocument(sdk, input);
763
+ assertOpenCapitalCall(capitalCall.value);
764
+ const crossChecks = (0, fundValidation_1.validateFundCrossChecks)(definition.value, capitalCall.value);
765
+ const refundOnlyCapitalCallValue = (0, fundValidation_1.buildRefundOnlyCapitalCallState)({ previous: capitalCall.value });
766
+ const refundOnlyCompiled = await compileRefundOnlyCapitalCallContract(sdk, {
767
+ definition: definition.value,
768
+ capitalCall: refundOnlyCapitalCallValue,
769
+ simfPath: input.refundOnlySimfPath,
770
+ artifactPath: input.refundOnlyArtifactPath,
771
+ });
772
+ const refundOnlyScriptPubKeyHex = await (0, outputBinding_1.getScriptPubKeyHexViaRpc)(sdk, refundOnlyCompiled.deployment().contractAddress);
773
+ const openCompiled = await compileOpenCapitalCallContract(sdk, {
774
+ definition: definition.value,
775
+ capitalCall: capitalCall.value,
776
+ refundOnlyScriptHash: (0, outputBinding_1.hashHexBytes)(refundOnlyScriptPubKeyHex),
777
+ simfPath: input.openSimfPath,
778
+ artifactPath: input.openArtifactPath,
779
+ });
780
+ return {
781
+ definition: definition.descriptor,
782
+ definitionValue: definition.value,
783
+ definitionSummary: definition.summary,
784
+ capitalCall: capitalCall.descriptor,
785
+ capitalCallValue: capitalCall.value,
786
+ capitalCallSummary: capitalCall.summary,
787
+ refundOnlyCapitalCallValue,
788
+ refundOnlyCapitalCallSummary: (0, fundValidation_1.summarizeCapitalCallState)(refundOnlyCapitalCallValue),
789
+ crossChecks,
790
+ openCompiled,
791
+ refundOnlyCompiled,
792
+ report: {
793
+ ...buildBaseFundReport(),
794
+ capitalCallTrust: {
795
+ capitalCallStage: deriveCapitalCallStage(capitalCall.value),
796
+ cutoffMode: "rollover-window",
797
+ fundIdMatch: crossChecks.fundIdMatch,
798
+ currencyMatch: crossChecks.currencyMatch,
799
+ managerMatch: crossChecks.managerMatch,
800
+ claimCutoffCommitted: true,
801
+ lpCommitted: true,
802
+ managerCommitted: true,
803
+ claimPathRuntimeAvailable: true,
804
+ refundPathRuntimeAvailable: false,
805
+ statusValid: true,
806
+ },
807
+ },
808
+ };
809
+ }
810
+ async function verifyCapitalCall(sdk, input) {
811
+ const definition = await loadFundDefinitionDocument(sdk, input);
812
+ const capitalCall = await loadCapitalCallDocument(sdk, input);
813
+ const crossChecks = (0, fundValidation_1.validateFundCrossChecks)(definition.value, capitalCall.value);
814
+ const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
815
+ const definitionVerification = artifact
816
+ ? await sdk.verifyDefinitionAgainstArtifact({
817
+ artifact,
818
+ type: "fund-definition",
819
+ id: definition.value.fundId,
820
+ value: definition.value,
821
+ })
822
+ : undefined;
823
+ const stateVerification = artifact
824
+ ? await sdk.verifyStateAgainstArtifact({
825
+ artifact,
826
+ type: "fund-capital-call",
827
+ id: capitalCall.value.callId,
828
+ value: capitalCall.value,
829
+ })
830
+ : undefined;
831
+ const artifactVars = artifact?.source.templateVars ?? {};
832
+ const artifactStage = artifact ? String(artifactVars.CAPITAL_CALL_STAGE ?? "").toUpperCase() : "";
833
+ const claimCutoffCommitted = artifact
834
+ ? Number(artifactVars.CLAIM_CUTOFF_HEIGHT ?? capitalCall.value.claimCutoffHeight) === capitalCall.value.claimCutoffHeight
835
+ : true;
836
+ const lpCommitted = artifact
837
+ ? String(artifactVars.LP_XONLY ?? "").toLowerCase() === capitalCall.value.lpXonly.toLowerCase()
838
+ : true;
839
+ const managerCommitted = artifact
840
+ ? artifactStage === "REFUND_ONLY"
841
+ ? true
842
+ : String(artifactVars.MANAGER_XONLY ?? "").toLowerCase() === definition.value.managerXonly.toLowerCase()
843
+ : true;
844
+ const stageValid = artifact
845
+ ? (capitalCall.value.status === "OPEN" && artifactStage === "OPEN")
846
+ || (capitalCall.value.status === "REFUND_ONLY" && artifactStage === "REFUND_ONLY")
847
+ : true;
848
+ const claimPathRuntimeAvailable = capitalCall.value.status === "OPEN";
849
+ const refundPathRuntimeAvailable = capitalCall.value.status === "REFUND_ONLY";
850
+ const statusValid = true;
851
+ const ok = (!definitionVerification || definitionVerification.ok)
852
+ && (!stateVerification || stateVerification.ok)
853
+ && crossChecks.fundIdMatch
854
+ && crossChecks.currencyMatch
855
+ && crossChecks.managerMatch
856
+ && claimCutoffCommitted
857
+ && lpCommitted
858
+ && managerCommitted
859
+ && stageValid
860
+ && statusValid;
861
+ return {
862
+ ok,
863
+ reason: ok ? undefined : "Fund capital call verification failed",
864
+ artifact,
865
+ definition: definition.descriptor,
866
+ definitionValue: definition.value,
867
+ capitalCall: capitalCall.descriptor,
868
+ capitalCallValue: capitalCall.value,
869
+ definitionSummary: definition.summary,
870
+ capitalCallSummary: capitalCall.summary,
871
+ artifactVerification: artifact && definitionVerification && stateVerification
872
+ ? { definition: definitionVerification, state: stateVerification }
873
+ : undefined,
874
+ report: {
875
+ ...buildBaseFundReport({
876
+ definitionTrust: definitionVerification?.trust,
877
+ stateTrust: stateVerification?.trust,
878
+ }),
879
+ capitalCallTrust: {
880
+ capitalCallStage: deriveCapitalCallStage(capitalCall.value),
881
+ cutoffMode: "rollover-window",
882
+ fundIdMatch: crossChecks.fundIdMatch,
883
+ currencyMatch: crossChecks.currencyMatch,
884
+ managerMatch: crossChecks.managerMatch,
885
+ claimCutoffCommitted,
886
+ lpCommitted,
887
+ managerCommitted,
888
+ claimPathRuntimeAvailable,
889
+ refundPathRuntimeAvailable,
890
+ statusValid,
891
+ },
892
+ },
893
+ };
894
+ }
895
+ async function signPositionReceipt(sdk, input) {
896
+ const definition = await loadFundDefinitionDocument(sdk, input);
897
+ const receipt = await loadBarePositionReceiptDocument(sdk, input);
898
+ const positionReceiptEnvelope = await (0, fundValidation_1.signLPPositionReceipt)({
899
+ receipt: receipt.value,
900
+ managerXonly: definition.value.managerXonly,
901
+ signer: input.signer,
902
+ signedAt: input.signedAt,
903
+ });
904
+ return {
905
+ definition: definition.descriptor,
906
+ definitionValue: definition.value,
907
+ definitionSummary: definition.summary,
908
+ positionReceipt: receipt.descriptor,
909
+ positionReceiptValue: receipt.value,
910
+ positionReceiptSummary: receipt.summary,
911
+ positionReceiptEnvelope,
912
+ positionReceiptEnvelopeSummary: (0, fundValidation_1.summarizeLPPositionReceiptEnvelope)(positionReceiptEnvelope),
913
+ };
914
+ }
915
+ async function verifyPositionReceipt(sdk, input) {
916
+ const definition = await loadFundDefinitionDocument(sdk, input);
917
+ const envelope = input.positionReceiptPath || input.positionReceiptValue
918
+ ? await loadPositionReceiptEnvelopeDocument(sdk, input)
919
+ : undefined;
920
+ const previousEnvelope = input.previousPositionReceiptPath || input.previousPositionReceiptValue
921
+ ? await loadPositionReceiptEnvelopeDocument(sdk, {
922
+ positionReceiptPath: input.previousPositionReceiptPath,
923
+ positionReceiptValue: input.previousPositionReceiptValue,
924
+ })
925
+ : undefined;
926
+ const chainEntries = input.positionReceiptChainPaths || input.positionReceiptChainValues
927
+ ? await loadPositionReceiptEnvelopeChainDocuments(sdk, {
928
+ positionReceiptChainPaths: input.positionReceiptChainPaths,
929
+ positionReceiptChainValues: input.positionReceiptChainValues,
930
+ })
931
+ : [];
932
+ const context = resolveReceiptChainContext({
933
+ receipt: envelope,
934
+ previousEnvelope,
935
+ chainEntries,
936
+ });
937
+ const receiptChecks = await ensureVerifiedEnvelopeContinuity(definition.value, context.receipt.value, context.previousEnvelope?.value);
938
+ const chainChecks = await (0, fundValidation_1.verifyLPPositionReceiptEnvelopeChain)({
939
+ envelopes: context.chainEntries.map((entry) => entry.value),
940
+ expectedManagerXonly: definition.value.managerXonly,
941
+ });
942
+ return {
943
+ verified: true,
944
+ definition: definition.descriptor,
945
+ definitionValue: definition.value,
946
+ definitionSummary: definition.summary,
947
+ positionReceipt: context.receipt.descriptor,
948
+ positionReceiptValue: context.receipt.value,
949
+ positionReceiptSummary: context.receipt.receiptSummary,
950
+ positionReceiptEnvelopeSummary: context.receipt.envelopeSummary,
951
+ ...(context.previousEnvelope
952
+ ? {
953
+ previousPositionReceipt: context.previousEnvelope.descriptor,
954
+ previousPositionReceiptValue: context.previousEnvelope.value,
955
+ previousPositionReceiptSummary: context.previousEnvelope.receiptSummary,
956
+ previousPositionReceiptEnvelopeSummary: context.previousEnvelope.envelopeSummary,
957
+ }
958
+ : {}),
959
+ ...(context.chainEntries.length > 0
960
+ ? {
961
+ positionReceiptChain: context.chainEntries.map((entry) => entry.descriptor),
962
+ positionReceiptChainValues: context.chainEntries.map((entry) => entry.value),
963
+ positionReceiptChainSummaries: context.chainEntries.map((entry) => entry.receiptSummary),
964
+ positionReceiptEnvelopeChainSummaries: context.chainEntries.map((entry) => entry.envelopeSummary),
965
+ }
966
+ : {}),
967
+ receiptChecks,
968
+ receiptChainChecks: chainChecks,
969
+ report: {
970
+ ...buildBaseFundReport(),
971
+ receiptTrust: buildReceiptTrust({ generated: false, envelope: context.receipt.value, checks: receiptChecks }),
972
+ receiptChainTrust: buildReceiptChainTrust(chainChecks),
973
+ },
974
+ };
975
+ }
976
+ async function verifyPositionReceiptChain(sdk, input) {
977
+ const definition = await loadFundDefinitionDocument(sdk, input);
978
+ const chainEntries = await loadPositionReceiptEnvelopeChainDocuments(sdk, input);
979
+ const context = resolveReceiptChainContext({ chainEntries });
980
+ const receiptChecks = await ensureVerifiedEnvelopeContinuity(definition.value, context.receipt.value, context.previousEnvelope?.value);
981
+ const chainChecks = await (0, fundValidation_1.verifyLPPositionReceiptEnvelopeChain)({
982
+ envelopes: context.chainEntries.map((entry) => entry.value),
983
+ expectedManagerXonly: definition.value.managerXonly,
984
+ });
985
+ return {
986
+ verified: chainChecks.fullChainVerified,
987
+ definition: definition.descriptor,
988
+ definitionValue: definition.value,
989
+ definitionSummary: definition.summary,
990
+ positionReceipt: context.receipt.descriptor,
991
+ positionReceiptValue: context.receipt.value,
992
+ positionReceiptSummary: context.receipt.receiptSummary,
993
+ positionReceiptEnvelopeSummary: context.receipt.envelopeSummary,
994
+ ...(context.previousEnvelope
995
+ ? {
996
+ previousPositionReceipt: context.previousEnvelope.descriptor,
997
+ previousPositionReceiptValue: context.previousEnvelope.value,
998
+ previousPositionReceiptSummary: context.previousEnvelope.receiptSummary,
999
+ previousPositionReceiptEnvelopeSummary: context.previousEnvelope.envelopeSummary,
1000
+ }
1001
+ : {}),
1002
+ positionReceiptChain: context.chainEntries.map((entry) => entry.descriptor),
1003
+ positionReceiptChainValues: context.chainEntries.map((entry) => entry.value),
1004
+ positionReceiptChainSummaries: context.chainEntries.map((entry) => entry.receiptSummary),
1005
+ positionReceiptEnvelopeChainSummaries: context.chainEntries.map((entry) => entry.envelopeSummary),
1006
+ receiptChecks,
1007
+ receiptChainChecks: chainChecks,
1008
+ report: {
1009
+ ...buildBaseFundReport(),
1010
+ receiptTrust: buildReceiptTrust({ generated: false, envelope: context.receipt.value, checks: receiptChecks }),
1011
+ receiptChainTrust: buildReceiptChainTrust(chainChecks),
1012
+ },
1013
+ };
1014
+ }
1015
+ async function inspectCapitalCallClaim(sdk, input) {
1016
+ const verified = await verifyCapitalCall(sdk, input);
1017
+ if (!verified.ok) {
1018
+ throw new errors_1.ValidationError(verified.reason ?? "Fund capital call verification failed", {
1019
+ code: "FUND_CAPITAL_CALL_VERIFY_FAILED",
1020
+ });
1021
+ }
1022
+ assertOpenCapitalCall(verified.capitalCallValue);
1023
+ const definition = await loadFundDefinitionDocument(sdk, input);
1024
+ const artifact = await requireFundArtifact(sdk, input);
1025
+ const payout = await buildFundPayoutDescriptor(sdk, {
1026
+ receiverAddress: input.payoutAddress,
1027
+ amountSat: verified.capitalCallValue.amount,
1028
+ assetId: verified.capitalCallValue.currencyAssetId,
1029
+ nextOutputHash: input.nextOutputHash,
1030
+ outputForm: input.outputForm,
1031
+ rawOutput: input.rawOutput,
1032
+ outputBindingMode: input.outputBindingMode,
1033
+ });
1034
+ const claimedAt = input.claimedAt ?? nowIso();
1035
+ const claimedCapitalCall = (0, fundValidation_1.buildClaimedCapitalCallState)({ previous: verified.capitalCallValue, claimedAt });
1036
+ const positionReceipt = (0, fundValidation_1.buildLPPositionReceipt)({
1037
+ positionId: input.positionId ?? defaultPositionId(verified.capitalCallValue),
1038
+ capitalCall: verified.capitalCallValue,
1039
+ effectiveAt: claimedAt,
1040
+ });
1041
+ const positionReceiptEnvelope = await (0, fundValidation_1.signLPPositionReceipt)({
1042
+ receipt: positionReceipt,
1043
+ managerXonly: definition.value.managerXonly,
1044
+ signer: input.signer,
1045
+ signedAt: claimedAt,
1046
+ });
1047
+ const receiptChecks = await ensureVerifiedEnvelope(definition.value, positionReceiptEnvelope);
1048
+ const contract = sdk.fromArtifact(artifact);
1049
+ const inspect = await contract.inspectCall({
1050
+ wallet: input.wallet,
1051
+ toAddress: payout.descriptor.receiverAddress,
1052
+ signer: input.signer,
1053
+ sendAmount: satToBtcAmount(payout.descriptor.amountSat),
1054
+ feeSat: input.feeSat,
1055
+ utxoPolicy: input.utxoPolicy,
1056
+ witness: buildClaimWitness(payout.descriptor),
1057
+ });
1058
+ return {
1059
+ mode: "claim",
1060
+ verified,
1061
+ payoutDescriptor: payout.descriptor,
1062
+ payoutSummary: payout.summary,
1063
+ claimedCapitalCall,
1064
+ positionReceipt,
1065
+ positionReceiptEnvelope,
1066
+ positionReceiptEnvelopeSummary: (0, fundValidation_1.summarizeLPPositionReceiptEnvelope)(positionReceiptEnvelope),
1067
+ inspect,
1068
+ report: {
1069
+ ...verified.report,
1070
+ outputBindingTrust: buildFundOutputBindingReport({
1071
+ descriptor: payout.descriptor,
1072
+ supportedForm: payout.supportedForm,
1073
+ reasonCode: payout.reasonCode,
1074
+ autoDerived: payout.autoDerivedNextOutputHash,
1075
+ fallbackReason: payout.fallbackReason,
1076
+ bindingInputs: payout.bindingInputs,
1077
+ }),
1078
+ receiptTrust: buildReceiptTrust({ generated: true, envelope: positionReceiptEnvelope, checks: receiptChecks }),
1079
+ },
1080
+ };
1081
+ }
1082
+ async function executeCapitalCallClaim(sdk, input) {
1083
+ const inspected = await inspectCapitalCallClaim(sdk, input);
1084
+ const artifact = await requireFundArtifact(sdk, input);
1085
+ const contract = sdk.fromArtifact(artifact);
1086
+ const execution = await contract.execute({
1087
+ wallet: input.wallet,
1088
+ toAddress: inspected.payoutDescriptor.receiverAddress,
1089
+ signer: input.signer,
1090
+ sendAmount: satToBtcAmount(inspected.payoutDescriptor.amountSat),
1091
+ feeSat: input.feeSat,
1092
+ utxoPolicy: input.utxoPolicy,
1093
+ broadcast: input.broadcast,
1094
+ witness: buildClaimWitness(inspected.payoutDescriptor),
1095
+ });
1096
+ return {
1097
+ ...inspected,
1098
+ mode: "claim",
1099
+ execution,
1100
+ };
1101
+ }
1102
+ async function inspectCapitalCallRollover(sdk, input) {
1103
+ const verified = await verifyCapitalCall(sdk, input);
1104
+ if (!verified.ok) {
1105
+ throw new errors_1.ValidationError(verified.reason ?? "Fund capital call verification failed", {
1106
+ code: "FUND_CAPITAL_CALL_VERIFY_FAILED",
1107
+ });
1108
+ }
1109
+ assertOpenCapitalCall(verified.capitalCallValue);
1110
+ const artifact = await requireFundArtifact(sdk, input);
1111
+ const refundOnlyArtifact = await requireRefundOnlyArtifact(sdk, input);
1112
+ const rolledOverCapitalCall = (0, fundValidation_1.buildRefundOnlyCapitalCallState)({ previous: verified.capitalCallValue });
1113
+ const contract = sdk.fromArtifact(artifact);
1114
+ const inspect = await contract.inspectCall({
1115
+ wallet: input.wallet,
1116
+ toAddress: refundOnlyArtifact.compiled.contractAddress,
1117
+ signer: input.signer,
1118
+ sendAmount: satToBtcAmount(verified.capitalCallValue.amount),
1119
+ feeSat: input.feeSat,
1120
+ utxoPolicy: input.utxoPolicy,
1121
+ locktimeHeight: verified.capitalCallValue.claimCutoffHeight,
1122
+ witness: buildRolloverWitness(),
1123
+ });
1124
+ return {
1125
+ mode: "rollover",
1126
+ verified,
1127
+ refundOnlyArtifact,
1128
+ rolledOverCapitalCall,
1129
+ inspect,
1130
+ report: verified.report,
1131
+ };
1132
+ }
1133
+ async function executeCapitalCallRollover(sdk, input) {
1134
+ const inspected = await inspectCapitalCallRollover(sdk, input);
1135
+ const artifact = await requireFundArtifact(sdk, input);
1136
+ const contract = sdk.fromArtifact(artifact);
1137
+ const execution = await contract.execute({
1138
+ wallet: input.wallet,
1139
+ toAddress: inspected.refundOnlyArtifact.compiled.contractAddress,
1140
+ signer: input.signer,
1141
+ sendAmount: satToBtcAmount(inspected.verified.capitalCallValue.amount),
1142
+ feeSat: input.feeSat,
1143
+ utxoPolicy: input.utxoPolicy,
1144
+ locktimeHeight: inspected.verified.capitalCallValue.claimCutoffHeight,
1145
+ broadcast: input.broadcast,
1146
+ witness: buildRolloverWitness(),
1147
+ });
1148
+ return {
1149
+ ...inspected,
1150
+ mode: "rollover",
1151
+ execution,
1152
+ };
1153
+ }
1154
+ async function inspectCapitalCallRefund(sdk, input) {
1155
+ const verified = await verifyCapitalCall(sdk, input);
1156
+ if (!verified.ok) {
1157
+ throw new errors_1.ValidationError(verified.reason ?? "Fund capital call verification failed", {
1158
+ code: "FUND_CAPITAL_CALL_VERIFY_FAILED",
1159
+ });
1160
+ }
1161
+ assertRefundOnlyCapitalCall(verified.capitalCallValue);
1162
+ const artifact = await requireFundArtifact(sdk, input);
1163
+ const refundedAt = input.refundedAt ?? nowIso();
1164
+ const refundedCapitalCall = (0, fundValidation_1.buildRefundedCapitalCallState)({ previous: verified.capitalCallValue, refundedAt });
1165
+ const feeSat = input.feeSat ?? 100;
1166
+ const refundAmountSat = verified.capitalCallValue.amount - feeSat;
1167
+ if (refundAmountSat <= 0) {
1168
+ throw new errors_1.ValidationError("Refund amount must remain positive after fee deduction", {
1169
+ code: "FUND_REFUND_AMOUNT_INVALID",
1170
+ details: {
1171
+ amount: verified.capitalCallValue.amount,
1172
+ feeSat,
1173
+ },
1174
+ });
1175
+ }
1176
+ const payout = await buildFundPayoutDescriptor(sdk, {
1177
+ receiverAddress: input.refundAddress,
1178
+ amountSat: refundAmountSat,
1179
+ assetId: verified.capitalCallValue.currencyAssetId,
1180
+ nextOutputHash: input.nextOutputHash,
1181
+ outputForm: input.outputForm,
1182
+ rawOutput: input.rawOutput,
1183
+ outputBindingMode: input.outputBindingMode,
1184
+ });
1185
+ const contract = sdk.fromArtifact(artifact);
1186
+ const inspect = await contract.inspectCall({
1187
+ wallet: input.wallet,
1188
+ toAddress: payout.descriptor.receiverAddress,
1189
+ signer: input.signer,
1190
+ sendAmount: satToBtcAmount(payout.descriptor.amountSat),
1191
+ feeSat,
1192
+ utxoPolicy: input.utxoPolicy,
1193
+ witness: buildRefundWitness(payout.descriptor),
1194
+ });
1195
+ return {
1196
+ mode: "refund",
1197
+ verified,
1198
+ payoutDescriptor: payout.descriptor,
1199
+ payoutSummary: payout.summary,
1200
+ refundedCapitalCall,
1201
+ inspect,
1202
+ report: {
1203
+ ...verified.report,
1204
+ outputBindingTrust: buildFundOutputBindingReport({
1205
+ descriptor: payout.descriptor,
1206
+ supportedForm: payout.supportedForm,
1207
+ reasonCode: payout.reasonCode,
1208
+ autoDerived: payout.autoDerivedNextOutputHash,
1209
+ fallbackReason: payout.fallbackReason,
1210
+ bindingInputs: payout.bindingInputs,
1211
+ }),
1212
+ },
1213
+ };
1214
+ }
1215
+ async function executeCapitalCallRefund(sdk, input) {
1216
+ const inspected = await inspectCapitalCallRefund(sdk, input);
1217
+ const artifact = await requireFundArtifact(sdk, input);
1218
+ const contract = sdk.fromArtifact(artifact);
1219
+ const feeSat = input.feeSat ?? 100;
1220
+ const execution = await contract.execute({
1221
+ wallet: input.wallet,
1222
+ toAddress: inspected.payoutDescriptor.receiverAddress,
1223
+ signer: input.signer,
1224
+ sendAmount: satToBtcAmount(inspected.payoutDescriptor.amountSat),
1225
+ feeSat,
1226
+ utxoPolicy: input.utxoPolicy,
1227
+ broadcast: input.broadcast,
1228
+ witness: buildRefundWitness(inspected.payoutDescriptor),
1229
+ });
1230
+ return {
1231
+ ...inspected,
1232
+ mode: "refund",
1233
+ execution,
1234
+ };
1235
+ }
1236
+ async function prepareDistribution(sdk, input) {
1237
+ const definition = await loadFundDefinitionDocument(sdk, input);
1238
+ const receipt = await loadPositionReceiptEnvelopeDocument(sdk, input);
1239
+ const receiptChecks = await ensureVerifiedEnvelope(definition.value, receipt.value);
1240
+ const distribution = await loadDistributionDocument(sdk, {
1241
+ distributionPath: input.distributionPath,
1242
+ distributionValue: input.distributionValue,
1243
+ positionReceipt: receipt.value.receipt,
1244
+ distributionId: input.distributionId,
1245
+ assetId: input.assetId,
1246
+ amountSat: input.amountSat,
1247
+ approvedAt: input.approvedAt,
1248
+ });
1249
+ const crossChecks = (0, fundValidation_1.validateDistributionAgainstReceipt)(receipt.value.receipt, distribution.value);
1250
+ const compiled = await compileDistributionClaimContract(sdk, {
1251
+ definition: definition.value,
1252
+ distribution: distribution.value,
1253
+ receipt: receipt.value.receipt,
1254
+ simfPath: input.simfPath,
1255
+ artifactPath: input.artifactPath,
1256
+ });
1257
+ return {
1258
+ definition: definition.descriptor,
1259
+ definitionValue: definition.value,
1260
+ definitionSummary: definition.summary,
1261
+ positionReceipt: receipt.descriptor,
1262
+ positionReceiptValue: receipt.value,
1263
+ positionReceiptSummary: receipt.receiptSummary,
1264
+ positionReceiptEnvelopeSummary: receipt.envelopeSummary,
1265
+ distribution: distribution.descriptor,
1266
+ distributionValue: distribution.value,
1267
+ distributionSummary: distribution.summary,
1268
+ crossChecks,
1269
+ compiled,
1270
+ report: {
1271
+ ...buildBaseFundReport(),
1272
+ distributionTrust: crossChecks,
1273
+ receiptTrust: buildReceiptTrust({ generated: false, envelope: receipt.value, checks: receiptChecks }),
1274
+ },
1275
+ };
1276
+ }
1277
+ async function reconcilePosition(sdk, input) {
1278
+ const definition = await loadFundDefinitionDocument(sdk, input);
1279
+ const receipt = await loadPositionReceiptEnvelopeDocument(sdk, input);
1280
+ await ensureVerifiedEnvelope(definition.value, receipt.value);
1281
+ const distributions = await loadDistributionDocuments(sdk, input);
1282
+ const reconciledReceiptValue = (0, fundValidation_1.reconcileLPPositionReceipt)({
1283
+ previousEnvelope: receipt.value,
1284
+ distributions: distributions.map((entry) => entry.value),
1285
+ });
1286
+ const reconciledReceiptEnvelope = await (0, fundValidation_1.signLPPositionReceipt)({
1287
+ receipt: reconciledReceiptValue,
1288
+ managerXonly: definition.value.managerXonly,
1289
+ signer: input.signer,
1290
+ signedAt: input.signedAt,
1291
+ });
1292
+ return {
1293
+ definition: definition.descriptor,
1294
+ definitionValue: definition.value,
1295
+ definitionSummary: definition.summary,
1296
+ positionReceipt: receipt.descriptor,
1297
+ positionReceiptValue: receipt.value,
1298
+ positionReceiptSummary: receipt.receiptSummary,
1299
+ positionReceiptEnvelopeSummary: receipt.envelopeSummary,
1300
+ distributions: distributions.map((distribution) => distribution.descriptor),
1301
+ distributionValues: distributions.map((distribution) => distribution.value),
1302
+ distributionSummaries: distributions.map((distribution) => distribution.summary),
1303
+ reconciledReceiptValue,
1304
+ reconciledReceiptSummary: (0, fundValidation_1.summarizeLPPositionReceipt)(reconciledReceiptValue),
1305
+ reconciledReceiptEnvelope,
1306
+ reconciledReceiptEnvelopeSummary: (0, fundValidation_1.summarizeLPPositionReceiptEnvelope)(reconciledReceiptEnvelope),
1307
+ totalDistributedAmount: reconciledReceiptValue.distributedAmount,
1308
+ distributionCount: reconciledReceiptValue.distributionCount,
1309
+ };
1310
+ }
1311
+ async function verifyDistribution(sdk, input) {
1312
+ const definition = await loadFundDefinitionDocument(sdk, input);
1313
+ const receipt = await loadPositionReceiptEnvelopeDocument(sdk, input);
1314
+ const receiptChecks = await ensureVerifiedEnvelope(definition.value, receipt.value);
1315
+ const distribution = await loadDistributionDocument(sdk, {
1316
+ distributionPath: input.distributionPath,
1317
+ distributionValue: input.distributionValue,
1318
+ });
1319
+ const crossChecks = (0, fundValidation_1.validateDistributionAgainstReceipt)(receipt.value.receipt, distribution.value);
1320
+ const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
1321
+ const definitionVerification = artifact
1322
+ ? await sdk.verifyDefinitionAgainstArtifact({
1323
+ artifact,
1324
+ type: "fund-definition",
1325
+ id: definition.value.fundId,
1326
+ value: definition.value,
1327
+ })
1328
+ : undefined;
1329
+ const stateVerification = artifact
1330
+ ? await sdk.verifyStateAgainstArtifact({
1331
+ artifact,
1332
+ type: "fund-distribution",
1333
+ id: distribution.value.distributionId,
1334
+ value: distribution.value,
1335
+ })
1336
+ : undefined;
1337
+ const artifactVars = artifact?.source.templateVars ?? {};
1338
+ const lpCommitted = artifact
1339
+ ? String(artifactVars.LP_XONLY ?? "").toLowerCase() === receipt.value.receipt.lpXonly.toLowerCase()
1340
+ : true;
1341
+ const ok = (!definitionVerification || definitionVerification.ok)
1342
+ && (!stateVerification || stateVerification.ok)
1343
+ && crossChecks.fundIdMatch
1344
+ && crossChecks.lpIdMatch
1345
+ && crossChecks.positionIdMatch
1346
+ && crossChecks.positionReceiptHashMatch
1347
+ && crossChecks.positionStatusEligible
1348
+ && lpCommitted;
1349
+ return {
1350
+ ok,
1351
+ reason: ok ? undefined : "Fund distribution verification failed",
1352
+ artifact,
1353
+ definition: definition.descriptor,
1354
+ definitionValue: definition.value,
1355
+ positionReceipt: receipt.descriptor,
1356
+ positionReceiptValue: receipt.value,
1357
+ distribution: distribution.descriptor,
1358
+ distributionValue: distribution.value,
1359
+ definitionSummary: definition.summary,
1360
+ positionReceiptSummary: receipt.receiptSummary,
1361
+ positionReceiptEnvelopeSummary: receipt.envelopeSummary,
1362
+ distributionSummary: distribution.summary,
1363
+ artifactVerification: artifact && definitionVerification && stateVerification
1364
+ ? { definition: definitionVerification, state: stateVerification }
1365
+ : undefined,
1366
+ report: {
1367
+ ...buildBaseFundReport({
1368
+ definitionTrust: definitionVerification?.trust,
1369
+ stateTrust: stateVerification?.trust,
1370
+ }),
1371
+ distributionTrust: {
1372
+ ...crossChecks,
1373
+ positionStatusEligible: crossChecks.positionStatusEligible && lpCommitted,
1374
+ },
1375
+ receiptTrust: buildReceiptTrust({ generated: false, envelope: receipt.value, checks: receiptChecks }),
1376
+ },
1377
+ };
1378
+ }
1379
+ async function inspectDistributionClaim(sdk, input) {
1380
+ const verified = await verifyDistribution(sdk, input);
1381
+ if (!verified.ok) {
1382
+ throw new errors_1.ValidationError(verified.reason ?? "Fund distribution verification failed", {
1383
+ code: "FUND_DISTRIBUTION_VERIFY_FAILED",
1384
+ });
1385
+ }
1386
+ const artifact = await requireFundArtifact(sdk, input);
1387
+ const payout = await buildFundPayoutDescriptor(sdk, {
1388
+ receiverAddress: input.payoutAddress,
1389
+ amountSat: verified.distributionValue.amountSat,
1390
+ assetId: verified.distributionValue.assetId,
1391
+ nextOutputHash: input.nextOutputHash,
1392
+ outputForm: input.outputForm,
1393
+ rawOutput: input.rawOutput,
1394
+ outputBindingMode: input.outputBindingMode,
1395
+ });
1396
+ const contract = sdk.fromArtifact(artifact);
1397
+ const inspect = await contract.inspectCall({
1398
+ wallet: input.wallet,
1399
+ toAddress: payout.descriptor.receiverAddress,
1400
+ signer: input.signer,
1401
+ sendAmount: satToBtcAmount(payout.descriptor.amountSat),
1402
+ feeSat: input.feeSat,
1403
+ utxoPolicy: input.utxoPolicy,
1404
+ witness: buildDistributionWitness(payout.descriptor),
1405
+ });
1406
+ return {
1407
+ mode: "distribution-claim",
1408
+ verified,
1409
+ payoutDescriptor: payout.descriptor,
1410
+ payoutSummary: payout.summary,
1411
+ inspect,
1412
+ report: {
1413
+ ...verified.report,
1414
+ outputBindingTrust: buildFundOutputBindingReport({
1415
+ descriptor: payout.descriptor,
1416
+ supportedForm: payout.supportedForm,
1417
+ reasonCode: payout.reasonCode,
1418
+ autoDerived: payout.autoDerivedNextOutputHash,
1419
+ fallbackReason: payout.fallbackReason,
1420
+ bindingInputs: payout.bindingInputs,
1421
+ }),
1422
+ },
1423
+ };
1424
+ }
1425
+ async function executeDistributionClaim(sdk, input) {
1426
+ const inspected = await inspectDistributionClaim(sdk, input);
1427
+ const artifact = await requireFundArtifact(sdk, input);
1428
+ const contract = sdk.fromArtifact(artifact);
1429
+ const execution = await contract.execute({
1430
+ wallet: input.wallet,
1431
+ toAddress: inspected.payoutDescriptor.receiverAddress,
1432
+ signer: input.signer,
1433
+ sendAmount: satToBtcAmount(inspected.payoutDescriptor.amountSat),
1434
+ feeSat: input.feeSat,
1435
+ utxoPolicy: input.utxoPolicy,
1436
+ broadcast: input.broadcast,
1437
+ witness: buildDistributionWitness(inspected.payoutDescriptor),
1438
+ });
1439
+ return {
1440
+ ...inspected,
1441
+ mode: "distribution-claim",
1442
+ execution,
1443
+ };
1444
+ }
1445
+ async function prepareClosing(sdk, input) {
1446
+ const definition = await loadFundDefinitionDocument(sdk, input);
1447
+ const receipt = input.positionReceiptPath || input.positionReceiptValue
1448
+ ? await loadPositionReceiptEnvelopeDocument(sdk, input)
1449
+ : undefined;
1450
+ const previousEnvelope = input.previousPositionReceiptPath || input.previousPositionReceiptValue
1451
+ ? await loadPositionReceiptEnvelopeDocument(sdk, {
1452
+ positionReceiptPath: input.previousPositionReceiptPath,
1453
+ positionReceiptValue: input.previousPositionReceiptValue,
1454
+ })
1455
+ : undefined;
1456
+ const chainEntries = input.positionReceiptChainPaths || input.positionReceiptChainValues
1457
+ ? await loadPositionReceiptEnvelopeChainDocuments(sdk, {
1458
+ positionReceiptChainPaths: input.positionReceiptChainPaths,
1459
+ positionReceiptChainValues: input.positionReceiptChainValues,
1460
+ })
1461
+ : [];
1462
+ const context = resolveReceiptChainContext({
1463
+ receipt,
1464
+ previousEnvelope,
1465
+ chainEntries,
1466
+ });
1467
+ const receiptChecks = await ensureVerifiedEnvelopeContinuity(definition.value, context.receipt.value, context.previousEnvelope?.value);
1468
+ const chainChecks = await (0, fundValidation_1.verifyLPPositionReceiptEnvelopeChain)({
1469
+ envelopes: context.chainEntries.map((entry) => entry.value),
1470
+ expectedManagerXonly: definition.value.managerXonly,
1471
+ });
1472
+ const closing = await loadClosingDocument(sdk, {
1473
+ closingPath: input.closingPath,
1474
+ closingValue: input.closingValue,
1475
+ positionReceipt: context.receipt.value.receipt,
1476
+ closingId: input.closingId,
1477
+ finalDistributionHashes: input.finalDistributionHashes,
1478
+ closedAt: input.closedAt,
1479
+ closingReason: input.closingReason,
1480
+ });
1481
+ const checks = (0, fundValidation_1.validateClosingAgainstReceipt)(context.receipt.value.receipt, closing.value);
1482
+ return {
1483
+ positionReceipt: context.receipt.descriptor,
1484
+ positionReceiptValue: context.receipt.value,
1485
+ positionReceiptSummary: context.receipt.receiptSummary,
1486
+ positionReceiptEnvelopeSummary: context.receipt.envelopeSummary,
1487
+ ...(context.previousEnvelope
1488
+ ? {
1489
+ previousPositionReceipt: context.previousEnvelope.descriptor,
1490
+ previousPositionReceiptValue: context.previousEnvelope.value,
1491
+ previousPositionReceiptSummary: context.previousEnvelope.receiptSummary,
1492
+ previousPositionReceiptEnvelopeSummary: context.previousEnvelope.envelopeSummary,
1493
+ }
1494
+ : {}),
1495
+ ...(context.chainEntries.length > 0
1496
+ ? {
1497
+ positionReceiptChain: context.chainEntries.map((entry) => entry.descriptor),
1498
+ positionReceiptChainValues: context.chainEntries.map((entry) => entry.value),
1499
+ positionReceiptChainSummaries: context.chainEntries.map((entry) => entry.receiptSummary),
1500
+ positionReceiptEnvelopeChainSummaries: context.chainEntries.map((entry) => entry.envelopeSummary),
1501
+ }
1502
+ : {}),
1503
+ closing: closing.descriptor,
1504
+ closingValue: closing.value,
1505
+ closingSummary: closing.summary,
1506
+ closingHash: closing.summary.hash,
1507
+ checks,
1508
+ report: {
1509
+ ...buildBaseFundReport(),
1510
+ closingTrust: checks,
1511
+ receiptTrust: buildReceiptTrust({
1512
+ generated: false,
1513
+ envelope: context.receipt.value,
1514
+ checks: receiptChecks,
1515
+ }),
1516
+ receiptChainTrust: buildReceiptChainTrust(chainChecks),
1517
+ },
1518
+ };
1519
+ }
1520
+ async function verifyClosing(sdk, input) {
1521
+ const definition = await loadFundDefinitionDocument(sdk, input);
1522
+ const receipt = input.positionReceiptPath || input.positionReceiptValue
1523
+ ? await loadPositionReceiptEnvelopeDocument(sdk, input)
1524
+ : undefined;
1525
+ const previousEnvelope = input.previousPositionReceiptPath || input.previousPositionReceiptValue
1526
+ ? await loadPositionReceiptEnvelopeDocument(sdk, {
1527
+ positionReceiptPath: input.previousPositionReceiptPath,
1528
+ positionReceiptValue: input.previousPositionReceiptValue,
1529
+ })
1530
+ : undefined;
1531
+ const chainEntries = input.positionReceiptChainPaths || input.positionReceiptChainValues
1532
+ ? await loadPositionReceiptEnvelopeChainDocuments(sdk, {
1533
+ positionReceiptChainPaths: input.positionReceiptChainPaths,
1534
+ positionReceiptChainValues: input.positionReceiptChainValues,
1535
+ })
1536
+ : [];
1537
+ const context = resolveReceiptChainContext({
1538
+ receipt,
1539
+ previousEnvelope,
1540
+ chainEntries,
1541
+ });
1542
+ const receiptChecks = await ensureVerifiedEnvelopeContinuity(definition.value, context.receipt.value, context.previousEnvelope?.value);
1543
+ const chainChecks = await (0, fundValidation_1.verifyLPPositionReceiptEnvelopeChain)({
1544
+ envelopes: context.chainEntries.map((entry) => entry.value),
1545
+ expectedManagerXonly: definition.value.managerXonly,
1546
+ });
1547
+ const closing = await loadClosingDocument(sdk, { closingPath: input.closingPath, closingValue: input.closingValue });
1548
+ const checks = (0, fundValidation_1.validateClosingAgainstReceipt)(context.receipt.value.receipt, closing.value);
1549
+ return {
1550
+ verified: true,
1551
+ definition: definition.descriptor,
1552
+ definitionValue: definition.value,
1553
+ definitionSummary: definition.summary,
1554
+ positionReceipt: context.receipt.descriptor,
1555
+ positionReceiptValue: context.receipt.value,
1556
+ positionReceiptSummary: context.receipt.receiptSummary,
1557
+ positionReceiptEnvelopeSummary: context.receipt.envelopeSummary,
1558
+ ...(context.previousEnvelope
1559
+ ? {
1560
+ previousPositionReceipt: context.previousEnvelope.descriptor,
1561
+ previousPositionReceiptValue: context.previousEnvelope.value,
1562
+ previousPositionReceiptSummary: context.previousEnvelope.receiptSummary,
1563
+ previousPositionReceiptEnvelopeSummary: context.previousEnvelope.envelopeSummary,
1564
+ }
1565
+ : {}),
1566
+ ...(context.chainEntries.length > 0
1567
+ ? {
1568
+ positionReceiptChain: context.chainEntries.map((entry) => entry.descriptor),
1569
+ positionReceiptChainValues: context.chainEntries.map((entry) => entry.value),
1570
+ positionReceiptChainSummaries: context.chainEntries.map((entry) => entry.receiptSummary),
1571
+ positionReceiptEnvelopeChainSummaries: context.chainEntries.map((entry) => entry.envelopeSummary),
1572
+ }
1573
+ : {}),
1574
+ closing: closing.descriptor,
1575
+ closingValue: closing.value,
1576
+ closingSummary: closing.summary,
1577
+ checks,
1578
+ report: {
1579
+ ...buildBaseFundReport(),
1580
+ closingTrust: checks,
1581
+ receiptTrust: buildReceiptTrust({ generated: false, envelope: context.receipt.value, checks: receiptChecks }),
1582
+ receiptChainTrust: buildReceiptChainTrust(chainChecks),
1583
+ },
1584
+ };
1585
+ }
1586
+ async function exportEvidence(sdk, input) {
1587
+ const definition = await loadFundDefinitionDocument(sdk, input);
1588
+ const capitalCall = input.capitalCallPath || input.capitalCallValue ? await loadCapitalCallDocument(sdk, input) : undefined;
1589
+ const receipt = input.positionReceiptPath || input.positionReceiptValue
1590
+ ? await loadPositionReceiptEnvelopeDocument(sdk, input)
1591
+ : undefined;
1592
+ const previousEnvelope = input.previousPositionReceiptPath || input.previousPositionReceiptValue
1593
+ ? await loadPositionReceiptEnvelopeDocument(sdk, {
1594
+ positionReceiptPath: input.previousPositionReceiptPath,
1595
+ positionReceiptValue: input.previousPositionReceiptValue,
1596
+ })
1597
+ : undefined;
1598
+ const chainEntries = input.positionReceiptChainPaths || input.positionReceiptChainValues
1599
+ ? await loadPositionReceiptEnvelopeChainDocuments(sdk, {
1600
+ positionReceiptChainPaths: input.positionReceiptChainPaths,
1601
+ positionReceiptChainValues: input.positionReceiptChainValues,
1602
+ })
1603
+ : [];
1604
+ const receiptContext = receipt || chainEntries.length > 0
1605
+ ? resolveReceiptChainContext({
1606
+ receipt,
1607
+ previousEnvelope,
1608
+ chainEntries,
1609
+ })
1610
+ : undefined;
1611
+ const distributions = input.distributionPath || input.distributionValue || input.distributionPaths || input.distributionValues
1612
+ ? await loadDistributionDocuments(sdk, {
1613
+ distributionPath: input.distributionPath,
1614
+ distributionValue: input.distributionValue,
1615
+ distributionPaths: input.distributionPaths,
1616
+ distributionValues: input.distributionValues,
1617
+ })
1618
+ : [];
1619
+ const distribution = distributions.at(-1);
1620
+ const closing = input.closingPath || input.closingValue
1621
+ ? await loadClosingDocument(sdk, { closingPath: input.closingPath, closingValue: input.closingValue })
1622
+ : undefined;
1623
+ const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
1624
+ const trust = input.verificationReportValue
1625
+ ?? (distribution && receiptContext?.receipt && artifact
1626
+ ? (await verifyDistribution(sdk, {
1627
+ artifact,
1628
+ definitionValue: definition.value,
1629
+ positionReceiptValue: receiptContext.receipt.value,
1630
+ distributionValue: distribution.value,
1631
+ })).report
1632
+ : capitalCall && artifact
1633
+ ? (await verifyCapitalCall(sdk, {
1634
+ artifact,
1635
+ definitionValue: definition.value,
1636
+ capitalCallValue: capitalCall.value,
1637
+ })).report
1638
+ : closing && receiptContext?.receipt
1639
+ ? (await verifyClosing(sdk, {
1640
+ definitionValue: definition.value,
1641
+ positionReceiptValue: receiptContext.receipt.value,
1642
+ previousPositionReceiptValue: receiptContext.previousEnvelope?.value,
1643
+ positionReceiptChainValues: receiptContext.chainEntries.map((entry) => entry.value),
1644
+ closingValue: closing.value,
1645
+ })).report
1646
+ : receiptContext?.receipt
1647
+ ? (await verifyPositionReceipt(sdk, {
1648
+ definitionValue: definition.value,
1649
+ positionReceiptValue: receiptContext.receipt.value,
1650
+ previousPositionReceiptValue: receiptContext.previousEnvelope?.value,
1651
+ positionReceiptChainValues: receiptContext.chainEntries.map((entry) => entry.value),
1652
+ })).report
1653
+ : buildBaseFundReport());
1654
+ const renderedSourceHash = artifact?.source.simfPath && (0, node_fs_1.existsSync)(artifact.source.simfPath)
1655
+ ? (0, summary_1.sha256HexUtf8)(await (0, promises_1.readFile)(artifact.source.simfPath, "utf8"))
1656
+ : undefined;
1657
+ return {
1658
+ schemaVersion: FUND_EVIDENCE_BUNDLE_SCHEMA_VERSION,
1659
+ ...(artifact ? { artifact } : {}),
1660
+ definition: definition.summary,
1661
+ ...(capitalCall ? { capitalCall: capitalCall.summary } : {}),
1662
+ ...(receiptContext?.receipt
1663
+ ? {
1664
+ positionReceipt: receiptContext.receipt.receiptSummary,
1665
+ positionReceiptEnvelope: receiptContext.receipt.envelopeSummary,
1666
+ }
1667
+ : {}),
1668
+ ...(distribution ? { distribution: distribution.summary } : {}),
1669
+ ...(distributions.length > 1 ? { distributions: distributions.map((entry) => entry.summary) } : {}),
1670
+ ...(closing ? { closing: closing.summary } : {}),
1671
+ trust,
1672
+ trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
1673
+ definitionTrust: trust.artifactTrust?.definition,
1674
+ stateTrust: trust.stateTrust,
1675
+ bindingMode: trust.outputBindingTrust?.mode ?? "none",
1676
+ lineageTrust: trust.receiptChainTrust,
1677
+ }),
1678
+ renderedSourceHash,
1679
+ sourceVerificationMode: renderedSourceHash ? "source-reloaded" : "artifact-only",
1680
+ ...(artifact
1681
+ ? {
1682
+ compiled: {
1683
+ program: artifact.compiled.program,
1684
+ cmr: artifact.compiled.cmr,
1685
+ contractAddress: artifact.compiled.contractAddress,
1686
+ },
1687
+ }
1688
+ : {}),
1689
+ };
1690
+ }
1691
+ async function exportFinalityPayload(sdk, input) {
1692
+ const evidence = await exportEvidence(sdk, input);
1693
+ const definition = await loadFundDefinitionDocument(sdk, input);
1694
+ const capitalCall = input.capitalCallPath || input.capitalCallValue ? await loadCapitalCallDocument(sdk, input) : undefined;
1695
+ const receipt = input.positionReceiptPath || input.positionReceiptValue
1696
+ ? await loadPositionReceiptEnvelopeDocument(sdk, input)
1697
+ : undefined;
1698
+ const previousEnvelope = input.previousPositionReceiptPath || input.previousPositionReceiptValue
1699
+ ? await loadPositionReceiptEnvelopeDocument(sdk, {
1700
+ positionReceiptPath: input.previousPositionReceiptPath,
1701
+ positionReceiptValue: input.previousPositionReceiptValue,
1702
+ })
1703
+ : undefined;
1704
+ const chainEntries = input.positionReceiptChainPaths || input.positionReceiptChainValues
1705
+ ? await loadPositionReceiptEnvelopeChainDocuments(sdk, {
1706
+ positionReceiptChainPaths: input.positionReceiptChainPaths,
1707
+ positionReceiptChainValues: input.positionReceiptChainValues,
1708
+ })
1709
+ : [];
1710
+ const receiptContext = receipt || chainEntries.length > 0
1711
+ ? resolveReceiptChainContext({
1712
+ receipt,
1713
+ previousEnvelope,
1714
+ chainEntries,
1715
+ })
1716
+ : undefined;
1717
+ const distributions = input.distributionPath || input.distributionValue || input.distributionPaths || input.distributionValues
1718
+ ? await loadDistributionDocuments(sdk, {
1719
+ distributionPath: input.distributionPath,
1720
+ distributionValue: input.distributionValue,
1721
+ distributionPaths: input.distributionPaths,
1722
+ distributionValues: input.distributionValues,
1723
+ })
1724
+ : [];
1725
+ const distribution = distributions.at(-1);
1726
+ const closing = input.closingPath || input.closingValue
1727
+ ? await loadClosingDocument(sdk, { closingPath: input.closingPath, closingValue: input.closingValue })
1728
+ : undefined;
1729
+ const lpId = closing?.value.lpId ?? distribution?.value.lpId ?? receiptContext?.receipt.value.receipt.lpId ?? capitalCall?.value.lpId;
1730
+ if (!lpId) {
1731
+ throw new errors_1.ValidationError("Finality payload requires at least one LP-linked document", {
1732
+ code: "FUND_FINALITY_LP_ID_REQUIRED",
1733
+ });
1734
+ }
1735
+ return {
1736
+ schemaVersion: FUND_FINALITY_PAYLOAD_SCHEMA_VERSION,
1737
+ fundId: definition.value.fundId,
1738
+ lpId,
1739
+ ...(capitalCall?.value.callId ? { callId: capitalCall.value.callId } : {}),
1740
+ ...(receiptContext?.receipt.value.receipt.positionId ?? distribution?.value.positionId ?? closing?.value.positionId
1741
+ ? {
1742
+ positionId: receiptContext?.receipt.value.receipt.positionId ?? distribution?.value.positionId ?? closing?.value.positionId,
1743
+ }
1744
+ : {}),
1745
+ definitionHash: definition.summary.hash,
1746
+ capitalCallStateHash: capitalCall?.summary.hash ?? null,
1747
+ positionReceiptHash: receiptContext?.receipt.receiptSummary.hash ?? null,
1748
+ positionReceiptEnvelopeHash: receiptContext?.receipt.envelopeSummary.hash ?? null,
1749
+ distributionHash: distribution?.summary.hash ?? null,
1750
+ distributionHashes: distributions.length > 0 ? distributions.map((entry) => entry.summary.hash) : null,
1751
+ closingHash: closing?.summary.hash ?? null,
1752
+ bindingMode: evidence.trust.outputBindingTrust?.mode ?? "none",
1753
+ trust: evidence.trust,
1754
+ trustSummary: evidence.trustSummary,
1755
+ };
1756
+ }