mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
finish up basic migrate lcoins hive => isar
This commit is contained in:
parent
a5ba67aa1d
commit
df0b004b82
3 changed files with 301 additions and 293 deletions
|
@ -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),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue