From 63a0395c2d5167ab813568f4ac7b41b08c5e97c1 Mon Sep 17 00:00:00 2001 From: M Date: Mon, 24 Jan 2022 14:04:23 +0200 Subject: [PATCH] Remove Next Address button and logic for electrum wallets. Add disclaimer for electrum wallets on address screen. Change way for generation of current receive and change addresses. --- cw_bitcoin/lib/electrum_transaction_info.dart | 4 +- cw_bitcoin/lib/electrum_wallet.dart | 37 ++++- cw_bitcoin/lib/electrum_wallet_addresses.dart | 148 +++++++++--------- lib/bitcoin/cw_bitcoin.dart | 12 -- .../dashboard/widgets/address_page.dart | 17 +- .../wallet_address_list_view_model.dart | 22 --- res/values/strings_de.arb | 3 +- res/values/strings_en.arb | 3 +- res/values/strings_es.arb | 3 +- res/values/strings_hi.arb | 3 +- res/values/strings_hr.arb | 3 +- res/values/strings_it.arb | 3 +- res/values/strings_ja.arb | 3 +- res/values/strings_ko.arb | 3 +- res/values/strings_nl.arb | 3 +- res/values/strings_pl.arb | 3 +- res/values/strings_pt.arb | 3 +- res/values/strings_ru.arb | 3 +- res/values/strings_uk.arb | 3 +- res/values/strings_zh.arb | 3 +- tool/configure.dart | 2 - 21 files changed, 142 insertions(+), 142 deletions(-) diff --git a/cw_bitcoin/lib/electrum_transaction_info.dart b/cw_bitcoin/lib/electrum_transaction_info.dart index b7438f14..98ad60f7 100644 --- a/cw_bitcoin/lib/electrum_transaction_info.dart +++ b/cw_bitcoin/lib/electrum_transaction_info.dart @@ -116,7 +116,9 @@ class ElectrumTransactionInfo extends TransactionInfo { factory ElectrumTransactionInfo.fromElectrumBundle( ElectrumTransactionBundle bundle, WalletType type, {@required Set addresses, int height}) { - final date = DateTime.fromMillisecondsSinceEpoch(bundle.time * 1000); + final date = bundle.time != null + ? DateTime.fromMillisecondsSinceEpoch(bundle.time * 1000) + : DateTime.now(); var direction = TransactionDirection.incoming; var amount = 0; var inputAmount = 0; diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 4bd46f43..03884d4b 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -484,7 +484,7 @@ abstract class ElectrumWalletBase extends WalletBase[]; final time = verboseTransaction['time'] as int; - final confirmations = verboseTransaction['time'] as int; + final confirmations = verboseTransaction['confirmations'] as int ?? 0; for (final vin in original.ins) { final id = HEX.encode(vin.hash.reversed.toList()); @@ -510,13 +510,35 @@ abstract class ElectrumWalletBase extends WalletBase> fetchTransactions() async { + final addressHashes = {}; + final normalizedHistories = >[]; + walletAddresses.addresses.forEach((addressRecord) { + if (addressRecord.isHidden) { + return; + } + + final sh = scriptHash(addressRecord.address, networkType: networkType); + addressHashes[sh] = addressRecord; + }); final histories = - publicScriptHashes.map((scriptHash) => electrumClient.getHistory(scriptHash)); - final _historiesWithDetails = await Future.wait(histories) - .then((histories) => histories.expand((i) => i).toList()) - .then((histories) => histories.map((tx) => fetchTransactionInfo( - hash: tx['tx_hash'] as String, height: tx['height'] as int))); - final historiesWithDetails = await Future.wait(_historiesWithDetails); + addressHashes.keys.map((scriptHash) => electrumClient + .getHistory(scriptHash) + .then((history) => {scriptHash: history})); + final historyResults = await Future.wait(histories); + historyResults.forEach((history) { + history.entries.forEach((historyItem) { + if (historyItem.value.isNotEmpty) { + final address = addressHashes[historyItem.key]; + address.setAsUsed(); + normalizedHistories.addAll(historyItem.value); + } + }); + }); + final historiesWithDetails = await Future.wait( + normalizedHistories + .map((transaction) => fetchTransactionInfo( + hash: transaction['tx_hash'] as String, + height: transaction['height'] as int))); return historiesWithDetails.fold>( {}, (acc, tx) { @@ -534,6 +556,7 @@ abstract class ElectrumWalletBase extends WalletBase.of( + (initialAddresses ?? []).toSet()), + receiveAddresses = ObservableList.of( + (initialAddresses ?? []) + .where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed) + .toSet()), + changeAddresses = ObservableList.of( + (initialAddresses ?? []) + .where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed) + .toSet()), + super(walletInfo) { currentReceiveAddressIndex = initialRegularAddressIndex; currentChangeAddressIndex = initialChangeAddressIndex; - addresses = ObservableList.of( - (initialAddresses ?? []).toSet()); } static const defaultReceiveAddressesCount = 22; static const defaultChangeAddressesCount = 17; static const gap = 20; + final ObservableList addresses; + final ObservableList receiveAddresses; + final ObservableList changeAddresses; + final ElectrumClient electrumClient; + final bitcoin.NetworkType networkType; + final bitcoin.HDWallet mainHd; + final bitcoin.HDWallet sideHd; + + @override + @computed + String get address => receiveAddresses.first.address; + @override - @observable - String address; + set address(String addr) => null; int currentReceiveAddressIndex; int currentChangeAddressIndex; - ElectrumClient electrumClient; - bitcoin.NetworkType networkType; - bitcoin.HDWallet mainHd; - bitcoin.HDWallet sideHd; - ObservableList addresses; - - List get receiveAddresses => addresses - .where((addr) => !addr.isHidden && !addr.isUsed) - .toList(); - - List get changeAddresses => addresses - .where((addr) => addr.isHidden && !addr.isUsed) - .toList(); - List get totalReceiveAddresses => addresses - .where((addr) => !addr.isHidden) - .toList(); + @computed + int get totalCountOfReceiveAddresses => + addresses.fold(0, (acc, addressRecord) { + if (!addressRecord.isHidden) { + return acc + 1; + } + return acc; + }); - List get totalChangeAddresses => addresses - .where((addr) => addr.isHidden) - .toList(); + @computed + int get totalCountOfChangeAddresses => + addresses.fold(0, (acc, addressRecord) { + if (addressRecord.isHidden) { + return acc + 1; + } + return acc; + }); Future discoverAddresses() async { await _discoverAddresses(mainHd, false); @@ -70,60 +85,39 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @override Future init() async { await _generateInitialAddresses(); - - if (receiveAddresses.isEmpty) { - final newAddresses = await _createNewAddresses( - gap, - hd: mainHd, - startIndex: totalReceiveAddresses.length > 0 - ? totalReceiveAddresses.length - 1 - : 0, - isHidden: false); - _addAddresses(newAddresses); - } else if (currentReceiveAddressIndex >= receiveAddresses.length) { - currentReceiveAddressIndex = 0; - } - - address = receiveAddresses[currentReceiveAddressIndex].address; + updateReceiveAddresses(); + updateChangeAddresses(); await updateAddressesInBox(); - } - @action - Future nextReceiveAddress() async { - if (receiveAddresses.isEmpty) { - final newAddresses = await _createNewAddresses( - gap, - hd: mainHd, - startIndex: totalReceiveAddresses.length > 0 - ? totalReceiveAddresses.length - 1 - : 0, - isHidden: false); - _addAddresses(newAddresses); - } else if (currentReceiveAddressIndex >= receiveAddresses.length) { + if (currentReceiveAddressIndex >= receiveAddresses.length) { currentReceiveAddressIndex = 0; } - address = receiveAddresses[currentReceiveAddressIndex].address; - currentReceiveAddressIndex += 1; - await updateAddressesInBox(); + if (currentChangeAddressIndex >= changeAddresses.length) { + currentChangeAddressIndex = 0; + } } @action Future getChangeAddress() async { + updateChangeAddresses(); + if (changeAddresses.isEmpty) { final newAddresses = await _createNewAddresses( gap, hd: sideHd, - startIndex: totalChangeAddresses.length > 0 - ? totalChangeAddresses.length - 1 + startIndex: totalCountOfChangeAddresses > 0 + ? totalCountOfChangeAddresses - 1 : 0, isHidden: true); _addAddresses(newAddresses); - } else if (currentChangeAddressIndex >= changeAddresses.length) { + } + + if (currentChangeAddressIndex >= changeAddresses.length) { currentChangeAddressIndex = 0; } - + updateChangeAddresses(); final address = changeAddresses[currentChangeAddressIndex].address; currentChangeAddressIndex += 1; return address; @@ -153,18 +147,20 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } } - void randomizeAddress() { - const minCountOfVisibleAddresses = 5; - final random = Random(); - var availableAddresses = addresses - .where((addr) => !addr.isHidden) - .toList(); - - if (availableAddresses.length < minCountOfVisibleAddresses) { - availableAddresses = addresses; - } + @action + void updateReceiveAddresses() { + receiveAddresses.removeRange(0, receiveAddresses.length); + final newAdresses = addresses + .where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed); + receiveAddresses.addAll(newAdresses); + } - address = availableAddresses[random.nextInt(availableAddresses.length)].address; + @action + void updateChangeAddresses() { + changeAddresses.removeRange(0, changeAddresses.length); + final newAdresses = addresses + .where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed); + changeAddresses.addAll(newAdresses); } Future _discoverAddresses(bitcoin.HDWallet hd, bool isHidden) async { @@ -187,12 +183,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { while(hasAddrUse) { final addr = addrs.last.address; - hasAddrUse = await _validateAddressUsing(addr); + hasAddrUse = await _hasAddressUsed(addr); if (!hasAddrUse) { break; } - + final start = addrs.length; final count = start + gap; final batch = await _createNewAddresses( @@ -264,9 +260,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { this.addresses.addAll(addressesSet); } - Future _validateAddressUsing(String address) async { + Future _hasAddressUsed(String address) async { final sh = scriptHash(address, networkType: networkType); - final balance = await electrumClient.getBalance(sh); - return balance.isEmpty; + final transactionHistory = await electrumClient.getHistory(sh); + return transactionHistory.isNotEmpty; } } \ No newline at end of file diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index de5f14af..e7386159 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -53,18 +53,6 @@ class CWBitcoin extends Bitcoin { final bitcoinWallet = wallet as ElectrumWallet; await bitcoinWallet.walletAddresses.generateNewAddress(); } - - @override - Future nextAddress(Object wallet) { - final bitcoinWallet = wallet as ElectrumWallet; - bitcoinWallet.walletAddresses.nextReceiveAddress(); - } - - @override - Future randomAddress(Object wallet) { - final bitcoinWallet = wallet as ElectrumWallet; - bitcoinWallet.walletAddresses.randomizeAddress(); - } @override Object createBitcoinTransactionCredentials(List outputs, TransactionPriority priority) diff --git a/lib/src/screens/dashboard/widgets/address_page.dart b/lib/src/screens/dashboard/widgets/address_page.dart index 51bb05a4..16153864 100644 --- a/lib/src/screens/dashboard/widgets/address_page.dart +++ b/lib/src/screens/dashboard/widgets/address_page.dart @@ -125,14 +125,15 @@ class AddressPage extends StatelessWidget { ), ), ) - : PrimaryButton( - onPressed: () => addressListViewModel.nextAddress(), - text: 'Next address', - color: Theme.of(context).buttonColor, - textColor: Theme.of(context) - .accentTextTheme - .display3 - .backgroundColor); + : Text( + S.of(context).electrum_address_disclaimer, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + color: Theme.of(context) + .accentTextTheme + .display2 + .backgroundColor)); }) ], ), diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index 47c135d2..e4aeca01 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -212,26 +212,4 @@ abstract class WalletAddressListViewModelBase with Store { _baseItems.add(WalletAddressListHeader()); } - - @action - void nextAddress() { - final wallet = _wallet; - - if (wallet.type == WalletType.bitcoin - || wallet.type == WalletType.litecoin) { - bitcoin.nextAddress(wallet); - wallet.save(); - } - } - - @action - void generateRandomAddress() { - final wallet = _wallet; - - if (wallet.type == WalletType.bitcoin - || wallet.type == WalletType.litecoin) { - bitcoin.randomAddress(wallet); - wallet.save(); - } - } } diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 2429e082..20b6182e 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!", "learn_more" : "Erfahren Sie mehr", - "new_template" : "neue Vorlage" + "new_template" : "neue Vorlage", + "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin" } diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 5034aba6..99ff5c1a 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -523,5 +523,6 @@ "third_intro_content" : "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!", "learn_more" : "Learn More", - "new_template" : "New Template" + "new_template" : "New Template", + "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work" } \ No newline at end of file diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index e105680b..9b365f1d 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Los Yats también viven fuera de Cake Wallet. Cualquier dirección de billetera en la tierra se puede reemplazar con un Yat!", "learn_more" : "Aprende más", - "new_template" : "Nueva plantilla" + "new_template" : "Nueva plantilla", + "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando" } \ No newline at end of file diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index b4f8e5cd..52d62525 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!", "learn_more" : "और अधिक जानें", - "new_template" : "नया टेम्पलेट" + "new_template" : "नया टेम्पलेट", + "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं" } \ No newline at end of file diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 75a49c67..9965226f 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yats žive i izvan Cake Wallet -a. Bilo koja adresa novčanika na svijetu može se zamijeniti Yat!", "learn_more" : "Saznajte više", - "new_template" : "novi predložak" + "new_template" : "novi predložak", + "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek" } \ No newline at end of file diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index effd153f..d0473def 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Anche Yats vive fuori da Cake Wallet. Qualsiasi indirizzo di portafoglio sulla terra può essere sostituito con un Yat!", "learn_more" : "Impara di più", - "new_template" : "Nuovo modello" + "new_template" : "Nuovo modello", + "electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare" } \ No newline at end of file diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index b57b41aa..c96e4724 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -522,5 +522,6 @@ "third_intro_content" : "YatsはCakeWalletの外にも住んでいます。 地球上のどのウォレットアドレスもYatに置き換えることができます!", "learn_more" : "もっと詳しく知る", - "new_template" : "新しいテンプレート" + "new_template" : "新しいテンプレート", + "electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します" } \ No newline at end of file diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index fcdcca9a..f8ba2fee 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yats는 Cake Wallet 밖에서도 살고 있습니다. 지구상의 모든 지갑 주소는 Yat!", "learn_more" : "더 알아보기", - "new_template" : "새 템플릿" + "new_template" : "새 템플릿", + "electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다." } \ No newline at end of file diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index adc5cfd3..29cc689f 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yats wonen ook buiten Cake Wallet. Elk portemonnee-adres op aarde kan worden vervangen door een Yat!", "learn_more" : "Kom meer te weten", - "new_template" : "Nieuwe sjabloon" + "new_template" : "Nieuwe sjabloon", + "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work" } \ No newline at end of file diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index ebfb6b12..9477f491 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yats mieszkają również poza Cake Wallet. Każdy adres portfela na ziemi można zastąpić Yat!", "learn_more" : "Ucz się więcej", - "new_template" : "Nowy szablon" + "new_template" : "Nowy szablon", + "electrum_address_disclaimer": "Za każdym razem, gdy korzystasz z jednego z nich, generujemy nowe adresy, ale poprzednie adresy nadal działają" } \ No newline at end of file diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index c1965a89..cbbba6f8 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yats também mora fora da Cake Wallet. Qualquer endereço de carteira na Terra pode ser substituído por um Yat!", "learn_more" : "Saber mais", - "new_template" : "Novo modelo" + "new_template" : "Novo modelo", + "electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando" } \ No newline at end of file diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 89b84592..d2276097 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -522,5 +522,6 @@ "third_intro_content" : "Yat находятся за пределами Cake Wallet. Любой адрес кошелька на земле можно заменить на Yat!", "learn_more" : "Узнать больше", - "new_template" : "Новый шаблон" + "new_template" : "Новый шаблон", + "electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать." } \ No newline at end of file diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 092818d2..b6680c0f 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -521,5 +521,6 @@ "third_intro_content" : "Yat знаходиться за межами Cake Wallet. Будь-яку адресу гаманця на землі можна замінити на Yat!", "learn_more" : "Дізнатися більше", - "new_template" : "Новий шаблон" + "new_template" : "Новий шаблон", + "electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати" } \ No newline at end of file diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index c4f32c64..0a49fce9 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -520,5 +520,6 @@ "third_intro_content" : "Yats 也住在 Cake Wallet 之外。 地球上任何一個錢包地址都可以用一個Yat來代替!", "learn_more" : "了解更多", - "new_template" : "新模板" + "new_template" : "新模板", + "electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效" } \ No newline at end of file diff --git a/tool/configure.dart b/tool/configure.dart index 84c1668d..45e0bd20 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -74,8 +74,6 @@ abstract class Bitcoin { TransactionPriority deserializeBitcoinTransactionPriority(int raw); int getFeeRate(Object wallet, TransactionPriority priority); Future generateNewAddress(Object wallet); - Future nextAddress(Object wallet); - Future randomAddress(Object wallet); Object createBitcoinTransactionCredentials(List outputs, TransactionPriority priority); List getAddresses(Object wallet);