From 25c8b633df49ef1f248eb2c402af284f02f5220c Mon Sep 17 00:00:00 2001 From: thisconnect Date: Wed, 2 Oct 2024 11:41:16 +0200 Subject: [PATCH 01/92] frontend: fix layout on mobile for spinner with error message Some error messages are only partly centered and have no padding to the edge of the container. Reason: Spinner is used in account and other components to show loading but also unknown error messages. Each line of the message is rendered in its own paragraph element. Those paragraphs are centered by the parent element using flexbox. As soon as a paragraph contains text that spawns over multiple lines it will cause the paragraph to use the full available width with left aligned text. --- frontends/web/src/components/spinner/Spinner.module.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontends/web/src/components/spinner/Spinner.module.css b/frontends/web/src/components/spinner/Spinner.module.css index b42aab9fd9..3fe9df69fb 100644 --- a/frontends/web/src/components/spinner/Spinner.module.css +++ b/frontends/web/src/components/spinner/Spinner.module.css @@ -23,7 +23,8 @@ .spinnerText { margin: 0; - /* font-weight: bold; */ + padding: 0 var(--spacing-default); + text-align: center; } .spinner div { From ecda50c1bf3e6b21ba17b8e678706569e4b58194 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Thu, 3 Oct 2024 16:10:52 +0200 Subject: [PATCH 02/92] CHANGELOG: add v4.44.1 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb2fcbf15f..318c7191f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ - Bitcoin: add support for sending to silent payment (BIP-352) addresses - Prevent macOS from going to sleep on long running interactions with the BitBox +## 4.44.1 +- Minor UI bugfixes + ## 4.44.0 - Bundle BitBox02 firmware version v9.20.0 - Add support for selling bitcoin in-app via Pocket From f564cfa94f0979fd3efff2b638ce1e933f4e63f0 Mon Sep 17 00:00:00 2001 From: NicolaLS Date: Wed, 5 Jun 2024 13:47:38 -0600 Subject: [PATCH 03/92] frontend: transform aopp.tsx to func. component --- .../web/src/components/aopp/aopp.module.css | 5 - frontends/web/src/components/aopp/aopp.tsx | 395 ++++++++---------- 2 files changed, 182 insertions(+), 218 deletions(-) diff --git a/frontends/web/src/components/aopp/aopp.module.css b/frontends/web/src/components/aopp/aopp.module.css index 8d2dadbf60..e9e8a89472 100644 --- a/frontends/web/src/components/aopp/aopp.module.css +++ b/frontends/web/src/components/aopp/aopp.module.css @@ -7,11 +7,6 @@ text-align: center; } -.smallIcon { - margin: auto 0; - width: 30px; -} - .successText { color: var(--color-secondary); font-weight: 400; diff --git a/frontends/web/src/components/aopp/aopp.tsx b/frontends/web/src/components/aopp/aopp.tsx index 41fa02be15..562fac387a 100644 --- a/frontends/web/src/components/aopp/aopp.tsx +++ b/frontends/web/src/components/aopp/aopp.tsx @@ -1,5 +1,5 @@ /** - * Copyright 2021 Shift Crypto AG + * Copyright 2021-2024 Shift Crypto AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,20 @@ * limitations under the License. */ -import React, { Component, ReactNode } from 'react'; +import React, { ReactNode, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import * as accountAPI from '@/api/account'; import * as aoppAPI from '@/api/aopp'; -import { translate, TranslateProps } from '@/decorators/translate'; import { equal } from '@/utils/equal'; import { SimpleMarkup } from '@/utils/markup'; import { View, ViewHeader, ViewContent, ViewButtons } from '@/components/view/view'; import { Message } from '@/components/message/message'; import { Button, Field, Label, Select } from '@/components/forms'; import { CopyableInput } from '@/components/copy/Copy'; -import { Cancel, PointToBitBox02 } from '@/components/icon'; +import { PointToBitBox02 } from '@/components/icon'; import { VerifyAddress } from './verifyaddress'; import { Vasp } from './vasp'; import styles from './aopp.module.css'; -import { TUnsubscribe } from '@/utils/transport-common'; type TProps = { children: ReactNode; @@ -38,164 +37,111 @@ const Banner = ({ children }: TProps) => (
{children}
); -type State = { - accountCode: accountAPI.AccountCode; - aopp?: aoppAPI.Aopp; -} - -type Props = TranslateProps; - const domain = (callback: string): string => new URL(callback).host; -class Aopp extends Component { - public readonly state: State = { - accountCode: '', - aopp: undefined, - }; - private unsubscribe?: TUnsubscribe; +export const Aopp = () => { + const { t } = useTranslation(); - public componentDidMount() { - this.setAccountCodeDefault(); - this.unsubscribe = aoppAPI.subscribeAOPP(aopp => this.updateAOPP(aopp)); - aoppAPI.getAOPP().then(aopp => this.setState({ aopp })); - } + const [accountCode, setAccountCode] = useState(''); + const [aopp, setAopp] = useState(); - public componentWillUnmount() { - if (this.unsubscribe) { - this.unsubscribe(); - } - } - private updateAOPP(aopp: aoppAPI.Aopp) { - let shouldUpdateAccountCodeDefault = false; - this.setState(currentState => { - if (aopp?.state === 'choosing-account' - && ( - currentState.aopp?.state !== 'choosing-account' - || !equal(aopp.accounts, currentState.aopp?.accounts) - ) - ) { - shouldUpdateAccountCodeDefault = true; - } - return { aopp }; - }, () => { // callback when state did update - if (shouldUpdateAccountCodeDefault) { - this.setAccountCodeDefault(); - } - }); - } - - private setAccountCodeDefault() { - const { aopp } = this.state; + const setAccountCodeDefault = (aopp: aoppAPI.Aopp | undefined) => { if (aopp === undefined || aopp.state !== 'choosing-account') { return; } if (aopp.accounts.length) { - this.setState({ accountCode: aopp.accounts[0].code }); + setAccountCode(aopp.accounts[0].code); } - } + }; + + useEffect(() => { + setAccountCodeDefault(aopp); + const unsubscribe = aoppAPI.subscribeAOPP((new_aopp: aoppAPI.Aopp) => { + if (new_aopp?.state === 'choosing-account' + && ( + aopp?.state !== 'choosing-account' + || !equal(new_aopp.accounts, aopp?.accounts) + )) { + setAccountCodeDefault(new_aopp); + } + setAopp(new_aopp); + }); + aoppAPI.getAOPP().then(aopp => setAopp(aopp)); + return unsubscribe; + }, [aopp]); - private chooseAccount = (e: React.SyntheticEvent) => { - if (this.state.accountCode) { - aoppAPI.chooseAccount(this.state.accountCode); + const chooseAccount = (e: React.SyntheticEvent) => { + if (accountCode) { + aoppAPI.chooseAccount(accountCode); } e.preventDefault(); }; - public render() { - const { t } = this.props; - const { accountCode, aopp } = this.state; - if (!aopp) { - return null; - } - switch (aopp.state) { - case 'error': - return ( - - -

{domain(aopp.callback)}

-
- - - - {t(`error.${aopp.errorCode}`, { host: domain(aopp.callback) })} - - - - - -
- ); - case 'inactive': - // Inactive, waiting for action. - return null; - case 'user-approval': - return ( - - - - ${domain(aopp.callback)}` - })}/> - )} - withLogoText={t('aopp.addressRequestWithLogo')} /> - - - - - - - ); - case 'awaiting-keystore': - return ( - {t('aopp.banner')} - ); - case 'choosing-account': { - const options = aopp.accounts.map(account => { - return { - text: account.name, - value: account.code, - }; - }); - return ( -
- - - - - - setAccountCode((e.target as HTMLSelectElement)?.value)} + id="account" /> + - ); - case 'signing': - return ( - - - - - -

{t('aopp.signing')}

- - - - - - -
- {aopp.message} -
-
- -
-
- ); - case 'success': - return ( - - -

{t('aopp.success.title')}

-

- {t('aopp.success.message', { host: domain(aopp.callback) })} -

- - - - - - -
- {aopp.message} -
-
-
- - - - -
- ); - } +
+ ); } -} + case 'syncing': + return ( + + + + + +

{t('aopp.syncing')}

+
+ + + +
+ ); + case 'signing': + return ( + + + + + +

{t('aopp.signing')}

+ + + + + + +
+ {aopp.message} +
+
+ +
+
+ ); + case 'success': + return ( + + +

{t('aopp.success.title')}

+

+ {t('aopp.success.message', { host: domain(aopp.callback) })} +

+ + + + + + +
+ {aopp.message} +
+
+
+ + + + +
+ ); + } +}; -const translateHOC = translate()(Aopp); -export { translateHOC as Aopp }; From d1992b7531b8c1a78e090c8b020a81c1840ea516 Mon Sep 17 00:00:00 2001 From: thisconnect Date: Mon, 2 Sep 2024 16:25:10 +0200 Subject: [PATCH 04/92] frontend: simplify transaction type --- frontends/web/src/api/account.ts | 7 +++++-- .../web/src/components/transactions/components/arrow.tsx | 7 +++++-- .../web/src/components/transactions/components/details.tsx | 6 +++--- .../web/src/components/transactions/components/status.tsx | 4 ++-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/frontends/web/src/api/account.ts b/frontends/web/src/api/account.ts index 744b9bed9a..5a8827e91f 100644 --- a/frontends/web/src/api/account.ts +++ b/frontends/web/src/api/account.ts @@ -236,6 +236,9 @@ export const getBalance = (code: AccountCode): Promise => { return apiGet(`account/${code}/balance`); }; +export type TTransactionStatus = 'complete' | 'pending' | 'failed'; +export type TTransactionType = 'send' | 'receive' | 'self'; + export interface ITransaction { addresses: string[]; amount: IAmount; @@ -249,9 +252,9 @@ export interface ITransaction { numConfirmations: number; numConfirmationsComplete: number; size: number; - status: 'complete' | 'pending' | 'failed'; + status: TTransactionStatus; time: string | null; - type: 'send' | 'receive' | 'self'; + type: TTransactionType; txID: string; vsize: number; weight: number; diff --git a/frontends/web/src/components/transactions/components/arrow.tsx b/frontends/web/src/components/transactions/components/arrow.tsx index 008c97db2d..0732909ba6 100644 --- a/frontends/web/src/components/transactions/components/arrow.tsx +++ b/frontends/web/src/components/transactions/components/arrow.tsx @@ -14,11 +14,14 @@ * limitations under the License. */ -import type { ITransaction } from '@/api/account'; +import type { TTransactionStatus, TTransactionType } from '@/api/account'; import { Warning } from '@/components/icon/icon'; import { ArrowIn, ArrowOut, ArrowSelf } from './icons'; -type TProps = Pick; +type TProps = { + status: TTransactionStatus; + type: TTransactionType; +}; export const Arrow = ({ status, type }: TProps) => { if (status === 'failed') { diff --git a/frontends/web/src/components/transactions/components/details.tsx b/frontends/web/src/components/transactions/components/details.tsx index 95620787ad..c480862fa4 100644 --- a/frontends/web/src/components/transactions/components/details.tsx +++ b/frontends/web/src/components/transactions/components/details.tsx @@ -16,7 +16,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { ITransaction, IAmount, getTransaction } from '@/api/account'; +import { ITransaction, IAmount, getTransaction, TTransactionStatus, TTransactionType } from '@/api/account'; import { A } from '@/components/anchor/anchor'; import { Dialog } from '@/components/dialog/dialog'; import { FiatConversion } from '@/components/rates/rates'; @@ -35,8 +35,8 @@ type TProps = { accountCode: string; internalID: string; note: string; - status: ITransaction['status']; - type: ITransaction['type']; + status: TTransactionStatus; + type: TTransactionType; numConfirmations: number; numConfirmationsComplete: number; time: string | null; diff --git a/frontends/web/src/components/transactions/components/status.tsx b/frontends/web/src/components/transactions/components/status.tsx index b0a3685ef1..33f3732a0a 100644 --- a/frontends/web/src/components/transactions/components/status.tsx +++ b/frontends/web/src/components/transactions/components/status.tsx @@ -15,14 +15,14 @@ */ import { useTranslation } from 'react-i18next'; -import type { ITransaction } from '@/api/account'; +import type { TTransactionStatus } from '@/api/account'; import { ProgressRing } from '@/components/progressRing/progressRing'; import { TxDetail } from './detail'; import transactionStyle from '@/components/transactions/transactions.module.css'; import parentStyle from '@/components/transactions/transaction.module.css'; type TProps = { - status: ITransaction['status']; + status: TTransactionStatus; numConfirmations: number; numConfirmationsComplete: number; } From b4d6649b128394695b892adeb82f072e16deb2a3 Mon Sep 17 00:00:00 2001 From: thisconnect Date: Wed, 18 Sep 2024 09:20:01 +0200 Subject: [PATCH 05/92] frontend: correct send_to_self type The transactions/transaction endpoint actually return "send", "receive" and "send_to_self" but the ITransaction type was "self" this was unnoticed because the type was never directly checked. But it should be the correct type, also in preparation for the frontend collaborative type implementation. --- frontends/web/src/api/account.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/web/src/api/account.ts b/frontends/web/src/api/account.ts index 5a8827e91f..f9034901a3 100644 --- a/frontends/web/src/api/account.ts +++ b/frontends/web/src/api/account.ts @@ -237,7 +237,7 @@ export const getBalance = (code: AccountCode): Promise => { }; export type TTransactionStatus = 'complete' | 'pending' | 'failed'; -export type TTransactionType = 'send' | 'receive' | 'self'; +export type TTransactionType = 'send' | 'receive' | 'send_to_self'; export interface ITransaction { addresses: string[]; From b61a18ae70265f82f09ad1391541a346013ef411 Mon Sep 17 00:00:00 2001 From: thisconnect Date: Wed, 18 Sep 2024 09:20:46 +0200 Subject: [PATCH 06/92] frontend: fix minor typescript formatting --- frontends/web/src/api/account.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontends/web/src/api/account.ts b/frontends/web/src/api/account.ts index f9034901a3..a20c5c148e 100644 --- a/frontends/web/src/api/account.ts +++ b/frontends/web/src/api/account.ts @@ -377,8 +377,8 @@ export interface IFeeTarget { } export interface IFeeTargetList { - feeTargets: IFeeTarget[], - defaultFeeTarget: FeeTargetCode + feeTargets: IFeeTarget[]; + defaultFeeTarget: FeeTargetCode; } export const getFeeTargetList = (code: AccountCode): Promise => { @@ -446,7 +446,7 @@ export const connectKeystore = (code: AccountCode): Promise<{ success: boolean; export type TSignMessage = { success: false, aborted?: boolean; errorMessage?: string; } | { success: true; signature: string; } export type TSignWalletConnectTx = { - success: false, + success: false; aborted?: boolean; errorMessage?: string; } | { From 6dd91963ac4be083809e66c3ba68da65d4390642 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Wed, 9 Oct 2024 09:45:26 +0200 Subject: [PATCH 07/92] frontend: make locize-pull --- frontends/web/src/locales/es/app.json | 2 +- frontends/web/src/locales/it/app.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontends/web/src/locales/es/app.json b/frontends/web/src/locales/es/app.json index 0dd9b1b0de..21929cc285 100644 --- a/frontends/web/src/locales/es/app.json +++ b/frontends/web/src/locales/es/app.json @@ -738,7 +738,7 @@ }, "generic": { "buy": "Comprar {{coinCode}} ", - "buySell": "Compra y venta", + "buySell": "Comprar y vender", "buy_bitcoin": "Comprar Bitcoin ", "buy_crypto": "Comprar criptomonedas", "enabled_false": "Desactivado", diff --git a/frontends/web/src/locales/it/app.json b/frontends/web/src/locales/it/app.json index 4f23751d01..a9635d9871 100644 --- a/frontends/web/src/locales/it/app.json +++ b/frontends/web/src/locales/it/app.json @@ -577,7 +577,7 @@ "description": "La root fingerprint è un identificatore univoco del wallet attualmente in uso. Ti può aiutare a distinguere wallet diversi se usi la passphrase." }, "securechip": { - "description": "Modello del secur chip." + "description": "Modello del secure chip." }, "title": "Informazioni sul dispositivo" }, From b52d3aca2be4a08f6d414e63ecafda1601d3061d Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Mon, 30 Sep 2024 11:26:58 +0200 Subject: [PATCH 08/92] backend: add ManualReconnect method and call on iOS When the iOS app goes into the background, its TCP connections (Electrum server connetions) are killed after a while (~30s). When the user goes back into the app, we want to immediatelly trigger a reconnect, not waiting for the regular 30s reconnect timer. ``` go get github.com/BitBoxSwiss/block-client-go@924dde9 go mod tidy go mod vendor ``` --- backend/backend.go | 37 +++++++++ backend/bridgecommon/bridgecommon.go | 12 +++ backend/coins/btc/blockchain/blockchain.go | 1 + .../coins/btc/blockchain/mocks/Interface.go | 81 ++++++++++++++++--- backend/coins/btc/blockchain/mocks/mock.go | 8 ++ backend/coins/btc/electrum/failoverclient.go | 4 + backend/mobileserver/mobileserver.go | 7 +- .../BitBoxApp/BitBoxApp/BitBoxAppApp.swift | 12 +-- go.mod | 2 +- go.sum | 4 +- .../block-client-go/failover/failover.go | 25 +++++- vendor/modules.txt | 2 +- 12 files changed, 171 insertions(+), 24 deletions(-) diff --git a/backend/backend.go b/backend/backend.go index 36fc3ad82a..4e1ce4293b 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -538,6 +538,43 @@ func (backend *Backend) Coin(code coinpkg.Code) (coinpkg.Coin, error) { return coin, nil } +// ManualReconnect triggers reconnecting to Electrum servers if their connection is down. +// Only coin connections that were previously established are reconnected. +// Calling this is a no-op for coins that are already connected. +func (backend *Backend) ManualReconnect() { + var electrumCoinCodes []coinpkg.Code + if backend.arguments.Testing() { + electrumCoinCodes = []coinpkg.Code{ + coinpkg.CodeTBTC, + coinpkg.CodeTLTC, + } + } else { + electrumCoinCodes = []coinpkg.Code{ + coinpkg.CodeBTC, + coinpkg.CodeLTC, + } + } + backend.log.Info("Manually reconnecting") + for _, code := range electrumCoinCodes { + c, err := backend.Coin(code) + if err != nil { + backend.log.WithError(err).Errorf("could not find coin: %s", code) + continue + } + btcCoin, ok := c.(*btc.Coin) + if !ok { + backend.log.Errorf("Expected %s to be a btc coin", code) + continue + } + blockchain := btcCoin.Blockchain() + if blockchain == nil { + // Not initialized yet + continue + } + blockchain.ManualReconnect() + } +} + // Testing returns whether this backend is for testing only. func (backend *Backend) Testing() bool { return backend.arguments.Testing() diff --git a/backend/bridgecommon/bridgecommon.go b/backend/bridgecommon/bridgecommon.go index 86d71dc6ef..7d4e306724 100644 --- a/backend/bridgecommon/bridgecommon.go +++ b/backend/bridgecommon/bridgecommon.go @@ -166,6 +166,18 @@ func UsingMobileDataChanged() { }) } +// ManualReconnect exposes the ManualReconnect backend method. +func ManualReconnect() { + mu.RLock() + defer mu.RUnlock() + + if globalBackend == nil { + return + } + globalBackend.ManualReconnect() + +} + // BackendEnvironment implements backend.Environment. type BackendEnvironment struct { NotifyUserFunc func(string) diff --git a/backend/coins/btc/blockchain/blockchain.go b/backend/coins/btc/blockchain/blockchain.go index 249ed2d6e0..eb74ae0085 100644 --- a/backend/coins/btc/blockchain/blockchain.go +++ b/backend/coins/btc/blockchain/blockchain.go @@ -118,4 +118,5 @@ type Interface interface { Close() ConnectionError() error RegisterOnConnectionErrorChangedEvent(func(error)) + ManualReconnect() } diff --git a/backend/coins/btc/blockchain/mocks/Interface.go b/backend/coins/btc/blockchain/mocks/Interface.go index 112d23293b..e0b0dd11bd 100644 --- a/backend/coins/btc/blockchain/mocks/Interface.go +++ b/backend/coins/btc/blockchain/mocks/Interface.go @@ -1,17 +1,15 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.40.1. DO NOT EDIT. package mocks import ( - btcutil "github.com/btcsuite/btcd/btcutil" blockchain "github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/blockchain" + btcutil "github.com/btcsuite/btcd/btcutil" chainhash "github.com/btcsuite/btcd/chaincfg/chainhash" mock "github.com/stretchr/testify/mock" - testing "testing" - types "github.com/BitBoxSwiss/block-client-go/electrum/types" wire "github.com/btcsuite/btcd/wire" @@ -31,6 +29,10 @@ func (_m *Interface) Close() { func (_m *Interface) ConnectionError() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConnectionError") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -45,14 +47,21 @@ func (_m *Interface) ConnectionError() error { func (_m *Interface) EstimateFee(_a0 int) (btcutil.Amount, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for EstimateFee") + } + var r0 btcutil.Amount + var r1 error + if rf, ok := ret.Get(0).(func(int) (btcutil.Amount, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(int) btcutil.Amount); ok { r0 = rf(_a0) } else { r0 = ret.Get(0).(btcutil.Amount) } - var r1 error if rf, ok := ret.Get(1).(func(int) error); ok { r1 = rf(_a0) } else { @@ -66,7 +75,15 @@ func (_m *Interface) EstimateFee(_a0 int) (btcutil.Amount, error) { func (_m *Interface) GetMerkle(_a0 chainhash.Hash, _a1 int) (*blockchain.GetMerkleResult, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for GetMerkle") + } + var r0 *blockchain.GetMerkleResult + var r1 error + if rf, ok := ret.Get(0).(func(chainhash.Hash, int) (*blockchain.GetMerkleResult, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(chainhash.Hash, int) *blockchain.GetMerkleResult); ok { r0 = rf(_a0, _a1) } else { @@ -75,7 +92,6 @@ func (_m *Interface) GetMerkle(_a0 chainhash.Hash, _a1 int) (*blockchain.GetMerk } } - var r1 error if rf, ok := ret.Get(1).(func(chainhash.Hash, int) error); ok { r1 = rf(_a0, _a1) } else { @@ -89,7 +105,15 @@ func (_m *Interface) GetMerkle(_a0 chainhash.Hash, _a1 int) (*blockchain.GetMerk func (_m *Interface) Headers(_a0 int, _a1 int) (*blockchain.HeadersResult, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for Headers") + } + var r0 *blockchain.HeadersResult + var r1 error + if rf, ok := ret.Get(0).(func(int, int) (*blockchain.HeadersResult, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(int, int) *blockchain.HeadersResult); ok { r0 = rf(_a0, _a1) } else { @@ -98,7 +122,6 @@ func (_m *Interface) Headers(_a0 int, _a1 int) (*blockchain.HeadersResult, error } } - var r1 error if rf, ok := ret.Get(1).(func(int, int) error); ok { r1 = rf(_a0, _a1) } else { @@ -113,6 +136,11 @@ func (_m *Interface) HeadersSubscribe(_a0 func(*types.Header)) { _m.Called(_a0) } +// ManualReconnect provides a mock function with given fields: +func (_m *Interface) ManualReconnect() { + _m.Called() +} + // RegisterOnConnectionErrorChangedEvent provides a mock function with given fields: _a0 func (_m *Interface) RegisterOnConnectionErrorChangedEvent(_a0 func(error)) { _m.Called(_a0) @@ -122,14 +150,21 @@ func (_m *Interface) RegisterOnConnectionErrorChangedEvent(_a0 func(error)) { func (_m *Interface) RelayFee() (btcutil.Amount, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RelayFee") + } + var r0 btcutil.Amount + var r1 error + if rf, ok := ret.Get(0).(func() (btcutil.Amount, error)); ok { + return rf() + } if rf, ok := ret.Get(0).(func() btcutil.Amount); ok { r0 = rf() } else { r0 = ret.Get(0).(btcutil.Amount) } - var r1 error if rf, ok := ret.Get(1).(func() error); ok { r1 = rf() } else { @@ -143,7 +178,15 @@ func (_m *Interface) RelayFee() (btcutil.Amount, error) { func (_m *Interface) ScriptHashGetHistory(_a0 blockchain.ScriptHashHex) (blockchain.TxHistory, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ScriptHashGetHistory") + } + var r0 blockchain.TxHistory + var r1 error + if rf, ok := ret.Get(0).(func(blockchain.ScriptHashHex) (blockchain.TxHistory, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(blockchain.ScriptHashHex) blockchain.TxHistory); ok { r0 = rf(_a0) } else { @@ -152,7 +195,6 @@ func (_m *Interface) ScriptHashGetHistory(_a0 blockchain.ScriptHashHex) (blockch } } - var r1 error if rf, ok := ret.Get(1).(func(blockchain.ScriptHashHex) error); ok { r1 = rf(_a0) } else { @@ -171,6 +213,10 @@ func (_m *Interface) ScriptHashSubscribe(_a0 func() func(), _a1 blockchain.Scrip func (_m *Interface) TransactionBroadcast(_a0 *wire.MsgTx) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for TransactionBroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(*wire.MsgTx) error); ok { r0 = rf(_a0) @@ -185,7 +231,15 @@ func (_m *Interface) TransactionBroadcast(_a0 *wire.MsgTx) error { func (_m *Interface) TransactionGet(_a0 chainhash.Hash) (*wire.MsgTx, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for TransactionGet") + } + var r0 *wire.MsgTx + var r1 error + if rf, ok := ret.Get(0).(func(chainhash.Hash) (*wire.MsgTx, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(chainhash.Hash) *wire.MsgTx); ok { r0 = rf(_a0) } else { @@ -194,7 +248,6 @@ func (_m *Interface) TransactionGet(_a0 chainhash.Hash) (*wire.MsgTx, error) { } } - var r1 error if rf, ok := ret.Get(1).(func(chainhash.Hash) error); ok { r1 = rf(_a0) } else { @@ -204,8 +257,12 @@ func (_m *Interface) TransactionGet(_a0 chainhash.Hash) (*wire.MsgTx, error) { return r0, r1 } -// NewInterface creates a new instance of Interface. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewInterface(t testing.TB) *Interface { +// NewInterface creates a new instance of Interface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewInterface(t interface { + mock.TestingT + Cleanup(func()) +}) *Interface { mock := &Interface{} mock.Mock.Test(t) diff --git a/backend/coins/btc/blockchain/mocks/mock.go b/backend/coins/btc/blockchain/mocks/mock.go index bff6b1c4d0..db76814734 100644 --- a/backend/coins/btc/blockchain/mocks/mock.go +++ b/backend/coins/btc/blockchain/mocks/mock.go @@ -39,6 +39,7 @@ type BlockchainMock struct { MockConnectionError func() error MockRegisterOnConnectionErrorChangedEvent func(func(error)) + MockManualReconnect func() } // ScriptHashGetHistory implements Interface. @@ -135,3 +136,10 @@ func (b *BlockchainMock) RegisterOnConnectionErrorChangedEvent(f func(error)) { b.MockRegisterOnConnectionErrorChangedEvent(f) } } + +// ManualReconnect implements Interface. +func (b *BlockchainMock) ManualReconnect() { + if b.MockManualReconnect != nil { + b.MockManualReconnect() + } +} diff --git a/backend/coins/btc/electrum/failoverclient.go b/backend/coins/btc/electrum/failoverclient.go index a443e785e1..ef104be651 100644 --- a/backend/coins/btc/electrum/failoverclient.go +++ b/backend/coins/btc/electrum/failoverclient.go @@ -156,6 +156,10 @@ func (f *failoverClient) TransactionGet(txHash chainhash.Hash) (*wire.MsgTx, err }) } +func (f *failoverClient) ManualReconnect() { + f.failover.ManualReconnect() +} + func (f *failoverClient) Close() { f.failover.Close() } diff --git a/backend/mobileserver/mobileserver.go b/backend/mobileserver/mobileserver.go index 57b21bf8de..9128048045 100644 --- a/backend/mobileserver/mobileserver.go +++ b/backend/mobileserver/mobileserver.go @@ -227,8 +227,13 @@ func CancelAuth() { bridgecommon.CancelAuth() } -// AuthResult triggers an auth feeedback notification (auth-ok/auth-err) towards the frontend, +// AuthResult triggers an auth feedback notification (auth-ok/auth-err) towards the frontend, // depending on the input value. func AuthResult(ok bool) { bridgecommon.AuthResult(ok) } + +// ManualReconnect wraps bridgecommon.ManualReconnect. +func ManualReconnect() { + bridgecommon.ManualReconnect() +} diff --git a/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift b/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift index d488825dcc..248fada3e2 100644 --- a/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift +++ b/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift @@ -91,7 +91,7 @@ class GoEnvironment: NSObject, MobileserverGoEnvironmentInterfaceProtocol { class GoAPI: NSObject, MobileserverGoAPIInterfaceProtocol, SetMessageHandlersProtocol { var handlers: MessageHandlersProtocol? - + func pushNotify(_ msg: String?) { self.handlers?.pushNotificationHandler(msg: msg!) } @@ -99,16 +99,15 @@ class GoAPI: NSObject, MobileserverGoAPIInterfaceProtocol, SetMessageHandlersPro func respond(_ queryID: Int, response: String?) { self.handlers?.callResponseHandler(queryID: queryID, response: response!) } - + func setMessageHandlers(handlers: MessageHandlersProtocol) { self.handlers = handlers } } - @main struct BitBoxAppApp: App { - var body: some Scene { + var body: some Scene { WindowGroup { GridLayout(alignment: .leading) { let goAPI = GoAPI() @@ -118,12 +117,13 @@ struct BitBoxAppApp: App { setupGoAPI(goAPI: goAPI) } .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in - MobileserverTriggerAuth() + MobileserverManualReconnect() + MobileserverTriggerAuth() } } } } - + func setupGoAPI(goAPI: MobileserverGoAPIInterfaceProtocol) { let appSupportDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! do { diff --git a/go.mod b/go.mod index 8e87a92ed3..430be73a8d 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.22 require ( github.com/BitBoxSwiss/bitbox02-api-go v0.0.0-20240925080402-a2115fee878e - github.com/BitBoxSwiss/block-client-go v0.0.0-20240516081043-0d604acd6519 + github.com/BitBoxSwiss/block-client-go v0.0.0-20241009081439-924dde98b9c1 github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/btcsuite/btcd/btcutil v1.1.6 diff --git a/go.sum b/go.sum index e3fdd62af6..aed142ec86 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/BitBoxSwiss/bitbox02-api-go v0.0.0-20240925080402-a2115fee878e h1:wEIIFhiZ58RsVjoKfwSBBD0i75uZ7KATOI/elaBWOOY= github.com/BitBoxSwiss/bitbox02-api-go v0.0.0-20240925080402-a2115fee878e/go.mod h1:Spf6hQRSylrvdjd7Cv4Tc8rFwlcamJAC8EuA61ARy7U= -github.com/BitBoxSwiss/block-client-go v0.0.0-20240516081043-0d604acd6519 h1:diVA/i8TJFBl9ZyMNX15KjZBpI2Gu63xQTozu6FsTrA= -github.com/BitBoxSwiss/block-client-go v0.0.0-20240516081043-0d604acd6519/go.mod h1:SJTiQZU9ggBzVKMni97rpNS9GddPKErndFXNSDrfEGc= +github.com/BitBoxSwiss/block-client-go v0.0.0-20241009081439-924dde98b9c1 h1:5hjP8mYSVKFibesrz8L6U0Vp5zSJt0LwXB3DSZGhnSo= +github.com/BitBoxSwiss/block-client-go v0.0.0-20241009081439-924dde98b9c1/go.mod h1:SJTiQZU9ggBzVKMni97rpNS9GddPKErndFXNSDrfEGc= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= diff --git a/vendor/github.com/BitBoxSwiss/block-client-go/failover/failover.go b/vendor/github.com/BitBoxSwiss/block-client-go/failover/failover.go index c076714279..cd937b394e 100644 --- a/vendor/github.com/BitBoxSwiss/block-client-go/failover/failover.go +++ b/vendor/github.com/BitBoxSwiss/block-client-go/failover/failover.go @@ -121,6 +121,8 @@ type Failover[C Client] struct { enableRetry bool subscriptions []func(client C, currentClientCounter int) + manualReconnect chan struct{} + closed bool closedMu sync.RWMutex } @@ -145,6 +147,7 @@ func New[C Client](opts *Options[C]) *Failover[C] { opts: opts, startServerIndex: startServerIndex, currentServerIndex: startServerIndex, + manualReconnect: make(chan struct{}), } } @@ -157,7 +160,17 @@ func (f *Failover[C]) establishConnection() error { if f.opts.OnRetry != nil { go f.opts.OnRetry(f.lastErr) } - time.Sleep(retryTimeout) + + // Drain the manualReconnect channel to avoid stale reconnect signals + select { + case <-f.manualReconnect: + default: + } + // Wait for retry timeout or manual reconnect + select { + case <-time.After(retryTimeout): + case <-f.manualReconnect: + } } f.enableRetry = true @@ -370,6 +383,16 @@ func (f *Failover[C]) isClosed() bool { return f.closed } +// ManualReconnect triggers a manual reconnect, non-blocking. +// This re-tries connecting immediately without waiting for the retry timeout. +// We we are not currently disconnected, this is a no-op. +func (f *Failover[C]) ManualReconnect() { + select { + case f.manualReconnect <- struct{}{}: + default: + } +} + // Close closes the failover client and closes the current client, resulting in `ErrClosed` in all // future `Call` and `Subscribe` calls. It also calls `Close()` on the currently active client if // one exists. diff --git a/vendor/modules.txt b/vendor/modules.txt index 4143777c63..fcd989efaf 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -8,7 +8,7 @@ github.com/BitBoxSwiss/bitbox02-api-go/communication/u2fhid github.com/BitBoxSwiss/bitbox02-api-go/util/errp github.com/BitBoxSwiss/bitbox02-api-go/util/semver github.com/BitBoxSwiss/bitbox02-api-go/util/sleep -# github.com/BitBoxSwiss/block-client-go v0.0.0-20240516081043-0d604acd6519 +# github.com/BitBoxSwiss/block-client-go v0.0.0-20241009081439-924dde98b9c1 ## explicit; go 1.19 github.com/BitBoxSwiss/block-client-go/electrum github.com/BitBoxSwiss/block-client-go/electrum/types From 2fc820f14139ce96bd77e9c11b5bda90d0c56906 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Wed, 9 Oct 2024 10:46:21 +0200 Subject: [PATCH 09/92] bump minimum platform support to Windows 10, macOS 10.15 We upgraded to Go 1.22 a while ago: https://go.dev/wiki/MinimumRequirements > For Go 1.21 and later: Windows 10 and higher or Windows Server 2016 > and higher. > Go 1.21 and later will support macOS Catalina 10.15 or newer; see https://go.dev/doc/go1.20#darwin. See also: - https://github.com/golang/go/issues/57003 - https://github.com/golang/go/issues/57125 - https://github.com/golang/go/issues/64622#issuecomment-1847475161 Windows 7 has oficially been EOL'd in Jan 2020, almost 5 years ago. It is reasonable to not officially support it. --- docs/BUILD.md | 4 ++-- env.mk.inc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/BUILD.md b/docs/BUILD.md index 487b7387c8..e4c8e1a988 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -6,8 +6,8 @@ Wallet application. * Debian: 11 bullseye or newer * Ubuntu: 20.04+ * Fedora: 36+ -* MacOS: 10.13+ -* Windows: Windows 7+ +* MacOS: 10.15+ +* Windows: Windows 10+ ## Debian, Ubuntu, and Fedora GNU/Linux with Docker diff --git a/env.mk.inc b/env.mk.inc index c12d677a84..83c586ede1 100644 --- a/env.mk.inc +++ b/env.mk.inc @@ -1,2 +1,2 @@ LIBNAME=libserver -MACOS_MIN_VERSION := 10.11 +MACOS_MIN_VERSION := 10.15 From 30c59f660659ea5ca74ef75908b5163685239a37 Mon Sep 17 00:00:00 2001 From: thisconnect Date: Mon, 2 Sep 2024 10:28:45 +0200 Subject: [PATCH 10/92] frontend: cleanup remove unused assets --- .../web/src/components/transactions/assets/icon-transfer-in.svg | 1 - .../web/src/components/transactions/assets/icon-transfer-out.svg | 1 - 2 files changed, 2 deletions(-) delete mode 100644 frontends/web/src/components/transactions/assets/icon-transfer-in.svg delete mode 100644 frontends/web/src/components/transactions/assets/icon-transfer-out.svg diff --git a/frontends/web/src/components/transactions/assets/icon-transfer-in.svg b/frontends/web/src/components/transactions/assets/icon-transfer-in.svg deleted file mode 100644 index a5ae91854e..0000000000 --- a/frontends/web/src/components/transactions/assets/icon-transfer-in.svg +++ /dev/null @@ -1 +0,0 @@ -icon-transfer-in \ No newline at end of file diff --git a/frontends/web/src/components/transactions/assets/icon-transfer-out.svg b/frontends/web/src/components/transactions/assets/icon-transfer-out.svg deleted file mode 100644 index 35c06d79c7..0000000000 --- a/frontends/web/src/components/transactions/assets/icon-transfer-out.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 317d0869eecfbd1f25294b4cfeb75ab59f9a7bbe Mon Sep 17 00:00:00 2001 From: thisconnect Date: Wed, 18 Sep 2024 09:14:32 +0200 Subject: [PATCH 11/92] frontend: import tx icons from svg assets There is no need to have these SVG's in JSX. --- .../icon/assets/icons/arrow-down-green.svg | 1 + .../icon/assets/icons/arrow-right-gray.svg | 1 + .../icon/assets/icons/arrow-up-red.svg | 1 + frontends/web/src/components/icon/icon.tsx | 6 +++ .../transactions/components/arrow.tsx | 19 ++++--- .../transactions/components/icons.module.css | 17 ------- .../transactions/components/icons.tsx | 49 ------------------- 7 files changed, 22 insertions(+), 72 deletions(-) create mode 100644 frontends/web/src/components/icon/assets/icons/arrow-down-green.svg create mode 100644 frontends/web/src/components/icon/assets/icons/arrow-right-gray.svg create mode 100644 frontends/web/src/components/icon/assets/icons/arrow-up-red.svg delete mode 100644 frontends/web/src/components/transactions/components/icons.module.css delete mode 100644 frontends/web/src/components/transactions/components/icons.tsx diff --git a/frontends/web/src/components/icon/assets/icons/arrow-down-green.svg b/frontends/web/src/components/icon/assets/icons/arrow-down-green.svg new file mode 100644 index 0000000000..1fdf2adee8 --- /dev/null +++ b/frontends/web/src/components/icon/assets/icons/arrow-down-green.svg @@ -0,0 +1 @@ + diff --git a/frontends/web/src/components/icon/assets/icons/arrow-right-gray.svg b/frontends/web/src/components/icon/assets/icons/arrow-right-gray.svg new file mode 100644 index 0000000000..1c93aeade7 --- /dev/null +++ b/frontends/web/src/components/icon/assets/icons/arrow-right-gray.svg @@ -0,0 +1 @@ + diff --git a/frontends/web/src/components/icon/assets/icons/arrow-up-red.svg b/frontends/web/src/components/icon/assets/icons/arrow-up-red.svg new file mode 100644 index 0000000000..e81258b09c --- /dev/null +++ b/frontends/web/src/components/icon/assets/icons/arrow-up-red.svg @@ -0,0 +1 @@ + diff --git a/frontends/web/src/components/icon/icon.tsx b/frontends/web/src/components/icon/icon.tsx index c617722696..fcb6c3f1cf 100644 --- a/frontends/web/src/components/icon/icon.tsx +++ b/frontends/web/src/components/icon/icon.tsx @@ -20,8 +20,11 @@ import BB02StylizedDark from '@/assets/device/bitbox02-stylized-reflection-dark. import BB02StylizedLight from '@/assets/device/bitbox02-stylized-reflection-light.png'; import info from './assets/icons/info.svg'; import arrowDownSVG from './assets/icons/arrow-down-active.svg'; +import arrowDownGreenSVG from './assets/icons/arrow-down-green.svg'; import arrowDownRedSVG from './assets/icons/arrow-down-red.svg'; +import arrowRightGraySVG from './assets/icons/arrow-right-gray.svg'; import arrowUpGreenSVG from './assets/icons/arrow-up-green.svg'; +import arrowUpRedSVG from './assets/icons/arrow-up-red.svg'; import arrowCircleLeftSVG from './assets/icons/arrow-circle-left.svg'; import arrowCircleLeftActiveSVG from './assets/icons/arrow-circle-left-active.svg'; import arrowCircleRightSVG from './assets/icons/arrow-circle-right.svg'; @@ -144,8 +147,11 @@ export const ExpandIcon = ({ type ImgProps = JSX.IntrinsicElements['img']; export const ArrowDown = (props: ImgProps) => (); +export const ArrowDownGreen = (props: ImgProps) => (); export const ArrowDownRed = (props: ImgProps) => (); +export const ArrowRightGray = (props: ImgProps) => (); export const ArrowUpGreen = (props: ImgProps) => (); +export const ArrowUpRed = (props: ImgProps) => (); export const ArrowCirlceLeft = (props: ImgProps) => (); export const ArrowCirlceLeftActive = (props: ImgProps) => (); export const ArrowCirlceRight = (props: ImgProps) => (); diff --git a/frontends/web/src/components/transactions/components/arrow.tsx b/frontends/web/src/components/transactions/components/arrow.tsx index 0732909ba6..501a242063 100644 --- a/frontends/web/src/components/transactions/components/arrow.tsx +++ b/frontends/web/src/components/transactions/components/arrow.tsx @@ -15,8 +15,7 @@ */ import type { TTransactionStatus, TTransactionType } from '@/api/account'; -import { Warning } from '@/components/icon/icon'; -import { ArrowIn, ArrowOut, ArrowSelf } from './icons'; +import { ArrowDownGreen, ArrowRightGray, ArrowUpRed, Warning } from '@/components/icon/icon'; type TProps = { status: TTransactionStatus; @@ -25,13 +24,21 @@ type TProps = { export const Arrow = ({ status, type }: TProps) => { if (status === 'failed') { - return ; + return ( + + ); } if (type === 'receive') { - return ; + return ( + + ); } if (type === 'send') { - return ; + return ( + + ); } - return ; + return ( + + ); }; diff --git a/frontends/web/src/components/transactions/components/icons.module.css b/frontends/web/src/components/transactions/components/icons.module.css deleted file mode 100644 index 5e1571bf2c..0000000000 --- a/frontends/web/src/components/transactions/components/icons.module.css +++ /dev/null @@ -1,17 +0,0 @@ -.txArrowType { - width: 18px; - height: 18px; -} - -.txArrowTypeIn { - stroke: var(--color-success) !important; -} - -.txArrowTypeOut { - stroke: var(--color-danger) !important; -} - -.txArrowTypeSelf { - stroke: var(--color-secondary) !important; -} - diff --git a/frontends/web/src/components/transactions/components/icons.tsx b/frontends/web/src/components/transactions/components/icons.tsx deleted file mode 100644 index a76eb94fd0..0000000000 --- a/frontends/web/src/components/transactions/components/icons.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import style from './icons.module.css'; - -export const ArrowIn = () => ( - - - - -); - -export const ArrowOut = () => ( - - - - -); - -export const ArrowSelf = () => ( - - - - -); From be1855defb9368ee6a8d4cc6664ccaab6c00f904 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Fri, 11 Oct 2024 09:42:59 +0200 Subject: [PATCH 12/92] ci: remove trivy It has been failing with random errors way too often which is distracting: > 2024-10-11T07:40:25Z FATAL Fatal error init error: DB error: failed to download vulnerability DB: database download error: oci download error: failed to fetch the layer: GET https://ghcr.io/v2/aquasecurity/trivy-db/blobs/sha256:d5984d994db8053be4c3cb88a0358784726280ff174ad24bb84b92138b8f4acb: TOOMANYREQUESTS: retry-after: 1.021981ms, It also does not seem to help much beyond the builtin GH security scans. --- .github/workflows/trivy.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/workflows/trivy.yml diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml deleted file mode 100644 index bf11e1a902..0000000000 --- a/.github/workflows/trivy.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: trivy check -on: - pull_request: - branches: - - master - push: - branches: - - master -jobs: - trivy: - runs-on: ubuntu-22.04 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Run Trivy - uses: aquasecurity/trivy-action@0.24.0 - with: - format: 'table' - ignore-unfixed: true - scan-type: 'fs' - exit-code: '1' - severity: 'MEDIUM,HIGH,CRITICAL' - From 3eb3f9d2cc75cf3d7bb620e52f9e2fb2dabc0fe0 Mon Sep 17 00:00:00 2001 From: thisconnect Date: Wed, 18 Sep 2024 14:36:14 +0200 Subject: [PATCH 13/92] frontend: add missing space before incoming tx --- frontends/web/src/components/balance/balance.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/web/src/components/balance/balance.tsx b/frontends/web/src/components/balance/balance.tsx index 6cfc7d8f37..e30ee7c18b 100644 --- a/frontends/web/src/components/balance/balance.tsx +++ b/frontends/web/src/components/balance/balance.tsx @@ -63,6 +63,7 @@ export const Balance = ({ balance.hasIncoming && (

{t('account.incoming')} + {' '} + Date: Wed, 18 Sep 2024 14:43:17 +0200 Subject: [PATCH 14/92] frontend: remove smaller font styling for balances on mobile The balance was using a smaller font-size so that both amounts, coin and currency, fit on one line. This was introduced a long time ago in b8cefe369a32f09de8b6fe4ecd0b35d2820e3ea4 Removing as longer amounts break nicelly on small screens anyway and this 'optimization' is not really needed. Total balance should use a larger font-size. --- frontends/web/src/components/balance/balance.module.css | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frontends/web/src/components/balance/balance.module.css b/frontends/web/src/components/balance/balance.module.css index 373a896a7b..1d70592229 100644 --- a/frontends/web/src/components/balance/balance.module.css +++ b/frontends/web/src/components/balance/balance.module.css @@ -58,9 +58,3 @@ padding-top: var(--space-quarter); } } - -@media (max-width: 560px) { - .balanceTable td { - font-size: var(--size-subheader); - } -} From 3f2ead013d9d0ef4886f4d5c8609966aa9a462c9 Mon Sep 17 00:00:00 2001 From: thisconnect Date: Fri, 27 Sep 2024 09:48:09 +0200 Subject: [PATCH 15/92] frontend: switch balance and action buttons So that the Balance is at the top of the screen. --- frontends/web/src/routes/account/account.module.css | 2 +- frontends/web/src/routes/account/account.tsx | 9 +++------ frontends/web/src/style/layout.css | 2 -- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/frontends/web/src/routes/account/account.module.css b/frontends/web/src/routes/account/account.module.css index fe41b982d0..c87a29b35c 100644 --- a/frontends/web/src/routes/account/account.module.css +++ b/frontends/web/src/routes/account/account.module.css @@ -112,10 +112,10 @@ .actionsContainer a { flex: 1 0 30%; + margin-left: 0; margin-right: 0; max-width: 30%; min-width: unset; - } .exchange, diff --git a/frontends/web/src/routes/account/account.tsx b/frontends/web/src/routes/account/account.tsx index 5fbe023d08..2799f4f07d 100644 --- a/frontends/web/src/routes/account/account.tsx +++ b/frontends/web/src/routes/account/account.tsx @@ -305,15 +305,12 @@ export const Account = ({

-
-