mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-22 11:29:23 +00:00
add functionality for different number of required min confirms for coinbase transactions and apply to firo
This commit is contained in:
parent
3566d75d58
commit
40b0f49f20
20 changed files with 107 additions and 21 deletions
|
@ -80,9 +80,14 @@ class UTXO {
|
|||
return max(0, currentChainHeight - (blockHeight! - 1));
|
||||
}
|
||||
|
||||
bool isConfirmed(int currentChainHeight, int minimumConfirms) {
|
||||
bool isConfirmed(
|
||||
int currentChainHeight,
|
||||
int minimumConfirms,
|
||||
int minimumCoinbaseConfirms,
|
||||
) {
|
||||
final confirmations = getConfirmations(currentChainHeight);
|
||||
return confirmations >= minimumConfirms;
|
||||
return confirmations >=
|
||||
(isCoinbase ? minimumCoinbaseConfirms : minimumConfirms);
|
||||
}
|
||||
|
||||
@ignore
|
||||
|
|
|
@ -112,9 +112,14 @@ class TransactionV2 {
|
|||
return max(0, currentChainHeight - (height! - 1));
|
||||
}
|
||||
|
||||
bool isConfirmed(int currentChainHeight, int minimumConfirms) {
|
||||
bool isConfirmed(
|
||||
int currentChainHeight,
|
||||
int minimumConfirms,
|
||||
int minimumCoinbaseConfirms,
|
||||
) {
|
||||
final confirmations = getConfirmations(currentChainHeight);
|
||||
return confirmations >= minimumConfirms;
|
||||
return confirmations >=
|
||||
(isCoinbase() ? minimumCoinbaseConfirms : minimumConfirms);
|
||||
}
|
||||
|
||||
Amount getFee({required int fractionDigits}) {
|
||||
|
@ -225,6 +230,7 @@ class TransactionV2 {
|
|||
String statusLabel({
|
||||
required int currentChainHeight,
|
||||
required int minConfirms,
|
||||
required int minCoinbaseConfirms,
|
||||
}) {
|
||||
String prettyConfirms() =>
|
||||
"(${getConfirmations(currentChainHeight)}/$minConfirms)";
|
||||
|
@ -233,7 +239,7 @@ class TransactionV2 {
|
|||
subType == TransactionSubType.mint ||
|
||||
(subType == TransactionSubType.sparkMint &&
|
||||
type == TransactionType.sentToSelf)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Anonymized";
|
||||
} else {
|
||||
return "Anonymizing ${prettyConfirms()}";
|
||||
|
@ -248,7 +254,7 @@ class TransactionV2 {
|
|||
if (isCancelled) {
|
||||
return "Cancelled";
|
||||
} else if (type == TransactionType.incoming) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Received";
|
||||
} else {
|
||||
if (numberOfMessages == 1) {
|
||||
|
@ -260,7 +266,7 @@ class TransactionV2 {
|
|||
}
|
||||
}
|
||||
} else if (type == TransactionType.outgoing) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Sent (confirmed)";
|
||||
} else {
|
||||
if (numberOfMessages == 1) {
|
||||
|
@ -278,19 +284,19 @@ class TransactionV2 {
|
|||
// if (_transaction.isMinting) {
|
||||
// return "Minting";
|
||||
// } else
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Received";
|
||||
} else {
|
||||
return "Receiving ${prettyConfirms()}";
|
||||
}
|
||||
} else if (type == TransactionType.outgoing) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Sent";
|
||||
} else {
|
||||
return "Sending ${prettyConfirms()}";
|
||||
}
|
||||
} else if (type == TransactionType.sentToSelf) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms)) {
|
||||
if (isConfirmed(currentChainHeight, minConfirms, minCoinbaseConfirms)) {
|
||||
return "Sent to self";
|
||||
} else {
|
||||
return "Sent to self ${prettyConfirms()}";
|
||||
|
@ -308,6 +314,9 @@ class TransactionV2 {
|
|||
return map[key];
|
||||
}
|
||||
|
||||
bool isCoinbase() =>
|
||||
type == TransactionType.incoming && inputs.any((e) => e.coinbase != null);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TransactionV2(\n'
|
||||
|
|
|
@ -350,6 +350,7 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> {
|
|||
utxo.isConfirmed(
|
||||
currentHeight,
|
||||
minConfirms,
|
||||
coin.minCoinbaseConfirms,
|
||||
)),
|
||||
initialSelectedState: isSelected,
|
||||
onSelectedChanged: (value) {
|
||||
|
@ -414,6 +415,7 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> {
|
|||
utxo.isConfirmed(
|
||||
currentHeight,
|
||||
minConfirms,
|
||||
coin.minCoinbaseConfirms,
|
||||
)),
|
||||
initialSelectedState: isSelected,
|
||||
onSelectedChanged: (value) {
|
||||
|
@ -558,6 +560,7 @@ class _CoinControlViewState extends ConsumerState<CoinControlView> {
|
|||
utxo.isConfirmed(
|
||||
currentHeight,
|
||||
minConfirms,
|
||||
coin.minCoinbaseConfirms,
|
||||
)),
|
||||
initialSelectedState: isSelected,
|
||||
onSelectedChanged: (value) {
|
||||
|
|
|
@ -117,6 +117,11 @@ class _UtxoCardState extends ConsumerState<UtxoCard> {
|
|||
.getWallet(widget.walletId)
|
||||
.cryptoCurrency
|
||||
.minConfirms,
|
||||
ref
|
||||
.watch(pWallets)
|
||||
.getWallet(widget.walletId)
|
||||
.cryptoCurrency
|
||||
.minCoinbaseConfirms,
|
||||
)
|
||||
? UTXOStatusIconStatus.confirmed
|
||||
: UTXOStatusIconStatus.unconfirmed,
|
||||
|
|
|
@ -98,6 +98,11 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
|
|||
final confirmed = utxo!.isConfirmed(
|
||||
currentHeight,
|
||||
ref.watch(pWallets).getWallet(widget.walletId).cryptoCurrency.minConfirms,
|
||||
ref
|
||||
.watch(pWallets)
|
||||
.getWallet(widget.walletId)
|
||||
.cryptoCurrency
|
||||
.minCoinbaseConfirms,
|
||||
);
|
||||
|
||||
return ConditionalParent(
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'dart:io';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart';
|
||||
import '../../../models/isar/models/isar_models.dart';
|
||||
import '../../../models/isar/stack_theme.dart';
|
||||
|
@ -106,6 +107,11 @@ class TxIcon extends ConsumerWidget {
|
|||
!tx.isConfirmed(
|
||||
currentHeight,
|
||||
ref.watch(pWallets).getWallet(tx.walletId).cryptoCurrency.minConfirms,
|
||||
ref
|
||||
.watch(pWallets)
|
||||
.getWallet(tx.walletId)
|
||||
.cryptoCurrency
|
||||
.minCoinbaseConfirms,
|
||||
),
|
||||
tx.subType,
|
||||
tx.type,
|
||||
|
|
|
@ -15,14 +15,11 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
import '../../../../models/isar/models/blockchain_data/v2/transaction_v2.dart';
|
||||
import '../../../../models/isar/models/contact_entry.dart';
|
||||
import '../../../../models/isar/models/isar_models.dart';
|
||||
import '../../../../models/transaction_filter.dart';
|
||||
import '../../sub_widgets/tx_icon.dart';
|
||||
import '../transaction_search_filter_view.dart';
|
||||
import 'transaction_v2_card.dart';
|
||||
import 'transaction_v2_details_view.dart';
|
||||
import '../../../../providers/db/main_db_provider.dart';
|
||||
import '../../../../providers/global/address_book_service_provider.dart';
|
||||
import '../../../../providers/providers.dart';
|
||||
|
@ -49,6 +46,10 @@ import '../../../../widgets/loading_indicator.dart';
|
|||
import '../../../../widgets/rounded_white_container.dart';
|
||||
import '../../../../widgets/stack_text_field.dart';
|
||||
import '../../../../widgets/textfield_icon_button.dart';
|
||||
import '../../sub_widgets/tx_icon.dart';
|
||||
import '../transaction_search_filter_view.dart';
|
||||
import 'transaction_v2_card.dart';
|
||||
import 'transaction_v2_details_view.dart';
|
||||
|
||||
typedef _GroupedTransactions = ({
|
||||
String label,
|
||||
|
@ -866,6 +867,11 @@ class _DesktopTransactionCardRowState
|
|||
String whatIsIt(TransactionV2 tx, int height) => tx.statusLabel(
|
||||
currentChainHeight: height,
|
||||
minConfirms: minConfirms,
|
||||
minCoinbaseConfirms: ref
|
||||
.read(pWallets)
|
||||
.getWallet(widget.walletId)
|
||||
.cryptoCurrency
|
||||
.minCoinbaseConfirms,
|
||||
);
|
||||
|
||||
@override
|
||||
|
|
|
@ -60,6 +60,11 @@ class _TransactionCardStateV2 extends ConsumerState<TransactionCardV2> {
|
|||
.getWallet(walletId)
|
||||
.cryptoCurrency
|
||||
.minConfirms,
|
||||
minCoinbaseConfirms: ref
|
||||
.read(pWallets)
|
||||
.getWallet(walletId)
|
||||
.cryptoCurrency
|
||||
.minCoinbaseConfirms,
|
||||
);
|
||||
|
||||
@override
|
||||
|
|
|
@ -373,6 +373,11 @@ class _TransactionV2DetailsViewState
|
|||
String whatIsIt(TransactionV2 tx, int height) => tx.statusLabel(
|
||||
currentChainHeight: height,
|
||||
minConfirms: minConfirms,
|
||||
minCoinbaseConfirms: ref
|
||||
.read(pWallets)
|
||||
.getWallet(walletId)
|
||||
.cryptoCurrency
|
||||
.minCoinbaseConfirms,
|
||||
);
|
||||
|
||||
Future<String> fetchContactNameFor(String address) async {
|
||||
|
@ -567,6 +572,7 @@ class _TransactionV2DetailsViewState
|
|||
final confirmedTxn = _transaction.isConfirmed(
|
||||
currentHeight,
|
||||
coin.minConfirms,
|
||||
coin.minCoinbaseConfirms,
|
||||
);
|
||||
|
||||
return ConditionalParent(
|
||||
|
@ -1367,6 +1373,7 @@ class _TransactionV2DetailsViewState
|
|||
? _transaction.isConfirmed(
|
||||
currentHeight,
|
||||
minConfirms,
|
||||
coin.minCoinbaseConfirms,
|
||||
)
|
||||
? ref
|
||||
.watch(pAmountFormatter(coin))
|
||||
|
@ -1484,9 +1491,9 @@ class _TransactionV2DetailsViewState
|
|||
height = "Unknown";
|
||||
} else {
|
||||
final confirmed = _transaction.isConfirmed(
|
||||
currentHeight,
|
||||
minConfirms,
|
||||
);
|
||||
currentHeight,
|
||||
minConfirms,
|
||||
coin.minCoinbaseConfirms);
|
||||
if (widget.coin is! Epiccash && confirmed) {
|
||||
height =
|
||||
"${_transaction.height == 0 ? "Unknown" : _transaction.height}";
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
import '../../db/isar/main_db.dart';
|
||||
import '../../models/isar/models/isar_models.dart';
|
||||
import '../../pages/coin_control/utxo_details_view.dart';
|
||||
|
@ -141,6 +142,11 @@ class _UtxoRowState extends ConsumerState<UtxoRow> {
|
|||
.getWallet(widget.walletId)
|
||||
.cryptoCurrency
|
||||
.minConfirms,
|
||||
ref
|
||||
.watch(pWallets)
|
||||
.getWallet(widget.walletId)
|
||||
.cryptoCurrency
|
||||
.minCoinbaseConfirms,
|
||||
)
|
||||
? UTXOStatusIconStatus.confirmed
|
||||
: UTXOStatusIconStatus.unconfirmed,
|
||||
|
|
|
@ -54,6 +54,9 @@ class Firo extends Bip39HDCurrency with ElectrumXCurrencyInterface {
|
|||
@override
|
||||
int get minConfirms => 1;
|
||||
|
||||
@override
|
||||
int get minCoinbaseConfirms => 100;
|
||||
|
||||
@override
|
||||
bool get torSupport => true;
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ abstract class CryptoCurrency {
|
|||
bool get torSupport => false;
|
||||
|
||||
int get minConfirms;
|
||||
int get minCoinbaseConfirms => minConfirms;
|
||||
|
||||
// TODO: [prio=low] could be handled differently as (at least) epiccash does not use this
|
||||
String get genesisHash;
|
||||
|
|
|
@ -129,6 +129,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
|
|||
(e) => !e.isConfirmed(
|
||||
currentHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
),
|
||||
);
|
||||
if (utxos.isEmpty) {
|
||||
|
@ -330,7 +331,11 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
|
|||
final height = await chainHeight;
|
||||
for (final output in (await mainDB.getUTXOs(walletId).findAll())) {
|
||||
if (!output.isBlocked &&
|
||||
output.isConfirmed(height, cryptoCurrency.minConfirms)) {
|
||||
output.isConfirmed(
|
||||
height,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
)) {
|
||||
available += output.value;
|
||||
inputCount++;
|
||||
}
|
||||
|
@ -448,7 +453,11 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
|
|||
.findFirst();
|
||||
|
||||
if (storedTx == null ||
|
||||
!storedTx.isConfirmed(currentHeight, cryptoCurrency.minConfirms)) {
|
||||
!storedTx.isConfirmed(
|
||||
currentHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
)) {
|
||||
final tx = await electrumXCachedClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
|
@ -1060,6 +1069,7 @@ class BitcoinFrostWallet<T extends FrostCurrency> extends Wallet<T>
|
|||
if (utxo.isConfirmed(
|
||||
currentChainHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
)) {
|
||||
satoshiBalanceSpendable += utxoAmount;
|
||||
} else {
|
||||
|
|
|
@ -592,7 +592,11 @@ class FiroWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T>
|
|||
);
|
||||
|
||||
if (_unconfirmedTxids.contains(tx.txid)) {
|
||||
if (tx.isConfirmed(await chainHeight, cryptoCurrency.minConfirms)) {
|
||||
if (tx.isConfirmed(
|
||||
await chainHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
)) {
|
||||
txns.add(tx);
|
||||
_unconfirmedTxids.removeWhere((e) => e == tx.txid);
|
||||
} else {
|
||||
|
|
|
@ -309,6 +309,7 @@ abstract class Bip39HDWallet<T extends Bip39HDCurrency> extends Bip39Wallet<T>
|
|||
if (utxo.isConfirmed(
|
||||
currentChainHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
)) {
|
||||
satoshiBalanceSpendable += utxoAmount;
|
||||
} else {
|
||||
|
|
|
@ -141,6 +141,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
e.isConfirmed(
|
||||
currentChainHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
)),
|
||||
)
|
||||
.toList();
|
||||
|
@ -1920,6 +1921,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
e.isConfirmed(
|
||||
info.cachedChainHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
|
|
@ -925,6 +925,7 @@ mixin LelantusInterface<T extends ElectrumXCurrencyInterface>
|
|||
if (availableOutputs[i].isConfirmed(
|
||||
currentChainHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
) ==
|
||||
true &&
|
||||
!(availableOutputs[i].isCoinbase &&
|
||||
|
|
|
@ -479,6 +479,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
|
|||
availableOutputs[i].isConfirmed(
|
||||
await fetchChainHeight(),
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
) ==
|
||||
true) {
|
||||
spendableOutputs.add(availableOutputs[i]);
|
||||
|
|
|
@ -121,6 +121,7 @@ mixin RbfInterface<T extends ElectrumXCurrencyInterface>
|
|||
(e) => !e.isConfirmed(
|
||||
height,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -1750,6 +1750,7 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
|||
(e) => !e.isConfirmed(
|
||||
currentHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -1845,7 +1846,11 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
|||
.where(
|
||||
(e) =>
|
||||
canCPFP ||
|
||||
e.isConfirmed(currentHeight, cryptoCurrency.minConfirms),
|
||||
e.isConfirmed(
|
||||
currentHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
cryptoCurrency.minCoinbaseConfirms,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
|
|
Loading…
Reference in a new issue