mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 09:47:37 +00:00
update other coin's parse transaction and db update
This commit is contained in:
parent
e14c362574
commit
3414c71741
10 changed files with 267 additions and 1240 deletions
|
@ -2064,7 +2064,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address>> txnsData = [];
|
||||
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||
|
||||
for (final txObject in allTransactions) {
|
||||
final data = await parseTransaction(
|
||||
|
@ -2077,40 +2077,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
|
||||
txnsData.add(data);
|
||||
}
|
||||
await isar.writeTxn(() async {
|
||||
for (final data in txnsData) {
|
||||
final tx = data.item1;
|
||||
|
||||
// save transaction
|
||||
await isar.transactions.put(tx);
|
||||
|
||||
// link and save outputs
|
||||
if (data.item2.isNotEmpty) {
|
||||
await isar.outputs.putAll(data.item2);
|
||||
tx.outputs.addAll(data.item2);
|
||||
await tx.outputs.save();
|
||||
}
|
||||
|
||||
// link and save inputs
|
||||
if (data.item3.isNotEmpty) {
|
||||
await isar.inputs.putAll(data.item3);
|
||||
tx.inputs.addAll(data.item3);
|
||||
await tx.inputs.save();
|
||||
}
|
||||
|
||||
// check if address exists in db and add if it does not
|
||||
if (await isar.addresses
|
||||
.where()
|
||||
.valueEqualTo(data.item4.value)
|
||||
.findFirst() ==
|
||||
null) {
|
||||
await isar.addresses.put(data.item4);
|
||||
}
|
||||
// link and save address
|
||||
tx.address.value = data.item4;
|
||||
await tx.address.save();
|
||||
}
|
||||
});
|
||||
await addNewTransactionData(txnsData);
|
||||
}
|
||||
|
||||
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||
|
|
|
@ -1940,21 +1940,31 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
final currentHeight = await chainHeight;
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = await isar.addresses
|
||||
.filter()
|
||||
.valueEqualTo(txHash["address"] as String)
|
||||
.findFirst();
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
for (final txHash in allTxHashes) {
|
||||
final storedTx = await isar.transactions
|
||||
.where()
|
||||
.txidEqualTo(txHash["tx_hash"] as String)
|
||||
.findFirst();
|
||||
|
||||
if (storedTx == null ||
|
||||
!storedTx.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS)) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = await isar.addresses
|
||||
.filter()
|
||||
.valueEqualTo(txHash["address"] as String)
|
||||
.findFirst();
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
|
@ -1964,7 +1974,9 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
// Logging.instance.log("allTransactions length: ${allTransactions.length}",
|
||||
// level: LogLevel.Info);
|
||||
|
||||
final List<isar_models.Transaction> txns = [];
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address?>> txns = [];
|
||||
|
||||
for (final txData in allTransactions) {
|
||||
Set<String> inputAddresses = {};
|
||||
|
@ -2060,6 +2072,10 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
tx.timestamp = txData["blocktime"] as int? ??
|
||||
(DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
||||
|
||||
// this is the address initially used to fetch the txid
|
||||
isar_models.Address transactionAddress =
|
||||
txData["address"] as isar_models.Address;
|
||||
|
||||
if (mySentFromAddresses.isNotEmpty && myReceivedOnAddresses.isNotEmpty) {
|
||||
// tx is sent to self
|
||||
tx.type = isar_models.TransactionType.sentToSelf;
|
||||
|
@ -2069,6 +2085,17 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
// outgoing tx
|
||||
tx.type = isar_models.TransactionType.outgoing;
|
||||
tx.amount = amountSentFromWallet - changeAmount - fee;
|
||||
final possible =
|
||||
outputAddresses.difference(myChangeReceivedOnAddresses).first;
|
||||
|
||||
if (transactionAddress.value != possible) {
|
||||
transactionAddress = isar_models.Address()
|
||||
..value = possible
|
||||
..derivationIndex = -1
|
||||
..subType = AddressSubType.nonWallet
|
||||
..type = AddressType.nonWallet
|
||||
..publicKey = [];
|
||||
}
|
||||
} else {
|
||||
// incoming tx
|
||||
tx.type = isar_models.TransactionType.incoming;
|
||||
|
@ -2079,7 +2106,9 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
tx.subType = isar_models.TransactionSubType.none;
|
||||
|
||||
tx.fee = fee;
|
||||
tx.address.value = txData["address"] as isar_models.Address;
|
||||
|
||||
List<isar_models.Input> inputs = [];
|
||||
List<isar_models.Output> outputs = [];
|
||||
|
||||
for (final json in txData["vin"] as List) {
|
||||
bool isCoinBase = json['coinbase'] != null;
|
||||
|
@ -2092,7 +2121,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
isCoinBase ? isCoinBase : json['is_coinbase'] as bool?;
|
||||
input.sequence = json['sequence'] as int?;
|
||||
input.innerRedeemScriptAsm = json['innerRedeemscriptAsm'] as String?;
|
||||
tx.inputs.add(input);
|
||||
inputs.add(input);
|
||||
}
|
||||
|
||||
for (final json in txData["vout"] as List) {
|
||||
|
@ -2107,7 +2136,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
Decimal.parse(json["value"].toString()),
|
||||
coin,
|
||||
);
|
||||
tx.outputs.add(output);
|
||||
outputs.add(output);
|
||||
}
|
||||
|
||||
tx.height = txData["height"] as int?;
|
||||
|
@ -2116,12 +2145,10 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
tx.slateId = null;
|
||||
tx.otherData = null;
|
||||
|
||||
txns.add(tx);
|
||||
txns.add(Tuple4(tx, outputs, inputs, transactionAddress));
|
||||
}
|
||||
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.putAll(txns);
|
||||
});
|
||||
await addNewTransactionData(txns);
|
||||
}
|
||||
|
||||
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||
|
|
|
@ -1846,18 +1846,27 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
|
||||
await fastFetch(hashes);
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
final currentHeight = await chainHeight;
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
final storedTx = await isar.transactions
|
||||
.where()
|
||||
.txidEqualTo(txHash["tx_hash"] as String)
|
||||
.findFirst();
|
||||
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = txHash["address"];
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
if (storedTx == null ||
|
||||
!storedTx.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS)) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = txHash["address"];
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1871,6 +1880,10 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
}
|
||||
await fastFetch(vHashes.toList());
|
||||
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address?>> txns = [];
|
||||
|
||||
for (final txObject in allTransactions) {
|
||||
final txn = await parseTransaction(
|
||||
txObject,
|
||||
|
@ -1880,17 +1893,10 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
MINIMUM_CONFIRMATIONS,
|
||||
);
|
||||
|
||||
// final tx = await isar.transactions
|
||||
// .filter()
|
||||
// .txidMatches(midSortedTx.txid)
|
||||
// .findFirst();
|
||||
// // we don't need to check this but it saves a write tx instead of overwriting the transaction in Isar
|
||||
// if (tx == null) {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.put(txn.item1);
|
||||
});
|
||||
// }
|
||||
txns.add(txn);
|
||||
}
|
||||
|
||||
await addNewTransactionData(txns);
|
||||
}
|
||||
|
||||
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||
|
|
|
@ -3228,241 +3228,58 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
}
|
||||
}
|
||||
|
||||
bool _duplicateTxCheck(
|
||||
List<Map<String, dynamic>> allTransactions, String txid) {
|
||||
for (int i = 0; i < allTransactions.length; i++) {
|
||||
if (allTransactions[i]["txid"] == txid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> _refreshTransactions() async {
|
||||
// final changeAddresses =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddresses')
|
||||
// as List<dynamic>;
|
||||
// final List<String> allAddresses = await _fetchAllOwnAddresses();
|
||||
// // Logging.instance.log("receiving addresses: $receivingAddresses");
|
||||
// // Logging.instance.log("change addresses: $changeAddresses");
|
||||
//
|
||||
// List<Map<String, dynamic>> allTxHashes = await _fetchHistory(allAddresses);
|
||||
//
|
||||
// final cachedTransactions =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
|
||||
// as models.TransactionData?;
|
||||
// int latestTxnBlockHeight =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: "storedTxnDataHeight")
|
||||
// as int? ??
|
||||
// 0;
|
||||
//
|
||||
// final unconfirmedCachedTransactions =
|
||||
// cachedTransactions?.getAllTransactions() ?? {};
|
||||
// unconfirmedCachedTransactions
|
||||
// .removeWhere((key, value) => value.confirmedStatus);
|
||||
//
|
||||
// if (cachedTransactions != null) {
|
||||
// for (final tx in allTxHashes.toList(growable: false)) {
|
||||
// final txHeight = tx["height"] as int;
|
||||
// if (txHeight > 0 &&
|
||||
// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
|
||||
// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
|
||||
// allTxHashes.remove(tx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// List<String> hashes = [];
|
||||
// for (var element in allTxHashes) {
|
||||
// hashes.add(element['tx_hash'] as String);
|
||||
// }
|
||||
final List<isar_models.Address> allAddresses =
|
||||
await _fetchAllOwnAddresses();
|
||||
|
||||
final List<Map<String, dynamic>> allTxHashes =
|
||||
await _fetchHistory(allAddresses.map((e) => e.value).toList());
|
||||
|
||||
List<String> hashes =
|
||||
allTxHashes.map((e) => e['tx_hash'] as String).toList(growable: false);
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
|
||||
List<Map<String, dynamic>> allTransactions = await fastFetch(hashes);
|
||||
final currentHeight = await chainHeight;
|
||||
|
||||
Logging.instance.log("allTransactions length: ${allTransactions.length}",
|
||||
level: LogLevel.Info);
|
||||
for (final txHash in allTxHashes) {
|
||||
final storedTx = await isar.transactions
|
||||
.where()
|
||||
.txidEqualTo(txHash["tx_hash"] as String)
|
||||
.findFirst();
|
||||
|
||||
if (storedTx == null ||
|
||||
!storedTx.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS)) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = await isar.addresses
|
||||
.filter()
|
||||
.valueEqualTo(txHash["address"] as String)
|
||||
.findFirst();
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||
|
||||
// // sort thing stuff
|
||||
// final currentPrice = await firoPrice;
|
||||
// final List<Map<String, dynamic>> midSortedArray = [];
|
||||
//
|
||||
// final locale =
|
||||
// Platform.isWindows ? "en_US" : await Devicelocale.currentLocale;
|
||||
//
|
||||
// Logging.instance.log("refresh the txs", level: LogLevel.Info);
|
||||
for (final txObject in allTransactions) {
|
||||
// // Logging.instance.log(txObject);
|
||||
// List<String> sendersArray = [];
|
||||
// List<String> recipientsArray = [];
|
||||
//
|
||||
// // Usually only has value when txType = 'Send'
|
||||
// int inputAmtSentFromWallet = 0;
|
||||
// // Usually has value regardless of txType due to change addresses
|
||||
// int outputAmtAddressedToWallet = 0;
|
||||
//
|
||||
// Map<String, dynamic> midSortedTx = {};
|
||||
// List<dynamic> aliens = [];
|
||||
//
|
||||
// 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 addresses = output["scriptPubKey"]["addresses"] as List?;
|
||||
// if (addresses != null && addresses.isNotEmpty) {
|
||||
// recipientsArray.add(addresses[0] as String);
|
||||
// }
|
||||
// }
|
||||
// // Logging.instance.log("recipientsArray: $recipientsArray");
|
||||
//
|
||||
// final foundInSenders =
|
||||
// allAddresses.any((element) => sendersArray.contains(element));
|
||||
// // 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"];
|
||||
// final value = input["valueSat"];
|
||||
// if (address != null && value != null) {
|
||||
// if (allAddresses.contains(address)) {
|
||||
// inputAmtSentFromWallet += value as int;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (value != null) {
|
||||
// inAmount += value as int;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (final output in txObject["vout"] as List) {
|
||||
// final addresses = output["scriptPubKey"]["addresses"] as List?;
|
||||
// final value = output["value"];
|
||||
// if (addresses != null && addresses.isNotEmpty) {
|
||||
// final address = addresses[0] as String;
|
||||
// if (value != null) {
|
||||
// if (changeAddresses.contains(address)) {
|
||||
// inputAmtSentFromWallet -= (Decimal.parse(value.toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// } else {
|
||||
// outAddress = address;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (value != null) {
|
||||
// outAmount += (Decimal.parse(value.toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// 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"];
|
||||
// // Logging.instance.log(address + value.toString());
|
||||
//
|
||||
// if (allAddresses.contains(address)) {
|
||||
// outputAmtAddressedToWallet += (Decimal.parse(value.toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// outAddress = address;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// final int confirms = txObject["confirmations"] as int? ?? 0;
|
||||
//
|
||||
// // create final tx map
|
||||
// midSortedTx["txid"] = txObject["txid"];
|
||||
// midSortedTx["confirmed_status"] = confirms >= MINIMUM_CONFIRMATIONS;
|
||||
// midSortedTx["confirmations"] = confirms;
|
||||
// midSortedTx["timestamp"] = txObject["blocktime"] ??
|
||||
// (DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
||||
// if (foundInSenders) {
|
||||
// midSortedTx["txType"] = "Sent";
|
||||
// midSortedTx["amount"] = inputAmtSentFromWallet;
|
||||
// final String worthNow = Format.localizedStringAsFixed(
|
||||
// value: ((currentPrice * Decimal.fromInt(inputAmtSentFromWallet)) /
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toDecimal(scaleOnInfinitePrecision: 2),
|
||||
// decimalPlaces: 2,
|
||||
// locale: locale!);
|
||||
// midSortedTx["worthNow"] = worthNow;
|
||||
// midSortedTx["worthAtBlockTimestamp"] = worthNow;
|
||||
// if (txObject["vout"][0]["scriptPubKey"]["type"] == "lelantusmint") {
|
||||
// midSortedTx["subType"] = "mint";
|
||||
// }
|
||||
// } else {
|
||||
// midSortedTx["txType"] = "Received";
|
||||
// midSortedTx["amount"] = outputAmtAddressedToWallet;
|
||||
// final worthNow = Format.localizedStringAsFixed(
|
||||
// value:
|
||||
// ((currentPrice * Decimal.fromInt(outputAmtAddressedToWallet)) /
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toDecimal(scaleOnInfinitePrecision: 2),
|
||||
// decimalPlaces: 2,
|
||||
// locale: locale!);
|
||||
// midSortedTx["worthNow"] = worthNow;
|
||||
// midSortedTx["worthAtBlockTimestamp"] = worthNow;
|
||||
// }
|
||||
// midSortedTx["aliens"] = aliens;
|
||||
// midSortedTx["fees"] = fees;
|
||||
// midSortedTx["address"] = outAddress;
|
||||
// midSortedTx["inputSize"] = txObject["vin"].length;
|
||||
// midSortedTx["outputSize"] = txObject["vout"].length;
|
||||
// midSortedTx["inputs"] = txObject["vin"];
|
||||
// midSortedTx["outputs"] = txObject["vout"];
|
||||
//
|
||||
// final int height = txObject["height"] as int? ?? 0;
|
||||
// midSortedTx["height"] = height;
|
||||
//
|
||||
// if (height >= latestTxnBlockHeight) {
|
||||
// latestTxnBlockHeight = height;
|
||||
// }
|
||||
//
|
||||
// midSortedArray.add(midSortedTx);
|
||||
|
||||
final txn = await parseTransaction(
|
||||
final data = await parseTransaction(
|
||||
txObject,
|
||||
cachedElectrumXClient,
|
||||
allAddresses,
|
||||
|
@ -3470,80 +3287,10 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
MINIMUM_CONFIRMATIONS,
|
||||
);
|
||||
|
||||
// final tx = await isar.transactions
|
||||
// .filter()
|
||||
// .txidMatches(midSortedTx.txid)
|
||||
// .findFirst();
|
||||
// // we don't need to check this but it saves a write tx instead of overwriting the transaction in Isar
|
||||
// if (tx == null) {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.put(txn.item1);
|
||||
});
|
||||
// }
|
||||
txnsData.add(data);
|
||||
}
|
||||
//
|
||||
// // sort by date ---- //TODO not sure if needed
|
||||
// // shouldn't be any issues with a null timestamp but I got one at some point?
|
||||
// midSortedArray.sort((a, b) {
|
||||
// final aT = a["timestamp"];
|
||||
// final bT = b["timestamp"];
|
||||
//
|
||||
// if (aT == null && bT == null) {
|
||||
// return 0;
|
||||
// } else if (aT == null) {
|
||||
// return -1;
|
||||
// } else if (bT == null) {
|
||||
// return 1;
|
||||
// } else {
|
||||
// return (bT as int) - (aT as int);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // buildDateTimeChunks
|
||||
// final Map<String, dynamic> result = {"dateTimeChunks": <dynamic>[]};
|
||||
// final dateArray = <dynamic>[];
|
||||
//
|
||||
// for (int i = 0; i < midSortedArray.length; i++) {
|
||||
// final txObject = midSortedArray[i];
|
||||
// final date =
|
||||
// models.extractDateFromTimestamp(txObject["timestamp"] as int);
|
||||
// final txTimeArray = [txObject["timestamp"], date];
|
||||
//
|
||||
// if (dateArray.contains(txTimeArray[1])) {
|
||||
// result["dateTimeChunks"].forEach((dynamic chunk) {
|
||||
// if (models.extractDateFromTimestamp(chunk["timestamp"] as int) ==
|
||||
// txTimeArray[1]) {
|
||||
// if (chunk["transactions"] == null) {
|
||||
// chunk["transactions"] = <Map<String, dynamic>>[];
|
||||
// }
|
||||
// chunk["transactions"].add(txObject);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// dateArray.add(txTimeArray[1]);
|
||||
// final chunk = {
|
||||
// "timestamp": txTimeArray[0],
|
||||
// "transactions": [txObject],
|
||||
// };
|
||||
// result["dateTimeChunks"].add(chunk);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// final transactionsMap = cachedTransactions?.getAllTransactions() ?? {};
|
||||
// transactionsMap
|
||||
// .addAll(models.TransactionData.fromJson(result).getAllTransactions());
|
||||
//
|
||||
// final txModel = models.TransactionData.fromMap(transactionsMap);
|
||||
//
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId,
|
||||
// key: 'storedTxnDataHeight',
|
||||
// value: latestTxnBlockHeight);
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId, key: 'latest_tx_model', value: txModel);
|
||||
//
|
||||
// cachedTxData = txModel;
|
||||
// return txModel;
|
||||
|
||||
await addNewTransactionData(txnsData);
|
||||
}
|
||||
|
||||
Future<void> _refreshUTXOs() async {
|
||||
|
|
|
@ -2094,83 +2094,42 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
final List<isar_models.Address> allAddresses =
|
||||
await _fetchAllOwnAddresses();
|
||||
|
||||
// final changeAddresses = DB.instance.get<dynamic>(
|
||||
// boxName: walletId, key: 'changeAddressesP2WPKH') as List<dynamic>;
|
||||
// final changeAddressesP2PKH =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH')
|
||||
// as List<dynamic>;
|
||||
// final changeAddressesP2SH =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH')
|
||||
// as List<dynamic>;
|
||||
//
|
||||
// for (var i = 0; i < changeAddressesP2PKH.length; i++) {
|
||||
// changeAddresses.add(changeAddressesP2PKH[i] as String);
|
||||
// }
|
||||
// for (var i = 0; i < changeAddressesP2SH.length; i++) {
|
||||
// changeAddresses.add(changeAddressesP2SH[i] as String);
|
||||
// }
|
||||
|
||||
final List<Map<String, dynamic>> allTxHashes =
|
||||
await _fetchHistory(allAddresses.map((e) => e.value).toList());
|
||||
|
||||
// final cachedTransactions =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
|
||||
// as TransactionData?;
|
||||
// int latestTxnBlockHeight =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: "storedTxnDataHeight")
|
||||
// as int? ??
|
||||
// 0;
|
||||
//
|
||||
// final unconfirmedCachedTransactions =
|
||||
// cachedTransactions?.getAllTransactions() ?? {};
|
||||
// unconfirmedCachedTransactions
|
||||
// .removeWhere((key, value) => value.confirmedStatus);
|
||||
//
|
||||
// if (cachedTransactions != null) {
|
||||
// for (final tx in allTxHashes.toList(growable: false)) {
|
||||
// final txHeight = tx["height"] as int;
|
||||
// if (txHeight > 0 &&
|
||||
// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
|
||||
// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
|
||||
// allTxHashes.remove(tx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Set<String> hashes = {};
|
||||
for (var element in allTxHashes) {
|
||||
hashes.add(element['tx_hash'] as String);
|
||||
}
|
||||
await fastFetch(hashes.toList());
|
||||
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
final currentHeight = await chainHeight;
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
final storedTx = await isar.transactions
|
||||
.where()
|
||||
.txidEqualTo(txHash["tx_hash"] as String)
|
||||
.findFirst();
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = txHash["address"];
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
if (storedTx == null ||
|
||||
!storedTx.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS)) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = txHash["address"];
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logging.instance.log("addAddresses: $allAddresses", level: LogLevel.Info);
|
||||
// Logging.instance.log("allTxHashes: $allTxHashes", level: LogLevel.Info);
|
||||
//
|
||||
// Logging.instance.log("allTransactions length: ${allTransactions.length}",
|
||||
// level: LogLevel.Info);
|
||||
//
|
||||
// final priceData =
|
||||
// await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency);
|
||||
// Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero;
|
||||
// final List<Map<String, dynamic>> midSortedArray = [];
|
||||
|
||||
// prefetch/cache
|
||||
Set<String> vHashes = {};
|
||||
for (final txObject in allTransactions) {
|
||||
for (int i = 0; i < (txObject["vin"] as List).length; i++) {
|
||||
|
@ -2181,8 +2140,12 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
}
|
||||
await fastFetch(vHashes.toList());
|
||||
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||
|
||||
for (final txObject in allTransactions) {
|
||||
final txn = await parseTransaction(
|
||||
final data = await parseTransaction(
|
||||
txObject,
|
||||
cachedElectrumXClient,
|
||||
allAddresses,
|
||||
|
@ -2190,261 +2153,9 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
MINIMUM_CONFIRMATIONS,
|
||||
);
|
||||
|
||||
// final tx = await isar.transactions
|
||||
// .filter()
|
||||
// .txidMatches(midSortedTx.txid)
|
||||
// .findFirst();
|
||||
// // we don't need to check this but it saves a write tx instead of overwriting the transaction in Isar
|
||||
// if (tx == null) {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.put(txn.item1);
|
||||
});
|
||||
// }
|
||||
|
||||
// List<String> sendersArray = [];
|
||||
// List<String> recipientsArray = [];
|
||||
//
|
||||
// // Usually only has value when txType = 'Send'
|
||||
// int inputAmtSentFromWallet = 0;
|
||||
// // Usually has value regardless of txType due to change addresses
|
||||
// int outputAmtAddressedToWallet = 0;
|
||||
// int fee = 0;
|
||||
//
|
||||
// Map<String, dynamic> midSortedTx = {};
|
||||
//
|
||||
// for (int i = 0; i < (txObject["vin"] as List).length; i++) {
|
||||
// final input = txObject["vin"]![i] as Map;
|
||||
// final prevTxid = input["txid"] as String;
|
||||
// final prevOut = input["vout"] as int;
|
||||
//
|
||||
// final tx = await _cachedElectrumXClient.getTransaction(
|
||||
// txHash: prevTxid,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// for (final out in tx["vout"] as List) {
|
||||
// if (prevOut == out["n"]) {
|
||||
// final address = out["scriptPubKey"]["addresses"][0] as String?;
|
||||
// if (address != null) {
|
||||
// sendersArray.add(address);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Logging.instance.log("sendersArray: $sendersArray", level: LogLevel.Info);
|
||||
//
|
||||
// for (final output in txObject["vout"] as List) {
|
||||
// final address = output["scriptPubKey"]["addresses"][0] as String?;
|
||||
// if (address != null) {
|
||||
// recipientsArray.add(address);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Logging.instance
|
||||
// .log("recipientsArray: $recipientsArray", level: LogLevel.Info);
|
||||
//
|
||||
// final foundInSenders =
|
||||
// allAddresses.any((element) => sendersArray.contains(element));
|
||||
// Logging.instance
|
||||
// .log("foundInSenders: $foundInSenders", level: LogLevel.Info);
|
||||
//
|
||||
// // If txType = Sent, then calculate inputAmtSentFromWallet
|
||||
// if (foundInSenders) {
|
||||
// int totalInput = 0;
|
||||
// for (int i = 0; i < (txObject["vin"] as List).length; i++) {
|
||||
// final input = txObject["vin"]![i] as Map;
|
||||
// final prevTxid = input["txid"] as String;
|
||||
// final prevOut = input["vout"] as int;
|
||||
// final tx = await _cachedElectrumXClient.getTransaction(
|
||||
// txHash: prevTxid,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// for (final out in tx["vout"] as List) {
|
||||
// if (prevOut == out["n"]) {
|
||||
// inputAmtSentFromWallet +=
|
||||
// (Decimal.parse(out["value"]!.toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// totalInput = inputAmtSentFromWallet;
|
||||
// int totalOutput = 0;
|
||||
//
|
||||
// for (final output in txObject["vout"] as List) {
|
||||
// final String address =
|
||||
// output["scriptPubKey"]!["addresses"][0] as String;
|
||||
// final value = output["value"]!;
|
||||
// final _value = (Decimal.parse(value.toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// totalOutput += _value;
|
||||
// if (changeAddresses.contains(address)) {
|
||||
// inputAmtSentFromWallet -= _value;
|
||||
// } else {
|
||||
// // change address from 'sent from' to the 'sent to' address
|
||||
// txObject["address"] = address;
|
||||
// }
|
||||
// }
|
||||
// // calculate transaction fee
|
||||
// fee = totalInput - totalOutput;
|
||||
// // subtract fee from sent to calculate correct value of sent tx
|
||||
// inputAmtSentFromWallet -= fee;
|
||||
// } else {
|
||||
// // counters for fee calculation
|
||||
// int totalOut = 0;
|
||||
// int totalIn = 0;
|
||||
//
|
||||
// // add up received tx value
|
||||
// for (final output in txObject["vout"] as List) {
|
||||
// final address = output["scriptPubKey"]["addresses"][0];
|
||||
// if (address != null) {
|
||||
// final value = (Decimal.parse(output["value"].toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// totalOut += value;
|
||||
// if (allAddresses.contains(address)) {
|
||||
// outputAmtAddressedToWallet += value;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // calculate fee for received tx
|
||||
// for (int i = 0; i < (txObject["vin"] as List).length; i++) {
|
||||
// final input = txObject["vin"][i] as Map;
|
||||
// final prevTxid = input["txid"] as String;
|
||||
// final prevOut = input["vout"] as int;
|
||||
// final tx = await _cachedElectrumXClient.getTransaction(
|
||||
// txHash: prevTxid,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// for (final out in tx["vout"] as List) {
|
||||
// if (prevOut == out["n"]) {
|
||||
// totalIn += (Decimal.parse(out["value"].toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// fee = totalIn - totalOut;
|
||||
// }
|
||||
//
|
||||
// // create final tx map
|
||||
// midSortedTx["txid"] = txObject["txid"];
|
||||
// midSortedTx["confirmed_status"] = (txObject["confirmations"] != null) &&
|
||||
// (txObject["confirmations"] as int >= MINIMUM_CONFIRMATIONS);
|
||||
// midSortedTx["confirmations"] = txObject["confirmations"] ?? 0;
|
||||
// midSortedTx["timestamp"] = txObject["blocktime"] ??
|
||||
// (DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
||||
//
|
||||
// if (foundInSenders) {
|
||||
// midSortedTx["txType"] = "Sent";
|
||||
// midSortedTx["amount"] = inputAmtSentFromWallet;
|
||||
// final String worthNow =
|
||||
// ((currentPrice * Decimal.fromInt(inputAmtSentFromWallet)) /
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toDecimal(scaleOnInfinitePrecision: 2)
|
||||
// .toStringAsFixed(2);
|
||||
// midSortedTx["worthNow"] = worthNow;
|
||||
// midSortedTx["worthAtBlockTimestamp"] = worthNow;
|
||||
// } else {
|
||||
// midSortedTx["txType"] = "Received";
|
||||
// midSortedTx["amount"] = outputAmtAddressedToWallet;
|
||||
// final worthNow =
|
||||
// ((currentPrice * Decimal.fromInt(outputAmtAddressedToWallet)) /
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toDecimal(scaleOnInfinitePrecision: 2)
|
||||
// .toStringAsFixed(2);
|
||||
// midSortedTx["worthNow"] = worthNow;
|
||||
// }
|
||||
// midSortedTx["aliens"] = <dynamic>[];
|
||||
// midSortedTx["fees"] = fee;
|
||||
// midSortedTx["address"] = txObject["address"];
|
||||
// midSortedTx["inputSize"] = txObject["vin"].length;
|
||||
// midSortedTx["outputSize"] = txObject["vout"].length;
|
||||
// midSortedTx["inputs"] = txObject["vin"];
|
||||
// midSortedTx["outputs"] = txObject["vout"];
|
||||
//
|
||||
// final int height = txObject["height"] as int;
|
||||
// midSortedTx["height"] = height;
|
||||
//
|
||||
// if (height >= latestTxnBlockHeight) {
|
||||
// latestTxnBlockHeight = height;
|
||||
// }
|
||||
//
|
||||
// midSortedArray.add(midSortedTx);
|
||||
txnsData.add(data);
|
||||
}
|
||||
//
|
||||
// // sort by date ---- //TODO not sure if needed
|
||||
// // shouldn't be any issues with a null timestamp but I got one at some point?
|
||||
// midSortedArray
|
||||
// .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int));
|
||||
// // {
|
||||
// // final aT = a["timestamp"];
|
||||
// // final bT = b["timestamp"];
|
||||
// //
|
||||
// // if (aT == null && bT == null) {
|
||||
// // return 0;
|
||||
// // } else if (aT == null) {
|
||||
// // return -1;
|
||||
// // } else if (bT == null) {
|
||||
// // return 1;
|
||||
// // } else {
|
||||
// // return bT - aT;
|
||||
// // }
|
||||
// // });
|
||||
//
|
||||
// // buildDateTimeChunks
|
||||
// final Map<String, dynamic> result = {"dateTimeChunks": <dynamic>[]};
|
||||
// final dateArray = <dynamic>[];
|
||||
//
|
||||
// for (int i = 0; i < midSortedArray.length; i++) {
|
||||
// final txObject = midSortedArray[i];
|
||||
// final date = extractDateFromTimestamp(txObject["timestamp"] as int);
|
||||
// final txTimeArray = [txObject["timestamp"], date];
|
||||
//
|
||||
// if (dateArray.contains(txTimeArray[1])) {
|
||||
// result["dateTimeChunks"].forEach((dynamic chunk) {
|
||||
// if (extractDateFromTimestamp(chunk["timestamp"] as int) ==
|
||||
// txTimeArray[1]) {
|
||||
// if (chunk["transactions"] == null) {
|
||||
// chunk["transactions"] = <Map<String, dynamic>>[];
|
||||
// }
|
||||
// chunk["transactions"].add(txObject);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// dateArray.add(txTimeArray[1]);
|
||||
// final chunk = {
|
||||
// "timestamp": txTimeArray[0],
|
||||
// "transactions": [txObject],
|
||||
// };
|
||||
// result["dateTimeChunks"].add(chunk);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// final transactionsMap = cachedTransactions?.getAllTransactions() ?? {};
|
||||
// transactionsMap
|
||||
// .addAll(TransactionData.fromJson(result).getAllTransactions());
|
||||
//
|
||||
// final txModel = TransactionData.fromMap(transactionsMap);
|
||||
//
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId,
|
||||
// key: 'storedTxnDataHeight',
|
||||
// value: latestTxnBlockHeight);
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId, key: 'latest_tx_model', value: txModel);
|
||||
//
|
||||
// cachedTxData = txModel;
|
||||
// return txModel;
|
||||
await addNewTransactionData(txnsData);
|
||||
}
|
||||
|
||||
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||
|
|
|
@ -46,6 +46,7 @@ import 'package:stackwallet/utilities/format.dart';
|
|||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 10;
|
||||
|
||||
|
@ -848,7 +849,9 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
//
|
||||
// final Set<String> cachedTxids = Set<String>.from(txidsList);
|
||||
|
||||
final List<isar_models.Transaction> txns = [];
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||
|
||||
if (transactions != null) {
|
||||
for (var tx in transactions.entries) {
|
||||
|
@ -865,6 +868,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
txn.txid = tx.value.id;
|
||||
txn.timestamp = (tx.value.date.millisecondsSinceEpoch ~/ 1000);
|
||||
|
||||
isar_models.Address? address;
|
||||
if (tx.value.direction == TransactionDirection.incoming) {
|
||||
final addressInfo = tx.value.additionalInfo;
|
||||
|
||||
|
@ -874,7 +878,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
);
|
||||
|
||||
if (addressString != null) {
|
||||
txn.address.value = await isar.addresses
|
||||
address = await isar.addresses
|
||||
.filter()
|
||||
.valueEqualTo(addressString)
|
||||
.findFirst();
|
||||
|
@ -899,67 +903,11 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
txn.slateId = null;
|
||||
txn.otherData = null;
|
||||
|
||||
txns.add(txn);
|
||||
txnsData.add(Tuple4(txn, [], [], address));
|
||||
}
|
||||
}
|
||||
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.putAll(txns);
|
||||
});
|
||||
|
||||
// // sort by date ----
|
||||
// midSortedArray
|
||||
// .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int));
|
||||
// Logging.instance.log(midSortedArray, level: LogLevel.Info);
|
||||
//
|
||||
// // buildDateTimeChunks
|
||||
// final Map<String, dynamic> result = {"dateTimeChunks": <dynamic>[]};
|
||||
// final dateArray = <dynamic>[];
|
||||
//
|
||||
// for (int i = 0; i < midSortedArray.length; i++) {
|
||||
// final txObject = midSortedArray[i];
|
||||
// final date = extractDateFromTimestamp(txObject["timestamp"] as int);
|
||||
// final txTimeArray = [txObject["timestamp"], date];
|
||||
//
|
||||
// if (dateArray.contains(txTimeArray[1])) {
|
||||
// result["dateTimeChunks"].forEach((dynamic chunk) {
|
||||
// if (extractDateFromTimestamp(chunk["timestamp"] as int) ==
|
||||
// txTimeArray[1]) {
|
||||
// if (chunk["transactions"] == null) {
|
||||
// chunk["transactions"] = <Map<String, dynamic>>[];
|
||||
// }
|
||||
// chunk["transactions"].add(txObject);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// dateArray.add(txTimeArray[1]);
|
||||
// final chunk = {
|
||||
// "timestamp": txTimeArray[0],
|
||||
// "transactions": [txObject],
|
||||
// };
|
||||
// result["dateTimeChunks"].add(chunk);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // final transactionsMap = cachedTransactions?.getAllTransactions() ?? {};
|
||||
// final Map<String, Transaction> transactionsMap = {};
|
||||
// transactionsMap
|
||||
// .addAll(TransactionData.fromJson(result).getAllTransactions());
|
||||
//
|
||||
// final txModel = TransactionData.fromMap(transactionsMap);
|
||||
//
|
||||
// // await DB.instance.put<dynamic>(
|
||||
// // boxName: walletId,
|
||||
// // key: 'storedTxnDataHeight',
|
||||
// // value: latestTxnBlockHeight);
|
||||
// // await DB.instance.put<dynamic>(
|
||||
// // boxName: walletId, key: 'latest_tx_model', value: txModel);
|
||||
// // await DB.instance.put<dynamic>(
|
||||
// // boxName: walletId,
|
||||
// // key: 'cachedTxids',
|
||||
// // value: cachedTxids.toList(growable: false));
|
||||
//
|
||||
// return txModel;
|
||||
await addNewTransactionData(txnsData);
|
||||
}
|
||||
|
||||
Future<String> _pathForWalletDir({
|
||||
|
|
|
@ -2076,69 +2076,37 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
final List<isar_models.Address> allAddresses =
|
||||
await _fetchAllOwnAddresses();
|
||||
|
||||
// final changeAddresses = DB.instance.get<dynamic>(
|
||||
// boxName: walletId, key: 'changeAddressesP2WPKH') as List<dynamic>;
|
||||
// final changeAddressesP2PKH =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH')
|
||||
// as List<dynamic>;
|
||||
// final changeAddressesP2SH =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH')
|
||||
// as List<dynamic>;
|
||||
//
|
||||
// for (var i = 0; i < changeAddressesP2PKH.length; i++) {
|
||||
// changeAddresses.add(changeAddressesP2PKH[i] as String);
|
||||
// }
|
||||
// for (var i = 0; i < changeAddressesP2SH.length; i++) {
|
||||
// changeAddresses.add(changeAddressesP2SH[i] as String);
|
||||
// }
|
||||
|
||||
final List<Map<String, dynamic>> allTxHashes =
|
||||
await _fetchHistory(allAddresses.map((e) => e.value).toList());
|
||||
|
||||
// final cachedTransactions =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
|
||||
// as TransactionData?;
|
||||
// int latestTxnBlockHeight =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: "storedTxnDataHeight")
|
||||
// as int? ??
|
||||
// 0;
|
||||
//
|
||||
// final unconfirmedCachedTransactions =
|
||||
// cachedTransactions?.getAllTransactions() ?? {};
|
||||
// unconfirmedCachedTransactions
|
||||
// .removeWhere((key, value) => value.confirmedStatus);
|
||||
//
|
||||
// if (cachedTransactions != null) {
|
||||
// for (final tx in allTxHashes.toList(growable: false)) {
|
||||
// final txHeight = tx["height"] as int;
|
||||
// if (txHeight > 0 &&
|
||||
// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
|
||||
// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
|
||||
// allTxHashes.remove(tx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Set<String> hashes = {};
|
||||
for (var element in allTxHashes) {
|
||||
hashes.add(element['tx_hash'] as String);
|
||||
}
|
||||
await fastFetch(hashes.toList());
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
final currentHeight = await chainHeight;
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
final storedTx = await isar.transactions
|
||||
.where()
|
||||
.txidEqualTo(txHash["tx_hash"] as String)
|
||||
.findFirst();
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = txHash["address"];
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
if (storedTx == null ||
|
||||
!storedTx.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS)) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = txHash["address"];
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2158,8 +2126,12 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
}
|
||||
await fastFetch(vHashes.toList());
|
||||
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address>> txnsData = [];
|
||||
|
||||
for (final txObject in allTransactions) {
|
||||
final txn = await parseTransaction(
|
||||
final data = await parseTransaction(
|
||||
txObject,
|
||||
cachedElectrumXClient,
|
||||
allAddresses,
|
||||
|
@ -2167,271 +2139,9 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
MINIMUM_CONFIRMATIONS,
|
||||
);
|
||||
|
||||
// final tx = await isar.transactions
|
||||
// .filter()
|
||||
// .txidMatches(midSortedTx.txid)
|
||||
// .findFirst();
|
||||
// // we don't need to check this but it saves a write tx instead of overwriting the transaction in Isar
|
||||
// if (tx == null) {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.put(txn.item1);
|
||||
});
|
||||
// }
|
||||
|
||||
// List<String> sendersArray = [];
|
||||
// List<String> recipientsArray = [];
|
||||
//
|
||||
// // Usually only has value when txType = 'Send'
|
||||
// int inputAmtSentFromWallet = 0;
|
||||
// // Usually has value regardless of txType due to change addresses
|
||||
// int outputAmtAddressedToWallet = 0;
|
||||
// int fee = 0;
|
||||
//
|
||||
// Map<String, dynamic> midSortedTx = {};
|
||||
//
|
||||
// for (int i = 0; i < (txObject["vin"] as List).length; i++) {
|
||||
// final input = txObject["vin"]![i] as Map;
|
||||
// final prevTxid = input["txid"] as String;
|
||||
// final prevOut = input["vout"] as int;
|
||||
//
|
||||
// final tx = await _cachedElectrumXClient.getTransaction(
|
||||
// txHash: prevTxid,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// for (final out in tx["vout"] as List) {
|
||||
// if (prevOut == out["n"]) {
|
||||
// String? address = out["scriptPubKey"]["address"] as String?;
|
||||
// if (address == null && out["scriptPubKey"]["address"] != null) {
|
||||
// address = out["scriptPubKey"]["address"] as String?;
|
||||
// }
|
||||
//
|
||||
// if (address != null) {
|
||||
// sendersArray.add(address);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Logging.instance.log("sendersArray: $sendersArray", level: LogLevel.Info);
|
||||
//
|
||||
// for (final output in txObject["vout"] as List) {
|
||||
// String? address = output["scriptPubKey"]["address"] as String?;
|
||||
// if (address == null && output["scriptPubKey"]["address"] != null) {
|
||||
// address = output["scriptPubKey"]["address"] as String?;
|
||||
// }
|
||||
// if (address != null) {
|
||||
// recipientsArray.add(address);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Logging.instance
|
||||
// .log("recipientsArray: $recipientsArray", level: LogLevel.Info);
|
||||
//
|
||||
// final foundInSenders =
|
||||
// allAddresses.any((element) => sendersArray.contains(element));
|
||||
// Logging.instance
|
||||
// .log("foundInSenders: $foundInSenders", level: LogLevel.Info);
|
||||
//
|
||||
// // If txType = Sent, then calculate inputAmtSentFromWallet
|
||||
// if (foundInSenders) {
|
||||
// int totalInput = 0;
|
||||
// for (int i = 0; i < (txObject["vin"] as List).length; i++) {
|
||||
// final input = txObject["vin"]![i] as Map;
|
||||
// final prevTxid = input["txid"] as String;
|
||||
// final prevOut = input["vout"] as int;
|
||||
// final tx = await _cachedElectrumXClient.getTransaction(
|
||||
// txHash: prevTxid,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// for (final out in tx["vout"] as List) {
|
||||
// if (prevOut == out["n"]) {
|
||||
// inputAmtSentFromWallet +=
|
||||
// (Decimal.parse(out["value"]!.toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// totalInput = inputAmtSentFromWallet;
|
||||
// int totalOutput = 0;
|
||||
//
|
||||
// for (final output in txObject["vout"] as List) {
|
||||
// Logging.instance.log(output, level: LogLevel.Info);
|
||||
// final address = output["scriptPubKey"]["address"];
|
||||
// final value = output["value"];
|
||||
// final _value = (Decimal.parse(value.toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// totalOutput += _value;
|
||||
// if (changeAddresses.contains(address)) {
|
||||
// inputAmtSentFromWallet -= _value;
|
||||
// } else {
|
||||
// // change address from 'sent from' to the 'sent to' address
|
||||
// txObject["address"] = address;
|
||||
// }
|
||||
// }
|
||||
// // calculate transaction fee
|
||||
// fee = totalInput - totalOutput;
|
||||
// // subtract fee from sent to calculate correct value of sent tx
|
||||
// inputAmtSentFromWallet -= fee;
|
||||
// } else {
|
||||
// // counters for fee calculation
|
||||
// int totalOut = 0;
|
||||
// int totalIn = 0;
|
||||
//
|
||||
// // add up received tx value
|
||||
// for (final output in txObject["vout"] as List) {
|
||||
// String? address = output["scriptPubKey"]["address"] as String?;
|
||||
// if (address == null && output["scriptPubKey"]["address"] != null) {
|
||||
// address = output["scriptPubKey"]["address"] as String?;
|
||||
// }
|
||||
// if (address != null) {
|
||||
// final value = (Decimal.parse(output["value"].toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// totalOut += value;
|
||||
// if (allAddresses.contains(address)) {
|
||||
// outputAmtAddressedToWallet += value;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // calculate fee for received tx
|
||||
// for (int i = 0; i < (txObject["vin"] as List).length; i++) {
|
||||
// final input = txObject["vin"][i] as Map;
|
||||
// final prevTxid = input["txid"] as String;
|
||||
// final prevOut = input["vout"] as int;
|
||||
// final tx = await _cachedElectrumXClient.getTransaction(
|
||||
// txHash: prevTxid,
|
||||
// coin: coin,
|
||||
// );
|
||||
//
|
||||
// for (final out in tx["vout"] as List) {
|
||||
// if (prevOut == out["n"]) {
|
||||
// totalIn += (Decimal.parse(out["value"].toString()) *
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toBigInt()
|
||||
// .toInt();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// fee = totalIn - totalOut;
|
||||
// }
|
||||
//
|
||||
// // create final tx map
|
||||
// midSortedTx["txid"] = txObject["txid"];
|
||||
// midSortedTx["confirmed_status"] = (txObject["confirmations"] != null) &&
|
||||
// (txObject["confirmations"] as int >= MINIMUM_CONFIRMATIONS);
|
||||
// midSortedTx["confirmations"] = txObject["confirmations"] ?? 0;
|
||||
// midSortedTx["timestamp"] = txObject["blocktime"] ??
|
||||
// (DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
||||
//
|
||||
// if (foundInSenders) {
|
||||
// midSortedTx["txType"] = "Sent";
|
||||
// midSortedTx["amount"] = inputAmtSentFromWallet;
|
||||
// final String worthNow =
|
||||
// ((currentPrice * Decimal.fromInt(inputAmtSentFromWallet)) /
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toDecimal(scaleOnInfinitePrecision: 2)
|
||||
// .toStringAsFixed(2);
|
||||
// midSortedTx["worthNow"] = worthNow;
|
||||
// midSortedTx["worthAtBlockTimestamp"] = worthNow;
|
||||
// } else {
|
||||
// midSortedTx["txType"] = "Received";
|
||||
// midSortedTx["amount"] = outputAmtAddressedToWallet;
|
||||
// final worthNow =
|
||||
// ((currentPrice * Decimal.fromInt(outputAmtAddressedToWallet)) /
|
||||
// Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||
// .toDecimal(scaleOnInfinitePrecision: 2)
|
||||
// .toStringAsFixed(2);
|
||||
// midSortedTx["worthNow"] = worthNow;
|
||||
// }
|
||||
// midSortedTx["aliens"] = <dynamic>[];
|
||||
// midSortedTx["fees"] = fee;
|
||||
// midSortedTx["address"] = txObject["address"];
|
||||
// midSortedTx["inputSize"] = txObject["vin"].length;
|
||||
// midSortedTx["outputSize"] = txObject["vout"].length;
|
||||
// midSortedTx["inputs"] = txObject["vin"];
|
||||
// midSortedTx["outputs"] = txObject["vout"];
|
||||
//
|
||||
// final int height = txObject["height"] as int;
|
||||
// midSortedTx["height"] = height;
|
||||
//
|
||||
// if (height >= latestTxnBlockHeight) {
|
||||
// latestTxnBlockHeight = height;
|
||||
// }
|
||||
//
|
||||
// midSortedArray.add(midSortedTx);
|
||||
txnsData.add(data);
|
||||
}
|
||||
//
|
||||
// // sort by date ---- //TODO not sure if needed
|
||||
// // shouldn't be any issues with a null timestamp but I got one at some point?
|
||||
// midSortedArray
|
||||
// .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int));
|
||||
// // {
|
||||
// // final aT = a["timestamp"];
|
||||
// // final bT = b["timestamp"];
|
||||
// //
|
||||
// // if (aT == null && bT == null) {
|
||||
// // return 0;
|
||||
// // } else if (aT == null) {
|
||||
// // return -1;
|
||||
// // } else if (bT == null) {
|
||||
// // return 1;
|
||||
// // } else {
|
||||
// // return bT - aT;
|
||||
// // }
|
||||
// // });
|
||||
//
|
||||
// // buildDateTimeChunks
|
||||
// final Map<String, dynamic> result = {"dateTimeChunks": <dynamic>[]};
|
||||
// final dateArray = <dynamic>[];
|
||||
//
|
||||
// for (int i = 0; i < midSortedArray.length; i++) {
|
||||
// final txObject = midSortedArray[i];
|
||||
// final date = extractDateFromTimestamp(txObject["timestamp"] as int);
|
||||
// final txTimeArray = [txObject["timestamp"], date];
|
||||
//
|
||||
// if (dateArray.contains(txTimeArray[1])) {
|
||||
// result["dateTimeChunks"].forEach((dynamic chunk) {
|
||||
// if (extractDateFromTimestamp(chunk["timestamp"] as int) ==
|
||||
// txTimeArray[1]) {
|
||||
// if (chunk["transactions"] == null) {
|
||||
// chunk["transactions"] = <Map<String, dynamic>>[];
|
||||
// }
|
||||
// chunk["transactions"].add(txObject);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// dateArray.add(txTimeArray[1]);
|
||||
// final chunk = {
|
||||
// "timestamp": txTimeArray[0],
|
||||
// "transactions": [txObject],
|
||||
// };
|
||||
// result["dateTimeChunks"].add(chunk);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// final transactionsMap = cachedTransactions?.getAllTransactions() ?? {};
|
||||
// transactionsMap
|
||||
// .addAll(TransactionData.fromJson(result).getAllTransactions());
|
||||
//
|
||||
// final txModel = TransactionData.fromMap(transactionsMap);
|
||||
//
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId,
|
||||
// key: 'storedTxnDataHeight',
|
||||
// value: latestTxnBlockHeight);
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId, key: 'latest_tx_model', value: txModel);
|
||||
//
|
||||
// cachedTxData = txModel;
|
||||
// return txModel;
|
||||
await addNewTransactionData(txnsData);
|
||||
}
|
||||
|
||||
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||
|
|
|
@ -1962,9 +1962,6 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
Future<void> _refreshTransactions() async {
|
||||
final allAddresses = await _fetchAllOwnAddresses();
|
||||
|
||||
// final changeAddresses = DB.instance.get<dynamic>(
|
||||
// boxName: walletId, key: 'changeAddressesP2WPKH') as List<dynamic>;
|
||||
|
||||
List<String> changeAddresses = allAddresses
|
||||
.where((e) => e.subType == isar_models.AddressSubType.change)
|
||||
.map((e) => e.value)
|
||||
|
@ -1973,54 +1970,38 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
final List<Map<String, dynamic>> allTxHashes = await _fetchHistory(
|
||||
allAddresses.map((e) => e.value).toList(growable: false));
|
||||
|
||||
// final cachedTransactions =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
|
||||
// as TransactionData?;
|
||||
// int latestTxnBlockHeight =
|
||||
// DB.instance.get<dynamic>(boxName: walletId, key: "storedTxnDataHeight")
|
||||
// as int? ??
|
||||
// 0;
|
||||
//
|
||||
// final unconfirmedCachedTransactions =
|
||||
// cachedTransactions?.getAllTransactions() ?? {};
|
||||
// unconfirmedCachedTransactions
|
||||
// .removeWhere((key, value) => value.confirmedStatus);
|
||||
//
|
||||
// if (cachedTransactions != null) {
|
||||
// for (final tx in allTxHashes.toList(growable: false)) {
|
||||
// final txHeight = tx["height"] as int;
|
||||
// if (txHeight > 0 &&
|
||||
// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
|
||||
// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
|
||||
// allTxHashes.remove(tx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Set<String> hashes = {};
|
||||
for (var element in allTxHashes) {
|
||||
hashes.add(element['tx_hash'] as String);
|
||||
}
|
||||
await fastFetch(hashes.toList());
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
final currentHeight = await chainHeight;
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
final storedTx = await isar.transactions
|
||||
.where()
|
||||
.txidEqualTo(txHash["tx_hash"] as String)
|
||||
.findFirst();
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
// TODO fix this for sent to self transactions?
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = await isar.addresses
|
||||
.filter()
|
||||
.valueEqualTo(txHash["address"] as String)
|
||||
.findFirst();
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
if (storedTx == null ||
|
||||
!storedTx.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS)) {
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
// Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}");
|
||||
// TODO fix this for sent to self transactions?
|
||||
if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) {
|
||||
tx["address"] = await isar.addresses
|
||||
.filter()
|
||||
.valueEqualTo(txHash["address"] as String)
|
||||
.findFirst();
|
||||
tx["height"] = txHash["height"];
|
||||
allTransactions.add(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2044,7 +2025,9 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
}
|
||||
await fastFetch(vHashes.toList());
|
||||
|
||||
final List<isar_models.Transaction> txns = [];
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address?>> txns = [];
|
||||
|
||||
for (final txObject in allTransactions) {
|
||||
List<String> sendersArray = [];
|
||||
|
@ -2269,7 +2252,11 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
tx.subType = isar_models.TransactionSubType.none;
|
||||
|
||||
tx.fee = fee;
|
||||
tx.address.value = midSortedTx["address"] as isar_models.Address?;
|
||||
isar_models.Address? transactionAddress =
|
||||
midSortedTx["address"] as isar_models.Address?;
|
||||
|
||||
List<isar_models.Input> inputs = [];
|
||||
List<isar_models.Output> outputs = [];
|
||||
|
||||
for (final json in midSortedTx["vin"] as List) {
|
||||
bool isCoinBase = json['coinbase'] != null;
|
||||
|
@ -2282,7 +2269,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
isCoinBase ? isCoinBase : json['is_coinbase'] as bool?;
|
||||
input.sequence = json['sequence'] as int?;
|
||||
input.innerRedeemScriptAsm = json['innerRedeemscriptAsm'] as String?;
|
||||
tx.inputs.add(input);
|
||||
inputs.add(input);
|
||||
}
|
||||
|
||||
for (final json in midSortedTx["vout"] as List) {
|
||||
|
@ -2298,7 +2285,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
Decimal.tryParse(json["value"].toString()) ?? Decimal.zero,
|
||||
coin,
|
||||
);
|
||||
tx.outputs.add(output);
|
||||
outputs.add(output);
|
||||
}
|
||||
|
||||
tx.height = height;
|
||||
|
@ -2307,76 +2294,10 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
tx.slateId = null;
|
||||
tx.otherData = null;
|
||||
|
||||
txns.add(tx);
|
||||
txns.add(Tuple4(tx, outputs, inputs, transactionAddress));
|
||||
}
|
||||
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.putAll(txns);
|
||||
});
|
||||
|
||||
//
|
||||
// // sort by date ---- //TODO not sure if needed
|
||||
// // shouldn't be any issues with a null timestamp but I got one at some point?
|
||||
// midSortedArray
|
||||
// .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int));
|
||||
// // {
|
||||
// // final aT = a["timestamp"];
|
||||
// // final bT = b["timestamp"];
|
||||
// //
|
||||
// // if (aT == null && bT == null) {
|
||||
// // return 0;
|
||||
// // } else if (aT == null) {
|
||||
// // return -1;
|
||||
// // } else if (bT == null) {
|
||||
// // return 1;
|
||||
// // } else {
|
||||
// // return bT - aT;
|
||||
// // }
|
||||
// // });
|
||||
//
|
||||
// // buildDateTimeChunks
|
||||
// final Map<String, dynamic> result = {"dateTimeChunks": <dynamic>[]};
|
||||
// final dateArray = <dynamic>[];
|
||||
//
|
||||
// for (int i = 0; i < midSortedArray.length; i++) {
|
||||
// final txObject = midSortedArray[i];
|
||||
// final date = extractDateFromTimestamp(txObject["timestamp"] as int);
|
||||
// final txTimeArray = [txObject["timestamp"], date];
|
||||
//
|
||||
// if (dateArray.contains(txTimeArray[1])) {
|
||||
// result["dateTimeChunks"].forEach((dynamic chunk) {
|
||||
// if (extractDateFromTimestamp(chunk["timestamp"] as int) ==
|
||||
// txTimeArray[1]) {
|
||||
// if (chunk["transactions"] == null) {
|
||||
// chunk["transactions"] = <Map<String, dynamic>>[];
|
||||
// }
|
||||
// chunk["transactions"].add(txObject);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// dateArray.add(txTimeArray[1]);
|
||||
// final chunk = {
|
||||
// "timestamp": txTimeArray[0],
|
||||
// "transactions": [txObject],
|
||||
// };
|
||||
// result["dateTimeChunks"].add(chunk);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// final transactionsMap = cachedTransactions?.getAllTransactions() ?? {};
|
||||
// transactionsMap
|
||||
// .addAll(TransactionData.fromJson(result).getAllTransactions());
|
||||
//
|
||||
// final txModel = TransactionData.fromMap(transactionsMap);
|
||||
//
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId,
|
||||
// key: 'storedTxnDataHeight',
|
||||
// value: latestTxnBlockHeight);
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId, key: 'latest_tx_model', value: txModel);
|
||||
//
|
||||
// return txModel;
|
||||
await addNewTransactionData(txns);
|
||||
}
|
||||
|
||||
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||
|
|
|
@ -48,6 +48,7 @@ import 'package:stackwallet/utilities/format.dart';
|
|||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 10;
|
||||
|
||||
|
@ -875,7 +876,9 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
// }
|
||||
// }
|
||||
|
||||
final List<isar_models.Transaction> txns = [];
|
||||
final List<
|
||||
Tuple4<isar_models.Transaction, List<isar_models.Output>,
|
||||
List<isar_models.Input>, isar_models.Address?>> txnsData = [];
|
||||
|
||||
if (transactions != null) {
|
||||
for (var tx in transactions.entries) {
|
||||
|
@ -934,6 +937,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
txn.txid = tx.value.id;
|
||||
txn.timestamp = (tx.value.date.millisecondsSinceEpoch ~/ 1000);
|
||||
|
||||
isar_models.Address? address;
|
||||
if (tx.value.direction == TransactionDirection.incoming) {
|
||||
final addressInfo = tx.value.additionalInfo;
|
||||
|
||||
|
@ -943,7 +947,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
);
|
||||
|
||||
if (addressString != null) {
|
||||
txn.address.value = await isar.addresses
|
||||
address = await isar.addresses
|
||||
.filter()
|
||||
.valueEqualTo(addressString)
|
||||
.findFirst();
|
||||
|
@ -968,67 +972,11 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
txn.slateId = null;
|
||||
txn.otherData = null;
|
||||
|
||||
txns.add(txn);
|
||||
txnsData.add(Tuple4(txn, [], [], address));
|
||||
}
|
||||
}
|
||||
|
||||
await isar.writeTxn(() async {
|
||||
await isar.transactions.putAll(txns);
|
||||
});
|
||||
|
||||
// // sort by date ----
|
||||
// midSortedArray
|
||||
// .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int));
|
||||
// Logging.instance.log(midSortedArray, level: LogLevel.Info);
|
||||
//
|
||||
// // buildDateTimeChunks
|
||||
// final Map<String, dynamic> result = {"dateTimeChunks": <dynamic>[]};
|
||||
// final dateArray = <dynamic>[];
|
||||
//
|
||||
// for (int i = 0; i < midSortedArray.length; i++) {
|
||||
// final txObject = midSortedArray[i];
|
||||
// final date = extractDateFromTimestamp(txObject["timestamp"] as int);
|
||||
// final txTimeArray = [txObject["timestamp"], date];
|
||||
//
|
||||
// if (dateArray.contains(txTimeArray[1])) {
|
||||
// result["dateTimeChunks"].forEach((dynamic chunk) {
|
||||
// if (extractDateFromTimestamp(chunk["timestamp"] as int) ==
|
||||
// txTimeArray[1]) {
|
||||
// if (chunk["transactions"] == null) {
|
||||
// chunk["transactions"] = <Map<String, dynamic>>[];
|
||||
// }
|
||||
// chunk["transactions"].add(txObject);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// dateArray.add(txTimeArray[1]);
|
||||
// final chunk = {
|
||||
// "timestamp": txTimeArray[0],
|
||||
// "transactions": [txObject],
|
||||
// };
|
||||
// result["dateTimeChunks"].add(chunk);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // final transactionsMap = cachedTransactions?.getAllTransactions() ?? {};
|
||||
// final Map<String, Transaction> transactionsMap = {};
|
||||
// transactionsMap
|
||||
// .addAll(TransactionData.fromJson(result).getAllTransactions());
|
||||
//
|
||||
// final txModel = TransactionData.fromMap(transactionsMap);
|
||||
// //
|
||||
// // await DB.instance.put<dynamic>(
|
||||
// // boxName: walletId,
|
||||
// // key: 'storedTxnDataHeight',
|
||||
// // value: latestTxnBlockHeight);
|
||||
// // await DB.instance.put<dynamic>(
|
||||
// // boxName: walletId, key: 'latest_tx_model', value: txModel);
|
||||
// // await DB.instance.put<dynamic>(
|
||||
// // boxName: walletId,
|
||||
// // key: 'cachedTxids',
|
||||
// // value: cachedTxids.toList(growable: false));
|
||||
//
|
||||
// return txModel;
|
||||
await addNewTransactionData(txnsData);
|
||||
}
|
||||
|
||||
Future<String> _pathForWalletDir({
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
mixin WalletDB {
|
||||
Isar? _isar;
|
||||
|
@ -29,4 +30,45 @@ mixin WalletDB {
|
|||
}
|
||||
|
||||
Future<bool> isarClose() async => await _isar?.close() ?? false;
|
||||
|
||||
Future<void> addNewTransactionData(
|
||||
List<Tuple4<Transaction, List<Output>, List<Input>, Address?>>
|
||||
transactionsData) async {
|
||||
await isar.writeTxn(() async {
|
||||
for (final data in transactionsData) {
|
||||
final tx = data.item1;
|
||||
|
||||
// save transaction
|
||||
await isar.transactions.put(tx);
|
||||
|
||||
// link and save outputs
|
||||
if (data.item2.isNotEmpty) {
|
||||
await isar.outputs.putAll(data.item2);
|
||||
tx.outputs.addAll(data.item2);
|
||||
await tx.outputs.save();
|
||||
}
|
||||
|
||||
// link and save inputs
|
||||
if (data.item3.isNotEmpty) {
|
||||
await isar.inputs.putAll(data.item3);
|
||||
tx.inputs.addAll(data.item3);
|
||||
await tx.inputs.save();
|
||||
}
|
||||
|
||||
if (data.item4 != null) {
|
||||
// check if address exists in db and add if it does not
|
||||
if (await isar.addresses
|
||||
.where()
|
||||
.valueEqualTo(data.item4!.value)
|
||||
.findFirst() ==
|
||||
null) {
|
||||
await isar.addresses.put(data.item4!);
|
||||
}
|
||||
// link and save address
|
||||
tx.address.value = data.item4;
|
||||
await tx.address.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue