144 lines
4.0 KiB
Go
144 lines
4.0 KiB
Go
package token
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"math/big"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
)
|
|
|
|
type TokenMarketValues struct {
|
|
MarketCap float64 `json:"marketCap"`
|
|
HighDay float64 `json:"highDay"`
|
|
LowDay float64 `json:"lowDay"`
|
|
ChangePctHour float64 `json:"changePctHour"`
|
|
ChangePctDay float64 `json:"changePctDay"`
|
|
ChangePct24hour float64 `json:"changePct24hour"`
|
|
Change24hour float64 `json:"change24hour"`
|
|
Price float64 `json:"price"`
|
|
HasError bool `json:"hasError"`
|
|
}
|
|
|
|
type StorageToken struct {
|
|
Token
|
|
BalancesPerChain map[uint64]ChainBalance `json:"balancesPerChain"`
|
|
Description string `json:"description"`
|
|
AssetWebsiteURL string `json:"assetWebsiteUrl"`
|
|
BuiltOn string `json:"builtOn"`
|
|
MarketValuesPerCurrency map[string]TokenMarketValues `json:"marketValuesPerCurrency"`
|
|
}
|
|
|
|
type ChainBalance struct {
|
|
RawBalance string `json:"rawBalance"`
|
|
Balance *big.Float `json:"balance"`
|
|
Balance1DayAgo string `json:"balance1DayAgo"`
|
|
Address common.Address `json:"address"`
|
|
ChainID uint64 `json:"chainId"`
|
|
HasError bool `json:"hasError"`
|
|
}
|
|
|
|
type TokenBalancesStorage interface {
|
|
SaveTokens(tokens map[common.Address][]StorageToken) error
|
|
GetTokens() (map[common.Address][]StorageToken, error)
|
|
}
|
|
|
|
type Persistence struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewPersistence(db *sql.DB) *Persistence {
|
|
return &Persistence{db: db}
|
|
}
|
|
|
|
func (p *Persistence) SaveTokens(tokens map[common.Address][]StorageToken) (err error) {
|
|
tx, err := p.db.BeginTx(context.Background(), &sql.TxOptions{})
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer func() {
|
|
if err == nil {
|
|
err = tx.Commit()
|
|
return
|
|
}
|
|
// don't shadow original error
|
|
_ = tx.Rollback()
|
|
}()
|
|
|
|
for address, addressTokens := range tokens {
|
|
for _, t := range addressTokens {
|
|
for chainID, b := range t.BalancesPerChain {
|
|
if b.HasError {
|
|
continue
|
|
}
|
|
_, err = tx.Exec(`INSERT INTO token_balances(user_address,token_name,token_symbol,token_address,token_decimals,token_description,token_url,balance,raw_balance,chain_id) VALUES (?,?,?,?,?,?,?,?,?,?)`, address.Hex(), t.Name, t.Symbol, b.Address.Hex(), t.Decimals, t.Description, t.AssetWebsiteURL, b.Balance.String(), b.RawBalance, chainID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Persistence) GetTokens() (map[common.Address][]StorageToken, error) {
|
|
rows, err := p.db.Query(`SELECT user_address, token_name, token_symbol, token_address, token_decimals, token_description, token_url, balance, raw_balance, chain_id FROM token_balances `)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
acc := make(map[common.Address]map[string]StorageToken)
|
|
|
|
for rows.Next() {
|
|
var addressStr, balance, rawBalance, tokenAddress string
|
|
token := StorageToken{}
|
|
var chainID uint64
|
|
|
|
err := rows.Scan(&addressStr, &token.Name, &token.Symbol, &tokenAddress, &token.Decimals, &token.Description, &token.AssetWebsiteURL, &balance, &rawBalance, &chainID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
token.Address = common.HexToAddress(tokenAddress)
|
|
token.ChainID = chainID
|
|
address := common.HexToAddress(addressStr)
|
|
|
|
if acc[address] == nil {
|
|
acc[address] = make(map[string]StorageToken)
|
|
}
|
|
|
|
if acc[address][token.Name].Name == "" {
|
|
token.BalancesPerChain = make(map[uint64]ChainBalance)
|
|
acc[address][token.Name] = token
|
|
}
|
|
|
|
tokenAcc := acc[address][token.Name]
|
|
|
|
balanceFloat := new(big.Float)
|
|
_, _, err = balanceFloat.Parse(balance, 10)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tokenAcc.BalancesPerChain[chainID] = ChainBalance{
|
|
RawBalance: rawBalance,
|
|
Balance: balanceFloat,
|
|
Address: common.HexToAddress(tokenAddress),
|
|
ChainID: chainID,
|
|
}
|
|
}
|
|
|
|
result := make(map[common.Address][]StorageToken)
|
|
|
|
for address, tks := range acc {
|
|
for _, t := range tks {
|
|
result[address] = append(result[address], t)
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|