finish up basic migrate lcoins hive => isar

This commit is contained in:
julian 2023-07-24 12:30:01 -06:00
parent a5ba67aa1d
commit df0b004b82
3 changed files with 301 additions and 293 deletions

View file

@ -26,7 +26,6 @@ import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
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/models/signing_data.dart'; import 'package:stackwallet/models/signing_data.dart';
@ -161,6 +160,7 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
final mnemonicPassphrase = arguments['mnemonicPassphrase'] as String; final mnemonicPassphrase = arguments['mnemonicPassphrase'] as String;
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 walletId = arguments['walletId'] as String;
final restoreData = await isolateRestore( final restoreData = await isolateRestore(
mnemonic, mnemonic,
@ -170,6 +170,7 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
setDataMap, setDataMap,
usedSerialNumbers, usedSerialNumbers,
network, network,
walletId,
); );
sendPort.send(restoreData); sendPort.send(restoreData);
return; return;
@ -206,13 +207,14 @@ Future<Map<String, dynamic>> isolateRestore(
Map<dynamic, dynamic> _setDataMap, Map<dynamic, dynamic> _setDataMap,
List<String> _usedSerialNumbers, List<String> _usedSerialNumbers,
NetworkType network, NetworkType network,
String walletId,
) async { ) async {
List<int> jindexes = []; List<int> jindexes = [];
List<Map<dynamic, LelantusCoin>> lelantusCoins = []; List<isar_models.LelantusCoin> lelantusCoins = [];
final List<String> spendTxIds = []; final List<String> spendTxIds = [];
var lastFoundIndex = 0; int lastFoundIndex = 0;
var currentIndex = 0; int currentIndex = 0;
try { try {
Set<String> usedSerialNumbersSet = _usedSerialNumbers.toSet(); Set<String> usedSerialNumbersSet = _usedSerialNumbers.toSet();
@ -239,7 +241,7 @@ Future<Map<String, dynamic>> isolateRestore(
isTestnet: coin == Coin.firoTestNet, isTestnet: coin == Coin.firoTestNet,
); );
for (var setId = 1; setId <= _latestSetId; setId++) { for (int setId = 1; setId <= _latestSetId; setId++) {
final setData = _setDataMap[setId] as Map; final setData = _setDataMap[setId] as Map;
final foundCoin = (setData["coins"] as List).firstWhere( final foundCoin = (setData["coins"] as List).firstWhere(
(e) => e[1] == mintTag, (e) => e[1] == mintTag,
@ -264,32 +266,23 @@ Future<Map<String, dynamic>> isolateRestore(
isTestnet: coin == Coin.firoTestNet, isTestnet: coin == Coin.firoTestNet,
); );
final bool isUsed = usedSerialNumbersSet.contains(serialNumber); final bool isUsed = usedSerialNumbersSet.contains(serialNumber);
final duplicateCoin = lelantusCoins.firstWhere(
(element) { lelantusCoins.removeWhere((e) =>
final coin = element.values.first; e.txid == txId &&
return coin.txId == txId && e.index == currentIndex &&
coin.index == currentIndex && e.anonymitySetId != setId);
coin.anonymitySetId != setId;
}, lelantusCoins.add(
orElse: () => {}, isar_models.LelantusCoin(
walletId: walletId,
index: currentIndex,
value: amount.toString(),
publicCoin: publicCoin,
txid: txId,
anonymitySetId: setId,
isUsed: isUsed,
),
); );
if (duplicateCoin.isNotEmpty) {
Logging.instance.log(
"Firo isolateRestore removing duplicate coin: $duplicateCoin",
level: LogLevel.Info,
);
lelantusCoins.remove(duplicateCoin);
}
lelantusCoins.add({
txId: LelantusCoin(
currentIndex,
amount,
publicCoin,
txId,
setId,
isUsed,
)
});
Logging.instance.log( Logging.instance.log(
"amount $amount used $isUsed", "amount $amount used $isUsed",
level: LogLevel.Info, level: LogLevel.Info,
@ -322,32 +315,22 @@ Future<Map<String, dynamic>> isolateRestore(
isTestnet: coin == Coin.firoTestNet, isTestnet: coin == Coin.firoTestNet,
); );
bool isUsed = usedSerialNumbersSet.contains(serialNumber); bool isUsed = usedSerialNumbersSet.contains(serialNumber);
final duplicateCoin = lelantusCoins.firstWhere( lelantusCoins.removeWhere((e) =>
(element) { e.txid == txId &&
final coin = element.values.first; e.index == currentIndex &&
return coin.txId == txId && e.anonymitySetId != setId);
coin.index == currentIndex &&
coin.anonymitySetId != setId; lelantusCoins.add(
}, isar_models.LelantusCoin(
orElse: () => {}, walletId: walletId,
index: currentIndex,
value: amount.toString(),
publicCoin: publicCoin,
txid: txId,
anonymitySetId: setId,
isUsed: isUsed,
),
); );
if (duplicateCoin.isNotEmpty) {
Logging.instance.log(
"Firo isolateRestore removing duplicate coin: $duplicateCoin",
level: LogLevel.Info,
);
lelantusCoins.remove(duplicateCoin);
}
lelantusCoins.add({
txId: LelantusCoin(
currentIndex,
amount,
publicCoin,
txId,
setId,
isUsed,
)
});
jindexes.add(currentIndex); jindexes.add(currentIndex);
spendTxIds.add(txId); spendTxIds.add(txId);
@ -396,73 +379,74 @@ Future<Map<dynamic, dynamic>> staticProcessRestore(
Map<dynamic, dynamic> result, Map<dynamic, dynamic> result,
int currentHeight, int currentHeight,
) async { ) async {
List<dynamic>? _l = result['_lelantus_coins'] as List?; List<isar_models.LelantusCoin> lelantusCoins =
final List<Map<dynamic, LelantusCoin>> lelantusCoins = []; result['_lelantus_coins'] as List<isar_models.LelantusCoin>;
for (var el in _l ?? []) {
lelantusCoins.add({el.keys.first: el.values.first as LelantusCoin});
}
// Edit the receive transactions with the mint fees. // Edit the receive transactions with the mint fees.
Map<String, isar_models.Transaction> editedTransactions = List<isar_models.Transaction> editedTransactions = [];
<String, isar_models.Transaction>{};
for (var item in lelantusCoins) { for (final coin in lelantusCoins) {
item.forEach((key, value) { String txid = coin.txid;
String txid = value.txId; isar_models.Transaction? tx;
isar_models.Transaction? tx; try {
tx = txns.firstWhere((e) => e.txid == txid);
} catch (_) {
tx = null;
}
if (tx == null || tx.subType == isar_models.TransactionSubType.join) {
// This is a jmint.
continue;
}
List<isar_models.Transaction> inputTxns = [];
for (final input in tx.inputs) {
isar_models.Transaction? inputTx;
try { try {
tx = txns.firstWhere((e) => e.txid == txid); inputTx = txns.firstWhere((e) => e.txid == input.txid);
} catch (_) { } catch (_) {
tx = null; inputTx = null;
} }
if (inputTx != null) {
inputTxns.add(inputTx);
}
}
if (inputTxns.isEmpty) {
//some error.
Logging.instance.log(
"cryptic \"//some error\" occurred in staticProcessRestore on lelantus coin: $coin",
level: LogLevel.Error,
);
continue;
}
if (tx == null || tx.subType == isar_models.TransactionSubType.join) { int mintFee = tx.fee;
// This is a jmint. int sharedFee = mintFee ~/ inputTxns.length;
return; for (final inputTx in inputTxns) {
} final edited = isar_models.Transaction(
List<isar_models.Transaction> inputs = []; walletId: inputTx.walletId,
for (var element in tx.inputs) { txid: inputTx.txid,
isar_models.Transaction? input; timestamp: inputTx.timestamp,
try { type: inputTx.type,
input = txns.firstWhere((e) => e.txid == element.txid); subType: isar_models.TransactionSubType.mint,
} catch (_) { amount: inputTx.amount,
input = null; amountString: Amount(
} rawValue: BigInt.from(inputTx.amount),
if (input != null) { fractionDigits: Coin.firo.decimals,
inputs.add(input); ).toJsonString(),
} fee: sharedFee,
} height: inputTx.height,
if (inputs.isEmpty) { isCancelled: false,
//some error. isLelantus: true,
return; slateId: null,
} otherData: txid,
nonce: null,
int mintFee = tx.fee; inputs: inputTx.inputs,
int sharedFee = mintFee ~/ inputs.length; outputs: inputTx.outputs,
for (var element in inputs) { numberOfMessages: null,
editedTransactions[element.txid] = isar_models.Transaction( )..address.value = inputTx.address.value;
walletId: element.walletId, editedTransactions.add(edited);
txid: element.txid, }
timestamp: element.timestamp,
type: element.type,
subType: isar_models.TransactionSubType.mint,
amount: element.amount,
amountString: Amount(
rawValue: BigInt.from(element.amount),
fractionDigits: Coin.firo.decimals,
).toJsonString(),
fee: sharedFee,
height: element.height,
isCancelled: false,
isLelantus: true,
slateId: null,
otherData: txid,
nonce: null,
inputs: element.inputs,
outputs: element.outputs,
numberOfMessages: null,
)..address.value = element.address.value;
}
});
} }
// Logging.instance.log(editedTransactions, addToDebugMessagesDB: false); // Logging.instance.log(editedTransactions, addToDebugMessagesDB: false);
@ -472,12 +456,13 @@ Future<Map<dynamic, dynamic>> staticProcessRestore(
} }
// Logging.instance.log(transactionMap, addToDebugMessagesDB: false); // Logging.instance.log(transactionMap, addToDebugMessagesDB: false);
editedTransactions.forEach((key, value) { // update with edited transactions
transactionMap.update(key, (_value) => value); for (final tx in editedTransactions) {
}); transactionMap[tx.txid] = tx;
}
transactionMap.removeWhere((key, value) => transactionMap.removeWhere((key, value) =>
lelantusCoins.any((element) => element.containsKey(key)) || lelantusCoins.any((element) => element.txid == key) ||
((value.height == -1 || value.height == null) && ((value.height == -1 || value.height == null) &&
!value.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS))); !value.isConfirmed(currentHeight, MINIMUM_CONFIRMATIONS)));
@ -2248,9 +2233,9 @@ class FiroWallet extends CoinServiceAPI
_feeObject = Future(() => feeObj); _feeObject = Future(() => feeObj);
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.60, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.60, walletId));
final lelantusCoins = getLelantusCoinMap(); // final lelantusCoins = getLelantusCoinMap();
Logging.instance.log("_lelantus_coins at refresh: $lelantusCoins", // Logging.instance.log("_lelantus_coins at refresh: $lelantusCoins",
level: LogLevel.Warning, printFullLength: true); // level: LogLevel.Warning, printFullLength: true);
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.70, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.70, walletId));
await _refreshLelantusData(); await _refreshLelantusData();
@ -2327,7 +2312,8 @@ class FiroWallet extends CoinServiceAPI
level: LogLevel.Error); level: LogLevel.Error);
} }
final List<LelantusCoin> lelantusCoins = await _getUnspentCoins(); final List<isar_models.LelantusCoin> lelantusCoins =
await _getUnspentCoins();
final root = await Bip32Utils.getBip32Root( final root = await Bip32Utils.getBip32Root(
_mnemonic!, _mnemonic!,
@ -2349,7 +2335,7 @@ class FiroWallet extends CoinServiceAPI
} }
final String privateKey = Format.uint8listToString(keyPair.privateKey!); final String privateKey = Format.uint8listToString(keyPair.privateKey!);
return DartLelantusEntry(coin.isUsed ? 1 : 0, 0, coin.anonymitySetId, return DartLelantusEntry(coin.isUsed ? 1 : 0, 0, coin.anonymitySetId,
coin.value, coin.index, privateKey); int.parse(coin.value), coin.index, privateKey);
}).toList(); }).toList();
final lelantusEntries = await Future.wait(waitLelantusEntries); final lelantusEntries = await Future.wait(waitLelantusEntries);
@ -2361,61 +2347,55 @@ class FiroWallet extends CoinServiceAPI
return lelantusEntries; return lelantusEntries;
} }
List<Map<dynamic, LelantusCoin>> getLelantusCoinMap() { Future<List<isar_models.LelantusCoin>> _getUnspentCoins() async {
final _l = firoGetLelantusCoins(); final jindexes = firoGetJIndex() ?? [];
final List<Map<dynamic, LelantusCoin>> lelantusCoins = [];
for (var el in _l ?? []) {
lelantusCoins.add({el.keys.first: el.values.first as LelantusCoin});
}
return lelantusCoins;
}
Future<List<LelantusCoin>> _getUnspentCoins() async { final lelantusCoinsList = await db.isar.lelantusCoins
final List<Map<dynamic, LelantusCoin>> lelantusCoins = getLelantusCoinMap(); .where()
if (lelantusCoins.isNotEmpty) { .walletIdEqualTo(walletId)
lelantusCoins.removeWhere((element) => .filter()
element.values.any((elementCoin) => elementCoin.value == 0)); .not()
} .valueEqualTo("0")
final jindexes = firoGetJIndex(); .findAll();
List<LelantusCoin> coins = []; List<isar_models.LelantusCoin> coins = [];
List<LelantusCoin> lelantusCoinsList =
lelantusCoins.fold(<LelantusCoin>[], (previousValue, element) {
previousValue.add(element.values.first);
return previousValue;
});
final currentChainHeight = await chainHeight; final currentChainHeight = await chainHeight;
for (int i = 0; i < lelantusCoinsList.length; i++) { for (int i = 0; i < lelantusCoinsList.length; i++) {
// Logging.instance.log("lelantusCoinsList[$i]: ${lelantusCoinsList[i]}"); // Logging.instance.log("lelantusCoinsList[$i]: ${lelantusCoinsList[i]}");
final txid = lelantusCoinsList[i].txId; final coin = lelantusCoinsList[i];
final txn = await cachedElectrumXClient.getTransaction(
txHash: txid,
verbose: true,
coin: coin,
);
final confirmations = txn["confirmations"];
bool isUnconfirmed = confirmations is int && confirmations < 1;
final tx = await db.getTransaction(walletId, txid); final tx = await db.getTransaction(walletId, coin.txid);
if (!jindexes!.contains(lelantusCoinsList[i].index) && // TODO check if sane default
tx != null && bool isUnconfirmed = false;
tx.isLelantus == true &&
!(tx.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS))) { if (tx != null) {
isUnconfirmed = true; bool isConfirmed = tx.isConfirmed(
currentChainHeight,
MINIMUM_CONFIRMATIONS,
);
if (!jindexes.contains(coin.index) &&
tx.isLelantus == true &&
!isConfirmed) {
isUnconfirmed = true;
} else if (!isConfirmed) {
continue;
}
} else {
final txn = await cachedElectrumXClient.getTransaction(
txHash: coin.txid,
verbose: true,
coin: this.coin,
);
final confirmations = txn["confirmations"];
isUnconfirmed = confirmations is int && confirmations < 1;
} }
if (!coin.isUsed &&
if (tx != null && coin.anonymitySetId != ANONYMITY_SET_EMPTY_ID &&
!tx.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) {
continue;
}
if (!lelantusCoinsList[i].isUsed &&
lelantusCoinsList[i].anonymitySetId != ANONYMITY_SET_EMPTY_ID &&
!isUnconfirmed) { !isUnconfirmed) {
coins.add(lelantusCoinsList[i]); coins.add(coin);
} }
} }
return coins; return coins;
@ -2427,62 +2407,65 @@ class FiroWallet extends CoinServiceAPI
Future<void> _refreshBalance() async { Future<void> _refreshBalance() async {
try { try {
final utxosUpdateFuture = _refreshUTXOs(); final utxosUpdateFuture = _refreshUTXOs();
final List<Map<dynamic, LelantusCoin>> lelantusCoins = final lelantusCoins = await db.isar.lelantusCoins
getLelantusCoinMap(); .where()
if (lelantusCoins.isNotEmpty) { .walletIdEqualTo(walletId)
lelantusCoins.removeWhere((element) => .filter()
element.values.any((elementCoin) => elementCoin.value == 0)); .not()
} .valueEqualTo(0.toString())
.findAll();
final currentChainHeight = await chainHeight; final currentChainHeight = await chainHeight;
final jindexes = firoGetJIndex(); final jindexes = firoGetJIndex();
int intLelantusBalance = 0; int intLelantusBalance = 0;
int unconfirmedLelantusBalance = 0; int unconfirmedLelantusBalance = 0;
for (final element in lelantusCoins) { for (final lelantusCoin in lelantusCoins) {
element.forEach((key, lelantusCoin) { isar_models.Transaction? txn = db.isar.transactions
isar_models.Transaction? txn = db.isar.transactions .where()
.where() .txidWalletIdEqualTo(
.txidWalletIdEqualTo( lelantusCoin.txid,
lelantusCoin.txId, walletId,
walletId, )
) .findFirstSync();
.findFirstSync();
if (txn == null) { if (txn == null) {
// TODO: ?????????????????????????????????????? // TODO: ??????????????????????????????????????
} else { Logging.instance.log(
bool isLelantus = txn.isLelantus == true; "Transaction not found in DB for lelantus coin: $lelantusCoin",
if (!jindexes!.contains(lelantusCoin.index) && isLelantus) { level: LogLevel.Fatal,
if (!lelantusCoin.isUsed && );
txn.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) { } else {
// mint tx, add value to balance bool isLelantus = txn.isLelantus == true;
intLelantusBalance += lelantusCoin.value; if (!jindexes!.contains(lelantusCoin.index) && isLelantus) {
} /* else { if (!lelantusCoin.isUsed &&
txn.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) {
// mint tx, add value to balance
intLelantusBalance += int.parse(lelantusCoin.value);
} /* else {
// This coin is not confirmed and may be replaced // This coin is not confirmed and may be replaced
}*/ }*/
} else if (jindexes.contains(lelantusCoin.index) && } else if (jindexes.contains(lelantusCoin.index) &&
isLelantus && isLelantus &&
!lelantusCoin.isUsed && !lelantusCoin.isUsed &&
!txn.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) { !txn.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS)) {
unconfirmedLelantusBalance += lelantusCoin.value; unconfirmedLelantusBalance += int.parse(lelantusCoin.value);
} else if (jindexes.contains(lelantusCoin.index) && } else if (jindexes.contains(lelantusCoin.index) &&
!lelantusCoin.isUsed) { !lelantusCoin.isUsed) {
intLelantusBalance += lelantusCoin.value; intLelantusBalance += int.parse(lelantusCoin.value);
} else if (!lelantusCoin.isUsed && } else if (!lelantusCoin.isUsed &&
(txn.isLelantus == true (txn.isLelantus == true
? true ? true
: txn.isConfirmed( : txn.isConfirmed(
currentChainHeight, MINIMUM_CONFIRMATIONS) != currentChainHeight, MINIMUM_CONFIRMATIONS) !=
false)) { false)) {
intLelantusBalance += lelantusCoin.value; intLelantusBalance += int.parse(lelantusCoin.value);
} else if (!isLelantus && } else if (!isLelantus &&
txn.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS) == txn.isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS) ==
false) { false) {
unconfirmedLelantusBalance += lelantusCoin.value; unconfirmedLelantusBalance += int.parse(lelantusCoin.value);
}
} }
}); }
} }
_balancePrivate = Balance( _balancePrivate = Balance(
@ -2551,17 +2534,19 @@ class FiroWallet extends CoinServiceAPI
} }
} }
final List<Map<dynamic, LelantusCoin>> lelantusCoins = getLelantusCoinMap(); final lelantusCoins = await db.isar.lelantusCoins
if (lelantusCoins.isNotEmpty) { .where()
lelantusCoins.removeWhere((element) => .walletIdEqualTo(walletId)
element.values.any((elementCoin) => elementCoin.value == 0)); .filter()
} .not()
.valueEqualTo(0.toString())
.findAll();
final data = await _txnData; final data = await _txnData;
for (final value in data) { for (final value in data) {
if (value.inputs.isNotEmpty) { if (value.inputs.isNotEmpty) {
for (var element in value.inputs) { for (var element in value.inputs) {
if (lelantusCoins if (lelantusCoins.any((e) => e.txid == value.txid) &&
.any((element) => element.keys.contains(value.txid)) &&
spendableOutputs.firstWhere( spendableOutputs.firstWhere(
(output) => output?.txid == element.txid, (output) => output?.txid == element.txid,
orElse: () => null) != orElse: () => null) !=
@ -2844,7 +2829,14 @@ class FiroWallet extends CoinServiceAPI
} }
Future<void> _refreshLelantusData() async { Future<void> _refreshLelantusData() async {
final List<Map<dynamic, LelantusCoin>> lelantusCoins = getLelantusCoinMap(); final lelantusCoins = await db.isar.lelantusCoins
.where()
.walletIdEqualTo(walletId)
.filter()
.not()
.valueEqualTo(0.toString())
.findAll();
final jindexes = firoGetJIndex(); final jindexes = firoGetJIndex();
// Get all joinsplit transaction ids // Get all joinsplit transaction ids
@ -2855,19 +2847,16 @@ class FiroWallet extends CoinServiceAPI
.isLelantusEqualTo(true) .isLelantusEqualTo(true)
.findAll(); .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) {
joinsplits.add(tx.txid); joinsplits.add(tx.txid);
} }
} }
for (final coin for (final coin in lelantusCoins) {
in lelantusCoins.fold(<LelantusCoin>[], (previousValue, element) {
(previousValue as List<LelantusCoin>).add(element.values.first);
return previousValue;
})) {
if (jindexes != null) { if (jindexes != null) {
if (jindexes.contains(coin.index) && !joinsplits.contains(coin.txId)) { if (jindexes.contains(coin.index) && !joinsplits.contains(coin.txid)) {
joinsplits.add(coin.txId); joinsplits.add(coin.txid);
} }
} }
} }
@ -3030,51 +3019,66 @@ class FiroWallet extends CoinServiceAPI
Logging.instance.log( Logging.instance.log(
"_submitLelantusToNetwork txid: ${transactionInfo['txid']}", "_submitLelantusToNetwork txid: ${transactionInfo['txid']}",
level: LogLevel.Info); level: LogLevel.Info);
if (txid == transactionInfo['txid']) { if (txid == transactionInfo['txid']) {
final index = firoGetMintIndex(); final index = firoGetMintIndex();
final List<Map<dynamic, LelantusCoin>> lelantusCoins =
getLelantusCoinMap();
List<Map<dynamic, LelantusCoin>> coins;
if (lelantusCoins.isEmpty) {
coins = [];
} else {
coins = [...lelantusCoins];
}
if (transactionInfo['spendCoinIndexes'] != null) { if (transactionInfo['spendCoinIndexes'] != null) {
// This is a joinsplit // This is a joinsplit
final spentCoinIndexes =
transactionInfo['spendCoinIndexes'] as List<int>;
final List<isar_models.LelantusCoin> updatedCoins = [];
// Update all of the coins that have been spent. // Update all of the coins that have been spent.
for (final lCoinMap in coins) {
final lCoin = lCoinMap.values.first; for (final index in spentCoinIndexes) {
if ((transactionInfo['spendCoinIndexes'] as List<int>) final possibleCoins = await db.isar.lelantusCoins
.contains(lCoin.index)) { .where()
lCoinMap[lCoinMap.keys.first] = LelantusCoin( .walletIdEqualTo(walletId)
lCoin.index, .filter()
lCoin.value, .indexEqualTo(index)
lCoin.publicCoin, .findAll();
lCoin.txId,
lCoin.anonymitySetId, if (possibleCoins.isNotEmpty) {
true); if (possibleCoins.length > 1) {
print(
"======================= possibleCoins.length > 1 !!! =================================");
} else {
final spentCoin = possibleCoins.first;
updatedCoins.add(spentCoin.copyWith(isUsed: true));
}
} }
} }
// if a jmint was made add it to the unspent coin index // if a jmint was made add it to the unspent coin index
LelantusCoin jmint = LelantusCoin( final jmint = isar_models.LelantusCoin(
index, walletId: walletId,
transactionInfo['jmintValue'] as int? ?? 0, index: index,
transactionInfo['publicCoin'] as String, value: (transactionInfo['jmintValue'] as int? ?? 0).toString(),
transactionInfo['txid'] as String, publicCoin: transactionInfo['publicCoin'] as String,
latestSetId, txid: transactionInfo['txid'] as String,
false); anonymitySetId: latestSetId,
if (jmint.value > 0) { isUsed: false,
coins.add({jmint.txId: jmint}); );
if (int.parse(jmint.value) > 0) {
updatedCoins.add(jmint);
final jindexes = firoGetJIndex()!; final jindexes = firoGetJIndex()!;
jindexes.add(index); jindexes.add(index);
await firoUpdateJIndex(jindexes); await firoUpdateJIndex(jindexes);
await firoUpdateMintIndex(index + 1); await firoUpdateMintIndex(index + 1);
} }
await firoUpdateLelantusCoins(coins);
await db.isar.writeTxn(() async {
for (final c in updatedCoins) {
await db.isar.lelantusCoins.deleteByPublicCoinWalletIdTxid(
c.publicCoin,
c.walletId,
c.txid,
);
}
await db.isar.lelantusCoins.putAll(updatedCoins);
});
final amount = Amount.fromDecimal( final amount = Amount.fromDecimal(
Decimal.parse(transactionInfo["amount"].toString()), Decimal.parse(transactionInfo["amount"].toString()),
@ -3087,14 +3091,8 @@ class FiroWallet extends CoinServiceAPI
txid: transactionInfo['txid'] as String, txid: transactionInfo['txid'] as String,
timestamp: transactionInfo['timestamp'] as int? ?? timestamp: transactionInfo['timestamp'] as int? ??
(DateTime.now().millisecondsSinceEpoch ~/ 1000), (DateTime.now().millisecondsSinceEpoch ~/ 1000),
type: transactionInfo['txType'] == "Received" type: isar_models.TransactionType.outgoing,
? isar_models.TransactionType.incoming subType: isar_models.TransactionSubType.join,
: isar_models.TransactionType.outgoing,
subType: transactionInfo["subType"] == "mint"
? isar_models.TransactionSubType.mint
: transactionInfo["subType"] == "join"
? isar_models.TransactionSubType.join
: isar_models.TransactionSubType.none,
amount: amount.raw.toInt(), amount: amount.raw.toInt(),
amountString: amount.toJsonString(), amountString: amount.toJsonString(),
fee: Amount.fromDecimal( fee: Amount.fromDecimal(
@ -3137,25 +3135,30 @@ class FiroWallet extends CoinServiceAPI
// This is a mint // This is a mint
Logging.instance.log("this is a mint", level: LogLevel.Info); Logging.instance.log("this is a mint", level: LogLevel.Info);
final List<isar_models.LelantusCoin> updatedCoins = [];
// TODO: transactionInfo['mintsMap'] // TODO: transactionInfo['mintsMap']
for (final mintMap for (final mintMap
in transactionInfo['mintsMap'] as List<Map<String, dynamic>>) { in transactionInfo['mintsMap'] as List<Map<String, dynamic>>) {
final index = mintMap['index'] as int?; final index = mintMap['index'] as int;
LelantusCoin mint = LelantusCoin( final mint = isar_models.LelantusCoin(
index!, walletId: walletId,
mintMap['value'] as int, index: index,
mintMap['publicCoin'] as String, value: (mintMap['value'] as int).toString(),
transactionInfo['txid'] as String, publicCoin: mintMap['publicCoin'] as String,
latestSetId, txid: transactionInfo['txid'] as String,
false, anonymitySetId: latestSetId,
isUsed: false,
); );
if (mint.value > 0) { if (int.parse(mint.value) > 0) {
coins.add({mint.txId: mint}); updatedCoins.add(mint);
await firoUpdateMintIndex(index + 1); await firoUpdateMintIndex(index + 1);
} }
} }
// Logging.instance.log(coins); // Logging.instance.log(coins);
await firoUpdateLelantusCoins(coins); await db.isar.writeTxn(() async {
await db.isar.lelantusCoins.putAll(updatedCoins);
});
} }
return true; return true;
} else { } else {
@ -4556,6 +4559,7 @@ class FiroWallet extends CoinServiceAPI
"setDataMap": setDataMap, "setDataMap": setDataMap,
"usedSerialNumbers": usedSerialNumbers, "usedSerialNumbers": usedSerialNumbers,
"network": _network, "network": _network,
"walletId": walletId,
}); });
await Future.wait([dataFuture]); await Future.wait([dataFuture]);
@ -4576,7 +4580,10 @@ class FiroWallet extends CoinServiceAPI
await Future.wait([ await Future.wait([
firoUpdateMintIndex(message['mintIndex'] as int), firoUpdateMintIndex(message['mintIndex'] as int),
firoUpdateLelantusCoins(message['_lelantus_coins'] as List), db.isar.writeTxn(() async {
await db.isar.lelantusCoins.putAll(
message['_lelantus_coins'] as List<isar_models.LelantusCoin>);
}),
firoUpdateJIndex(message['jindex'] as List), firoUpdateJIndex(message['jindex'] as List),
]); ]);

View file

@ -30,19 +30,19 @@ mixin FiroHive {
); );
} }
// _lelantus_coins // // _lelantus_coins
List? firoGetLelantusCoins() { // List? firoGetLelantusCoins() {
return DB.instance.get<dynamic>(boxName: _walletId, key: "_lelantus_coins") // return DB.instance.get<dynamic>(boxName: _walletId, key: "_lelantus_coins")
as List?; // as List?;
} // }
//
Future<void> firoUpdateLelantusCoins(List lelantusCoins) async { // Future<void> firoUpdateLelantusCoins(List lelantusCoins) async {
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: _walletId, // boxName: _walletId,
key: "_lelantus_coins", // key: "_lelantus_coins",
value: lelantusCoins, // value: lelantusCoins,
); // );
} // }
// mintIndex // mintIndex
int firoGetMintIndex() { int firoGetMintIndex() {

View file

@ -388,7 +388,8 @@ class DbVersionMigrator with WalletDB {
final List<isar_models.LelantusCoin> coins = []; final List<isar_models.LelantusCoin> coins = [];
for (final e in hiveLCoins) { for (final e in hiveLCoins) {
final lcoin = e as LelantusCoin; final map = e as Map;
final lcoin = map.values.first as LelantusCoin;
final coin = isar_models.LelantusCoin( final coin = isar_models.LelantusCoin(
walletId: walletId, walletId: walletId,