mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-20 22:28:48 +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,
|
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";
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue