Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to cs_monero from flutter_libmonero #1012

Closed
wants to merge 12 commits into from
Prev Previous commit
Next Next commit
use transactionV2 in xmr/wow wallets
julian-CStack committed Oct 29, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 498a491a1e30594f59e9cb39930f9a2fc62e9248
134 changes: 59 additions & 75 deletions lib/wallets/wallet/intermediate/lib_monero_wallet.dart
Original file line number Diff line number Diff line change
@@ -8,13 +8,15 @@ import 'package:cs_monero/cs_monero.dart' as lib_monero;
import 'package:isar/isar.dart';
import 'package:mutex/mutex.dart';
import 'package:stack_wallet_backup/generate_password.dart';
import 'package:tuple/tuple.dart';

import '../../../db/hive/db.dart';
import '../../../models/balance.dart';
import '../../../models/isar/models/blockchain_data/address.dart';
import '../../../models/isar/models/blockchain_data/transaction.dart';
import '../../../models/isar/models/blockchain_data/utxo.dart';
import '../../../models/isar/models/blockchain_data/v2/input_v2.dart';
import '../../../models/isar/models/blockchain_data/v2/output_v2.dart';
import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart';
import '../../../models/keys/cw_key_data.dart';
import '../../../models/paymint/fee_object_model.dart';
import '../../../services/event_bus/events/global/blocks_remaining_event.dart';
@@ -38,6 +40,9 @@ import 'cryptonote_wallet.dart';

abstract class LibMoneroWallet<T extends CryptonoteCurrency>
extends CryptonoteWallet<T> implements MultiAddressInterface<T> {
@override
int get isarTransactionVersion => 2;

LibMoneroWallet(super.currency, this.compatType) {
final bus = GlobalEventBus.instance;

@@ -472,6 +477,8 @@ abstract class LibMoneroWallet<T extends CryptonoteCurrency>

final transactions = await base.getTxs(refresh: true);

final allOutputs = await base.getOutputs(includeSpent: true, refresh: true);

// final cachedTransactions =
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
// as TransactionData?;
@@ -504,98 +511,75 @@ abstract class LibMoneroWallet<T extends CryptonoteCurrency>
// }
// }

final List<Tuple2<Transaction, Address?>> txnsData = [];
final List<TransactionV2> txns = [];

for (final tx in transactions) {
Address? address;
final associatedOutputs = allOutputs.where((e) => e.hash == tx.hash);
final List<InputV2> inputs = [];
final List<OutputV2> outputs = [];
TransactionType type;
if (!tx.isSpend) {
final String? addressString;
if (tx.addressIndexes.isEmpty) {
addressString = null;
Logging.instance.log(
"tx.addressIndexes.isEmpty for receive",
level: LogLevel.Warning,
type = TransactionType.incoming;
for (final output in associatedOutputs) {
outputs.add(
OutputV2.isarCantDoRequiredInDefaultConstructor(
scriptPubKeyHex: "",
valueStringSats: output.value.toString(),
addresses: [output.address],
walletOwns: true,
),
);
} else {
if (tx.addressIndexes.length > 1) {
Logging.instance.log(
"tx.addressIndexes contains more than one in receive",
level: LogLevel.Warning,
);
}
addressString = libMoneroWallet
?.getAddress(
accountIndex: tx.accountIndex,
addressIndex: tx.addressIndexes.first,
)
.value;
}

if (addressString != null) {
address = await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(addressString)
.findFirst();
}

type = TransactionType.incoming;
} else {
// txn.address = "";
type = TransactionType.outgoing;
for (final output in associatedOutputs) {
inputs.add(
InputV2.isarCantDoRequiredInDefaultConstructor(
scriptSigHex: null,
scriptSigAsm: null,
sequence: null,
outpoint: null,
addresses: [output.address],
valueStringSats: output.value.toString(),
witness: null,
innerRedeemScriptAsm: null,
coinbase: null,
walletOwns: true,
),
);
}
}

final txn = Transaction(
final txn = TransactionV2(
walletId: walletId,
blockHash: null, // not exposed via current cs_monero
hash: tx.hash,
txid: tx.hash,
timestamp: (tx.timeStamp.millisecondsSinceEpoch ~/ 1000),
height: tx.blockHeight,
inputs: inputs,
outputs: outputs,
version: -1, // not exposed via current cs_monero
type: type,
subType: TransactionSubType.none,
amount: tx.amount.toInt(),
amountString: Amount(
rawValue: tx.amount,
fractionDigits: cryptoCurrency.fractionDigits,
).toJsonString(),
fee: tx.fee.toInt(),
height: tx.blockHeight,
isCancelled: false,
isLelantus: false,
slateId: null,
otherData: null,
nonce: null,
inputs: [],
outputs: [],
numberOfMessages: null,
otherData: jsonEncode({
TxV2OdKeys.overrideFee: Amount(
rawValue: tx.fee,
fractionDigits: cryptoCurrency.fractionDigits,
).toJsonString(),
TxV2OdKeys.moneroAmount: Amount(
rawValue: tx.amount,
fractionDigits: cryptoCurrency.fractionDigits,
).toJsonString(),
TxV2OdKeys.moneroAccountIndex: tx.accountIndex,
TxV2OdKeys.isMoneroTransaction: true,
}),
);

txnsData.add(Tuple2(txn, address));
txns.add(txn);
}
await mainDB.isar.writeTxn(() async {
await mainDB.isar.transactions
.where()
.walletIdEqualTo(walletId)
.deleteAll();
for (final data in txnsData) {
final tx = data.item1;

// save transaction
await mainDB.isar.transactions.put(tx);

if (data.item2 != null) {
final address = await mainDB.getAddress(walletId, data.item2!.value);

// check if address exists in db and add if it does not
if (address == null) {
await mainDB.isar.addresses.put(data.item2!);
}

// link and save address
tx.address.value = address ?? data.item2!;
await tx.address.save();
}
}
});
await mainDB.updateOrPutTransactionV2s(txns);
}

Future<Amount> get availableBalance async {
@@ -927,7 +911,7 @@ abstract class LibMoneroWallet<T extends CryptonoteCurrency>
.and()
.txidEqualTo(rawUTXO.hash)
.findFirst();
final tx = await mainDB.isar.transactions
final tx = await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()