@hyperscale0/udl 2.0.2 → 2.0.3
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/CHANGELOG.md +8 -0
- package/dist/finance.d.ts +1 -0
- package/dist/finance.d.ts.map +1 -1
- package/dist/finance.js +42 -4
- package/dist/finance.js.map +1 -1
- package/dist/schema.d.ts +36 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +7 -0
- package/dist/schema.js.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +66 -0
- package/dist/validation.js.map +1 -1
- package/docs/guide/04-fees-and-remainder.md +21 -0
- package/docs/llms-full.txt +22 -1
- package/docs/llms.txt +1 -1
- package/docs/reference/clauses.md +1 -1
- package/docs/reference/cli.md +1 -1
- package/docs/reference/diagnostics.md +1 -1
- package/package.json +2 -2
- package/spec/udl.schema.json +4 -0
- package/src/finance.ts +76 -9
- package/src/schema.ts +9 -0
- package/src/validation.ts +94 -0
package/dist/validation.js
CHANGED
|
@@ -2443,6 +2443,46 @@ function validateQuoteCommit(instrument, base, references, add) {
|
|
|
2443
2443
|
if (committing.length !== 1) {
|
|
2444
2444
|
add([...quoteBase], `quoting action ${actionName} must be committed by exactly one action, not ${committing.length}`, "UDL5006");
|
|
2445
2445
|
}
|
|
2446
|
+
if (quote.chargeRetainedBy !== undefined) {
|
|
2447
|
+
const retainedRole = quote.chargeRetainedBy;
|
|
2448
|
+
// Own keys only: a role named after a prototype member is undeclared.
|
|
2449
|
+
const partyField = Object.hasOwn(instrument.parties ?? {}, retainedRole)
|
|
2450
|
+
? instrument.parties?.[retainedRole]
|
|
2451
|
+
: undefined;
|
|
2452
|
+
if (!partyField) {
|
|
2453
|
+
add([...quoteBase, "chargeRetainedBy"], `quoting action ${actionName} retains charge by undeclared party role ${retainedRole}`, "UDL5006");
|
|
2454
|
+
}
|
|
2455
|
+
else {
|
|
2456
|
+
const partySchema = instrument.fields[partyField];
|
|
2457
|
+
if (!partySchema || !references.accepts(partySchema, "acct")) {
|
|
2458
|
+
add([...quoteBase, "chargeRetainedBy"], `charge-retaining party field ${partyField} must be an account field`, "UDL5006");
|
|
2459
|
+
}
|
|
2460
|
+
if (!instrument.required.includes(partyField)) {
|
|
2461
|
+
add([...quoteBase, "chargeRetainedBy"], `charge-retaining party field ${partyField} must be required`, "UDL5006");
|
|
2462
|
+
}
|
|
2463
|
+
if (!quote.fixes.includes(partyField)) {
|
|
2464
|
+
add([...quoteBase, "chargeRetainedBy"], `quoting action ${actionName} must freeze its charge-retaining party field ${partyField}`, "UDL5006");
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
const chargePath = `refs.${quote.chargeRef}`;
|
|
2468
|
+
for (const [consumerName, candidateAction] of Object.entries(instrument.actions)) {
|
|
2469
|
+
for (const [moveIndex, move] of (candidateAction.moves ?? []).entries()) {
|
|
2470
|
+
for (const [target, binding] of Object.entries(move.bind)) {
|
|
2471
|
+
if (binding.from === "instance" && binding.path === chargePath) {
|
|
2472
|
+
add([
|
|
2473
|
+
...base,
|
|
2474
|
+
"actions",
|
|
2475
|
+
consumerName,
|
|
2476
|
+
"moves",
|
|
2477
|
+
moveIndex,
|
|
2478
|
+
"bind",
|
|
2479
|
+
target,
|
|
2480
|
+
], `charge ${chargePath} is retained by ${retainedRole} and cannot be consumed by an action`, "UDL5006");
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2446
2486
|
}
|
|
2447
2487
|
const seededBy = new Map();
|
|
2448
2488
|
for (const [actionName, action] of quotingActions) {
|
|
@@ -2499,6 +2539,32 @@ function validateQuoteCommit(instrument, base, references, add) {
|
|
|
2499
2539
|
destinationBinding.path !== `fields.${quote.netDestinationField}`) {
|
|
2500
2540
|
add([...base, "actions", actionName, "moves"], `commit action ${actionName} must contain exactly one internal transfer whose source comes from the instrument instance, amount is refs.${quote.netRef}, and destination is fields.${quote.netDestinationField}`, "UDL5006");
|
|
2501
2541
|
}
|
|
2542
|
+
if (quote.chargeRetainedBy !== undefined) {
|
|
2543
|
+
const partyField = instrument.parties?.[quote.chargeRetainedBy];
|
|
2544
|
+
let sourceField;
|
|
2545
|
+
if (sourceBinding?.from === "instance") {
|
|
2546
|
+
if (sourceBinding.path.startsWith("fields.")) {
|
|
2547
|
+
sourceField = sourceBinding.path.slice("fields.".length);
|
|
2548
|
+
}
|
|
2549
|
+
else if (sourceBinding.path.startsWith("party.")) {
|
|
2550
|
+
const role = sourceBinding.path.slice("party.".length);
|
|
2551
|
+
sourceField = instrument.parties?.[role];
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
if (sourceBinding?.from !== "instance" ||
|
|
2555
|
+
!sourceField ||
|
|
2556
|
+
sourceField !== partyField) {
|
|
2557
|
+
add([
|
|
2558
|
+
...base,
|
|
2559
|
+
"actions",
|
|
2560
|
+
actionName,
|
|
2561
|
+
"moves",
|
|
2562
|
+
0,
|
|
2563
|
+
"bind",
|
|
2564
|
+
"sourceAccountId",
|
|
2565
|
+
], `commit action ${actionName} refund source must come from charge-retaining party field ${partyField ?? quote.chargeRetainedBy}`, "UDL5006");
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2502
2568
|
}
|
|
2503
2569
|
}
|
|
2504
2570
|
function validateAggregates(instrument, base, instruments, references, add) {
|