withdraw_service.dart 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import 'package:decimal/decimal.dart';
  2. import 'package:dio/dio.dart';
  3. import '../models/asset/account_auth.dart';
  4. import '../models/asset/withdraw_balance.dart';
  5. import '../models/asset/withdraw_coin_option.dart';
  6. import '../models/asset/withdraw_record.dart';
  7. /// 提币 API 服务(无状态)
  8. class WithdrawService {
  9. const WithdrawService(this._dio);
  10. final Dio _dio;
  11. /// 获取可用余额
  12. Future<WithdrawBalance> getBalance(String coinName) async {
  13. // 可用余额必须始终从服务器获取,不能使用缓存
  14. final response = await _dio.post<Map<String, dynamic>>(
  15. 'uc/asset/wallet/$coinName',
  16. options: Options(extra: {'noCache': true}),
  17. );
  18. final data = response.data?['data'];
  19. if (data is Map<String, dynamic>) {
  20. return WithdrawBalance.fromJson(data);
  21. }
  22. return WithdrawBalance();
  23. }
  24. /// 获取认证信息(Google验证状态等)
  25. Future<AccountAuth> getSecuritySetting() async {
  26. final response = await _dio.post<Map<String, dynamic>>(
  27. 'uc/approve/security/setting',
  28. );
  29. final data = response.data?['data'];
  30. if (data is Map<String, dynamic>) {
  31. return AccountAuth.fromJson(data);
  32. }
  33. return const AccountAuth();
  34. }
  35. /// 发送提币邮箱验证码
  36. Future<void> sendWithdrawEmailCode({
  37. required String unit,
  38. required String address,
  39. required String amount,
  40. }) async {
  41. await _dio.post(
  42. 'uc/withdraw/email/code',
  43. data: {'unit': unit, 'address': address, 'amount': amount},
  44. options: Options(contentType: Headers.formUrlEncodedContentType),
  45. );
  46. }
  47. /// 链上提币
  48. Future<void> withdrawApply({
  49. required String unit,
  50. required String amount,
  51. required String address,
  52. required String fee,
  53. required String vcode,
  54. required String jyPassword,
  55. required String vcode2,
  56. String remark = '',
  57. }) async {
  58. await _dio.post(
  59. 'uc/withdraw/apply/code',
  60. data: {
  61. 'unit': unit,
  62. 'amount': amount,
  63. 'address': address,
  64. 'fee': fee,
  65. 'vcode': vcode,
  66. 'vtype': '2', // 邮箱验证
  67. 'jyPassword': jyPassword,
  68. 'vcode2': vcode2,
  69. 'remark': remark,
  70. },
  71. options: Options(contentType: Headers.formUrlEncodedContentType),
  72. );
  73. }
  74. /// 获取支持币种列表
  75. Future<List<SupportCoinInfo>> getSupportCoinInfo() async {
  76. final response = await _dio.post<Map<String, dynamic>>(
  77. 'uc/withdraw/support/coin/info',
  78. options: Options(extra: {'noCache': true}),
  79. );
  80. final data = response.data?['data'];
  81. if (data is List) {
  82. return data
  83. .whereType<Map<String, dynamic>>()
  84. .map(SupportCoinInfo.fromJson)
  85. .toList();
  86. }
  87. return [];
  88. }
  89. /// 提币主网列表
  90. Future<List<WithdrawNetworkItem>> getWithdrawNetworks() async {
  91. final response = await _dio.get<Map<String, dynamic>>(
  92. 'uc/coin-network/withdraw-networks',
  93. );
  94. final data = response.data?['data'];
  95. if (data is List) {
  96. return data
  97. .whereType<Map<String, dynamic>>()
  98. .map(WithdrawNetworkItem.fromJson)
  99. .where((n) => n.id > 0)
  100. .toList()
  101. ..sort((a, b) => a.sort.compareTo(b.sort));
  102. }
  103. return [];
  104. }
  105. /// 某主网下可提子币种
  106. Future<List<WithdrawCoinOption>> getWithdrawConfigs({
  107. required int networkId,
  108. required List<SupportCoinInfo> coinInfoList,
  109. }) async {
  110. final response = await _dio.get<Map<String, dynamic>>(
  111. 'uc/coin-network/withdraw-configs',
  112. queryParameters: {'networkId': networkId},
  113. );
  114. final data = response.data?['data'];
  115. if (data is! List) {
  116. return [];
  117. }
  118. final supportMap = supportInfoByUnit(coinInfoList);
  119. return data
  120. .whereType<Map<String, dynamic>>()
  121. .map((r) => mapWithdrawConfigFromDb(r, supportMap))
  122. .where((c) => c.unit.isNotEmpty)
  123. .toList();
  124. }
  125. /// 内部转账主币列表
  126. Future<List<WithdrawCoinOption>> getTransferParents({
  127. required List<SupportCoinInfo> coinInfoList,
  128. }) async {
  129. final response = await _dio.get<Map<String, dynamic>>(
  130. 'uc/coin-network/transfer-parents',
  131. );
  132. final data = response.data?['data'];
  133. if (data is! List) {
  134. return [];
  135. }
  136. final supportMap = supportInfoByUnit(coinInfoList);
  137. return data
  138. .whereType<Map<String, dynamic>>()
  139. .map((r) => mapTransferParent(r, supportMap))
  140. .where((c) => c.unit.isNotEmpty)
  141. .toList()
  142. ..sort((a, b) => a.displayName.compareTo(b.displayName));
  143. }
  144. /// 获取内部转账最小金额(USDT 基础币种配置)
  145. Future<Decimal> getTransferMinAmount({String unit = 'USDT'}) async {
  146. try {
  147. final response = await _dio.post<Map<String, dynamic>>(
  148. 'uc/withdraw/support/coin/info',
  149. options: Options(extra: {'noCache': true}),
  150. );
  151. final data = response.data?['data'];
  152. if (data is List) {
  153. for (final item in data) {
  154. if (item is Map<String, dynamic> && item['unit'] == unit) {
  155. return Decimal.tryParse(item['minAmount']?.toString() ?? '') ?? Decimal.zero;
  156. }
  157. }
  158. }
  159. } catch (_) {}
  160. return Decimal.zero;
  161. }
  162. /// 内部转账
  163. Future<void> internalTransfer({
  164. required String unit,
  165. required String amount,
  166. required String address,
  167. required String vcode,
  168. required String jyPassword,
  169. required String vcode2,
  170. String remark = '',
  171. }) async {
  172. await _dio.post(
  173. 'uc/withdraw/transfer',
  174. data: {
  175. 'unit': unit,
  176. 'amount': amount,
  177. 'address': address,
  178. 'vcode': vcode,
  179. 'vtype': '2',
  180. 'jyPassword': jyPassword,
  181. 'vcode2': vcode2,
  182. 'remark': remark,
  183. },
  184. options: Options(contentType: Headers.formUrlEncodedContentType),
  185. );
  186. }
  187. /// 链上提现记录(page 从 0 开始)
  188. Future<List<WithdrawRecord>> getWithdrawRecords({
  189. int page = 0,
  190. int pageSize = 10,
  191. }) async {
  192. final response = await _dio.get<Map<String, dynamic>>(
  193. 'uc/withdraw/record',
  194. queryParameters: {'page': page, 'pageSize': pageSize},
  195. );
  196. return _parseRecordList(response.data);
  197. }
  198. /// 内部转账记录(pageNo 从 0 开始)
  199. Future<List<WithdrawRecord>> getTransferRecords({
  200. int pageNo = 0,
  201. int pageSize = 10,
  202. }) async {
  203. final response = await _dio.get<Map<String, dynamic>>(
  204. 'uc/withdraw/transfer/record',
  205. queryParameters: {'pageNo': pageNo, 'pageSize': pageSize},
  206. );
  207. return _parseRecordList(response.data);
  208. }
  209. /// 取消链上提现
  210. Future<void> cancelWithdraw(String id) async {
  211. await _dio.post('uc/withdraw/cancel', queryParameters: {'id': id});
  212. }
  213. /// 获取单条链上提现记录详情
  214. Future<WithdrawRecord> getWithdrawRecord(String id) async {
  215. final response = await _dio.get<Map<String, dynamic>>(
  216. 'uc/withdraw/record/$id',
  217. );
  218. final data = response.data?['data'];
  219. if (data is Map<String, dynamic>) {
  220. return WithdrawRecord.fromJson(data);
  221. }
  222. return WithdrawRecord(id: id);
  223. }
  224. /// 获取单条内部转账记录详情
  225. Future<WithdrawRecord> getTransferRecord(String id) async {
  226. final response = await _dio.get<Map<String, dynamic>>(
  227. 'uc/withdraw/transfer/record/$id',
  228. );
  229. final data = response.data?['data'];
  230. if (data is Map<String, dynamic>) {
  231. return WithdrawRecord.fromJson(data);
  232. }
  233. return WithdrawRecord(id: id);
  234. }
  235. /// 取消内部转账
  236. Future<void> cancelTransfer(String id) async {
  237. await _dio.post('uc/withdraw/transfer/cancel', queryParameters: {'id': id});
  238. }
  239. List<WithdrawRecord> _parseRecordList(Map<String, dynamic>? responseData) {
  240. final data = responseData?['data'];
  241. if (data is Map<String, dynamic>) {
  242. final content = data['content'];
  243. if (content is List) {
  244. return content
  245. .whereType<Map<String, dynamic>>()
  246. .map((e) => WithdrawRecord.fromJson(e))
  247. .toList();
  248. }
  249. }
  250. return [];
  251. }
  252. }