Skip to content

Commit

Permalink
chore: Oracle methods to public (#732)
Browse files Browse the repository at this point in the history
## Description
- Modified some methods of oracle to public to decrease code duplication in peggo

#### Helps #661
#### Closes: #734
----

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added appropriate labels to the PR
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/umee-network/umee/blob/main/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)

(cherry picked from commit b934ac2)
  • Loading branch information
RafilxTenfen authored and mergify-bot committed Apr 4, 2022
1 parent 8ffec4b commit f1f62e4
Show file tree
Hide file tree
Showing 4 changed files with 279 additions and 68 deletions.
5 changes: 5 additions & 0 deletions price-feeder/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements

- [#684](https://github.com/umee-network/umee/pull/684) Log errors when providers are unable to unmarshal candles and tickers, instead of either one.
- [#732](https://github.com/umee-network/umee/pull/732) Set oracle functions to public to facilitate usage in other repositories.

### Bugs

- [#732](https://github.com/umee-network/umee/pull/732) Fixes an issue where filtering out erroneous providers' candles wasn't working.

## [v0.1.4](https://github.com/umee-network/umee/releases/tag/price-feeder%2Fv0.1.4) - 2022-03-24

Expand Down
139 changes: 72 additions & 67 deletions price-feeder/oracle/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const (

// deviationThreshold defines how many 𝜎 a provider can be away from the mean
// without being considered faulty.
var deviationThreshold = sdk.MustNewDecFromStr("2")
var deviationThreshold = sdk.MustNewDecFromStr("1.0")

// PreviousPrevote defines a structure for defining the previous prevote
// submitted on-chain.
Expand Down Expand Up @@ -228,23 +228,8 @@ func (o *Oracle) SetPrices(ctx context.Context, acceptList oracletypes.DenomList
// e.g.: {ProviderKraken: {"ATOM": <price, volume>, ...}}
mtx.Lock()
for _, pair := range acceptedPairs {
if _, ok := providerPrices[providerName]; !ok {
providerPrices[providerName] = make(map[string]provider.TickerPrice)
}
if _, ok := providerCandles[providerName]; !ok {
providerCandles[providerName] = make(map[string][]provider.CandlePrice)
}

tp, pricesOk := prices[pair.String()]
cp, candlesOk := candles[pair.String()]
if pricesOk {
providerPrices[providerName][pair.Base] = tp
}
if candlesOk {
providerCandles[providerName][pair.Base] = cp
}

if !pricesOk && !candlesOk {
success := SetProviderTickerPricesAndCandles(providerName, providerPrices, providerCandles, prices, candles, pair)
if !success {
mtx.Unlock()
return fmt.Errorf("failed to find any exchange rates in provider responses")
}
Expand All @@ -259,74 +244,92 @@ func (o *Oracle) SetPrices(ctx context.Context, acceptList oracletypes.DenomList
o.logger.Debug().Err(err).Msg("failed to get ticker prices from provider")
}

filteredCandles, err := o.filterCandleDeviations(providerCandles)
computedPrices, err := GetComputedPrices(o.logger, providerCandles, providerPrices)
if err != nil {
return err
}

if len(computedPrices) != len(requiredRates) {
return fmt.Errorf("unable to get prices for all exchange candles")
}
for base := range requiredRates {
if _, ok := computedPrices[base]; !ok {
return fmt.Errorf("reported prices were not equal to required rates, missed: %s", base)
}
}

o.prices = computedPrices
return nil
}

// GetComputedPrices gets the candle and ticker prices and computes it.
// It returns candles' TVWAP if possible, if not possible (not available
// or due to some staleness) it will use the most recent ticker prices
// and the VWAP formula instead.
func GetComputedPrices(
logger zerolog.Logger,
providerCandles provider.AggregatedProviderCandles,
providerPrices provider.AggregatedProviderPrices,
) (prices map[string]sdk.Dec, err error) {
filteredCandles, err := FilterCandleDeviations(logger, providerCandles)
if err != nil {
return nil, err
}

// attempt to use candles for TVWAP calculations
tvwapPrices, err := ComputeTVWAP(filteredCandles)
if err != nil {
return err
return nil, err
}

// If TVWAP candles are not available or were filtered out due to staleness,
// use most recent prices & VWAP instead.
if len(tvwapPrices) == 0 {
filteredProviderPrices, err := o.filterTickerDeviations(providerPrices)
filteredProviderPrices, err := FilterTickerDeviations(logger, providerPrices)
if err != nil {
return err
return nil, err
}

vwapPrices, err := ComputeVWAP(filteredProviderPrices)
if err != nil {
return err
return nil, err
}

// warn the user of any missing prices
reportedPrices := make(map[string]struct{})
for _, providers := range filteredProviderPrices {
for base := range providers {
if _, ok := reportedPrices[base]; !ok {
reportedPrices[base] = struct{}{}
}
}
}
return vwapPrices, nil
}

if len(reportedPrices) != len(requiredRates) {
return fmt.Errorf("unable to get prices for all exchange prices")
}
for base := range requiredRates {
if _, ok := reportedPrices[base]; !ok {
return fmt.Errorf("reported prices were not equal to required rates")
}
}
return tvwapPrices, nil
}

o.prices = vwapPrices
} else {
// warn the user of any missing candles
reportedCandles := make(map[string]struct{})
for _, providers := range filteredCandles {
for base := range providers {
if _, ok := reportedCandles[base]; !ok {
reportedCandles[base] = struct{}{}
}
}
}
// SetProviderTickerPricesAndCandles flattens and collects prices for
// candles and tickers based on the base currency per provider.
// Returns true if at least one of price or candle exists.
func SetProviderTickerPricesAndCandles(
providerName string,
providerPrices provider.AggregatedProviderPrices,
providerCandles provider.AggregatedProviderCandles,
prices map[string]provider.TickerPrice,
candles map[string][]provider.CandlePrice,
pair types.CurrencyPair,
) (success bool) {
if _, ok := providerPrices[providerName]; !ok {
providerPrices[providerName] = make(map[string]provider.TickerPrice)
}
if _, ok := providerCandles[providerName]; !ok {
providerCandles[providerName] = make(map[string][]provider.CandlePrice)
}

if len(reportedCandles) != len(requiredRates) {
return fmt.Errorf("unable to get prices for all exchange candles")
}
for base := range requiredRates {
if _, ok := reportedCandles[base]; !ok {
return fmt.Errorf("reported candles were not equal to required rates")
}
}
tp, pricesOk := prices[pair.String()]
cp, candlesOk := candles[pair.String()]

o.prices = tvwapPrices
if pricesOk {
providerPrices[providerName][pair.Base] = tp
}
if candlesOk {
providerCandles[providerName][pair.Base] = cp
}

return nil
return pricesOk || candlesOk
}

// GetParams returns the current on-chain parameters of the x/oracle module.
Expand Down Expand Up @@ -405,9 +408,10 @@ func NewProvider(ctx context.Context, providerName string, logger zerolog.Logger
return nil, fmt.Errorf("provider %s not found", providerName)
}

// filterTickerDeviations finds the standard deviations of the prices of
// FilterTickerDeviations finds the standard deviations of the prices of
// all assets, and filters out any providers that are not within 2𝜎 of the mean.
func (o *Oracle) filterTickerDeviations(
func FilterTickerDeviations(
logger zerolog.Logger,
prices provider.AggregatedProviderPrices,
) (provider.AggregatedProviderPrices, error) {
var (
Expand Down Expand Up @@ -442,7 +446,7 @@ func (o *Oracle) filterTickerDeviations(
filteredPrices[providerName][base] = tp
} else {
telemetry.IncrCounter(1, "failure", "provider", "type", "ticker")
o.logger.Warn().
logger.Warn().
Str("base", base).
Str("provider", providerName).
Str("price", tp.Price.String()).
Expand All @@ -454,9 +458,10 @@ func (o *Oracle) filterTickerDeviations(
return filteredPrices, nil
}

// filterCandleDeviations finds the standard deviations of the tvwaps of
// FilterCandleDeviations finds the standard deviations of the tvwaps of
// all assets, and filters out any providers that are not within 2𝜎 of the mean.
func (o *Oracle) filterCandleDeviations(
func FilterCandleDeviations(
logger zerolog.Logger,
candles provider.AggregatedProviderCandles,
) (provider.AggregatedProviderCandles, error) {
var (
Expand Down Expand Up @@ -507,7 +512,7 @@ func (o *Oracle) filterCandleDeviations(
filteredCandles[providerName][base] = candles[providerName][base]
} else {
telemetry.IncrCounter(1, "failure", "provider", "type", "candle")
o.logger.Warn().
logger.Warn().
Str("base", base).
Str("provider", providerName).
Str("price", price.String()).
Expand Down
Loading

0 comments on commit f1f62e4

Please sign in to comment.