Skip to content

Commit c094479

Browse files
committed
Merge branch 'keystore-balance'
2 parents ab99618 + b383d28 commit c094479

File tree

5 files changed

+105
-114
lines changed

5 files changed

+105
-114
lines changed

backend/accounts.go

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"encoding/hex"
1919
"fmt"
2020
"math"
21+
"math/big"
2122
"sort"
2223
"strings"
2324
"time"
@@ -28,10 +29,13 @@ import (
2829
accountsTypes "github.com/digitalbitbox/bitbox-wallet-app/backend/accounts/types"
2930
"github.com/digitalbitbox/bitbox-wallet-app/backend/bitsurance"
3031
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc"
32+
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc/util"
33+
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/coin"
3134
coinpkg "github.com/digitalbitbox/bitbox-wallet-app/backend/coins/coin"
3235
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/eth"
3336
"github.com/digitalbitbox/bitbox-wallet-app/backend/config"
3437
"github.com/digitalbitbox/bitbox-wallet-app/backend/keystore"
38+
"github.com/digitalbitbox/bitbox-wallet-app/backend/rates"
3539
"github.com/digitalbitbox/bitbox-wallet-app/backend/signing"
3640
"github.com/digitalbitbox/bitbox-wallet-app/util/errp"
3741
"github.com/digitalbitbox/bitbox-wallet-app/util/observable"
@@ -60,7 +64,7 @@ type AccountsList []accounts.Interface
6064

6165
// KeystoresAccountsListMap is a map where keys are keystores' fingerprints and values are
6266
// AccountsLists of accounts belonging to each keystore.
63-
type KeystoresAccountsListMap map[*config.Keystore]AccountsList
67+
type KeystoresAccountsListMap map[string]AccountsList
6468

6569
func (a AccountsList) lookup(code accountsTypes.Code) accounts.Interface {
6670
for _, acct := range a {
@@ -205,6 +209,90 @@ func (backend *Backend) SupportedCoins(keystore keystore.Keystore) []coinpkg.Cod
205209
return availableCoins
206210
}
207211

212+
// AccountsByKeystore returns a map of the current accounts of the backend, grouped
213+
// by keystore.
214+
func (backend *Backend) AccountsByKeystore() (KeystoresAccountsListMap, error) {
215+
defer backend.accountsAndKeystoreLock.RLock()()
216+
accountsByKeystore := KeystoresAccountsListMap{}
217+
for _, account := range backend.accounts {
218+
persistedAccount := account.Config().Config
219+
rootFingerprint, err := persistedAccount.SigningConfigurations.RootFingerprint()
220+
if err != nil {
221+
return nil, err
222+
}
223+
hexFingerprint := hex.EncodeToString(rootFingerprint)
224+
accountsByKeystore[hexFingerprint] = append(accountsByKeystore[hexFingerprint], account)
225+
}
226+
return accountsByKeystore, nil
227+
}
228+
229+
// accountFiatBalance returns an account's balance, converted in fiat currency.
230+
func (backend *Backend) accountFiatBalance(account accounts.Interface, fiat string) (*big.Rat, error) {
231+
balance, err := account.Balance()
232+
if err != nil {
233+
return nil, err
234+
}
235+
236+
coinDecimals := coin.DecimalsExp(account.Coin())
237+
238+
price, err := backend.RatesUpdater().LatestPriceForPair(account.Coin().Unit(false), fiat)
239+
if err != nil {
240+
return nil, err
241+
}
242+
fiatValue := new(big.Rat).Mul(
243+
new(big.Rat).SetFrac(
244+
balance.Available().BigInt(),
245+
coinDecimals,
246+
),
247+
new(big.Rat).SetFloat64(price),
248+
)
249+
return fiatValue, nil
250+
}
251+
252+
// AccountsTotalBalanceByKeystore returns a map of accounts' total balances across coins, grouped by keystore.
253+
func (backend *Backend) AccountsTotalBalanceByKeystore() (map[string]KeystoreTotalAmount, error) {
254+
totalAmounts := make(map[string]KeystoreTotalAmount)
255+
fiat := backend.Config().AppConfig().Backend.MainFiat
256+
isFiatBtc := fiat == rates.BTC.String()
257+
fiatUnit := fiat
258+
if isFiatBtc && backend.Config().AppConfig().Backend.BtcUnit == coinpkg.BtcUnitSats {
259+
fiatUnit = "sat"
260+
}
261+
262+
formatBtcAsSat := util.FormatBtcAsSat(backend.Config().AppConfig().Backend.BtcUnit)
263+
264+
accountsByKeystore, err := backend.AccountsByKeystore()
265+
if err != nil {
266+
return nil, err
267+
}
268+
for rootFingerprint, accountList := range accountsByKeystore {
269+
currentTotal := new(big.Rat)
270+
for _, account := range accountList {
271+
if account.Config().Config.Inactive {
272+
continue
273+
}
274+
if account.FatalError() {
275+
continue
276+
}
277+
err := account.Initialize()
278+
if err != nil {
279+
return nil, err
280+
}
281+
282+
fiatValue, err := backend.accountFiatBalance(account, fiat)
283+
if err != nil {
284+
return nil, err
285+
}
286+
currentTotal.Add(currentTotal, fiatValue)
287+
}
288+
totalAmounts[rootFingerprint] = KeystoreTotalAmount{
289+
FiatUnit: fiatUnit,
290+
Total: coinpkg.FormatAsCurrency(currentTotal, isFiatBtc, formatBtcAsSat),
291+
}
292+
}
293+
return totalAmounts, nil
294+
}
295+
208296
// LookupInsuredAccounts queries the insurance status of specified or all active BTC accounts
209297
// and updates the internal state based on the retrieved information. If the accountCode is
210298
// provided, it checks the insurance status for that specific account; otherwise, it checks

backend/backend.go

Lines changed: 1 addition & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
package backend
1717

1818
import (
19-
"encoding/hex"
2019
"fmt"
21-
"math/big"
2220
"net/http"
2321
"net/url"
2422
"os"
@@ -34,8 +32,6 @@ import (
3432
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc"
3533
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc/electrum"
3634
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc/types"
37-
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc/util"
38-
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/coin"
3935
coinpkg "github.com/digitalbitbox/bitbox-wallet-app/backend/coins/coin"
4036
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/eth"
4137
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/eth/etherscan"
@@ -545,97 +541,14 @@ func (backend *Backend) Accounts() AccountsList {
545541
return backend.accounts
546542
}
547543

548-
// AccountsByKeystore returns a map of the current accounts of the backend, grouped
549-
// by keystore.
550-
func (backend *Backend) AccountsByKeystore() (KeystoresAccountsListMap, error) {
551-
accountsByKeystore := KeystoresAccountsListMap{}
552-
defer backend.accountsAndKeystoreLock.RLock()()
553-
for _, account := range backend.accounts {
554-
persistedAccount := account.Config().Config
555-
rootFingerprint, err := persistedAccount.SigningConfigurations.RootFingerprint()
556-
if err != nil {
557-
return nil, err
558-
}
559-
keystore, err := backend.Config().AccountsConfig().LookupKeystore(rootFingerprint)
560-
if err != nil {
561-
return nil, err
562-
}
563-
accountsByKeystore[keystore] = append(accountsByKeystore[keystore], account)
564-
}
565-
return accountsByKeystore, nil
566-
}
567-
568-
// KeystoreTotalAmount represents the total balance amount of the accounts belongings to a keystore.
544+
// KeystoreTotalAmount represents the total balance amount of the accounts belonging to a keystore.
569545
type KeystoreTotalAmount = struct {
570546
// FiatUnit is the fiat unit of the total amount
571547
FiatUnit string `json:"fiatUnit"`
572548
// Total formatted for frontend visualization
573549
Total string `json:"total"`
574550
}
575551

576-
// AccountsTotalBalanceByKeystore returns a map of accounts' total balances across coins, grouped by keystore.
577-
func (backend *Backend) AccountsTotalBalanceByKeystore() (map[string]KeystoreTotalAmount, error) {
578-
totalAmounts := make(map[string]KeystoreTotalAmount)
579-
fiat := backend.Config().AppConfig().Backend.MainFiat
580-
isFiatBtc := fiat == rates.BTC.String()
581-
fiatUnit := fiat
582-
if isFiatBtc && backend.Config().AppConfig().Backend.BtcUnit == coin.BtcUnitSats {
583-
fiatUnit = "sat"
584-
}
585-
586-
formatBtcAsSat := util.FormatBtcAsSat(backend.Config().AppConfig().Backend.BtcUnit)
587-
588-
accountsByKeystore, err := backend.AccountsByKeystore()
589-
if err != nil {
590-
return nil, err
591-
}
592-
for keystore, accountList := range accountsByKeystore {
593-
rootFingerprint := hex.EncodeToString(keystore.RootFingerprint)
594-
currentTotal := new(big.Rat)
595-
for _, account := range accountList {
596-
if account.Config().Config.Inactive {
597-
continue
598-
}
599-
if account.FatalError() {
600-
continue
601-
}
602-
err := account.Initialize()
603-
if err != nil {
604-
return nil, err
605-
}
606-
balance, err := account.Balance()
607-
if err != nil {
608-
return nil, err
609-
}
610-
// e.g. 1e8 for Bitcoin/Litecoin, 1e18 for Ethereum, etc. Used to convert from the smallest
611-
// unit to the standard unit (BTC, LTC; ETH, etc.).
612-
coinDecimals := new(big.Int).Exp(
613-
big.NewInt(10),
614-
big.NewInt(int64(account.Coin().Decimals(false))),
615-
nil,
616-
)
617-
618-
price, err := backend.RatesUpdater().LatestPriceForPair(account.Coin().Unit(false), fiat)
619-
if err != nil {
620-
return nil, err
621-
}
622-
fiatValue := new(big.Rat).Mul(
623-
new(big.Rat).SetFrac(
624-
balance.Available().BigInt(),
625-
coinDecimals,
626-
),
627-
new(big.Rat).SetFloat64(price),
628-
)
629-
currentTotal.Add(currentTotal, fiatValue)
630-
}
631-
totalAmounts[rootFingerprint] = KeystoreTotalAmount{
632-
FiatUnit: fiatUnit,
633-
Total: coin.FormatAsCurrency(currentTotal, isFiatBtc, formatBtcAsSat),
634-
}
635-
}
636-
return totalAmounts, nil
637-
}
638-
639552
// OnAccountInit installs a callback to be called when an account is initialized.
640553
func (backend *Backend) OnAccountInit(f func(accounts.Interface)) {
641554
backend.onAccountInit = f

backend/chart.go

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -148,42 +148,24 @@ func (backend *Backend) ChartData() (*Chart, error) {
148148
if err != nil {
149149
return nil, err
150150
}
151-
balance, err := account.Balance()
152-
if err != nil {
153-
return nil, err
154-
}
155151
txs, err := account.Transactions()
156152
if err != nil {
157153
return nil, err
158154
}
159155
totalNumberOfTransactions += len(txs)
160156

161-
// e.g. 1e8 for Bitcoin/Litecoin, 1e18 for Ethereum, etc. Used to convert from the smallest
162-
// unit to the standard unit (BTC, LTC; ETH, etc.).
163-
coinDecimals := new(big.Int).Exp(
164-
big.NewInt(10),
165-
big.NewInt(int64(account.Coin().Decimals(false))),
166-
nil,
167-
)
157+
coinDecimals := coin.DecimalsExp(account.Coin())
168158

169159
// HACK: The latest prices might deviate from the latest historical prices (which can lag
170160
// behind by many minutes), which results in different total balances in the chart and the
171161
// summary table.
172162
//
173-
// As a workaround, we manually compute the total based on the latest rates.
174-
price, err := backend.RatesUpdater().LatestPriceForPair(account.Coin().Unit(false), fiat)
163+
// As a workaround, we calls accountFiatBalance, which computes the total based on the latest rates.
164+
fiatValue, err := backend.accountFiatBalance(account, fiat)
175165
if err != nil {
176166
currentTotalMissing = true
177-
backend.log.
178-
WithField("coin", account.Coin().Code()).WithError(err).Info("currentTotalMissing")
167+
return nil, err
179168
}
180-
fiatValue := new(big.Rat).Mul(
181-
new(big.Rat).SetFrac(
182-
balance.Available().BigInt(),
183-
coinDecimals,
184-
),
185-
new(big.Rat).SetFloat64(price),
186-
)
187169
currentTotal.Add(currentTotal, fiatValue)
188170

189171
// Below here, only chart data is being computed.

backend/coins/coin/coin.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,13 @@ type Coin interface {
8282
// Close shuts down all resources obtained by the coin (network connections, databases, etc.).
8383
Close() error
8484
}
85+
86+
// DecimalsExp returns the conversion exponential from the smallest unit to the standard unit
87+
// (BTC, LTC; ETH, etc.). e.g. 1e8 for Bitcoin/Litecoin, 1e18 for Ethereum, etc.
88+
func DecimalsExp(coin Coin) *big.Int {
89+
return new(big.Int).Exp(
90+
big.NewInt(10),
91+
big.NewInt(int64(coin.Decimals(false))),
92+
nil,
93+
)
94+
}

backend/handlers/handlers.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package handlers
1818
import (
1919
"bytes"
2020
"encoding/base64"
21-
"encoding/hex"
2221
"encoding/json"
2322
"fmt"
2423
"io"
@@ -696,8 +695,7 @@ func (handlers *Handlers) getAccountsBalance(*http.Request) (interface{}, error)
696695
if err != nil {
697696
return nil, err
698697
}
699-
for keystore, accountList := range accountsByKeystore {
700-
rootFingerprint := hex.EncodeToString(keystore.RootFingerprint)
698+
for rootFingerprint, accountList := range accountsByKeystore {
701699
totalPerCoin := make(map[coin.Code]*big.Int)
702700
conversionsPerCoin := make(map[coin.Code]map[string]string)
703701
for _, account := range accountList {

0 commit comments

Comments
 (0)