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, 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 => bool get isEpiccashTransaction =>
_getFromOtherData(key: "isEpiccashTransaction") == true; _getFromOtherData(key: TxV2OdKeys.isEpiccashTransaction) == true;
int? get numberOfMessages => int? get numberOfMessages =>
_getFromOtherData(key: "numberOfMessages") as int?; _getFromOtherData(key: TxV2OdKeys.numberOfMessages) as int?;
String? get slateId => _getFromOtherData(key: "slateId") as String?; String? get slateId => _getFromOtherData(key: TxV2OdKeys.slateId) as String?;
String? get onChainNote => _getFromOtherData(key: "onChainNote") as String?; String? get onChainNote =>
bool get isCancelled => _getFromOtherData(key: "isCancelled") == true; _getFromOtherData(key: TxV2OdKeys.onChainNote) as String?;
bool get isCancelled =>
_getFromOtherData(key: TxV2OdKeys.isCancelled) == true;
String? get contractAddress => String? get contractAddress =>
_getFromOtherData(key: "contractAddress") as String?; _getFromOtherData(key: TxV2OdKeys.contractAddress) as String?;
int? get nonce => _getFromOtherData(key: "nonce") as int?; int? get nonce => _getFromOtherData(key: TxV2OdKeys.nonce) as int?;
int getConfirmations(int currentChainHeight) { int getConfirmations(int currentChainHeight) {
if (height == null || height! <= 0) return 0; if (height == null || height! <= 0) return 0;
@ -146,7 +181,7 @@ class TransactionV2 {
Amount? _getOverrideFee() { Amount? _getOverrideFee() {
try { try {
return Amount.fromSerializedJsonString( return Amount.fromSerializedJsonString(
_getFromOtherData(key: "overrideFee") as String, _getFromOtherData(key: TxV2OdKeys.overrideFee) as String,
); );
} catch (_) { } catch (_) {
return null; 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/conditional_parent.dart';
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../../../widgets/desktop/primary_button.dart'; import '../../../../widgets/desktop/primary_button.dart';
import '../../../../widgets/detail_item.dart';
import '../../../../widgets/rounded_white_container.dart'; import '../../../../widgets/rounded_white_container.dart';
class BoostTransactionView extends ConsumerStatefulWidget { class BoostTransactionView extends ConsumerStatefulWidget {
@ -45,6 +46,7 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
late final String walletId; late final String walletId;
late final TransactionV2 _transaction; late final TransactionV2 _transaction;
late final Amount fee; late final Amount fee;
late final Amount amount;
BigInt? customFee; BigInt? customFee;
@ -74,6 +76,9 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
fee = _transaction.getFee( fee = _transaction.getFee(
fractionDigits: ref.read(pWalletCoin(walletId)).fractionDigits, fractionDigits: ref.read(pWalletCoin(walletId)).fractionDigits,
); );
amount = _transaction.getAmountSentFromThisWallet(
fractionDigits: ref.read(pWalletCoin(walletId)).fractionDigits,
);
super.initState(); super.initState();
} }
@ -84,6 +89,12 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
final String feeString = ref.watch(pAmountFormatter(coin)).format( final String feeString = ref.watch(pAmountFormatter(coin)).format(
fee, 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( return ConditionalParent(
condition: !isDesktop, condition: !isDesktop,
@ -118,68 +129,58 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
child: ConditionalParent( child: ConditionalParent(
condition: isDesktop, condition: isDesktop,
builder: (child) { builder: (child) {
return RoundedWhiteContainer( return Column(
borderColor: isDesktop children: [
? Theme.of(context).extension<StackColors>()!.backgroundAppBar RoundedWhiteContainer(
: null, borderColor: isDesktop
padding: const EdgeInsets.all(0), ? Theme.of(context)
child: child, .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( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// const _Divider(),
RoundedWhiteContainer( RoundedWhiteContainer(
padding: isDesktop padding: isDesktop
? const EdgeInsets.all(16) ? const EdgeInsets.all(0)
: const EdgeInsets.all(12), : const EdgeInsets.all(12),
child: Column( child: Column(
children: [ children: [
Row( DetailItem(
mainAxisAlignment: MainAxisAlignment.spaceBetween, title: "Send amount",
crossAxisAlignment: CrossAxisAlignment.start, detail: amountString,
children: [ horizontal: true,
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),
],
), ),
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(
padding: const EdgeInsets.only( padding: const EdgeInsets.all(10),
bottom: 12,
top: 16,
),
child: BoostFeeSlider( child: BoostFeeSlider(
coin: coin, coin: coin,
onFeeChanged: (fee) { onFeeChanged: (fee) {
@ -195,15 +196,19 @@ class _BoostTransactionViewState extends ConsumerState<BoostTransactionView> {
// TODO [prio=med]: The max fee should be set to an absurd fee. // 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:async';
import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -104,6 +105,14 @@ class _TransactionV2DetailsViewState
String? _sparkMemo; 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; bool _boostButtonLock = false;
Future<void> _boostPressed() async { Future<void> _boostPressed() async {
final wallet = ref.read(pWallets).getWallet(walletId); final wallet = ref.read(pWallets).getWallet(walletId);
@ -113,13 +122,16 @@ class _TransactionV2DetailsViewState
_boostButtonLock = true; _boostButtonLock = true;
try { try {
if (Util.isDesktop) { if (Util.isDesktop) {
// TODO fetch size from _transaction after its added to db schema, if not there, if (_transaction.vSize == null) {
// then fetch using the function below final updatedTx = await showLoading(
final size = await showLoading( whileFuture: _updateVSize(wallet),
whileFuture: wallet.getVSize(_transaction.txid), context: context,
context: context, message: "Fetching transaction vSize...",
message: "Fetching transaction vSize...", );
);
// TODO handle errors if null
_transaction = updatedTx!;
}
// TODO pass the size in to the rbf screen // TODO pass the size in to the rbf screen

View file

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

View file

@ -1794,6 +1794,14 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
continue; 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( final tx = TransactionV2(
walletId: walletId, walletId: walletId,
blockHash: txData["blockhash"] as String?, blockHash: txData["blockhash"] as String?,
@ -1807,7 +1815,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
outputs: List.unmodifiable(outputs), outputs: List.unmodifiable(outputs),
type: type, type: type,
subType: subType, subType: subType,
otherData: null, otherData: otherData,
); );
txns.add(tx); txns.add(tx);