From 7fd35f2d225a458a3ca05b5283ec2ceed4b38e96 Mon Sep 17 00:00:00 2001 From: bracr10 Date: Mon, 23 Feb 2026 20:55:58 -0600 Subject: [PATCH 1/2] Adds initiator to restored dispute data Adds the 'initiator' field to the `RestoredDispute` model to indicate which party initiated the dispute, simplifying the dispute initiation detection logic and removing the need for trade index comparison. --- lib/data/models/restore_response.dart | 6 +- lib/features/restore/restore_manager.dart | 67 +++-------------------- 2 files changed, 13 insertions(+), 60 deletions(-) diff --git a/lib/data/models/restore_response.dart b/lib/data/models/restore_response.dart index 3fad332b..e62421b8 100644 --- a/lib/data/models/restore_response.dart +++ b/lib/data/models/restore_response.dart @@ -65,12 +65,14 @@ class RestoredDispute { final String orderId; final int tradeIndex; final String status; + final String? initiator; RestoredDispute({ required this.disputeId, required this.orderId, required this.tradeIndex, required this.status, + this.initiator, }); factory RestoredDispute.fromJson(Map json) { @@ -79,6 +81,7 @@ class RestoredDispute { orderId: json['order_id'] as String, tradeIndex: json['trade_index'] as int, status: json['status'] as String, + initiator: json['initiator'] as String?, ); } @@ -87,5 +90,6 @@ class RestoredDispute { 'order_id': orderId, 'trade_index': tradeIndex, 'status': status, + if (initiator != null) 'initiator': initiator, }; -} \ No newline at end of file +} diff --git a/lib/features/restore/restore_manager.dart b/lib/features/restore/restore_manager.dart index 2f859f53..41bcf662 100644 --- a/lib/features/restore/restore_manager.dart +++ b/lib/features/restore/restore_manager.dart @@ -400,47 +400,6 @@ class RestoreService { } } - /// Determines if the user initiated the dispute with double verification - /// - /// Security checks: - /// 1. Verify session belongs to this order (compare pubkeys based on role) - /// 2. Compare trade_index to determine who initiated the dispute - /// - /// The dispute's trade_index indicates which party initiated it. - /// If it matches the user's session trade_index, the user initiated the dispute. - bool _determineIfUserInitiatedDispute({ - required RestoredDispute restoredDispute, - required Session session, - required Order order, - }) { - // Security verification: ensure session's trade pubkey matches order's pubkey for the role - final sessionPubkey = session.tradeKey.public; - final sessionRole = session.role; - - bool sessionMatchesOrder = false; - if (sessionRole == Role.buyer && order.buyerTradePubkey == sessionPubkey) { - sessionMatchesOrder = true; - } else if (sessionRole == Role.seller && - order.sellerTradePubkey == sessionPubkey) { - sessionMatchesOrder = true; - } - - if (!sessionMatchesOrder) { - logger.w('Restore: session pubkey mismatch for order ${order.id} - ' - 'session role: $sessionRole, session pubkey: $sessionPubkey, ' - 'buyer pubkey: ${order.buyerTradePubkey}, seller pubkey: ${order.sellerTradePubkey}'); - // Default to peer-initiated if we can't verify session belongs to order - return false; - } - - // Compare trade indexes: if dispute trade_index matches user's session trade_index, - // then the user initiated the dispute - final userInitiated = restoredDispute.tradeIndex == session.keyIndex; - - //TODO: Improve dispute initiation detection if protocol changes in future - return userInitiated; - } - /// Maps Status to the appropriate Action for restored orders Action _getActionFromStatus(Status status, Role? userRole) { switch (status) { @@ -627,24 +586,14 @@ class RestoreService { .read(sessionNotifierProvider.notifier) .getSessionByOrderId(orderDetail.id); - // We need the session to compare trade indexes - bool userInitiated = false; - if (session == null) { - logger.w( - 'Restore: no session found for disputed order ${orderDetail.id}, defaulting to peer-initiated'); - action = Action.disputeInitiatedByPeer; - } else { - // Determine if user initiated with double verification TODO : improve if protocol changes - userInitiated = _determineIfUserInitiatedDispute( - restoredDispute: restoredDispute, - session: session, - order: order, - ); - - action = userInitiated - ? Action.disputeInitiatedByYou - : Action.disputeInitiatedByPeer; - } + final userInitiated = restoredDispute.initiator != null && session?.role != null + ? (session!.role == Role.buyer && restoredDispute.initiator == 'buyer') || + (session.role == Role.seller && restoredDispute.initiator == 'seller') + : false; + + action = userInitiated + ? Action.disputeInitiatedByYou + : Action.disputeInitiatedByPeer; // Create Dispute object dispute = Dispute( From 2b70163a8bd24b4445969ec70d46e474f77ee7c9 Mon Sep 17 00:00:00 2001 From: bracr10 Date: Mon, 23 Feb 2026 22:00:43 -0600 Subject: [PATCH 2/2] Normalizes dispute initiator value Normalizes the `initiator` field in the `RestoredDispute` model to ensure consistency. It trims whitespace and converts the value to lowercase before validation. If the normalized value is 'buyer' or 'seller', it's returned; otherwise, it returns null. This prevents issues caused by inconsistent initiator naming when restoring disputes. --- lib/data/models/restore_response.dart | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/data/models/restore_response.dart b/lib/data/models/restore_response.dart index e62421b8..70cbe0a6 100644 --- a/lib/data/models/restore_response.dart +++ b/lib/data/models/restore_response.dart @@ -76,15 +76,29 @@ class RestoredDispute { }); factory RestoredDispute.fromJson(Map json) { + final rawInitiator = json['initiator'] as String?; + final normalizedInitiator = _normalizeInitiator(rawInitiator); + return RestoredDispute( disputeId: json['dispute_id'] as String, orderId: json['order_id'] as String, tradeIndex: json['trade_index'] as int, status: json['status'] as String, - initiator: json['initiator'] as String?, + initiator: normalizedInitiator, ); } + static String? _normalizeInitiator(String? value) { + if (value == null) return null; + + final normalized = value.trim().toLowerCase(); + if (normalized == 'buyer' || normalized == 'seller') { + return normalized; + } + + return null; + } + Map toJson() => { 'dispute_id': disputeId, 'order_id': orderId,