@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.
- package/CHANGELOG.md +20 -0
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/std-bundle.js +19 -19
- package/dist/src/std-bundle.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/docs/guide/01-first-program.md +1 -1
- package/docs/llms-full.txt +43 -38
- package/docs/llms.txt +2 -2
- package/docs/reference/cli.md +2 -2
- package/docs/reference/diagnostics.md +1 -1
- package/docs/reference/grammar.md +1 -1
- package/docs/reference/std/advance.md +1 -1
- package/docs/reference/std/cancellable_booking.md +1 -1
- package/docs/reference/std/captured_payment.md +1 -1
- package/docs/reference/std/conditional_disbursement.md +1 -1
- package/docs/reference/std/credit_facility.md +1 -1
- package/docs/reference/std/held_payment.md +41 -36
- package/docs/reference/std/instant_transfer.md +1 -1
- package/docs/reference/std/metered.md +1 -1
- package/docs/reference/std/pooled_split.md +1 -1
- package/docs/reference/std/premium_forward.md +1 -1
- package/docs/reference/std/reconciled_payout.md +1 -1
- package/docs/reference/std/recurring_collection.md +1 -1
- package/docs/reference/std/rotating_pool.md +1 -1
- package/docs/reference/std/scheduled.md +1 -1
- package/docs/reference/std/security_deposit.md +1 -1
- package/docs/reference/std/settlement_batch.md +1 -1
- package/docs/reference/std/swap.md +1 -1
- package/docs/reference/std/threshold_pool.md +1 -1
- package/docs/reference/std/weighted_distribution.md +1 -1
- package/docs/reference/types.md +1 -1
- package/docs/reference/udl-output.md +1 -1
- package/package.json +3 -3
- package/skills/hsx/SKILL.md +2 -2
- package/src/std-bundle.ts +19 -19
- package/src/version.ts +1 -1
- package/std/money_flows/advance.hsx +45 -0
- package/std/money_flows/cancellable_booking.hsx +45 -0
- package/std/money_flows/captured_payment.hsx +55 -0
- package/std/money_flows/conditional_disbursement.hsx +46 -0
- package/std/money_flows/credit_facility.hsx +57 -0
- package/std/money_flows/held_payment.hsx +150 -3
- package/std/money_flows/instant_transfer.hsx +42 -0
- package/std/money_flows/metered.hsx +41 -0
- package/std/money_flows/pooled_split.hsx +41 -0
- package/std/money_flows/premium_forward.hsx +51 -0
- package/std/money_flows/reconciled_payout.hsx +42 -0
- package/std/money_flows/recurring_collection.hsx +45 -0
- package/std/money_flows/rotating_pool.hsx +51 -0
- package/std/money_flows/scheduled.hsx +53 -0
- package/std/money_flows/security_deposit.hsx +58 -0
- package/std/money_flows/settlement_batch.hsx +51 -0
- package/std/money_flows/swap.hsx +53 -0
- package/std/money_flows/threshold_pool.hsx +51 -0
- package/std/money_flows/weighted_distribution.hsx +54 -0
package/src/version.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
123
|
-
|
|
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);
|