/// 提现支持币种 — POST uc/withdraw/support/coin/info class SupportCoinInfo { final String unit; final String? aliasName; final String? nameCn; final String? name; final String? balance; final String minWithdrawAmount; final String? minAmount; final String? minTransferAmount; final String? withdrawFeeValue; final String? fee; const SupportCoinInfo({ required this.unit, this.aliasName, this.nameCn, this.name, this.balance, this.minWithdrawAmount = '0', this.minAmount, this.minTransferAmount, this.withdrawFeeValue, this.fee, }); factory SupportCoinInfo.fromJson(Map json) { return SupportCoinInfo( unit: json['unit']?.toString() ?? '', aliasName: json['aliasName']?.toString(), nameCn: json['nameCn']?.toString(), name: json['name']?.toString(), balance: json['balance']?.toString(), minWithdrawAmount: json['minWithdrawAmount']?.toString() ?? '0', minAmount: json['minAmount']?.toString(), minTransferAmount: json['minTransferAmount']?.toString(), withdrawFeeValue: json['withdrawFeeValue']?.toString(), fee: json['fee']?.toString(), ); } } /// 提币主网 — GET uc/coin-network/withdraw-networks class WithdrawNetworkItem { final int id; final String name; final String protocol; final int sort; const WithdrawNetworkItem({ required this.id, required this.name, required this.protocol, this.sort = 0, }); factory WithdrawNetworkItem.fromJson(Map json) { return WithdrawNetworkItem( id: int.tryParse(json['id']?.toString() ?? '') ?? 0, name: json['name']?.toString() ?? '', protocol: json['protocol']?.toString() ?? '', sort: int.tryParse(json['sort']?.toString() ?? '') ?? 0, ); } } /// 可提/可转币种选项(链上子币或内部转账主币) class WithdrawCoinOption { final String unit; final String displayName; final String networkLabel; final int? networkId; final String balance; final String minWithdraw; final String minTransfer; final String withdrawFee; final bool isUsdtFamily; final bool isMainCoin; const WithdrawCoinOption({ required this.unit, required this.displayName, this.networkLabel = '', this.networkId, this.balance = '0', this.minWithdraw = '0', this.minTransfer = '0', this.withdrawFee = '0', this.isUsdtFamily = false, this.isMainCoin = false, }); } String firstNonEmptyStr(List vals) { for (final v in vals) { if (v == null) { continue; } final s = v.toString().trim(); if (s.isNotEmpty) { return s; } } return ''; } bool isUsdtFamilyUnit(String unit) { final u = unit.toUpperCase(); return u == 'USDT' || u == 'EUSDT' || u == 'TUSDT' || u.contains('BEP20'); } Map supportInfoByUnit(List list) { final map = {}; for (final c in list) { final u = c.unit.toLowerCase(); if (u.isNotEmpty) { map[u] = c; } } return map; } WithdrawCoinOption mapTransferParent( Map row, Map supportMap, ) { final unit = firstNonEmptyStr([row['unit']]).toLowerCase(); final name = row['name']?.toString() ?? ''; final support = supportMap[unit] ?? supportMap[name.toLowerCase()]; final minFromCoin = firstNonEmptyStr([row['minWithdrawAmount']]); final minFromSupport = firstNonEmptyStr([ support?.minAmount, support?.minWithdrawAmount, support?.minTransferAmount, ]); return WithdrawCoinOption( unit: unit, displayName: firstNonEmptyStr([ row['nameCn'], support?.nameCn, support?.aliasName, name, ]).isNotEmpty ? firstNonEmptyStr([ row['nameCn'], support?.nameCn, support?.aliasName, name, ]) : unit.toUpperCase(), balance: firstNonEmptyStr([support?.balance, '0']), minWithdraw: minFromSupport.isNotEmpty ? minFromSupport : minFromCoin, minTransfer: firstNonEmptyStr([ support?.minTransferAmount, support?.minAmount, minFromSupport, minFromCoin, ]), withdrawFee: firstNonEmptyStr([ support?.withdrawFeeValue, support?.fee, row['withdrawFeeValue'], ]), isUsdtFamily: isUsdtFamilyUnit(unit), isMainCoin: true, ); } WithdrawCoinOption mapWithdrawConfigFromDb( Map row, Map supportMap, ) { final unit = firstNonEmptyStr([row['unit']]).toLowerCase(); final coinName = row['coinName']?.toString() ?? ''; final support = supportMap[unit] ?? supportMap[coinName.toLowerCase()]; final networkName = row['networkName']?.toString() ?? ''; final minFromDb = firstNonEmptyStr([row['minWithdrawAmount'], row['minAmount']]); final minFromSupport = firstNonEmptyStr([support?.minAmount, support?.minWithdrawAmount]); return WithdrawCoinOption( unit: unit, displayName: firstNonEmptyStr([ row['coinNameCn'], support?.nameCn, support?.aliasName, coinName, ]).isNotEmpty ? firstNonEmptyStr([ row['coinNameCn'], support?.nameCn, support?.aliasName, coinName, ]) : unit.toUpperCase(), networkLabel: networkName, networkId: int.tryParse(row['networkId']?.toString() ?? '') ?? 0, balance: firstNonEmptyStr([support?.balance, '0']), minWithdraw: minFromSupport.isNotEmpty ? minFromSupport : minFromDb, minTransfer: firstNonEmptyStr([ support?.minTransferAmount, support?.minAmount, minFromSupport, ]), withdrawFee: firstNonEmptyStr([ support?.withdrawFeeValue, support?.fee, row['withdrawFeeValue'], ]), isUsdtFamily: isUsdtFamilyUnit(unit), isMainCoin: false, ); } String symbolForWithdrawCoin(WithdrawCoinOption? coin) { if (coin == null) { return 'USDT'; } if (coin.isMainCoin && coin.unit.toUpperCase() == 'USDT') { return 'USDT'; } if (coin.isUsdtFamily && coin.networkLabel.isNotEmpty && coin.unit.toUpperCase() != 'USDT') { return '${coin.displayName} (${coin.unit.toUpperCase()})'; } return coin.displayName.isNotEmpty ? coin.displayName : coin.unit.toUpperCase(); } const networkWithdrawDefaults = { 'TRC20': (fee: '1', min: '10'), 'ERC20': (fee: '5', min: '20'), 'BEP20': (fee: '2', min: '10'), };