mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-22 10:34:32 +00:00
add size and vSize to btc and ltc transactions to use and display in rbf boost txn view
This commit is contained in:
parent
ac07aee9c3
commit
1426495474
5 changed files with 155 additions and 72 deletions
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue