@hyperscale0/hsx 2.0.1 → 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.
Files changed (56) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/src/cli.d.ts +1 -1
  3. package/dist/src/std-bundle.js +19 -19
  4. package/dist/src/std-bundle.js.map +1 -1
  5. package/dist/src/version.d.ts +1 -1
  6. package/dist/src/version.js +1 -1
  7. package/docs/guide/01-first-program.md +1 -1
  8. package/docs/llms-full.txt +43 -38
  9. package/docs/llms.txt +2 -2
  10. package/docs/reference/cli.md +2 -2
  11. package/docs/reference/diagnostics.md +1 -1
  12. package/docs/reference/grammar.md +1 -1
  13. package/docs/reference/std/advance.md +1 -1
  14. package/docs/reference/std/cancellable_booking.md +1 -1
  15. package/docs/reference/std/captured_payment.md +1 -1
  16. package/docs/reference/std/conditional_disbursement.md +1 -1
  17. package/docs/reference/std/credit_facility.md +1 -1
  18. package/docs/reference/std/held_payment.md +41 -36
  19. package/docs/reference/std/instant_transfer.md +1 -1
  20. package/docs/reference/std/metered.md +1 -1
  21. package/docs/reference/std/pooled_split.md +1 -1
  22. package/docs/reference/std/premium_forward.md +1 -1
  23. package/docs/reference/std/reconciled_payout.md +1 -1
  24. package/docs/reference/std/recurring_collection.md +1 -1
  25. package/docs/reference/std/rotating_pool.md +1 -1
  26. package/docs/reference/std/scheduled.md +1 -1
  27. package/docs/reference/std/security_deposit.md +1 -1
  28. package/docs/reference/std/settlement_batch.md +1 -1
  29. package/docs/reference/std/swap.md +1 -1
  30. package/docs/reference/std/threshold_pool.md +1 -1
  31. package/docs/reference/std/weighted_distribution.md +1 -1
  32. package/docs/reference/types.md +1 -1
  33. package/docs/reference/udl-output.md +1 -1
  34. package/package.json +3 -3
  35. package/skills/hsx/SKILL.md +2 -2
  36. package/src/std-bundle.ts +19 -19
  37. package/src/version.ts +1 -1
  38. package/std/money_flows/advance.hsx +45 -0
  39. package/std/money_flows/cancellable_booking.hsx +45 -0
  40. package/std/money_flows/captured_payment.hsx +55 -0
  41. package/std/money_flows/conditional_disbursement.hsx +46 -0
  42. package/std/money_flows/credit_facility.hsx +57 -0
  43. package/std/money_flows/held_payment.hsx +150 -3
  44. package/std/money_flows/instant_transfer.hsx +42 -0
  45. package/std/money_flows/metered.hsx +41 -0
  46. package/std/money_flows/pooled_split.hsx +41 -0
  47. package/std/money_flows/premium_forward.hsx +51 -0
  48. package/std/money_flows/reconciled_payout.hsx +42 -0
  49. package/std/money_flows/recurring_collection.hsx +45 -0
  50. package/std/money_flows/rotating_pool.hsx +51 -0
  51. package/std/money_flows/scheduled.hsx +53 -0
  52. package/std/money_flows/security_deposit.hsx +58 -0
  53. package/std/money_flows/settlement_batch.hsx +51 -0
  54. package/std/money_flows/swap.hsx +53 -0
  55. package/std/money_flows/threshold_pool.hsx +51 -0
  56. package/std/money_flows/weighted_distribution.hsx +54 -0
package/src/version.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Package version reported by the command line. */
2
- export const HSX_VERSION = "2.0.1";
2
+ export const HSX_VERSION = "2.0.3";
3
3
 
4
4
  /** Canonical UDL contract version emitted by this compiler. */
5
5
  export const HSX_TARGET_UDL_VERSION = 1;
@@ -1,5 +1,50 @@
1
1
  module std.money_flows.advance
2
2
 
