mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-16 17:27:37 +00:00
Electrum enhancements (#1794)
* Enhance the code for sending/sending-ALL for Electrum * remove prints [skip ci]
This commit is contained in:
parent
0fcfd76afd
commit
389c334f10
2 changed files with 63 additions and 100 deletions
|
@ -11,7 +11,6 @@ import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cw_bitcoin/address_from_output.dart';
|
import 'package:cw_bitcoin/address_from_output.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||||
|
@ -597,8 +596,8 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
UtxoDetails _createUTXOS({
|
UtxoDetails _createUTXOS({
|
||||||
required bool sendAll,
|
required bool sendAll,
|
||||||
required int credentialsAmount,
|
|
||||||
required bool paysToSilentPayment,
|
required bool paysToSilentPayment,
|
||||||
|
int credentialsAmount = 0,
|
||||||
int? inputsCount,
|
int? inputsCount,
|
||||||
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
||||||
}) {
|
}) {
|
||||||
|
@ -732,13 +731,11 @@ abstract class ElectrumWalletBase
|
||||||
List<BitcoinOutput> outputs,
|
List<BitcoinOutput> outputs,
|
||||||
int feeRate, {
|
int feeRate, {
|
||||||
String? memo,
|
String? memo,
|
||||||
int credentialsAmount = 0,
|
|
||||||
bool hasSilentPayment = false,
|
bool hasSilentPayment = false,
|
||||||
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
||||||
}) async {
|
}) async {
|
||||||
final utxoDetails = _createUTXOS(
|
final utxoDetails = _createUTXOS(
|
||||||
sendAll: true,
|
sendAll: true,
|
||||||
credentialsAmount: credentialsAmount,
|
|
||||||
paysToSilentPayment: hasSilentPayment,
|
paysToSilentPayment: hasSilentPayment,
|
||||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||||
);
|
);
|
||||||
|
@ -764,23 +761,11 @@ abstract class ElectrumWalletBase
|
||||||
throw BitcoinTransactionWrongBalanceException(amount: utxoDetails.allInputsAmount + fee);
|
throw BitcoinTransactionWrongBalanceException(amount: utxoDetails.allInputsAmount + fee);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount <= 0) {
|
|
||||||
throw BitcoinTransactionWrongBalanceException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempting to send less than the dust limit
|
// Attempting to send less than the dust limit
|
||||||
if (_isBelowDust(amount)) {
|
if (_isBelowDust(amount)) {
|
||||||
throw BitcoinTransactionNoDustException();
|
throw BitcoinTransactionNoDustException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (credentialsAmount > 0) {
|
|
||||||
final amountLeftForFee = amount - credentialsAmount;
|
|
||||||
if (amountLeftForFee > 0 && _isBelowDust(amountLeftForFee)) {
|
|
||||||
amount -= amountLeftForFee;
|
|
||||||
fee += amountLeftForFee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputs.length == 1) {
|
if (outputs.length == 1) {
|
||||||
outputs[0] = BitcoinOutput(address: outputs.last.address, value: BigInt.from(amount));
|
outputs[0] = BitcoinOutput(address: outputs.last.address, value: BigInt.from(amount));
|
||||||
}
|
}
|
||||||
|
@ -810,6 +795,11 @@ abstract class ElectrumWalletBase
|
||||||
bool hasSilentPayment = false,
|
bool hasSilentPayment = false,
|
||||||
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
||||||
}) async {
|
}) async {
|
||||||
|
// Attempting to send less than the dust limit
|
||||||
|
if (_isBelowDust(credentialsAmount)) {
|
||||||
|
throw BitcoinTransactionNoDustException();
|
||||||
|
}
|
||||||
|
|
||||||
final utxoDetails = _createUTXOS(
|
final utxoDetails = _createUTXOS(
|
||||||
sendAll: false,
|
sendAll: false,
|
||||||
credentialsAmount: credentialsAmount,
|
credentialsAmount: credentialsAmount,
|
||||||
|
@ -894,7 +884,43 @@ abstract class ElectrumWalletBase
|
||||||
final lastOutput = updatedOutputs.last;
|
final lastOutput = updatedOutputs.last;
|
||||||
final amountLeftForChange = amountLeftForChangeAndFee - fee;
|
final amountLeftForChange = amountLeftForChangeAndFee - fee;
|
||||||
|
|
||||||
if (!_isBelowDust(amountLeftForChange)) {
|
if (_isBelowDust(amountLeftForChange)) {
|
||||||
|
// If has change that is lower than dust, will end up with tx rejected by network rules
|
||||||
|
// so remove the change amount
|
||||||
|
updatedOutputs.removeLast();
|
||||||
|
outputs.removeLast();
|
||||||
|
|
||||||
|
if (amountLeftForChange < 0) {
|
||||||
|
if (!spendingAllCoins) {
|
||||||
|
return estimateTxForAmount(
|
||||||
|
credentialsAmount,
|
||||||
|
outputs,
|
||||||
|
updatedOutputs,
|
||||||
|
feeRate,
|
||||||
|
inputsCount: utxoDetails.utxos.length + 1,
|
||||||
|
memo: memo,
|
||||||
|
useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
|
||||||
|
hasSilentPayment: hasSilentPayment,
|
||||||
|
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw BitcoinTransactionWrongBalanceException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EstimatedTxResult(
|
||||||
|
utxos: utxoDetails.utxos,
|
||||||
|
inputPrivKeyInfos: utxoDetails.inputPrivKeyInfos,
|
||||||
|
publicKeys: utxoDetails.publicKeys,
|
||||||
|
fee: fee,
|
||||||
|
amount: amount,
|
||||||
|
hasChange: false,
|
||||||
|
isSendAll: spendingAllCoins,
|
||||||
|
memo: memo,
|
||||||
|
spendsUnconfirmedTX: utxoDetails.spendsUnconfirmedTX,
|
||||||
|
spendsSilentPayment: utxoDetails.spendsSilentPayment,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
// Here, lastOutput already is change, return the amount left without the fee to the user's address.
|
// Here, lastOutput already is change, return the amount left without the fee to the user's address.
|
||||||
updatedOutputs[updatedOutputs.length - 1] = BitcoinOutput(
|
updatedOutputs[updatedOutputs.length - 1] = BitcoinOutput(
|
||||||
address: lastOutput.address,
|
address: lastOutput.address,
|
||||||
|
@ -908,75 +934,6 @@ abstract class ElectrumWalletBase
|
||||||
isSilentPayment: lastOutput.isSilentPayment,
|
isSilentPayment: lastOutput.isSilentPayment,
|
||||||
isChange: true,
|
isChange: true,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
// If has change that is lower than dust, will end up with tx rejected by network rules, so estimate again without the added change
|
|
||||||
updatedOutputs.removeLast();
|
|
||||||
outputs.removeLast();
|
|
||||||
|
|
||||||
// Still has inputs to spend before failing
|
|
||||||
if (!spendingAllCoins) {
|
|
||||||
return estimateTxForAmount(
|
|
||||||
credentialsAmount,
|
|
||||||
outputs,
|
|
||||||
updatedOutputs,
|
|
||||||
feeRate,
|
|
||||||
inputsCount: utxoDetails.utxos.length + 1,
|
|
||||||
memo: memo,
|
|
||||||
hasSilentPayment: hasSilentPayment,
|
|
||||||
useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
|
|
||||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final estimatedSendAll = await estimateSendAllTx(
|
|
||||||
updatedOutputs,
|
|
||||||
feeRate,
|
|
||||||
memo: memo,
|
|
||||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (estimatedSendAll.amount == credentialsAmount) {
|
|
||||||
return estimatedSendAll;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Estimate to user how much is needed to send to cover the fee
|
|
||||||
final maxAmountWithReturningChange = utxoDetails.allInputsAmount - _dustAmount - fee - 1;
|
|
||||||
throw BitcoinTransactionNoDustOnChangeException(
|
|
||||||
bitcoinAmountToString(amount: maxAmountWithReturningChange),
|
|
||||||
bitcoinAmountToString(amount: estimatedSendAll.amount),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempting to send less than the dust limit
|
|
||||||
if (_isBelowDust(amount)) {
|
|
||||||
throw BitcoinTransactionNoDustException();
|
|
||||||
}
|
|
||||||
|
|
||||||
final totalAmount = amount + fee;
|
|
||||||
|
|
||||||
if (totalAmount > (balance[currency]!.confirmed + balance[currency]!.secondConfirmed)) {
|
|
||||||
throw BitcoinTransactionWrongBalanceException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalAmount > utxoDetails.allInputsAmount) {
|
|
||||||
if (spendingAllCoins) {
|
|
||||||
throw BitcoinTransactionWrongBalanceException();
|
|
||||||
} else {
|
|
||||||
updatedOutputs.removeLast();
|
|
||||||
outputs.removeLast();
|
|
||||||
return estimateTxForAmount(
|
|
||||||
credentialsAmount,
|
|
||||||
outputs,
|
|
||||||
updatedOutputs,
|
|
||||||
feeRate,
|
|
||||||
inputsCount: utxoDetails.utxos.length + 1,
|
|
||||||
memo: memo,
|
|
||||||
useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
|
|
||||||
hasSilentPayment: hasSilentPayment,
|
|
||||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EstimatedTxResult(
|
return EstimatedTxResult(
|
||||||
utxos: utxoDetails.utxos,
|
utxos: utxoDetails.utxos,
|
||||||
|
@ -985,12 +942,13 @@ abstract class ElectrumWalletBase
|
||||||
fee: fee,
|
fee: fee,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
hasChange: true,
|
hasChange: true,
|
||||||
isSendAll: false,
|
isSendAll: spendingAllCoins,
|
||||||
memo: memo,
|
memo: memo,
|
||||||
spendsUnconfirmedTX: utxoDetails.spendsUnconfirmedTX,
|
spendsUnconfirmedTX: utxoDetails.spendsUnconfirmedTX,
|
||||||
spendsSilentPayment: utxoDetails.spendsSilentPayment,
|
spendsSilentPayment: utxoDetails.spendsSilentPayment,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> calcFee({
|
Future<int> calcFee({
|
||||||
required List<UtxoWithAddress> utxos,
|
required List<UtxoWithAddress> utxos,
|
||||||
|
@ -1080,15 +1038,20 @@ abstract class ElectrumWalletBase
|
||||||
: feeRate(transactionCredentials.priority!);
|
: feeRate(transactionCredentials.priority!);
|
||||||
|
|
||||||
EstimatedTxResult estimatedTx;
|
EstimatedTxResult estimatedTx;
|
||||||
final updatedOutputs =
|
final updatedOutputs = outputs
|
||||||
outputs.map((e) => BitcoinOutput(address: e.address, value: e.value)).toList();
|
.map((e) => BitcoinOutput(
|
||||||
|
address: e.address,
|
||||||
|
value: e.value,
|
||||||
|
isSilentPayment: e.isSilentPayment,
|
||||||
|
isChange: e.isChange,
|
||||||
|
))
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (sendAll) {
|
if (sendAll) {
|
||||||
estimatedTx = await estimateSendAllTx(
|
estimatedTx = await estimateSendAllTx(
|
||||||
updatedOutputs,
|
updatedOutputs,
|
||||||
feeRateInt,
|
feeRateInt,
|
||||||
memo: memo,
|
memo: memo,
|
||||||
credentialsAmount: credentialsAmount,
|
|
||||||
hasSilentPayment: hasSilentPayment,
|
hasSilentPayment: hasSilentPayment,
|
||||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||||
);
|
);
|
||||||
|
|
|
@ -568,10 +568,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: ledger_flutter_plus
|
name: ledger_flutter_plus
|
||||||
sha256: ea3ed586e1697776dacf42ac979095f1ca3bd143bf007cbe5c78e09cb6943f42
|
sha256: c7b04008553193dbca7e17b430768eecc372a72b0ff3625b5e7fc5e5c8d3231b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.5"
|
version: "1.4.1"
|
||||||
ledger_litecoin:
|
ledger_litecoin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
Loading…
Reference in a new issue