@hyperscale0/hsx 3.2.0 → 4.0.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/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/src/ast.d.ts +17 -2
- package/dist/src/ast.d.ts.map +1 -1
- package/dist/src/ast.js.map +1 -1
- package/dist/src/cli.js +1 -1
- package/dist/src/compile.d.ts +6 -0
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +1194 -97
- package/dist/src/compile.js.map +1 -1
- package/dist/src/cost.d.ts +1 -1
- package/dist/src/cost.d.ts.map +1 -1
- package/dist/src/cost.js +52 -9
- package/dist/src/cost.js.map +1 -1
- package/dist/src/headers.d.ts +2 -2
- package/dist/src/headers.d.ts.map +1 -1
- package/dist/src/headers.js +3 -2
- package/dist/src/headers.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lex.d.ts +1 -1
- package/dist/src/lex.d.ts.map +1 -1
- package/dist/src/lex.js +5 -0
- package/dist/src/lex.js.map +1 -1
- package/dist/src/parse.js +91 -5
- package/dist/src/parse.js.map +1 -1
- package/dist/src/std-bundle.d.ts.map +1 -1
- package/dist/src/std-bundle.js +10 -9
- package/dist/src/std-bundle.js.map +1 -1
- package/dist/src/version.d.ts +2 -2
- package/dist/src/version.js +2 -2
- package/docs/README.md +51 -27
- package/docs/headers.md +43 -40
- package/examples/cost-table.json +40 -324
- package/examples/library.hsx +12 -57
- package/package.json +7 -5
- package/src/ast.ts +11 -1
- package/src/cli.ts +1 -1
- package/src/compile.ts +1630 -114
- package/src/cost.ts +60 -16
- package/src/headers.ts +3 -2
- package/src/index.ts +12 -1
- package/src/lex.ts +5 -0
- package/src/parse.ts +87 -5
- package/src/std-bundle.ts +10 -9
- package/src/version.ts +2 -2
- package/std/approvals.hsx +3 -3
- package/std/collections.hsx +45 -4
- package/std/escrow.hsx +17 -8
- package/std/financing.hsx +292 -42
- package/std/insurance.hsx +4 -5
- package/std/lending.hsx +7 -8
- package/std/marketplace.hsx +90 -6
- package/std/money.hsx +15 -49
- package/std/reporting.hsx +1286 -0
- package/std/travel.hsx +5 -6
package/std/lending.hsx
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
header lending
|
|
2
2
|
|
|
3
|
-
instrument round(borrower: party,
|
|
3
|
+
instrument round(borrower: party, plan: ref<financing.installments> = object(financing.installments), minimum_ticket: money = 100 SAR, investor_cap: percent = 20%, commitments: ref<lending.commitment> = object(lending.commitment)) {
|
|
4
4
|
summary: "A threshold funding round; failed rounds return each original wallet contribution."
|
|
5
5
|
fields {
|
|
6
|
-
borrower: account of borrower,
|
|
7
|
-
months: integer = months, profit: money = rate(self.price, profit)
|
|
6
|
+
borrower: account of borrower, plan: ref<plan>, price: money = self.plan.principal, closesAt: date
|
|
8
7
|
minimumTicket: money = minimum_ticket, maximumTicket: money = rate(self.price, investor_cap)
|
|
9
8
|
held: account of self
|
|
10
9
|
}
|
|
11
10
|
lifecycle { states: [open, funded, failed], initial: open }
|
|
12
|
-
action create { requires unique "funding_plan" on [self.plan]; requires self.
|
|
11
|
+
action create { requires unique "funding_plan" on [self.plan]; requires self.borrower == self.plan.funds.payer }
|
|
13
12
|
action close {
|
|
14
13
|
from: open, to: funded
|
|
15
14
|
requires sum "amount" of { instrument: commitments, reference: "round", anchor: self.id, states: [committed], limit: 366 } == self.price
|
|
@@ -58,13 +57,13 @@ instrument distribution(round: ref<lending.round>, receipt: ref, commitments: re
|
|
|
58
57
|
held: account of self, losses: account(self, claim), residualLoss: account(residual_to, claim, "loss")
|
|
59
58
|
}
|
|
60
59
|
lifecycle { states: [pending, cash_ready, loss_ready, distributed], initial: pending }
|
|
61
|
-
action create { requires self.round in [funded]; requires self.source.plan == self.round.plan; requires unique "settlement_consumption" on [self.source.plan, self.source.identity] }
|
|
60
|
+
action create { requires self.round in [funded]; requires self.source in [recorded]; requires self.source.plan == self.round.plan; requires unique "settlement_consumption" on [self.source.plan, self.source.identity] }
|
|
62
61
|
action prepare_cash {
|
|
63
62
|
from: pending, to: cash_ready
|
|
64
|
-
requires self.mode == "cash"; requires self.source.kind == "cash"
|
|
63
|
+
requires self.mode == "cash"; requires self.source.kind == "cash"; requires self.source in [recorded]
|
|
65
64
|
calculate: [
|
|
66
65
|
{ target: "principal", op: "sum", values: [{ field: self.source.principal }] }
|
|
67
|
-
{ target: "profit", op: "sum", values: [{ field: self.source.
|
|
66
|
+
{ target: "profit", op: "sum", values: [{ field: self.source.retainedProfit }] }
|
|
68
67
|
{ target: "charge", op: "rate", base: { field: self.profit }, bps: { literal: fee }, rounding: "floor" }
|
|
69
68
|
{ target: "vat", op: "rate", base: { field: self.charge }, bps: { literal: tax }, rounding: "floor" }
|
|
70
69
|
{ target: "grossTotal", op: "sum", values: [{ field: self.principal }, { field: self.profit }] }
|
|
@@ -73,7 +72,7 @@ instrument distribution(round: ref<lending.round>, receipt: ref, commitments: re
|
|
|
73
72
|
}
|
|
74
73
|
action prepare_loss {
|
|
75
74
|
from: pending, to: loss_ready
|
|
76
|
-
requires self.mode == "loss"; requires self.source.kind == "loss"
|
|
75
|
+
requires self.mode == "loss"; requires self.source.kind == "loss"; requires self.source in [recorded]
|
|
77
76
|
calculate: [{ target: "net", op: "sum", values: [{ field: self.source.loss }] }]
|
|
78
77
|
}
|
|
79
78
|
action distribute_cash {
|
package/std/marketplace.hsx
CHANGED
|
@@ -1,24 +1,108 @@
|
|
|
1
1
|
header marketplace
|
|
2
2
|
|
|
3
3
|
instrument listing(seller: party) {
|
|
4
|
+
revisioned: true
|
|
4
5
|
summary: "A seller's offer and its asking price."
|
|
5
6
|
fields { seller: account of seller, title: text, price: money }
|
|
6
7
|
lifecycle { states: [draft, active, withdrawn, sold], initial: draft }
|
|
7
8
|
action create { actor: { party: seller } }
|
|
8
|
-
action publish {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
action publish {
|
|
10
|
+
from: draft, to: active, actor: { party: seller }
|
|
11
|
+
}
|
|
12
|
+
action withdraw { from: active, to: withdrawn, actor: { party: seller }, requires count of { instrument: all(marketplace.reservation), reference: "listing", anchor: self.id, states: [active], limit: 366 } == 0 }
|
|
13
|
+
action sell { from: active, to: sold, actor: { party: seller }, requires count of { instrument: all(marketplace.reservation), reference: "listing", anchor: self.id, states: [active], limit: 366 } == 0 }
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
instrument order(listing: ref<marketplace.listing>, buyer: party) {
|
|
17
|
+
revisioned: true
|
|
14
18
|
summary: "A buyer's order for one listing at its declared price."
|
|
15
|
-
fields { listing: ref<listing>, buyer: account of buyer, price: money }
|
|
16
|
-
lifecycle { states: [placed, fulfilled, cancelled], initial:
|
|
19
|
+
fields { listing: ref<listing>, buyer: account of buyer, price: money, reservations: integer?, ownReservations: integer?, blockingQuotes: integer?, ownBlockingQuotes: integer? }
|
|
20
|
+
lifecycle { states: [quoted, placed, fulfilled, cancelled], initial: quoted }
|
|
17
21
|
action create {
|
|
18
22
|
actor: { party: buyer }
|
|
19
23
|
requires self.listing in [active]
|
|
24
|
+
calculate: [
|
|
25
|
+
{ target: blockingQuotes, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: "listing", anchor: self.listing, states: [active], limit: 366, where: { quotePolicy: { literal: "blocked" } } }, measure: count }
|
|
26
|
+
{ target: ownBlockingQuotes, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: "listing", anchor: self.listing, states: [active], limit: 366, where: { quotePolicy: { literal: "blocked" }, buyer: { field: self.buyer } } }, measure: count }
|
|
27
|
+
]
|
|
28
|
+
requires self.blockingQuotes == self.ownBlockingQuotes
|
|
20
29
|
requires self.price == self.listing.price
|
|
21
30
|
}
|
|
31
|
+
action commit {
|
|
32
|
+
from: [quoted, placed], to: placed
|
|
33
|
+
requires self.listing in [active]
|
|
34
|
+
calculate: [
|
|
35
|
+
{ target: reservations, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: "listing", anchor: self.listing, states: [active], limit: 366 }, measure: count }
|
|
36
|
+
{ target: ownReservations, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: "listing", anchor: self.listing, states: [active], limit: 366, where: { buyer: { field: self.buyer } } }, measure: count }
|
|
37
|
+
]
|
|
38
|
+
requires self.reservations == self.ownReservations
|
|
39
|
+
requires count of { instrument: current(), reference: "listing", anchor: self.listing, states: [placed, fulfilled], limit: 366 } <= 1
|
|
40
|
+
}
|
|
41
|
+
invariants count of { instrument: current(), reference: "listing", anchor: self.listing, states: [placed, fulfilled], limit: 366 } <= 1
|
|
22
42
|
action fulfill { from: placed, to: fulfilled }
|
|
23
|
-
action cancel { from: placed, to: cancelled, actor: { party: buyer } }
|
|
43
|
+
action cancel { from: [quoted, placed], to: cancelled, actor: { party: buyer } }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
instrument reservation(listing: ref<marketplace.listing>, funds: ref<escrow.hold>, plans: ref<financing.installments>[], converters: ref[], buyer: party, seller: party, expires_after: duration = 48h, deposit: money = 1000 SAR, cancellation_refund: percent = 100%, expiry_refund: percent = 100%, retained_to: party = programOperator, operator: party = programOperator, competing_quotes: enum(allowed, blocked) = allowed) {
|
|
47
|
+
revisioned: true
|
|
48
|
+
summary: "Exclusive timed listing hold with explicit deposit credit and refund."
|
|
49
|
+
fields {
|
|
50
|
+
listing: ref<listing>, funds: ref<funds>, buyer: account of buyer, seller: account of seller, price: money, terms: text
|
|
51
|
+
held: account of self, quotePolicy: enum(allowed, blocked) = competing_quotes, deposit: money = deposit, proposalExpiresAt: date = after(self.createdAt, expires_after), expiresAt: date?
|
|
52
|
+
credit: money?, refund: money?, retained: money?, dispositionAt: date?, reason: text?
|
|
53
|
+
}
|
|
54
|
+
lifecycle { states: [proposed, active, converted, cancelled, expired], initial: proposed }
|
|
55
|
+
invariants count of { instrument: current(), reference: "listing", anchor: self.listing, states: [active], limit: 366 } <= 1
|
|
56
|
+
action create { actor: { party: buyer }, requires self.listing in [active]; requires self.seller == self.listing.seller; requires self.price == self.listing.price }
|
|
57
|
+
action activate {
|
|
58
|
+
from: proposed, to: active, actor: { party: buyer }, deadline: { at: self.proposalExpiresAt }
|
|
59
|
+
calculate: [{ target: expiresAt, op: shift, date: { field: self.now }, milliseconds: { literal: expires_after }, direction: after }]
|
|
60
|
+
requires self.listing in [active]; requires self.price == self.listing.price
|
|
61
|
+
requires count of { instrument: all(marketplace.order), reference: "listing", anchor: self.listing, states: [placed, fulfilled], limit: 366 } == 0
|
|
62
|
+
moves self.deposit from self.buyer to self.held
|
|
63
|
+
}
|
|
64
|
+
action convert_financed {
|
|
65
|
+
from: active, to: active, actor: { party: buyer }, deadline: { at: self.expiresAt }
|
|
66
|
+
input { plan: ref<plans> }
|
|
67
|
+
requires input.plan.funds == self.funds; requires input.plan.borrower == self.buyer
|
|
68
|
+
invoke: [{ reference: input.plan, action: disburse, input: {} }]
|
|
69
|
+
}
|
|
70
|
+
action convert_cash {
|
|
71
|
+
from: active, to: active, actor: { party: buyer }, deadline: { at: self.expiresAt }
|
|
72
|
+
invoke: [{ reference: self.funds, action: fund, input: {} }]
|
|
73
|
+
}
|
|
74
|
+
action credit {
|
|
75
|
+
from: active, to: converted, actor: { parent: converters }, deadline: { at: self.expiresAt }
|
|
76
|
+
input { funds: ref<funds>, contribution: money }
|
|
77
|
+
requires input.funds == self.funds; requires input.funds in [pending, funded]; requires input.funds.payer == self.buyer; requires input.funds.price == self.price
|
|
78
|
+
requires input.contribution <= self.price
|
|
79
|
+
calculate: [{ target: credit, op: minimum, values: [{ field: self.held.balance }, { field: input.contribution }] }, { target: refund, op: subtract, base: { field: self.held.balance }, subtract: [{ field: self.credit }] }]
|
|
80
|
+
set: { dispositionAt: { field: self.now } }
|
|
81
|
+
moves self.credit from self.held to input.funds.held
|
|
82
|
+
moves self.refund from self.held to self.buyer
|
|
83
|
+
}
|
|
84
|
+
action cancel {
|
|
85
|
+
from: active, to: cancelled, actor: { party: buyer }, input { reason: text }
|
|
86
|
+
calculate: [{ target: refund, op: rate, base: { field: self.held.balance }, bps: { literal: cancellation_refund }, rounding: floor }, { target: retained, op: subtract, base: { field: self.held.balance }, subtract: [{ field: self.refund }] }]
|
|
87
|
+
set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }
|
|
88
|
+
moves self.refund from self.held to self.buyer; moves self.retained from self.held to retained_to
|
|
89
|
+
}
|
|
90
|
+
action seller_cancel {
|
|
91
|
+
from: active, to: cancelled, actor: { party: seller }, input { reason: text }
|
|
92
|
+
set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }
|
|
93
|
+
moves self.held.balance from self.held to self.buyer
|
|
94
|
+
}
|
|
95
|
+
action operator_cancel {
|
|
96
|
+
from: active, to: cancelled, actor: { party: operator }, input { reason: text }
|
|
97
|
+
set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }
|
|
98
|
+
moves self.held.balance from self.held to self.buyer
|
|
99
|
+
}
|
|
100
|
+
action withdraw { from: proposed, to: cancelled, actor: { party: buyer } }
|
|
101
|
+
action expire {
|
|
102
|
+
from: active, to: expired, actor: clock, due: { at: self.expiresAt }
|
|
103
|
+
calculate: [{ target: refund, op: rate, base: { field: self.held.balance }, bps: { literal: expiry_refund }, rounding: floor }, { target: retained, op: subtract, base: { field: self.held.balance }, subtract: [{ field: self.refund }] }]
|
|
104
|
+
set: { dispositionAt: { field: self.now } }
|
|
105
|
+
moves self.refund from self.held to self.buyer; moves self.retained from self.held to retained_to
|
|
106
|
+
}
|
|
107
|
+
action expire_proposal { from: proposed, to: expired, actor: clock, due: { at: self.proposalExpiresAt } }
|
|
24
108
|
}
|
package/std/money.hsx
CHANGED
|
@@ -130,23 +130,24 @@ instrument deposit(payer: party, payee: party, amount: money, expires: date, app
|
|
|
130
130
|
action cancel { from: pending, to: cancelled }
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
instrument payout(payer: party, payee: party,
|
|
134
|
-
summary: "
|
|
135
|
-
fields { amount: money = amount,
|
|
136
|
-
lifecycle { states: [pending, instructed, settled,
|
|
133
|
+
instrument payout(payer: party, payee: party, adapter: text, max_age: duration, amount: money = runtime) {
|
|
134
|
+
summary: "Reserve funds until matching terminal boundary evidence permits posting."
|
|
135
|
+
fields { amount: money = amount, receipt: text? }
|
|
136
|
+
lifecycle { states: [pending, instructed, settled, rejected], initial: pending }
|
|
137
137
|
action create {}
|
|
138
|
-
action instruct {
|
|
139
|
-
|
|
140
|
-
from
|
|
141
|
-
requires self.receipt.status == "settled"
|
|
138
|
+
action instruct {
|
|
139
|
+
from: pending, to: instructed, actor: { party: payer }, humanApproval: "distinct_member"
|
|
140
|
+
moves reserve self.amount from payer to payee capture "receipt" boundary adapter
|
|
142
141
|
}
|
|
143
|
-
action
|
|
144
|
-
from: instructed, to:
|
|
145
|
-
requires self.
|
|
142
|
+
action confirm {
|
|
143
|
+
from: instructed, to: settled
|
|
144
|
+
requires evidence self.id family boundary check outcome result confirmed maxAge max_age instruction self.receipt
|
|
145
|
+
moves post self.receipt
|
|
146
146
|
}
|
|
147
|
-
action
|
|
148
|
-
from:
|
|
149
|
-
requires self.
|
|
147
|
+
action reject {
|
|
148
|
+
from: instructed, to: rejected
|
|
149
|
+
requires evidence self.id family boundary check outcome result rejected maxAge max_age instruction self.receipt
|
|
150
|
+
moves void self.receipt
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
|
|
@@ -158,38 +159,3 @@ instrument metered(payer: party, payee: party, unit_price: money, units: integer
|
|
|
158
159
|
action bill { from: recorded, to: billed, moves self.amount from payer to payee fee fee }
|
|
159
160
|
action cancel { from: recorded, to: cancelled }
|
|
160
161
|
}
|
|
161
|
-
|
|
162
|
-
instrument batch(payer: party, payee: party, closes: date, approval: approval, reconcile_within: duration = 3d) {
|
|
163
|
-
summary: "A frozen positive net of credit and debit entries, paid once."
|
|
164
|
-
fields { closesAt: date = closes, credits: money, debits: money, amount: money = subtract(self.credits, self.debits), bank: account(payee, cash, external, "bank"), receipt: text?, instructedAt: date?, expectedAt: date? }
|
|
165
|
-
lifecycle { states: [open, closed, approved, instructed, exception, paid, reversed], initial: open }
|
|
166
|
-
action create {}
|
|
167
|
-
action close {
|
|
168
|
-
from: open, to: closed, actor: clock, due: { at: self.closesAt }
|
|
169
|
-
requires sum "amount" of { instrument: credit, reference: "batch", anchor: self.id, states: [recorded], limit: 366 } == self.credits
|
|
170
|
-
requires sum "amount" of { instrument: debit, reference: "batch", anchor: self.id, states: [recorded], limit: 366 } == self.debits
|
|
171
|
-
requires self.amount > "0"
|
|
172
|
-
}
|
|
173
|
-
action approve { from: closed, to: approved, requires approval by approval }
|
|
174
|
-
action pay {
|
|
175
|
-
from: approved, to: instructed
|
|
176
|
-
set: { instructedAt: { field: self.now } }
|
|
177
|
-
calculate: [{ target: "expectedAt", op: "shift", date: { field: self.now }, milliseconds: { literal: reconcile_within }, direction: "after" }]
|
|
178
|
-
moves self.amount from payer to self.bank capture "receipt"
|
|
179
|
-
}
|
|
180
|
-
action confirm { from: [instructed, exception], to: paid, requires self.receipt.status == "settled" }
|
|
181
|
-
action expire { from: instructed, to: exception, actor: clock, due: { at: self.expectedAt }, requires self.receipt.status != "settled" }
|
|
182
|
-
action reverse { from: [instructed, exception], to: reversed, requires self.receipt.status == "reversed" }
|
|
183
|
-
records {
|
|
184
|
-
credit: {
|
|
185
|
-
fields { batch: ref<parent>, identity: text, amount: money }
|
|
186
|
-
lifecycle { states: [recorded], initial: recorded }
|
|
187
|
-
action create { requires self.batch in [open]; requires unique "batch_credit" on [self.identity] }
|
|
188
|
-
}
|
|
189
|
-
debit: {
|
|
190
|
-
fields { batch: ref<parent>, identity: text, amount: money }
|
|
191
|
-
lifecycle { states: [recorded], initial: recorded }
|
|
192
|
-
action create { requires self.batch in [open]; requires unique "batch_debit" on [self.identity] }
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|