Skip to content

Commit

Permalink
fix: Update mexc provider to use v3 api (#367)
Browse files Browse the repository at this point in the history
* fix: Update mexc provider to use v3 api

* lint

* pr comments

* args

* err lint

* comment out astroport test
  • Loading branch information
rbajollari authored Mar 28, 2024
1 parent 48cb7fb commit f10accf
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 101 deletions.
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func getVersionCmd() *cobra.Command {
versionCmd := &cobra.Command{
Use: "version",
Short: "Print binary version information",
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
verInfo := versionInfo{
Version: Version,
Commit: Commit,
Expand Down
2 changes: 1 addition & 1 deletion config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func LoadConfigFromFlags(nodeConfigPath, dirPrefix string) (Config, error) {
// filesInFolder returns a slice of all file paths in a given folder.
func filesInFolder(folder string) ([]string, error) {
var files []string
err := filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
err := filepath.Walk(folder, func(path string, info os.FileInfo, _ error) error {
if info != nil && !info.IsDir() {
files = append(files, path)
}
Expand Down
70 changes: 35 additions & 35 deletions oracle/provider/astroport_test.go
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)
// }
112 changes: 59 additions & 53 deletions oracle/provider/mexc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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,
}
}
12 changes: 6 additions & 6 deletions oracle/provider/mexc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -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,
}
Expand All @@ -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) {
Expand All @@ -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))
}
2 changes: 1 addition & 1 deletion oracle/types/currency.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func MapPairsToSlice(mapPairs map[string]CurrencyPair) []CurrencyPair {
return currencyPairs
}

func (cp CurrencyPair) MarshalText() (text []byte, err error) {
func (cp CurrencyPair) MarshalText() ([]byte, error) {
type noMethod CurrencyPair
return json.Marshal(noMethod(cp))
}
Expand Down
Loading

0 comments on commit f10accf

Please sign in to comment.