import 'package:basic_utils/basic_utils.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/utils/print_verbose.dart'; class Bip353Record { Bip353Record({ required this.uri, required this.domain, }); final String uri; final String domain; static const Map keyDisplayMap = { 'lno': 'BOLT 12 Offer', 'sp': 'Silent Payment', 'address': 'On-Chain Address', }; static Future?> fetchUriByCryptoCurrency( String bip353Name, String asset) async { try { // 1. Parse the user and domain from "user@domain" final parts = bip353Name.split('@'); if (parts.length != 2) return null; final userPart = parts[0]; final domainPart = parts[1]; // 2. Construct the correct subdomain: "user._bitcoin-payment.domain" final bip353Domain = '$userPart.user._bitcoin-payment.$domainPart'; // 3. Lookup the TXT record with DNSSEC final txtRecords = await DnsUtils.lookupRecord( bip353Domain, RRecordType.TXT, dnssec: true, ); if (txtRecords == null) return null; final assetName = CryptoCurrency.fromString(asset).fullName; if (assetName == null) throw Exception('Invalid asset name'); final formattedAssetName = assetName.toLowerCase().replaceAll(' ', '') + ':'; for (final record in txtRecords) { final data = record.data.replaceAll('"', ''); if (data.startsWith(formattedAssetName)) { return _parseAssetUri(data, formattedAssetName); } } } catch (e) { printV('BIP353Record.fetchBitcoinUri error: $e'); } return null; } static Map? _parseAssetUri(String fullUri, String prefix) { final afterPrefix = fullUri.substring(prefix.length); if (afterPrefix.isEmpty) return null; final questionIndex = afterPrefix.indexOf('?'); if (questionIndex == -1) { return {'address': afterPrefix}; } else { final addressPart = afterPrefix.substring(0, questionIndex); final queryPart = afterPrefix.substring(questionIndex + 1); final result = {}; if (addressPart.isNotEmpty) result['address'] = addressPart; final queryMap = Uri.splitQueryString(queryPart); result.addAll(queryMap); return result; } } }