add size and vSize to btc and ltc transactions to use and display in rbf boost txn view

This commit is contained in:
julian 2024-06-16 10:27:54 -06:00
parent ac07aee9c3
commit 1426495474
5 changed files with 155 additions and 72 deletions

View file

@ -57,17 +57,52 @@ class TransactionV2 {
required this.otherData,
});
TransactionV2 copyWith({
String? walletId,
String? txid,
String? hash,
int? timestamp,
int? height,
String? blockHash,
int? version,
List<InputV2>? inputs,
List<OutputV2>? outputs,
TransactionType? type,
TransactionSubType? subType,
String? otherData,
}) {
return TransactionV2(
walletId: walletId ?? this.walletId,
txid: txid ?? this.txid,
hash: hash ?? this.hash,
timestamp: timestamp ?? this.timestamp,
height: height ?? this.height,
blockHash: blockHash ?? this.blockHash,
version: version ?? this.version,
inputs: inputs ?? this.inputs,
outputs: outputs ?? this.outputs,
type: type ?? this.type,
subType: subType ?? this.subType,
otherData: otherData ?? this.otherData,
);
}
int? get size => _getFromOtherData(key: TxV2OdKeys.size) as int?;
int? get vSize => _getFromOtherData(key: TxV2OdKeys.vSize) as int?;
bool get isEpiccashTransaction =>
_getFromOtherData(key: "isEpiccashTransaction") == true;
_getFromOtherData(key: TxV2OdKeys.isEpiccashTransaction) == true;
int? get numberOfMessages =>
_getFromOtherData(key: "numberOfMessages") as int?;
String? get slateId => _getFromOtherData(key: "slateId") as String?;
String? get onChainNote => _getFromOtherData(key: "onChainNote") as String?;
bool get isCancelled => _getFromOtherData(key: "isCancelled") == true;
_getFromOtherData(key: TxV2OdKeys.numberOfMessages) as int?;
String? get slateId => _getFromOtherData(key: TxV2OdKeys.slateId) as String?;
String? get onChainNote =>
_getFromOtherData(key: TxV2OdKeys.onChainNote) as String?;
bool get isCancelled =>
_getFromOtherData(key: TxV2OdKeys.isCancelled) == true;
String? get contractAddress =>
_getFromOtherData(key: "contractAddress") as String?;
int? get nonce => _getFromOtherData(key: "nonce") as int?;
_getFromOtherData(key: TxV2OdKeys.contractAddress) as String?;
int? get nonce => _getFromOtherData(key: TxV2OdKeys.nonce) as int?;
int getConfirmations(int currentChainHeight) {
if (height == null || height! <= 0) return 0;
@ -146,7 +181,7 @@ class TransactionV2 {
Amount? _getOverrideFee() {
try {
return Amount.fromSerializedJsonString(
_getFromOtherData(key: "overrideFee") as String,
_getFromOtherData(key: TxV2OdKeys.overrideFee) as String,
);
} catch (_) {
return null;
@ -250,3 +285,16 @@ class TransactionV2 {
')';
}
}
abstract final class TxV2OdKeys {
static const size = "size";
static const vSize = "vSize";
static const isEpiccashTransaction = "isEpiccashTransaction";
static const numberOfMessages = "numberOfMessages";
static const slateId = "slateId";
static const onChainNote = "onChainNote";
static const isCancelled = "isCancelled";
static const contractAddress = "contractAddress";
static const nonce = "nonce";
static const overrideFee = "overrideFee";
}

View file

@ -23,6 +23,7 @@ import '../../../../widgets/boost_fee_slider.dart';
import '../../../../widgets/conditional_parent.dart';
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../../../widgets/desktop/primary_button.dart';
import '../../../../widgets/detail_item.dart';
import '../../../../widgets/rounded_white_container.dart';
class BoostTransactionView extends ConsumerStatefulWidget {
@ -45,6 +46,7 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
late final String walletId;
late final TransactionV2 _transaction;
late final Amount fee;
late final Amount amount;
BigInt? customFee;
@ -74,6 +76,9 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
fee = _transaction.getFee(
fractionDigits: ref.read(pWalletCoin(walletId)).fractionDigits,
);
amount = _transaction.getAmountSentFromThisWallet(
fractionDigits: ref.read(pWalletCoin(walletId)).fractionDigits,
);
super.initState();
}
@ -84,6 +89,12 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
final String feeString = ref.watch(pAmountFormatter(coin)).format(
fee,
);
final String amountString = ref.watch(pAmountFormatter(coin)).format(
amount,
);
final String feeRateString =
"${(fee.raw / BigInt.from(_transaction.vSize!)).toStringAsFixed(1)}"
" sats/vByte";
return ConditionalParent(
condition: !isDesktop,
@ -118,68 +129,58 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
child: ConditionalParent(
condition: isDesktop,
builder: (child) {
return RoundedWhiteContainer(
borderColor: isDesktop
? Theme.of(context).extension<StackColors>()!.backgroundAppBar
: null,
padding: const EdgeInsets.all(0),
child: child,
return Column(
children: [
RoundedWhiteContainer(
borderColor: isDesktop
? Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar
: null,
padding: const EdgeInsets.all(0),
child: child,
),
const SizedBox(
height: 32,
),
PrimaryButton(
buttonHeight: ButtonHeight.l,
label: "Preview send",
onPressed: _previewTxn,
),
],
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// const _Divider(),
RoundedWhiteContainer(
padding: isDesktop
? const EdgeInsets.all(16)
? const EdgeInsets.all(0)
: const EdgeInsets.all(12),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Boost fee",
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(
context,
)
: STextStyles.itemSubtitle(
context,
),
),
],
),
if (!isDesktop)
SelectableText(
feeString,
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(
context,
).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
)
: STextStyles.itemSubtitle12(
context,
),
),
// if (isDesktop)
// IconCopyButton(data: feeString),
],
DetailItem(
title: "Send amount",
detail: amountString,
horizontal: true,
),
const _Divider(),
DetailItem(
title: "Current fee",
detail: feeString,
horizontal: true,
),
const _Divider(),
DetailItem(
title: "Current fee rate",
detail: feeRateString,
horizontal: true,
),
const _Divider(),
Padding(
padding: const EdgeInsets.only(
bottom: 12,
top: 16,
),
padding: const EdgeInsets.all(10),
child: BoostFeeSlider(
coin: coin,
onFeeChanged: (fee) {
@ -195,15 +196,19 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
// TODO [prio=med]: The max fee should be set to an absurd fee.
),
),
const _Divider(),
PrimaryButton(
buttonHeight: ButtonHeight.l,
label: "Preview send",
onPressed: _previewTxn,
),
],
),
),
if (!isDesktop)
const SizedBox(
height: 20,
),
if (!isDesktop)
PrimaryButton(
buttonHeight: ButtonHeight.l,
label: "Preview send",
onPressed: _previewTxn,
),
],
),
),

