// Package coingecko implements a Service which returns price info on cryptocurrencies from coingecko package coingecko import ( "encoding/json" "fmt" "net/http" "strings" "github.com/matrix-org/go-neb/types" mevt "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) // ServiceType of the coingecko service const ServiceType = "coingecko" // Service represents the coingecko service. It has no Config fields. type Service struct { types.DefaultService } type CoinList struct { Id string `json:"id"` Symbol string `json:"symbol"` Name string `json:"name"` } type Market struct { Id string `json:"id"` Symbol string `json:"symbol"` Name string `json:"name"` Image string `json:"image"` CurrentPrice float64 `json:"current_price"` MarketCap float64 `json:"market_cap"` MarketCapRank int16 `json:"market_cap_rank"` FullyDilutedValuation string `json:"fully_diluted_valuation"` TotalVolume float64 `json:"total_volume"` High24 float64 `json:"high_24h"` Low24 float64 `json:"low_24h"` PriceChange24h float64 `json:"price_change_24h"` PriceChangePercentage24h float64 `json:"price_change_percentage_24h"` MarketCapChange24h float64 `json:"market_cap_change_24h"` MarketCapChangePercentage24h float64 `json:"market_cap_change_percentage_24h"` CirculatingSupply float64 `json:"circulating_supply"` TotalSupply float64 `json:"total_supply"` MaxSupply float64 `json:"max_supply"` ATH float64 `json:"ath"` ATHChangePercentage float64 `json:"ath_change_percentage"` ATHDate string `json:"ath_date"` ATL float64 `json:"atl"` ATLChangePercentage float64 `json:"atl_change_percentage"` ATLDate string `json:"atl_date"` LastUpdated string `json:"last_updated"` } func getIds(query string) []string { req, _ := http.NewRequest("GET", "https://api.coingecko.com/api/v3/coins/list", nil) req.Header.Set("Accept", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var coinList *[]CoinList json.NewDecoder(resp.Body).Decode(&coinList) var returnList []string for _, coin := range *coinList { // get the coingecko ids for the requested coin if coin.Symbol == query { returnList = append(returnList, coin.Id) } } if len(returnList) > 0 { return returnList } else { // fallback to bitcoin returnList = append(returnList, "bitcoin") return returnList } } func getData(query []string) string { symbol := strings.Join(query, ",") url := fmt.Sprintf("https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=%s&order=market_cap_desc&per_page=1&page=1&sparkline=false", symbol) req, _ := http.NewRequest("GET", url, nil) req.Header.Set("Accept", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var coin []*Market json.NewDecoder(resp.Body).Decode(&coin) c := coin[0] const output = `%s (%s) Current Price: $%.4f Market Ca: $%.0f 24 Hour Volume: $%.0f 24 Hour High: $%.4f 24 Hour Low: $%.4f All Time High: $%.4f All Time Low: $%.4f` return fmt.Sprintf(output, c.Id, c.Symbol, c.CurrentPrice, c.MarketCap, c.TotalVolume, c.High24, c.Low24, c.ATH, c.ATL) } // Commands supported: // !coingecko SYMBOL // Responds with price data on the currency func (e *Service) Commands(cli types.MatrixClient) []types.Command { return []types.Command{ { Path: []string{"cc"}, Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) { coinIds := getIds(strings.Join(args, "")) output := getData(coinIds) return &mevt.MessageEventContent{ MsgType: mevt.MsgNotice, Body: output, }, nil }, }, } } func init() { types.RegisterService(func(serviceID string, serviceUserID id.UserID, webhookEndpointURL string) types.Service { return &Service{ DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType), } }) }