Add EpicTransaction DTO for parsing transactions, clean out mutex stuff for calls to the abstract class

This commit is contained in:
likho 2023-10-04 09:53:05 +02:00
parent e28c7f5019
commit 3b4de2b2d5
3 changed files with 90 additions and 122 deletions

View file

@ -1,22 +1,18 @@
import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-10-03
*
*/
class EpicTransaction {
@Index()
late final String walletId;
@Index()
final String parentKeyId;
@Index(unique: true, composite: [CompositeIndex("walletId")])
late final int id;
final int id;
final String? txSlateId;
@enumerated
final TransactionType txType;
final EpicTransactionType txType;
final String creationTs;
final String confirmationTs;
final bool confirmed;
@ -32,9 +28,6 @@ class EpicTransaction {
final int? kernelLookupMinHeight;
final String? paymentProof;
@Backlink(to: "transactions")
final address = IsarLink<Address>();
EpicTransaction({
required this.parentKeyId,
required this.id,
@ -56,26 +49,27 @@ class EpicTransaction {
this.paymentProof,
});
factory EpicTransaction.fromJson(Map<String, dynamic> json) {
factory EpicTransaction.fromJson(dynamic json) {
// print("THIS JSON IS $json")
return EpicTransaction(
parentKeyId: json['parent_key_id'] as String,
id: json['id'] as int,
txSlateId: json['tx_slate_id'] as String,
txType: json['tx_type'] as TransactionType,
creationTs: json['creation_ts'] as String,
confirmationTs: json['confirmation_ts'] as String,
confirmed: json['confirmed'] as bool,
numInputs: json['num_inputs'] as int,
numOutputs: json['num_outputs'] as int,
amountCredited: json['amount_credited'] as String,
amountDebited: json['amount_debited'] as String,
fee: json['fee'] as String,
ttlCutoffHeight: json['ttl_cutoff_height'] as String,
id: int.parse(json!['id'].toString()),
txSlateId: json['tx_slate_id'].toString(),
txType: EpicTransactionType.values.byName(json['tx_type'] as String),
creationTs: json['creation_ts'].toString(),
confirmationTs: json['confirmation_ts'].toString(),
confirmed: bool.parse(json['confirmed'].toString()),
numInputs: int.parse(json['num_inputs'].toString()),
numOutputs: int.parse(json['num_outputs'].toString()),
amountCredited: json['amount_credited'].toString(),
amountDebited: json['amount_debited'].toString(),
fee: json['fee'].toString(),
ttlCutoffHeight: json['ttl_cutoff_height'].toString(),
messages: json['messages'] != null ? Messages.fromJson(json['messages'] as Map<String, dynamic>) : null,
storedTx: json['stored_tx'] as String,
kernelExcess: json['kernel_excess'] as String,
kernelLookupMinHeight: json['kernel_lookup_min_height'] as int,
paymentProof: json['payment_proof'] as String,
storedTx: json['stored_tx'].toString(),
kernelExcess: json['kernel_excess'].toString(),
kernelLookupMinHeight: json['kernel_lookup_min_height'] == null? null : int.parse(json['kernel_lookup_min_height'].toString()),
paymentProof: json['payment_proof'].toString(),
);
}
}
@ -107,10 +101,10 @@ class Message {
factory Message.fromJson(Map<String, dynamic> json) {
return Message(
id: json['id'] as String,
publicKey: json['public_key'] as String,
message: json['message'] as String,
messageSig: json['message_sig'] as String,
id: json['id'].toString(),
publicKey: json['public_key'].toString(),
message: json['message'].toString(),
messageSig: json['message_sig'].toString(),
);
}
}
@ -118,8 +112,8 @@ class Message {
enum EpicTransactionType {
//Use Epic transaction type here
outgoing,
incoming,
sentToSelf, // should we keep this?
unknown;
TxReceived,
TxReceivedCancelled,
TxSent,
TxSentCancelled, // should we keep this?
}

View file

@ -23,6 +23,7 @@ import 'package:stack_wallet_backup/generate_password.dart';
import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/epicbox_config_model.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/epic_transaction.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart';
@ -108,16 +109,6 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
sendPort.send(result);
return;
}
} else if (function == "getTransactions") {
final wallet = arguments['wallet'] as String?;
final refreshFromNode = arguments['refreshFromNode'] as int?;
Map<String, dynamic> result = {};
if (!(wallet == null || refreshFromNode == null)) {
var res = await getTransactions(wallet, refreshFromNode);
result['result'] = res;
sendPort.send(result);
return;
}
} else if (function == "startSync") {
final wallet = arguments['wallet'] as String?;
const int refreshFromNode = 1;
@ -315,12 +306,10 @@ class EpicCashWallet extends CoinServiceAPI
key: '${_walletId}_wallet',
))!;
final result = await m.protect(() async {
return await epiccash.LibEpiccash.cancelTransaction(
wallet: wallet,
transactionId: txSlateId,
);
});
final result = await epiccash.LibEpiccash.cancelTransaction(
wallet: wallet,
transactionId: txSlateId,
);
Logging.instance.log(
"cancel $txSlateId result: $result",
level: LogLevel.Info,
@ -1062,14 +1051,11 @@ class EpicCashWallet extends CoinServiceAPI
Future<int> get chainHeight async {
try {
final config = await getRealConfig();
int? latestHeight;
await m.protect(() async {
latestHeight =
await epiccash.LibEpiccash.getChainHeight(config: config);
});
int? latestHeight =
await epiccash.LibEpiccash.getChainHeight(config: config);
await updateCachedChainHeight(latestHeight!);
if (latestHeight! > storedChainHeight) {
await updateCachedChainHeight(latestHeight);
if (latestHeight > storedChainHeight) {
GlobalEventBus.instance.fire(
UpdatedInBackgroundEvent(
"Updated current chain height in $walletId $walletName!",
@ -1077,7 +1063,7 @@ class EpicCashWallet extends CoinServiceAPI
),
);
}
return latestHeight!;
return latestHeight;
} catch (e, s) {
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
level: LogLevel.Error);
@ -1383,80 +1369,56 @@ class EpicCashWallet extends CoinServiceAPI
bool get isConnected => _isConnected;
Future<void> _refreshTransactions() async {
// final currentChainHeight = await chainHeight;
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
const refreshFromNode = 1;
dynamic message;
await m.protect(() async {
ReceivePort receivePort = await getIsolate({
"function": "getTransactions",
"wallet": wallet!,
"refreshFromNode": refreshFromNode,
}, name: walletName);
message = await receivePort.first;
if (message is String) {
Logging.instance
.log("this is a string $message", level: LogLevel.Error);
stop(receivePort);
throw Exception("getTransactions isolate failed");
}
stop(receivePort);
Logging.instance
.log('Closing getTransactions!\n $message', level: LogLevel.Info);
});
// return message;
final String transactions = message['result'] as String;
print("RETURNED TRANSACTIONS IS $transactions");
final jsonTransactions = json.decode(transactions) as List;
var transactions = await epiccash.LibEpiccash.getTransactions(wallet: wallet!, refreshFromNode: refreshFromNode);
final List<Tuple2<isar_models.Transaction, isar_models.Address?>> txnsData =
[];
final slatesToCommits = await getSlatesToCommits();
for (var tx in jsonTransactions) {
for (var tx in transactions) {
Logging.instance.log("tx: $tx", level: LogLevel.Info);
// // TODO: does "confirmed" mean finalized? If so please remove this todo
final isConfirmed = tx["confirmed"] as bool;
final isConfirmed = tx.confirmed;
int amt = 0;
if (tx["tx_type"] == "TxReceived" ||
tx["tx_type"] == "TxReceivedCancelled") {
amt = int.parse(tx['amount_credited'] as String);
if (tx.txType == EpicTransactionType.TxReceived ||
tx.txType == EpicTransactionType.TxReceivedCancelled) {
amt = int.parse(tx.amountCredited);
} else {
int debit = int.parse(tx['amount_debited'] as String);
int credit = int.parse(tx['amount_credited'] as String);
int fee = int.parse((tx['fee'] ?? "0") as String);
int debit = int.parse(tx.amountDebited);
int credit = int.parse(tx.amountCredited);
int fee = int.parse((tx.fee ?? "0"));
amt = debit - credit - fee;
}
DateTime dt = DateTime.parse(tx["creation_ts"] as String);
DateTime dt = DateTime.parse(tx.creationTs);
String? slateId = tx['tx_slate_id'] as String?;
String? slateId = tx.txSlateId;
String address = slatesToCommits[slateId]
?[tx["tx_type"] == "TxReceived" ? "from" : "to"] as String? ??
?[tx.txType == EpicTransactionType.TxReceived ? "from" : "to"] as String? ??
"";
String? commitId = slatesToCommits[slateId]?['commitId'] as String?;
tx['numberOfMessages'] = tx['messages']?['messages']?.length;
tx['onChainNote'] = tx['messages']?['messages']?[0]?['message'];
int? numberOfMessages = tx.messages?.messages.length;
String? onChainNote = tx.messages?.messages[0].message;
int? height;
if (isConfirmed) {
height = tx["kernel_lookup_min_height"] as int? ?? 1;
height = tx.kernelLookupMinHeight ?? 1;
} else {
height = null;
}
final isIncoming = (tx["tx_type"] == "TxReceived" ||
tx["tx_type"] == "TxReceivedCancelled");
final isIncoming = (tx.txType == EpicTransactionType.TxReceived ||
tx.txType == EpicTransactionType.TxReceivedCancelled);
final txn = isar_models.Transaction(
walletId: walletId,
txid: commitId ?? tx["id"].toString(),
txid: commitId ?? tx.id.toString(),
timestamp: (dt.millisecondsSinceEpoch ~/ 1000),
type: isIncoming
? isar_models.TransactionType.incoming
@ -1467,19 +1429,17 @@ class EpicCashWallet extends CoinServiceAPI
rawValue: BigInt.from(amt),
fractionDigits: coin.decimals,
).toJsonString(),
fee: (tx["fee"] == null) ? 0 : int.parse(tx["fee"] as String),
fee: (tx.fee == "null") ? 0 : int.parse(tx.fee!),
height: height,
isCancelled: tx["tx_type"] == "TxSentCancelled" ||
tx["tx_type"] == "TxReceivedCancelled",
isCancelled: tx.txType == EpicTransactionType.TxSentCancelled ||
tx.txType == EpicTransactionType.TxReceivedCancelled,
isLelantus: false,
slateId: slateId,
nonce: null,
otherData: tx['onChainNote'].toString(),
otherData: onChainNote,
inputs: [],
outputs: [],
numberOfMessages: ((tx["numberOfMessages"] == null)
? 0
: tx["numberOfMessages"]) as int,
numberOfMessages: numberOfMessages,
);
// txn.address =

View file

@ -4,6 +4,7 @@ import 'package:decimal/decimal.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash;
import 'package:mutex/mutex.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/epic_transaction.dart';
///
/// Wrapped up calls to flutter_libepiccash.
@ -263,17 +264,30 @@ abstract class LibEpiccash {
///
///
///
static Future<String> getTransaction({
static Future<List<EpicTransaction>> getTransactions({
required String wallet,
required int refreshFromNode,
}) async {
try {
return await compute(_getTransactionsWrapper, (
wallet: wallet,
refreshFromNode: refreshFromNode,
var result = await compute(_getTransactionsWrapper, (
wallet: wallet,
refreshFromNode: refreshFromNode,
));
if (result.toUpperCase().contains("ERROR")) {
throw Exception("Error getting epic transactions ${result.toString()}");
}
//Parse the returned data as an EpicTransaction
List<EpicTransaction> finalResult = [];
var jsonResult = json.decode(result) as List;
for (var tx in jsonResult) {
EpicTransaction itemTx = EpicTransaction.fromJson(tx);
finalResult.add(itemTx);
}
return finalResult;
} catch (e) {
throw ("Error getting epic transaction : ${e.toString()}");
throw ("Error getting epic transactions : ${e.toString()}");
}
}