fix_: Prioritize tokens on eth platform (#5151)
This commit is contained in:
parent
3b5eab3bf1
commit
838311e902
|
@ -18,7 +18,6 @@ var coinGeckoMapping = map[string]string{
|
|||
"SNT": "status",
|
||||
"ETH": "ethereum",
|
||||
"AST": "airswap",
|
||||
"AMB": "",
|
||||
"ABT": "arcblock",
|
||||
"ATM": "",
|
||||
"BNB": "binancecoin",
|
||||
|
@ -26,7 +25,6 @@ var coinGeckoMapping = map[string]string{
|
|||
"CDT": "",
|
||||
"COMP": "compound-coin",
|
||||
"EDG": "edgeless",
|
||||
"ELF": "",
|
||||
"ENG": "enigma",
|
||||
"EOS": "eos",
|
||||
"GEN": "daostack",
|
||||
|
@ -46,13 +44,11 @@ var coinGeckoMapping = map[string]string{
|
|||
"GRT": "the-graph",
|
||||
"TNT": "tierion",
|
||||
"TRX": "tron",
|
||||
"TGT": "",
|
||||
"RARE": "superrare",
|
||||
"UNI": "uniswap",
|
||||
"USDC": "usd-coin",
|
||||
"USDP": "paxos-standard",
|
||||
"VRS": "",
|
||||
"TIME": "",
|
||||
"USDT": "tether",
|
||||
"SHIB": "shiba-inu",
|
||||
"LINK": "chainlink",
|
||||
|
@ -83,17 +79,49 @@ type GeckoToken struct {
|
|||
ID string `json:"id"`
|
||||
Symbol string `json:"symbol"`
|
||||
Name string `json:"name"`
|
||||
EthPlatform bool
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
client *http.Client
|
||||
tokens map[string]GeckoToken
|
||||
tokens map[string][]GeckoToken
|
||||
tokensURL string
|
||||
fetchTokensMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewClient() *Client {
|
||||
return &Client{client: &http.Client{Timeout: time.Minute}, tokens: make(map[string]GeckoToken), tokensURL: fmt.Sprintf("%scoins/list", baseURL)}
|
||||
return &Client{client: &http.Client{Timeout: time.Minute}, tokens: make(map[string][]GeckoToken), tokensURL: fmt.Sprintf("%scoins/list?include_platform=true", baseURL)}
|
||||
}
|
||||
|
||||
func (gt *GeckoToken) UnmarshalJSON(data []byte) error {
|
||||
// Define an auxiliary struct to hold the JSON data
|
||||
var aux struct {
|
||||
ID string `json:"id"`
|
||||
Symbol string `json:"symbol"`
|
||||
Name string `json:"name"`
|
||||
Platforms struct {
|
||||
Ethereum string `json:"ethereum"`
|
||||
// Other platforms can be added here if needed
|
||||
} `json:"platforms"`
|
||||
}
|
||||
|
||||
// Unmarshal the JSON data into the auxiliary struct
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the fields of GeckoToken from the auxiliary struct
|
||||
gt.ID = aux.ID
|
||||
gt.Symbol = aux.Symbol
|
||||
gt.Name = aux.Name
|
||||
|
||||
// Check if "ethereum" key exists in the platforms map
|
||||
if aux.Platforms.Ethereum != "" {
|
||||
gt.EthPlatform = true
|
||||
} else {
|
||||
gt.EthPlatform = false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DoQuery(url string) (*http.Response, error) {
|
||||
|
@ -105,18 +133,40 @@ func (c *Client) DoQuery(url string) (*http.Response, error) {
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
func mapTokensToSymbols(tokens []GeckoToken, tokenMap map[string]GeckoToken) {
|
||||
func mapTokensToSymbols(tokens []GeckoToken, tokenMap map[string][]GeckoToken) {
|
||||
for _, token := range tokens {
|
||||
if id, ok := coinGeckoMapping[strings.ToUpper(token.Symbol)]; ok {
|
||||
symbol := strings.ToUpper(token.Symbol)
|
||||
if id, ok := coinGeckoMapping[symbol]; ok {
|
||||
if id != token.ID {
|
||||
continue
|
||||
}
|
||||
}
|
||||
tokenMap[strings.ToUpper(token.Symbol)] = token
|
||||
tokenMap[symbol] = append(tokenMap[symbol], token)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) getTokens() (map[string]GeckoToken, error) {
|
||||
func getGeckoTokenFromSymbol(tokens map[string][]GeckoToken, symbol string) (GeckoToken, error) {
|
||||
tokenList, ok := tokens[strings.ToUpper(symbol)]
|
||||
if !ok {
|
||||
return GeckoToken{}, fmt.Errorf("token not found for symbol %s", symbol)
|
||||
}
|
||||
for _, t := range tokenList {
|
||||
if t.EthPlatform {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return tokenList[0], nil
|
||||
}
|
||||
|
||||
func getIDFromSymbol(tokens map[string][]GeckoToken, symbol string) (string, error) {
|
||||
token, err := getGeckoTokenFromSymbol(tokens, symbol)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token.ID, nil
|
||||
}
|
||||
|
||||
func (c *Client) getTokens() (map[string][]GeckoToken, error) {
|
||||
c.fetchTokensMutex.Lock()
|
||||
defer c.fetchTokensMutex.Unlock()
|
||||
|
||||
|
@ -153,23 +203,16 @@ func (c *Client) mapSymbolsToIds(symbols []string) ([]string, error) {
|
|||
}
|
||||
ids := make([]string, 0)
|
||||
for _, symbol := range utils.RenameSymbols(symbols) {
|
||||
if token, ok := tokens[symbol]; ok {
|
||||
ids = append(ids, token.ID)
|
||||
id, err := getIDFromSymbol(tokens, symbol)
|
||||
if err == nil {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
ids = utils.RemoveDuplicates(ids)
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (c *Client) getIDFromSymbol(symbol string) (string, error) {
|
||||
tokens, err := c.getTokens()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tokens[strings.ToUpper(symbol)].ID, nil
|
||||
}
|
||||
|
||||
func (c *Client) FetchPrices(symbols []string, currencies []string) (map[string]map[string]float64, error) {
|
||||
ids, err := c.mapSymbolsToIds(symbols)
|
||||
if err != nil {
|
||||
|
@ -193,10 +236,14 @@ func (c *Client) FetchPrices(symbols []string, currencies []string) (map[string]
|
|||
return nil, fmt.Errorf("%s - %s", err, string(body))
|
||||
}
|
||||
|
||||
tokens, err := c.getTokens()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make(map[string]map[string]float64)
|
||||
for _, symbol := range symbols {
|
||||
result[symbol] = map[string]float64{}
|
||||
id, err := c.getIDFromSymbol(utils.GetRealSymbol(symbol))
|
||||
id, err := getIDFromSymbol(tokens, utils.GetRealSymbol(symbol))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -215,14 +262,14 @@ func (c *Client) FetchTokenDetails(symbols []string) (map[string]thirdparty.Toke
|
|||
}
|
||||
result := make(map[string]thirdparty.TokenDetails)
|
||||
for _, symbol := range symbols {
|
||||
if value, ok := tokens[utils.GetRealSymbol(symbol)]; ok {
|
||||
token, err := getGeckoTokenFromSymbol(tokens, utils.GetRealSymbol(symbol))
|
||||
if err == nil {
|
||||
result[symbol] = thirdparty.TokenDetails{
|
||||
ID: value.ID,
|
||||
Name: value.Name,
|
||||
ID: token.ID,
|
||||
Name: token.Name,
|
||||
Symbol: symbol,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
@ -251,9 +298,14 @@ func (c *Client) FetchTokenMarketValues(symbols []string, currency string) (map[
|
|||
return nil, fmt.Errorf("%s - %s", err, string(body))
|
||||
}
|
||||
|
||||
tokens, err := c.getTokens()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]thirdparty.TokenMarketValues)
|
||||
for _, symbol := range symbols {
|
||||
id, err := c.getIDFromSymbol(utils.GetRealSymbol(symbol))
|
||||
id, err := getIDFromSymbol(tokens, utils.GetRealSymbol(symbol))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -282,7 +334,12 @@ func (c *Client) FetchHistoricalHourlyPrices(symbol string, currency string, lim
|
|||
}
|
||||
|
||||
func (c *Client) FetchHistoricalDailyPrices(symbol string, currency string, limit int, allData bool, aggregate int) ([]thirdparty.HistoricalPrice, error) {
|
||||
id, err := c.getIDFromSymbol(utils.GetRealSymbol(symbol))
|
||||
tokens, err := c.getTokens()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, err := getIDFromSymbol(tokens, utils.GetRealSymbol(symbol))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -10,6 +10,18 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type TestTokenPlatform struct {
|
||||
Ethereum string `json:"ethereum"`
|
||||
Arb string `json:"arb"`
|
||||
}
|
||||
|
||||
type TestGeckoToken struct {
|
||||
ID string `json:"id"`
|
||||
Symbol string `json:"symbol"`
|
||||
Name string `json:"name"`
|
||||
Platforms TestTokenPlatform `json:"platforms"`
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T, response []byte) (*httptest.Server, func()) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
|
@ -38,17 +50,17 @@ func TestGetTokensSuccess(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
expectedMap := map[string]GeckoToken{
|
||||
"ETH": {
|
||||
expectedMap := map[string][]GeckoToken{
|
||||
"ETH": []GeckoToken{{
|
||||
ID: "ethereum",
|
||||
Symbol: "eth",
|
||||
Name: "Ethereum",
|
||||
},
|
||||
"SNT": {
|
||||
}},
|
||||
"SNT": []GeckoToken{{
|
||||
ID: "status",
|
||||
Symbol: "snt",
|
||||
Name: "Status",
|
||||
},
|
||||
}},
|
||||
}
|
||||
response, _ := json.Marshal(expected)
|
||||
|
||||
|
@ -57,7 +69,89 @@ func TestGetTokensSuccess(t *testing.T) {
|
|||
|
||||
geckoClient := &Client{
|
||||
client: srv.Client(),
|
||||
tokens: make(map[string]GeckoToken),
|
||||
tokens: make(map[string][]GeckoToken),
|
||||
tokensURL: srv.URL,
|
||||
}
|
||||
|
||||
tokenMap, err := geckoClient.getTokens()
|
||||
require.NoError(t, err)
|
||||
require.True(t, reflect.DeepEqual(expectedMap, tokenMap))
|
||||
}
|
||||
|
||||
func TestGetTokensEthPlatform(t *testing.T) {
|
||||
tokenList := []TestGeckoToken{
|
||||
{
|
||||
ID: "ethereum",
|
||||
Symbol: "eth-test",
|
||||
Name: "Ethereum",
|
||||
Platforms: TestTokenPlatform{
|
||||
Ethereum: "0x123",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "usdt-bridge-test",
|
||||
Symbol: "usdt-test",
|
||||
Name: "USDT Bridge Test",
|
||||
Platforms: TestTokenPlatform{
|
||||
Arb: "0x123",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tether",
|
||||
Symbol: "usdt-test",
|
||||
Name: "Tether",
|
||||
Platforms: TestTokenPlatform{
|
||||
Arb: "0x1234",
|
||||
Ethereum: "0x12345",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "AirDao",
|
||||
Symbol: "amb-test",
|
||||
Name: "Amber",
|
||||
Platforms: TestTokenPlatform{
|
||||
Arb: "0x123455",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedMap := map[string][]GeckoToken{
|
||||
"ETH-TEST": {{
|
||||
ID: "ethereum",
|
||||
Symbol: "eth-test",
|
||||
Name: "Ethereum",
|
||||
EthPlatform: true,
|
||||
}},
|
||||
"USDT-TEST": {
|
||||
{
|
||||
ID: "usdt-bridge-test",
|
||||
Symbol: "usdt-test",
|
||||
Name: "USDT Bridge Test",
|
||||
EthPlatform: false,
|
||||
},
|
||||
{
|
||||
ID: "tether",
|
||||
Symbol: "usdt-test",
|
||||
Name: "Tether",
|
||||
EthPlatform: true,
|
||||
},
|
||||
},
|
||||
"AMB-TEST": {{
|
||||
ID: "AirDao",
|
||||
Symbol: "amb-test",
|
||||
Name: "Amber",
|
||||
EthPlatform: false,
|
||||
}},
|
||||
}
|
||||
|
||||
response, _ := json.Marshal(tokenList)
|
||||
|
||||
srv, stop := setupTest(t, response)
|
||||
defer stop()
|
||||
|
||||
geckoClient := &Client{
|
||||
client: srv.Client(),
|
||||
tokens: make(map[string][]GeckoToken),
|
||||
tokensURL: srv.URL,
|
||||
}
|
||||
|
||||
|
@ -73,7 +167,7 @@ func TestGetTokensFailure(t *testing.T) {
|
|||
|
||||
geckoClient := &Client{
|
||||
client: srv.Client(),
|
||||
tokens: make(map[string]GeckoToken),
|
||||
tokens: make(map[string][]GeckoToken),
|
||||
tokensURL: srv.URL,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue