mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-03 17:29:23 +00:00
Merge branch 'staging' into balance
This commit is contained in:
commit
8bafcb7179
14 changed files with 261 additions and 172 deletions
|
@ -1,5 +1,5 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.8.0'
|
||||
ext.kotlin_version = '2.0.20'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit db7585d8cd493b143e0a0652c618904d1f636d1d
|
||||
Subproject commit c0b8994009d29bc7fd2f0f2edbb004c39bf93951
|
|
@ -3,7 +3,7 @@ PODS:
|
|||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- SwiftProtobuf
|
||||
- coinlib_flutter (0.3.2):
|
||||
- coinlib_flutter (0.5.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- connectivity_plus (0.0.1):
|
||||
|
@ -83,14 +83,14 @@ PODS:
|
|||
- SDWebImage/Core (5.13.2)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- sqlite3 (3.46.0):
|
||||
- sqlite3/common (= 3.46.0)
|
||||
- sqlite3/common (3.46.0)
|
||||
- sqlite3/fts5 (3.46.0):
|
||||
- "sqlite3 (3.46.0+1)":
|
||||
- "sqlite3/common (= 3.46.0+1)"
|
||||
- "sqlite3/common (3.46.0+1)"
|
||||
- "sqlite3/fts5 (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3/perf-threadsafe (3.46.0):
|
||||
- "sqlite3/perf-threadsafe (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3/rtree (3.46.0):
|
||||
- "sqlite3/rtree (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
|
@ -207,13 +207,13 @@ EXTERNAL SOURCES:
|
|||
|
||||
SPEC CHECKSUMS:
|
||||
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
|
||||
coinlib_flutter: 6abec900d67762a6e7ccfd567a3cd3ae00bbee35
|
||||
coinlib_flutter: 9275e8255ef67d3da33beb6e117d09ced4f46eb5
|
||||
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
||||
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
|
||||
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
|
||||
devicelocale: b22617f40038496deffba44747101255cee005b0
|
||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_libepiccash: 36241aa7d3126f6521529985ccb3dc5eaf7bb317
|
||||
flutter_libmonero: da68a616b73dd0374a8419c684fa6b6df2c44ffe
|
||||
|
@ -222,7 +222,7 @@ SPEC CHECKSUMS:
|
|||
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
||||
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
|
||||
frostdart: 4c72b69ccac2f13ede744107db046a125acce597
|
||||
integration_test: 13825b8a9334a850581300559b8839134b124670
|
||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
|
||||
lelantus: 417f0221260013dfc052cae9cf4b741b6479edba
|
||||
local_auth: 1740f55d7af0a2e2a8684ce225fe79d8931e808c
|
||||
|
@ -233,7 +233,7 @@ SPEC CHECKSUMS:
|
|||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
|
||||
share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
|
||||
sqlite3: 154b084339ede06960a5b3c8160066adc9176b7d
|
||||
sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630
|
||||
sqlite3_flutter_libs: 0d611efdf6d1c9297d5ab03dab21b75aeebdae31
|
||||
stack_wallet_backup: 5b8563aba5d8ffbf2ce1944331ff7294a0ec7c03
|
||||
SwiftProtobuf: 6ef3f0e422ef90d6605ca20b21a94f6c1324d6b3
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
|
|
|
@ -154,6 +154,8 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
}
|
||||
}
|
||||
|
||||
String _receivingAddressValidationErrorString = "";
|
||||
|
||||
void selectCrypto() async {
|
||||
if (ref.read(simplexProvider).supportedCryptos.isEmpty) {
|
||||
bool shouldPop = false;
|
||||
|
@ -1218,6 +1220,15 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
_address = newValue;
|
||||
setState(() {
|
||||
_addressToggleFlag = newValue.isNotEmpty;
|
||||
|
||||
// TODO [prio=low]: Validate address.
|
||||
if (newValue.startsWith("bc1p")) {
|
||||
// Display an error message or handle invalid address
|
||||
_receivingAddressValidationErrorString =
|
||||
"Taproot addresses are not allowed.";
|
||||
} else {
|
||||
_receivingAddressValidationErrorString = "";
|
||||
}
|
||||
});
|
||||
},
|
||||
focusNode: _receiveAddressFocusNode,
|
||||
|
@ -1430,6 +1441,14 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: isDesktop ? 10 : 4,
|
||||
),
|
||||
if (_receivingAddressValidationErrorString.isNotEmpty)
|
||||
Text(
|
||||
_receivingAddressValidationErrorString,
|
||||
style: STextStyles.errorSmall(context),
|
||||
),
|
||||
SizedBox(
|
||||
height: isDesktop ? 20 : 12,
|
||||
),
|
||||
|
|
|
@ -522,9 +522,11 @@ class _ConfirmTransactionViewState
|
|||
SelectableText(
|
||||
ref.watch(pAmountFormatter(coin)).format(
|
||||
amountWithoutChange,
|
||||
ethContract: ref
|
||||
.watch(pCurrentTokenWallet)
|
||||
?.tokenContract,
|
||||
ethContract: widget.isTokenTx
|
||||
? ref
|
||||
.watch(pCurrentTokenWallet)!
|
||||
.tokenContract
|
||||
: null,
|
||||
),
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
textAlign: TextAlign.right,
|
||||
|
@ -745,9 +747,11 @@ class _ConfirmTransactionViewState
|
|||
SelectableText(
|
||||
ref.watch(pAmountFormatter(coin)).format(
|
||||
amountWithoutChange,
|
||||
ethContract: ref
|
||||
.read(pCurrentTokenWallet)
|
||||
?.tokenContract,
|
||||
ethContract: widget.isTokenTx
|
||||
? ref
|
||||
.watch(pCurrentTokenWallet)!
|
||||
.tokenContract
|
||||
: null,
|
||||
),
|
||||
style: STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
|
|
|
@ -881,6 +881,48 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
}
|
||||
}
|
||||
|
||||
String _getSendAllTitle(bool showCoinControl, Set<UTXO> selectedUTXOs) {
|
||||
if (showCoinControl && selectedUTXOs.isNotEmpty) {
|
||||
return "Send all selected";
|
||||
}
|
||||
|
||||
return "Send all ${coin.ticker}";
|
||||
}
|
||||
|
||||
Amount _selectedUtxosAmount(Set<UTXO> utxos) => Amount(
|
||||
rawValue:
|
||||
utxos.map((e) => BigInt.from(e.value)).reduce((v, e) => v += e),
|
||||
fractionDigits: ref.read(pWalletCoin(walletId)).fractionDigits,
|
||||
);
|
||||
|
||||
Future<void> _sendAllTapped(bool showCoinControl) async {
|
||||
final Amount amount;
|
||||
|
||||
if (showCoinControl && selectedUTXOs.isNotEmpty) {
|
||||
amount = _selectedUtxosAmount(selectedUTXOs);
|
||||
} else if (isFiro) {
|
||||
switch (ref.read(publicPrivateBalanceStateProvider.state).state) {
|
||||
case FiroType.public:
|
||||
amount = ref.read(pWalletBalance(walletId)).spendable;
|
||||
break;
|
||||
case FiroType.lelantus:
|
||||
amount = ref.read(pWalletBalanceSecondary(walletId)).spendable;
|
||||
break;
|
||||
case FiroType.spark:
|
||||
amount = ref.read(pWalletBalanceTertiary(walletId)).spendable;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
amount = ref.read(pWalletBalance(walletId)).spendable;
|
||||
}
|
||||
|
||||
cryptoAmountController.text = ref.read(pAmountFormatter(coin)).format(
|
||||
amount,
|
||||
withUnitName: false,
|
||||
);
|
||||
_cryptoAmountChanged();
|
||||
}
|
||||
|
||||
bool get isPaynymSend => widget.accountLite != null;
|
||||
|
||||
bool isCustomFee = false;
|
||||
|
@ -1772,59 +1814,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
),
|
||||
if (coin is! Ethereum && coin is! Tezos)
|
||||
CustomTextButton(
|
||||
text: "Send all ${coin.ticker}",
|
||||
onTap: () async {
|
||||
if (isFiro) {
|
||||
final Amount amount;
|
||||
switch (ref
|
||||
.read(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state,
|
||||
)
|
||||
.state) {
|
||||
case FiroType.public:
|
||||
amount = ref
|
||||
.read(pWalletBalance(walletId))
|
||||
.spendable;
|
||||
break;
|
||||
case FiroType.lelantus:
|
||||
amount = ref
|
||||
.read(
|
||||
pWalletBalanceSecondary(
|
||||
walletId,
|
||||
),
|
||||
)
|
||||
.spendable;
|
||||
break;
|
||||
case FiroType.spark:
|
||||
amount = ref
|
||||
.read(
|
||||
pWalletBalanceTertiary(
|
||||
walletId,
|
||||
),
|
||||
)
|
||||
.spendable;
|
||||
break;
|
||||
}
|
||||
|
||||
cryptoAmountController.text = ref
|
||||
.read(pAmountFormatter(coin))
|
||||
.format(
|
||||
amount,
|
||||
withUnitName: false,
|
||||
);
|
||||
} else {
|
||||
cryptoAmountController.text = ref
|
||||
.read(pAmountFormatter(coin))
|
||||
.format(
|
||||
ref
|
||||
.read(pWalletBalance(walletId))
|
||||
.spendable,
|
||||
withUnitName: false,
|
||||
);
|
||||
}
|
||||
_cryptoAmountChanged();
|
||||
},
|
||||
text: _getSendAllTitle(
|
||||
showCoinControl, selectedUTXOs),
|
||||
onTap: () => _sendAllTapped(showCoinControl),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -357,6 +357,8 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
|||
focusNode: _toFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
onChanged: (value) {
|
||||
ref.read(desktopExchangeModelProvider)!.recipientAddress =
|
||||
_toController.text;
|
||||
widget.enableNextChanged.call(
|
||||
_next(),
|
||||
);
|
||||
|
@ -504,6 +506,8 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
|||
focusNode: _refundFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
onChanged: (value) {
|
||||
ref.read(desktopExchangeModelProvider)!.refundAddress =
|
||||
_refundController.text;
|
||||
widget.enableNextChanged.call(
|
||||
_next(),
|
||||
);
|
||||
|
|
|
@ -18,6 +18,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
import '../../../../models/isar/models/blockchain_data/utxo.dart';
|
||||
import '../../../../models/isar/models/contact_entry.dart';
|
||||
import '../../../../models/paynym/paynym_account_lite.dart';
|
||||
import '../../../../models/send_view_auto_fill_data.dart';
|
||||
|
@ -932,30 +933,45 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
ref.read(pSendAmount.notifier).state = amount;
|
||||
}
|
||||
|
||||
Future<void> sendAllTapped() async {
|
||||
final info = ref.read(pWalletInfo(walletId));
|
||||
String _getSendAllTitle(bool showCoinControl, Set<UTXO> selectedUTXOs) {
|
||||
if (showCoinControl && selectedUTXOs.isNotEmpty) {
|
||||
return "Send all selected";
|
||||
}
|
||||
|
||||
if (coin is Firo) {
|
||||
return "Send all ${coin.ticker}";
|
||||
}
|
||||
|
||||
Amount _selectedUtxosAmount(Set<UTXO> utxos) => Amount(
|
||||
rawValue:
|
||||
utxos.map((e) => BigInt.from(e.value)).reduce((v, e) => v += e),
|
||||
fractionDigits: ref.read(pWalletCoin(walletId)).fractionDigits,
|
||||
);
|
||||
|
||||
Future<void> _sendAllTapped(bool showCoinControl) async {
|
||||
final Amount amount;
|
||||
|
||||
if (showCoinControl && ref.read(desktopUseUTXOs).isNotEmpty) {
|
||||
amount = _selectedUtxosAmount(ref.read(desktopUseUTXOs));
|
||||
} else if (coin is Firo) {
|
||||
switch (ref.read(publicPrivateBalanceStateProvider.state).state) {
|
||||
case FiroType.public:
|
||||
cryptoAmountController.text = info.cachedBalance.spendable.decimal
|
||||
.toStringAsFixed(coin.fractionDigits);
|
||||
amount = ref.read(pWalletBalance(walletId)).spendable;
|
||||
break;
|
||||
case FiroType.lelantus:
|
||||
cryptoAmountController.text = info
|
||||
.cachedBalanceSecondary.spendable.decimal
|
||||
.toStringAsFixed(coin.fractionDigits);
|
||||
amount = ref.read(pWalletBalanceSecondary(walletId)).spendable;
|
||||
break;
|
||||
case FiroType.spark:
|
||||
cryptoAmountController.text = info
|
||||
.cachedBalanceTertiary.spendable.decimal
|
||||
.toStringAsFixed(coin.fractionDigits);
|
||||
amount = ref.read(pWalletBalanceTertiary(walletId)).spendable;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cryptoAmountController.text = info.cachedBalance.spendable.decimal
|
||||
.toStringAsFixed(coin.fractionDigits);
|
||||
amount = ref.read(pWalletBalance(walletId)).spendable;
|
||||
}
|
||||
|
||||
cryptoAmountController.text = ref.read(pAmountFormatter(coin)).format(
|
||||
amount,
|
||||
withUnitName: false,
|
||||
);
|
||||
}
|
||||
|
||||
void _showDesktopCoinControl() async {
|
||||
|
@ -1280,8 +1296,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
),
|
||||
if (coin is! Ethereum && coin is! Tezos)
|
||||
CustomTextButton(
|
||||
text: "Send all ${coin.ticker}",
|
||||
onTap: sendAllTapped,
|
||||
text: _getSendAllTitle(
|
||||
showCoinControl,
|
||||
ref.watch(desktopUseUTXOs),
|
||||
),
|
||||
onTap: () => _sendAllTapped(showCoinControl),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -105,6 +105,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
required TxData txData,
|
||||
required bool coinControl,
|
||||
required bool isSendAll,
|
||||
required bool isSendAllCoinControlUtxos,
|
||||
int additionalOutputs = 0,
|
||||
List<UTXO>? utxos,
|
||||
}) async {
|
||||
|
@ -144,7 +145,9 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
|
||||
if (spendableSatoshiValue < satoshiAmountToSend) {
|
||||
throw Exception("Insufficient balance");
|
||||
} else if (spendableSatoshiValue == satoshiAmountToSend && !isSendAll) {
|
||||
} else if (spendableSatoshiValue == satoshiAmountToSend &&
|
||||
!isSendAll &&
|
||||
!isSendAllCoinControlUtxos) {
|
||||
throw Exception("Insufficient balance to pay transaction fee");
|
||||
}
|
||||
|
||||
|
@ -220,7 +223,13 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
// gather required signing data
|
||||
final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse);
|
||||
|
||||
if (isSendAll) {
|
||||
if (isSendAll || isSendAllCoinControlUtxos) {
|
||||
if (satoshiAmountToSend != satoshisBeingUsed) {
|
||||
throw Exception(
|
||||
"Something happened that should never actually happen. "
|
||||
"Please report this error to the developers.",
|
||||
);
|
||||
}
|
||||
return await _sendAllBuilder(
|
||||
txData: txData,
|
||||
recipientAddress: recipientAddress,
|
||||
|
@ -357,6 +366,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
additionalOutputs: additionalOutputs + 1,
|
||||
utxos: utxos,
|
||||
coinControl: coinControl,
|
||||
isSendAllCoinControlUtxos: isSendAllCoinControlUtxos,
|
||||
);
|
||||
}
|
||||
throw Exception("Insufficient balance to pay transaction fee");
|
||||
|
@ -827,6 +837,11 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
|
||||
Future<int> fetchChainHeight({int retries = 1}) async {
|
||||
try {
|
||||
// Ensure server version is initialized and genesis hash is checked.
|
||||
if (_serverVersion == null) {
|
||||
await _initializeServerVersionAndCheckGenesisHash();
|
||||
}
|
||||
|
||||
return await ClientManager.sharedInstance.getChainHeightFor(
|
||||
cryptoCurrency,
|
||||
);
|
||||
|
@ -1681,11 +1696,23 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
@override
|
||||
Future<TxData> prepareSend({required TxData txData}) async {
|
||||
try {
|
||||
if (txData.amount == null) {
|
||||
throw Exception("No recipients in attempted transaction!");
|
||||
}
|
||||
|
||||
final feeRateType = txData.feeRateType;
|
||||
final customSatsPerVByte = txData.satsPerVByte;
|
||||
final feeRateAmount = txData.feeRateAmount;
|
||||
final utxos = txData.utxos;
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final isSendAllCoinControlUtxos = coinControl &&
|
||||
txData.amount!.raw ==
|
||||
utxos
|
||||
.map((e) => e.value)
|
||||
.fold(BigInt.zero, (p, e) => p + BigInt.from(e));
|
||||
|
||||
if (customSatsPerVByte != null) {
|
||||
// check for send all
|
||||
bool isSendAll = false;
|
||||
|
@ -1694,8 +1721,6 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
if (coinControl &&
|
||||
this is CpfpInterface &&
|
||||
txData.amount ==
|
||||
|
@ -1709,6 +1734,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: coinControl,
|
||||
isSendAllCoinControlUtxos: isSendAllCoinControlUtxos,
|
||||
);
|
||||
|
||||
Logging.instance
|
||||
|
@ -1750,8 +1776,6 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final result = await coinSelection(
|
||||
txData: txData.copyWith(
|
||||
feeRateAmount: rate,
|
||||
|
@ -1759,6 +1783,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: coinControl,
|
||||
isSendAllCoinControlUtxos: isSendAllCoinControlUtxos,
|
||||
);
|
||||
|
||||
Logging.instance.log("prepare send: $result", level: LogLevel.Info);
|
||||
|
@ -1783,6 +1808,21 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
|
||||
@override
|
||||
Future<void> init() async {
|
||||
try {
|
||||
// Server features and genesis hash check deferred.
|
||||
// See _initializeServerVersionAndCheckGenesisHash.
|
||||
|
||||
await super.init();
|
||||
} catch (e, s) {
|
||||
// do nothing, still allow user into wallet
|
||||
Logging.instance.log(
|
||||
"$runtimeType init() did not complete: $e\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initializeServerVersionAndCheckGenesisHash() async {
|
||||
try {
|
||||
final features = await electrumXClient
|
||||
.getServerFeatures()
|
||||
|
@ -1794,17 +1834,14 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
|
|||
_parseServerVersion(features["server_version"] as String);
|
||||
|
||||
if (cryptoCurrency.genesisHash != features['genesis_hash']) {
|
||||
throw Exception("genesis hash does not match!");
|
||||
throw Exception("Genesis hash does not match!");
|
||||
}
|
||||
} catch (e, s) {
|
||||
// do nothing, still allow user into wallet
|
||||
Logging.instance.log(
|
||||
"$runtimeType init() did not complete: $e\n$s",
|
||||
"$runtimeType _initializeServerVersionAndCheckGenesisHash() did not complete: $e\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
|
||||
await super.init();
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
|
|
|
@ -23,6 +23,7 @@ import '../../isar/models/spark_coin.dart';
|
|||
import '../../isar/models/wallet_info.dart';
|
||||
import '../../models/tx_data.dart';
|
||||
import '../intermediate/bip39_hd_wallet.dart';
|
||||
import 'cpfp_interface.dart';
|
||||
import 'electrumx_interface.dart';
|
||||
|
||||
const kDefaultSparkIndex = 1;
|
||||
|
@ -1809,20 +1810,25 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
|||
throw Exception("Attempted send of zero amount");
|
||||
}
|
||||
|
||||
final utxos = txData.utxos;
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final utxosTotal = coinControl
|
||||
? utxos
|
||||
.map((e) => e.value)
|
||||
.fold(BigInt.zero, (p, e) => p + BigInt.from(e))
|
||||
: null;
|
||||
|
||||
if (coinControl && utxosTotal! < total) {
|
||||
throw Exception("Insufficient selected UTXOs!");
|
||||
}
|
||||
|
||||
final isSendAllCoinControlUtxos = coinControl && total == utxosTotal;
|
||||
|
||||
final currentHeight = await chainHeight;
|
||||
|
||||
// coin control not enabled for firo currently so we can ignore this
|
||||
// final utxosToUse = txData.utxos?.toList() ?? await mainDB.isar.utxos
|
||||
// .where()
|
||||
// .walletIdEqualTo(walletId)
|
||||
// .filter()
|
||||
// .isBlockedEqualTo(false)
|
||||
// .and()
|
||||
// .group((q) => q.usedEqualTo(false).or().usedIsNull())
|
||||
// .and()
|
||||
// .valueGreaterThan(0)
|
||||
// .findAll();
|
||||
final spendableUtxos = await mainDB.isar.utxos
|
||||
final availableOutputs = utxos?.toList() ??
|
||||
await mainDB.isar.utxos
|
||||
.where()
|
||||
.walletIdEqualTo(walletId)
|
||||
.filter()
|
||||
|
@ -1833,12 +1839,15 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
|||
.valueGreaterThan(0)
|
||||
.findAll();
|
||||
|
||||
spendableUtxos.removeWhere(
|
||||
(e) => !e.isConfirmed(
|
||||
currentHeight,
|
||||
cryptoCurrency.minConfirms,
|
||||
),
|
||||
);
|
||||
final canCPFP = this is CpfpInterface && coinControl;
|
||||
|
||||
final spendableUtxos = availableOutputs
|
||||
.where(
|
||||
(e) =>
|
||||
canCPFP ||
|
||||
e.isConfirmed(currentHeight, cryptoCurrency.minConfirms),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (spendableUtxos.isEmpty) {
|
||||
throw Exception("No available UTXOs found to anonymize");
|
||||
|
@ -1849,7 +1858,9 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
|
|||
.reduce((value, element) => value += element);
|
||||
|
||||
final bool subtractFeeFromAmount;
|
||||
if (available < total) {
|
||||
if (isSendAllCoinControlUtxos) {
|
||||
subtractFeeFromAmount = true;
|
||||
} else if (available < total) {
|
||||
throw Exception("Insufficient balance");
|
||||
} else if (available == total) {
|
||||
subtractFeeFromAmount = true;
|
||||
|
|
|
@ -11,8 +11,6 @@ import 'package:camera_windows/camera_windows.dart';
|
|||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:zxing2/qrcode.dart';
|
||||
|
||||
import '../../notifications/show_flush_bar.dart';
|
||||
|
@ -21,6 +19,8 @@ import '../../utilities/logger.dart';
|
|||
import '../../utilities/text_styles.dart';
|
||||
import 'desktop_dialog.dart';
|
||||
import 'desktop_dialog_close_button.dart';
|
||||
import 'primary_button.dart';
|
||||
import 'secondary_button.dart';
|
||||
|
||||
class QrCodeScannerDialog extends StatefulWidget {
|
||||
final Function(String) onQrCodeDetected;
|
||||
|
|
70
pubspec.lock
70
pubspec.lock
|
@ -37,10 +37,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: archive
|
||||
sha256: e0902a06f0e00414e4e3438a084580161279f137aeb862274710f29ec10cf01e
|
||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.9"
|
||||
version: "3.6.1"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -522,18 +522,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: "86add5ef97215562d2e090535b0a16f197902b10c369c558a100e74ea06e8659"
|
||||
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.3"
|
||||
version: "10.1.2"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64
|
||||
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
version: "7.0.1"
|
||||
devicelocale:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -643,10 +643,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
|
||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.3"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1105,18 +1105,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.4"
|
||||
version: "10.0.5"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.5"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1176,10 +1176,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
version: "0.11.1"
|
||||
memoize:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1192,10 +1192,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: meta
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
version: "1.15.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1417,18 +1417,18 @@ packages:
|
|||
dependency: "direct overridden"
|
||||
description:
|
||||
name: pinenacl
|
||||
sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9
|
||||
sha256: "57e907beaacbc3c024a098910b6240758e899674de07d6949a67b52fd984cbdf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.4"
|
||||
version: "0.6.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
version: "3.1.5"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1777,32 +1777,32 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: test
|
||||
sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073"
|
||||
sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.25.2"
|
||||
version: "1.25.7"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
version: "0.7.2"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4"
|
||||
sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
version: "0.6.4"
|
||||
tezart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "13fa937ea9a9fc34caf047e068df9535f65c27ad"
|
||||
resolved-ref: "13fa937ea9a9fc34caf047e068df9535f65c27ad"
|
||||
ref: d000cc245e51d3ff50e6467960fb3d9159d5b2a9
|
||||
resolved-ref: d000cc245e51d3ff50e6467960fb3d9159d5b2a9
|
||||
url: "https://github.com/cypherstack/tezart.git"
|
||||
source: git
|
||||
version: "2.0.5"
|
||||
|
@ -1995,10 +1995,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.1"
|
||||
version: "14.2.5"
|
||||
wakelock:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -2105,13 +2105,13 @@ packages:
|
|||
source: hosted
|
||||
version: "1.2.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: win32
|
||||
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
|
||||
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.2.0"
|
||||
version: "5.5.4"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -2178,5 +2178,5 @@ packages:
|
|||
source: hosted
|
||||
version: "0.2.3"
|
||||
sdks:
|
||||
dart: ">=3.3.4 <4.0.0"
|
||||
flutter: ">=3.19.6"
|
||||
dart: ">=3.5.2 <4.0.0"
|
||||
flutter: ">=3.24.2"
|
||||
|
|
|
@ -14,8 +14,8 @@ description: PLACEHOLDER
|
|||
version: PLACEHOLDER_V+PLACEHOLDER_B
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.4 <4.0.0"
|
||||
flutter: ^3.19.6
|
||||
sdk: ">=3.5.2 <4.0.0"
|
||||
flutter: ^3.24.2
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -84,7 +84,7 @@ dependencies:
|
|||
http: ^0.13.0
|
||||
local_auth: ^1.1.10
|
||||
permission_handler: ^11.0.0
|
||||
flutter_local_notifications: ^17.0.0
|
||||
flutter_local_notifications: ^17.2.2
|
||||
rxdart: ^0.27.3
|
||||
zxcvbn: ^1.0.0
|
||||
dart_numerics: ^0.0.6
|
||||
|
@ -134,7 +134,7 @@ dependencies:
|
|||
wakelock: ^0.6.2
|
||||
intl: ^0.17.0
|
||||
devicelocale: ^0.6.0
|
||||
device_info_plus: ^9.0.2
|
||||
device_info_plus: ^10.1.2
|
||||
keyboard_dismisser: ^3.0.0
|
||||
another_flushbar: ^1.10.28
|
||||
tuple: ^2.0.0
|
||||
|
@ -156,7 +156,7 @@ dependencies:
|
|||
dart_bs58: ^1.0.1
|
||||
dart_bs58check: ^3.0.2
|
||||
hex: ^0.2.0
|
||||
archive: ^3.3.2
|
||||
archive: ^3.6.1
|
||||
desktop_drop: ^0.4.1
|
||||
nanodart: ^2.0.0
|
||||
basic_utils: ^5.5.4
|
||||
|
@ -166,7 +166,7 @@ dependencies:
|
|||
tezart:
|
||||
git:
|
||||
url: https://github.com/cypherstack/tezart.git
|
||||
ref: 13fa937ea9a9fc34caf047e068df9535f65c27ad
|
||||
ref: d000cc245e51d3ff50e6467960fb3d9159d5b2a9
|
||||
socks5_proxy: ^1.0.3+dev.3
|
||||
convert: ^3.1.1
|
||||
flutter_hooks: ^0.20.3
|
||||
|
@ -224,6 +224,9 @@ flutter_native_splash:
|
|||
|
||||
dependency_overrides:
|
||||
|
||||
# needed for dart 3.5+ (at least for now)
|
||||
win32: ^5.5.4
|
||||
|
||||
# coin lib git for testing while waiting for publishing
|
||||
coinlib:
|
||||
git:
|
||||
|
@ -280,7 +283,7 @@ dependency_overrides:
|
|||
|
||||
crypto: 3.0.2
|
||||
analyzer: ^5.2.0
|
||||
pinenacl: ^0.3.3
|
||||
pinenacl: ^0.6.0
|
||||
http: ^0.13.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
|
|
Loading…
Reference in a new issue