fix: sp input calc (#1756)
Rafael committed
Oct 18, 2024 at 20:24 UTC
7faca38cfa52bcb3914c8b20cda291e4eefe594a
1 file changed
+37
-8
cw_bitcoin/lib/electrum_wallet.dart
+37
-8
@@ -784,6 +784,7 @@ abstract class ElectrumWalletBase
784
Future<EstimatedTxResult> estimateTxForAmount(
785
int credentialsAmount,
786
List<BitcoinOutput> outputs,
787
+ List<BitcoinOutput> updatedOutputs,
788
int feeRate, {
789
int? inputsCount,
790
String? memo,
@@ -812,6 +813,7 @@ abstract class ElectrumWalletBase
813
return estimateTxForAmount(
814
credentialsAmount,
815
outputs,
816
+ updatedOutputs,
817
feeRate,
818
inputsCount: utxoDetails.utxos.length + 1,
819
memo: memo,
@@ -824,19 +826,30 @@ abstract class ElectrumWalletBase
826
}
827
828
final changeAddress = await walletAddresses.getChangeAddress(
827
- outputs: outputs,
829
+ outputs: updatedOutputs,
830
utxoDetails: utxoDetails,
831
);
832
final address = RegexUtils.addressTypeFromStr(changeAddress, network);
833
+ updatedOutputs.add(BitcoinOutput(
834
+ address: address,
835
+ value: BigInt.from(amountLeftForChangeAndFee),
836
+ isChange: true,
837
+ ));
838
outputs.add(BitcoinOutput(
839
address: address,
840
value: BigInt.from(amountLeftForChangeAndFee),
841
isChange: true,
842
));
843
844
+ // calcFee updates the silent payment outputs to calculate the tx size accounting
845
+ // for taproot addresses, but if more inputs are needed to make up for fees,
846
+ // the silent payment outputs need to be recalculated for the new inputs
847
+ var temp = outputs.map((output) => output).toList();
848
int fee = await calcFee(
849
utxos: utxoDetails.utxos,
839
- outputs: outputs,
850
+ // Always take only not updated bitcoin outputs here so for every estimation
851
+ // the SP outputs are re-generated to the proper taproot addresses
852
+ outputs: temp,
853
network: network,
854
memo: memo,
855
feeRate: feeRate,
@@ -844,18 +857,25 @@ abstract class ElectrumWalletBase
857
vinOutpoints: utxoDetails.vinOutpoints,
858
);
859
860
+ updatedOutputs.clear();
861
+ updatedOutputs.addAll(temp);
862
+
863
if (fee == 0) {
864
throw BitcoinTransactionNoFeeException();
865
}
866
867
int amount = credentialsAmount;
852
- final lastOutput = outputs.last;
868
+ final lastOutput = updatedOutputs.last;
869
final amountLeftForChange = amountLeftForChangeAndFee - fee;
870
855
- print(amountLeftForChangeAndFee);
856
-
871
if (!_isBelowDust(amountLeftForChange)) {
872
// Here, lastOutput already is change, return the amount left without the fee to the user's address.
873
+ updatedOutputs[updatedOutputs.length - 1] = BitcoinOutput(
874
+ address: lastOutput.address,
875
+ value: BigInt.from(amountLeftForChange),
876
+ isSilentPayment: lastOutput.isSilentPayment,
877
+ isChange: true,
878
+ );
879
outputs[outputs.length - 1] = BitcoinOutput(
880
address: lastOutput.address,
881
value: BigInt.from(amountLeftForChange),
@@ -864,6 +884,7 @@ abstract class ElectrumWalletBase
884
);
885
} else {
886
// If has change that is lower than dust, will end up with tx rejected by network rules, so estimate again without the added change
887
+ updatedOutputs.removeLast();
888
outputs.removeLast();
889
890
// Still has inputs to spend before failing
@@ -871,16 +892,18 @@ abstract class ElectrumWalletBase
892
return estimateTxForAmount(
893
credentialsAmount,
894
outputs,
895
+ updatedOutputs,
896
feeRate,
897
inputsCount: utxoDetails.utxos.length + 1,
898
memo: memo,
899
+ hasSilentPayment: hasSilentPayment,
900
useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
901
coinTypeToSpendFrom: coinTypeToSpendFrom,
902
);
903
}
904
905
final estimatedSendAll = await estimateSendAllTx(
883
- outputs,
906
+ updatedOutputs,
907
feeRate,
908
memo: memo,
909
coinTypeToSpendFrom: coinTypeToSpendFrom,
@@ -913,10 +936,12 @@ abstract class ElectrumWalletBase
936
if (spendingAllCoins) {
937
throw BitcoinTransactionWrongBalanceException();
938
} else {
939
+ updatedOutputs.removeLast();
940
outputs.removeLast();
941
return estimateTxForAmount(
942
credentialsAmount,
943
outputs,
944
+ updatedOutputs,
945
feeRate,
946
inputsCount: utxoDetails.utxos.length + 1,
947
memo: memo,
@@ -1029,6 +1054,9 @@ abstract class ElectrumWalletBase
1054
: feeRate(transactionCredentials.priority!);
1055
1056
EstimatedTxResult estimatedTx;
1057
+ final updatedOutputs =
1058
+ outputs.map((e) => BitcoinOutput(address: e.address, value: e.value)).toList();
1059
+
1060
if (sendAll) {
1061
estimatedTx = await estimateSendAllTx(
1062
outputs,
@@ -1042,6 +1070,7 @@ abstract class ElectrumWalletBase
1070
estimatedTx = await estimateTxForAmount(
1071
credentialsAmount,
1072
outputs,
1073
+ updatedOutputs,
1074
feeRateInt,
1075
memo: memo,
1076
hasSilentPayment: hasSilentPayment,
@@ -1052,7 +1081,7 @@ abstract class ElectrumWalletBase
1081
if (walletInfo.isHardwareWallet) {
1082
final transaction = await buildHardwareWalletTransaction(
1083
utxos: estimatedTx.utxos,
1055
- outputs: outputs,
1084
+ outputs: updatedOutputs,
1085
publicKeys: estimatedTx.publicKeys,
1086
fee: BigInt.from(estimatedTx.fee),
1087
network: network,
@@ -1092,7 +1121,7 @@ abstract class ElectrumWalletBase
1121
} else {
1122
txb = BitcoinTransactionBuilder(
1123
utxos: estimatedTx.utxos,
1095
- outputs: outputs,
1124
+ outputs: updatedOutputs,
1125
fee: BigInt.from(estimatedTx.fee),
1126
network: network,
1127
memo: estimatedTx.memo,