Skip to content

Commit 38411ca

Browse files
committed
frontend/settings: add Satoshi as currency
This commit adds Satoshi as an option in active currencies. It now functions independently of the enabled sats mode, allowing users to have either or both currencies (btc, sat) enabled.
1 parent 40f494b commit 38411ca

File tree

15 files changed

+55
-64
lines changed

15 files changed

+55
-64
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Use mempool.space as preferred fee estimation source for BTC
1212
- Fix Wallet Connect issue where account unspecified by the connecting dapp caused a UI crash
1313
- Fix Wallet Connect issue with required/optionalNamespace and handling all possible namespace definitions
14+
- Add Satoshi as an option in active currencies
1415

1516
## 4.42.0
1617
- Preselect backup when there's only one backup available

backend/accounts.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,11 @@ import (
2828
accountsTypes "github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts/types"
2929
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/bitsurance"
3030
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc"
31-
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/util"
3231
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/coin"
3332
coinpkg "github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/coin"
3433
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/eth"
3534
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/config"
3635
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/keystore"
37-
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/rates"
3836
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/signing"
3937
"github.com/BitBoxSwiss/bitbox-wallet-app/util/errp"
4038
"github.com/BitBoxSwiss/bitbox-wallet-app/util/observable"
@@ -234,7 +232,6 @@ func (backend *Backend) accountFiatBalance(account accounts.Interface, fiat stri
234232
}
235233

236234
coinDecimals := coin.DecimalsExp(account.Coin())
237-
238235
price, err := backend.RatesUpdater().LatestPriceForPair(account.Coin().Unit(false), fiat)
239236
if err != nil {
240237
return nil, err
@@ -253,13 +250,6 @@ func (backend *Backend) accountFiatBalance(account accounts.Interface, fiat stri
253250
func (backend *Backend) AccountsTotalBalanceByKeystore() (map[string]KeystoreTotalAmount, error) {
254251
totalAmounts := make(map[string]KeystoreTotalAmount)
255252
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)
263253

264254
accountsByKeystore, err := backend.AccountsByKeystore()
265255
if err != nil {
@@ -286,8 +276,8 @@ func (backend *Backend) AccountsTotalBalanceByKeystore() (map[string]KeystoreTot
286276
currentTotal.Add(currentTotal, fiatValue)
287277
}
288278
totalAmounts[rootFingerprint] = KeystoreTotalAmount{
289-
FiatUnit: fiatUnit,
290-
Total: coinpkg.FormatAsCurrency(currentTotal, isFiatBtc, formatBtcAsSat),
279+
FiatUnit: fiat,
280+
Total: coinpkg.FormatAsCurrency(currentTotal, fiat),
291281
}
292282
}
293283
return totalAmounts, nil

backend/bitsurance/bitsurance.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts"
2424
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts/types"
2525
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/coin"
26+
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/rates"
2627
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/signing"
2728
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/util"
2829
"github.com/BitBoxSwiss/bitbox-wallet-app/util/errp"
@@ -86,7 +87,7 @@ func bitsuranceCheckId(devServer bool, httpClient *http.Client, accountId string
8687
return account, err
8788
}
8889
ratAmount := new(big.Rat).SetInt64(int64(account.Details.MaxCoverage))
89-
account.Details.MaxCoverageFormatted = coin.FormatAsCurrency(ratAmount, false, false)
90+
account.Details.MaxCoverageFormatted = coin.FormatAsCurrency(ratAmount, rates.EUR.String())
9091
return account, nil
9192
}
9293

backend/chart.go

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ import (
2121

2222
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts"
2323
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/accounts/errors"
24-
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/util"
2524
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/coin"
26-
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/rates"
2725
"github.com/BitBoxSwiss/bitbox-wallet-app/util/errp"
2826
)
2927

@@ -120,7 +118,6 @@ func (backend *Backend) ChartData() (*Chart, error) {
120118
chartEntriesHourly := map[int64]RatChartEntry{}
121119

122120
fiat := backend.Config().AppConfig().Backend.MainFiat
123-
isFiatBtc := fiat == rates.BTC.String()
124121

125122
// Chart data until this point in time.
126123
until := backend.RatesUpdater().HistoryLatestTimestampAll(backend.allCoinCodes(), fiat)
@@ -131,8 +128,6 @@ func (backend *Backend) ChartData() (*Chart, error) {
131128
isUpToDate := time.Since(until) < 2*time.Hour
132129
lastTimestamp := until.UnixMilli()
133130

134-
formatBtcAsSat := util.FormatBtcAsSat(backend.Config().AppConfig().Backend.BtcUnit)
135-
136131
currentTotal := new(big.Rat)
137132
currentTotalMissing := false
138133
// Total number of transactions across all active accounts.
@@ -245,7 +240,7 @@ func (backend *Backend) ChartData() (*Chart, error) {
245240
result[i] = ChartEntry{
246241
Time: entry.Time,
247242
Value: floatValue,
248-
FormattedValue: coin.FormatAsCurrency(entry.RatValue, fiat == rates.BTC.String(), formatBtcAsSat),
243+
FormattedValue: coin.FormatAsCurrency(entry.RatValue, fiat),
249244
}
250245
i++
251246
}
@@ -261,7 +256,7 @@ func (backend *Backend) ChartData() (*Chart, error) {
261256
result = append(result, ChartEntry{
262257
Time: time.Now().Unix(),
263258
Value: total,
264-
FormattedValue: coin.FormatAsCurrency(currentTotal, isFiatBtc, formatBtcAsSat),
259+
FormattedValue: coin.FormatAsCurrency(currentTotal, fiat),
265260
})
266261
}
267262
// Truncate leading zeroes, if there are any keep the first one to start the chart with 0
@@ -285,23 +280,18 @@ func (backend *Backend) ChartData() (*Chart, error) {
285280
chartDataMissing = false
286281
}
287282

288-
chartFiat := fiat
289-
if isFiatBtc && backend.Config().AppConfig().Backend.BtcUnit == coin.BtcUnitSats {
290-
chartFiat = "sat"
291-
}
292-
293283
var chartTotal *float64
294284
var formattedChartTotal string
295285
if !currentTotalMissing {
296286
tot, _ := currentTotal.Float64()
297287
chartTotal = &tot
298-
formattedChartTotal = coin.FormatAsCurrency(currentTotal, isFiatBtc, formatBtcAsSat)
288+
formattedChartTotal = coin.FormatAsCurrency(currentTotal, fiat)
299289
}
300290
return &Chart{
301291
DataMissing: chartDataMissing,
302292
DataDaily: toSortedSlice(chartEntriesDaily, fiat),
303293
DataHourly: toSortedSlice(chartEntriesHourly, fiat),
304-
Fiat: chartFiat,
294+
Fiat: fiat,
305295
Total: chartTotal,
306296
FormattedTotal: formattedChartTotal,
307297
IsUpToDate: isUpToDate,

backend/coins/coin/conversions.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,22 @@ func Btc2Sat(amount *big.Rat) *big.Rat {
2323

2424
// FormatAsPlainCurrency handles formatting for currencies in a simplified way.
2525
// This should be used when `FormatAsCurrency` can't be used because a simpler formatting is needed (e.g. to populate forms in the frontend).
26-
func FormatAsPlainCurrency(amount *big.Rat, isBtc bool, formatBtcAsSats bool) string {
26+
func FormatAsPlainCurrency(amount *big.Rat, currency string) string {
2727
var formatted string
28-
if isBtc {
29-
if formatBtcAsSats {
30-
amount = Btc2Sat(amount)
31-
formatted = amount.FloatString(0)
32-
} else {
33-
formatted = amount.FloatString(8)
34-
}
35-
} else {
28+
switch currency {
29+
case ratesPkg.BTC.String():
30+
formatted = amount.FloatString(8)
31+
case ratesPkg.SAT.String():
32+
formatted = amount.FloatString(0)
33+
default:
3634
formatted = amount.FloatString(2)
3735
}
3836
return formatted
3937
}
4038

4139
// FormatAsCurrency handles formatting for currencies.
42-
func FormatAsCurrency(amount *big.Rat, isBtc bool, formatBtcAsSats bool) string {
43-
formatted := FormatAsPlainCurrency(amount, isBtc, formatBtcAsSats)
40+
func FormatAsCurrency(amount *big.Rat, currency string) string {
41+
formatted := FormatAsPlainCurrency(amount, currency)
4442
position := strings.Index(formatted, ".") - 3
4543
for position > 0 {
4644
formatted = formatted[:position] + "'" + formatted[position:]
@@ -59,7 +57,7 @@ func Conversions(amount Amount, coin Coin, isFee bool, ratesUpdater *ratesPkg.Ra
5957
conversions = map[string]string{}
6058
for key, value := range rates[unit] {
6159
convertedAmount := new(big.Rat).Mul(new(big.Rat).SetFloat64(coin.ToUnit(amount, isFee)), new(big.Rat).SetFloat64(value))
62-
conversions[key] = FormatAsCurrency(convertedAmount, key == ratesPkg.BTC.String(), formatBtcAsSats)
60+
conversions[key] = FormatAsCurrency(convertedAmount, key)
6361
}
6462
}
6563
return conversions
@@ -77,7 +75,7 @@ func ConversionsAtTime(amount Amount, coin Coin, isFee bool, ratesUpdater *rates
7775
conversions[currency] = ""
7876
} else {
7977
convertedAmount := new(big.Rat).Mul(new(big.Rat).SetFloat64(coin.ToUnit(amount, isFee)), new(big.Rat).SetFloat64(value))
80-
conversions[currency] = FormatAsCurrency(convertedAmount, currency == ratesPkg.BTC.String(), formatBtcAsSats)
78+
conversions[currency] = FormatAsCurrency(convertedAmount, currency)
8179
}
8280
}
8381
}

backend/handlers/handlers.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,6 @@ func (handlers *Handlers) getConvertToPlainFiat(r *http.Request) interface{} {
955955
coinCode := r.URL.Query().Get("from")
956956
currency := r.URL.Query().Get("to")
957957
amount := r.URL.Query().Get("amount")
958-
959958
currentCoin, err := handlers.backend.Coin(coinpkg.Code(coinCode))
960959
if err != nil {
961960
handlers.log.WithError(err).Error("Could not get coin " + coinCode)
@@ -979,10 +978,9 @@ func (handlers *Handlers) getConvertToPlainFiat(r *http.Request) interface{} {
979978

980979
convertedAmount := new(big.Rat).Mul(coinUnitAmount, new(big.Rat).SetFloat64(rate))
981980

982-
btcUnit := handlers.backend.Config().AppConfig().Backend.BtcUnit
983981
return map[string]interface{}{
984982
"success": true,
985-
"fiatAmount": coinpkg.FormatAsPlainCurrency(convertedAmount, currency == rates.BTC.String(), util.FormatBtcAsSat(btcUnit)),
983+
"fiatAmount": coinpkg.FormatAsPlainCurrency(convertedAmount, currency),
986984
}
987985
}
988986

@@ -1017,10 +1015,6 @@ func (handlers *Handlers) getConvertFromFiat(r *http.Request) interface{} {
10171015
unit = unit[3:]
10181016
}
10191017

1020-
if from == rates.BTC.String() && handlers.backend.Config().AppConfig().Backend.BtcUnit == coinpkg.BtcUnitSats {
1021-
fiatRat = coinpkg.Sat2Btc(fiatRat)
1022-
}
1023-
10241018
rate := handlers.backend.RatesUpdater().LatestPrice()[unit][from]
10251019
result := coin.NewAmountFromInt64(0)
10261020
if rate != 0.0 {

backend/rates/gecko.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ var (
100100
"SEK": "sek",
101101
"PLN": "pln",
102102
"CZK": "czk",
103+
// Satoshi rates are converted manually in the backend using Bitcoin.
104+
"sat": "btc",
103105
}
104106

105107
// Copied from https://api.coingecko.com/api/v3/simple/supported_vs_currencies.

backend/rates/history.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,12 @@ func (updater *RateUpdater) fetchGeckoMarketRange(ctx context.Context, coin, fia
290290
// Transform the response into a usable result.
291291
rates := make([]exchangeRate, len(jsonBody.Prices))
292292
for i, v := range jsonBody.Prices {
293+
value := v[1]
294+
if fiat == SAT.String() {
295+
value *= unitSatoshi
296+
}
293297
rates[i] = exchangeRate{
294-
value: v[1],
298+
value: value,
295299
timestamp: time.Unix(int64(v[0])/1000, 0), // local timezone
296300
}
297301
}

backend/rates/rates.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ const (
4949

5050
const interval = time.Minute
5151

52+
// unitSatoshi is 1 BTC (default unit) in Satoshi.
53+
const unitSatoshi = 1e8
54+
5255
type exchangeRate struct {
5356
value float64
5457
timestamp time.Time
@@ -83,6 +86,7 @@ const (
8386
SGD Fiat = "SGD"
8487
USD Fiat = "USD"
8588
BTC Fiat = "BTC"
89+
SAT Fiat = "sat"
8690
)
8791

8892
// RateUpdater provides cryptocurrency-to-fiat conversion rates.
@@ -316,11 +320,21 @@ func (updater *RateUpdater) updateLast(ctx context.Context) {
316320
updater.log.Errorf("unsupported fiat: %s", geckoFiat)
317321
continue
318322
}
323+
if fiat == BTC.String() {
324+
newVal[SAT.String()] = rates * unitSatoshi
325+
}
319326
newVal[fiat] = rates
320327
}
321328
rates[coinUnit] = newVal
322329
}
323330

331+
// Create sat rates from BTC
332+
sat := make(map[string]float64)
333+
for currency, rate := range rates[BTC.String()] {
334+
sat[currency] = rate / unitSatoshi
335+
}
336+
rates[SAT.String()] = sat
337+
324338
// Provide conversion rates for testnets as well, useful for testing.
325339
for _, testnetUnit := range []string{"TBTC", "RBTC", "TLTC", "GOETH", "SEPETH"} {
326340
switch testnetUnit {

frontends/web/src/api/account.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export type CoinCode = 'btc' | 'tbtc' | 'ltc' | 'tltc' | 'eth' | 'goeth' | 'sepe
2323

2424
export type AccountCode = string;
2525

26-
export type Fiat = 'AUD' | 'BRL' | 'BTC' | 'CAD' | 'CHF' | 'CNY' | 'CZK' | 'EUR' | 'GBP' | 'HKD' | 'ILS' | 'JPY' | 'KRW' | 'NOK' | 'PLN' | 'RUB' | 'SEK' | 'SGD' | 'USD';
26+
export type Fiat = 'AUD' | 'BRL' | 'BTC' | 'CAD' | 'CHF' | 'CNY' | 'CZK' | 'EUR' | 'GBP' | 'HKD' | 'ILS' | 'JPY' | 'KRW' | 'NOK' | 'PLN' | 'RUB' | 'sat' | 'SEK' | 'SGD' | 'USD';
2727

2828
export type ConversionUnit = Fiat | 'sat'
2929

0 commit comments

Comments
 (0)