json.gno
6.42 Kb · 149 lines
1package markets
2
3import (
4 "strconv"
5 "strings"
6)
7
8// Gno 1.5.0 has no encoding/json. These read-only projections write explicit
9// fields with JSON string escaping. Amounts in ugnot and micro-shares are
10// strings, so JavaScript never rounds them; prices, times and counts are numbers.
11
12// MarketJSON returns one market with its quote history.
13func MarketJSON(id string) string {
14 r := mustMarket(id)
15 m := r.market
16 var out strings.Builder
17 out.WriteString(`{"id":` + jsonString(m.ID) + `,"question":` + jsonString(m.Question) + `,"rules":` + jsonString(m.Rules))
18 out.WriteString(`,"rulesHash":` + jsonString(m.RulesHash) + `,"conditionId":` + jsonString(m.ConditionID))
19 out.WriteString(`,"yesTokenId":` + jsonString(m.YesTokenID) + `,"noTokenId":` + jsonString(m.NoTokenID))
20 out.WriteString(`,"yesLabel":` + jsonString(m.YesLabel) + `,"noLabel":` + jsonString(m.NoLabel))
21 out.WriteString(`,"oracle":` + jsonString(string(m.Oracle)) + `,"treasury":` + jsonString(string(m.Treasury)) + `,"topic":` + jsonString(m.Topic))
22 out.WriteString(`,"feePpm":` + decimal(m.FeePpm) + `,"createdAt":` + decimal(m.CreatedAt))
23 out.WriteString(`,"tradingEndsAt":` + decimal(m.TradingEndsAt) + `,"abandonAt":` + decimal(m.AbandonAt))
24 out.WriteString(`,"yesPricePpm":` + decimal(m.YesPricePpm) + `,"noPricePpm":` + decimal(m.NoPricePpm))
25 out.WriteString(`,"quoteVersion":` + decimal(m.QuoteVersion) + `,"quotedAt":` + decimal(m.QuotedAt))
26 out.WriteString(`,"state":` + jsonString(m.State) + `,"outcome":` + jsonString(m.Outcome) + `,"evidenceHash":` + jsonString(m.EvidenceHash))
27 out.WriteString(`,"proposedAt":` + decimal(m.ProposedAt) + `,"finalizedAt":` + decimal(m.FinalizedAt))
28 amounts := []struct {
29 key string
30 value int64
31 }{
32 {"escrowUgnot", m.EscrowUgnot}, {"feesUgnot", m.FeesUgnot}, {"reserveUgnot", m.ReserveUgnot}, {"costUgnot", m.CostUgnot},
33 {"feesCollectedUgnot", m.FeesCollectedUgnot}, {"yesMicroShares", m.YesMicroShares}, {"noMicroShares", m.NoMicroShares},
34 {"paidUgnot", m.PaidUgnot}, {"refundedCostUgnot", m.RefundedCostUgnot}, {"refundedFeesUgnot", m.RefundedFeesUgnot},
35 {"withdrawnUgnot", m.WithdrawnUgnot}, {"maxTradeMicroShares", m.MaxTradeMicroShares},
36 {"maxHolderMicroShares", m.MaxHolderMicroShares}, {"maxSideMicroShares", m.MaxSideMicroShares}, {"volumeUgnot", m.VolumeUgnot},
37 }
38 for _, a := range amounts {
39 out.WriteString(`,"` + a.key + `":` + jsonString(decimal(a.value)))
40 }
41 out.WriteString(`,"holders":` + decimal(m.Holders) + `,"trades":` + decimal(m.Trades))
42 out.WriteString(`,"history":` + historyJSON(r.history) + `}`)
43 return out.String()
44}
45
46// MarketsJSON returns every market in creation order as one JSON array.
47func MarketsJSON() string {
48 var out strings.Builder
49 out.WriteByte('[')
50 for i, id := range marketIDs {
51 if i > 0 {
52 out.WriteByte(',')
53 }
54 out.WriteString(MarketJSON(id))
55 }
56 out.WriteByte(']')
57 return out.String()
58}
59
60// PositionJSON returns one open position; an empty one if the owner holds
61// nothing there or has claimed.
62func PositionJSON(id string, owner address) string {
63 p := GetPosition(id, owner)
64 return `{"yesMicroShares":` + jsonString(decimal(p.YesMicroShares)) + `,"noMicroShares":` + jsonString(decimal(p.NoMicroShares)) +
65 `,"spentUgnot":` + jsonString(decimal(p.SpentUgnot)) + `,"feeUgnot":` + jsonString(decimal(p.FeeUgnot)) + `}`
66}
67
68// PositionsJSON returns the owner's open positions in market creation order.
69// Claimed positions are gone; their record is in the Claimed events.
70func PositionsJSON(owner address) string {
71 var out strings.Builder
72 out.WriteByte('[')
73 first := true
74 for _, id := range marketIDs {
75 if _, ok := records[id].positions[owner]; !ok {
76 continue
77 }
78 if !first {
79 out.WriteByte(',')
80 }
81 first = false
82 out.WriteString(`{"marketId":` + jsonString(id) + `,"position":` + PositionJSON(id, owner) + `}`)
83 }
84 out.WriteByte(']')
85 return out.String()
86}
87
88// RealmJSON returns the roles, settings, limits and totals.
89func RealmJSON() string {
90 return `{"administrator":` + jsonString(string(administrator)) + `,"pendingAdministrator":` + jsonString(string(pendingAdministrator)) +
91 `,"quoter":` + jsonString(string(quoter)) + `,"pendingQuoter":` + jsonString(string(pendingQuoter)) +
92 `,"guardian":` + jsonString(string(guardian)) + `,"pendingGuardian":` + jsonString(string(pendingGuardian)) +
93 `,"lister":` + jsonString(string(lister)) + `,"pendingLister":` + jsonString(string(pendingLister)) +
94 `,"listingTerms":{"oracle":` + jsonString(string(listingOracle)) + `,"treasury":` + jsonString(string(listingTreasury)) + `,"feePpm":` + decimal(listingFeePpm) + `}` +
95 `,"paused":` + strconv.FormatBool(realmPaused) + `,"quoteTtl":` + decimal(quoteTTL) + `,"minSpreadPpm":` + decimal(minSpreadPpm) +
96 `,"maxExposureMicroShares":` + jsonString(decimal(maxExposure)) + `,"openExposureMicroShares":` + jsonString(decimal(openExposure)) +
97 `,"heldUgnot":` + jsonString(decimal(totalHeldUgnot)) +
98 `,"defaultLimits":{"maxTradeMicroShares":` + jsonString(decimal(defaultLimits.MaxTradeMicroShares)) +
99 `,"maxHolderMicroShares":` + jsonString(decimal(defaultLimits.MaxHolderMicroShares)) +
100 `,"maxSideMicroShares":` + jsonString(decimal(defaultLimits.MaxSideMicroShares)) + `}` +
101 `,"maxFeePpm":` + decimal(MaxFeePpm) + `,"minPricePpm":` + decimal(MinPricePpm) + `,"maxPricePpm":` + decimal(MaxPricePpm) +
102 `,"disputeWindow":` + decimal(DisputeWindow) + `,"abandonAfter":` + decimal(AbandonAfter) + `,"markets":` + strconv.Itoa(len(marketIDs)) + `}`
103}
104
105func historyJSON(points []QuotePoint) string {
106 var out strings.Builder
107 out.WriteByte('[')
108 for i, point := range points {
109 if i > 0 {
110 out.WriteByte(',')
111 }
112 out.WriteString(`{"at":` + decimal(point.At) + `,"yesPricePpm":` + decimal(point.YesPricePpm) + `,"noPricePpm":` + decimal(point.NoPricePpm) + `,"version":` + decimal(point.Version) + `}`)
113 }
114 out.WriteByte(']')
115 return out.String()
116}
117
118func jsonString(value string) string {
119 var out strings.Builder
120 out.WriteByte('"')
121 for _, character := range value {
122 switch character {
123 case '"', '\\':
124 out.WriteByte('\\')
125 out.WriteRune(character)
126 case '\b':
127 out.WriteString(`\b`)
128 case '\f':
129 out.WriteString(`\f`)
130 case '\n':
131 out.WriteString(`\n`)
132 case '\r':
133 out.WriteString(`\r`)
134 case '\t':
135 out.WriteString(`\t`)
136 default:
137 if character < 32 {
138 const digits = "0123456789abcdef"
139 out.WriteString(`\u00`)
140 out.WriteByte(digits[byte(character)/16])
141 out.WriteByte(digits[byte(character)%16])
142 } else {
143 out.WriteRune(character)
144 }
145 }
146 }
147 out.WriteByte('"')
148 return out.String()
149}