-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Update mexc provider to use v3 api (#367)
* fix: Update mexc provider to use v3 api * lint * pr comments * args * err lint * comment out astroport test
- Loading branch information
1 parent
48cb7fb
commit f10accf
Showing
7 changed files
with
107 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,41 @@ | ||
package provider | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"testing" | ||
"time" | ||
// import ( | ||
// "context" | ||
// "os" | ||
// "testing" | ||
// "time" | ||
|
||
"github.com/ojo-network/price-feeder/oracle/types" | ||
"github.com/rs/zerolog" | ||
"github.com/stretchr/testify/require" | ||
) | ||
// "github.com/ojo-network/price-feeder/oracle/types" | ||
// "github.com/rs/zerolog" | ||
// "github.com/stretchr/testify/require" | ||
// ) | ||
|
||
// TestAstroportProvider_GetTickers tests the polling process. | ||
// TODO: Make this more comprehensive. | ||
// | ||
// Ref: https://github.com/ojo-network/price-feeder/issues/317 | ||
func TestAstroportProvider_GetTickers(t *testing.T) { | ||
ctx := context.Background() | ||
pairs := []types.CurrencyPair{{ | ||
Base: "STINJ", | ||
Quote: "INJ", | ||
}} | ||
p, err := NewAstroportProvider( | ||
ctx, | ||
zerolog.New(os.Stdout).With().Timestamp().Logger(), | ||
Endpoint{}, | ||
pairs..., | ||
) | ||
require.NoError(t, err) | ||
availPairs, err := p.GetAvailablePairs() | ||
require.NoError(t, err) | ||
require.NotEmpty(t, availPairs) | ||
// // TestAstroportProvider_GetTickers tests the polling process. | ||
// // TODO: Make this more comprehensive. | ||
// // | ||
// // Ref: https://github.com/ojo-network/price-feeder/issues/317 | ||
// func TestAstroportProvider_GetTickers(t *testing.T) { | ||
// ctx := context.Background() | ||
// pairs := []types.CurrencyPair{{ | ||
// Base: "STINJ", | ||
// Quote: "INJ", | ||
// }} | ||
// p, err := NewAstroportProvider( | ||
// ctx, | ||
// zerolog.New(os.Stdout).With().Timestamp().Logger(), | ||
// Endpoint{}, | ||
// pairs..., | ||
// ) | ||
// require.NoError(t, err) | ||
// availPairs, err := p.GetAvailablePairs() | ||
// require.NoError(t, err) | ||
// require.NotEmpty(t, availPairs) | ||
|
||
p.StartConnections() | ||
time.Sleep(10 * time.Second) | ||
// p.StartConnections() | ||
// time.Sleep(10 * time.Second) | ||
|
||
res, err := p.GetTickerPrices(pairs...) | ||
require.NoError(t, err) | ||
require.NotEmpty(t, res) | ||
} | ||
// res, err := p.GetTickerPrices(pairs...) | ||
// require.NoError(t, err) | ||
// require.NotEmpty(t, res) | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,23 +3,25 @@ package provider | |
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"math/big" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
"sync" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
"github.com/gorilla/websocket" | ||
"github.com/ojo-network/price-feeder/oracle/types" | ||
"github.com/rs/zerolog" | ||
|
||
"github.com/ojo-network/ojo/util/decmath" | ||
) | ||
|
||
const ( | ||
mexcWSHost = "wbs.mexc.com" | ||
mexcWSPath = "/raw/ws" | ||
mexcRestHost = "https://www.mexc.com" | ||
mexcRestPath = "/open/api/v2/market/ticker" | ||
mexcWSPath = "/ws" | ||
mexcRestHost = "https://api.mexc.com/" | ||
mexcRestPath = "/api/v3/ticker/price" | ||
) | ||
|
||
var _ Provider = (*MexcProvider)(nil) | ||
|
@@ -28,9 +30,7 @@ type ( | |
// MexcProvider defines an Oracle provider implemented by the Mexc public | ||
// API. | ||
// | ||
// REF: https://mxcdevelop.github.io/apidocs/spot_v2_en/#ticker-information | ||
// REF: https://mxcdevelop.github.io/apidocs/spot_v2_en/#k-line | ||
// REF: https://mxcdevelop.github.io/apidocs/spot_v2_en/#overview | ||
// REF: https://mexcdevelop.github.io/apidocs/spot_v3_en/ | ||
MexcProvider struct { | ||
wsc *WebsocketController | ||
logger zerolog.Logger | ||
|
@@ -42,41 +42,43 @@ type ( | |
|
||
// MexcTickerResponse is the ticker price response object. | ||
MexcTickerResponse struct { | ||
Symbol map[string]MexcTicker `json:"data"` // e.x. ATOM_USDT | ||
Symbol string `json:"s"` // e.x. ATOMUSDT | ||
Metadata MexcTicker `json:"d"` // Metadata for ticker | ||
} | ||
MexcTicker struct { | ||
LastPrice float64 `json:"p"` // Last price ex.: 0.0025 | ||
Volume float64 `json:"v"` // Total traded base asset volume ex.: 1000 | ||
LastPrice string `json:"b"` // Best bid price ex.: 0.0025 | ||
Volume string `json:"B"` // Best bid qty ex.: 1000 | ||
} | ||
|
||
// MexcCandle is the candle websocket response object. | ||
MexcCandleResponse struct { | ||
Symbol string `json:"symbol"` // Symbol ex.: ATOM_USDT | ||
Metadata MexcCandle `json:"data"` // Metadata for candle | ||
Symbol string `json:"s"` // Symbol ex.: ATOMUSDT | ||
Metadata MexcCandle `json:"d"` // Metadata for candle | ||
} | ||
MexcCandle struct { | ||
Close float64 `json:"c"` // Price at close | ||
TimeStamp int64 `json:"t"` // Close time in unix epoch ex.: 1645756200000 | ||
Volume float64 `json:"v"` // Volume during period | ||
Data MexcCandleData `json:"k"` | ||
} | ||
MexcCandleData struct { | ||
Close *big.Float `json:"c"` // Price at close | ||
TimeStamp int64 `json:"T"` // Close time in unix epoch ex.: 1645756200 | ||
Volume *big.Float `json:"v"` // Volume during period | ||
} | ||
|
||
// MexcCandleSubscription Msg to subscribe all the candle channels. | ||
MexcCandleSubscription struct { | ||
OP string `json:"op"` // kline | ||
Symbol string `json:"symbol"` // streams to subscribe ex.: atom_usdt | ||
Interval string `json:"interval"` // Min1、Min5、Min15、Min30 | ||
Method string `json:"method"` // ex.: SUBSCRIPTION | ||
Params []string `json:"params"` // ex.: [[email protected]@<symbol>@<interval>] | ||
} | ||
|
||
// MexcTickerSubscription Msg to subscribe all the ticker channels. | ||
MexcTickerSubscription struct { | ||
OP string `json:"op"` // kline | ||
Method string `json:"method"` // ex.: SUBSCRIPTION | ||
Params []string `json:"params"` // ex.: [[email protected]@<symbol>] | ||
} | ||
|
||
// MexcPairSummary defines the response structure for a Mexc pair | ||
// summary. | ||
MexcPairSummary struct { | ||
Data []MexcPairData `json:"data"` | ||
} | ||
MexcPairSummary []MexcPairData | ||
|
||
// MexcPairData defines the data response structure for an Mexc pair. | ||
MexcPairData struct { | ||
|
@@ -144,12 +146,13 @@ func (p *MexcProvider) StartConnections() { | |
} | ||
|
||
func (p *MexcProvider) getSubscriptionMsgs(cps ...types.CurrencyPair) []interface{} { | ||
subscriptionMsgs := make([]interface{}, 0, len(cps)+1) | ||
subscriptionMsgs := make([]interface{}, 0, len(cps)*2) | ||
mexcPairs := make([]string, 0, len(cps)) | ||
for _, cp := range cps { | ||
mexcPair := currencyPairToMexcPair(cp) | ||
subscriptionMsgs = append(subscriptionMsgs, newMexcCandleSubscriptionMsg(mexcPair)) | ||
mexcPairs = append(mexcPairs, currencyPairToMexcPair(cp)) | ||
} | ||
subscriptionMsgs = append(subscriptionMsgs, newMexcTickerSubscriptionMsg()) | ||
subscriptionMsgs = append(subscriptionMsgs, newMexcCandleSubscriptionMsg(mexcPairs)) | ||
subscriptionMsgs = append(subscriptionMsgs, newMexcTickerSubscriptionMsg(mexcPairs)) | ||
return subscriptionMsgs | ||
} | ||
|
||
|
@@ -195,20 +198,14 @@ func (p *MexcProvider) messageReceived(_ int, _ *WebsocketConnection, bz []byte) | |
) | ||
|
||
tickerErr = json.Unmarshal(bz, &tickerResp) | ||
for _, cp := range p.subscribedPairs { | ||
mexcPair := currencyPairToMexcPair(cp) | ||
if tickerResp.Symbol[mexcPair].LastPrice != 0 { | ||
p.setTickerPair( | ||
tickerResp.Symbol[mexcPair], | ||
mexcPair, | ||
) | ||
telemetryWebsocketMessage(ProviderMexc, MessageTypeTicker) | ||
return | ||
} | ||
if tickerResp.Metadata.LastPrice != "" { | ||
p.setTickerPair(tickerResp.Metadata, tickerResp.Symbol) | ||
telemetryWebsocketMessage(ProviderMexc, MessageTypeTicker) | ||
return | ||
} | ||
|
||
candleErr = json.Unmarshal(bz, &candleResp) | ||
if candleResp.Metadata.Close != 0 { | ||
if candleResp.Metadata.Data.Close != nil { | ||
p.setCandlePair(candleResp.Metadata, candleResp.Symbol) | ||
telemetryWebsocketMessage(ProviderMexc, MessageTypeCandle) | ||
return | ||
|
@@ -224,11 +221,11 @@ func (p *MexcProvider) messageReceived(_ int, _ *WebsocketConnection, bz []byte) | |
} | ||
|
||
func (mt MexcTicker) toTickerPrice() (types.TickerPrice, error) { | ||
price, err := decmath.NewDecFromFloat(mt.LastPrice) | ||
price, err := sdk.NewDecFromStr(mt.LastPrice) | ||
if err != nil { | ||
return types.TickerPrice{}, err | ||
} | ||
volume, err := decmath.NewDecFromFloat(mt.Volume) | ||
volume, err := sdk.NewDecFromStr(mt.Volume) | ||
if err != nil { | ||
return types.TickerPrice{}, err | ||
} | ||
|
@@ -241,19 +238,20 @@ func (mt MexcTicker) toTickerPrice() (types.TickerPrice, error) { | |
} | ||
|
||
func (mc MexcCandle) toCandlePrice() (types.CandlePrice, error) { | ||
close, err := decmath.NewDecFromFloat(mc.Close) | ||
close, err := sdk.NewDecFromStr(mc.Data.Close.String()) | ||
if err != nil { | ||
return types.CandlePrice{}, err | ||
} | ||
volume, err := decmath.NewDecFromFloat(mc.Volume) | ||
volume, err := sdk.NewDecFromStr(mc.Data.Volume.String()) | ||
if err != nil { | ||
return types.CandlePrice{}, err | ||
} | ||
|
||
candle := types.CandlePrice{ | ||
Price: close, | ||
Volume: volume, | ||
// convert seconds -> milli | ||
TimeStamp: SecondsToMilli(mc.TimeStamp), | ||
TimeStamp: SecondsToMilli(mc.Data.TimeStamp), | ||
} | ||
return candle, nil | ||
} | ||
|
@@ -279,9 +277,9 @@ func (p *MexcProvider) GetAvailablePairs() (map[string]struct{}, error) { | |
return nil, err | ||
} | ||
|
||
availablePairs := make(map[string]struct{}, len(pairsSummary.Data)) | ||
for _, pairName := range pairsSummary.Data { | ||
availablePairs[strings.ToUpper(strings.ReplaceAll(pairName.Symbol, "_", ""))] = struct{}{} | ||
availablePairs := make(map[string]struct{}, len(pairsSummary)) | ||
for _, pairName := range pairsSummary { | ||
availablePairs[strings.ToUpper(pairName.Symbol)] = struct{}{} | ||
} | ||
|
||
return availablePairs, nil | ||
|
@@ -290,21 +288,29 @@ func (p *MexcProvider) GetAvailablePairs() (map[string]struct{}, error) { | |
// currencyPairToMexcPair receives a currency pair and return mexc | ||
// ticker symbol atomusdt@ticker. | ||
func currencyPairToMexcPair(cp types.CurrencyPair) string { | ||
return strings.ToUpper(cp.Base + "_" + cp.Quote) | ||
return strings.ToUpper(cp.Base + cp.Quote) | ||
} | ||
|
||
// newMexcCandleSubscriptionMsg returns a new candle subscription Msg. | ||
func newMexcCandleSubscriptionMsg(param string) MexcCandleSubscription { | ||
func newMexcCandleSubscriptionMsg(symbols []string) MexcCandleSubscription { | ||
params := make([]string, len(symbols)) | ||
for i, symbol := range symbols { | ||
params[i] = fmt.Sprintf("[email protected]@%s@Min1", symbol) | ||
} | ||
return MexcCandleSubscription{ | ||
OP: "sub.kline", | ||
Symbol: param, | ||
Interval: "Min1", | ||
Method: "SUBSCRIPTION", | ||
Params: params, | ||
} | ||
} | ||
|
||
// newMexcTickerSubscriptionMsg returns a new ticker subscription Msg. | ||
func newMexcTickerSubscriptionMsg() MexcTickerSubscription { | ||
func newMexcTickerSubscriptionMsg(symbols []string) MexcTickerSubscription { | ||
params := make([]string, len(symbols)) | ||
for i, symbol := range symbols { | ||
params[i] = fmt.Sprintf("[email protected]@%s", symbol) | ||
} | ||
return MexcTickerSubscription{ | ||
OP: "sub.overview", | ||
Method: "SUBSCRIPTION", | ||
Params: params, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ func TestMexcProvider_GetTickerPrices(t *testing.T) { | |
volume := sdk.MustNewDecFromStr("2396974.02000000") | ||
|
||
tickerMap := map[string]types.TickerPrice{} | ||
tickerMap["ATOM_USDT"] = types.TickerPrice{ | ||
tickerMap["ATOMUSDT"] = types.TickerPrice{ | ||
Price: lastPrice, | ||
Volume: volume, | ||
} | ||
|
@@ -45,12 +45,12 @@ func TestMexcProvider_GetTickerPrices(t *testing.T) { | |
volume := sdk.MustNewDecFromStr("2396974.02000000") | ||
|
||
tickerMap := map[string]types.TickerPrice{} | ||
tickerMap["ATOM_USDT"] = types.TickerPrice{ | ||
tickerMap["ATOMUSDT"] = types.TickerPrice{ | ||
Price: lastPriceAtom, | ||
Volume: volume, | ||
} | ||
|
||
tickerMap["LUNA_USDT"] = types.TickerPrice{ | ||
tickerMap["LUNAUSDT"] = types.TickerPrice{ | ||
Price: lastPriceLuna, | ||
Volume: volume, | ||
} | ||
|
@@ -77,7 +77,7 @@ func TestMexcProvider_GetTickerPrices(t *testing.T) { | |
func TestMexcCurrencyPairToMexcPair(t *testing.T) { | ||
cp := types.CurrencyPair{Base: "ATOM", Quote: "USDT"} | ||
MexcSymbol := currencyPairToMexcPair(cp) | ||
require.Equal(t, MexcSymbol, "ATOM_USDT") | ||
require.Equal(t, MexcSymbol, "ATOMUSDT") | ||
} | ||
|
||
func TestMexcProvider_getSubscriptionMsgs(t *testing.T) { | ||
|
@@ -88,8 +88,8 @@ func TestMexcProvider_getSubscriptionMsgs(t *testing.T) { | |
subMsgs := provider.getSubscriptionMsgs(cps...) | ||
|
||
msg, _ := json.Marshal(subMsgs[0]) | ||
require.Equal(t, "{\"op\":\"sub.kline\",\"symbol\":\"ATOM_USDT\",\"interval\":\"Min1\"}", string(msg)) | ||
require.Equal(t, "{\"method\":\"SUBSCRIPTION\",\"params\":[\"[email protected]@ATOMUSDT@Min1\"]}", string(msg)) | ||
|
||
msg, _ = json.Marshal(subMsgs[1]) | ||
require.Equal(t, "{\"op\":\"sub.overview\"}", string(msg)) | ||
require.Equal(t, "{\"method\":\"SUBSCRIPTION\",\"params\":[\"[email protected]@ATOMUSDT\"]}", string(msg)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.