379
topic: topic,
380
response: response,
381
);
382
+
383
+ if (session == null) return;
384
+
385
MethodsUtils.handleRedirect(
386
topic,
384
- session!.peer.metadata.redirect,
387
+ session.peer.metadata.redirect,
388
response.error?.message,
389
response.error == null,
390
);
391
} on ReownSignError catch (error) {
392
+ if (session == null) return;
393
+
394
MethodsUtils.handleRedirect(
395
topic,
391
- session!.peer.metadata.redirect,
396
+ session.peer.metadata.redirect,
397
error.message,
398
);
399
}
494
final typedData = jsonDecode(data[1] as String) as Map<String, dynamic>;
495
496
// Extracting domain details.
492
- final domain = typedData['domain'] ?? {} as Map<String, dynamic>;
497
+ final domain = typedData['domain'] as Map<String, dynamic>? ?? {};
498
final domainName = domain['name']?.toString() ?? '';
494
- final verifyingContract = domain['verifyingContract']?.toString() ?? '';
495
-
499
+ final version = domain['version']?.toString() ?? '';
500
final chainId = domain['chainId']?.toString() ?? '';
497
- final chainName = getChainNameBasedOnWalletType(appStore.wallet!.type);
501
+ final verifyingContract = domain['verifyingContract']?.toString() ?? '';
502
499
- // Get the primary type.
503
+ // Get the primary type and types
504
final primaryType = typedData['primaryType']?.toString() ?? '';
505
+ final types = typedData['types'] as Map<String, dynamic>? ?? {};
506
+ final message = typedData['message'] as Map<String, dynamic>? ?? {};
507
+
508
+ // Build a readable message based on the primary type and its structure
509
+ String messageDetails = '';
510
+
511
+ if (types.containsKey(primaryType)) {
512
+ final typeFields = types[primaryType] as List<dynamic>;
513
+ messageDetails = _formatMessageFields(message, typeFields, types);
514
+ } else {
515
+ // For unknown types, show the raw message
516
+ messageDetails = message.toString();
517
+ }
518
502
- // Extracting message details.
503
- final message = typedData['message'] ?? {} as Map<String, dynamic>;
504
- final details = message['details'] ?? {} as Map<String, dynamic>;
505
- final amount = details['amount']?.toString() ?? '';
506
- final expirationRaw = details['expiration']?.toString() ?? '';
507
- final nonce = details['nonce']?.toString() ?? '';
508
-
509
- final tokenAddress = details['token']?.toString() ?? '';
510
- final token = await getTokenDetails(tokenAddress, chainName);
511
-
512
- final spender = message['spender']?.toString() ?? '';
513
- final sigDeadlineRaw = message['sigDeadline']?.toString() ?? '';
519
+ return '''Domain Name: $domainName
520
+Version: $version
521
+Chain ID: $chainId
522
+Verifying Contract: $verifyingContract
523
+Primary Type: $primaryType\n
524
+Message:
525
+$messageDetails''';
526
+ }
527
+ return 'Invalid typed data format';
528
+ }
529
515
- // Converting expiration and sigDeadline from Unix time (seconds) to DateTime.
516
- DateTime? expirationDate;
517
- DateTime? sigDeadlineDate;
518
- try {
519
- if (expirationRaw.isNotEmpty) {
520
- final int expirationInt = int.parse(expirationRaw);
521
- expirationDate = DateTime.fromMillisecondsSinceEpoch(expirationInt * 1000);
530
+ String _formatMessageFields(
531
+ Map<String, dynamic> message, List<dynamic> fields, Map<String, dynamic> types) {
532
+ final buffer = StringBuffer();
533
+
534
+ for (var field in fields) {
535
+ final fieldName = _toCamelCase(field['name'] as String);
536
+ final fieldType = field['type'] as String;
537
+ final value = message[field['name'] as String];
538
+
539
+ if (value == null) continue;
540
+
541
+ if (types.containsKey(fieldType)) {
542
+ // Handle nested types
543
+ final nestedFields = types[fieldType] as List<dynamic>;
544
+ if (fieldType == 'Person') {
545
+ // Special formatting for Person type
546
+ final name = value['name'] as String;
547
+ final wallet = value['wallet'] as String;
548
+ buffer.writeln('$fieldName: $name ($wallet)');
549
+ } else {
550
+ // For other nested types, format each field
551
+ final formattedValue =
552
+ _formatMessageFields(value as Map<String, dynamic>, nestedFields, types);
553
+ buffer.writeln('$fieldName: $formattedValue');
554
}
523
- if (sigDeadlineRaw.isNotEmpty) {
524
- final int sigDeadlineInt = int.parse(sigDeadlineRaw);
525
- sigDeadlineDate = DateTime.fromMillisecondsSinceEpoch(sigDeadlineInt * 1000);
526
- }
527
- } catch (e) {
528
- // Parsing failed; we leave dates as null.
555
+ } else {
556
+ // Handle primitive types
557
+ buffer.writeln('$fieldName: $value');
558
}
559
+ }
560
531
- final permitData = {
532
- 'domainName': domainName,
533
- 'chainId': chainId,
534
- 'verifyingContract': verifyingContract,
535
- 'primaryType': primaryType,
536
- 'token': token,
537
- 'amount': amount,
538
- 'expiration': expirationDate,
539
- 'nonce': nonce,
540
- 'spender': spender,
541
- 'sigDeadline': sigDeadlineDate,
542
- };
561
+ return buffer.toString();
562
+ }
563
544
- return 'Domain: ${permitData['domainName']}'
545
- 'Chain ID: ${permitData['chainId']}'
546
- 'Verifying Contract: ${permitData['verifyingContract']}'
547
- 'Primary Type: ${permitData['primaryType']}'
548
- 'Token: ${permitData['token']}'
549
- 'Expiration: ${permitData['expiration'] != null ? permitData['expiration'] : 'N/A'}'
550
- 'Spender: ${permitData['spender']}'
551
- 'Signature Deadline: ${permitData['sigDeadline'] != null ? permitData['sigDeadline'] : 'N/A'}';
552
- }
553
- return '';
564
+ String _toCamelCase(String input) {
565
+ if (input.isEmpty) return input;
566
+ return input[0].toUpperCase() + input.substring(1).toLowerCase();
567
}
568
569
Future<String> getTokenDetails(String contractAddress, String chainName) async {