mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 17:57:40 +00:00
firo isar index and null address fix
This commit is contained in:
parent
38453ceafb
commit
9bb71b0e13
2 changed files with 337 additions and 73 deletions
|
@ -18,7 +18,6 @@ import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
||||||
import 'package:stackwallet/models/lelantus_coin.dart';
|
import 'package:stackwallet/models/lelantus_coin.dart';
|
||||||
import 'package:stackwallet/models/lelantus_fee_data.dart';
|
import 'package:stackwallet/models/lelantus_fee_data.dart';
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_paynym_extension.dart';
|
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
||||||
|
@ -103,28 +102,25 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
|
||||||
final subtractFeeFromAmount = arguments['subtractFeeFromAmount'] as bool;
|
final subtractFeeFromAmount = arguments['subtractFeeFromAmount'] as bool;
|
||||||
final mnemonic = arguments['mnemonic'] as String;
|
final mnemonic = arguments['mnemonic'] as String;
|
||||||
final index = arguments['index'] as int;
|
final index = arguments['index'] as int;
|
||||||
final price = arguments['price'] as Decimal;
|
|
||||||
final lelantusEntries =
|
final lelantusEntries =
|
||||||
arguments['lelantusEntries'] as List<DartLelantusEntry>;
|
arguments['lelantusEntries'] as List<DartLelantusEntry>;
|
||||||
final coin = arguments['coin'] as Coin;
|
final coin = arguments['coin'] as Coin;
|
||||||
final network = arguments['network'] as NetworkType?;
|
final network = arguments['network'] as NetworkType?;
|
||||||
final locktime = arguments['locktime'] as int;
|
final locktime = arguments['locktime'] as int;
|
||||||
final anonymitySets = arguments['_anonymity_sets'] as List<Map>?;
|
final anonymitySets = arguments['_anonymity_sets'] as List<Map>?;
|
||||||
final locale = arguments["locale"] as String;
|
|
||||||
if (!(network == null || anonymitySets == null)) {
|
if (!(network == null || anonymitySets == null)) {
|
||||||
var joinSplit = await isolateCreateJoinSplitTransaction(
|
var joinSplit = await isolateCreateJoinSplitTransaction(
|
||||||
spendAmount,
|
spendAmount,
|
||||||
address,
|
address,
|
||||||
subtractFeeFromAmount,
|
subtractFeeFromAmount,
|
||||||
mnemonic,
|
mnemonic,
|
||||||
index,
|
index,
|
||||||
price,
|
lelantusEntries,
|
||||||
lelantusEntries,
|
locktime,
|
||||||
locktime,
|
coin,
|
||||||
coin,
|
network,
|
||||||
network,
|
anonymitySets,
|
||||||
anonymitySets,
|
);
|
||||||
locale);
|
|
||||||
sendPort.send(joinSplit);
|
sendPort.send(joinSplit);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -496,13 +492,11 @@ Future<dynamic> isolateCreateJoinSplitTransaction(
|
||||||
bool subtractFeeFromAmount,
|
bool subtractFeeFromAmount,
|
||||||
String mnemonic,
|
String mnemonic,
|
||||||
int index,
|
int index,
|
||||||
Decimal price,
|
|
||||||
List<DartLelantusEntry> lelantusEntries,
|
List<DartLelantusEntry> lelantusEntries,
|
||||||
int locktime,
|
int locktime,
|
||||||
Coin coin,
|
Coin coin,
|
||||||
NetworkType _network,
|
NetworkType _network,
|
||||||
List<Map<dynamic, dynamic>> anonymitySetsArg,
|
List<Map<dynamic, dynamic>> anonymitySetsArg,
|
||||||
String locale,
|
|
||||||
) async {
|
) async {
|
||||||
final estimateJoinSplitFee = await isolateEstimateJoinSplitFee(
|
final estimateJoinSplitFee = await isolateEstimateJoinSplitFee(
|
||||||
spendAmount, subtractFeeFromAmount, lelantusEntries, coin);
|
spendAmount, subtractFeeFromAmount, lelantusEntries, coin);
|
||||||
|
@ -647,12 +641,6 @@ Future<dynamic> isolateCreateJoinSplitTransaction(
|
||||||
"confirmed_status": false,
|
"confirmed_status": false,
|
||||||
"amount": Format.satoshisToAmount(amount, coin: coin).toDouble(),
|
"amount": Format.satoshisToAmount(amount, coin: coin).toDouble(),
|
||||||
"recipientAmt": amount,
|
"recipientAmt": amount,
|
||||||
"worthNow": Format.localizedStringAsFixed(
|
|
||||||
value: ((Decimal.fromInt(amount) * price) /
|
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
|
||||||
.toDecimal(scaleOnInfinitePrecision: 2),
|
|
||||||
decimalPlaces: 2,
|
|
||||||
locale: locale),
|
|
||||||
"address": address,
|
"address": address,
|
||||||
"timestamp": DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
"timestamp": DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
"subType": "join",
|
"subType": "join",
|
||||||
|
@ -869,11 +857,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
// _transactionData = Future(() => cachedTxData!);
|
// _transactionData = Future(() => cachedTxData!);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds wallet lelantus transaction data
|
|
||||||
Future<List<isar_models.Transaction>> get lelantusTransactionData =>
|
|
||||||
db.getTransactions(walletId).filter().isLelantusEqualTo(true).findAll();
|
|
||||||
// _lelantusTransactionData ??= _getLelantusTransactionData();
|
|
||||||
|
|
||||||
/// Holds the max fee that can be sent
|
/// Holds the max fee that can be sent
|
||||||
Future<int>? _maxFee;
|
Future<int>? _maxFee;
|
||||||
@override
|
@override
|
||||||
|
@ -2302,7 +2285,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
}
|
}
|
||||||
final jindexes = firoGetJIndex();
|
final jindexes = firoGetJIndex();
|
||||||
final transactions = await _txnData;
|
final transactions = await _txnData;
|
||||||
final lelantusTransactionsd = await lelantusTransactionData;
|
final lelantusTransactionsd = await db
|
||||||
|
.getTransactions(walletId)
|
||||||
|
.filter()
|
||||||
|
.isLelantusEqualTo(true)
|
||||||
|
.findAll();
|
||||||
|
|
||||||
List<LelantusCoin> coins = [];
|
List<LelantusCoin> coins = [];
|
||||||
|
|
||||||
|
@ -2369,7 +2356,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
element.values.any((elementCoin) => elementCoin.value == 0));
|
element.values.any((elementCoin) => elementCoin.value == 0));
|
||||||
}
|
}
|
||||||
final data = await _txnData;
|
final data = await _txnData;
|
||||||
final lData = await lelantusTransactionData;
|
final lData = await db
|
||||||
|
.getTransactions(walletId)
|
||||||
|
.filter()
|
||||||
|
.isLelantusEqualTo(true)
|
||||||
|
.findAll();
|
||||||
final currentChainHeight = await chainHeight;
|
final currentChainHeight = await chainHeight;
|
||||||
final jindexes = firoGetJIndex();
|
final jindexes = firoGetJIndex();
|
||||||
int intLelantusBalance = 0;
|
int intLelantusBalance = 0;
|
||||||
|
@ -2771,7 +2762,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
|
|
||||||
// Get all joinsplit transaction ids
|
// Get all joinsplit transaction ids
|
||||||
|
|
||||||
final listLelantusTxData = await lelantusTransactionData;
|
final listLelantusTxData = await db
|
||||||
|
.getTransactions(walletId)
|
||||||
|
.filter()
|
||||||
|
.isLelantusEqualTo(true)
|
||||||
|
.findAll();
|
||||||
List<String> joinsplits = [];
|
List<String> joinsplits = [];
|
||||||
for (final tx in listLelantusTxData) {
|
for (final tx in listLelantusTxData) {
|
||||||
if (tx.subType == isar_models.TransactionSubType.join) {
|
if (tx.subType == isar_models.TransactionSubType.join) {
|
||||||
|
@ -2790,6 +2785,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, Tuple2<isar_models.Address?, isar_models.Transaction>> data =
|
||||||
|
{};
|
||||||
|
for (final entry in listLelantusTxData) {
|
||||||
|
data[entry.txid] = Tuple2(entry.address.value, entry);
|
||||||
|
}
|
||||||
|
|
||||||
// Grab the most recent information on all the joinsplits
|
// Grab the most recent information on all the joinsplits
|
||||||
|
|
||||||
final updatedJSplit = await getJMintTransactions(
|
final updatedJSplit = await getJMintTransactions(
|
||||||
|
@ -2801,26 +2802,29 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
final currentChainHeight = await chainHeight;
|
final currentChainHeight = await chainHeight;
|
||||||
|
|
||||||
// update all of joinsplits that are now confirmed.
|
// update all of joinsplits that are now confirmed.
|
||||||
for (final tx in updatedJSplit) {
|
for (final tx in updatedJSplit.entries) {
|
||||||
isar_models.Transaction? currentTx;
|
isar_models.Transaction? currentTx;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
currentTx = listLelantusTxData.firstWhere((e) => e.txid == tx.txid);
|
currentTx =
|
||||||
|
listLelantusTxData.firstWhere((e) => e.txid == tx.value.txid);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
currentTx = null;
|
currentTx = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTx == null) {
|
if (currentTx == null) {
|
||||||
// this send was accidentally not included in the list
|
// this send was accidentally not included in the list
|
||||||
tx.isLelantus = true;
|
tx.value.isLelantus = true;
|
||||||
listLelantusTxData.add(tx);
|
data[tx.value.txid] =
|
||||||
|
Tuple2(tx.value.address.value ?? tx.key, tx.value);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (currentTx.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS) !=
|
if (currentTx.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS) !=
|
||||||
tx.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) {
|
tx.value.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) {
|
||||||
listLelantusTxData.removeWhere((e) => e.txid == tx.txid);
|
tx.value.isLelantus = true;
|
||||||
tx.isLelantus = true;
|
data[tx.value.txid] =
|
||||||
listLelantusTxData.add(tx);
|
Tuple2(tx.value.address.value ?? tx.key, tx.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2844,19 +2848,31 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
if (value.type == isar_models.TransactionType.incoming &&
|
if (value.type == isar_models.TransactionType.incoming &&
|
||||||
value.subType != isar_models.TransactionSubType.mint) {
|
value.subType != isar_models.TransactionSubType.mint) {
|
||||||
// Every receive other than a mint should be shown. Mints will be collected and shown from the send side
|
// Every receive other than a mint should be shown. Mints will be collected and shown from the send side
|
||||||
listLelantusTxData.removeWhere((e) => e.txid == value.txid);
|
|
||||||
value.isLelantus = true;
|
value.isLelantus = true;
|
||||||
listLelantusTxData.add(value);
|
data[value.txid] = Tuple2(value.address.value, value);
|
||||||
} else if (value.type == isar_models.TransactionType.outgoing) {
|
} else if (value.type == isar_models.TransactionType.outgoing) {
|
||||||
// all sends should be shown, mints will be displayed correctly in the ui
|
// all sends should be shown, mints will be displayed correctly in the ui
|
||||||
listLelantusTxData.removeWhere((e) => e.txid == value.txid);
|
|
||||||
value.isLelantus = true;
|
value.isLelantus = true;
|
||||||
listLelantusTxData.add(value);
|
data[value.txid] = Tuple2(value.address.value, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize this whole lelantus process
|
// TODO: optimize this whole lelantus process
|
||||||
await db.putTransactions(listLelantusTxData);
|
|
||||||
|
final List<
|
||||||
|
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||||
|
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||||
|
|
||||||
|
for (final value in data.values) {
|
||||||
|
final transactionAddress = value.item1!;
|
||||||
|
final outs =
|
||||||
|
value.item2.outputs.where((_) => true).toList(growable: false);
|
||||||
|
final ins = value.item2.inputs.where((_) => true).toList(growable: false);
|
||||||
|
|
||||||
|
txnsData.add(Tuple4(value.item2, outs, ins, transactionAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
await addNewTransactionData(txnsData, walletId);
|
||||||
|
|
||||||
// // update the _lelantusTransactionData
|
// // update the _lelantusTransactionData
|
||||||
// final models.TransactionData newTxData =
|
// final models.TransactionData newTxData =
|
||||||
|
@ -2978,13 +2994,27 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
otherData: transactionInfo["otherData"] as String?,
|
otherData: transactionInfo["otherData"] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
transaction.address.value = await db
|
final transactionAddress = await db
|
||||||
.getAddresses(walletId)
|
.getAddresses(walletId)
|
||||||
.filter()
|
.filter()
|
||||||
.valueEqualTo(transactionInfo["address"] as String)
|
.valueEqualTo(transactionInfo["address"] as String)
|
||||||
.findFirst();
|
.findFirst() ??
|
||||||
|
isar_models.Address(
|
||||||
|
walletId: walletId,
|
||||||
|
value: transactionInfo["address"] as String,
|
||||||
|
derivationIndex: -1,
|
||||||
|
type: isar_models.AddressType.nonWallet,
|
||||||
|
subType: isar_models.AddressSubType.nonWallet,
|
||||||
|
publicKey: [],
|
||||||
|
);
|
||||||
|
|
||||||
await db.putTransaction(transaction);
|
final List<
|
||||||
|
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||||
|
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||||
|
|
||||||
|
txnsData.add(Tuple4(transaction, [], [], transactionAddress));
|
||||||
|
|
||||||
|
await addNewTransactionData(txnsData, walletId);
|
||||||
|
|
||||||
// final models.TransactionData newTxData =
|
// final models.TransactionData newTxData =
|
||||||
// models.TransactionData.fromMap(transactions);
|
// models.TransactionData.fromMap(transactions);
|
||||||
|
@ -3290,17 +3320,209 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||||
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||||
|
|
||||||
|
Set<String> changeAddresses = allAddresses
|
||||||
|
.where((e) => e.subType == isar_models.AddressSubType.change)
|
||||||
|
.map((e) => e.value)
|
||||||
|
.toSet();
|
||||||
|
|
||||||
for (final txObject in allTransactions) {
|
for (final txObject in allTransactions) {
|
||||||
final data = await parseTransaction(
|
// Logging.instance.log(txObject);
|
||||||
txObject,
|
List<String> sendersArray = [];
|
||||||
cachedElectrumXClient,
|
List<String> recipientsArray = [];
|
||||||
allAddresses,
|
|
||||||
coin,
|
// Usually only has value when txType = 'Send'
|
||||||
MINIMUM_CONFIRMATIONS,
|
int inputAmtSentFromWallet = 0;
|
||||||
walletId,
|
// Usually has value regardless of txType due to change addresses
|
||||||
|
int outputAmtAddressedToWallet = 0;
|
||||||
|
|
||||||
|
for (final input in txObject["vin"] as List) {
|
||||||
|
final address = input["address"] as String?;
|
||||||
|
if (address != null) {
|
||||||
|
sendersArray.add(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging.instance.log("sendersArray: $sendersArray");
|
||||||
|
|
||||||
|
for (final output in txObject["vout"] as List) {
|
||||||
|
final address = output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
|
output["scriptPubKey"]?["address"] as String?;
|
||||||
|
if (address != null) {
|
||||||
|
recipientsArray.add(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Logging.instance.log("recipientsArray: $recipientsArray");
|
||||||
|
|
||||||
|
final foundInSenders =
|
||||||
|
allAddresses.any((element) => sendersArray.contains(element.value));
|
||||||
|
// Logging.instance.log("foundInSenders: $foundInSenders");
|
||||||
|
|
||||||
|
String outAddress = "";
|
||||||
|
|
||||||
|
int fees = 0;
|
||||||
|
|
||||||
|
// If txType = Sent, then calculate inputAmtSentFromWallet, calculate who received how much in aliens array (check outputs)
|
||||||
|
if (foundInSenders) {
|
||||||
|
int outAmount = 0;
|
||||||
|
int inAmount = 0;
|
||||||
|
bool nFeesUsed = false;
|
||||||
|
|
||||||
|
for (final input in txObject["vin"] as List) {
|
||||||
|
final nFees = input["nFees"];
|
||||||
|
if (nFees != null) {
|
||||||
|
nFeesUsed = true;
|
||||||
|
fees = (Decimal.parse(nFees.toString()) *
|
||||||
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
.toBigInt()
|
||||||
|
.toInt();
|
||||||
|
}
|
||||||
|
final address = input["address"] as String?;
|
||||||
|
final value = input["valueSat"] as int?;
|
||||||
|
if (address != null && value != null) {
|
||||||
|
if (allAddresses.where((e) => e.value == address).isNotEmpty) {
|
||||||
|
inputAmtSentFromWallet += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
inAmount += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final output in txObject["vout"] as List) {
|
||||||
|
final address = output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
|
output["scriptPubKey"]?["address"] as String?;
|
||||||
|
final value = output["value"];
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
outAmount += (Decimal.parse(value.toString()) *
|
||||||
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
.toBigInt()
|
||||||
|
.toInt();
|
||||||
|
|
||||||
|
if (address != null) {
|
||||||
|
if (changeAddresses.contains(address)) {
|
||||||
|
inputAmtSentFromWallet -= (Decimal.parse(value.toString()) *
|
||||||
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
.toBigInt()
|
||||||
|
.toInt();
|
||||||
|
} else {
|
||||||
|
outAddress = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fees = nFeesUsed ? fees : inAmount - outAmount;
|
||||||
|
inputAmtSentFromWallet -= inAmount - outAmount;
|
||||||
|
} else {
|
||||||
|
for (final input in txObject["vin"] as List) {
|
||||||
|
final nFees = input["nFees"];
|
||||||
|
if (nFees != null) {
|
||||||
|
fees += (Decimal.parse(nFees.toString()) *
|
||||||
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
.toBigInt()
|
||||||
|
.toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final output in txObject["vout"] as List) {
|
||||||
|
final addresses = output["scriptPubKey"]["addresses"] as List?;
|
||||||
|
if (addresses != null && addresses.isNotEmpty) {
|
||||||
|
final address = addresses[0] as String;
|
||||||
|
final value = output["value"] ?? 0;
|
||||||
|
// Logging.instance.log(address + value.toString());
|
||||||
|
|
||||||
|
if (allAddresses.where((e) => e.value == address).isNotEmpty) {
|
||||||
|
outputAmtAddressedToWallet += (Decimal.parse(value.toString()) *
|
||||||
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
.toBigInt()
|
||||||
|
.toInt();
|
||||||
|
outAddress = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isar_models.TransactionType type;
|
||||||
|
isar_models.TransactionSubType subType =
|
||||||
|
isar_models.TransactionSubType.none;
|
||||||
|
int amount;
|
||||||
|
if (foundInSenders) {
|
||||||
|
type = isar_models.TransactionType.outgoing;
|
||||||
|
amount = inputAmtSentFromWallet;
|
||||||
|
|
||||||
|
if (txObject["vout"][0]["scriptPubKey"]["type"] == "lelantusmint") {
|
||||||
|
subType = isar_models.TransactionSubType.mint;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = isar_models.TransactionType.incoming;
|
||||||
|
amount = outputAmtAddressedToWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
final transactionAddress =
|
||||||
|
allAddresses.firstWhere((e) => e.value == outAddress,
|
||||||
|
orElse: () => isar_models.Address(
|
||||||
|
walletId: walletId,
|
||||||
|
value: outAddress,
|
||||||
|
derivationIndex: -1,
|
||||||
|
type: isar_models.AddressType.nonWallet,
|
||||||
|
subType: isar_models.AddressSubType.nonWallet,
|
||||||
|
publicKey: [],
|
||||||
|
));
|
||||||
|
|
||||||
|
final tx = isar_models.Transaction(
|
||||||
|
walletId: walletId,
|
||||||
|
txid: txObject["txid"] as String,
|
||||||
|
timestamp: txObject["blocktime"] as int? ??
|
||||||
|
(DateTime.now().millisecondsSinceEpoch ~/ 1000),
|
||||||
|
type: type,
|
||||||
|
subType: subType,
|
||||||
|
amount: amount,
|
||||||
|
fee: fees,
|
||||||
|
height: txObject["height"] as int? ?? 0,
|
||||||
|
isCancelled: false,
|
||||||
|
isLelantus: false,
|
||||||
|
slateId: null,
|
||||||
|
otherData: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
txnsData.add(data);
|
List<isar_models.Output> outs = [];
|
||||||
|
List<isar_models.Input> ins = [];
|
||||||
|
|
||||||
|
for (final json in txObject["vin"] as List) {
|
||||||
|
bool isCoinBase = json['coinbase'] != null;
|
||||||
|
final input = isar_models.Input(
|
||||||
|
walletId: walletId,
|
||||||
|
txid: json['txid'] as String? ?? "",
|
||||||
|
vout: json['vout'] as int? ?? -1,
|
||||||
|
scriptSig: json['scriptSig']?['hex'] as String?,
|
||||||
|
scriptSigAsm: json['scriptSig']?['asm'] as String?,
|
||||||
|
isCoinbase: isCoinBase ? isCoinBase : json['is_coinbase'] as bool?,
|
||||||
|
sequence: json['sequence'] as int?,
|
||||||
|
innerRedeemScriptAsm: json['innerRedeemscriptAsm'] as String?,
|
||||||
|
);
|
||||||
|
ins.add(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final json in txObject["vout"] as List) {
|
||||||
|
final output = isar_models.Output(
|
||||||
|
walletId: walletId,
|
||||||
|
scriptPubKey: json['scriptPubKey']?['hex'] as String?,
|
||||||
|
scriptPubKeyAsm: json['scriptPubKey']?['asm'] as String?,
|
||||||
|
scriptPubKeyType: json['scriptPubKey']?['type'] as String?,
|
||||||
|
scriptPubKeyAddress:
|
||||||
|
json["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
|
json['scriptPubKey']['type'] as String,
|
||||||
|
value: Format.decimalAmountToSatoshis(
|
||||||
|
Decimal.parse(json["value"].toString()),
|
||||||
|
coin,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
outs.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
txnsData.add(Tuple4(tx, outs, ins, transactionAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
await addNewTransactionData(txnsData, walletId);
|
await addNewTransactionData(txnsData, walletId);
|
||||||
|
@ -3970,7 +4192,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
changeIndex = i;
|
changeIndex = i;
|
||||||
final addr = isar_models.Address(
|
final addr = isar_models.Address(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
value: address,
|
value: _address,
|
||||||
publicKey: Format.stringToUint8List(
|
publicKey: Format.stringToUint8List(
|
||||||
changeDerivation['publicKey'] as String),
|
changeDerivation['publicKey'] as String),
|
||||||
type: isar_models.AddressType.p2pkh,
|
type: isar_models.AddressType.p2pkh,
|
||||||
|
@ -4046,7 +4268,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
Future<void> _restore(int latestSetId, Map<dynamic, dynamic> setDataMap,
|
Future<void> _restore(int latestSetId, Map<dynamic, dynamic> setDataMap,
|
||||||
dynamic usedSerialNumbers) async {
|
dynamic usedSerialNumbers) async {
|
||||||
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
|
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
|
||||||
final dataFuture = _txnData;
|
final dataFuture = _refreshTransactions();
|
||||||
|
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "restore",
|
"function": "restore",
|
||||||
|
@ -4069,7 +4291,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
stop(receivePort);
|
stop(receivePort);
|
||||||
|
|
||||||
final message = await staticProcessRestore(
|
final message = await staticProcessRestore(
|
||||||
(await dataFuture),
|
(await _txnData),
|
||||||
result as Map<dynamic, dynamic>,
|
result as Map<dynamic, dynamic>,
|
||||||
await chainHeight,
|
await chainHeight,
|
||||||
);
|
);
|
||||||
|
@ -4082,6 +4304,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
|
|
||||||
final transactionMap =
|
final transactionMap =
|
||||||
message["newTxMap"] as Map<String, isar_models.Transaction>;
|
message["newTxMap"] as Map<String, isar_models.Transaction>;
|
||||||
|
Map<String, Tuple2<isar_models.Address?, isar_models.Transaction>> data =
|
||||||
|
{};
|
||||||
|
|
||||||
|
for (final entry in transactionMap.entries) {
|
||||||
|
data[entry.key] = Tuple2(entry.value.address.value, entry.value);
|
||||||
|
}
|
||||||
|
|
||||||
// Create the joinsplit transactions.
|
// Create the joinsplit transactions.
|
||||||
final spendTxs = await getJMintTransactions(
|
final spendTxs = await getJMintTransactions(
|
||||||
|
@ -4090,11 +4318,37 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
coin,
|
coin,
|
||||||
);
|
);
|
||||||
Logging.instance.log(spendTxs, level: LogLevel.Info);
|
Logging.instance.log(spendTxs, level: LogLevel.Info);
|
||||||
for (var element in spendTxs) {
|
|
||||||
transactionMap[element.txid] = element;
|
for (var element in spendTxs.entries) {
|
||||||
|
final address = element.value.address.value ??
|
||||||
|
data[element.value.txid]?.item1 ??
|
||||||
|
element.key;
|
||||||
|
// isar_models.Address(
|
||||||
|
// walletId: walletId,
|
||||||
|
// value: transactionInfo["address"] as String,
|
||||||
|
// derivationIndex: -1,
|
||||||
|
// type: isar_models.AddressType.nonWallet,
|
||||||
|
// subType: isar_models.AddressSubType.nonWallet,
|
||||||
|
// publicKey: [],
|
||||||
|
// );
|
||||||
|
|
||||||
|
data[element.value.txid] = Tuple2(address, element.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.putTransactions(transactionMap.values.toList());
|
final List<
|
||||||
|
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||||
|
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||||
|
|
||||||
|
for (final value in data.values) {
|
||||||
|
final transactionAddress = value.item1!;
|
||||||
|
final outs =
|
||||||
|
value.item2.outputs.where((_) => true).toList(growable: false);
|
||||||
|
final ins = value.item2.inputs.where((_) => true).toList(growable: false);
|
||||||
|
|
||||||
|
txnsData.add(Tuple4(value.item2, outs, ins, transactionAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
await addNewTransactionData(txnsData, walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Map<String, dynamic>>> fetchAnonymitySets() async {
|
Future<List<Map<String, dynamic>>> fetchAnonymitySets() async {
|
||||||
|
@ -4474,7 +4728,8 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
return allTransactions;
|
return allTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<isar_models.Transaction>> getJMintTransactions(
|
Future<Map<isar_models.Address, isar_models.Transaction>>
|
||||||
|
getJMintTransactions(
|
||||||
CachedElectrumX cachedClient,
|
CachedElectrumX cachedClient,
|
||||||
List<String> transactions,
|
List<String> transactions,
|
||||||
// String currency,
|
// String currency,
|
||||||
|
@ -4483,7 +4738,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
// String locale,
|
// String locale,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
List<isar_models.Transaction> txs = [];
|
Map<isar_models.Address, isar_models.Transaction> txs = {};
|
||||||
List<Map<String, dynamic>> allTransactions =
|
List<Map<String, dynamic>> allTransactions =
|
||||||
await fastFetch(transactions);
|
await fastFetch(transactions);
|
||||||
|
|
||||||
|
@ -4522,13 +4777,21 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
otherData: null,
|
otherData: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
txn.address.value = await db
|
final address = await db
|
||||||
.getAddresses(walletId)
|
.getAddresses(walletId)
|
||||||
.filter()
|
.filter()
|
||||||
.valueEqualTo(tx["address"] as String)
|
.valueEqualTo(tx["address"] as String)
|
||||||
.findFirst();
|
.findFirst() ??
|
||||||
|
isar_models.Address(
|
||||||
|
walletId: walletId,
|
||||||
|
value: tx["address"] as String,
|
||||||
|
derivationIndex: -2,
|
||||||
|
type: isar_models.AddressType.nonWallet,
|
||||||
|
subType: isar_models.AddressSubType.unknown,
|
||||||
|
publicKey: [],
|
||||||
|
);
|
||||||
|
|
||||||
txs.add(txn);
|
txs[address] = txn;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Exception caught in getJMintTransactions(): $e\n$s",
|
"Exception caught in getJMintTransactions(): $e\n$s",
|
||||||
|
|
|
@ -49,7 +49,8 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
|
||||||
coin.requiredConfirmations,
|
coin.requiredConfirmations,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_transaction.subType == TransactionSubType.mint) {
|
if (type != TransactionType.incoming &&
|
||||||
|
_transaction.subType == TransactionSubType.mint) {
|
||||||
// if (type == "Received") {
|
// if (type == "Received") {
|
||||||
if (confirmedStatus) {
|
if (confirmedStatus) {
|
||||||
return "Anonymized";
|
return "Anonymized";
|
||||||
|
|
Loading…
Reference in a new issue