@hazbase/simplicity 0.1.1 → 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.
- package/README.md +139 -1534
- package/dist/cli.js +1107 -1
- package/dist/client/SimplicityClient.d.ts +30 -3
- package/dist/client/SimplicityClient.js +28 -0
- package/dist/core/lineage.d.ts +18 -0
- package/dist/core/lineage.js +30 -0
- package/dist/core/reporting.d.ts +22 -0
- package/dist/core/reporting.js +40 -0
- package/dist/core/schnorr.d.ts +3 -3
- package/dist/core/schnorr.js +19 -7
- package/dist/core/types.d.ts +251 -5
- package/dist/docs/definitions/fund-capital-call-refund-only.simf +36 -2
- package/dist/docs/definitions/receivable-definition.json +9 -0
- package/dist/docs/definitions/receivable-funding-claim.json +13 -0
- package/dist/docs/definitions/receivable-funding-claim.simf +58 -0
- package/dist/docs/definitions/receivable-repayment-claim.json +13 -0
- package/dist/docs/definitions/receivable-repayment-claim.simf +59 -0
- package/dist/docs/definitions/receivable-state-funded.json +20 -0
- package/dist/docs/definitions/receivable-state-originated.json +19 -0
- package/dist/docs/definitions/receivable-state-repaid.json +20 -0
- package/dist/domain/bond.d.ts +82 -15
- package/dist/domain/bond.js +159 -10
- package/dist/domain/bondValidation.d.ts +31 -1
- package/dist/domain/bondValidation.js +73 -9
- package/dist/domain/fund.d.ts +451 -68
- package/dist/domain/fund.js +460 -88
- package/dist/domain/fundValidation.d.ts +33 -3
- package/dist/domain/fundValidation.js +137 -5
- package/dist/domain/policies.d.ts +13 -0
- package/dist/domain/policies.js +50 -30
- package/dist/domain/receivable.d.ts +824 -0
- package/dist/domain/receivable.js +1375 -0
- package/dist/domain/receivableValidation.d.ts +147 -0
- package/dist/domain/receivableValidation.js +831 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +55 -3
- package/package.json +6 -1
|
@@ -0,0 +1,1375 @@
|
|
|
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.verifyStateHistory = verifyStateHistory;
|
|
10
|
+
exports.prepareFunding = prepareFunding;
|
|
11
|
+
exports.verifyFunding = verifyFunding;
|
|
12
|
+
exports.prepareRepayment = prepareRepayment;
|
|
13
|
+
exports.verifyRepayment = verifyRepayment;
|
|
14
|
+
exports.prepareFundingClaim = prepareFundingClaim;
|
|
15
|
+
exports.verifyFundingClaim = verifyFundingClaim;
|
|
16
|
+
exports.inspectFundingClaim = inspectFundingClaim;
|
|
17
|
+
exports.executeFundingClaim = executeFundingClaim;
|
|
18
|
+
exports.prepareRepaymentClaim = prepareRepaymentClaim;
|
|
19
|
+
exports.verifyRepaymentClaim = verifyRepaymentClaim;
|
|
20
|
+
exports.inspectRepaymentClaim = inspectRepaymentClaim;
|
|
21
|
+
exports.executeRepaymentClaim = executeRepaymentClaim;
|
|
22
|
+
exports.prepareWriteOff = prepareWriteOff;
|
|
23
|
+
exports.verifyWriteOff = verifyWriteOff;
|
|
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 node_path_1 = __importDefault(require("node:path"));
|
|
30
|
+
const errors_1 = require("../core/errors");
|
|
31
|
+
const reporting_1 = require("../core/reporting");
|
|
32
|
+
const outputBinding_1 = require("../core/outputBinding");
|
|
33
|
+
const receivableValidation_1 = require("./receivableValidation");
|
|
34
|
+
const RECEIVABLE_VERIFICATION_REPORT_SCHEMA_VERSION = "receivable-verification-report/v1";
|
|
35
|
+
const RECEIVABLE_EVIDENCE_BUNDLE_SCHEMA_VERSION = "receivable-evidence-bundle/v1";
|
|
36
|
+
const RECEIVABLE_FINALITY_PAYLOAD_SCHEMA_VERSION = "receivable-finality-payload/v1";
|
|
37
|
+
function resolveReceivableDocsAsset(filename) {
|
|
38
|
+
const cwdCandidate = node_path_1.default.resolve(process.cwd(), "docs/definitions", filename);
|
|
39
|
+
if ((0, node_fs_1.existsSync)(cwdCandidate))
|
|
40
|
+
return cwdCandidate;
|
|
41
|
+
const bundledCandidate = node_path_1.default.resolve(__dirname, "../docs/definitions", filename);
|
|
42
|
+
if ((0, node_fs_1.existsSync)(bundledCandidate))
|
|
43
|
+
return bundledCandidate;
|
|
44
|
+
return cwdCandidate;
|
|
45
|
+
}
|
|
46
|
+
function satToBtcAmount(sat) {
|
|
47
|
+
return Number((sat / 1e8).toFixed(8));
|
|
48
|
+
}
|
|
49
|
+
function nowIso() {
|
|
50
|
+
return new Date().toISOString();
|
|
51
|
+
}
|
|
52
|
+
function resolveValueOrPath(options) {
|
|
53
|
+
if (options.pathValue)
|
|
54
|
+
return { jsonPath: options.pathValue };
|
|
55
|
+
if (options.objectValue !== undefined)
|
|
56
|
+
return { value: options.objectValue };
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
async function loadReceivableDefinitionDocument(sdk, input) {
|
|
60
|
+
const source = resolveValueOrPath({
|
|
61
|
+
pathValue: input.definitionPath,
|
|
62
|
+
objectValue: input.definitionValue,
|
|
63
|
+
});
|
|
64
|
+
if (!source.jsonPath && source.value === undefined) {
|
|
65
|
+
throw new errors_1.ValidationError("definitionPath or definitionValue is required", {
|
|
66
|
+
code: "RECEIVABLE_DEFINITION_REQUIRED",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const descriptor = await sdk.loadDefinition({
|
|
70
|
+
type: "receivable-definition",
|
|
71
|
+
id: "RECEIVABLE-DEFINITION",
|
|
72
|
+
...source,
|
|
73
|
+
});
|
|
74
|
+
const value = (0, receivableValidation_1.validateReceivableDefinition)(JSON.parse(descriptor.canonicalJson));
|
|
75
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableDefinition)(value) };
|
|
76
|
+
}
|
|
77
|
+
async function loadReceivableStateDocument(sdk, input) {
|
|
78
|
+
const source = resolveValueOrPath({
|
|
79
|
+
pathValue: input.statePath,
|
|
80
|
+
objectValue: input.stateValue,
|
|
81
|
+
});
|
|
82
|
+
if (!source.jsonPath && source.value === undefined) {
|
|
83
|
+
throw new errors_1.ValidationError("statePath or stateValue is required", {
|
|
84
|
+
code: "RECEIVABLE_STATE_REQUIRED",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const descriptor = await sdk.loadStateDocument({
|
|
88
|
+
type: "receivable-state",
|
|
89
|
+
id: "RECEIVABLE-STATE",
|
|
90
|
+
...source,
|
|
91
|
+
});
|
|
92
|
+
const value = (0, receivableValidation_1.validateReceivableState)(JSON.parse(descriptor.canonicalJson));
|
|
93
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableState)(value) };
|
|
94
|
+
}
|
|
95
|
+
async function loadReceivableStateHistoryDocuments(sdk, input) {
|
|
96
|
+
const results = [];
|
|
97
|
+
for (const statePath of input.stateHistoryPaths ?? []) {
|
|
98
|
+
const descriptor = await sdk.loadStateDocument({
|
|
99
|
+
type: "receivable-state",
|
|
100
|
+
id: "RECEIVABLE-STATE-HISTORY",
|
|
101
|
+
jsonPath: statePath,
|
|
102
|
+
});
|
|
103
|
+
const value = (0, receivableValidation_1.validateReceivableState)(JSON.parse(descriptor.canonicalJson));
|
|
104
|
+
results.push({ descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableState)(value) });
|
|
105
|
+
}
|
|
106
|
+
for (const stateValue of input.stateHistoryValues ?? []) {
|
|
107
|
+
const value = (0, receivableValidation_1.validateReceivableState)(stateValue);
|
|
108
|
+
const descriptor = await sdk.loadStateDocument({
|
|
109
|
+
type: "receivable-state",
|
|
110
|
+
id: value.stateId,
|
|
111
|
+
value,
|
|
112
|
+
});
|
|
113
|
+
results.push({ descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableState)(value) });
|
|
114
|
+
}
|
|
115
|
+
return results;
|
|
116
|
+
}
|
|
117
|
+
async function loadReceivableClosingDocument(sdk, input) {
|
|
118
|
+
const source = resolveValueOrPath({
|
|
119
|
+
pathValue: input.closingPath,
|
|
120
|
+
objectValue: input.closingValue,
|
|
121
|
+
});
|
|
122
|
+
if (source.jsonPath || source.value !== undefined) {
|
|
123
|
+
const descriptor = await sdk.loadStateDocument({
|
|
124
|
+
type: "receivable-closing",
|
|
125
|
+
id: input.closingValue?.closingId ?? input.closingId ?? "REC-CLOSE-001",
|
|
126
|
+
...source,
|
|
127
|
+
});
|
|
128
|
+
const value = (0, receivableValidation_1.validateReceivableClosingDescriptor)(JSON.parse(descriptor.canonicalJson));
|
|
129
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableClosingDescriptor)(value) };
|
|
130
|
+
}
|
|
131
|
+
if (!input.latestStateValue || !input.closingId || !input.closedAt) {
|
|
132
|
+
throw new errors_1.ValidationError("closingPath/closingValue or latestState + closingId + closedAt is required", { code: "RECEIVABLE_CLOSING_REQUIRED" });
|
|
133
|
+
}
|
|
134
|
+
const value = (0, receivableValidation_1.buildReceivableClosingDescriptor)({
|
|
135
|
+
closingId: input.closingId,
|
|
136
|
+
latestState: input.latestStateValue,
|
|
137
|
+
closedAt: input.closedAt,
|
|
138
|
+
...(input.closingReason ? { closingReason: input.closingReason } : {}),
|
|
139
|
+
});
|
|
140
|
+
const descriptor = await sdk.loadStateDocument({
|
|
141
|
+
type: "receivable-closing",
|
|
142
|
+
id: value.closingId,
|
|
143
|
+
value,
|
|
144
|
+
});
|
|
145
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableClosingDescriptor)(value) };
|
|
146
|
+
}
|
|
147
|
+
function assertLatestStateMatchesHistoryTip(input) {
|
|
148
|
+
if (!input.latestState || input.history.length === 0)
|
|
149
|
+
return;
|
|
150
|
+
const historyTip = input.history.at(-1);
|
|
151
|
+
if (!historyTip)
|
|
152
|
+
return;
|
|
153
|
+
if (historyTip.summary.hash !== input.latestState.summary.hash) {
|
|
154
|
+
throw new errors_1.ValidationError("latest receivable state must match the tip of the provided state history", {
|
|
155
|
+
code: "RECEIVABLE_HISTORY_TIP_MISMATCH",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function validateReceivablePayoutDescriptor(descriptor) {
|
|
160
|
+
if (!descriptor.receiverAddress || descriptor.receiverAddress.trim().length === 0) {
|
|
161
|
+
throw new errors_1.ValidationError("receiverAddress must be a non-empty string", {
|
|
162
|
+
code: "RECEIVABLE_PAYOUT_RECEIVER_REQUIRED",
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (!Number.isInteger(descriptor.amountSat) || descriptor.amountSat <= 0) {
|
|
166
|
+
throw new errors_1.ValidationError("amountSat must be a positive integer", {
|
|
167
|
+
code: "RECEIVABLE_PAYOUT_AMOUNT_INVALID",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
if (!descriptor.assetId || descriptor.assetId.trim().length === 0) {
|
|
171
|
+
throw new errors_1.ValidationError("assetId must be a non-empty string", {
|
|
172
|
+
code: "RECEIVABLE_PAYOUT_ASSET_REQUIRED",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (!Number.isInteger(descriptor.feeIndex) || descriptor.feeIndex < 0) {
|
|
176
|
+
throw new errors_1.ValidationError("feeIndex must be a non-negative integer", {
|
|
177
|
+
code: "RECEIVABLE_PAYOUT_FEE_INDEX_INVALID",
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (!Number.isInteger(descriptor.nextOutputIndex) || descriptor.nextOutputIndex < 0) {
|
|
181
|
+
throw new errors_1.ValidationError("nextOutputIndex must be a non-negative integer", {
|
|
182
|
+
code: "RECEIVABLE_PAYOUT_NEXT_OUTPUT_INDEX_INVALID",
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (!Number.isInteger(descriptor.maxFeeSat) || descriptor.maxFeeSat < 0) {
|
|
186
|
+
throw new errors_1.ValidationError("maxFeeSat must be a non-negative integer", {
|
|
187
|
+
code: "RECEIVABLE_PAYOUT_MAX_FEE_INVALID",
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (!["none", "script-bound", "descriptor-bound"].includes(descriptor.outputBindingMode)) {
|
|
191
|
+
throw new errors_1.ValidationError("outputBindingMode must be none, script-bound, or descriptor-bound", {
|
|
192
|
+
code: "RECEIVABLE_PAYOUT_BINDING_MODE_INVALID",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (descriptor.requestedOutputBindingMode
|
|
196
|
+
&& !["none", "script-bound", "descriptor-bound"].includes(descriptor.requestedOutputBindingMode)) {
|
|
197
|
+
throw new errors_1.ValidationError("requestedOutputBindingMode must be none, script-bound, or descriptor-bound", {
|
|
198
|
+
code: "RECEIVABLE_PAYOUT_REQUESTED_BINDING_MODE_INVALID",
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (descriptor.nextOutputHash && !/^[0-9a-f]{64}$/i.test(descriptor.nextOutputHash)) {
|
|
202
|
+
throw new errors_1.ValidationError("nextOutputHash must be a 64-character hex string", {
|
|
203
|
+
code: "RECEIVABLE_PAYOUT_OUTPUT_HASH_INVALID",
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (descriptor.nextOutputScriptHash && !/^[0-9a-f]{64}$/i.test(descriptor.nextOutputScriptHash)) {
|
|
207
|
+
throw new errors_1.ValidationError("nextOutputScriptHash must be a 64-character hex string", {
|
|
208
|
+
code: "RECEIVABLE_PAYOUT_OUTPUT_SCRIPT_HASH_INVALID",
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
descriptor.rawOutput = (0, outputBinding_1.normalizeOutputRawFields)(descriptor.rawOutput);
|
|
212
|
+
descriptor.outputForm = (0, outputBinding_1.normalizeOutputForm)(descriptor.outputForm);
|
|
213
|
+
descriptor.requestedOutputBindingMode = descriptor.requestedOutputBindingMode ?? descriptor.outputBindingMode;
|
|
214
|
+
return descriptor;
|
|
215
|
+
}
|
|
216
|
+
function buildBindingModeWitnessValue(mode) {
|
|
217
|
+
return mode === "descriptor-bound" ? "0x01" : mode === "script-bound" ? "0x02" : "0x03";
|
|
218
|
+
}
|
|
219
|
+
function buildReceivableClaimWitness(descriptor) {
|
|
220
|
+
return {
|
|
221
|
+
values: {
|
|
222
|
+
EXPECTED_PAYOUT_OUTPUT_HASH: {
|
|
223
|
+
type: "u256",
|
|
224
|
+
value: `0x${descriptor.nextOutputHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
|
|
225
|
+
},
|
|
226
|
+
EXPECTED_PAYOUT_OUTPUT_SCRIPT_HASH: {
|
|
227
|
+
type: "u256",
|
|
228
|
+
value: `0x${descriptor.nextOutputScriptHash ?? "0000000000000000000000000000000000000000000000000000000000000000"}`,
|
|
229
|
+
},
|
|
230
|
+
OUTPUT_BINDING_MODE: {
|
|
231
|
+
type: "u8",
|
|
232
|
+
value: buildBindingModeWitnessValue(descriptor.outputBindingMode),
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
async function buildReceivablePayoutDescriptor(sdk, input) {
|
|
238
|
+
const nextScriptPubKeyHex = await (0, outputBinding_1.getScriptPubKeyHexViaRpc)(sdk, input.receiverAddress);
|
|
239
|
+
const nextOutputScriptHash = (0, outputBinding_1.hashHexBytes)(nextScriptPubKeyHex);
|
|
240
|
+
const requestedBindingMode = input.outputBindingMode ?? "descriptor-bound";
|
|
241
|
+
const outputForm = (0, outputBinding_1.normalizeOutputForm)(input.outputForm);
|
|
242
|
+
const rawOutput = (0, outputBinding_1.normalizeOutputRawFields)(input.rawOutput);
|
|
243
|
+
const rawOutputAnalysis = (0, outputBinding_1.analyzeOutputRawFields)(rawOutput);
|
|
244
|
+
const explicitAssetHex = requestedBindingMode !== "none" && (0, outputBinding_1.isExplicitV1OutputForm)(outputForm)
|
|
245
|
+
? await (0, outputBinding_1.resolveExplicitAssetHex)(sdk, input.assetId)
|
|
246
|
+
: undefined;
|
|
247
|
+
const autoDerivedNextOutputHash = requestedBindingMode === "descriptor-bound" && !input.nextOutputHash
|
|
248
|
+
? rawOutputAnalysis.valid && rawOutputAnalysis.normalized
|
|
249
|
+
? (0, outputBinding_1.computeRawOutputV1Hash)(rawOutputAnalysis.normalized)
|
|
250
|
+
: explicitAssetHex
|
|
251
|
+
? (0, outputBinding_1.computeExplicitV1OutputHash)({
|
|
252
|
+
assetHex: explicitAssetHex,
|
|
253
|
+
nextAmountSat: input.amountSat,
|
|
254
|
+
nextOutputScriptHash,
|
|
255
|
+
})
|
|
256
|
+
: undefined
|
|
257
|
+
: undefined;
|
|
258
|
+
const nextOutputHash = input.nextOutputHash ?? autoDerivedNextOutputHash;
|
|
259
|
+
const bindingResolution = (0, outputBinding_1.resolveOutputBindingDecision)({
|
|
260
|
+
requestedBindingMode,
|
|
261
|
+
nextOutputHash,
|
|
262
|
+
nextOutputScriptHash,
|
|
263
|
+
autoDerivedNextOutputHash: Boolean(autoDerivedNextOutputHash && !input.nextOutputHash),
|
|
264
|
+
explicitAssetSupported: Boolean(explicitAssetHex),
|
|
265
|
+
outputForm,
|
|
266
|
+
rawOutput,
|
|
267
|
+
});
|
|
268
|
+
const descriptor = validateReceivablePayoutDescriptor({
|
|
269
|
+
receiverAddress: input.receiverAddress,
|
|
270
|
+
nextOutputHash: bindingResolution.outputBindingMode === "descriptor-bound" ? nextOutputHash : undefined,
|
|
271
|
+
nextOutputScriptHash: bindingResolution.outputBindingMode !== "none" ? nextOutputScriptHash : undefined,
|
|
272
|
+
amountSat: input.amountSat,
|
|
273
|
+
assetId: input.assetId,
|
|
274
|
+
requestedOutputBindingMode: requestedBindingMode,
|
|
275
|
+
outputForm,
|
|
276
|
+
rawOutput,
|
|
277
|
+
feeIndex: input.feeIndex ?? 1,
|
|
278
|
+
nextOutputIndex: input.nextOutputIndex ?? 0,
|
|
279
|
+
maxFeeSat: input.maxFeeSat ?? 100,
|
|
280
|
+
outputBindingMode: bindingResolution.outputBindingMode,
|
|
281
|
+
});
|
|
282
|
+
const bindingInputs = {
|
|
283
|
+
assetId: descriptor.assetId,
|
|
284
|
+
assetForm: descriptor.outputForm?.assetForm ?? "explicit",
|
|
285
|
+
amountForm: descriptor.outputForm?.amountForm ?? "explicit",
|
|
286
|
+
nonceForm: descriptor.outputForm?.nonceForm ?? "null",
|
|
287
|
+
rangeProofForm: descriptor.outputForm?.rangeProofForm ?? "empty",
|
|
288
|
+
nextAmountSat: descriptor.amountSat,
|
|
289
|
+
nextOutputIndex: descriptor.nextOutputIndex,
|
|
290
|
+
feeIndex: descriptor.feeIndex,
|
|
291
|
+
maxFeeSat: descriptor.maxFeeSat,
|
|
292
|
+
...(rawOutputAnalysis.valid && rawOutputAnalysis.normalized
|
|
293
|
+
? {
|
|
294
|
+
rawOutputComponents: {
|
|
295
|
+
scriptPubKey: rawOutputAnalysis.normalized.scriptComponentSource,
|
|
296
|
+
rangeProof: rawOutputAnalysis.normalized.rangeProofComponentSource,
|
|
297
|
+
},
|
|
298
|
+
}
|
|
299
|
+
: {}),
|
|
300
|
+
};
|
|
301
|
+
return {
|
|
302
|
+
descriptor,
|
|
303
|
+
supportedForm: bindingResolution.supportedForm,
|
|
304
|
+
autoDerivedNextOutputHash: bindingResolution.autoDerived,
|
|
305
|
+
reasonCode: bindingResolution.reasonCode,
|
|
306
|
+
fallbackReason: bindingResolution.fallbackReason,
|
|
307
|
+
bindingInputs,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function buildReceivableStateLineageTrust(checks) {
|
|
311
|
+
const identityConsistent = checks.receivableIdConsistent
|
|
312
|
+
&& checks.originatorConsistent
|
|
313
|
+
&& checks.debtorConsistent
|
|
314
|
+
&& checks.currencyConsistent
|
|
315
|
+
&& checks.controllerConsistent
|
|
316
|
+
&& checks.faceValueConsistent;
|
|
317
|
+
return {
|
|
318
|
+
...(0, reporting_1.buildLineageTrustBase)({
|
|
319
|
+
lineageKind: "state-history",
|
|
320
|
+
chainLength: checks.chainLength,
|
|
321
|
+
latestOrdinal: Math.max(0, checks.chainLength - 1),
|
|
322
|
+
allHashLinksVerified: checks.allPreviousStateHashMatch,
|
|
323
|
+
identityConsistent,
|
|
324
|
+
fullLineageVerified: checks.fullHistoryVerified,
|
|
325
|
+
}),
|
|
326
|
+
latestStatus: checks.latestStatus,
|
|
327
|
+
startsAtGenesis: checks.startsAtGenesis,
|
|
328
|
+
receivableIdConsistent: checks.receivableIdConsistent,
|
|
329
|
+
originatorConsistent: checks.originatorConsistent,
|
|
330
|
+
debtorConsistent: checks.debtorConsistent,
|
|
331
|
+
currencyConsistent: checks.currencyConsistent,
|
|
332
|
+
controllerConsistent: checks.controllerConsistent,
|
|
333
|
+
faceValueConsistent: checks.faceValueConsistent,
|
|
334
|
+
allPreviousStateHashMatch: checks.allPreviousStateHashMatch,
|
|
335
|
+
allArithmeticValid: checks.allArithmeticValid,
|
|
336
|
+
allStatusProgressionValid: checks.allStatusProgressionValid,
|
|
337
|
+
fullHistoryVerified: checks.fullHistoryVerified,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
async function requireReceivableArtifact(sdk, input) {
|
|
341
|
+
const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
|
|
342
|
+
if (!artifact) {
|
|
343
|
+
throw new errors_1.ValidationError("artifactPath or artifact is required", {
|
|
344
|
+
code: "RECEIVABLE_ARTIFACT_REQUIRED",
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
return artifact;
|
|
348
|
+
}
|
|
349
|
+
function buildReceivableClaimTrust(input) {
|
|
350
|
+
const bindingMode = input.payout?.descriptor.outputBindingMode ?? "none";
|
|
351
|
+
return {
|
|
352
|
+
...input.checks,
|
|
353
|
+
generated: input.generated,
|
|
354
|
+
claimantXonlyCommitted: input.claimantXonlyCommitted,
|
|
355
|
+
bindingMode,
|
|
356
|
+
requestedMode: input.payout?.descriptor.requestedOutputBindingMode,
|
|
357
|
+
supportedForm: input.payout?.supportedForm ?? "unsupported",
|
|
358
|
+
reasonCode: input.payout?.reasonCode
|
|
359
|
+
?? (bindingMode === "descriptor-bound"
|
|
360
|
+
? "OK_MANUAL_HASH"
|
|
361
|
+
: bindingMode === "script-bound"
|
|
362
|
+
? "OK_SCRIPT_BOUND"
|
|
363
|
+
: "OK_NONE"),
|
|
364
|
+
nextReceiverRuntimeCommitted: bindingMode !== "none",
|
|
365
|
+
nextOutputHashRuntimeBound: bindingMode === "descriptor-bound",
|
|
366
|
+
nextOutputScriptRuntimeBound: bindingMode !== "none",
|
|
367
|
+
amountRuntimeBound: bindingMode === "descriptor-bound",
|
|
368
|
+
autoDerived: input.payout?.autoDerivedNextOutputHash,
|
|
369
|
+
fallbackReason: input.payout?.fallbackReason,
|
|
370
|
+
bindingInputs: input.payout?.bindingInputs,
|
|
371
|
+
fullClaimVerified: input.checks.fullClaimVerified && input.claimantXonlyCommitted,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function buildReceivableReport(input) {
|
|
375
|
+
return {
|
|
376
|
+
schemaVersion: RECEIVABLE_VERIFICATION_REPORT_SCHEMA_VERSION,
|
|
377
|
+
receivableTrust: {
|
|
378
|
+
...input.crossChecks,
|
|
379
|
+
statusValid: true,
|
|
380
|
+
},
|
|
381
|
+
...(input.transitionTrust ? { transitionTrust: input.transitionTrust } : {}),
|
|
382
|
+
...(input.closingTrust ? { closingTrust: input.closingTrust } : {}),
|
|
383
|
+
...(input.fundingClaimTrust ? { fundingClaimTrust: input.fundingClaimTrust } : {}),
|
|
384
|
+
...(input.repaymentClaimTrust ? { repaymentClaimTrust: input.repaymentClaimTrust } : {}),
|
|
385
|
+
...(input.lineageChecks ? { stateLineageTrust: buildReceivableStateLineageTrust(input.lineageChecks) } : {}),
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
async function define(sdk, input) {
|
|
389
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
390
|
+
return {
|
|
391
|
+
ok: true,
|
|
392
|
+
definition: definition.descriptor,
|
|
393
|
+
definitionValue: definition.value,
|
|
394
|
+
summary: definition.summary,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
async function verify(sdk, input) {
|
|
398
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
399
|
+
const state = await loadReceivableStateDocument(sdk, input);
|
|
400
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, state.value);
|
|
401
|
+
const report = buildReceivableReport({ crossChecks });
|
|
402
|
+
return {
|
|
403
|
+
verified: Object.values(crossChecks).every(Boolean),
|
|
404
|
+
definition: definition.descriptor,
|
|
405
|
+
definitionValue: definition.value,
|
|
406
|
+
definitionSummary: definition.summary,
|
|
407
|
+
state: state.descriptor,
|
|
408
|
+
stateValue: state.value,
|
|
409
|
+
stateSummary: state.summary,
|
|
410
|
+
crossChecks,
|
|
411
|
+
report,
|
|
412
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
413
|
+
bindingMode: "none",
|
|
414
|
+
}),
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
async function load(sdk, input) {
|
|
418
|
+
const verification = await verify(sdk, input);
|
|
419
|
+
return {
|
|
420
|
+
definition: verification.definition,
|
|
421
|
+
definitionValue: verification.definitionValue,
|
|
422
|
+
definitionSummary: verification.definitionSummary,
|
|
423
|
+
state: verification.state,
|
|
424
|
+
stateValue: verification.stateValue,
|
|
425
|
+
stateSummary: verification.stateSummary,
|
|
426
|
+
crossChecks: verification.crossChecks,
|
|
427
|
+
report: verification.report,
|
|
428
|
+
trustSummary: verification.trustSummary,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
async function verifyStateHistory(sdk, input) {
|
|
432
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
433
|
+
const stateHistory = await loadReceivableStateHistoryDocuments(sdk, input);
|
|
434
|
+
const latest = stateHistory.at(-1);
|
|
435
|
+
if (!latest) {
|
|
436
|
+
throw new errors_1.ValidationError("stateHistoryPaths or stateHistoryValues must contain at least one state", {
|
|
437
|
+
code: "RECEIVABLE_STATE_HISTORY_REQUIRED",
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, latest.value);
|
|
441
|
+
const checks = (0, receivableValidation_1.verifyReceivableStateHistory)({
|
|
442
|
+
history: stateHistory.map((entry) => entry.value),
|
|
443
|
+
});
|
|
444
|
+
const lineageTrust = buildReceivableStateLineageTrust(checks);
|
|
445
|
+
const report = buildReceivableReport({
|
|
446
|
+
crossChecks,
|
|
447
|
+
lineageChecks: checks,
|
|
448
|
+
});
|
|
449
|
+
return {
|
|
450
|
+
verified: checks.fullHistoryVerified && Object.values(crossChecks).every(Boolean),
|
|
451
|
+
definition: definition.descriptor,
|
|
452
|
+
definitionValue: definition.value,
|
|
453
|
+
definitionSummary: definition.summary,
|
|
454
|
+
latestState: latest.descriptor,
|
|
455
|
+
latestStateValue: latest.value,
|
|
456
|
+
latestStateSummary: latest.summary,
|
|
457
|
+
stateHistory: stateHistory.map((entry) => entry.descriptor),
|
|
458
|
+
stateHistoryValues: stateHistory.map((entry) => entry.value),
|
|
459
|
+
stateHistorySummaries: stateHistory.map((entry) => entry.summary),
|
|
460
|
+
checks,
|
|
461
|
+
report,
|
|
462
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
463
|
+
bindingMode: "none",
|
|
464
|
+
lineageTrust,
|
|
465
|
+
}),
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
async function loadPreviousAndNextReceivableStates(sdk, input) {
|
|
469
|
+
const previous = await loadReceivableStateDocument(sdk, {
|
|
470
|
+
statePath: input.previousStatePath,
|
|
471
|
+
stateValue: input.previousStateValue,
|
|
472
|
+
});
|
|
473
|
+
const next = await loadReceivableStateDocument(sdk, {
|
|
474
|
+
statePath: input.nextStatePath,
|
|
475
|
+
stateValue: input.nextStateValue,
|
|
476
|
+
});
|
|
477
|
+
return { previous, next };
|
|
478
|
+
}
|
|
479
|
+
function buildTransitionVerificationResult(input) {
|
|
480
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(input.definition.value, input.next.value);
|
|
481
|
+
const report = buildReceivableReport({
|
|
482
|
+
crossChecks,
|
|
483
|
+
transitionTrust: input.transitionTrust,
|
|
484
|
+
});
|
|
485
|
+
return {
|
|
486
|
+
verified: input.transitionTrust.fullTransitionVerified && Object.values(crossChecks).every(Boolean),
|
|
487
|
+
definition: input.definition.descriptor,
|
|
488
|
+
definitionValue: input.definition.value,
|
|
489
|
+
definitionSummary: input.definition.summary,
|
|
490
|
+
previousState: input.previous.descriptor,
|
|
491
|
+
previousStateValue: input.previous.value,
|
|
492
|
+
previousStateSummary: input.previous.summary,
|
|
493
|
+
nextState: input.next.descriptor,
|
|
494
|
+
nextStateValue: input.next.value,
|
|
495
|
+
nextStateSummary: input.next.summary,
|
|
496
|
+
report,
|
|
497
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
498
|
+
bindingMode: "none",
|
|
499
|
+
}),
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
async function prepareFunding(sdk, input) {
|
|
503
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
504
|
+
const previous = await loadReceivableStateDocument(sdk, {
|
|
505
|
+
statePath: input.previousStatePath,
|
|
506
|
+
stateValue: input.previousStateValue,
|
|
507
|
+
});
|
|
508
|
+
const next = input.nextStatePath || input.nextStateValue
|
|
509
|
+
? await loadReceivableStateDocument(sdk, {
|
|
510
|
+
statePath: input.nextStatePath,
|
|
511
|
+
stateValue: input.nextStateValue,
|
|
512
|
+
})
|
|
513
|
+
: await loadReceivableStateDocument(sdk, {
|
|
514
|
+
stateValue: (0, receivableValidation_1.buildFundedReceivableState)({
|
|
515
|
+
previous: previous.value,
|
|
516
|
+
stateId: input.stateId ?? `${previous.value.receivableId}-FUNDED`,
|
|
517
|
+
holderEntityId: input.holderEntityId ?? previous.value.holderEntityId,
|
|
518
|
+
fundedAt: input.fundedAt ?? new Date().toISOString(),
|
|
519
|
+
}),
|
|
520
|
+
});
|
|
521
|
+
const transitionTrust = (0, receivableValidation_1.validateReceivableFundingTransition)(previous.value, next.value);
|
|
522
|
+
return buildTransitionVerificationResult({
|
|
523
|
+
definition,
|
|
524
|
+
previous,
|
|
525
|
+
next,
|
|
526
|
+
transitionTrust,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
async function loadReceivableFundingClaimDocument(sdk, input) {
|
|
530
|
+
const source = resolveValueOrPath({
|
|
531
|
+
pathValue: input.fundingClaimPath,
|
|
532
|
+
objectValue: input.fundingClaimValue,
|
|
533
|
+
});
|
|
534
|
+
if (source.jsonPath || source.value !== undefined) {
|
|
535
|
+
const descriptor = await sdk.loadStateDocument({
|
|
536
|
+
type: "receivable-funding-claim",
|
|
537
|
+
id: input.fundingClaimValue?.claimId ?? input.claimId ?? "REC-FUNDING-CLAIM-001",
|
|
538
|
+
...source,
|
|
539
|
+
});
|
|
540
|
+
const value = (0, receivableValidation_1.validateReceivableFundingClaimDescriptor)(JSON.parse(descriptor.canonicalJson));
|
|
541
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableFundingClaimDescriptor)(value) };
|
|
542
|
+
}
|
|
543
|
+
if (!input.currentStateValue || !input.claimId) {
|
|
544
|
+
throw new errors_1.ValidationError("fundingClaimPath/fundingClaimValue or currentStateValue + claimId is required", { code: "RECEIVABLE_FUNDING_CLAIM_REQUIRED" });
|
|
545
|
+
}
|
|
546
|
+
const value = (0, receivableValidation_1.buildReceivableFundingClaimDescriptor)({
|
|
547
|
+
claimId: input.claimId,
|
|
548
|
+
currentState: input.currentStateValue,
|
|
549
|
+
payerEntityId: input.payerEntityId,
|
|
550
|
+
payeeEntityId: input.payeeEntityId,
|
|
551
|
+
claimantXonly: input.claimantXonly,
|
|
552
|
+
amountSat: input.amountSat,
|
|
553
|
+
eventTimestamp: input.eventTimestamp,
|
|
554
|
+
});
|
|
555
|
+
const descriptor = await sdk.loadStateDocument({
|
|
556
|
+
type: "receivable-funding-claim",
|
|
557
|
+
id: value.claimId,
|
|
558
|
+
value,
|
|
559
|
+
});
|
|
560
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableFundingClaimDescriptor)(value) };
|
|
561
|
+
}
|
|
562
|
+
async function loadReceivableRepaymentClaimDocument(sdk, input) {
|
|
563
|
+
const source = resolveValueOrPath({
|
|
564
|
+
pathValue: input.repaymentClaimPath,
|
|
565
|
+
objectValue: input.repaymentClaimValue,
|
|
566
|
+
});
|
|
567
|
+
if (source.jsonPath || source.value !== undefined) {
|
|
568
|
+
const descriptor = await sdk.loadStateDocument({
|
|
569
|
+
type: "receivable-repayment-claim",
|
|
570
|
+
id: input.repaymentClaimValue?.claimId ?? input.claimId ?? "REC-REPAYMENT-CLAIM-001",
|
|
571
|
+
...source,
|
|
572
|
+
});
|
|
573
|
+
const value = (0, receivableValidation_1.validateReceivableRepaymentClaimDescriptor)(JSON.parse(descriptor.canonicalJson));
|
|
574
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableRepaymentClaimDescriptor)(value) };
|
|
575
|
+
}
|
|
576
|
+
if (!input.currentStateValue || !input.claimId) {
|
|
577
|
+
throw new errors_1.ValidationError("repaymentClaimPath/repaymentClaimValue or currentStateValue + claimId is required", { code: "RECEIVABLE_REPAYMENT_CLAIM_REQUIRED" });
|
|
578
|
+
}
|
|
579
|
+
const value = (0, receivableValidation_1.buildReceivableRepaymentClaimDescriptor)({
|
|
580
|
+
claimId: input.claimId,
|
|
581
|
+
currentState: input.currentStateValue,
|
|
582
|
+
payerEntityId: input.payerEntityId,
|
|
583
|
+
payeeEntityId: input.payeeEntityId,
|
|
584
|
+
claimantXonly: input.claimantXonly,
|
|
585
|
+
amountSat: input.amountSat,
|
|
586
|
+
eventTimestamp: input.eventTimestamp,
|
|
587
|
+
});
|
|
588
|
+
const descriptor = await sdk.loadStateDocument({
|
|
589
|
+
type: "receivable-repayment-claim",
|
|
590
|
+
id: value.claimId,
|
|
591
|
+
value,
|
|
592
|
+
});
|
|
593
|
+
return { descriptor, value, summary: (0, receivableValidation_1.summarizeReceivableRepaymentClaimDescriptor)(value) };
|
|
594
|
+
}
|
|
595
|
+
async function compileFundingClaimContract(sdk, input) {
|
|
596
|
+
return sdk.compileFromFile({
|
|
597
|
+
simfPath: input.simfPath ?? resolveReceivableDocsAsset("receivable-funding-claim.simf"),
|
|
598
|
+
templateVars: {
|
|
599
|
+
CLAIMANT_XONLY: input.claim.claimantXonly,
|
|
600
|
+
},
|
|
601
|
+
definition: {
|
|
602
|
+
type: "receivable-definition",
|
|
603
|
+
id: input.definition.receivableId,
|
|
604
|
+
value: input.definition,
|
|
605
|
+
anchorMode: "on-chain-constant-committed",
|
|
606
|
+
},
|
|
607
|
+
state: {
|
|
608
|
+
type: "receivable-funding-claim",
|
|
609
|
+
id: input.claim.claimId,
|
|
610
|
+
value: input.claim,
|
|
611
|
+
anchorMode: "on-chain-constant-committed",
|
|
612
|
+
},
|
|
613
|
+
artifactPath: input.artifactPath,
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
async function compileRepaymentClaimContract(sdk, input) {
|
|
617
|
+
return sdk.compileFromFile({
|
|
618
|
+
simfPath: input.simfPath ?? resolveReceivableDocsAsset("receivable-repayment-claim.simf"),
|
|
619
|
+
templateVars: {
|
|
620
|
+
CLAIMANT_XONLY: input.claim.claimantXonly,
|
|
621
|
+
},
|
|
622
|
+
definition: {
|
|
623
|
+
type: "receivable-definition",
|
|
624
|
+
id: input.definition.receivableId,
|
|
625
|
+
value: input.definition,
|
|
626
|
+
anchorMode: "on-chain-constant-committed",
|
|
627
|
+
},
|
|
628
|
+
state: {
|
|
629
|
+
type: "receivable-repayment-claim",
|
|
630
|
+
id: input.claim.claimId,
|
|
631
|
+
value: input.claim,
|
|
632
|
+
anchorMode: "on-chain-constant-committed",
|
|
633
|
+
},
|
|
634
|
+
artifactPath: input.artifactPath,
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
async function verifyFunding(sdk, input) {
|
|
638
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
639
|
+
const { previous, next } = await loadPreviousAndNextReceivableStates(sdk, input);
|
|
640
|
+
const transitionTrust = (0, receivableValidation_1.validateReceivableFundingTransition)(previous.value, next.value);
|
|
641
|
+
return buildTransitionVerificationResult({
|
|
642
|
+
definition,
|
|
643
|
+
previous,
|
|
644
|
+
next,
|
|
645
|
+
transitionTrust,
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
async function prepareRepayment(sdk, input) {
|
|
649
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
650
|
+
const previous = await loadReceivableStateDocument(sdk, {
|
|
651
|
+
statePath: input.previousStatePath,
|
|
652
|
+
stateValue: input.previousStateValue,
|
|
653
|
+
});
|
|
654
|
+
const next = input.nextStatePath || input.nextStateValue
|
|
655
|
+
? await loadReceivableStateDocument(sdk, {
|
|
656
|
+
statePath: input.nextStatePath,
|
|
657
|
+
stateValue: input.nextStateValue,
|
|
658
|
+
})
|
|
659
|
+
: await loadReceivableStateDocument(sdk, {
|
|
660
|
+
stateValue: (0, receivableValidation_1.applyReceivableRepayment)({
|
|
661
|
+
previous: previous.value,
|
|
662
|
+
stateId: input.stateId ?? `${previous.value.receivableId}-REPAY-${previous.value.repaidAmount + (input.amount ?? 0)}`,
|
|
663
|
+
amount: input.amount ?? previous.value.outstandingAmount,
|
|
664
|
+
repaidAt: input.repaidAt ?? new Date().toISOString(),
|
|
665
|
+
}),
|
|
666
|
+
});
|
|
667
|
+
const transitionTrust = (0, receivableValidation_1.validateReceivableRepaymentTransition)(previous.value, next.value);
|
|
668
|
+
return buildTransitionVerificationResult({
|
|
669
|
+
definition,
|
|
670
|
+
previous,
|
|
671
|
+
next,
|
|
672
|
+
transitionTrust,
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
async function verifyRepayment(sdk, input) {
|
|
676
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
677
|
+
const { previous, next } = await loadPreviousAndNextReceivableStates(sdk, input);
|
|
678
|
+
const transitionTrust = (0, receivableValidation_1.validateReceivableRepaymentTransition)(previous.value, next.value);
|
|
679
|
+
return buildTransitionVerificationResult({
|
|
680
|
+
definition,
|
|
681
|
+
previous,
|
|
682
|
+
next,
|
|
683
|
+
transitionTrust,
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
function buildClaimVerificationResult(input) {
|
|
687
|
+
return {
|
|
688
|
+
verified: input.verified,
|
|
689
|
+
artifact: input.artifact,
|
|
690
|
+
artifactVerification: input.artifactVerification,
|
|
691
|
+
definition: input.definition.descriptor,
|
|
692
|
+
definitionValue: input.definition.value,
|
|
693
|
+
definitionSummary: input.definition.summary,
|
|
694
|
+
currentState: input.currentState.descriptor,
|
|
695
|
+
currentStateValue: input.currentState.value,
|
|
696
|
+
currentStateSummary: input.currentState.summary,
|
|
697
|
+
...(input.stateHistory && input.stateHistory.length > 0
|
|
698
|
+
? {
|
|
699
|
+
stateHistory: input.stateHistory.map((entry) => entry.descriptor),
|
|
700
|
+
stateHistoryValues: input.stateHistory.map((entry) => entry.value),
|
|
701
|
+
stateHistorySummaries: input.stateHistory.map((entry) => entry.summary),
|
|
702
|
+
}
|
|
703
|
+
: {}),
|
|
704
|
+
claim: input.claim.descriptor,
|
|
705
|
+
claimValue: input.claim.value,
|
|
706
|
+
claimSummary: input.claim.summary,
|
|
707
|
+
report: input.report,
|
|
708
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
709
|
+
bindingMode: input.report.fundingClaimTrust?.bindingMode
|
|
710
|
+
?? input.report.repaymentClaimTrust?.bindingMode
|
|
711
|
+
?? "none",
|
|
712
|
+
...(input.report.stateLineageTrust ? { lineageTrust: input.report.stateLineageTrust } : {}),
|
|
713
|
+
...(input.artifactVerification?.definition?.trust ? { definitionTrust: input.artifactVerification.definition.trust } : {}),
|
|
714
|
+
...(input.artifactVerification?.state?.trust ? { stateTrust: input.artifactVerification.state.trust } : {}),
|
|
715
|
+
}),
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
async function prepareFundingClaim(sdk, input) {
|
|
719
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
720
|
+
const currentState = await loadReceivableStateDocument(sdk, {
|
|
721
|
+
statePath: input.currentStatePath,
|
|
722
|
+
stateValue: input.currentStateValue,
|
|
723
|
+
});
|
|
724
|
+
const history = input.stateHistoryPaths || input.stateHistoryValues
|
|
725
|
+
? await loadReceivableStateHistoryDocuments(sdk, input)
|
|
726
|
+
: [];
|
|
727
|
+
assertLatestStateMatchesHistoryTip({ latestState: currentState, history });
|
|
728
|
+
const claim = await loadReceivableFundingClaimDocument(sdk, {
|
|
729
|
+
fundingClaimPath: input.fundingClaimPath,
|
|
730
|
+
fundingClaimValue: input.fundingClaimValue,
|
|
731
|
+
currentStateValue: currentState.value,
|
|
732
|
+
claimId: input.claimId ?? `${currentState.value.receivableId}-FUNDING-CLAIM`,
|
|
733
|
+
payerEntityId: input.payerEntityId,
|
|
734
|
+
payeeEntityId: input.payeeEntityId,
|
|
735
|
+
claimantXonly: input.claimantXonly,
|
|
736
|
+
amountSat: input.amountSat,
|
|
737
|
+
eventTimestamp: input.eventTimestamp,
|
|
738
|
+
});
|
|
739
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, currentState.value);
|
|
740
|
+
const lineageChecks = history.length > 0
|
|
741
|
+
? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
|
|
742
|
+
: undefined;
|
|
743
|
+
const claimChecks = (0, receivableValidation_1.validateReceivableFundingClaimAgainstState)({
|
|
744
|
+
currentState: currentState.value,
|
|
745
|
+
claim: claim.value,
|
|
746
|
+
});
|
|
747
|
+
const report = buildReceivableReport({
|
|
748
|
+
crossChecks,
|
|
749
|
+
...(lineageChecks ? { lineageChecks } : {}),
|
|
750
|
+
fundingClaimTrust: buildReceivableClaimTrust({
|
|
751
|
+
generated: !input.fundingClaimPath && !input.fundingClaimValue,
|
|
752
|
+
claimantXonlyCommitted: true,
|
|
753
|
+
checks: claimChecks,
|
|
754
|
+
}),
|
|
755
|
+
});
|
|
756
|
+
const compiled = await compileFundingClaimContract(sdk, {
|
|
757
|
+
definition: definition.value,
|
|
758
|
+
claim: claim.value,
|
|
759
|
+
simfPath: input.simfPath,
|
|
760
|
+
artifactPath: input.artifactPath,
|
|
761
|
+
});
|
|
762
|
+
return {
|
|
763
|
+
...buildClaimVerificationResult({
|
|
764
|
+
verified: report.fundingClaimTrust?.fullClaimVerified === true && Object.values(crossChecks).every(Boolean),
|
|
765
|
+
definition,
|
|
766
|
+
currentState,
|
|
767
|
+
stateHistory: history,
|
|
768
|
+
claim,
|
|
769
|
+
report,
|
|
770
|
+
}),
|
|
771
|
+
compiled,
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
async function verifyFundingClaim(sdk, input) {
|
|
775
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
776
|
+
const currentState = await loadReceivableStateDocument(sdk, {
|
|
777
|
+
statePath: input.currentStatePath,
|
|
778
|
+
stateValue: input.currentStateValue,
|
|
779
|
+
});
|
|
780
|
+
const history = input.stateHistoryPaths || input.stateHistoryValues
|
|
781
|
+
? await loadReceivableStateHistoryDocuments(sdk, input)
|
|
782
|
+
: [];
|
|
783
|
+
assertLatestStateMatchesHistoryTip({ latestState: currentState, history });
|
|
784
|
+
const claim = await loadReceivableFundingClaimDocument(sdk, {
|
|
785
|
+
fundingClaimPath: input.fundingClaimPath,
|
|
786
|
+
fundingClaimValue: input.fundingClaimValue,
|
|
787
|
+
});
|
|
788
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, currentState.value);
|
|
789
|
+
const lineageChecks = history.length > 0
|
|
790
|
+
? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
|
|
791
|
+
: undefined;
|
|
792
|
+
const claimChecks = (0, receivableValidation_1.validateReceivableFundingClaimAgainstState)({
|
|
793
|
+
currentState: currentState.value,
|
|
794
|
+
claim: claim.value,
|
|
795
|
+
});
|
|
796
|
+
const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
|
|
797
|
+
const definitionVerification = artifact
|
|
798
|
+
? await sdk.verifyDefinitionAgainstArtifact({
|
|
799
|
+
artifact,
|
|
800
|
+
type: "receivable-definition",
|
|
801
|
+
id: definition.value.receivableId,
|
|
802
|
+
value: definition.value,
|
|
803
|
+
})
|
|
804
|
+
: undefined;
|
|
805
|
+
const stateVerification = artifact
|
|
806
|
+
? await sdk.verifyStateAgainstArtifact({
|
|
807
|
+
artifact,
|
|
808
|
+
type: "receivable-funding-claim",
|
|
809
|
+
id: claim.value.claimId,
|
|
810
|
+
value: claim.value,
|
|
811
|
+
})
|
|
812
|
+
: undefined;
|
|
813
|
+
const claimantXonlyCommitted = artifact
|
|
814
|
+
? String(artifact.source.templateVars?.CLAIMANT_XONLY ?? "").toLowerCase() === claim.value.claimantXonly.toLowerCase()
|
|
815
|
+
: true;
|
|
816
|
+
const report = buildReceivableReport({
|
|
817
|
+
crossChecks,
|
|
818
|
+
...(lineageChecks ? { lineageChecks } : {}),
|
|
819
|
+
fundingClaimTrust: buildReceivableClaimTrust({
|
|
820
|
+
generated: false,
|
|
821
|
+
claimantXonlyCommitted,
|
|
822
|
+
checks: claimChecks,
|
|
823
|
+
}),
|
|
824
|
+
});
|
|
825
|
+
const verified = report.fundingClaimTrust?.fullClaimVerified === true
|
|
826
|
+
&& Object.values(crossChecks).every(Boolean)
|
|
827
|
+
&& (!definitionVerification || definitionVerification.ok)
|
|
828
|
+
&& (!stateVerification || stateVerification.ok);
|
|
829
|
+
return buildClaimVerificationResult({
|
|
830
|
+
verified,
|
|
831
|
+
definition,
|
|
832
|
+
currentState,
|
|
833
|
+
stateHistory: history,
|
|
834
|
+
claim,
|
|
835
|
+
artifact,
|
|
836
|
+
artifactVerification: artifact && (definitionVerification || stateVerification)
|
|
837
|
+
? {
|
|
838
|
+
...(definitionVerification ? { definition: definitionVerification } : {}),
|
|
839
|
+
...(stateVerification ? { state: stateVerification } : {}),
|
|
840
|
+
}
|
|
841
|
+
: undefined,
|
|
842
|
+
report,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
async function inspectFundingClaim(sdk, input) {
|
|
846
|
+
const verified = await verifyFundingClaim(sdk, input);
|
|
847
|
+
if (!verified.verified) {
|
|
848
|
+
throw new errors_1.ValidationError("Receivable funding claim verification failed", {
|
|
849
|
+
code: "RECEIVABLE_FUNDING_CLAIM_VERIFY_FAILED",
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
const artifact = await requireReceivableArtifact(sdk, input);
|
|
853
|
+
const payout = await buildReceivablePayoutDescriptor(sdk, {
|
|
854
|
+
receiverAddress: input.payoutAddress,
|
|
855
|
+
amountSat: verified.claimValue.amountSat,
|
|
856
|
+
assetId: verified.claimValue.currencyAssetId,
|
|
857
|
+
nextOutputHash: input.nextOutputHash,
|
|
858
|
+
outputForm: input.outputForm,
|
|
859
|
+
rawOutput: input.rawOutput,
|
|
860
|
+
outputBindingMode: input.outputBindingMode,
|
|
861
|
+
});
|
|
862
|
+
const contract = sdk.fromArtifact(artifact);
|
|
863
|
+
const inspect = await contract.inspectCall({
|
|
864
|
+
wallet: input.wallet,
|
|
865
|
+
toAddress: payout.descriptor.receiverAddress,
|
|
866
|
+
signer: input.signer,
|
|
867
|
+
sendAmount: satToBtcAmount(payout.descriptor.amountSat),
|
|
868
|
+
feeSat: input.feeSat,
|
|
869
|
+
utxoPolicy: input.utxoPolicy,
|
|
870
|
+
witness: buildReceivableClaimWitness(payout.descriptor),
|
|
871
|
+
});
|
|
872
|
+
return {
|
|
873
|
+
...verified,
|
|
874
|
+
payoutDescriptor: payout.descriptor,
|
|
875
|
+
inspect,
|
|
876
|
+
report: buildReceivableReport({
|
|
877
|
+
crossChecks: verified.report.receivableTrust,
|
|
878
|
+
...(verified.report.stateLineageTrust
|
|
879
|
+
? {
|
|
880
|
+
lineageChecks: (0, receivableValidation_1.verifyReceivableStateHistory)({
|
|
881
|
+
history: verified.stateHistoryValues ?? [verified.currentStateValue],
|
|
882
|
+
}),
|
|
883
|
+
}
|
|
884
|
+
: {}),
|
|
885
|
+
fundingClaimTrust: buildReceivableClaimTrust({
|
|
886
|
+
generated: verified.report.fundingClaimTrust?.generated ?? false,
|
|
887
|
+
claimantXonlyCommitted: verified.report.fundingClaimTrust?.claimantXonlyCommitted ?? true,
|
|
888
|
+
checks: {
|
|
889
|
+
claimKind: verified.report.fundingClaimTrust?.claimKind ?? "FUNDING",
|
|
890
|
+
stateStatusEligible: verified.report.fundingClaimTrust?.stateStatusEligible ?? false,
|
|
891
|
+
receivableIdMatch: verified.report.fundingClaimTrust?.receivableIdMatch ?? false,
|
|
892
|
+
currentStateHashMatch: verified.report.fundingClaimTrust?.currentStateHashMatch ?? false,
|
|
893
|
+
currentStatusMatch: verified.report.fundingClaimTrust?.currentStatusMatch ?? false,
|
|
894
|
+
payerEntityMatch: verified.report.fundingClaimTrust?.payerEntityMatch ?? false,
|
|
895
|
+
payeeEntityMatch: verified.report.fundingClaimTrust?.payeeEntityMatch ?? false,
|
|
896
|
+
claimantXonlyMatch: verified.report.fundingClaimTrust?.claimantXonlyMatch ?? false,
|
|
897
|
+
currencyAssetMatch: verified.report.fundingClaimTrust?.currencyAssetMatch ?? false,
|
|
898
|
+
amountMatch: verified.report.fundingClaimTrust?.amountMatch ?? false,
|
|
899
|
+
eventTimestampMatch: verified.report.fundingClaimTrust?.eventTimestampMatch ?? false,
|
|
900
|
+
fullClaimVerified: verified.report.fundingClaimTrust?.fullClaimVerified ?? false,
|
|
901
|
+
},
|
|
902
|
+
payout,
|
|
903
|
+
}),
|
|
904
|
+
}),
|
|
905
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
906
|
+
bindingMode: payout.descriptor.outputBindingMode,
|
|
907
|
+
...(verified.report.stateLineageTrust ? { lineageTrust: verified.report.stateLineageTrust } : {}),
|
|
908
|
+
...(verified.artifactVerification?.definition?.trust ? { definitionTrust: verified.artifactVerification.definition.trust } : {}),
|
|
909
|
+
...(verified.artifactVerification?.state?.trust ? { stateTrust: verified.artifactVerification.state.trust } : {}),
|
|
910
|
+
}),
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
async function executeFundingClaim(sdk, input) {
|
|
914
|
+
const inspected = await inspectFundingClaim(sdk, input);
|
|
915
|
+
const artifact = await requireReceivableArtifact(sdk, input);
|
|
916
|
+
const contract = sdk.fromArtifact(artifact);
|
|
917
|
+
const execution = await contract.execute({
|
|
918
|
+
wallet: input.wallet,
|
|
919
|
+
toAddress: inspected.payoutDescriptor.receiverAddress,
|
|
920
|
+
signer: input.signer,
|
|
921
|
+
sendAmount: satToBtcAmount(inspected.payoutDescriptor.amountSat),
|
|
922
|
+
feeSat: input.feeSat,
|
|
923
|
+
utxoPolicy: input.utxoPolicy,
|
|
924
|
+
broadcast: input.broadcast,
|
|
925
|
+
witness: buildReceivableClaimWitness(inspected.payoutDescriptor),
|
|
926
|
+
});
|
|
927
|
+
return {
|
|
928
|
+
...inspected,
|
|
929
|
+
execution,
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
async function prepareRepaymentClaim(sdk, input) {
|
|
933
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
934
|
+
const currentState = await loadReceivableStateDocument(sdk, {
|
|
935
|
+
statePath: input.currentStatePath,
|
|
936
|
+
stateValue: input.currentStateValue,
|
|
937
|
+
});
|
|
938
|
+
const history = input.stateHistoryPaths || input.stateHistoryValues
|
|
939
|
+
? await loadReceivableStateHistoryDocuments(sdk, input)
|
|
940
|
+
: [];
|
|
941
|
+
assertLatestStateMatchesHistoryTip({ latestState: currentState, history });
|
|
942
|
+
const claim = await loadReceivableRepaymentClaimDocument(sdk, {
|
|
943
|
+
repaymentClaimPath: input.repaymentClaimPath,
|
|
944
|
+
repaymentClaimValue: input.repaymentClaimValue,
|
|
945
|
+
currentStateValue: currentState.value,
|
|
946
|
+
claimId: input.claimId ?? `${currentState.value.receivableId}-REPAYMENT-CLAIM`,
|
|
947
|
+
payerEntityId: input.payerEntityId,
|
|
948
|
+
payeeEntityId: input.payeeEntityId,
|
|
949
|
+
claimantXonly: input.claimantXonly,
|
|
950
|
+
amountSat: input.amountSat,
|
|
951
|
+
eventTimestamp: input.eventTimestamp,
|
|
952
|
+
});
|
|
953
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, currentState.value);
|
|
954
|
+
const lineageChecks = history.length > 0
|
|
955
|
+
? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
|
|
956
|
+
: undefined;
|
|
957
|
+
const claimChecks = (0, receivableValidation_1.validateReceivableRepaymentClaimAgainstState)({
|
|
958
|
+
currentState: currentState.value,
|
|
959
|
+
claim: claim.value,
|
|
960
|
+
});
|
|
961
|
+
const report = buildReceivableReport({
|
|
962
|
+
crossChecks,
|
|
963
|
+
...(lineageChecks ? { lineageChecks } : {}),
|
|
964
|
+
repaymentClaimTrust: buildReceivableClaimTrust({
|
|
965
|
+
generated: !input.repaymentClaimPath && !input.repaymentClaimValue,
|
|
966
|
+
claimantXonlyCommitted: true,
|
|
967
|
+
checks: claimChecks,
|
|
968
|
+
}),
|
|
969
|
+
});
|
|
970
|
+
const compiled = await compileRepaymentClaimContract(sdk, {
|
|
971
|
+
definition: definition.value,
|
|
972
|
+
claim: claim.value,
|
|
973
|
+
simfPath: input.simfPath,
|
|
974
|
+
artifactPath: input.artifactPath,
|
|
975
|
+
});
|
|
976
|
+
return {
|
|
977
|
+
...buildClaimVerificationResult({
|
|
978
|
+
verified: report.repaymentClaimTrust?.fullClaimVerified === true && Object.values(crossChecks).every(Boolean),
|
|
979
|
+
definition,
|
|
980
|
+
currentState,
|
|
981
|
+
stateHistory: history,
|
|
982
|
+
claim,
|
|
983
|
+
report,
|
|
984
|
+
}),
|
|
985
|
+
compiled,
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
async function verifyRepaymentClaim(sdk, input) {
|
|
989
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
990
|
+
const currentState = await loadReceivableStateDocument(sdk, {
|
|
991
|
+
statePath: input.currentStatePath,
|
|
992
|
+
stateValue: input.currentStateValue,
|
|
993
|
+
});
|
|
994
|
+
const history = input.stateHistoryPaths || input.stateHistoryValues
|
|
995
|
+
? await loadReceivableStateHistoryDocuments(sdk, input)
|
|
996
|
+
: [];
|
|
997
|
+
assertLatestStateMatchesHistoryTip({ latestState: currentState, history });
|
|
998
|
+
const claim = await loadReceivableRepaymentClaimDocument(sdk, {
|
|
999
|
+
repaymentClaimPath: input.repaymentClaimPath,
|
|
1000
|
+
repaymentClaimValue: input.repaymentClaimValue,
|
|
1001
|
+
});
|
|
1002
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, currentState.value);
|
|
1003
|
+
const lineageChecks = history.length > 0
|
|
1004
|
+
? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
|
|
1005
|
+
: undefined;
|
|
1006
|
+
const claimChecks = (0, receivableValidation_1.validateReceivableRepaymentClaimAgainstState)({
|
|
1007
|
+
currentState: currentState.value,
|
|
1008
|
+
claim: claim.value,
|
|
1009
|
+
});
|
|
1010
|
+
const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
|
|
1011
|
+
const definitionVerification = artifact
|
|
1012
|
+
? await sdk.verifyDefinitionAgainstArtifact({
|
|
1013
|
+
artifact,
|
|
1014
|
+
type: "receivable-definition",
|
|
1015
|
+
id: definition.value.receivableId,
|
|
1016
|
+
value: definition.value,
|
|
1017
|
+
})
|
|
1018
|
+
: undefined;
|
|
1019
|
+
const stateVerification = artifact
|
|
1020
|
+
? await sdk.verifyStateAgainstArtifact({
|
|
1021
|
+
artifact,
|
|
1022
|
+
type: "receivable-repayment-claim",
|
|
1023
|
+
id: claim.value.claimId,
|
|
1024
|
+
value: claim.value,
|
|
1025
|
+
})
|
|
1026
|
+
: undefined;
|
|
1027
|
+
const claimantXonlyCommitted = artifact
|
|
1028
|
+
? String(artifact.source.templateVars?.CLAIMANT_XONLY ?? "").toLowerCase() === claim.value.claimantXonly.toLowerCase()
|
|
1029
|
+
: true;
|
|
1030
|
+
const report = buildReceivableReport({
|
|
1031
|
+
crossChecks,
|
|
1032
|
+
...(lineageChecks ? { lineageChecks } : {}),
|
|
1033
|
+
repaymentClaimTrust: buildReceivableClaimTrust({
|
|
1034
|
+
generated: false,
|
|
1035
|
+
claimantXonlyCommitted,
|
|
1036
|
+
checks: claimChecks,
|
|
1037
|
+
}),
|
|
1038
|
+
});
|
|
1039
|
+
const verified = report.repaymentClaimTrust?.fullClaimVerified === true
|
|
1040
|
+
&& Object.values(crossChecks).every(Boolean)
|
|
1041
|
+
&& (!definitionVerification || definitionVerification.ok)
|
|
1042
|
+
&& (!stateVerification || stateVerification.ok);
|
|
1043
|
+
return buildClaimVerificationResult({
|
|
1044
|
+
verified,
|
|
1045
|
+
definition,
|
|
1046
|
+
currentState,
|
|
1047
|
+
stateHistory: history,
|
|
1048
|
+
claim,
|
|
1049
|
+
artifact,
|
|
1050
|
+
artifactVerification: artifact && (definitionVerification || stateVerification)
|
|
1051
|
+
? {
|
|
1052
|
+
...(definitionVerification ? { definition: definitionVerification } : {}),
|
|
1053
|
+
...(stateVerification ? { state: stateVerification } : {}),
|
|
1054
|
+
}
|
|
1055
|
+
: undefined,
|
|
1056
|
+
report,
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
async function inspectRepaymentClaim(sdk, input) {
|
|
1060
|
+
const verified = await verifyRepaymentClaim(sdk, input);
|
|
1061
|
+
if (!verified.verified) {
|
|
1062
|
+
throw new errors_1.ValidationError("Receivable repayment claim verification failed", {
|
|
1063
|
+
code: "RECEIVABLE_REPAYMENT_CLAIM_VERIFY_FAILED",
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
const artifact = await requireReceivableArtifact(sdk, input);
|
|
1067
|
+
const payout = await buildReceivablePayoutDescriptor(sdk, {
|
|
1068
|
+
receiverAddress: input.payoutAddress,
|
|
1069
|
+
amountSat: verified.claimValue.amountSat,
|
|
1070
|
+
assetId: verified.claimValue.currencyAssetId,
|
|
1071
|
+
nextOutputHash: input.nextOutputHash,
|
|
1072
|
+
outputForm: input.outputForm,
|
|
1073
|
+
rawOutput: input.rawOutput,
|
|
1074
|
+
outputBindingMode: input.outputBindingMode,
|
|
1075
|
+
});
|
|
1076
|
+
const contract = sdk.fromArtifact(artifact);
|
|
1077
|
+
const inspect = await contract.inspectCall({
|
|
1078
|
+
wallet: input.wallet,
|
|
1079
|
+
toAddress: payout.descriptor.receiverAddress,
|
|
1080
|
+
signer: input.signer,
|
|
1081
|
+
sendAmount: satToBtcAmount(payout.descriptor.amountSat),
|
|
1082
|
+
feeSat: input.feeSat,
|
|
1083
|
+
utxoPolicy: input.utxoPolicy,
|
|
1084
|
+
witness: buildReceivableClaimWitness(payout.descriptor),
|
|
1085
|
+
});
|
|
1086
|
+
return {
|
|
1087
|
+
...verified,
|
|
1088
|
+
payoutDescriptor: payout.descriptor,
|
|
1089
|
+
inspect,
|
|
1090
|
+
report: buildReceivableReport({
|
|
1091
|
+
crossChecks: verified.report.receivableTrust,
|
|
1092
|
+
...(verified.report.stateLineageTrust
|
|
1093
|
+
? {
|
|
1094
|
+
lineageChecks: (0, receivableValidation_1.verifyReceivableStateHistory)({
|
|
1095
|
+
history: verified.stateHistoryValues ?? [verified.currentStateValue],
|
|
1096
|
+
}),
|
|
1097
|
+
}
|
|
1098
|
+
: {}),
|
|
1099
|
+
repaymentClaimTrust: buildReceivableClaimTrust({
|
|
1100
|
+
generated: verified.report.repaymentClaimTrust?.generated ?? false,
|
|
1101
|
+
claimantXonlyCommitted: verified.report.repaymentClaimTrust?.claimantXonlyCommitted ?? true,
|
|
1102
|
+
checks: {
|
|
1103
|
+
claimKind: verified.report.repaymentClaimTrust?.claimKind ?? "REPAYMENT",
|
|
1104
|
+
stateStatusEligible: verified.report.repaymentClaimTrust?.stateStatusEligible ?? false,
|
|
1105
|
+
receivableIdMatch: verified.report.repaymentClaimTrust?.receivableIdMatch ?? false,
|
|
1106
|
+
currentStateHashMatch: verified.report.repaymentClaimTrust?.currentStateHashMatch ?? false,
|
|
1107
|
+
currentStatusMatch: verified.report.repaymentClaimTrust?.currentStatusMatch ?? false,
|
|
1108
|
+
payerEntityMatch: verified.report.repaymentClaimTrust?.payerEntityMatch ?? false,
|
|
1109
|
+
payeeEntityMatch: verified.report.repaymentClaimTrust?.payeeEntityMatch ?? false,
|
|
1110
|
+
claimantXonlyMatch: verified.report.repaymentClaimTrust?.claimantXonlyMatch ?? false,
|
|
1111
|
+
currencyAssetMatch: verified.report.repaymentClaimTrust?.currencyAssetMatch ?? false,
|
|
1112
|
+
amountMatch: verified.report.repaymentClaimTrust?.amountMatch ?? false,
|
|
1113
|
+
eventTimestampMatch: verified.report.repaymentClaimTrust?.eventTimestampMatch ?? false,
|
|
1114
|
+
fullClaimVerified: verified.report.repaymentClaimTrust?.fullClaimVerified ?? false,
|
|
1115
|
+
},
|
|
1116
|
+
payout,
|
|
1117
|
+
}),
|
|
1118
|
+
}),
|
|
1119
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
1120
|
+
bindingMode: payout.descriptor.outputBindingMode,
|
|
1121
|
+
...(verified.report.stateLineageTrust ? { lineageTrust: verified.report.stateLineageTrust } : {}),
|
|
1122
|
+
...(verified.artifactVerification?.definition?.trust ? { definitionTrust: verified.artifactVerification.definition.trust } : {}),
|
|
1123
|
+
...(verified.artifactVerification?.state?.trust ? { stateTrust: verified.artifactVerification.state.trust } : {}),
|
|
1124
|
+
}),
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
async function executeRepaymentClaim(sdk, input) {
|
|
1128
|
+
const inspected = await inspectRepaymentClaim(sdk, input);
|
|
1129
|
+
const artifact = await requireReceivableArtifact(sdk, input);
|
|
1130
|
+
const contract = sdk.fromArtifact(artifact);
|
|
1131
|
+
const execution = await contract.execute({
|
|
1132
|
+
wallet: input.wallet,
|
|
1133
|
+
toAddress: inspected.payoutDescriptor.receiverAddress,
|
|
1134
|
+
signer: input.signer,
|
|
1135
|
+
sendAmount: satToBtcAmount(inspected.payoutDescriptor.amountSat),
|
|
1136
|
+
feeSat: input.feeSat,
|
|
1137
|
+
utxoPolicy: input.utxoPolicy,
|
|
1138
|
+
broadcast: input.broadcast,
|
|
1139
|
+
witness: buildReceivableClaimWitness(inspected.payoutDescriptor),
|
|
1140
|
+
});
|
|
1141
|
+
return {
|
|
1142
|
+
...inspected,
|
|
1143
|
+
execution,
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
async function prepareWriteOff(sdk, input) {
|
|
1147
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
1148
|
+
const previous = await loadReceivableStateDocument(sdk, {
|
|
1149
|
+
statePath: input.previousStatePath,
|
|
1150
|
+
stateValue: input.previousStateValue,
|
|
1151
|
+
});
|
|
1152
|
+
const next = input.nextStatePath || input.nextStateValue
|
|
1153
|
+
? await loadReceivableStateDocument(sdk, {
|
|
1154
|
+
statePath: input.nextStatePath,
|
|
1155
|
+
stateValue: input.nextStateValue,
|
|
1156
|
+
})
|
|
1157
|
+
: await loadReceivableStateDocument(sdk, {
|
|
1158
|
+
stateValue: (0, receivableValidation_1.buildDefaultedReceivableState)({
|
|
1159
|
+
previous: previous.value,
|
|
1160
|
+
stateId: input.stateId ?? `${previous.value.receivableId}-DEFAULTED`,
|
|
1161
|
+
defaultedAt: input.defaultedAt ?? new Date().toISOString(),
|
|
1162
|
+
...(input.writeOffAmount !== undefined ? { writeOffAmount: input.writeOffAmount } : {}),
|
|
1163
|
+
}),
|
|
1164
|
+
});
|
|
1165
|
+
const transitionTrust = (0, receivableValidation_1.validateReceivableWriteOffTransition)(previous.value, next.value);
|
|
1166
|
+
return buildTransitionVerificationResult({
|
|
1167
|
+
definition,
|
|
1168
|
+
previous,
|
|
1169
|
+
next,
|
|
1170
|
+
transitionTrust,
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
async function verifyWriteOff(sdk, input) {
|
|
1174
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
1175
|
+
const { previous, next } = await loadPreviousAndNextReceivableStates(sdk, input);
|
|
1176
|
+
const transitionTrust = (0, receivableValidation_1.validateReceivableWriteOffTransition)(previous.value, next.value);
|
|
1177
|
+
return buildTransitionVerificationResult({
|
|
1178
|
+
definition,
|
|
1179
|
+
previous,
|
|
1180
|
+
next,
|
|
1181
|
+
transitionTrust,
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
async function prepareClosing(sdk, input) {
|
|
1185
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
1186
|
+
const latestState = await loadReceivableStateDocument(sdk, {
|
|
1187
|
+
statePath: input.latestStatePath,
|
|
1188
|
+
stateValue: input.latestStateValue,
|
|
1189
|
+
});
|
|
1190
|
+
const history = input.stateHistoryPaths || input.stateHistoryValues
|
|
1191
|
+
? await loadReceivableStateHistoryDocuments(sdk, input)
|
|
1192
|
+
: [];
|
|
1193
|
+
assertLatestStateMatchesHistoryTip({ latestState, history });
|
|
1194
|
+
const closing = await loadReceivableClosingDocument(sdk, {
|
|
1195
|
+
closingPath: input.closingPath,
|
|
1196
|
+
closingValue: input.closingValue,
|
|
1197
|
+
closingId: input.closingId,
|
|
1198
|
+
latestStateValue: latestState.value,
|
|
1199
|
+
closedAt: input.closedAt,
|
|
1200
|
+
closingReason: input.closingReason,
|
|
1201
|
+
});
|
|
1202
|
+
const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, latestState.value);
|
|
1203
|
+
const lineageChecks = history.length > 0
|
|
1204
|
+
? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
|
|
1205
|
+
: undefined;
|
|
1206
|
+
const closingTrust = (0, receivableValidation_1.validateReceivableClosingAgainstState)({
|
|
1207
|
+
latestState: latestState.value,
|
|
1208
|
+
closing: closing.value,
|
|
1209
|
+
...(history.length > 0 ? { history: history.map((entry) => entry.value) } : {}),
|
|
1210
|
+
});
|
|
1211
|
+
const report = buildReceivableReport({
|
|
1212
|
+
crossChecks,
|
|
1213
|
+
...(lineageChecks ? { lineageChecks } : {}),
|
|
1214
|
+
closingTrust,
|
|
1215
|
+
});
|
|
1216
|
+
return {
|
|
1217
|
+
verified: closingTrust.fullClosingVerified
|
|
1218
|
+
&& Object.values(crossChecks).every(Boolean)
|
|
1219
|
+
&& (lineageChecks ? lineageChecks.fullHistoryVerified : true),
|
|
1220
|
+
definition: definition.descriptor,
|
|
1221
|
+
definitionValue: definition.value,
|
|
1222
|
+
definitionSummary: definition.summary,
|
|
1223
|
+
latestState: latestState.descriptor,
|
|
1224
|
+
latestStateValue: latestState.value,
|
|
1225
|
+
latestStateSummary: latestState.summary,
|
|
1226
|
+
...(history.length > 0
|
|
1227
|
+
? {
|
|
1228
|
+
stateHistory: history.map((entry) => entry.descriptor),
|
|
1229
|
+
stateHistoryValues: history.map((entry) => entry.value),
|
|
1230
|
+
stateHistorySummaries: history.map((entry) => entry.summary),
|
|
1231
|
+
}
|
|
1232
|
+
: {}),
|
|
1233
|
+
closing: closing.descriptor,
|
|
1234
|
+
closingValue: closing.value,
|
|
1235
|
+
closingSummary: closing.summary,
|
|
1236
|
+
report,
|
|
1237
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
1238
|
+
bindingMode: "none",
|
|
1239
|
+
...(report.stateLineageTrust ? { lineageTrust: report.stateLineageTrust } : {}),
|
|
1240
|
+
}),
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
async function verifyClosing(sdk, input) {
|
|
1244
|
+
if (!input.closingPath && !input.closingValue) {
|
|
1245
|
+
throw new errors_1.ValidationError("closingPath or closingValue is required", {
|
|
1246
|
+
code: "RECEIVABLE_CLOSING_REQUIRED",
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
return prepareClosing(sdk, input);
|
|
1250
|
+
}
|
|
1251
|
+
async function exportEvidence(sdk, input) {
|
|
1252
|
+
const definition = await loadReceivableDefinitionDocument(sdk, input);
|
|
1253
|
+
const latestState = input.statePath || input.stateValue
|
|
1254
|
+
? await loadReceivableStateDocument(sdk, input)
|
|
1255
|
+
: undefined;
|
|
1256
|
+
const history = input.stateHistoryPaths || input.stateHistoryValues
|
|
1257
|
+
? await loadReceivableStateHistoryDocuments(sdk, input)
|
|
1258
|
+
: [];
|
|
1259
|
+
assertLatestStateMatchesHistoryTip({ latestState, history });
|
|
1260
|
+
const latest = latestState ?? history.at(-1);
|
|
1261
|
+
if (!latest) {
|
|
1262
|
+
throw new errors_1.ValidationError("statePath/stateValue or stateHistoryPaths/stateHistoryValues is required", {
|
|
1263
|
+
code: "RECEIVABLE_STATE_REQUIRED",
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
const closing = input.closingPath || input.closingValue
|
|
1267
|
+
? await loadReceivableClosingDocument(sdk, {
|
|
1268
|
+
closingPath: input.closingPath,
|
|
1269
|
+
closingValue: input.closingValue,
|
|
1270
|
+
})
|
|
1271
|
+
: undefined;
|
|
1272
|
+
const fundingClaim = input.fundingClaimPath || input.fundingClaimValue
|
|
1273
|
+
? await loadReceivableFundingClaimDocument(sdk, {
|
|
1274
|
+
fundingClaimPath: input.fundingClaimPath,
|
|
1275
|
+
fundingClaimValue: input.fundingClaimValue,
|
|
1276
|
+
})
|
|
1277
|
+
: undefined;
|
|
1278
|
+
const repaymentClaim = input.repaymentClaimPath || input.repaymentClaimValue
|
|
1279
|
+
? await loadReceivableRepaymentClaimDocument(sdk, {
|
|
1280
|
+
repaymentClaimPath: input.repaymentClaimPath,
|
|
1281
|
+
repaymentClaimValue: input.repaymentClaimValue,
|
|
1282
|
+
})
|
|
1283
|
+
: undefined;
|
|
1284
|
+
const lineageChecks = history.length > 0
|
|
1285
|
+
? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
|
|
1286
|
+
: undefined;
|
|
1287
|
+
const trust = input.verificationReportValue
|
|
1288
|
+
?? (lineageChecks
|
|
1289
|
+
? buildReceivableReport({
|
|
1290
|
+
crossChecks: (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, latest.value),
|
|
1291
|
+
lineageChecks,
|
|
1292
|
+
...(closing
|
|
1293
|
+
? {
|
|
1294
|
+
closingTrust: (0, receivableValidation_1.validateReceivableClosingAgainstState)({
|
|
1295
|
+
latestState: latest.value,
|
|
1296
|
+
closing: closing.value,
|
|
1297
|
+
history: history.map((entry) => entry.value),
|
|
1298
|
+
}),
|
|
1299
|
+
}
|
|
1300
|
+
: {}),
|
|
1301
|
+
})
|
|
1302
|
+
: buildReceivableReport({
|
|
1303
|
+
crossChecks: (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, latest.value),
|
|
1304
|
+
...(closing
|
|
1305
|
+
? {
|
|
1306
|
+
closingTrust: (0, receivableValidation_1.validateReceivableClosingAgainstState)({
|
|
1307
|
+
latestState: latest.value,
|
|
1308
|
+
closing: closing.value,
|
|
1309
|
+
}),
|
|
1310
|
+
}
|
|
1311
|
+
: {}),
|
|
1312
|
+
}));
|
|
1313
|
+
return {
|
|
1314
|
+
schemaVersion: RECEIVABLE_EVIDENCE_BUNDLE_SCHEMA_VERSION,
|
|
1315
|
+
definition: definition.summary,
|
|
1316
|
+
state: latest.summary,
|
|
1317
|
+
...(history.length > 1 ? { stateHistory: history.map((entry) => entry.summary) } : {}),
|
|
1318
|
+
...(fundingClaim ? { fundingClaim: fundingClaim.summary } : {}),
|
|
1319
|
+
...(repaymentClaim ? { repaymentClaim: repaymentClaim.summary } : {}),
|
|
1320
|
+
...(closing ? { closing: closing.summary } : {}),
|
|
1321
|
+
trust,
|
|
1322
|
+
trustSummary: (0, reporting_1.buildVerificationTrustSummary)({
|
|
1323
|
+
bindingMode: "none",
|
|
1324
|
+
lineageTrust: trust.stateLineageTrust,
|
|
1325
|
+
}),
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
async function exportFinalityPayload(sdk, input) {
|
|
1329
|
+
const evidence = await exportEvidence(sdk, input);
|
|
1330
|
+
const latestState = input.statePath || input.stateValue
|
|
1331
|
+
? await loadReceivableStateDocument(sdk, input)
|
|
1332
|
+
: undefined;
|
|
1333
|
+
const history = input.stateHistoryPaths || input.stateHistoryValues
|
|
1334
|
+
? await loadReceivableStateHistoryDocuments(sdk, input)
|
|
1335
|
+
: [];
|
|
1336
|
+
assertLatestStateMatchesHistoryTip({ latestState, history });
|
|
1337
|
+
const latest = latestState ?? history.at(-1);
|
|
1338
|
+
if (!latest) {
|
|
1339
|
+
throw new errors_1.ValidationError("statePath/stateValue or stateHistoryPaths/stateHistoryValues is required", {
|
|
1340
|
+
code: "RECEIVABLE_STATE_REQUIRED",
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
const closing = input.closingPath || input.closingValue
|
|
1344
|
+
? await loadReceivableClosingDocument(sdk, {
|
|
1345
|
+
closingPath: input.closingPath,
|
|
1346
|
+
closingValue: input.closingValue,
|
|
1347
|
+
})
|
|
1348
|
+
: undefined;
|
|
1349
|
+
const fundingClaim = input.fundingClaimPath || input.fundingClaimValue
|
|
1350
|
+
? await loadReceivableFundingClaimDocument(sdk, {
|
|
1351
|
+
fundingClaimPath: input.fundingClaimPath,
|
|
1352
|
+
fundingClaimValue: input.fundingClaimValue,
|
|
1353
|
+
})
|
|
1354
|
+
: undefined;
|
|
1355
|
+
const repaymentClaim = input.repaymentClaimPath || input.repaymentClaimValue
|
|
1356
|
+
? await loadReceivableRepaymentClaimDocument(sdk, {
|
|
1357
|
+
repaymentClaimPath: input.repaymentClaimPath,
|
|
1358
|
+
repaymentClaimValue: input.repaymentClaimValue,
|
|
1359
|
+
})
|
|
1360
|
+
: undefined;
|
|
1361
|
+
return {
|
|
1362
|
+
schemaVersion: RECEIVABLE_FINALITY_PAYLOAD_SCHEMA_VERSION,
|
|
1363
|
+
receivableId: latest.value.receivableId,
|
|
1364
|
+
holderEntityId: latest.value.holderEntityId,
|
|
1365
|
+
definitionHash: evidence.definition.hash,
|
|
1366
|
+
latestStateHash: evidence.state.hash,
|
|
1367
|
+
stateHistoryHashes: history.length > 1 ? history.map((entry) => entry.summary.hash) : null,
|
|
1368
|
+
fundingClaimHash: fundingClaim?.summary.hash ?? null,
|
|
1369
|
+
repaymentClaimHash: repaymentClaim?.summary.hash ?? null,
|
|
1370
|
+
closingHash: closing?.summary.hash ?? null,
|
|
1371
|
+
closingReason: closing?.value.closingReason ?? null,
|
|
1372
|
+
trust: evidence.trust,
|
|
1373
|
+
trustSummary: evidence.trustSummary,
|
|
1374
|
+
};
|
|
1375
|
+
}
|