2024-06-06 19:57:29 +00:00
package token
2023-04-25 12:00:17 +00:00
import (
"context"
"database/sql"
"math/big"
"github.com/ethereum/go-ethereum/common"
)
2024-06-06 19:57:29 +00:00
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 )
}
2023-04-25 12:00:17 +00:00
type Persistence struct {
db * sql . DB
}
func NewPersistence ( db * sql . DB ) * Persistence {
return & Persistence { db : db }
}
2024-06-06 19:57:29 +00:00
func ( p * Persistence ) SaveTokens ( tokens map [ common . Address ] [ ] StorageToken ) ( err error ) {
2023-04-25 12:00:17 +00:00
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 {
2024-03-11 13:48:40 +00:00
if b . HasError {
2023-04-25 12:00:17 +00:00
continue
}
2023-10-17 15:05:05 +00:00
_ , 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 )
2023-04-25 12:00:17 +00:00
if err != nil {
return err
}
}
}
}
return nil
}
2024-06-06 19:57:29 +00:00
func ( p * Persistence ) GetTokens ( ) ( map [ common . Address ] [ ] StorageToken , error ) {
2023-10-17 15:05:05 +00:00
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 ` )
2023-04-25 12:00:17 +00:00
if err != nil {
return nil , err
}
defer rows . Close ( )
2024-06-06 19:57:29 +00:00
acc := make ( map [ common . Address ] map [ string ] StorageToken )
2023-04-25 12:00:17 +00:00
for rows . Next ( ) {
2023-09-20 10:48:08 +00:00
var addressStr , balance , rawBalance , tokenAddress string
2024-06-06 19:57:29 +00:00
token := StorageToken { }
2023-04-25 12:00:17 +00:00
var chainID uint64
2023-10-17 15:05:05 +00:00
err := rows . Scan ( & addressStr , & token . Name , & token . Symbol , & tokenAddress , & token . Decimals , & token . Description , & token . AssetWebsiteURL , & balance , & rawBalance , & chainID )
2023-04-25 12:00:17 +00:00
if err != nil {
return nil , err
}
2024-06-06 19:57:29 +00:00
token . Address = common . HexToAddress ( tokenAddress )
token . ChainID = chainID
2023-04-25 12:00:17 +00:00
address := common . HexToAddress ( addressStr )
if acc [ address ] == nil {
2024-06-06 19:57:29 +00:00
acc [ address ] = make ( map [ string ] StorageToken )
2023-04-25 12:00:17 +00:00
}
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 {
2023-09-20 10:48:08 +00:00
RawBalance : rawBalance ,
Balance : balanceFloat ,
Address : common . HexToAddress ( tokenAddress ) ,
ChainID : chainID ,
2023-04-25 12:00:17 +00:00
}
}
2024-06-06 19:57:29 +00:00
result := make ( map [ common . Address ] [ ] StorageToken )
2023-04-25 12:00:17 +00:00
for address , tks := range acc {
for _ , t := range tks {
result [ address ] = append ( result [ address ] , t )
}
}
return result , nil
}