From 9af37ac96fc319c6e5135d7317becc394744b6ea Mon Sep 17 00:00:00 2001 From: Serhii Date: Mon, 28 Aug 2023 15:45:31 +0300 Subject: [PATCH] minor fix --- .../lib/bitcoin_transaction_priority.dart | 51 +++++++++++++++++++ .../lib/src/bitcoin_cash_wallet.dart | 48 ++++++++++++----- .../unspent_coins_details_view_model.dart | 2 +- 3 files changed, 88 insertions(+), 13 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_transaction_priority.dart b/cw_bitcoin/lib/bitcoin_transaction_priority.dart index d82ea429e..47ca23690 100644 --- a/cw_bitcoin/lib/bitcoin_transaction_priority.dart +++ b/cw_bitcoin/lib/bitcoin_transaction_priority.dart @@ -100,4 +100,55 @@ class LitecoinTransactionPriority extends BitcoinTransactionPriority { return label; } + } +class BitcoinCashTransactionPriority extends BitcoinTransactionPriority { + const BitcoinCashTransactionPriority({required String title, required int raw}) + : super(title: title, raw: raw); + + static const List all = [fast, medium, slow]; + static const BitcoinCashTransactionPriority slow = + BitcoinCashTransactionPriority(title: 'Slow', raw: 0); + static const BitcoinCashTransactionPriority medium = + BitcoinCashTransactionPriority(title: 'Medium', raw: 1); + static const BitcoinCashTransactionPriority fast = + BitcoinCashTransactionPriority(title: 'Fast', raw: 2); + + static BitcoinCashTransactionPriority deserialize({required int raw}) { + switch (raw) { + case 0: + return slow; + case 1: + return medium; + case 2: + return fast; + default: + throw Exception('Unexpected token: $raw for LitecoinTransactionPriority deserialize'); + } + } + + @override + String get units => 'Latoshi'; + + @override + String toString() { + var label = ''; + + switch (this) { + case BitcoinCashTransactionPriority.slow: + label = 'Slow'; // S.current.transaction_priority_slow; + break; + case BitcoinCashTransactionPriority.medium: + label = 'Medium'; // S.current.transaction_priority_medium; + break; + case BitcoinCashTransactionPriority.fast: + label = 'Fast'; // S.current.transaction_priority_fast; + break; + default: + break; + } + + return label; + } +} + diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart index 1a02c7cff..61a492c47 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart @@ -2,6 +2,8 @@ import 'package:bitbox/bitbox.dart' as bitbox; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; +import 'package:cw_bitcoin/bitcoin_transaction_no_inputs_exception.dart'; +import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/electrum_wallet.dart'; @@ -105,26 +107,41 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { @override Future createTransaction(Object credentials) async { - final _wallet = hd; + const minAmount = 546; final transactionCredentials = credentials as BitcoinTransactionCredentials; - final utxosToUse = unspentCoins.where((element) => element.isSending).toList(); + final outputs = transactionCredentials.outputs; + final hasMultiDestination = outputs.length > 1; final builder = bitbox.Bitbox.transactionBuilder(testnet: false); - int totalBalance = 0; + var allInputsAmount = 0; + var inputs = []; + + if (unspentCoins.isEmpty) await updateUnspent(); + + inputs = unspentCoins.where((element) => element.isSending).toList(); + allInputsAmount = inputs.fold(0, (prev, element) => prev + element.value); + + if (inputs.isEmpty) throw BitcoinTransactionNoInputsException(); + + inputs.forEach((BitcoinUnspent utx) => builder.addInput(utx.hash, utx.vout)); + + final allAmountFee = transactionCredentials.feeRate != null + ? feeAmountWithFeeRate(transactionCredentials.feeRate!, inputs.length, outputs.length) + : feeAmountForPriority(transactionCredentials.priority!, inputs.length, outputs.length); + + final allAmount = allInputsAmount - allAmountFee; + + + //allInputsAmount - transactionCredentials.outputs.fold(0, (prev, element) => prev + element.value); -// Add all inputs - utxosToUse.forEach((BitcoinUnspent utxo) { - builder.addInput(utxo.hash, utxo.vout); - totalBalance += utxo.value; - }); // Calculate the amount to send and change final sendAmount = transactionCredentials.outputs[0].formattedCryptoAmount!; final outputAddress = transactionCredentials.outputs[0].isParsedAddress ? transactionCredentials.outputs[0].extractedAddress : transactionCredentials.outputs[0].address; - final fee = bitbox.BitcoinCash.getByteCount(utxosToUse.length, 2); - final changeAmount = totalBalance - sendAmount - fee; + final fee = bitbox.BitcoinCash.getByteCount(inputs.length, 2); + final changeAmount = allInputsAmount - sendAmount - fee; // Add output for the recipient builder.addOutput(outputAddress, sendAmount); @@ -136,8 +153,8 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { } // Sign all inputs after adding all outputs - for (var i = 0; i < utxosToUse.length; i++) { - final input = utxosToUse[i]; + for (var i = 0; i < inputs.length; i++) { + final input = inputs[i]; final keyPair = generateKeyPair( hd: input.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, index: input.bitcoinAddressRecord.index, @@ -157,4 +174,11 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { required int index, required bitcoin.NetworkType network}) => bitbox.ECPair.fromWIF(hd.derive(index).wif!); + + @override + int feeAmountForPriority(BitcoinTransactionPriority priority, int inputsCount, int outputsCount) => + feeRate(priority) * bitbox.BitcoinCash.getByteCount(inputsCount, outputsCount); + + int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount) => + feeRate * bitbox.BitcoinCash.getByteCount(inputsCount, outputsCount); } diff --git a/lib/view_model/unspent_coins/unspent_coins_details_view_model.dart b/lib/view_model/unspent_coins/unspent_coins_details_view_model.dart index 955383cf6..1892504f2 100644 --- a/lib/view_model/unspent_coins/unspent_coins_details_view_model.dart +++ b/lib/view_model/unspent_coins/unspent_coins_details_view_model.dart @@ -46,7 +46,7 @@ abstract class UnspentCoinsDetailsViewModelBase with Store { }) ]; - if ([WalletType.bitcoin, WalletType.litecoin].contains(unspentCoinsListViewModel.wallet.type)) { + if ([WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(unspentCoinsListViewModel.wallet.type)) { items.add(BlockExplorerListItem( title: S.current.view_in_block_explorer, value: _explorerDescription(unspentCoinsListViewModel.wallet.type),