mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-02-02 19:26:37 +00:00
port recent updates from bitcoin_wallet to particl_wallet
This commit is contained in:
parent
6c9690dcf5
commit
61f3135889
1 changed files with 92 additions and 31 deletions
|
@ -10,8 +10,8 @@ import 'package:bitcoindart/bitcoindart.dart';
|
||||||
import 'package:bs58check/bs58check.dart' as bs58check;
|
import 'package:bs58check/bs58check.dart' as bs58check;
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
|
import 'package:devicelocale/devicelocale.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||||
|
@ -194,20 +194,24 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
Future<Decimal> get availableBalance async {
|
Future<Decimal> get availableBalance async {
|
||||||
final data = await utxoData;
|
final data = await utxoData;
|
||||||
return Format.satoshisToAmount(
|
return Format.satoshisToAmount(
|
||||||
data.satoshiBalance - data.satoshiBalanceUnconfirmed);
|
data.satoshiBalance - data.satoshiBalanceUnconfirmed,
|
||||||
|
coin: coin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Decimal> get pendingBalance async {
|
Future<Decimal> get pendingBalance async {
|
||||||
final data = await utxoData;
|
final data = await utxoData;
|
||||||
return Format.satoshisToAmount(data.satoshiBalanceUnconfirmed);
|
return Format.satoshisToAmount(
|
||||||
|
data.satoshiBalanceUnconfirmed,
|
||||||
|
coin: coin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Decimal> get balanceMinusMaxFee async =>
|
Future<Decimal> get balanceMinusMaxFee async =>
|
||||||
(await availableBalance) -
|
(await availableBalance) -
|
||||||
(Decimal.fromInt((await maxFee)) / Decimal.fromInt(Constants.satsPerCoin))
|
(Decimal.fromInt((await maxFee)) /
|
||||||
.toDecimal();
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
.toDecimal();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Decimal> get totalBalance async {
|
Future<Decimal> get totalBalance async {
|
||||||
|
@ -216,13 +220,19 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
.get<dynamic>(boxName: walletId, key: 'totalBalance') as int?;
|
.get<dynamic>(boxName: walletId, key: 'totalBalance') as int?;
|
||||||
if (totalBalance == null) {
|
if (totalBalance == null) {
|
||||||
final data = await utxoData;
|
final data = await utxoData;
|
||||||
return Format.satoshisToAmount(data.satoshiBalance);
|
return Format.satoshisToAmount(
|
||||||
|
data.satoshiBalance,
|
||||||
|
coin: coin);
|
||||||
} else {
|
} else {
|
||||||
return Format.satoshisToAmount(totalBalance);
|
return Format.satoshisToAmount(
|
||||||
|
totalBalance,
|
||||||
|
coin: coin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final data = await utxoData;
|
final data = await utxoData;
|
||||||
return Format.satoshisToAmount(data.satoshiBalance);
|
return Format.satoshisToAmount(
|
||||||
|
data.satoshiBalance,
|
||||||
|
coin: coin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -260,7 +270,8 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
@override
|
@override
|
||||||
Future<int> get maxFee async {
|
Future<int> get maxFee async {
|
||||||
final fee = (await fees).fast as String;
|
final fee = (await fees).fast as String;
|
||||||
final satsFee = Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin);
|
final satsFee =
|
||||||
|
Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin(coin));
|
||||||
return satsFee.floor().toBigInt().toInt();
|
return satsFee.floor().toBigInt().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1083,7 +1094,8 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
// check for send all
|
// check for send all
|
||||||
bool isSendAll = false;
|
bool isSendAll = false;
|
||||||
final balance = Format.decimalAmountToSatoshis(await availableBalance);
|
final balance =
|
||||||
|
Format.decimalAmountToSatoshis(await availableBalance, coin);
|
||||||
if (satoshiAmount == balance) {
|
if (satoshiAmount == balance) {
|
||||||
isSendAll = true;
|
isSendAll = true;
|
||||||
}
|
}
|
||||||
|
@ -1273,6 +1285,55 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
_transactionData ??= _fetchTransactionData();
|
_transactionData ??= _fetchTransactionData();
|
||||||
Future<TransactionData>? _transactionData;
|
Future<TransactionData>? _transactionData;
|
||||||
|
|
||||||
|
TransactionData? cachedTxData;
|
||||||
|
|
||||||
|
// TODO make sure this copied implementation from bitcoin_wallet.dart applies for particl just as well--or import it
|
||||||
|
// hack to add tx to txData before refresh completes
|
||||||
|
// required based on current app architecture where we don't properly store
|
||||||
|
// transactions locally in a good way
|
||||||
|
@override
|
||||||
|
Future<void> updateSentCachedTxData(Map<String, dynamic> txData) async {
|
||||||
|
final priceData =
|
||||||
|
await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency);
|
||||||
|
Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero;
|
||||||
|
final locale = await Devicelocale.currentLocale;
|
||||||
|
final String worthNow = Format.localizedStringAsFixed(
|
||||||
|
value:
|
||||||
|
((currentPrice * Decimal.fromInt(txData["recipientAmt"] as int)) /
|
||||||
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
.toDecimal(scaleOnInfinitePrecision: 2),
|
||||||
|
decimalPlaces: 2,
|
||||||
|
locale: locale!);
|
||||||
|
|
||||||
|
final tx = models.Transaction(
|
||||||
|
txid: txData["txid"] as String,
|
||||||
|
confirmedStatus: false,
|
||||||
|
timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
|
txType: "Sent",
|
||||||
|
amount: txData["recipientAmt"] as int,
|
||||||
|
worthNow: worthNow,
|
||||||
|
worthAtBlockTimestamp: worthNow,
|
||||||
|
fees: txData["fee"] as int,
|
||||||
|
inputSize: 0,
|
||||||
|
outputSize: 0,
|
||||||
|
inputs: [],
|
||||||
|
outputs: [],
|
||||||
|
address: txData["address"] as String,
|
||||||
|
height: -1,
|
||||||
|
confirmations: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cachedTxData == null) {
|
||||||
|
final data = await _fetchTransactionData();
|
||||||
|
_transactionData = Future(() => data);
|
||||||
|
}
|
||||||
|
|
||||||
|
final transactions = cachedTxData!.getAllTransactions();
|
||||||
|
transactions[tx.txid] = tx;
|
||||||
|
cachedTxData = models.TransactionData.fromMap(transactions);
|
||||||
|
_transactionData = Future(() => cachedTxData!);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool validateAddress(String address) {
|
bool validateAddress(String address) {
|
||||||
return Address.validateAddress(address, _network);
|
return Address.validateAddress(address, _network);
|
||||||
|
@ -1310,7 +1371,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
required CachedElectrumX cachedClient,
|
required CachedElectrumX cachedClient,
|
||||||
required TransactionNotificationTracker tracker,
|
required TransactionNotificationTracker tracker,
|
||||||
PriceAPI? priceAPI,
|
PriceAPI? priceAPI,
|
||||||
SecureStorageInterface? secureStore,
|
required SecureStorageInterface secureStore,
|
||||||
}) {
|
}) {
|
||||||
txTracker = tracker;
|
txTracker = tracker;
|
||||||
_walletId = walletId;
|
_walletId = walletId;
|
||||||
|
@ -1320,13 +1381,12 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
_cachedElectrumXClient = cachedClient;
|
_cachedElectrumXClient = cachedClient;
|
||||||
|
|
||||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||||
_secureStore =
|
_secureStore = secureStore;
|
||||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> updateNode(bool shouldRefresh) async {
|
Future<void> updateNode(bool shouldRefresh) async {
|
||||||
final failovers = NodeService()
|
final failovers = NodeService(secureStorageInterface: _secureStore)
|
||||||
.failoverNodesFor(coin: coin)
|
.failoverNodesFor(coin: coin)
|
||||||
.map((e) => ElectrumXNode(
|
.map((e) => ElectrumXNode(
|
||||||
address: e.host,
|
address: e.host,
|
||||||
|
@ -1364,7 +1424,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ElectrumXNode> getCurrentNode() async {
|
Future<ElectrumXNode> getCurrentNode() async {
|
||||||
final node = NodeService().getPrimaryNodeFor(coin: coin) ??
|
final node = NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) ??
|
||||||
DefaultNodes.getNodeFor(coin);
|
DefaultNodes.getNodeFor(coin);
|
||||||
|
|
||||||
return ElectrumXNode(
|
return ElectrumXNode(
|
||||||
|
@ -1439,9 +1499,9 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
numberOfBlocksFast: f,
|
numberOfBlocksFast: f,
|
||||||
numberOfBlocksAverage: m,
|
numberOfBlocksAverage: m,
|
||||||
numberOfBlocksSlow: s,
|
numberOfBlocksSlow: s,
|
||||||
fast: Format.decimalAmountToSatoshis(fast),
|
fast: Format.decimalAmountToSatoshis(fast, coin),
|
||||||
medium: Format.decimalAmountToSatoshis(medium),
|
medium: Format.decimalAmountToSatoshis(medium, coin),
|
||||||
slow: Format.decimalAmountToSatoshis(slow),
|
slow: Format.decimalAmountToSatoshis(slow, coin),
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info);
|
||||||
|
@ -1905,7 +1965,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
utxo["status"]["block_time"] = txn["blocktime"];
|
utxo["status"]["block_time"] = txn["blocktime"];
|
||||||
|
|
||||||
final fiatValue = ((Decimal.fromInt(value) * currentPrice) /
|
final fiatValue = ((Decimal.fromInt(value) * currentPrice) /
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toDecimal(scaleOnInfinitePrecision: 2);
|
.toDecimal(scaleOnInfinitePrecision: 2);
|
||||||
utxo["rawWorth"] = fiatValue;
|
utxo["rawWorth"] = fiatValue;
|
||||||
utxo["fiatWorth"] = fiatValue.toString();
|
utxo["fiatWorth"] = fiatValue.toString();
|
||||||
|
@ -1914,16 +1974,17 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
Decimal currencyBalanceRaw =
|
Decimal currencyBalanceRaw =
|
||||||
((Decimal.fromInt(satoshiBalance) * currentPrice) /
|
((Decimal.fromInt(satoshiBalance) * currentPrice) /
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toDecimal(scaleOnInfinitePrecision: 2);
|
.toDecimal(scaleOnInfinitePrecision: 2);
|
||||||
|
|
||||||
final Map<String, dynamic> result = {
|
final Map<String, dynamic> result = {
|
||||||
"total_user_currency": currencyBalanceRaw.toString(),
|
"total_user_currency": currencyBalanceRaw.toString(),
|
||||||
"total_sats": satoshiBalance,
|
"total_sats": satoshiBalance,
|
||||||
"total_btc": (Decimal.fromInt(satoshiBalance) /
|
"total_btc": (Decimal.fromInt(satoshiBalance) /
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toDecimal(scaleOnInfinitePrecision: Constants.decimalPlaces)
|
.toDecimal(
|
||||||
|
scaleOnInfinitePrecision: Constants.decimalPlacesForCoin(coin))
|
||||||
.toString(),
|
.toString(),
|
||||||
"outputArray": outputArray,
|
"outputArray": outputArray,
|
||||||
"unconfirmed": satoshiBalancePending,
|
"unconfirmed": satoshiBalancePending,
|
||||||
|
@ -2469,7 +2530,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
if (prevOut == out["n"]) {
|
if (prevOut == out["n"]) {
|
||||||
inputAmtSentFromWallet +=
|
inputAmtSentFromWallet +=
|
||||||
(Decimal.parse(out["value"]!.toString()) *
|
(Decimal.parse(out["value"]!.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
}
|
}
|
||||||
|
@ -2482,7 +2543,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
final String address = output["scriptPubKey"]!["address"] as String;
|
final String address = output["scriptPubKey"]!["address"] as String;
|
||||||
final value = output["value"]!;
|
final value = output["value"]!;
|
||||||
final _value = (Decimal.parse(value.toString()) *
|
final _value = (Decimal.parse(value.toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
totalOutput += _value;
|
totalOutput += _value;
|
||||||
|
@ -2507,7 +2568,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
final address = output["scriptPubKey"]["address"];
|
final address = output["scriptPubKey"]["address"];
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
final value = (Decimal.parse(output["value"].toString()) *
|
final value = (Decimal.parse(output["value"].toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
totalOut += value;
|
totalOut += value;
|
||||||
|
@ -2530,7 +2591,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
for (final out in tx["vout"] as List) {
|
for (final out in tx["vout"] as List) {
|
||||||
if (prevOut == out["n"]) {
|
if (prevOut == out["n"]) {
|
||||||
totalIn += (Decimal.parse(out["value"].toString()) *
|
totalIn += (Decimal.parse(out["value"].toString()) *
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toBigInt()
|
.toBigInt()
|
||||||
.toInt();
|
.toInt();
|
||||||
}
|
}
|
||||||
|
@ -2552,7 +2613,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
midSortedTx["amount"] = inputAmtSentFromWallet;
|
midSortedTx["amount"] = inputAmtSentFromWallet;
|
||||||
final String worthNow =
|
final String worthNow =
|
||||||
((currentPrice * Decimal.fromInt(inputAmtSentFromWallet)) /
|
((currentPrice * Decimal.fromInt(inputAmtSentFromWallet)) /
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toDecimal(scaleOnInfinitePrecision: 2)
|
.toDecimal(scaleOnInfinitePrecision: 2)
|
||||||
.toStringAsFixed(2);
|
.toStringAsFixed(2);
|
||||||
midSortedTx["worthNow"] = worthNow;
|
midSortedTx["worthNow"] = worthNow;
|
||||||
|
@ -2562,7 +2623,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
midSortedTx["amount"] = outputAmtAddressedToWallet;
|
midSortedTx["amount"] = outputAmtAddressedToWallet;
|
||||||
final worthNow =
|
final worthNow =
|
||||||
((currentPrice * Decimal.fromInt(outputAmtAddressedToWallet)) /
|
((currentPrice * Decimal.fromInt(outputAmtAddressedToWallet)) /
|
||||||
Decimal.fromInt(Constants.satsPerCoin))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
.toDecimal(scaleOnInfinitePrecision: 2)
|
.toDecimal(scaleOnInfinitePrecision: 2)
|
||||||
.toStringAsFixed(2);
|
.toStringAsFixed(2);
|
||||||
midSortedTx["worthNow"] = worthNow;
|
midSortedTx["worthNow"] = worthNow;
|
||||||
|
@ -3689,7 +3750,7 @@ class ParticlWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
Future<int> estimateFeeFor(int satoshiAmount, int feeRate) async {
|
||||||
final available = Format.decimalAmountToSatoshis(await availableBalance);
|
final available = Format.decimalAmountToSatoshis(await availableBalance, coin);
|
||||||
|
|
||||||
if (available == satoshiAmount) {
|
if (available == satoshiAmount) {
|
||||||
return satoshiAmount - sweepAllEstimate(feeRate);
|
return satoshiAmount - sweepAllEstimate(feeRate);
|
||||||
|
|
Loading…
Reference in a new issue