Skip to content

Commit b383d28

Browse files
committed
backend/backend: refactor backend accounts keystores
1 parent 192e22d commit b383d28

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"
@@ -544,97 +540,14 @@ func (backend *Backend) Accounts() AccountsList {
544540
return backend.accounts
545541
}
546542

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

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