Skip to content

Commit

Permalink
fix: holders (#203)
Browse files Browse the repository at this point in the history
* fix: holders
fix: floor decorator in db init

* S1028: should use fmt.Errorf(...) instead of errors.New(fmt.Sprintf(...)) (gosimple)

* remove frequency override for holders
  • Loading branch information
rssnyder authored Sep 1, 2023
1 parent a1048a8 commit ac4cfa4
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 40 deletions.
18 changes: 12 additions & 6 deletions holders.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Holders struct {
Activity string `json:"activity"`
Nickname bool `json:"nickname"`
Frequency int `json:"frequency"`
APIToken string `json:"api_token"`
ClientID string `json:"client_id"`
Token string `json:"discord_bot_token"`
close chan int `json:"-"`
Expand Down Expand Up @@ -78,7 +79,7 @@ func (h *Holders) watchHolders() {
// check for frequency override
// set to one hour to avoid lockout
if *frequency != 0 {
h.Frequency = 3600
h.Frequency = *frequency
}

// perform management operations
Expand All @@ -99,29 +100,34 @@ func (h *Holders) watchHolders() {
return
case <-ticker.C:

nickname := utils.GetHolders(h.Network, h.Address)
holders, err := utils.GetHolders(h.Network, h.Address, h.APIToken)
if err != nil {
logger.Errorf("Error getting holders for %s/%s %s", h.Network, h.Address, err)
continue
}
displayName := fmt.Sprintf("%d", holders)

if h.Nickname {

for _, g := range guilds {

err = dg.GuildMemberNickname(g.ID, "@me", nickname)
err = dg.GuildMemberNickname(g.ID, "@me", displayName)
if err != nil {
logger.Errorf("Error updating nickname: %s\n", err)
continue
} else {
logger.Debugf("Set nickname in %s: %s\n", g.Name, nickname)
logger.Debugf("Set nickname in %s: %s\n", g.Name, displayName)
}
lastUpdate.With(prometheus.Labels{"type": "holders", "ticker": fmt.Sprintf("%s-%s", h.Network, h.Address), "guild": g.Name}).SetToCurrentTime()
time.Sleep(time.Duration(h.Frequency) * time.Second)
}
} else {

err = dg.UpdateWatchStatus(0, nickname)
err = dg.UpdateWatchStatus(0, displayName)
if err != nil {
logger.Errorf("Unable to set activity: %s\n", err)
} else {
logger.Debugf("Set activity: %s\n", nickname)
logger.Debugf("Set activity: %s\n", displayName)
lastUpdate.With(prometheus.Labels{"type": "holders", "ticker": fmt.Sprintf("%s-%s", h.Network, h.Address), "guild": "None"}).SetToCurrentTime()
}
}
Expand Down
8 changes: 4 additions & 4 deletions holders_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func (m *Manager) ImportHolder() {

// query
rows, err := m.DB.Query("SELECT clientID, token, nickname, activity, network, address, frequency FROM holders")
rows, err := m.DB.Query("SELECT clientID, token, nickname, activity, network, address, frequency, apiToken FROM holders")
if err != nil {
logger.Warningf("Unable to query tokens in db: %s", err)
return
Expand All @@ -24,7 +24,7 @@ func (m *Manager) ImportHolder() {
for rows.Next() {
var importedHolders Holders

err = rows.Scan(&importedHolders.ClientID, &importedHolders.Token, &importedHolders.Nickname, &importedHolders.Activity, &importedHolders.Network, &importedHolders.Address, &importedHolders.Frequency)
err = rows.Scan(&importedHolders.ClientID, &importedHolders.Token, &importedHolders.Nickname, &importedHolders.Activity, &importedHolders.Network, &importedHolders.Address, &importedHolders.Frequency, &importedHolders.APIToken)
if err != nil {
logger.Errorf("Unable to load token from db: %s", err)
continue
Expand Down Expand Up @@ -163,13 +163,13 @@ func (m *Manager) WatchHolders(holders *Holders) {
func (m *Manager) StoreHolders(holders *Holders) {

// store new entry in db
stmt, err := m.DB.Prepare("INSERT INTO holders(clientId, token, nickname, activity, network, address, frequency) values(?,?,?,?,?,?,?)")
stmt, err := m.DB.Prepare("INSERT INTO holders(clientId, token, nickname, activity, network, address, frequency, apiToken) values(?,?,?,?,?,?,?,?)")
if err != nil {
logger.Warningf("Unable to store holders in db %s: %s", holders.label(), err)
return
}

res, err := stmt.Exec(holders.ClientID, holders.Token, holders.Nickname, holders.Activity, holders.Network, holders.Address, holders.Frequency)
res, err := stmt.Exec(holders.ClientID, holders.Token, holders.Nickname, holders.Activity, holders.Network, holders.Address, holders.Frequency, holders.APIToken)
if err != nil {
logger.Warningf("Unable to store holders in db %s: %s", holders.label(), err)
return
Expand Down
29 changes: 22 additions & 7 deletions manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ func dbInit(fileName string) *sql.DB {
nickname bool,
activity string,
network string,
address string
address string,
apiToken string
);
CREATE TABLE IF NOT EXISTS gases (
id integer primary key autoincrement,
Expand Down Expand Up @@ -413,7 +414,8 @@ func dbInit(fileName string) *sql.DB {
nickname bool,
activity string,
marketplace string,
name string
name string,
decorator string
);`

_, err = db.Exec(bootstrap)
Expand All @@ -440,7 +442,7 @@ func dbInit(fileName string) *sql.DB {
// v3.11.0 - add gas API Token
_, err = db.Exec("alter table gases add column apiToken default \"\";")
if err == nil {
logger.Warnln("Added new column to tickers: apiToken (1)")
logger.Warnln("Added new column to gases: apiToken (1)")
} else if err.Error() == "SQL logic error: duplicate column name: apiToken (1)" {
logger.Debug("New column already exists in gases: apiToken (1)")
} else if err != nil {
Expand All @@ -453,7 +455,7 @@ func dbInit(fileName string) *sql.DB {
// v3.11.0 - add floor activity
_, err = db.Exec("alter table floors add column activity default \"\";")
if err == nil {
logger.Warnln("Added new column to tickers: activity (1)")
logger.Warnln("Added new column to floors: activity (1)")
} else if err.Error() == "SQL logic error: duplicate column name: activity (1)" {
logger.Debug("New column already exists in floors: activity (1)")
} else if err != nil {
Expand All @@ -466,7 +468,7 @@ func dbInit(fileName string) *sql.DB {
// v3.11.0 - add floor color
_, err = db.Exec("alter table floors add column color default false;")
if err == nil {
logger.Warnln("Added new column to tickers: color (1)")
logger.Warnln("Added new column to floors: color (1)")
} else if err.Error() == "SQL logic error: duplicate column name: color (1)" {
logger.Debug("New column already exists in floors: color (1)")
} else if err != nil {
Expand All @@ -479,7 +481,7 @@ func dbInit(fileName string) *sql.DB {
// v3.11.0 - add floor decorator
_, err = db.Exec("alter table floors add column decorator default \"\";")
if err == nil {
logger.Warnln("Added new column to tickers: decorator (1)")
logger.Warnln("Added new column to floors: decorator (1)")
} else if err.Error() == "SQL logic error: duplicate column name: decorator (1)" {
logger.Debug("New column already exists in floors: decorator (1)")
} else if err != nil {
Expand All @@ -492,7 +494,7 @@ func dbInit(fileName string) *sql.DB {
// v3.11.0 - add floor currency
_, err = db.Exec("alter table floors add column currency default \"\";")
if err == nil {
logger.Warnln("Added new column to tickers: currency (1)")
logger.Warnln("Added new column to floors: currency (1)")
} else if err.Error() == "SQL logic error: duplicate column name: currency (1)" {
logger.Debug("New column already exists in floors: currency (1)")
} else if err != nil {
Expand All @@ -502,6 +504,19 @@ func dbInit(fileName string) *sql.DB {
return dbNull
}

// v3.10.6
_, err = db.Exec("alter table holders add column apiToken default \"\";")
if err == nil {
logger.Warnln("Added new column to holders: apiToken (1)")
} else if err.Error() == "SQL logic error: duplicate column name: apiToken (1)" {
logger.Debug("New column already exists in floors: apiToken (1)")
} else if err != nil {
logger.Errorln(err)
logger.Warning("Will not be storing state.")
var dbNull *sql.DB
return dbNull
}

logger.Infof("Will be storing state in %s\n", fileName)

return db
Expand Down
85 changes: 62 additions & 23 deletions utils/holders.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,88 @@
package utils

import (
"encoding/json"
"fmt"
"log"
"io"
"net/http"
"strings"

"github.com/PuerkitoBio/goquery"
"time"
)

const (
ChainURL = "https://%s/token/%s"
ChainURL = "https://api.covalenthq.com/v1/%s/tokens/%s/token_holders_v2/"
)

func GetHolders(chain, contract string) string {
var holders string
type Holders struct {
Data struct {
UpdatedAt time.Time `json:"updated_at"`
ChainID int `json:"chain_id"`
ChainName string `json:"chain_name"`
Items []struct {
ContractDecimals int `json:"contract_decimals"`
ContractName string `json:"contract_name"`
ContractTickerSymbol string `json:"contract_ticker_symbol"`
ContractAddress string `json:"contract_address"`
SupportsErc []string `json:"supports_erc"`
LogoURL string `json:"logo_url"`
Address string `json:"address"`
Balance string `json:"balance"`
TotalSupply string `json:"total_supply"`
BlockHeight int `json:"block_height"`
} `json:"items"`
Pagination struct {
HasMore bool `json:"has_more"`
PageNumber int `json:"page_number"`
PageSize int `json:"page_size"`
TotalCount int `json:"total_count"`
} `json:"pagination"`
} `json:"data"`
Error bool `json:"error"`
ErrorMessage interface{} `json:"error_message"`
ErrorCode interface{} `json:"error_code"`
}

func GetHolders(chain, contract, apiKey string) (int, error) {
var holders Holders
var result int

switch chain {
case "ethereum":
chain = "etherscan.io"
chain = "eth-mainnet"
case "binance-smart-chain":
chain = "bscscan.com"
chain = "bsc-mainnet"
default:
chain = "etherscan.io"
chain = "eth-mainnet"
}

reqUrl := fmt.Sprintf(ChainURL, chain, contract)

req, err := http.NewRequest("GET", reqUrl, nil)
req.SetBasicAuth(apiKey, "")
if err != nil {
return result, err
}

reqURL := fmt.Sprintf(ChainURL, chain, contract)
req.Header.Add("User-Agent", "Mozilla/5.0")
req.Header.Add("accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return result, err
}

response, err := http.Get(reqURL)
results, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
return result, err
}
defer response.Body.Close()

document, err := goquery.NewDocumentFromReader(response.Body)
err = json.Unmarshal(results, &holders)
if err != nil {
log.Fatal("Error loading HTTP response body. ", err)
return result, err
}

document.Find("div").Each(func(index int, element *goquery.Selection) {
exists := element.HasClass("mr-3")
if exists {
holders = strings.TrimSpace(element.Text())
}
})
if holders.Error {
return result, fmt.Errorf("%v", holders.ErrorMessage)
}

return holders
return holders.Data.Pagination.TotalCount, err
}

0 comments on commit ac4cfa4

Please sign in to comment.