169 lines
3.6 KiB
Go
Executable File
169 lines
3.6 KiB
Go
Executable File
package coingecko
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
)
|
|
|
|
var ErrCoinNotFound = fmt.Errorf("coin not found")
|
|
var ErrTooManyRequests = fmt.Errorf("too many requests")
|
|
|
|
type CoinGeckoAPI struct {
|
|
ApiURL string
|
|
HeaderKey string
|
|
ApiKey string
|
|
tokenCache map[string]TokenItem
|
|
}
|
|
|
|
type TokenItem struct {
|
|
Id string
|
|
Chain string
|
|
Symbol string
|
|
Decimals int
|
|
}
|
|
|
|
func NewCoinGeckoAPI(url, headerKey string, apiKey string) *CoinGeckoAPI {
|
|
return &CoinGeckoAPI{
|
|
ApiURL: url,
|
|
HeaderKey: headerKey,
|
|
ApiKey: apiKey,
|
|
tokenCache: make(map[string]TokenItem),
|
|
}
|
|
}
|
|
|
|
func (cg *CoinGeckoAPI) GetSymbolDailyPrice(coinID, days string) (*CoinHistoryResponse, error) {
|
|
|
|
url := fmt.Sprintf("%s/api/v3/coins/%s/market_chart?vs_currency=usd&days=%s&interval=daily", cg.ApiURL, coinID, days)
|
|
method := "GET"
|
|
|
|
client := &http.Client{}
|
|
req, err := http.NewRequest(method, url, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if cg.HeaderKey != "" && cg.ApiKey != "" {
|
|
req.Header.Add(cg.HeaderKey, cg.ApiKey)
|
|
}
|
|
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode != 200 {
|
|
switch res.StatusCode {
|
|
case 404:
|
|
return nil, ErrCoinNotFound
|
|
case 429:
|
|
return nil, ErrTooManyRequests
|
|
default:
|
|
return nil, fmt.Errorf("failed request with status code; %d", res.StatusCode)
|
|
}
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var td CoinHistoryResponse
|
|
err = json.Unmarshal(body, &td)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &td, nil
|
|
|
|
}
|
|
|
|
func (cg *CoinGeckoAPI) GetSymbol(ChainId string, ContractId string) (string, error) {
|
|
|
|
// lookup on cache first
|
|
if val, ok := cg.tokenCache[ContractId]; ok {
|
|
return val.Symbol, nil
|
|
}
|
|
|
|
// lookup on coingecko
|
|
ti, err := cg.GetSymbolByContract(ChainId, ContractId)
|
|
if err != nil {
|
|
|
|
// if not found, return none
|
|
if err.Error() == "token not found" {
|
|
return "none", nil
|
|
}
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
// add to cache
|
|
fmt.Printf("adding to cache: %s\n", ti.Symbol)
|
|
cg.tokenCache[ContractId] = *ti
|
|
return ti.Symbol, nil
|
|
|
|
}
|
|
|
|
func (cg *CoinGeckoAPI) convertChain(chain string) string {
|
|
|
|
// check if chain exsist on map
|
|
if val, ok := convertionMap[chain]; ok {
|
|
return val
|
|
}
|
|
return chain
|
|
|
|
}
|
|
|
|
// GetSymbolByContract returns the symbol of the token
|
|
// Input: ChaindId is the name of the chain: ie: ethereum, solana, etc
|
|
// Input: ContractId is the contract address of the token (ECR-20 or other)
|
|
func (cg *CoinGeckoAPI) GetSymbolByContract(ChainId string, ContractId string) (*TokenItem, error) {
|
|
|
|
chain := cg.convertChain(ChainId)
|
|
//url := "https://api.coingecko.com/api/v3/coins/avalanche/contract/0x2b2c81e08f1af8835a78bb2a90ae924ace0ea4be"
|
|
url := fmt.Sprintf("https://%s/api/v3/coins/%s/contract/%s", cg.ApiURL, chain, ContractId)
|
|
method := "GET"
|
|
|
|
client := &http.Client{}
|
|
req, err := http.NewRequest(method, url, nil)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
//req.Header.Add("Cookie", "__cf_bm=jUWxA1U8U3SdvDF2EXgCZUmnDopOozWnB5VpXIjWH.c-1682970763-0-AaLD4yVrSy53aAJQwVNe61P5IcXSnW4vIMeRrsRDIMGJ/+PbEcOv/lene34+FB4Q4kapT//4660lx/Rw507zw7Q=")
|
|
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
if res.StatusCode == 404 {
|
|
return nil, fmt.Errorf("token not found")
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var td TokenData
|
|
err = json.Unmarshal(body, &td)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ti := TokenItem{
|
|
Id: td.ID,
|
|
Chain: ChainId,
|
|
Symbol: td.Symbol,
|
|
}
|
|
|
|
fmt.Printf("\"%s\": \"%s\",\n", ContractId, ti.Symbol)
|
|
|
|
return &ti, nil
|
|
}
|