fix: correct date (#2367)

rafael_xmr committed Jul 10, 2025 at 10:06 UTC 15491e8c61ffb6bc399d5f31546e72e002571ca7
1 file changed +46 -205
cw_bitcoin/lib/electrum_wallet.dart
+46 -205
@@ -370,6 +370,7 @@ abstract class ElectrumWalletBase
370 existingTxInfo.amount = tx.amount;
371 existingTxInfo.confirmations = tx.confirmations;
372 existingTxInfo.height = tx.height;
373 + existingTxInfo.date = tx.date;
374
375 final newUnspents = tx.unspents!
376 .where((unspent) => !(existingTxInfo.unspents?.any((element) =>
@@ -1879,20 +1880,24 @@ abstract class ElectrumWalletBase
1880
1881 if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
1882 try {
1882 - final blockHash = await ProxyWrapper().get(
1883 - clearnetUri: Uri.parse(
1884 - "https://mempool.cakewallet.com/api/v1/block-height/$height",
1885 - ),
1886 - ).timeout(Duration(seconds: 15));
1883 + final blockHash = await ProxyWrapper()
1884 + .get(
1885 + clearnetUri: Uri.parse(
1886 + "https://mempool.cakewallet.com/api/v1/block-height/$height",
1887 + ),
1888 + )
1889 + .timeout(Duration(seconds: 15));
1890
1891 if (blockHash.statusCode == 200 &&
1892 blockHash.body.isNotEmpty &&
1893 jsonDecode(blockHash.body) != null) {
1891 - final blockResponse = await ProxyWrapper().get(
1892 - clearnetUri: Uri.parse(
1893 - "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
1894 - ),
1895 - ).timeout(Duration(seconds: 15));
1894 + final blockResponse = await ProxyWrapper()
1895 + .get(
1896 + clearnetUri: Uri.parse(
1897 + "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
1898 + ),
1899 + )
1900 + .timeout(Duration(seconds: 15));
1901 if (blockResponse.statusCode == 200 &&
1902 blockResponse.body.isNotEmpty &&
1903 jsonDecode(blockResponse.body)['timestamp'] != null) {
@@ -2614,7 +2619,7 @@ Future<void> _handleScanSilentPayments(ScanData scanData) async {
2619
2620 var _scanningStream = await scanningClient.subscribe(req);
2621
2617 - void listenFn(Map<String, dynamic> event, ElectrumTweaksSubscribe req) {
2622 + void listenFn(Map<String, dynamic> event, ElectrumTweaksSubscribe req) async {
2623 final response = req.onResponse(event);
2624
2625 if (response == null || _scanningStream == null) {
@@ -2695,6 +2700,35 @@ Future<void> _handleScanSilentPayments(ScanData scanData) async {
2700 continue;
2701 }
2702
2703 + var txDate = DateTime.now();
2704 + bool isDateNow = true;
2705 +
2706 + final tweakBlockHash = await ProxyWrapper()
2707 + .get(
2708 + clearnetUri: Uri.parse(
2709 + "https://mempool.cakewallet.com/api/v1/block-height/$tweakHeight",
2710 + ),
2711 + )
2712 + .timeout(Duration(seconds: 15));
2713 + final blockResponse = await ProxyWrapper()
2714 + .get(
2715 + clearnetUri: Uri.parse(
2716 + "https://mempool.cakewallet.com/api/v1/block/${tweakBlockHash.body}",
2717 + ),
2718 + )
2719 + .timeout(Duration(seconds: 15));
2720 +
2721 + if (blockResponse.statusCode == 200 &&
2722 + blockResponse.body.isNotEmpty &&
2723 + jsonDecode(blockResponse.body)['timestamp'] != null) {
2724 + try {
2725 + txDate = DateTime.fromMillisecondsSinceEpoch(
2726 + int.parse(jsonDecode(blockResponse.body)['timestamp'].toString()) * 1000,
2727 + );
2728 + isDateNow = false;
2729 + } catch (_) {}
2730 + }
2731 +
2732 // initial placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s) on the following loop
2733 final txInfo = ElectrumTransactionInfo(
2734 WalletType.bitcoin,
@@ -2706,7 +2740,7 @@ Future<void> _handleScanSilentPayments(ScanData scanData) async {
2740 isReplaced: false,
2741 // TODO: fetch block data and get the date from it
2742 date: scanData.network == BitcoinNetwork.mainnet
2709 - ? getDateByBitcoinHeight(tweakHeight)
2743 + ? (isDateNow ? getDateByBitcoinHeight(tweakHeight) : txDate)
2744 : DateTime.now(),
2745 confirmations: scanData.chainTip - tweakHeight + 1,
2746 isReceivedSilentPayment: true,
@@ -2803,199 +2837,6 @@ Future<void> _handleScanSilentPayments(ScanData scanData) async {
2837 }
2838 }
2839
2806 -Future<void> startRefresh(ScanData scanData) async {
2807 - int syncHeight = scanData.height;
2808 - int initialSyncHeight = syncHeight;
2809 -
2810 - BehaviorSubject<Object>? tweaksSubscription = null;
2811 -
2812 - final electrumClient = scanData.electrumClient;
2813 - await electrumClient.connectToUri(
2814 - scanData.node?.uri ?? Uri.parse("tcp://electrs.cakewallet.com:50001"),
2815 - useSSL: scanData.node?.useSSL ?? false,
2816 - );
2817 -
2818 - int getCountToScanPerRequest(int syncHeight) {
2819 - if (scanData.isSingleScan) {
2820 - return 1;
2821 - }
2822 -
2823 - final amountLeft = scanData.chainTip - syncHeight + 1;
2824 - return amountLeft;
2825 - }
2826 -
2827 - if (tweaksSubscription == null) {
2828 - final receiver = Receiver(
2829 - scanData.silentAddress.b_scan.toHex(),
2830 - scanData.silentAddress.B_spend.toHex(),
2831 - scanData.network == BitcoinNetwork.testnet,
2832 - scanData.labelIndexes,
2833 - scanData.labelIndexes.length,
2834 - );
2835 -
2836 - // Initial status UI update, send how many blocks in total to scan
2837 - final initialCount = getCountToScanPerRequest(syncHeight);
2838 - scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight)));
2839 -
2840 - tweaksSubscription = await electrumClient.tweaksSubscribe(
2841 - height: syncHeight,
2842 - count: initialCount,
2843 - );
2844 -
2845 - Future<void> listenFn(t) async {
2846 - final tweaks = t as Map<String, dynamic>;
2847 - final msg = tweaks["message"];
2848 -
2849 - // is success or error msg
2850 - final noData = msg != null;
2851 -
2852 - if (noData) {
2853 - if (scanData.isSingleScan) {
2854 - return;
2855 - }
2856 -
2857 - // re-subscribe to continue receiving messages, starting from the next unscanned height
2858 - final nextHeight = syncHeight + 1;
2859 -
2860 - if (nextHeight <= scanData.chainTip) {
2861 - final nextStream = electrumClient.tweaksSubscribe(
2862 - height: nextHeight,
2863 - count: getCountToScanPerRequest(nextHeight),
2864 - );
2865 - nextStream?.listen(listenFn);
2866 - }
2867 -
2868 - return;
2869 - }
2870 -
2871 - // Continuous status UI update, send how many blocks left to scan
2872 - final syncingStatus = scanData.isSingleScan
2873 - ? SyncingSyncStatus(1, 0)
2874 - : SyncingSyncStatus.fromHeightValues(scanData.chainTip, initialSyncHeight, syncHeight);
2875 - scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
2876 -
2877 - final blockHeight = tweaks.keys.first;
2878 - final tweakHeight = int.parse(blockHeight);
2879 -
2880 - try {
2881 - final blockTweaks = tweaks[blockHeight] as Map<String, dynamic>;
2882 -
2883 - for (var j = 0; j < blockTweaks.keys.length; j++) {
2884 - final txid = blockTweaks.keys.elementAt(j);
2885 - final details = blockTweaks[txid] as Map<String, dynamic>;
2886 - final outputPubkeys = (details["output_pubkeys"] as Map<dynamic, dynamic>);
2887 - final tweak = details["tweak"].toString();
2888 -
2889 - try {
2890 - // scanOutputs called from rust here
2891 - final addToWallet = scanOutputs(
2892 - outputPubkeys.values.toList(),
2893 - tweak,
2894 - receiver,
2895 - );
2896 -
2897 - if (addToWallet.isEmpty) {
2898 - // no results tx, continue to next tx
2899 - continue;
2900 - }
2901 -
2902 - // placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s)
2903 - final txInfo = ElectrumTransactionInfo(
2904 - WalletType.bitcoin,
2905 - id: txid,
2906 - height: tweakHeight,
2907 - amount: 0,
2908 - fee: 0,
2909 - direction: TransactionDirection.incoming,
2910 - isPending: false,
2911 - isReplaced: false,
2912 - date: scanData.network == BitcoinNetwork.mainnet
2913 - ? getDateByBitcoinHeight(tweakHeight)
2914 - : DateTime.now(),
2915 - confirmations: scanData.chainTip - tweakHeight + 1,
2916 - unspents: [],
2917 - isReceivedSilentPayment: true,
2918 - );
2919 -
2920 - addToWallet.forEach((label, value) {
2921 - (value as Map<String, dynamic>).forEach((output, tweak) {
2922 - final t_k = tweak.toString();
2923 -
2924 - final receivingOutputAddress = ECPublic.fromHex(output)
2925 - .toTaprootAddress(tweak: false)
2926 - .toAddress(scanData.network);
2927 -
2928 - int? amount;
2929 - int? pos;
2930 - outputPubkeys.entries.firstWhere((k) {
2931 - final isMatchingOutput = k.value[0] == output;
2932 - if (isMatchingOutput) {
2933 - amount = int.parse(k.value[1].toString());
2934 - pos = int.parse(k.key.toString());
2935 - return true;
2936 - }
2937 - return false;
2938 - });
2939 -
2940 - final receivedAddressRecord = BitcoinSilentPaymentAddressRecord(
2941 - receivingOutputAddress,
2942 - index: 0,
2943 - isHidden: false,
2944 - isUsed: true,
2945 - network: scanData.network,
2946 - silentPaymentTweak: t_k,
2947 - type: SegwitAddresType.p2tr,
2948 - txCount: 1,
2949 - balance: amount!,
2950 - );
2951 -
2952 - final unspent = BitcoinSilentPaymentsUnspent(
2953 - receivedAddressRecord,
2954 - txid,
2955 - amount!,
2956 - pos!,
2957 - silentPaymentTweak: t_k,
2958 - silentPaymentLabel: label == "None" ? null : label,
2959 - );
2960 -
2961 - txInfo.unspents!.add(unspent);
2962 - txInfo.amount += unspent.value;
2963 - });
2964 - });
2965 -
2966 - scanData.sendPort.send({txInfo.id: txInfo});
2967 - } catch (_) {}
2968 - }
2969 - } catch (_) {}
2970 -
2971 - syncHeight = tweakHeight;
2972 -
2973 - if (tweakHeight >= scanData.chainTip || scanData.isSingleScan) {
2974 - if (tweakHeight >= scanData.chainTip)
2975 - scanData.sendPort.send(SyncResponse(
2976 - syncHeight,
2977 - SyncedTipSyncStatus(scanData.chainTip),
2978 - ));
2979 -
2980 - if (scanData.isSingleScan) {
2981 - scanData.sendPort.send(SyncResponse(syncHeight, SyncedSyncStatus()));
2982 - }
2983 -
2984 - await tweaksSubscription!.close();
2985 - await electrumClient.close();
2986 - }
2987 - }
2988 -
2989 - tweaksSubscription?.listen(listenFn);
2990 - }
2991 -
2992 - if (tweaksSubscription == null) {
2993 - return scanData.sendPort.send(
2994 - SyncResponse(syncHeight, UnsupportedSyncStatus()),
2995 - );
2996 - }
2997 -}
2998 -
2840 class EstimatedTxResult {
2841 EstimatedTxResult({
2842 required this.utxos,