Skip to content

Commit

Permalink
fix: currency provider tracker causing price feeder to error (#1781)
Browse files Browse the repository at this point in the history
* fix currency tracker

* price-feeder e2e timeout

* example config

* PR comments

* comment and changelog

---------

Co-authored-by: Sai Kumar <17549398+gsk967@users.noreply.github.com>
  • Loading branch information
rbajollari and gsk967 authored Feb 7, 2023
1 parent 852ff39 commit 89d2d3d
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 56 deletions.
2 changes: 2 additions & 0 deletions price-feeder/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

## Unreleased

- [1781](https://github.com/umee-network/umee/pull/1781) BTC was removed from example config since WBTC is used by the `Oracle` module instead.

## [v2.0.2](https://github.com/umee-network/umee/releases/tag/price-feeder/v2.0.2) 2022-12-14

### Bugs
Expand Down
104 changes: 68 additions & 36 deletions price-feeder/config/currency_provider_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
coinGeckoTickersEndpoint = "tickers"
osmosisV2RestURL = "https://api.osmo-api.network.umee.cc"
osmosisV2AssetPairsEndpoint = "assetpairs"
requestTimeout = time.Second * 2
trackingPeriod = time.Hour * 24
)

Expand Down Expand Up @@ -80,7 +81,12 @@ func NewCurrencyProviderTracker(
return nil, err
}

if err := currencyProviderTracker.setCurrencyProviders(); err != nil {
osmosisAPIPairs, err := currencyProviderTracker.getOsmosisAPIPairs()
if err != nil {
return nil, err
}

if err := currencyProviderTracker.setCurrencyProviders(osmosisAPIPairs); err != nil {
return nil, err
}

Expand Down Expand Up @@ -111,51 +117,71 @@ func (t *CurrencyProviderTracker) setCoinIDSymbolMap() error {
}

for _, coin := range listResponse {
t.coinIDSymbolMap[coin.Symbol] = coin.ID
if _, ok := t.coinIDSymbolMap[coin.Symbol]; !ok {
t.coinIDSymbolMap[coin.Symbol] = coin.ID
}
}

return nil
}

// setCurrencyProviders queries CoinGecko's tickers endpoint and the osmosis-api assetpairs
// endpoint to get all the exchanges that support each price feeder currency pair and store
// it in the CurrencyProviders map.
func (t *CurrencyProviderTracker) setCurrencyProviders() error {
for _, pair := range t.pairs {
// check if CoinGecko API supports pair
pairBaseID := t.coinIDSymbolMap[strings.ToLower(pair.Base)]
coinGeckoResp, err := http.Get(fmt.Sprintf("%s/%s/%s", coinGeckoRestURL, pairBaseID, coinGeckoTickersEndpoint))
if err != nil {
return err
}
defer coinGeckoResp.Body.Close()
// getOsmosisAPIPairs queries the osmosis-api assetpairs endpoint to get the asset pairs
// supported by it.
func (t *CurrencyProviderTracker) getOsmosisAPIPairs() (map[string]string, error) {
client := &http.Client{
Timeout: requestTimeout,
}
osmosisAPIPairs := make(map[string]string)

var tickerResponse coinTickerResponse
if err = json.NewDecoder(coinGeckoResp.Body).Decode(&tickerResponse); err != nil {
return err
}
osmosisResp, err := client.Get(fmt.Sprintf("%s/%s", osmosisV2RestURL, osmosisV2AssetPairsEndpoint))
if err != nil {
return nil, err
}
defer osmosisResp.Body.Close()
var assetPairsResponse []assetPair
if err = json.NewDecoder(osmosisResp.Body).Decode(&assetPairsResponse); err != nil {
return nil, err
}

for _, ticker := range tickerResponse.Tickers {
if ticker.Target == pair.Quote {
t.CurrencyProviders[pair.Base] = append(t.CurrencyProviders[pair.Base], ticker.Market.Name)
}
for _, assetPair := range assetPairsResponse {
osmosisAPIPairs[assetPair.Base] = assetPair.Quote
}

return osmosisAPIPairs, nil
}

// setCurrencyProviders queries CoinGecko's tickers endpoint to get all the exchanges
// that support each price feeder currency pair and store it in the CurrencyProviders map.
func (t *CurrencyProviderTracker) setCurrencyProviders(osmosisAPIPairs map[string]string) error {
client := &http.Client{
Timeout: requestTimeout,
}
for _, pair := range t.pairs {
// check if its a pair supported by the osmosis api
if osmosisAPIPairs[strings.ToUpper(pair.Base)] == strings.ToUpper(pair.Quote) {
t.CurrencyProviders[pair.Base] = append(t.CurrencyProviders[pair.Base], "osmosisv2")
}

// check if osmosis-api supports pair
osmosisResp, err := http.Get(fmt.Sprintf("%s/%s", osmosisV2RestURL, osmosisV2AssetPairsEndpoint))
// check if CoinGecko API supports pair
pairBaseID := t.coinIDSymbolMap[strings.ToLower(pair.Base)]
coinGeckoResp, err := client.Get(fmt.Sprintf("%s/%s/%s", coinGeckoRestURL, pairBaseID, coinGeckoTickersEndpoint))
if err != nil {
return err
}
defer osmosisResp.Body.Close()
t.logger.Error().Err(err).Msg(fmt.Sprintf("Failed to query coin gecko api tickers endpoint for %s", pair.Base))
} else {
defer coinGeckoResp.Body.Close()
var tickerResponse coinTickerResponse
if err = json.NewDecoder(coinGeckoResp.Body).Decode(&tickerResponse); err != nil {
return err
}

var assetPairsResponse []assetPair
if err = json.NewDecoder(osmosisResp.Body).Decode(&assetPairsResponse); err != nil {
return err
}
for _, ticker := range tickerResponse.Tickers {
if ticker.Target == pair.Quote {
t.CurrencyProviders[pair.Base] = append(t.CurrencyProviders[pair.Base], ticker.Market.Name)
}
}

for _, assetPair := range assetPairsResponse {
if pair.Base == assetPair.Base && pair.Quote == assetPair.Quote {
t.CurrencyProviders[pair.Base] = append(t.CurrencyProviders[pair.Base], "osmosisv2")
if len(t.CurrencyProviders[pair.Base]) == 0 {
t.logger.Warn().Msg(fmt.Sprintf("Coin gecko found 0 providers for %s", pair.Base))
}
}
}
Expand All @@ -168,7 +194,9 @@ func (t *CurrencyProviderTracker) setCurrencyProviders() error {
// set to 3 providers.
func (t *CurrencyProviderTracker) setCurrencyProviderMin() {
for base, exchanges := range t.CurrencyProviders {
if len(exchanges) < 3 {
// If CoinGecko returns 0 or 3 and above providers for a given pair, the
// minimum providers enforced will default to 3.
if len(exchanges) < 3 && len(exchanges) > 0 {
t.CurrencyProviderMin[base] = len(exchanges)
} else {
t.CurrencyProviderMin[base] = 3
Expand All @@ -186,7 +214,11 @@ func (t *CurrencyProviderTracker) trackCurrencyProviders(ctx context.Context) {
case <-ctx.Done():
return
case <-time.After(trackingPeriod):
if err := t.setCurrencyProviders(); err != nil {
osmosisAPIPairs, err := t.getOsmosisAPIPairs()
if err != nil {
t.logger.Error().Err(err).Msg("failed to query osmosis-api for available asset pairs")
}
if err := t.setCurrencyProviders(osmosisAPIPairs); err != nil {
t.logger.Error().Err(err).Msg("failed to set available providers for currencies")
}

Expand Down
19 changes: 0 additions & 19 deletions price-feeder/price-feeder.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ threshold = "2"
base = "OSMO"
threshold = "2"

[[deviation_thresholds]]
base = "BTC"
threshold = "1.5"

[[deviation_thresholds]]
base = "stATOM"
threshold = "2"
Expand Down Expand Up @@ -211,21 +207,6 @@ providers = [
]
quote = "USD"

[[currency_pairs]]
base = "BTC"
providers = [
"coinbase",
]
quote = "USD"

[[currency_pairs]]
base = "BTC"
providers = [
"huobi",
"kraken",
]
quote = "USDT"

[[currency_pairs]]
base = "stATOM"
providers = [
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/e2e_setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ func (s *IntegrationTestSuite) runPriceFeeder() {

return len(prices) > 0
},
time.Second*90, // 1:30 min
time.Minute,
time.Second,
"price-feeder not healthy",
)
Expand Down

0 comments on commit 89d2d3d

Please sign in to comment.