feat: single block scan, rescan by date working for btc mainnet

This commit is contained in:
Rafael Saes 2024-04-09 12:15:21 -03:00
parent 058ff6aeec
commit 8ea2e6ee40
33 changed files with 147 additions and 24 deletions

View file

@ -201,7 +201,7 @@ abstract class ElectrumWalletBase
}
@action
Future<void> _setListeners(int height, {int? chainTip}) async {
Future<void> _setListeners(int height, {int? chainTip, bool? doSingleScan}) async {
final currentChainTip = chainTip ?? await electrumClient.getCurrentBlockChainTip() ?? 0;
syncStatus = AttemptingSyncStatus();
@ -223,6 +223,7 @@ abstract class ElectrumWalletBase
transactionHistoryIds: transactionHistory.transactions.keys.toList(),
node: ScanNode(node!.uri, node!.useSSL),
labels: walletAddresses.labels,
isSingleScan: doSingleScan ?? false,
));
await for (var message in receivePort) {
@ -981,9 +982,10 @@ abstract class ElectrumWalletBase
@action
@override
Future<void> rescan({required int height, int? chainTip, ScanData? scanData}) async {
Future<void> rescan(
{required int height, int? chainTip, ScanData? scanData, bool? doSingleScan}) async {
silentPaymentsScanningActive = true;
_setListeners(height);
_setListeners(height, doSingleScan: doSingleScan);
}
@override
@ -1606,6 +1608,7 @@ class ScanData {
final ElectrumClient electrumClient;
final List<String> transactionHistoryIds;
final Map<String, String> labels;
final bool isSingleScan;
ScanData({
required this.sendPort,
@ -1617,6 +1620,7 @@ class ScanData {
required this.electrumClient,
required this.transactionHistoryIds,
required this.labels,
required this.isSingleScan,
});
factory ScanData.fromHeight(ScanData scanData, int newHeight) {
@ -1630,6 +1634,7 @@ class ScanData {
transactionHistoryIds: scanData.transactionHistoryIds,
electrumClient: scanData.electrumClient,
labels: scanData.labels,
isSingleScan: scanData.isSingleScan,
);
}
}
@ -1689,11 +1694,17 @@ Future<void> startRefresh(ScanData scanData) async {
while (true) {
lastKnownBlockHeight = syncHeight;
final syncingStatus =
SyncingSyncStatus.fromHeightValues(currentChainTip, initialSyncHeight, syncHeight);
SyncingSyncStatus syncingStatus;
if (scanData.isSingleScan) {
syncingStatus = SyncingSyncStatus(1, 0);
} else {
syncingStatus =
SyncingSyncStatus.fromHeightValues(currentChainTip, initialSyncHeight, syncHeight);
}
scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
if (syncingStatus.blocksLeft <= 0) {
if (syncingStatus.blocksLeft <= 0 || (scanData.isSingleScan && scanData.height != syncHeight)) {
scanData.sendPort.send(SyncResponse(currentChainTip, SyncedSyncStatus()));
return;
}
@ -1701,7 +1712,8 @@ Future<void> startRefresh(ScanData scanData) async {
try {
final electrumClient = await getElectrumConnection();
final scanningBlockCount = scanData.network == BitcoinNetwork.testnet ? 50 : 10;
final scanningBlockCount =
scanData.isSingleScan ? 1 : (scanData.network == BitcoinNetwork.testnet ? 1 : 10);
Map<String, dynamic>? tweaks;
try {
@ -1743,8 +1755,7 @@ Future<void> startRefresh(ScanData scanData) async {
scanData.silentAddress.b_scan,
scanData.silentAddress.B_spend,
outputPubkeys.values
.map((o) => getScriptFromOutput(
o["pubkey"].toString(), int.parse(o["amount"].toString())))
.map((o) => getScriptFromOutput(o[0].toString(), int.parse(o[1].toString())))
.toList(),
precomputedLabels: scanData.labels,
);
@ -1770,9 +1781,9 @@ Future<void> startRefresh(ScanData scanData) async {
int? amount;
int? pos;
outputPubkeys.entries.firstWhere((k) {
final matches = k.value["pubkey"] == key;
final matches = k.value[0] == key;
if (matches) {
amount = int.parse(k.value["amount"].toString());
amount = int.parse(k.value[1].toString());
pos = int.parse(k.key.toString());
return true;
}

View file

@ -242,3 +242,32 @@ Future<int> getHavenCurrentHeight() async {
throw Exception('Failed to load current blockchain height');
}
}
// Data taken from https://timechaincalendar.com/
const bitcoinDates = {
"2024-04": 837182,
"2024-03": 832623,
"2024-02": 828319,
"2024-01": 823807,
"2023-12": 819206,
"2023-11": 814765,
"2023-10": 810098,
"2023-09": 805675,
"2023-08": 801140,
"2023-07": 796640,
"2023-06": 792330,
"2023-05": 787733,
"2023-04": 783403,
"2023-03": 778740,
"2023-02": 774525,
"2023-01": 769810,
};
int getBitcoinHeightByDate({required DateTime date}) {
String closestKey =
bitcoinDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
final oldestHeight = bitcoinDates.values.last;
return bitcoinDates[closestKey] ?? oldestHeight;
}

View file

@ -335,4 +335,12 @@ class CWBitcoin extends Bitcoin {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.isTestnet ?? false;
}
@override
int getHeightByDate({required DateTime date}) => getBitcoinHeightByDate(date: date);
void rescan(Object wallet, {required int height, bool? doSingleScan}) {
final bitcoinWallet = wallet as ElectrumWallet;
bitcoinWallet.rescan(height: height, doSingleScan: doSingleScan);
}
}

View file

@ -21,11 +21,15 @@ class RescanPage extends BasePage {
return Padding(
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
child: Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
BlockchainHeightWidget(
key: _blockchainHeightWidgetKey,
onHeightOrDateEntered: (value) => _rescanViewModel.isButtonEnabled = value,
isSilentPaymentsScan: _rescanViewModel.isSilentPaymentsScan,
),
Observer(
builder: (_) => BlockchainHeightWidget(
key: _blockchainHeightWidgetKey,
onHeightOrDateEntered: (value) => _rescanViewModel.isButtonEnabled = value,
isSilentPaymentsScan: _rescanViewModel.isSilentPaymentsScan,
doSingleScan: _rescanViewModel.doSingleScan,
toggleSingleScan: () =>
_rescanViewModel.doSingleScan = !_rescanViewModel.doSingleScan,
)),
Observer(
builder: (_) => LoadingPrimaryButton(
isLoading: _rescanViewModel.state == RescanWalletState.rescaning,

View file

@ -1,3 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/src/widgets/standard_switch.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/utils/date_picker.dart';
import 'package:flutter/material.dart';
@ -14,6 +16,8 @@ class BlockchainHeightWidget extends StatefulWidget {
this.onHeightOrDateEntered,
this.hasDatePicker = true,
this.isSilentPaymentsScan = false,
this.toggleSingleScan,
this.doSingleScan = false,
}) : super(key: key);
final Function(int)? onHeightChange;
@ -21,6 +25,8 @@ class BlockchainHeightWidget extends StatefulWidget {
final FocusNode? focusNode;
final bool hasDatePicker;
final bool isSilentPaymentsScan;
final bool doSingleScan;
final Function()? toggleSingleScan;
@override
State<StatefulWidget> createState() => BlockchainHeightState();
@ -101,6 +107,30 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
))
],
),
if (widget.isSilentPaymentsScan)
Padding(
padding: EdgeInsets.only(top: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
S.of(context).scan_one_block,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
Padding(
padding: const EdgeInsets.only(right: 8),
child: StandardSwitch(
value: widget.doSingleScan,
onTaped: () => widget.toggleSingleScan?.call(),
),
)
],
),
),
Padding(
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
child: Text(
@ -126,7 +156,12 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
lastDate: now);
if (date != null) {
final height = monero!.getHeightByDate(date: date);
int height;
if (widget.isSilentPaymentsScan) {
height = bitcoin!.getHeightByDate(date: date);
} else {
height = monero!.getHeightByDate(date: date);
}
setState(() {
dateController.text = DateFormat('yyyy-MM-dd').format(date);
restoreHeightController.text = '$height';

View file

@ -12,7 +12,8 @@ enum RescanWalletState { rescaning, none }
abstract class RescanViewModelBase with Store {
RescanViewModelBase(this._wallet)
: state = RescanWalletState.none,
isButtonEnabled = false;
isButtonEnabled = false,
doSingleScan = false;
final WalletBase _wallet;
@ -22,14 +23,21 @@ abstract class RescanViewModelBase with Store {
@observable
bool isButtonEnabled;
@observable
bool doSingleScan;
@computed
bool get isSilentPaymentsScan => bitcoin!.hasSelectedSilentPayments(_wallet);
bool get isSilentPaymentsScan => _wallet.type == WalletType.bitcoin;
@action
Future<void> rescanCurrentWallet({required int restoreHeight}) async {
state = RescanWalletState.rescaning;
_wallet.rescan(height: restoreHeight);
if (_wallet.type != WalletType.bitcoin) _wallet.transactionHistory.clear();
if (_wallet.type != WalletType.bitcoin) {
_wallet.rescan(height: restoreHeight);
_wallet.transactionHistory.clear();
} else {
bitcoin!.rescan(_wallet, height: restoreHeight, doSingleScan: doSingleScan);
}
state = RescanWalletState.none;
}
}

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "حفظ كلمة المرور الاحتياطية",
"save_to_downloads": "ﺕﻼﻳﺰﻨﺘﻟﺍ ﻲﻓ ﻆﻔﺣ",
"saved_the_trade_id": "لقد تم حفظ معرف العملية",
"scan_one_block": "مسح كتلة واحدة",
"scan_qr_code": "امسح رمز QR ضوئيًا",
"scan_qr_code_to_get_address": "امسح ال QR للحصول على العنوان",
"scan_qr_on_device": " ﺮﺧﺁ ﺯﺎﻬﺟ ﻰﻠﻋ ﺎﻴًﺋﻮﺿ ﺍﺬﻫ ﺔﻌﻳﺮﺴﻟﺍ ﺔﺑﺎﺠﺘﺳﻻﺍ ﺰﻣﺭ ﺢﺴﻤﺑ ﻢﻗ",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Запазване на паролата за възстановяване",
"save_to_downloads": "Запазване в Изтегляния",
"saved_the_trade_id": "Запазих trade ID-то",
"scan_one_block": "Сканирайте един блок",
"scan_qr_code": "Сканирайте QR кода, за да получите адреса",
"scan_qr_code_to_get_address": "Сканирайте QR кода, за да получите адреса",
"scan_qr_on_device": "Сканирайте този QR код на друго устройство",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Uložit heslo pro zálohy",
"save_to_downloads": "Uložit do Stažených souborů",
"saved_the_trade_id": "Uložil jsem si ID transakce (trade ID)",
"scan_one_block": "Prohledejte jeden blok",
"scan_qr_code": "Naskenujte QR kód pro získání adresy",
"scan_qr_code_to_get_address": "Prohledejte QR kód a získejte adresu",
"scan_qr_on_device": "Naskenujte tento QR kód na jiném zařízení",

View file

@ -512,6 +512,7 @@
"save_backup_password_alert": "Sicherungskennwort speichern",
"save_to_downloads": "Unter „Downloads“ speichern",
"saved_the_trade_id": "Ich habe die Handels-ID gespeichert",
"scan_one_block": "Einen Block scannen",
"scan_qr_code": "QR-Code scannen",
"scan_qr_code_to_get_address": "Scannen Sie den QR-Code, um die Adresse zu erhalten",
"scan_qr_on_device": "Scannen Sie diesen QR-Code auf einem anderen Gerät",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Save backup password",
"save_to_downloads": "Save to Downloads",
"saved_the_trade_id": "I've saved the trade ID",
"scan_one_block": "Scan one block",
"scan_qr_code": "Scan QR code",
"scan_qr_code_to_get_address": "Scan the QR code to get the address",
"scan_qr_on_device": "Scan this QR code on another device",

View file

@ -512,6 +512,7 @@
"save_backup_password_alert": "Guardar contraseña de respaldo",
"save_to_downloads": "Guardar en Descargas",
"saved_the_trade_id": "He salvado comercial ID",
"scan_one_block": "Escanear un bloque",
"scan_qr_code": "Escanear código QR",
"scan_qr_code_to_get_address": "Escanee el código QR para obtener la dirección",
"scan_qr_on_device": "Escanea este código QR en otro dispositivo",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Enregistrer le mot de passe de sauvegarde",
"save_to_downloads": "Enregistrer dans les téléchargements",
"saved_the_trade_id": "J'ai sauvegardé l'ID d'échange",
"scan_one_block": "Scanner un bloc",
"scan_qr_code": "Scannez le QR code",
"scan_qr_code_to_get_address": "Scannez le QR code pour obtenir l'adresse",
"scan_qr_on_device": "Scannez ce code QR sur un autre appareil",

View file

@ -513,6 +513,7 @@
"save_backup_password_alert": "Ajiye kalmar sirri ta ajiya",
"save_to_downloads": "Ajiye zuwa Zazzagewa",
"saved_the_trade_id": "Na ajiye ID na ciniki",
"scan_one_block": "Duba toshe daya",
"scan_qr_code": "Gani QR kodin",
"scan_qr_code_to_get_address": "Duba lambar QR don samun adireshin",
"scan_qr_on_device": "Duba wannan lambar QR akan wata na'ura",

View file

@ -513,6 +513,7 @@
"save_backup_password_alert": "बैकअप पासवर्ड सेव करें",
"save_to_downloads": "डाउनलोड में सहेजें",
"saved_the_trade_id": "मैंने व्यापार बचा लिया है ID",
"scan_one_block": "एक ब्लॉक को स्कैन करना",
"scan_qr_code": "स्कैन क्यू आर कोड",
"scan_qr_code_to_get_address": "पता प्राप्त करने के लिए QR कोड स्कैन करें",
"scan_qr_on_device": "इस QR कोड को किसी अन्य डिवाइस पर स्कैन करें",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Spremi lozinku za sigurnosnu kopiju",
"save_to_downloads": "Spremi u Preuzimanja",
"saved_the_trade_id": "Spremio/la sam transakcijski ID",
"scan_one_block": "Skenirajte jedan blok",
"scan_qr_code": "Skenirajte QR kod",
"scan_qr_code_to_get_address": "Skeniraj QR kod za dobivanje adrese",
"scan_qr_on_device": "Skenirajte ovaj QR kod na drugom uređaju",

View file

@ -514,6 +514,7 @@
"save_backup_password_alert": "Simpan kata sandi cadangan",
"save_to_downloads": "Simpan ke Unduhan",
"saved_the_trade_id": "Saya telah menyimpan ID perdagangan",
"scan_one_block": "Pindai satu blok",
"scan_qr_code": "Scan kode QR untuk mendapatkan alamat",
"scan_qr_code_to_get_address": "Pindai kode QR untuk mendapatkan alamat",
"scan_qr_on_device": "Pindai kode QR ini di perangkat lain",

View file

@ -513,6 +513,7 @@
"save_backup_password_alert": "Salva password Backup",
"save_to_downloads": "Salva in Download",
"saved_the_trade_id": "Ho salvato l'ID dello scambio",
"scan_one_block": "Scansionare un blocco",
"scan_qr_code": "Scansiona il codice QR",
"scan_qr_code_to_get_address": "Scansiona il codice QR per ottenere l'indirizzo",
"scan_qr_on_device": "Scansiona questo codice QR su un altro dispositivo",

View file

@ -512,6 +512,7 @@
"save_backup_password_alert": "バックアップパスワードを保存する",
"save_to_downloads": "ダウンロードに保存",
"saved_the_trade_id": "取引IDを保存しました",
"scan_one_block": "1つのブロックをスキャンします",
"scan_qr_code": "QRコードをスキャン",
"scan_qr_code_to_get_address": "QRコードをスキャンして住所を取得します",
"scan_qr_on_device": "別のデバイスでこの QR コードをスキャンします",

View file

@ -512,6 +512,7 @@
"save_backup_password_alert": "백업 비밀번호 저장",
"save_to_downloads": "다운로드에 저장",
"saved_the_trade_id": "거래 ID를 저장했습니다",
"scan_one_block": "하나의 블록을 스캔하십시오",
"scan_qr_code": "QR 코드 스캔",
"scan_qr_code_to_get_address": "QR 코드를 스캔하여 주소를 얻습니다.",
"scan_qr_on_device": "다른 기기에서 이 QR 코드를 스캔하세요.",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "အရန်စကားဝှက်ကို သိမ်းဆည်းပါ။",
"save_to_downloads": "ဒေါင်းလုဒ်များထံ သိမ်းဆည်းပါ။",
"saved_the_trade_id": "ကုန်သွယ်မှု ID ကို သိမ်းဆည်းပြီးပါပြီ။",
"scan_one_block": "တစ်ကွက်ကိုစကင်ဖတ်စစ်ဆေးပါ",
"scan_qr_code": "QR ကုဒ်ကို စကင်န်ဖတ်ပါ။",
"scan_qr_code_to_get_address": "လိပ်စာရယူရန် QR ကုဒ်ကို စကင်န်ဖတ်ပါ။",
"scan_qr_on_device": "အခြားစက်တွင် ဤ QR ကုဒ်ကို စကင်ဖတ်ပါ။",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Bewaar back-upwachtwoord",
"save_to_downloads": "Opslaan in downloads",
"saved_the_trade_id": "Ik heb de ruil-ID opgeslagen",
"scan_one_block": "Scan een blok",
"scan_qr_code": "Scan QR-code",
"scan_qr_code_to_get_address": "Scan de QR-code om het adres te krijgen",
"scan_qr_on_device": "Scan deze QR-code op een ander apparaat",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Zapisz hasło kopii zapasowej",
"save_to_downloads": "Zapisz w Pobranych",
"saved_the_trade_id": "Zapisałem ID",
"scan_one_block": "Zeskanuj jeden blok",
"scan_qr_code": "Skanowania QR code",
"scan_qr_code_to_get_address": "Zeskanuj kod QR, aby uzyskać adres",
"scan_qr_on_device": "Zeskanuj ten kod QR na innym urządzeniu",

View file

@ -513,6 +513,7 @@
"save_backup_password_alert": "Salvar senha de backup",
"save_to_downloads": "Salvar em Downloads",
"saved_the_trade_id": "ID da troca salvo",
"scan_one_block": "Escanear um bloco",
"scan_qr_code": "Escanear código QR",
"scan_qr_code_to_get_address": "Digitalize o código QR para obter o endereço",
"scan_qr_on_device": "Digitalize este código QR em outro dispositivo",
@ -624,7 +625,7 @@
"silent_payments": "Pagamentos silenciosos",
"silent_payments_disclaimer": "Novos endereços não são novas identidades. É uma reutilização de uma identidade existente com um rótulo diferente.",
"silent_payments_scan_from_date": "Escanear a partir da data",
"silent_payments_scan_from_date_or_blockheight": "Por favor, insira a altura do bloco que deseja iniciar o escaneamento para obter pagamentos silenciosos ou use a data. Você pode escolher se a carteira continua digitalizando cada bloco ou verifica apenas a altura especificada.",
"silent_payments_scan_from_date_or_blockheight": "Por favor, insira a altura do bloco que deseja iniciar o escaneamento para obter pagamentos silenciosos ou use a data. Você pode escolher se a carteira continua escaneando cada bloco ou verifica apenas a altura especificada.",
"silent_payments_scan_from_height": "Escanear a partir da altura do bloco",
"silent_payments_scanning": "Escanear Pagamentos Silenciosos",
"slidable": "Deslizável",
@ -823,4 +824,4 @@
"you_will_get": "Converter para",
"you_will_send": "Converter de",
"yy": "aa"
}
}

View file

@ -512,6 +512,7 @@
"save_backup_password_alert": "Сохранить пароль резервной копии",
"save_to_downloads": "Сохранить в загрузках",
"saved_the_trade_id": "Я сохранил ID сделки",
"scan_one_block": "Сканируйте один блок",
"scan_qr_code": "Сканировать QR-код",
"scan_qr_code_to_get_address": "Отсканируйте QR-код для получения адреса",
"scan_qr_on_device": "Отсканируйте этот QR-код на другом устройстве",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "บันทึกรหัสผ่านสำรอง",
"save_to_downloads": "บันทึกลงดาวน์โหลด",
"saved_the_trade_id": "ฉันได้บันทึก ID ของการซื้อขายแล้ว",
"scan_one_block": "สแกนหนึ่งบล็อก",
"scan_qr_code": "สแกนรหัส QR",
"scan_qr_code_to_get_address": "สแกน QR code เพื่อรับที่อยู่",
"scan_qr_on_device": "สแกนโค้ด QR นี้บนอุปกรณ์อื่น",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "I -save ang backup password",
"save_to_downloads": "I -save sa mga pag -download",
"saved_the_trade_id": "Nai -save ko ang trade ID",
"scan_one_block": "I -scan ang isang bloke",
"scan_qr_code": "I -scan ang QR Code",
"scan_qr_code_to_get_address": "I -scan ang QR code upang makuha ang address",
"scan_qr_on_device": "I-scan ang QR code na ito sa ibang device",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "Yedek parolasını kaydet",
"save_to_downloads": "İndirilenlere Kaydet",
"saved_the_trade_id": "Takas ID'imi kaydettim",
"scan_one_block": "Bir bloğu tara",
"scan_qr_code": "QR kodunu tarayın",
"scan_qr_code_to_get_address": "Adresi getirmek için QR kodunu tara",
"scan_qr_on_device": "Bu QR kodunu başka bir cihazda tarayın",

View file

@ -512,6 +512,7 @@
"save_backup_password_alert": "Зберегти пароль резервної копії",
"save_to_downloads": "Зберегти до завантажень",
"saved_the_trade_id": "Я зберіг ID операції",
"scan_one_block": "Сканувати один блок",
"scan_qr_code": "Відскануйте QR-код",
"scan_qr_code_to_get_address": "Скануйте QR-код для одержання адреси",
"scan_qr_on_device": "Відскануйте цей QR-код на іншому пристрої",

View file

@ -513,6 +513,7 @@
"save_backup_password_alert": "بیک اپ پاس ورڈ محفوظ کریں۔",
"save_to_downloads": "۔ﮟﯾﺮﮐ ﻅﻮﻔﺤﻣ ﮟﯿﻣ ﺯﮈﻮﻟ ﻥﺅﺍﮈ",
"saved_the_trade_id": "میں نے تجارتی ID محفوظ کر لی ہے۔",
"scan_one_block": "ایک بلاک اسکین کریں",
"scan_qr_code": "پتہ حاصل کرنے کے لیے QR کوڈ اسکین کریں۔",
"scan_qr_code_to_get_address": "پتہ حاصل کرنے کے لئے QR کوڈ کو اسکین کریں",
"scan_qr_on_device": " ۔ﮟﯾﺮﮐ ﻦﯿﮑﺳﺍ ﺮﭘ ﺲﺋﺍﻮﯾﮈ ﺭﻭﺍ ﯽﺴﮐ ﻮﮐ ﮈﻮﮐ QR ﺱﺍ",

View file

@ -512,6 +512,7 @@
"save_backup_password_alert": "Pamọ́ ọ̀rọ̀ aṣínà ti ẹ̀dà",
"save_to_downloads": "Fipamọ si Awọn igbasilẹ",
"saved_the_trade_id": "Mo ti pamọ́ àmì ìdánimọ̀ pàṣípààrọ̀",
"scan_one_block": "Ọlọjẹ ọkan bulọki",
"scan_qr_code": "Yan QR koodu",
"scan_qr_code_to_get_address": "Ṣayẹwo koodu QR naa lati gba adirẹsi naa",
"scan_qr_on_device": "Ṣe ayẹwo koodu QR yii lori ẹrọ miiran",

View file

@ -511,6 +511,7 @@
"save_backup_password_alert": "保存备份密码",
"save_to_downloads": "保存到下载",
"saved_the_trade_id": "我已经保存了交易编号",
"scan_one_block": "扫描一个街区",
"scan_qr_code": "扫描二维码",
"scan_qr_code_to_get_address": "扫描二维码获取地址",
"scan_qr_on_device": "在另一台设备上扫描此二维码",

View file

@ -87,7 +87,7 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
import 'package:cw_bitcoin/litecoin_wallet_service.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
import 'package:cw_core/get_height_by_date.dart';
import 'package:mobx/mobx.dart';
""";
const bitcoinCwPart = "part 'cw_bitcoin.dart';";
@ -167,6 +167,8 @@ abstract class Bitcoin {
Future<bool> isChangeSufficientForFee(Object wallet, String txId, String newFee);
int getFeeAmountForPriority(Object wallet, TransactionPriority priority, int inputsCount, int outputsCount, {int? size});
int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size});
int getHeightByDate({required DateTime date});
void rescan(Object wallet, {required int height, bool? doSingleScan});
}
""";