mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 20:39:51 +00:00
cleaned up handling of xelis tx details and history syncing
This commit is contained in:
parent
03665e30f7
commit
194245ba38
9 changed files with 144 additions and 85 deletions
|
@ -49,7 +49,7 @@ class XelisAssetBalance extends Balance {
|
|||
}
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => formatXelisAmount(balance, decimals: decimals);
|
||||
String get formattedAvailableBalance => XelisFormatter.formatAmount(balance, decimals: decimals);
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance => '0';
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import 'dart:math';
|
||||
|
||||
class XelisFormatter {
|
||||
static int _divider = 0;
|
||||
|
||||
static int parseXelisAmount(String amount) {
|
||||
try {
|
||||
final decimalLength = _getDividerForInput(amount);
|
||||
_divider = decimalLength;
|
||||
return (double.parse(amount) * pow(10, decimalLength)).round();
|
||||
return (double.parse(amount) * pow(10, 8)).round();
|
||||
} catch (_) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -15,38 +11,44 @@ class XelisFormatter {
|
|||
|
||||
static double parseXelisAmountToDouble(int amount) {
|
||||
try {
|
||||
return amount / pow(10, _divider);
|
||||
return amount / pow(10, 8);
|
||||
} catch (_) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int _getDividerForInput(String amount) {
|
||||
final result = amount.split('.');
|
||||
if (result.length > 1) {
|
||||
final decimalLength = result[1].length;
|
||||
return decimalLength;
|
||||
} else {
|
||||
static int parseAmount(String amount, int decimals) {
|
||||
try {
|
||||
return (double.parse(amount) * pow(10, decimals)).round();
|
||||
} catch (_) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String formatXelisAmountWithSymbol(
|
||||
static double parseAmountToDouble(int amount, int decimals) {
|
||||
try {
|
||||
return amount / pow(10, decimals);
|
||||
} catch (_) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static String formatAmountWithSymbol(
|
||||
int rawAmount, {
|
||||
required int decimals,
|
||||
String? symbol,
|
||||
}) {
|
||||
}) {
|
||||
final formatted = rawAmount / pow(10, decimals);
|
||||
// final symbol = assetId == null || assetId == xelisAsset ? 'XEL' : assetId;
|
||||
final sym = symbol ?? 'XEL';
|
||||
return '$formatted $sym';
|
||||
}
|
||||
}
|
||||
|
||||
String formatXelisAmount(
|
||||
static String formatAmount(
|
||||
int rawAmount, {
|
||||
required int decimals,
|
||||
}) {
|
||||
}) {
|
||||
final formatted = rawAmount / pow(10, decimals);
|
||||
return '$formatted';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class XelisPendingTransaction with PendingTransaction {
|
|||
String get amountFormatted => amount.toString();
|
||||
|
||||
@override
|
||||
String get feeFormatted => formatXelisAmount(fee, decimals: 8);
|
||||
String get feeFormatted => XelisFormatter.formatAmount(fee, decimals: 8);
|
||||
|
||||
@override
|
||||
String get hex => "";
|
||||
|
|
|
@ -72,7 +72,7 @@ abstract class XelisTransactionHistoryBase
|
|||
final val = entry.value;
|
||||
|
||||
if (val is Map<String, dynamic>) {
|
||||
final tx = XelisTransactionInfo.fromJson(val);
|
||||
final tx = XelisTransactionInfo.fromJson(val, isAssetEnabled: (id) => true); // asset filtering needs to happen elsewhere before serializing
|
||||
addOne(tx);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:cw_xelis/xelis_formatting.dart';
|
|||
import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk;
|
||||
import 'package:cw_xelis/src/api/wallet.dart' as x_wallet;
|
||||
import 'package:cw_core/format_amount.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
|
@ -94,7 +95,7 @@ class XelisTransactionInfo extends TransactionInfo {
|
|||
|
||||
@override
|
||||
String feeFormatted() =>
|
||||
formatXelisAmountWithSymbol(fee, decimals: 8, symbol: 'XEL');
|
||||
XelisFormatter.formatAmountWithSymbol(fee, decimals: 8, symbol: 'XEL');
|
||||
|
||||
@override
|
||||
String fiatAmount() => _fiatAmount ?? '';
|
||||
|
@ -127,9 +128,7 @@ class XelisTransactionInfo extends TransactionInfo {
|
|||
|
||||
for (final transfer in txType.transfers) {
|
||||
final asset = transfer.asset;
|
||||
if (!isAssetEnabled(asset)) {
|
||||
continue;
|
||||
}
|
||||
if (!isAssetEnabled(asset)) continue;
|
||||
|
||||
assetAmounts[asset] = (assetAmounts[asset] ?? BigInt.zero) + BigInt.from(transfer.amount);
|
||||
|
||||
|
@ -144,43 +143,27 @@ class XelisTransactionInfo extends TransactionInfo {
|
|||
case xelis_sdk.OutgoingEntry():
|
||||
direction = TransactionDirection.outgoing;
|
||||
|
||||
List<XelisTransfer> localTransfers = [];
|
||||
final formattedTransfers = <String>[];
|
||||
|
||||
for (final transfer in txType.transfers) {
|
||||
final asset = transfer.asset;
|
||||
if (!isAssetEnabled(asset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
assetAmounts[asset] = (assetAmounts[asset] ?? BigInt.zero) + BigInt.from(transfer.amount);
|
||||
if (!isAssetEnabled(asset)) continue;
|
||||
|
||||
final meta = await wallet.getAssetMetadata(asset: asset);
|
||||
localTransfers.add(
|
||||
XelisTransfer(
|
||||
meta: meta,
|
||||
amount: transfer.amount
|
||||
)
|
||||
);
|
||||
final formatted = XelisTransfer(meta: meta, amount: transfer.amount).format();
|
||||
|
||||
assetDecimals[asset] = meta.decimals;
|
||||
assetSymbolsMap[asset] = meta.ticker;
|
||||
}
|
||||
assetAmounts[asset] = (assetAmounts[asset] ?? BigInt.zero) + BigInt.from(transfer.amount);
|
||||
|
||||
final formattedTransfers = txType.transfers
|
||||
.asMap()
|
||||
.entries
|
||||
.map((entry) {
|
||||
final index = entry.key;
|
||||
final t = entry.value;
|
||||
if (txType.transfers.length > 1) {
|
||||
return "${t.destination} ( ${localTransfers[index].format()} )";
|
||||
formattedTransfers.add("${transfer.destination} ( $formatted )");
|
||||
} else {
|
||||
formattedTransfers.add("${transfer.destination}");
|
||||
}
|
||||
}
|
||||
return "${t.destination}";
|
||||
})
|
||||
.where((transfer) => transfer.isNotEmpty)
|
||||
.toList();
|
||||
|
||||
to = formattedTransfers.join('\n\n');
|
||||
|
||||
fee = BigInt.from(txType.fee);
|
||||
break;
|
||||
|
||||
|
@ -248,12 +231,13 @@ class XelisTransactionInfo extends TransactionInfo {
|
|||
break;
|
||||
}
|
||||
|
||||
final assetIds = assetAmounts.keys.toList();
|
||||
final filteredAssetIds = assetAmounts.keys.where(isAssetEnabled).toList();
|
||||
final assetIds = filteredAssetIds;
|
||||
final assetSymbols = assetIds.map((id) => assetSymbolsMap[id] ?? '???').toList();
|
||||
final decimals = assetIds.map((id) => assetDecimals[id] ?? 8).toList();
|
||||
final amounts = assetIds.map((id) => assetAmounts[id]!).toList();
|
||||
|
||||
final xelAmount = amounts.isNotEmpty ? amounts[0] : BigInt.zero;
|
||||
final xelAmount = assetAmounts[xelis_sdk.xelisAsset] ?? BigInt.zero;
|
||||
|
||||
return XelisTransactionInfo(
|
||||
id: entry.hash,
|
||||
|
@ -271,20 +255,42 @@ class XelisTransactionInfo extends TransactionInfo {
|
|||
);
|
||||
}
|
||||
|
||||
factory XelisTransactionInfo.fromJson(Map<String, dynamic> data) {
|
||||
factory XelisTransactionInfo.fromJson(
|
||||
Map<String, dynamic> data, {
|
||||
required bool Function(String assetId) isAssetEnabled,
|
||||
}) {
|
||||
final allAssetIds = List<String>.from(data['assetIds']);
|
||||
final allAssetSymbols = List<String>.from(data['assetSymbols']);
|
||||
final allAssetAmounts = (data['assetAmounts'] as List)
|
||||
.map<BigInt>((val) => BigInt.parse(val.toString()))
|
||||
.toList();
|
||||
final allDecimals = List<int>.from(data['decimals']);
|
||||
|
||||
final filteredIndices = <int>[];
|
||||
for (int i = 0; i < allAssetIds.length; i++) {
|
||||
if (isAssetEnabled(allAssetIds[i])) {
|
||||
filteredIndices.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
final assetIds = filteredIndices.map((i) => allAssetIds[i]).toList();
|
||||
final assetSymbols = filteredIndices.map((i) => allAssetSymbols[i]).toList();
|
||||
final assetAmounts = filteredIndices.map((i) => allAssetAmounts[i]).toList();
|
||||
final decimals = filteredIndices.map((i) => allDecimals[i]).toList();
|
||||
|
||||
final xelAmount = assetAmounts.isNotEmpty ? assetAmounts[0] : BigInt.zero;
|
||||
|
||||
return XelisTransactionInfo(
|
||||
id: data['id'] as String,
|
||||
height: data['height'] as int,
|
||||
decimals: List<int>.from(data['decimals']),
|
||||
assetAmounts: (data['assetAmounts'] as List)
|
||||
.map<BigInt>((val) => BigInt.parse(val.toString()))
|
||||
.toList(),
|
||||
xelAmount: BigInt.parse(data['xelAmount']),
|
||||
decimals: decimals,
|
||||
assetAmounts: assetAmounts,
|
||||
xelAmount: xelAmount,
|
||||
xelFee: BigInt.parse(data['xelFee']),
|
||||
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
||||
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
||||
assetSymbols: List<String>.from(data['assetSymbols']),
|
||||
assetIds: List<String>.from(data['assetIds']),
|
||||
assetSymbols: assetSymbols,
|
||||
assetIds: assetIds,
|
||||
to: data['to'],
|
||||
from: data['from'],
|
||||
);
|
||||
|
|
|
@ -18,6 +18,7 @@ import 'package:cw_core/node.dart';
|
|||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
|
||||
import 'package:cw_xelis/xelis_formatting.dart';
|
||||
import 'package:cw_xelis/xelis_exception.dart';
|
||||
import 'package:cw_xelis/xelis_asset_balance.dart';
|
||||
import 'package:cw_xelis/src/api/wallet.dart' as x_wallet;
|
||||
|
@ -342,28 +343,74 @@ abstract class XelisWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
@action
|
||||
Future<void> rescan({required int height}) async {
|
||||
walletInfo.restoreHeight = height;
|
||||
walletInfo.isRecovery = true;
|
||||
syncStatus = AttemptingSyncStatus();
|
||||
balance.clear();
|
||||
|
||||
final curr = isTestnet ? CryptoCurrency.xet : CryptoCurrency.xel;
|
||||
balance[curr] = XelisAssetBalance.zero(symbol: isTestnet ? "XET" : "XEL");
|
||||
|
||||
await _libWallet.rescan(topoheight: BigInt.from(pruneHeight > height ? pruneHeight : height));
|
||||
await walletInfo.save();
|
||||
await connectToNode(node: currentNode!);
|
||||
syncStatus = SyncedSyncStatus();
|
||||
}
|
||||
|
||||
List<XelisTransactionInfo> _txBuffer = [];
|
||||
Timer? _txBatchTimer;
|
||||
Timer? _txSaveDebounceTimer;
|
||||
|
||||
void _bufferTransaction(XelisTransactionInfo tx) {
|
||||
_txBuffer.add(tx);
|
||||
|
||||
if (_txBatchTimer == null || !_txBatchTimer!.isActive) {
|
||||
_txBatchTimer = Timer(Duration(seconds: 1), () async {
|
||||
final buffered = List<XelisTransactionInfo>.from(_txBuffer);
|
||||
_txBuffer.clear();
|
||||
_txBatchTimer = null;
|
||||
|
||||
final txMap = {
|
||||
for (var tx in buffered) tx.id: tx
|
||||
};
|
||||
transactionHistory.addMany(txMap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _flushTransactionBuffer() async {
|
||||
if (_txBuffer.isEmpty) return;
|
||||
|
||||
final toAdd = Map.fromEntries(_txBuffer.map((tx) => MapEntry(tx.id, tx)));
|
||||
|
||||
runInAction(() {
|
||||
transactionHistory.addMany(toAdd);
|
||||
});
|
||||
|
||||
_txBuffer.clear();
|
||||
_txBatchTimer = null;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> _handleEvent(Event event) async {
|
||||
switch (event) {
|
||||
case NewTransaction():
|
||||
if (!isSupportedEntryType(event.tx)) { break; }
|
||||
if (!isSupportedEntryType(event.tx)) break;
|
||||
|
||||
final transactionInfo = await XelisTransactionInfo.fromTransactionEntry(
|
||||
event.tx,
|
||||
wallet: _libWallet,
|
||||
isAssetEnabled: (id) => findTrackedAssetById(id)?.enabled ?? id == xelis_sdk.xelisAsset
|
||||
);
|
||||
transactionHistory.addOne(transactionInfo);
|
||||
_bufferTransaction(transactionInfo);
|
||||
|
||||
_txSaveDebounceTimer?.cancel();
|
||||
_txSaveDebounceTimer = Timer(Duration(seconds: 1), () async {
|
||||
await _flushTransactionBuffer();
|
||||
await transactionHistory.save();
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case BalanceChanged():
|
||||
|
@ -452,6 +499,7 @@ abstract class XelisWalletBase
|
|||
// _lastSyncError = event.message;
|
||||
break;
|
||||
}
|
||||
await Future.delayed(Duration.zero);
|
||||
}
|
||||
|
||||
Future<void> _fetchPruneHeight() async {
|
||||
|
@ -880,7 +928,7 @@ abstract class XelisWalletBase
|
|||
|
||||
return XelisPendingTransaction(
|
||||
txid: txHash,
|
||||
amount: totalAmountFromCredentials.toString(),
|
||||
amount: XelisFormatter.formatAmount(totalAmountFromCredentials, decimals: balance[transactionCurrency]!.decimals),
|
||||
fee: txMap['fee'],
|
||||
decimals: balance[transactionCurrency]!.decimals,
|
||||
send: send
|
||||
|
@ -906,9 +954,7 @@ abstract class XelisWalletBase
|
|||
}
|
||||
|
||||
final txList = (await _libWallet.allHistory())
|
||||
.map((jsonStr) => xelis_sdk.TransactionEntry.fromJson(
|
||||
json.decode(jsonStr),
|
||||
) as xelis_sdk.TransactionEntry)
|
||||
.map((jsonStr) => xelis_sdk.TransactionEntry.fromJson(json.decode(jsonStr)) as xelis_sdk.TransactionEntry)
|
||||
.toList();
|
||||
|
||||
final Map<String, XelisTransactionInfo> result = {};
|
||||
|
@ -980,6 +1026,8 @@ abstract class XelisWalletBase
|
|||
}
|
||||
requestedClose = true;
|
||||
_isTransactionUpdating = false;
|
||||
_txSaveDebounceTimer?.cancel();
|
||||
_txBatchTimer?.cancel();
|
||||
await _unsubscribeFromWalletEvents();
|
||||
await _libWallet.close();
|
||||
x_wallet.dropWallet(wallet: _libWallet);
|
||||
|
|
|
@ -118,7 +118,7 @@ abstract class OutputBase with Store {
|
|||
_amount = zano!.formatterParseAmount(amount: _cryptoAmount, currency: cryptoCurrencyHandler());
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
_amount = xelis!.formatterStringDoubleToXelisAmount(_cryptoAmount);
|
||||
_amount = xelis!.formatterStringDoubleToAmount(_cryptoAmount, currency: cryptoCurrencyHandler());
|
||||
break;
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
|
|
|
@ -110,7 +110,10 @@ class CWXelis extends Xelis {
|
|||
);
|
||||
|
||||
@override
|
||||
int formatterStringDoubleToXelisAmount(String amount) => XelisFormatter.parseXelisAmount(amount);
|
||||
int formatterStringDoubleToAmount(String amount, {required CryptoCurrency currency}) {
|
||||
if (currency is XelisAsset) return XelisFormatter.parseAmount(amount, currency.decimals);
|
||||
return XelisFormatter.parseXelisAmount(amount);
|
||||
}
|
||||
|
||||
@override
|
||||
double formatterXelisAmountToDouble(
|
||||
|
|
|
@ -1451,7 +1451,7 @@ abstract class Xelis {
|
|||
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);
|
||||
|
||||
double formatterXelisAmountToDouble({TransactionInfo? transaction, BigInt? amount, int decimals = 8});
|
||||
int formatterStringDoubleToXelisAmount(String amount);
|
||||
int formatterStringDoubleToAmount(String amount, {required CryptoCurrency currency});
|
||||
|
||||
// CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);
|
||||
double? getEstimateFees(WalletBase wallet);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue