diff --git a/address.go b/address.go index 9639bfe..7e0db1c 100644 --- a/address.go +++ b/address.go @@ -2,14 +2,13 @@ package main import ( "fmt" - "strconv" - "strings" "time" log "github.com/sirupsen/logrus" ) // AddressInfo represents information about a given address. +// AddressInfo implements the Info interface type AddressInfo struct { Address string `gorm:"primaryKey"` Nickname string @@ -82,16 +81,17 @@ main: log.Errorf("error calling btcapi: %v", err) } - currencyBalance, err := w.ConvertBalance(addressSummary.TXHistory.BalanceSat) - if err != nil { + currencyBalance, err := w.ConvertBalance(oldAddressInfo.Currency, addressSummary.TXHistory.BalanceSat) + if err != nil || currencyBalance == nil { log.Errorf("unable to convert balance of %d to %s, err: %v", addressSummary.TXHistory.BalanceSat, w.Currency, err) + currencyBalance[0] = "0.00" } addressInfo := AddressInfo{ Address: address, Nickname: nickname, BalanceSat: addressSummary.TXHistory.BalanceSat, - BalanceCurrency: strconv.FormatFloat(currencyBalance, 'f', 2, 64), - Currency: strings.ToUpper(w.Currency), + BalanceCurrency: currencyBalance[0], + Currency: oldAddressInfo.Currency, PreviousBalanceSat: oldAddressInfo.BalanceSat, PreviousBalanceCurrency: oldAddressInfo.BalanceCurrency, TXCount: addressSummary.TXHistory.TXCount, @@ -123,10 +123,10 @@ func (w Watcher) CreateNewAddressInfo(address string, nickname string) (AddressI Address: address, Nickname: nickname, BalanceSat: 0, - BalanceCurrency: "0.0", + BalanceCurrency: "0.00", Currency: w.Currency, PreviousBalanceSat: 0, - PreviousBalanceCurrency: "0.0", + PreviousBalanceCurrency: "0.00", TXCount: 0, } @@ -137,12 +137,25 @@ func (w Watcher) CreateNewAddressInfo(address string, nickname string) (AddressI return addressInfo, nil } -// Gets an AddressInfo object from the database with an address -func (w Watcher) GetAddressInfo(address string) (addressInfo AddressInfo) { +// Gets an AddressInfo object from the database identified by an address +func (w Watcher) GetAddressInfo(address string) (a AddressInfo) { w.DB.Model(&AddressInfo{}). Where(&AddressInfo{Address: address}). - Scan(&addressInfo) - return addressInfo + Scan(&a) + // Update the object with current exchange rates + if (a != AddressInfo{}) { + var err error + bs, err := w.ConvertBalance(a.Currency, a.PreviousBalanceSat, a.BalanceSat) + if err != nil || bs == nil { + log.Errorf("error converting balance, err: %v", err) + return a + } + a.PreviousBalanceCurrency = bs[0] + a.BalanceCurrency = bs[1] + // Update the currency data in the database + w.UpdateInfo(a) + } + return a } // Deletes an AddressInfo object from the database with an address diff --git a/btc.go b/btc.go index 0ba210a..c0944b1 100644 --- a/btc.go +++ b/btc.go @@ -2,31 +2,42 @@ package main import ( "fmt" - "strings" + "math" ) -// ConvertBalance takes a balance in satoshis and returns the equivalent -// balance in the currency specified by Watcher.Currency -func (w Watcher) ConvertBalance(balanceSat int) (float64, error) { +const ( + CurrencyUSD = "USD" + CurrencyEUR = "EUR" + CurrencyGBP = "GBP" + CurrencyXAU = "XAU" +) + +// ConvertBalance takes a currency and one or more balances in satoshis and +// returns the equivalent balance(s) in the currency specified with +// two digits of precision. +func (w Watcher) ConvertBalance(currency string, balancesSat ...int) (bs []string, err error) { price, err := w.BTCAPI.Price() if err != nil { - return 0.0, fmt.Errorf("error calling btcapi: %v", err) + return nil, fmt.Errorf("error calling btcapi: %v", err) } - balanceFiat := 0.0 - currency := strings.ToUpper(w.Currency) - bitcoinBalance := float64(balanceSat) / float64(SatsPerBitcoin) - switch currency { - case "USD": - balanceFiat = price.USD * bitcoinBalance - case "EUR": - balanceFiat = price.EUR * bitcoinBalance - case "GBP": - balanceFiat = price.GBP * bitcoinBalance - case "XAU": - balanceFiat = price.XAU * bitcoinBalance - default: - balanceFiat = price.USD * bitcoinBalance + for _, b := range balancesSat { + balanceCurrency := 0.0 + bitcoinBalance := float64(b) / float64(SatsPerBitcoin) + switch currency { + case CurrencyUSD: + balanceCurrency = price.USD * bitcoinBalance + case CurrencyEUR: + balanceCurrency = price.EUR * bitcoinBalance + case CurrencyGBP: + balanceCurrency = price.GBP * bitcoinBalance + case CurrencyXAU: + balanceCurrency = price.XAU * bitcoinBalance + default: + balanceCurrency = price.USD * bitcoinBalance + } + bs = append(bs, fmt.Sprint(math.Round(balanceCurrency*100)/100)) } - return balanceFiat, nil + // Round with two digits of precision + return bs, nil } diff --git a/pubkey.go b/pubkey.go index 6355639..b79f9a7 100644 --- a/pubkey.go +++ b/pubkey.go @@ -2,8 +2,6 @@ package main import ( "fmt" - "strconv" - "strings" "time" log "github.com/sirupsen/logrus" @@ -11,6 +9,7 @@ import ( ) // PubkeyInfo represents information about a given pubkey. +// Pubkey implements the Info interface type PubkeyInfo struct { Pubkey string `gorm:"primaryKey"` Nickname string @@ -154,17 +153,18 @@ main: totalTxCount = totalTxCount + totalPubkeyTxCount } - currencyBalance, err := w.ConvertBalance(totalBalance) - if err != nil { + currencyBalance, err := w.ConvertBalance(oldPubkeyInfo.Currency, totalBalance) + if err != nil || currencyBalance == nil { log.Errorf("unable to convert balance of %d to %s, err: %v", totalBalance, w.Currency, err) + currencyBalance[0] = "0.00" } pubkeyInfo := PubkeyInfo{ Pubkey: pubKeys[0], Nickname: nickname, BalanceSat: totalBalance, + BalanceCurrency: currencyBalance[0], + Currency: oldPubkeyInfo.Currency, PreviousBalanceSat: oldPubkeyInfo.BalanceSat, - Currency: strings.ToUpper(w.Currency), - BalanceCurrency: strconv.FormatFloat(currencyBalance, 'f', 2, 64), PreviousBalanceCurrency: oldPubkeyInfo.BalanceCurrency, TXCount: totalTxCount, } @@ -194,10 +194,10 @@ func (w Watcher) CreateNewPubkeyInfo(pubkey string, nickname string) (PubkeyInfo Pubkey: pubkey, Nickname: nickname, BalanceSat: 0, - BalanceCurrency: "0.0", + BalanceCurrency: "0.00", Currency: w.Currency, PreviousBalanceSat: 0, - PreviousBalanceCurrency: "0.0", + PreviousBalanceCurrency: "0.00", TXCount: 0, } tx := w.DB.Model(&PubkeyInfo{}).Create(&pubkeyInfo) @@ -219,12 +219,24 @@ func (w Watcher) UpdatePubkeysTotal(address string, totalPubkeyBalance *int, tot return addressSummary, nil } -// GetPubkeyInfo gets a PubkeyInfo object from the database with a pubkey -func (w Watcher) GetPubkeyInfo(pubkey string) (pubkeyInfo PubkeyInfo) { +// GetPubkeyInfo gets a PubkeyInfo object from the database identified by a pubkey +func (w Watcher) GetPubkeyInfo(pubkey string) (p PubkeyInfo) { w.DB.Model(&PubkeyInfo{}). Where(&PubkeyInfo{Pubkey: pubkey}). - Scan(&pubkeyInfo) - return pubkeyInfo + Scan(&p) + // Update the object with current exchange rates + if (p != PubkeyInfo{}) { + bs, err := w.ConvertBalance(p.Currency, p.PreviousBalanceSat, p.BalanceSat) + if err != nil || bs == nil { + log.Errorf("error converting balance, err: %v", err) + return p + } + p.PreviousBalanceCurrency = bs[0] + p.BalanceCurrency = bs[1] + // Update the currency data in the database + w.UpdateInfo(p) + } + return p } // DeletePubkeyInfo deletes a PubkeyInfo object from the database with a pubkey diff --git a/util.go b/util.go index 628da3f..479902b 100644 --- a/util.go +++ b/util.go @@ -89,7 +89,7 @@ func (w Watcher) FillDefaults() { watcher.Port = "80" } if w.Currency == "" { - watcher.Currency = "USD" + watcher.Currency = CurrencyUSD } // Set up DB path