code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/market/oracle_configs.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package market 17 18 import ( 19 "embed" 20 "errors" 21 "fmt" 22 23 "code.vegaprotocol.io/vega/core/datasource" 24 "code.vegaprotocol.io/vega/core/integration/steps/helpers" 25 "code.vegaprotocol.io/vega/core/integration/steps/market/defaults" 26 vegapb "code.vegaprotocol.io/vega/protos/vega" 27 28 "github.com/jinzhu/copier" 29 ) 30 31 var ( 32 //go:embed defaults/oracle-config/*future.json 33 defaultOracleConfigs embed.FS 34 defaultOracleConfigFileNames = []string{ 35 "defaults/oracle-config/default-eth-for-future.json", 36 "defaults/oracle-config/default-usd-for-future.json", 37 "defaults/oracle-config/default-dai-for-future.json", 38 } 39 //go:embed defaults/oracle-config/*perps.json 40 defaultOraclePerpsConfigs embed.FS 41 defaultPerpsOracleConfigFileNames = []string{ 42 "defaults/oracle-config/default-eth-for-perps.json", 43 "defaults/oracle-config/default-usd-for-perps.json", 44 "defaults/oracle-config/default-dai-for-perps.json", 45 } 46 47 // swap out the oracle names for future with perp oracles. 48 perpsSwapMapping = map[string]string{ 49 "default-eth-for-future": "default-eth-for-perps", 50 "default-usd-for-future": "default-usd-for-perps", 51 "default-dai-for-future": "default-dai-for-perps", 52 } 53 ) 54 55 type Binding interface { 56 Descriptor() ([]byte, []int) 57 GetSettlementDataProperty() string 58 ProtoMessage() 59 } 60 61 type BindType interface { 62 *vegapb.DataSourceSpecToFutureBinding | *vegapb.DataSourceSpecToPerpetualBinding 63 } 64 65 type oracleConfigs struct { 66 futures *oConfig[*vegapb.DataSourceSpecToFutureBinding] 67 perps *oConfig[*vegapb.DataSourceSpecToPerpetualBinding] 68 fullPerps map[string]*vegapb.Perpetual 69 fullFutures map[string]*vegapb.Future 70 perpSwap bool 71 compositePriceOracles map[string]CompositePriceOracleConfig 72 timeTriggers map[string]*datasource.Spec 73 } 74 75 type oConfig[T BindType] struct { 76 configForSettlementData map[string]*OracleConfig[T] 77 configFoTradingTermination map[string]*OracleConfig[T] 78 configForSchedule map[string]*OracleConfig[T] 79 settlementDataDecimals map[string]uint32 80 } 81 82 type OracleConfig[T BindType] struct { 83 Spec *vegapb.OracleSpec 84 Binding T 85 } 86 87 type CompositePriceOracleConfig struct { 88 Spec *vegapb.OracleSpec 89 Binding *vegapb.SpecBindingForCompositePrice 90 } 91 92 func newOracleSpecs(unmarshaler *defaults.Unmarshaler) *oracleConfigs { 93 configs := &oracleConfigs{ 94 futures: newOConfig[*vegapb.DataSourceSpecToFutureBinding](), 95 perps: newOConfig[*vegapb.DataSourceSpecToPerpetualBinding](), 96 fullPerps: map[string]*vegapb.Perpetual{}, 97 fullFutures: map[string]*vegapb.Future{}, 98 compositePriceOracles: map[string]CompositePriceOracleConfig{}, 99 timeTriggers: map[string]*datasource.Spec{}, 100 } 101 configs.futureOracleSpecs(unmarshaler) 102 configs.perpetualOracleSpecs(unmarshaler) 103 return configs 104 } 105 106 func newOConfig[T BindType]() *oConfig[T] { 107 return &oConfig[T]{ 108 configForSettlementData: map[string]*OracleConfig[T]{}, 109 configFoTradingTermination: map[string]*OracleConfig[T]{}, 110 configForSchedule: map[string]*OracleConfig[T]{}, 111 settlementDataDecimals: map[string]uint32{}, 112 } 113 } 114 115 func (c *oracleConfigs) SwapToPerps() { 116 c.perpSwap = true 117 } 118 119 func (c *oracleConfigs) CheckName(name string) string { 120 if !c.perpSwap { 121 return name 122 } 123 if alt, ok := perpsSwapMapping[name]; ok { 124 return alt 125 } 126 return name 127 } 128 129 func (c *oracleConfigs) futureOracleSpecs(unmarshaler *defaults.Unmarshaler) { 130 contentReaders := helpers.ReadAll(defaultOracleConfigs, defaultOracleConfigFileNames) 131 for name, contentReader := range contentReaders { 132 future, err := unmarshaler.UnmarshalDataSourceConfig(contentReader) 133 if err != nil { 134 panic(fmt.Errorf("couldn't unmarshal default data source config %s: %v", name, err)) 135 } 136 if err := c.AddFuture(name, future); err != nil { 137 panic(fmt.Errorf("failed to add default data source config %s: %v", name, err)) 138 } 139 } 140 } 141 142 func (c *oracleConfigs) perpetualOracleSpecs(unmarshaler *defaults.Unmarshaler) { 143 contentReaders := helpers.ReadAll(defaultOraclePerpsConfigs, defaultPerpsOracleConfigFileNames) 144 for name, contentReader := range contentReaders { 145 perp, err := unmarshaler.UnmarshalPerpsDataSourceConfig(contentReader) 146 if err != nil { 147 panic(fmt.Errorf("couldn't unmarshal default data source config %s: %v", name, err)) 148 } 149 if err := c.AddPerp(name, perp); err != nil { 150 panic(fmt.Errorf("failed to add default data source config %s: %v", name, err)) 151 } 152 } 153 } 154 155 func (c *oracleConfigs) SetSettlementDataDP(name string, decimals uint32) { 156 // for now, wing it and set for both 157 c.futures.SetSettlementDataDP(name, decimals) 158 c.perps.SetSettlementDataDP(name, decimals) 159 } 160 161 func (f *oConfig[T]) SetSettlementDataDP(name string, decimals uint32) { 162 f.settlementDataDecimals[name] = decimals 163 } 164 165 func (c *oracleConfigs) GetSettlementDataDP(name string) uint32 { 166 fd, ok := c.futures.GetSettlementDataDP(name) 167 if !ok { 168 fd, _ = c.perps.GetSettlementDataDP(name) 169 } 170 return fd 171 } 172 173 func (f *oConfig[T]) GetSettlementDataDP(name string) (uint32, bool) { 174 dp, ok := f.settlementDataDecimals[name] 175 if ok { 176 return dp, ok 177 } 178 return 0, ok 179 } 180 181 func (c *oracleConfigs) AddFuture(name string, future *vegapb.Future) error { 182 if err := c.futures.Add(name, "settlement data", future.DataSourceSpecForSettlementData, future.DataSourceSpecBinding); err != nil { 183 return err 184 } 185 if err := c.futures.Add(name, "trading termination", future.DataSourceSpecForTradingTermination, future.DataSourceSpecBinding); err != nil { 186 return err 187 } 188 c.fullFutures[name] = future 189 return nil 190 } 191 192 func (c *oracleConfigs) AddCompositePriceOracle(name string, spec *vegapb.DataSourceSpec, binding *vegapb.SpecBindingForCompositePrice) { 193 c.compositePriceOracles[name] = CompositePriceOracleConfig{ 194 Spec: &vegapb.OracleSpec{ 195 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 196 Spec: spec, 197 }, 198 }, 199 Binding: binding, 200 } 201 } 202 203 func (c *oracleConfigs) AddPerp(name string, perp *vegapb.Perpetual) error { 204 if err := c.perps.Add(name, "settlement data", perp.DataSourceSpecForSettlementData, perp.DataSourceSpecBinding); err != nil { 205 return err 206 } 207 if err := c.perps.Add(name, "settlement schedule", perp.DataSourceSpecForSettlementSchedule, perp.DataSourceSpecBinding); err != nil { 208 return err 209 } 210 c.fullPerps[name] = perp 211 return nil 212 } 213 214 func (c *oracleConfigs) AddTimeTrigger(name string, spec *datasource.Spec) error { 215 c.timeTriggers[name] = spec 216 return nil 217 } 218 219 func (c *oracleConfigs) Add(name, specType string, spec *vegapb.DataSourceSpec, binding Binding) error { 220 switch bt := binding.(type) { 221 case *vegapb.DataSourceSpecToPerpetualBinding: 222 return c.perps.Add(name, specType, spec, bt) 223 case *vegapb.DataSourceSpecToFutureBinding: 224 return c.futures.Add(name, specType, spec, bt) 225 default: 226 panic("unsupported binding type") 227 } 228 return nil 229 } 230 231 func (f *oConfig[T]) Add( 232 name string, 233 specType string, 234 spec *vegapb.DataSourceSpec, 235 binding T, 236 ) error { 237 if specType == "settlement data" { 238 f.configForSettlementData[name] = &OracleConfig[T]{ 239 Spec: &vegapb.OracleSpec{ 240 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 241 Spec: spec, 242 }, 243 }, 244 Binding: binding, 245 } 246 for _, filter := range spec.GetData().GetFilters() { 247 if filter.Key.NumberDecimalPlaces != nil { 248 f.settlementDataDecimals[name] = uint32(*filter.Key.NumberDecimalPlaces) 249 break 250 } 251 } 252 } else if specType == "trading termination" { 253 f.configFoTradingTermination[name] = &OracleConfig[T]{ 254 Spec: &vegapb.OracleSpec{ 255 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 256 Spec: spec, 257 }, 258 }, 259 Binding: binding, 260 } 261 } else if specType == "settlement schedule" { 262 f.configForSchedule[name] = &OracleConfig[T]{ 263 Spec: &vegapb.OracleSpec{ 264 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 265 Spec: spec, 266 }, 267 }, 268 Binding: binding, 269 } 270 } else { 271 return errors.New("unknown oracle spec type definition - expecting settlement data or trading termination") 272 } 273 274 return nil 275 } 276 277 func (c *oracleConfigs) GetFullInstrument(name string) (*vegapb.Instrument, error) { 278 var instrument vegapb.Instrument 279 if fut, ok := c.fullFutures[name]; ok { 280 instrument.Product = &vegapb.Instrument_Future{ 281 Future: fut, 282 } 283 return &instrument, nil 284 } 285 if perp, ok := c.fullPerps[name]; ok { 286 instrument.Product = &vegapb.Instrument_Perpetual{ 287 Perpetual: perp, 288 } 289 return &instrument, nil 290 } 291 return nil, fmt.Errorf("no products with name %s found", name) 292 } 293 294 func (c *oracleConfigs) GetOracleDefinitionForCompositePrice(name string) (*vegapb.OracleSpec, *vegapb.SpecBindingForCompositePrice, error) { 295 if oc, found := c.compositePriceOracles[name]; !found { 296 return nil, nil, fmt.Errorf("oracle config for composite price not found") 297 } else { 298 return oc.Spec, oc.Binding, nil 299 } 300 } 301 302 func (c *oracleConfigs) GetFuture(name, specType string) (*OracleConfig[*vegapb.DataSourceSpecToFutureBinding], error) { 303 return c.futures.Get(name, specType) 304 } 305 306 func (c *oracleConfigs) GetPerps(name, specType string) (*OracleConfig[*vegapb.DataSourceSpecToPerpetualBinding], error) { 307 return c.perps.Get(name, specType) 308 } 309 310 func (c *oracleConfigs) GetFullPerp(name string) (*vegapb.Perpetual, error) { 311 // if we're swapping to perps, ensure we have the correct oracle name 312 if c.perpSwap { 313 name = c.CheckName(name) 314 } 315 perp, ok := c.fullPerps[name] 316 if !ok { 317 return nil, fmt.Errorf("perpetual product with name %s not found", name) 318 } 319 copyConfig := &vegapb.Perpetual{} 320 if err := copier.Copy(copyConfig, perp); err != nil { 321 panic(fmt.Errorf("failed to deep copy oracle config: %v", err)) 322 } 323 return copyConfig, nil 324 } 325 326 func (c *oracleConfigs) GetFullFuture(name string) (*vegapb.Future, error) { 327 future, ok := c.fullFutures[name] 328 if !ok { 329 return nil, fmt.Errorf("future product with name %s not found", name) 330 } 331 copyConfig := &vegapb.Future{} 332 if err := copier.Copy(copyConfig, future); err != nil { 333 panic(fmt.Errorf("failed to deep copy oracle config: %v", err)) 334 } 335 return copyConfig, nil 336 } 337 338 func (f *oConfig[T]) Get(name string, specType string) (*OracleConfig[T], error) { 339 var cfg map[string]*OracleConfig[T] 340 341 if specType == "settlement data" { 342 cfg = f.configForSettlementData 343 } else if specType == "trading termination" { 344 cfg = f.configFoTradingTermination 345 } else if specType == "settlement schedule" { 346 cfg = f.configForSchedule 347 } else { 348 return nil, errors.New("unknown oracle spec type definition - expecting settlement data or trading termination") 349 } 350 351 config, ok := cfg[name] 352 if !ok { 353 return config, fmt.Errorf("no oracle spec \"%s\" registered", name) 354 } 355 // Copy to avoid modification between tests. 356 copyConfig := &OracleConfig[T]{} 357 if err := copier.Copy(copyConfig, config); err != nil { 358 panic(fmt.Errorf("failed to deep copy oracle config: %v", err)) 359 } 360 return copyConfig, nil 361 } 362 363 func (c *oracleConfigs) GetTimeTrigger(name string) (*datasource.Spec, error) { 364 ds, ok := c.timeTriggers[name] 365 if !ok { 366 return nil, fmt.Errorf("oracle name not found") 367 } 368 return ds, nil 369 }