@hazbase/simplicity 0.0.5 → 0.1.1

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