github.com/status-im/status-go@v1.1.0/services/wallet/thirdparty/cryptocompare/client.go (about)

     1  package cryptocompare
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/url"
     8  	"strings"
     9  
    10  	"github.com/status-im/status-go/services/wallet/thirdparty"
    11  	"github.com/status-im/status-go/services/wallet/thirdparty/utils"
    12  )
    13  
    14  const baseID = "cryptocompare"
    15  const extraParamStatus = "Status.im"
    16  const baseURL = "https://min-api.cryptocompare.com"
    17  
    18  type HistoricalPricesContainer struct {
    19  	Aggregated     bool                         `json:"Aggregated"`
    20  	TimeFrom       int64                        `json:"TimeFrom"`
    21  	TimeTo         int64                        `json:"TimeTo"`
    22  	HistoricalData []thirdparty.HistoricalPrice `json:"Data"`
    23  }
    24  
    25  type HistoricalPricesData struct {
    26  	Data HistoricalPricesContainer `json:"Data"`
    27  }
    28  
    29  type TokenDetailsContainer struct {
    30  	Data map[string]thirdparty.TokenDetails `json:"Data"`
    31  }
    32  
    33  type MarketValuesContainer struct {
    34  	Raw map[string]map[string]thirdparty.TokenMarketValues `json:"Raw"`
    35  }
    36  
    37  type Params struct {
    38  	ID       string
    39  	URL      string
    40  	User     string
    41  	Password string
    42  }
    43  
    44  type Client struct {
    45  	id         string
    46  	httpClient *thirdparty.HTTPClient
    47  	baseURL    string
    48  	creds      *thirdparty.BasicCreds
    49  }
    50  
    51  func NewClient() *Client {
    52  	return NewClientWithParams(Params{
    53  		ID:  baseID,
    54  		URL: baseURL,
    55  	})
    56  }
    57  
    58  func NewClientWithParams(params Params) *Client {
    59  	var creds *thirdparty.BasicCreds
    60  	if params.User != "" {
    61  		creds = &thirdparty.BasicCreds{
    62  			User:     params.User,
    63  			Password: params.Password,
    64  		}
    65  	}
    66  
    67  	return &Client{
    68  		id:         params.ID,
    69  		httpClient: thirdparty.NewHTTPClient(),
    70  		baseURL:    params.URL,
    71  		creds:      creds,
    72  	}
    73  }
    74  
    75  func (c *Client) FetchPrices(symbols []string, currencies []string) (map[string]map[string]float64, error) {
    76  	chunks := utils.ChunkSymbols(symbols, 60)
    77  	result := make(map[string]map[string]float64)
    78  	realCurrencies := utils.RenameSymbols(currencies)
    79  	for _, smbls := range chunks {
    80  		realSymbols := utils.RenameSymbols(smbls)
    81  
    82  		params := url.Values{}
    83  		params.Add("fsyms", strings.Join(realSymbols, ","))
    84  		params.Add("tsyms", strings.Join(realCurrencies, ","))
    85  		params.Add("extraParams", extraParamStatus)
    86  
    87  		url := fmt.Sprintf("%s/data/pricemulti", c.baseURL)
    88  		response, err := c.httpClient.DoGetRequest(context.Background(), url, params, c.creds)
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  
    93  		prices := make(map[string]map[string]float64)
    94  		err = json.Unmarshal(response, &prices)
    95  		if err != nil {
    96  			return nil, fmt.Errorf("%s - %s", err, string(response))
    97  		}
    98  
    99  		for _, symbol := range smbls {
   100  			result[symbol] = map[string]float64{}
   101  			for _, currency := range currencies {
   102  				result[symbol][currency] = prices[utils.GetRealSymbol(symbol)][utils.GetRealSymbol(currency)]
   103  			}
   104  		}
   105  	}
   106  	return result, nil
   107  }
   108  
   109  func (c *Client) FetchTokenDetails(symbols []string) (map[string]thirdparty.TokenDetails, error) {
   110  	url := fmt.Sprintf("%s/data/all/coinlist", c.baseURL)
   111  	response, err := c.httpClient.DoGetRequest(context.Background(), url, nil, c.creds)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	container := TokenDetailsContainer{}
   117  	err = json.Unmarshal(response, &container)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	tokenDetails := make(map[string]thirdparty.TokenDetails)
   123  
   124  	for _, symbol := range symbols {
   125  		tokenDetails[symbol] = container.Data[utils.GetRealSymbol(symbol)]
   126  	}
   127  
   128  	return tokenDetails, nil
   129  }
   130  
   131  func (c *Client) FetchTokenMarketValues(symbols []string, currency string) (map[string]thirdparty.TokenMarketValues, error) {
   132  	chunks := utils.ChunkSymbols(symbols)
   133  	realCurrency := utils.GetRealSymbol(currency)
   134  	item := map[string]thirdparty.TokenMarketValues{}
   135  	for _, smbls := range chunks {
   136  		realSymbols := utils.RenameSymbols(smbls)
   137  
   138  		params := url.Values{}
   139  		params.Add("fsyms", strings.Join(realSymbols, ","))
   140  		params.Add("tsyms", realCurrency)
   141  		params.Add("extraParams", extraParamStatus)
   142  
   143  		url := fmt.Sprintf("%s/data/pricemultifull", c.baseURL)
   144  		response, err := c.httpClient.DoGetRequest(context.Background(), url, params, c.creds)
   145  		if err != nil {
   146  			return nil, err
   147  		}
   148  
   149  		container := MarketValuesContainer{}
   150  		err = json.Unmarshal(response, &container)
   151  
   152  		if len(container.Raw) == 0 {
   153  			return nil, fmt.Errorf("no data found - %s", string(response))
   154  		}
   155  		if err != nil {
   156  			return nil, fmt.Errorf("%s - %s", err, string(response))
   157  		}
   158  
   159  		for _, symbol := range smbls {
   160  			item[symbol] = container.Raw[utils.GetRealSymbol(symbol)][realCurrency]
   161  		}
   162  	}
   163  	return item, nil
   164  }
   165  
   166  func (c *Client) FetchHistoricalHourlyPrices(symbol string, currency string, limit int, aggregate int) ([]thirdparty.HistoricalPrice, error) {
   167  	item := []thirdparty.HistoricalPrice{}
   168  
   169  	params := url.Values{}
   170  	params.Add("fsym", utils.GetRealSymbol(symbol))
   171  	params.Add("tsym", currency)
   172  	params.Add("aggregate", fmt.Sprintf("%d", aggregate))
   173  	params.Add("limit", fmt.Sprintf("%d", limit))
   174  	params.Add("extraParams", extraParamStatus)
   175  
   176  	url := fmt.Sprintf("%s/data/v2/histohour", c.baseURL)
   177  	response, err := c.httpClient.DoGetRequest(context.Background(), url, params, c.creds)
   178  	if err != nil {
   179  		return item, err
   180  	}
   181  
   182  	container := HistoricalPricesData{}
   183  	err = json.Unmarshal(response, &container)
   184  	if err != nil {
   185  		return item, err
   186  	}
   187  
   188  	item = container.Data.HistoricalData
   189  
   190  	return item, nil
   191  }
   192  
   193  func (c *Client) FetchHistoricalDailyPrices(symbol string, currency string, limit int, allData bool, aggregate int) ([]thirdparty.HistoricalPrice, error) {
   194  	item := []thirdparty.HistoricalPrice{}
   195  
   196  	params := url.Values{}
   197  	params.Add("fsym", utils.GetRealSymbol(symbol))
   198  	params.Add("tsym", currency)
   199  	params.Add("aggregate", fmt.Sprintf("%d", aggregate))
   200  	params.Add("limit", fmt.Sprintf("%d", limit))
   201  	params.Add("allData", fmt.Sprintf("%v", allData))
   202  	params.Add("extraParams", extraParamStatus)
   203  
   204  	url := fmt.Sprintf("%s/data/v2/histoday", c.baseURL)
   205  	response, err := c.httpClient.DoGetRequest(context.Background(), url, params, c.creds)
   206  	if err != nil {
   207  		return item, err
   208  	}
   209  
   210  	container := HistoricalPricesData{}
   211  	err = json.Unmarshal(response, &container)
   212  	if err != nil {
   213  		return item, err
   214  	}
   215  
   216  	item = container.Data.HistoricalData
   217  
   218  	return item, nil
   219  }
   220  
   221  func (c *Client) ID() string {
   222  	return c.id
   223  }