@hyperscale0/hsx 3.1.0 → 3.3.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.
@@ -1,24 +1,111 @@
1
1
  header marketplace
2
2
 
3
- instrument listing(seller: party) {
3
+ instrument listing(seller: party, vehicle_facts: enum(optional, required) = optional) {
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 { from: draft, to: active, actor: { party: seller } }
9
- action withdraw { from: active, to: withdrawn, actor: { party: seller } }
10
- action sell { from: active, to: sold, actor: { party: seller } }
9
+ action publish {
10
+ from: draft, to: active, actor: { party: seller }
11
+ when vehicle_facts is required { requires count of { instrument: all(vehicles.vehicle), reference: "listing", anchor: self.id, states: [draft], limit: 1 } == 1 }
12
+ invoke: [{ selection: { instrument: all(vehicles.vehicle), reference: "listing", anchor: self.id, states: [draft], limit: 1 }, action: publish, input: {} }]
13
+ }
14
+ 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 }
15
+ 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
16
  }
12
17
 
13
18
  instrument order(listing: ref<marketplace.listing>, buyer: party) {
19
+ revisioned: true
14
20
  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: placed }
21
+ fields { listing: ref<listing>, buyer: account of buyer, price: money, reservations: integer?, ownReservations: integer?, blockingQuotes: integer?, ownBlockingQuotes: integer? }
22
+ lifecycle { states: [quoted, placed, fulfilled, cancelled], initial: quoted }
17
23
  action create {
18
24
  actor: { party: buyer }
19
25
  requires self.listing in [active]
26
+ calculate: [
27
+ { target: blockingQuotes, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: "listing", anchor: self.listing, states: [active], limit: 366, where: { quotePolicy: { literal: "blocked" } } }, measure: count }
28
+ { 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 }
29
+ ]
30
+ requires self.blockingQuotes == self.ownBlockingQuotes
20
31
  requires self.price == self.listing.price
21
32
  }
33
+ action commit {
34
+ from: [quoted, placed], to: placed
35
+ requires self.listing in [active]
36
+ calculate: [
37
+ { target: reservations, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: "listing", anchor: self.listing, states: [active], limit: 366 }, measure: count }
38
+ { 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 }
39
+ ]
40
+ requires self.reservations == self.ownReservations
41
+ requires count of { instrument: current(), reference: "listing", anchor: self.listing, states: [placed, fulfilled], limit: 366 } <= 1
42
+ }
43
+ invariants count of { instrument: current(), reference: "listing", anchor: self.listing, states: [placed, fulfilled], limit: 366 } <= 1
22
44
  action fulfill { from: placed, to: fulfilled }
23
- action cancel { from: placed, to: cancelled, actor: { party: buyer } }
45
+ action cancel { from: [quoted, placed], to: cancelled, actor: { party: buyer } }
46
+ }
47
+
48
+ 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) {
49
+ revisioned: true
50
+ summary: "Exclusive timed listing hold with explicit deposit credit and refund."
51
+ fields {
52
+ listing: ref<listing>, funds: ref<funds>, buyer: account of buyer, seller: account of seller, price: money, terms: text
53
+ held: account of self, quotePolicy: enum(allowed, blocked) = competing_quotes, deposit: money = deposit, proposalExpiresAt: date = after(self.createdAt, expires_after), expiresAt: date?
54
+ credit: money?, refund: money?, retained: money?, dispositionAt: date?, reason: text?
55
+ }
56
+ lifecycle { states: [proposed, active, converted, cancelled, expired], initial: proposed }
57
+ invariants count of { instrument: current(), reference: "listing", anchor: self.listing, states: [active], limit: 366 } <= 1
58
+ action create { actor: { party: buyer }, requires self.listing in [active]; requires self.seller == self.listing.seller; requires self.price == self.listing.price }
59
+ action activate {
60
+ from: proposed, to: active, actor: { party: buyer }, deadline: { at: self.proposalExpiresAt }
61
+ calculate: [{ target: expiresAt, op: shift, date: { field: self.now }, milliseconds: { literal: expires_after }, direction: after }]
62
+ requires self.listing in [active]; requires self.price == self.listing.price
63
+ requires count of { instrument: all(marketplace.order), reference: "listing", anchor: self.listing, states: [placed, fulfilled], limit: 366 } == 0
64
+ moves self.deposit from self.buyer to self.held
65
+ }
66
+ action convert_financed {
67
+ from: active, to: active, actor: { party: buyer }, deadline: { at: self.expiresAt }
68
+ input { plan: ref<plans> }
69
+ requires input.plan.funds == self.funds; requires input.plan.borrower == self.buyer
70
+ invoke: [{ reference: input.plan, action: disburse, input: {} }]
71
+ }
72
+ action convert_cash {
73
+ from: active, to: active, actor: { party: buyer }, deadline: { at: self.expiresAt }
74
+ invoke: [{ reference: self.funds, action: fund, input: {} }]
75
+ }
76
+ action credit {
77
+ from: active, to: converted, actor: { parent: converters }, deadline: { at: self.expiresAt }
78
+ input { funds: ref<funds>, contribution: money }
79
+ requires input.funds == self.funds; requires input.funds in [pending, funded]; requires input.funds.order.listing == self.listing; requires input.funds.payer == self.buyer; requires input.funds.price == self.price
80
+ requires input.contribution <= self.price
81
+ 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 }] }]
82
+ set: { dispositionAt: { field: self.now } }
83
+ moves self.credit from self.held to input.funds.held
84
+ moves self.refund from self.held to self.buyer
85
+ invoke: [{ reference: input.funds.order, action: commit, input: {} }]
86
+ }
87
+ action cancel {
88
+ from: active, to: cancelled, actor: { party: buyer }, input { reason: text }
89
+ 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 }] }]
90
+ set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }
91
+ moves self.refund from self.held to self.buyer; moves self.retained from self.held to retained_to
92
+ }
93
+ action seller_cancel {
94
+ from: active, to: cancelled, actor: { party: seller }, input { reason: text }
95
+ set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }
96
+ moves self.held.balance from self.held to self.buyer
97
+ }
98
+ action operator_cancel {
99
+ from: active, to: cancelled, actor: { party: operator }, input { reason: text }
100
+ set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }
101
+ moves self.held.balance from self.held to self.buyer
102
+ }
103
+ action withdraw { from: proposed, to: cancelled, actor: { party: buyer } }
104
+ action expire {
105
+ from: active, to: expired, actor: clock, due: { at: self.expiresAt }
106
+ 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 }] }]
107
+ set: { dispositionAt: { field: self.now } }
108
+ moves self.refund from self.held to self.buyer; moves self.retained from self.held to retained_to
109
+ }
110
+ action expire_proposal { from: proposed, to: expired, actor: clock, due: { at: self.proposalExpiresAt } }
24
111
  }
package/std/money.hsx CHANGED
@@ -135,7 +135,7 @@ instrument payout(payer: party, payee: party, amount: money = runtime, reconcile
135
135
  fields { amount: money = amount, bank: account(payee, cash, external, "bank"), receipt: text?, expectedAt: date = after(self.createdAt, reconcile_within) }
136
136
  lifecycle { states: [pending, instructed, settled, exception, reversed], initial: pending }
137
137
  action create {}
138
- action instruct { from: pending, to: instructed, actor: { party: payer }, moves self.amount from payer to self.bank capture "receipt" }
138
+ action instruct { from: pending, to: instructed, actor: { party: payer }, humanApproval: "distinct_member", moves self.amount from payer to self.bank capture "receipt" }
139
139
  action confirm {
140
140
  from: [instructed, exception], to: settled
141
141
  requires self.receipt.status == "settled"