View file

@ -9,6 +9,7 @@
*/
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -104,6 +105,14 @@ class _TransactionV2DetailsViewState
String? _sparkMemo;
Future<TransactionV2> _updateVSize(RbfInterface rbfWallet) async {
final size = await rbfWallet.getVSize(_transaction.txid);
final otherData = jsonDecode(_transaction.otherData ?? "{}");
otherData[TxV2OdKeys.vSize] = size!.virtual;
otherData[TxV2OdKeys.size] = size.real;
return _transaction.copyWith(otherData: jsonEncode(otherData));
}
bool _boostButtonLock = false;
Future<void> _boostPressed() async {
final wallet = ref.read(pWallets).getWallet(walletId);
@ -113,13 +122,16 @@ class _TransactionV2DetailsViewState
_boostButtonLock = true;
try {
if (Util.isDesktop) {
// TODO fetch size from _transaction after its added to db schema, if not there,
// then fetch using the function below
final size = await showLoading(
whileFuture: wallet.getVSize(_transaction.txid),
context: context,
message: "Fetching transaction vSize...",
);
if (_transaction.vSize == null) {
final updatedTx = await showLoading(
whileFuture: _updateVSize(wallet),
context: context,
message: "Fetching transaction vSize...",
);
// TODO handle errors if null
_transaction = updatedTx!;
}
// TODO pass the size in to the rbf screen

View file

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:isar/isar.dart';
import '../../../models/isar/models/blockchain_data/address.dart';
@ -290,6 +292,14 @@ class LitecoinWallet<T extends ElectrumXCurrencyInterface>
continue;
}
String? otherData;
if (txData["size"] is int || txData["vsize"] is int) {
otherData = jsonEncode({
TxV2OdKeys.size: txData["size"] as int?,
TxV2OdKeys.vSize: txData["vsize"] as int?,
});
}
final tx = TransactionV2(
walletId: walletId,
blockHash: txData["blockhash"] as String?,
@ -303,7 +313,7 @@ class LitecoinWallet<T extends ElectrumXCurrencyInterface>
outputs: List.unmodifiable(outputs),
type: type,
subType: subType,
otherData: null,
otherData: otherData,
);
txns.add(tx);

View file

@ -1794,6 +1794,14 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
continue;
}
String? otherData;
if (txData["size"] is int || txData["vsize"] is int) {
otherData = jsonEncode({
TxV2OdKeys.size: txData["size"] as int?,
TxV2OdKeys.vSize: txData["vsize"] as int?,
});
}
final tx = TransactionV2(
walletId: walletId,
blockHash: txData["blockhash"] as String?,
@ -1807,7 +1815,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
outputs: List.unmodifiable(outputs),
type: type,
subType: subType,
otherData: null,
otherData: otherData,
);
txns.add(tx);