stack_wallet/lib/wallets/wallet/wallet_mixin_interfaces/rbf_interface.dart

120 lines
3.3 KiB
Dart
Raw Normal View History

2024-06-16 16:33:54 +00:00
import 'dart:convert';
2024-06-16 19:25:07 +00:00
import 'package:isar/isar.dart';
2024-06-16 16:33:54 +00:00
import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart';
2024-06-16 19:25:07 +00:00
import '../../../models/isar/models/isar_models.dart';
import '../../../utilities/amount/amount.dart';
import '../../../utilities/enums/fee_rate_type_enum.dart';
2024-06-15 17:36:53 +00:00
import '../../crypto_currency/interfaces/electrumx_currency_interface.dart';
2024-06-16 19:25:07 +00:00
import '../../models/tx_data.dart';
2024-06-15 17:36:53 +00:00
import 'electrumx_interface.dart';
typedef TxSize = ({int real, int virtual});
mixin RbfInterface<T extends ElectrumXCurrencyInterface>
on ElectrumXInterface<T> {
Future<TxSize?> getVSize(String txid) async {
final tx = await electrumXCachedClient.getTransaction(
txHash: txid,
cryptoCurrency: cryptoCurrency,
);
try {
return (real: tx["size"] as int, virtual: tx["vsize"] as int);
} catch (_) {
return null;
}
}
2024-06-16 16:33:54 +00:00
Future<TransactionV2> updateVSize(TransactionV2 transactionV2) async {
final size = await getVSize(transactionV2.txid);
final otherData = jsonDecode(transactionV2.otherData ?? "{}");
otherData[TxV2OdKeys.vSize] = size!.virtual;
otherData[TxV2OdKeys.size] = size.real;
final updatedTx = transactionV2.copyWith(otherData: jsonEncode(otherData));
await mainDB.updateOrPutTransactionV2s([updatedTx]);
return updatedTx;
}
2024-06-16 19:25:07 +00:00
Future<TxData> prepareRbfSend({
required TransactionV2 oldTransaction,
required int newRate,
}) async {
final Set<UTXO> utxos = {};
for (final input in oldTransaction.inputs) {
final utxo = UTXO(
walletId: walletId,
txid: input.outpoint!.txid,
vout: input.outpoint!.vout,
value: input.value.toInt(),
name: "rbf",
isBlocked: false,
blockedReason: null,
isCoinbase: false,
blockHash: "rbf",
blockHeight: 1,
blockTime: 1,
used: false,
address: input.addresses.first,
);
utxos.add(utxo);
}
Amount sendAmount = oldTransaction.getAmountSentFromThisWallet(
fractionDigits: cryptoCurrency.fractionDigits,
);
// TODO: fix fragile firstWhere (or at least add some error checking)
final address = oldTransaction.outputs
.firstWhere(
(e) => e.value == sendAmount.raw,
)
.addresses
.first;
final inSum = utxos
.map((e) => BigInt.from(e.value))
.fold(BigInt.zero, (p, e) => p + e);
if (oldTransaction
.getFee(fractionDigits: cryptoCurrency.fractionDigits)
.raw +
sendAmount.raw ==
inSum) {
sendAmount = Amount(
rawValue: oldTransaction
.getFee(fractionDigits: cryptoCurrency.fractionDigits)
.raw +
sendAmount.raw,
fractionDigits: cryptoCurrency.fractionDigits,
);
}
final note = await mainDB.isar.transactionNotes
.where()
.walletIdEqualTo(walletId)
.filter()
.txidEqualTo(oldTransaction.txid)
.findFirst();
final txData = TxData(
recipients: [
(
address: address,
amount: sendAmount,
isChange: false,
),
],
feeRateType: FeeRateType.custom,
satsPerVByte: newRate,
utxos: utxos,
ignoreCachedBalanceChecks: true,
note: note?.value ?? "",
);
return await prepareSend(txData: txData);
}
2024-06-15 17:36:53 +00:00
}