-
Notifications
You must be signed in to change notification settings - Fork 353
/
market.go
193 lines (169 loc) · 5.29 KB
/
market.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package types
import (
"errors"
"fmt"
"strings"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Market an asset in the pricefeed
type Market struct {
MarketID string `json:"market_id" yaml:"market_id"`
BaseAsset string `json:"base_asset" yaml:"base_asset"`
QuoteAsset string `json:"quote_asset" yaml:"quote_asset"`
Oracles []sdk.AccAddress `json:"oracles" yaml:"oracles"`
Active bool `json:"active" yaml:"active"`
}
// NewMarket returns a new Market
func NewMarket(id, base, quote string, oracles []sdk.AccAddress, active bool) Market {
return Market{
MarketID: id,
BaseAsset: base,
QuoteAsset: quote,
Oracles: oracles,
Active: active,
}
}
// String implement fmt.Stringer
func (m Market) String() string {
return fmt.Sprintf(`Asset:
Market ID: %s
Base Asset: %s
Quote Asset: %s
Oracles: %s
Active: %t`,
m.MarketID, m.BaseAsset, m.QuoteAsset, m.Oracles, m.Active)
}
// Validate performs a basic validation of the market params
func (m Market) Validate() error {
if strings.TrimSpace(m.MarketID) == "" {
return errors.New("market id cannot be blank")
}
if err := sdk.ValidateDenom(m.BaseAsset); err != nil {
return fmt.Errorf("invalid base asset: %w", err)
}
if err := sdk.ValidateDenom(m.QuoteAsset); err != nil {
return fmt.Errorf("invalid quote asset: %w", err)
}
seenOracles := make(map[string]bool)
for i, oracle := range m.Oracles {
if oracle.Empty() {
return fmt.Errorf("oracle %d is empty", i)
}
if seenOracles[oracle.String()] {
return fmt.Errorf("duplicated oracle %s", oracle)
}
seenOracles[oracle.String()] = true
}
return nil
}
// Markets array type for oracle
type Markets []Market
// Validate checks if all the markets are valid and there are no duplicated
// entries.
func (ms Markets) Validate() error {
seenMarkets := make(map[string]bool)
for _, m := range ms {
if seenMarkets[m.MarketID] {
return fmt.Errorf("duplicated market %s", m.MarketID)
}
if err := m.Validate(); err != nil {
return err
}
seenMarkets[m.MarketID] = true
}
return nil
}
// String implements fmt.Stringer
func (ms Markets) String() string {
out := "Markets:\n"
for _, m := range ms {
out += fmt.Sprintf("%s\n", m.String())
}
return strings.TrimSpace(out)
}
// CurrentPrice struct that contains the metadata of a current price for a particular market in the pricefeed module.
type CurrentPrice struct {
MarketID string `json:"market_id" yaml:"market_id"`
Price sdk.Dec `json:"price" yaml:"price"`
}
// NewCurrentPrice returns an instance of CurrentPrice
func NewCurrentPrice(marketID string, price sdk.Dec) CurrentPrice {
return CurrentPrice{MarketID: marketID, Price: price}
}
// CurrentPrices type for an array of CurrentPrice
type CurrentPrices []CurrentPrice
// PostedPrice price for market posted by a specific oracle
type PostedPrice struct {
MarketID string `json:"market_id" yaml:"market_id"`
OracleAddress sdk.AccAddress `json:"oracle_address" yaml:"oracle_address"`
Price sdk.Dec `json:"price" yaml:"price"`
Expiry time.Time `json:"expiry" yaml:"expiry"`
}
// NewPostedPrice returns a new PostedPrice
func NewPostedPrice(marketID string, oracle sdk.AccAddress, price sdk.Dec, expiry time.Time) PostedPrice {
return PostedPrice{
MarketID: marketID,
OracleAddress: oracle,
Price: price,
Expiry: expiry,
}
}
// Validate performs a basic check of a PostedPrice params.
func (pp PostedPrice) Validate() error {
if strings.TrimSpace(pp.MarketID) == "" {
return errors.New("market id cannot be blank")
}
if pp.OracleAddress.Empty() {
return errors.New("oracle address cannot be empty")
}
if pp.Price.IsNegative() {
return fmt.Errorf("posted price cannot be negative %s", pp.Price)
}
if pp.Expiry.Unix() <= 0 {
return errors.New("expiry time cannot be zero")
}
return nil
}
// PostedPrices type for an array of PostedPrice
type PostedPrices []PostedPrice
// Validate checks if all the posted prices are valid and there are no duplicated
// entries.
func (pps PostedPrices) Validate() error {
seenPrices := make(map[string]bool)
for _, pp := range pps {
if pp.OracleAddress != nil && seenPrices[pp.MarketID+pp.OracleAddress.String()] {
return fmt.Errorf("duplicated posted price for marked id %s and oracle address %s", pp.MarketID, pp.OracleAddress)
}
if err := pp.Validate(); err != nil {
return err
}
seenPrices[pp.MarketID+pp.OracleAddress.String()] = true
}
return nil
}
// implement fmt.Stringer
func (cp CurrentPrice) String() string {
return strings.TrimSpace(fmt.Sprintf(`Market ID: %s
Price: %s`, cp.MarketID, cp.Price))
}
// implement fmt.Stringer
func (pp PostedPrice) String() string {
return strings.TrimSpace(fmt.Sprintf(`Market ID: %s
Oracle Address: %s
Price: %s
Expiry: %s`, pp.MarketID, pp.OracleAddress, pp.Price, pp.Expiry))
}
// String implements fmt.Stringer
func (ps PostedPrices) String() string {
out := "Posted Prices:\n"
for _, p := range ps {
out += fmt.Sprintf("%s\n", p.String())
}
return strings.TrimSpace(out)
}
// SortDecs provides the interface needed to sort sdk.Dec slices
type SortDecs []sdk.Dec
func (a SortDecs) Len() int { return len(a) }
func (a SortDecs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortDecs) Less(i, j int) bool { return a[i].LT(a[j]) }