3
+ // Upfront capital disbursement repaid by carving future held payment releases or over scheduled installments.
4
+ //
5
+ // ### Purpose
6
+ // `advance` provides working capital, merchant cash advances, or contractor pre-funding from a funder to a recipient.
7
+ // Repayment occurs either automatically by intercepting (carving) releases from a linked escrow hold (`against`),
8
+ // or over calendar-anchored installment repayments (`count`, `every`, `first_due`).
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `credit_facility`: `advance` disburses a single upfront lump-sum principal that is repaid over time.
12
+ // `credit_facility` establishes a reusable revolving credit line with multiple draws up to a limit,
13
+ // where repayments restore available borrowing capacity.
14
+ // - vs `conditional_disbursement`: `advance` expects repayment of the advanced principal plus optional fees.
15
+ // `conditional_disbursement` disburses non-repayable grants, claims, or milestone payments against external evidence.
16
+ // - vs `held_payment`: `held_payment` holds customer funds in escrow until delivery. An `advance` can carve repayments
17
+ // directly out of a `held_payment`'s release using `against`.
18
+ //
19
+ // ### Parameters
20
+ // - `funder`: The party providing the upfront capital.
21
+ // - `to`: The party receiving the advance and responsible for repayment.
22
+ // - `amount`: Total advanced principal in minor units of currency `C`.
23
+ // - `fee`: Optional markup percentage fee charged on the advance (basis points precision).
24
+ // - `count`: Optional number of scheduled installment repayments.
25
+ // - `every`: Optional recurrence duration between installments (e.g. `"P30D"`).
26
+ // - `first_due`: Optional date for the first installment repayment.
27
+ // - `against`: Optional reference to a hold instrument whose release will be carved to repay the advance.
28
+ //
29
+ // ### Decision ports
30
+ // None. Repayment is driven by linked hold releases or scheduled calendar dates.
31
+ //
32
+ // ### Example
33
+ // ```hsx
34
+ // program advance_example "Advance example"
35
+ // import { advance } from "std/money_flows"
36
+ // party funder: business
37
+ // party recipient: business
38
+ // settlement advance_payment = advance {
39
+ // funder: funder
40
+ // to: recipient
41
+ // amount: principal: money(SAR)
42
+ // fee: 2.5%
43
+ // count: 2
44
+ // every: P30D
45
+ // first_due: firstDueAt
46
+ // }
47
+ // ```
3
48
  export instrument advance<C>(
4
49
  funder: party,
5
50
  to: party,
@@ -1,5 +1,50 @@
1
1
  module std.money_flows.cancellable_booking
2
2
 
3
+ // Time-anchored reservation holding booking funds in escrow with dynamically quoted cancellation penalties.
4
+ //
5
+ // ### Purpose
6
+ // `cancellable_booking` holds booking fees in escrow from a guest for a host until a scheduled start date.
7
+ // It fits hospitality, travel reservations, studio rentals, event tickets, and appointments where guests
8
+ // can cancel prior to start, but cancellation penalties depend on how close to the start date cancellation occurs.
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `held_payment`: Both hold money in escrow and both quote a cancellation before it is spent.
12
+ // `cancellable_booking` prices the penalty against the time left before `starts_at`, so the charge moves
13
+ // as the start approaches; `held_payment` has no start date and quotes one flat charge.
14
+ // Choose `cancellable_booking` whenever cancellation fees are time-sensitive.
15
+ // - vs `security_deposit`: `security_deposit` holds funds to cover damages claimed by the holder.
16
+ // `cancellable_booking` holds the service fee itself and releases to the host upon `starts_at` or refunds net of penalty.
17
+ //
18
+ // ### Parameters
19
+ // - `guest`: The booking customer paying the fee and receiving refunds.
20
+ // - `host`: The service provider receiving the payout or retained cancellation penalty.
21
+ // - `amount`: Total booking price in minor units of currency `C`.
22
+ // - `starts_at`: Stored ISO 8601 date when the booking begins.
23
+ // - `late_penalty_bps`: Penalty in basis points applied when cancelling within the late window.
24
+ // - `late_within`: ISO 8601 duration defining the late window before `starts_at` (e.g. `"P2D"` for 2 days).
25
+ // - `early_penalty_bps`: Penalty in basis points applied when cancelling before the late window.
26
+ // - `offer_life`: ISO 8601 duration defining how long a quoted cancellation offer remains valid (e.g. `"PT30M"`).
27
+ //
28
+ // ### Decision ports
29
+ // None. Action transitions are driven by guest API calls (`take`, `cancel`, `confirm`) and scheduled completion (`complete` due at `starts_at`).
30
+ //
31
+ // ### Example
32
+ // ```hsx
33
+ // program studio_booking "Studio booking"
34
+ // import { cancellable_booking } from "std/money_flows"
35
+ // party guest: person
36
+ // party studio: business
37
+ // settlement studio_session = cancellable_booking {
38
+ // guest: guest
39
+ // host: studio
40
+ // amount: sessionPrice: money(SAR)
41
+ // starts_at: startsAt
42
+ // late_penalty_bps: 5000
43
+ // late_within: "P2D"
44
+ // early_penalty_bps: 1000
45
+ // offer_life: "PT30M"
46
+ // }
47
+ // ```
3
48
  export instrument cancellable_booking<C>(
4
49
  guest: party,
5
50
  host: party,
@@ -1,5 +1,60 @@
1
1
  module std.money_flows.captured_payment
2
2
 
3
+ // Two-phase authorization and capture payment flow for card and merchant processing.
4
+ //
5
+ // ### Purpose
6
+ // `captured_payment` reserves funds against a payer's account and allows the payee to capture the authorized
7
+ // balance in one or multiple slices before a reservation expiry date (`reserve_until`). It fits ecommerce checkouts,
8
+ // card processing, hotel authorizations, and pay-at-pump fuel payments where final amounts vary or settle later.
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `instant_transfer`: `instant_transfer` immediately transfers money from payer to payee in a single irreversible
12
+ // step without reservation or settlement delays. `captured_payment` separates authorization from capture, allowing
13
+ // incremental captures, voids, amount corrections via the `correction` port, and external network reversals via `external_reversal`.
14
+ // - vs `held_payment`: `held_payment` holds the full amount in third-party escrow pending release. `captured_payment`
15
+ // reserves funds directly on payer balance and settles incrementally directly to payee.
16
+ //
17
+ // ### Parameters
18
+ // - `payer`: Party whose account balance is reserved during authorization.
19
+ // - `payee`: Beneficiary party capturing authorized funds.
20
+ // - `amount`: Maximum authorized reservation in minor units of currency `C`.
21
+ // - `reserve_until`: Expiration date for the authorization hold.
22
+ // - `correction`: Condition port allowing post-settlement amount corrections.
23
+ // - `external_reversal`: Condition port allowing external processor chargebacks/reversals.
24
+ // - `capture_mode`: Text specifying capture behavior (`"slice"` or `"full"`).
25
+ // - `correction_mode`: Text specifying correction behavior.
26
+ // - `negative_position`: Text policy when correction creates an overdraft.
27
+ // - `timeout`: Timeout duration string for pending authorizations.
28
+ // - `derived_amount`: Optional block declaring percentage fee calculation.
29
+ //
30
+ // ### Decision ports
31
+ // - `correction`: Condition allowing payee or processor to submit an amount correction after settlement.
32
+ // - `external_reversal`: Condition allowing bank or card network to execute an external reversal.
33
+ //
34
+ // ### Example
35
+ // ```hsx
36
+ // program captured_payment_example "Captured payment example"
37
+ // import { captured_payment } from "std/money_flows"
38
+ // party payer: person
39
+ // party payee: business
40
+ // settlement card_payment = captured_payment {
41
+ // payer: payer
42
+ // payee: payee
43
+ // amount: authorizedAmount: money(SAR)
44
+ // reserve_until: reserveUntil
45
+ // correction: port correct_capture
46
+ // external_reversal: port reverse_capture within P14D
47
+ // capture_mode: partial_then_full
48
+ // correction_mode: full_only
49
+ // negative_position: reject
50
+ // timeout: reject
51
+ // }
52
+ // port correct_capture { allowed: [payee] }
53
+ // port reverse_capture {
54
+ // allowed: [payee]
55
+ // shape: { externalReference: text }
56
+ // }
57
+ // ```
3
58
  export instrument captured_payment<C>(payer: party, payee: party, amount: money<C>, reserve_until: date, correction: condition, external_reversal: condition, capture_mode: text, correction_mode: text, negative_position: text, timeout: text, derived_amount: optional<block>) {
4
59
  let(correction_name): correction;
5
60
  let(reversal_name): external_reversal;
@@ -1,5 +1,51 @@
1
1
  module std.money_flows.conditional_disbursement
2
2
 
3
+ // Capped disbursement from a source party to a destination party gated on stored external decision evidence.
4
+ //
5
+ // ### Purpose
6
+ // `conditional_disbursement` manages evidence-contingent payouts subject to a cumulative cap.
7
+ // It fits insurance claim settlements, grant tranches, subsidy distributions, and escrow milestones
8
+ // where each approved payment requires explicit external evidence and the total paid must not exceed `cap`.
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `advance`: `conditional_disbursement` disburses non-repayable funds against external evidence
12
+ // up to a declared cap. `advance` pays money up front with the expectation of repayment through carved
13
+ // hold releases or scheduled installments.
14
+ // - vs `instant_transfer`: `instant_transfer` moves money immediately with no evidence gate or cap.
15
+ // `conditional_disbursement` requires an external decision port and evidence reference before any child amount moves.
16
+ //
17
+ // ### Parameters
18
+ // - `source`: The funding party providing the money.
19
+ // - `destination`: The beneficiary party receiving approved disbursements.
20
+ // - `cap`: Maximum total amount that can be disbursed across all child approvals in minor units of currency `C`.
21
+ // - `amount`: Binding name for child approval amount values.
22
+ // - `decision`: Port conditioning approval, requiring evidence reference.
23
+ // - `reopen_policy`: Policy for reopening closed disbursements (`refuse`).
24
+ // - `recovery_policy`: Policy for recovering overpayments (`separate_transfer`).
25
+ //
26
+ // ### Decision ports
27
+ // - `decision`: External port providing decision evidence required to approve child disbursement amounts.
28
+ //
29
+ // ### Example
30
+ // ```hsx
31
+ // program conditional_disbursement_example "Conditional disbursement example"
32
+ // import { conditional_disbursement } from "std/money_flows"
33
+ // party source: business
34
+ // party claimant: person
35
+ // settlement claim_payment = conditional_disbursement {
36
+ // source: source
37
+ // destination: claimant
38
+ // cap: policyLimit: money(SAR)
39
+ // amount: approvedAmount: money(SAR)
40
+ // decision: port approve_claim
41
+ // reopen_policy: refuse
42
+ // recovery_policy: separate_transfer
43
+ // }
44
+ // port approve_claim {
45
+ // allowed: [source]
46
+ // shape: { evidenceReference: text }
47
+ // }
48
+ // ```
3
49
  export instrument conditional_disbursement<C>(
4
50
  source: party,
5
51
  destination: party,
@@ -1,5 +1,62 @@
1
1
  module std.money_flows.credit_facility
2
2
 
3
+ // Revolving credit line providing reusable borrowing capacity up to a limit backed by scheduled obligations.
4
+ //
5
+ // ### Purpose
6
+ // `credit_facility` manages revolving commercial credit, inventory financing, and overdraft facilities.
7
+ // A borrower can draw funds multiple times up to `limit` into `draw_destination`. Each draw creates a child
8
+ // record linked to a scheduled `obligation`. Repayments restore available borrowing capacity until `expires_at`.
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `advance`: `credit_facility` provides revolving, reusable credit lines where multiple draws can occur
12
+ // and repayments restore capacity. `advance` is a single upfront lump-sum disbursement with a fixed repayment plan.
13
+ // - vs `scheduled`: `scheduled` defines repayment installments or recurring transfers. `credit_facility` delegates
14
+ // draw repayments to a `scheduled` obligation while tracking total facility utilization and limit compliance.
15
+ //
16
+ // ### Parameters
17
+ // - `lender`: The financing institution or party providing the credit capacity.
18
+ // - `borrower`: The borrowing party authorized to draw against the facility limit.
19
+ // - `draw_destination`: Account or party receiving disbursed draw proceeds.
20
+ // - `limit`: Total revolving borrowing limit in minor units of currency `C`.
21
+ // - `expires_at`: Expiration date after which new draws cannot be opened.
22
+ // - `obligation`: Reference to a scheduled obligation instrument handling draw repayments.
23
+ // - `availability_policy`: Facility capacity availability policy (`revolving`).
24
+ // - `expiry_policy`: Policy on facility expiration (`freeze_draws`).
25
+ // - `close_policy`: Policy on facility closure (`no_open_draws`).
26
+ //
27
+ // ### Decision ports
28
+ // None on the facility itself. Mandates and decision ports are declared on the linked `obligation` instrument.
29
+ //
30
+ // ### Example
31
+ // ```hsx
32
+ // program credit_facility_example "Credit facility example"
33
+ // import { credit_facility, scheduled } from "std/money_flows"
34
+ // party lender: business
35
+ // party borrower: business
36
+ // party draw_destination: business
37
+ // party repayment_source: business
38
+ // settlement repayment = scheduled {
39
+ // mode: obligation
40
+ // payer: repayment_source
41
+ // payee: lender
42
+ // debtor: borrower
43
+ // amount: principal: money(SAR)
44
+ // count: 2
45
+ // every: P30D
46
+ // first_due: firstDueAt
47
+ // }
48
+ // settlement facility = credit_facility {
49
+ // lender: lender
50
+ // borrower: borrower
51
+ // draw_destination: draw_destination
52
+ // limit: facilityLimit: money(SAR)
53
+ // expires_at: expiresAt
54
+ // obligation: repayment.obligation
55
+ // availability_policy: revolving
56
+ // expiry_policy: freeze_draws
57
+ // close_policy: no_open_draws
58
+ // }
59
+ // ```
3
60
  export instrument credit_facility<C>(
4
61
  lender: party,
5
62
  borrower: party,
@@ -1,6 +1,66 @@
1
1
  module std.money_flows.held_payment
2
2
 
3
- export instrument held_payment<C>(payer: party, payee: party, amount: money<C>, release: condition, fees: optional<block>, on_cancel: optional<block>, derived_amount: optional<block>, release_to: optional<party>, whole_amount: optional<block>, release_action: optional<text>, whole_fee: optional<money<C>>, reference: optional<text>, upstream: optional<ref>, id_prefix_override: optional<text>) {
3
+ // Escrow settlement holding funds from a payer before releasing to a payee upon a verified condition or deadline.
4
+ //
5
+ // ### Purpose
6
+ // `held_payment` holds customer funds in a dedicated product escrow account away from both payer and payee.
7
+ // It fits milestone-gated commerce, vehicle escrow, contractor holdbacks, and goods purchases where funds
8
+ // must remain reserved until delivery confirmation or inspection.
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `cancellable_booking`: Both hold funds in custody and both can quote a cancellation before it is
12
+ // spent. `held_payment` quotes one flat charge declared by `cancel_charge_bps`, because it has no scheduled
13
+ // start to price against, and `on_cancel` remains the way to unwind it on static splits instead.
14
+ // Choose `cancellable_booking` when the charge must follow the time left before a scheduled start date.
15
+ // - vs `security_deposit`: `held_payment` releases or cancels the principal according to predefined splits.
16
+ // Choose `security_deposit` when the holder must assess damages and claim an arbitrary partial amount
17
+ // via a `decided amount` clause while returning the unspent remainder to the payer.
18
+ // - vs `swap`: `held_payment` is a one-way transfer from payer to payee. Choose `swap` for bilateral or
19
+ // multi-party atomic exchanges where all parties must fund their legs into escrow before simultaneous release.
20
+ // - vs `premium_forward`: Choose `premium_forward` for insurance premium collection requiring carrier policy
21
+ // binding conditions, broker commission retention, policy endorsements, and lapse schedules.
22
+ //
23
+ // ### Parameters
24
+ // - `payer`: The funding party providing the money.
25
+ // - `payee`: The beneficiary party receiving the released funds.
26
+ // - `amount`: Total amount in minor units of currency `C`.
27
+ // - `release`: Condition required to release funds. Supports decision ports (`port <name>`), date deadlines
28
+ // (`at(<date>)`), or disjunctions (`port <name> | at(<date>)`).
29
+ // - `fees`: Optional block declaring percentage or fixed fee cuts, e.g. `{ buyer: 1%, seller: 2% }`.
30
+ // - `on_cancel`: Optional block defining refund splits if cancelled while funded, e.g. `(funded) { buyer: 90%, seller: 10% }`.
31
+ // - `derived_amount`: Optional block declaring machine-derived fees calculated as a percentage of another field.
32
+ // - `release_to`: Optional third-party destination for release.
33
+ // - `whole_amount`: Optional block enabling single-action funding and release of principal plus on-top fee.
34
+ // - `release_action`: Optional custom name for the release action.
35
+ // - `whole_fee`: Optional money amount for the whole-amount fee.
36
+ // - `reference`: Optional string reference stored on the instance.
37
+ // - `upstream`: Optional reference to a parent instrument.
38
+ // - `id_prefix_override`: Optional custom prefix for generated instrument IDs.
39
+ // - `cancel_charge_bps`: Optional cancellation charge in basis points. Declaring it gives the settlement a
40
+ // quoted cancellation: `quote_cancellation` prices the charge and the refund and freezes both,
41
+ // `cancel` pays the refund to the payer, and `retain_cancellation_charge` pays the charge to the payee.
42
+ // - `cancel_offer_life`: ISO 8601 duration a cancellation quote stays open, required with `cancel_charge_bps`.
43
+ //
44
+ // ### Decision ports
45
+ // - `release`: Port deciding release authorization, answered by allowed parties declared in the port.
46
+ //
47
+ // ### Example
48
+ // ```hsx
49
+ // program held_payment_example "Held payment example"
50
+ // import { held_payment } from "std/money_flows"
51
+ // party buyer: person
52
+ // party seller: business
53
+ // settlement sale = held_payment {
54
+ // payer: buyer
55
+ // payee: seller
56
+ // amount: price: money(SAR)
57
+ // fees { buyer: 1% }
58
+ // on_cancel(funded) { buyer: 100% }
59
+ // release: port confirm_delivery | at(releaseDueAt)
60
+ // }
61
+ // port confirm_delivery { allowed: [buyer] }
62
+ // ```
63
+ export instrument held_payment<C>(payer: party, payee: party, amount: money<C>, release: condition, fees: optional<block>, on_cancel: optional<block>, derived_amount: optional<block>, release_to: optional<party>, whole_amount: optional<block>, release_action: optional<text>, whole_fee: optional<money<C>>, reference: optional<text>, upstream: optional<ref>, id_prefix_override: optional<text>, cancel_charge_bps: optional<integer>, cancel_offer_life: optional<text>) {
4
64
  let(release_name): release;
5
65
  let(release_actor_text): if_eq(len(release_allowed), 1, words(at(release_allowed, 1)), concat("a party allowed by ", release));
6
66
  let(payer_account_field): camel(concat(payer, "_account_id"));
@@ -19,6 +79,45 @@ export instrument held_payment<C>(payer: party, payee: party, amount: money<C>,
19
79
  }
20
80
  }
21
81
  }
82
+ when(cancel_charge_bps) {
83
+ when(on_cancel) {
84
+ unsupported {
85
+ code: HSX1110;
86
+ message: "a quoted cancellation cannot combine with on_cancel splits";
87
+ fix: "drop on_cancel and let cancel_charge_bps price the cancellation";
88
+ }
89
+ }
90
+ when(payee_fee) {
91
+ unsupported {
92
+ code: HSX1110;
93
+ message: "a quoted cancellation cannot combine with a payee fee";
94
+ fix: "drop the payee fee, or unwind through on_cancel splits instead of a quote";
95
+ }
96
+ }
97
+ when(whole_amount) {
98
+ unsupported {
99
+ code: HSX1110;
100
+ message: "a quoted cancellation cannot combine with whole_amount";
101
+ fix: "drop whole_amount, which cancels the whole hold without quoting it";
102
+ }
103
+ }
104
+ when_not(cancel_offer_life) {
105
+ unsupported {
106
+ code: HSX1110;
107
+ message: "a quoted cancellation needs cancel_offer_life";
108
+ fix: "declare how long the quote stays open, for example PT30M";
109
+ }
110
+ }
111
+ }
112
+ when(cancel_offer_life) {
113
+ when_not(cancel_charge_bps) {
114
+ unsupported {
115
+ code: HSX1110;
116
+ message: "cancel_offer_life needs a nonzero cancel_charge_bps to quote";
117
+ fix: "declare the cancellation charge in basis points, or drop cancel_offer_life";
118
+ }
119
+ }
120
+ }
22
121
  let(payer_bps): basis_points(payer_fee);
23
122
  let(payee_bps): basis_points(payee_fee);
24
123
  let(net_bps): sub(10000, payee_fee);
@@ -103,6 +202,7 @@ export instrument held_payment<C>(payer: party, payee: party, amount: money<C>,
103
202
  when_not(cancel_splits) {
104
203
  states created funded disputed released;
105
204
  when(on_cancel) { states cancelled; }
205
+ when(cancel_charge_bps) { states cancellation_quoted cancelled settled; }
106
206
  states abandoned;
107
207
  }
108
208
  when(cancel_splits) { states created funding_1 funded disputed releasing_1 released cancelling_1 cancelled abandoned; }
@@ -119,8 +219,17 @@ export instrument held_payment<C>(payer: party, payee: party, amount: money<C>,
119
219
  when_not(payee_fee) {
120
220
  when_not(cancel_splits) {
121
221
  on fund_piece_1: created -> funded;
122
- on [release_name]: funded -> released;
123
- when(release_deadline) { on release_on_deadline: funded -> released; }
222
+ when_not(cancel_charge_bps) {
223
+ on [release_name]: funded -> released;
224
+ when(release_deadline) { on release_on_deadline: funded -> released; }
225
+ }
226
+ when(cancel_charge_bps) {
227
+ on [release_name]: funded | cancellation_quoted -> released;
228
+ when(release_deadline) { on release_on_deadline: funded | cancellation_quoted -> released; }
229
+ on quote_cancellation: funded -> cancellation_quoted;
230
+ on cancel: cancellation_quoted -> cancelled;
231
+ on retain_cancellation_charge: cancelled -> settled;
232
+ }
124
233
  when(on_cancel) { on cancel: funded -> cancelled; }
125
234
  }
126
235
  when(cancel_splits) {
@@ -411,6 +520,44 @@ export instrument held_payment<C>(payer: party, payee: party, amount: money<C>,
411
520
  steps: [];
412
521
  }
413
522
  }
523
+ when(cancel_charge_bps) {
524
+ action quote_cancellation {
525
+ agent_description: concat("Price the cancellation and hold that price open. No money moves. The charge the ", words(payee), " keeps and the refund the ", words(payer), " gets back are worked out here and frozen for ", cancel_offer_life, ", after which a fresh call prices it again. Call cancel to spend the quote.");
526
+ summary: "Price the cancellation and hold that price open";
527
+ when(release_deadline) { deadline { field: release_deadline; }; }
528
+ quote {
529
+ baseField: amount;
530
+ chargeRef: cancellationChargeAmount;
531
+ charges: [{ bps: cancel_charge_bps; }];
532
+ expires { offset: cancel_offer_life; }
533
+ fixes: [amount, payer_account_field];
534
+ netDestinationField: payer_account_field;
535
+ netRef: cancellationRefundAmount;
536
+ }
537
+ moves: [];
538
+ steps: [];
539
+ }
540
+ action cancel {
541
+ let(metadata_instrument): "metadata.instrumentId";
542
+ let(metadata_instance): "metadata.instrumentInstanceId";
543
+ let(metadata_phase): "metadata.phase";
544
+ agent_description: concat("Spend the frozen quote and return the net refund to the ", words(payer), ". This moves money and does not reverse. It needs an un-expired quote from quote_cancellation, and the charge that refund left behind goes to the ", words(payee), " through retain_cancellation_charge.");
545
+ summary: concat("Spend the quoted cancellation and return the net to the ", words(payer));
546
+ commit: quote_cancellation;
547
+ when(release_deadline) { deadline { field: release_deadline; }; }
548
+ moves: [{ key: refund; operation: internal_transfer.create; bind: { amount: { from: instance; path: refs.cancellationRefundAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payer_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: cancel; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { cancelTransferTransferId: transferId; }; }];
549
+ steps: [];
550
+ }
551
+ action retain_cancellation_charge {
552
+ let(metadata_instrument): "metadata.instrumentId";
553
+ let(metadata_instance): "metadata.instrumentInstanceId";
554
+ let(metadata_phase): "metadata.phase";
555
+ agent_description: concat("Pay the quoted cancellation charge out of escrow to the ", words(payee), ". This moves money and does not reverse. The settlement must already be cancelled, so the figure is the one the quote fixed and the escrow ends empty.");
556
+ summary: concat("Pay the quoted cancellation charge to the ", words(payee));
557
+ moves: [{ key: charge; operation: internal_transfer.create; bind: { amount: { from: instance; path: refs.cancellationChargeAmount; }; currency: { from: instance; path: fields.currency; }; destinationAccountId: { from: instance; path: concat("fields.", payee_account_field); }; [metadata_instrument]: { from: const; value: instrument; }; [metadata_instance]: { from: instance; path: instrumentInstanceId; }; [metadata_phase]: { from: const; value: retain_cancellation_charge; }; productId: { from: instance; path: productId; }; sourceAccountId: { from: instance; path: refs.escrowAccountId; }; }; capture: { retainCancellationChargeTransferId: transferId; }; }];
558
+ steps: [];
559
+ }
560
+ }
414
561
  when(payee_fee) {
415
562
  when_not(on_cancel) {
416
563
  action fund_piece_2 {
@@ -1,5 +1,47 @@
1
1
  module std.money_flows.instant_transfer
2
2
 
3
+ // Direct, single-step push transfer from payer to payee with optional tiered or percentage fees.
4
+ //
5
+ // ### Purpose
6
+ // `instant_transfer` debits a payer and credits a payee immediately in a single execution step.
7
+ // It fits peer-to-peer transfers, direct disbursements, instant payouts, wallet reloads, and simple point-of-sale payments.
8
+ //
9
+ // ### Selection guidance
10
+ // - vs `captured_payment`: `instant_transfer` moves money in one atomic step without prior authorization holds,
11
+ // incremental captures, voids, or post-settlement correction ports. Use `captured_payment` when authorization must precede capture.
12
+ // - vs `conditional_disbursement`: `instant_transfer` executes immediately without external decision evidence
13
+ // or cumulative cap tracking. Use `conditional_disbursement` when payments require evidence submission or aggregate milestone caps.
14
+ // - vs `held_payment`: `instant_transfer` never holds funds in an intermediary escrow account.
15
+ //
16
+ // ### Parameters
17
+ // - `payer`: Funding party whose account is debited.
18
+ // - `payee`: Recipient party whose account is credited.
19
+ // - `amount`: Transfer amount in minor units of currency `C`.
20
+ // - `fees`: Optional fee configuration block specifying flat fees, percentage fees, or bracketed fee tiers for payer and/or payee.
21
+ // - `derived_amount`: Optional block declaring derived platform fees calculated from the transfer amount.
22
+ //
23
+ // ### Decision ports
24
+ // None. Transfers execute immediately upon invocation.
25
+ //
26
+ // ### Example
27
+ // ```hsx
28
+ // program instant_transfer_example "Instant transfer example"
29
+ // import { instant_transfer } from "std/money_flows"
30
+ // party customer: person
31
+ // party merchant: business
32
+ // settlement transfer = instant_transfer {
33
+ // payer: customer
34
+ // payee: merchant
35
+ // amount: transferAmount: money(SAR)
36
+ // fees {
37
+ // customer: checkoutFee: money(SAR)
38
+ // merchant {
39
+ // tier { from: 0, to: 10000, fee: 1% }
40
+ // tier { from: 10000, fee: highValueFee: money(SAR) }
41
+ // }
42
+ // }
43
+ // }
44
+ // ```
3
45
  export instrument instant_transfer<C>(payer: party, payee: party, amount: money<C>, fees: optional<block>, derived_amount: optional<block>) {
4
46
  let(payer_fee): get(fees, payer);
5
47
  let(payee_fee): get(fees, payee);
@@ -1,5 +1,46 @@
1
1
  module std.money_flows.metered
2
2
 
3
+ // Usage-based billing against a committed rate card over an open period until a stored close date.
4
+ //
5
+ // ### Purpose
6
+ // `metered` bills customers for variable resource consumption such as API requests, compute hours,
7
+ // storage gigabytes, or utility consumption. The rate card is fixed when the period opens, and individual
8
+ // usage events are charged incrementally until the billing period closes on `close_by`.
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `scheduled`: `metered` charges variable amounts per event calculated from consumed units and committed
12
+ // rate card prices. `scheduled` executes transfers on fixed calendar recurrence intervals (`every`, `first_due`)
13
+ // with predetermined amounts or installments.
14
+ // - vs `recurring_collection`: `metered` calculates and executes real ledger transfers for each usage charge.
15
+ // `recurring_collection` is a lightweight status tracker for collection runs without balance transfers or rate cards.
16
+ // - vs `instant_transfer`: `instant_transfer` executes a single immediate payment. `metered` manages a stateful
17
+ // open billing cycle accepting multiple usage charges under a fixed rate card.
18
+ //
19
+ // ### Parameters
20
+ // - `payer`: The customer being billed for usage.
21
+ // - `payee`: The service provider receiving usage revenue.
22
+ // - `close_by`: Date when the metering period closes, preventing further usage charges.
23
+ // - `rates`: Block mapping rate metric names to their per-unit money prices committed at period open.
24
+ //
25
+ // ### Decision ports
26
+ // None. Charges are driven by caller billing actions and period closure.
27
+ //
28
+ // ### Example
29
+ // ```hsx
30
+ // program metered_example "Metered example"
31
+ // import { metered } from "std/money_flows"
32
+ // party customer: business
33
+ // party provider: business
34
+ // settlement usage = metered {
35
+ // payer: customer
36
+ // payee: provider
37
+ // close_by: periodEnd
38
+ // rates {
39
+ // api_call: callRate: money(SAR)
40
+ // storage_gib: storageRate: money(SAR)
41
+ // }
42
+ // }
43
+ // ```
3
44
  export instrument metered(
4
45
  payer: party,
5
46
  payee: party,
@@ -1,5 +1,46 @@
1
1
  module std.money_flows.pooled_split
2
2
 
3
+ // Fixed multi-recipient revenue or period pool funded share-by-share and released automatically on a due date.
4
+ //
5
+ // ### Purpose
6
+ // `pooled_split` pools a period total from one payer and splits it across a fixed roster of recipients
7
+ // according to predetermined percentage shares (with integer division remainder assigned to `remainder_to`).
8
+ // Callers fund the pool share-by-share, and payouts disburse automatically to each recipient on `payout_due`.
9
+ //
10
+ // ### Selection guidance
11
+ // - vs `weighted_distribution`: `pooled_split` hardcodes a fixed set of recipients and static percentage shares
12
+ // directly in the contract. `weighted_distribution` handles dynamic recipient counts where arbitrary weights
13
+ // are recorded as child records and frozen via a snapshot port before distribution.
14
+ // - vs `settlement_batch`: `settlement_batch` aggregates multiple payments from many sources into one net payout.
15
+ // `pooled_split` takes one period total from one payer and partitions it out to multiple recipients.
16
+ //
17
+ // ### Parameters
18
+ // - `payer`: The funding party providing the pooled amount.
19
+ // - `amount`: Total pooled amount in minor units of currency `C`.
20
+ // - `payout_due`: Stored payout date when the pool distributes to all recipients.
21
+ // - `split`: Block declaring each recipient's percentage share and `remainder_to` recipient for rounding remainders.
22
+ //
23
+ // ### Decision ports
24
+ // None. Payout distribution triggers automatically from the stored `payout_due` date.
25
+ //
26
+ // ### Example
27
+ // ```hsx
28
+ // program pooled_split_example "Pooled split example"
29
+ // import { pooled_split } from "std/money_flows"
30
+ // party payer: business
31
+ // party first_recipient: business
32
+ // party second_recipient: business
33
+ // settlement pool = pooled_split {
34
+ // payer: payer
35
+ // amount: poolAmount: money(SAR)
36
+ // payout_due: payoutDueAt
37
+ // split {
38
+ // first_recipient: 60%
39
+ // second_recipient: 40%
40
+ // remainder_to: first_recipient
41
+ // }
42
+ // }
43
+ // ```
3
44
  export instrument pooled_split<C>(payer: party, amount: money<C>, payout_due: date, split: block) {
4
45
  let(recipients): keys_except(split, "remainder_to");
5
46
  let(recipient_count): len(recipients);