Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: currency provider tracker causing price feeder to error #1781

Merged
merged 13 commits into from
Feb 7, 2023
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")
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
}

// 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
rbajollari marked this conversation as resolved.
Show resolved Hide resolved
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"
rbajollari marked this conversation as resolved.
Show resolved Hide resolved

[[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