diff --git a/lib/exceptions/exchange/exchange_exception.dart b/lib/exceptions/exchange/exchange_exception.dart new file mode 100644 index 000000000..af7aa8f65 --- /dev/null +++ b/lib/exceptions/exchange/exchange_exception.dart @@ -0,0 +1,13 @@ +import 'package:stackwallet/exceptions/sw_exception.dart'; + +enum ExchangeExceptionType { generic, serializeResponseError } + +class ExchangeException extends SWException { + ExchangeExceptionType type; + ExchangeException(super.message, this.type); + + @override + String toString() { + return message; + } +} diff --git a/lib/exceptions/exchange/majestic_bank/mb_exception.dart b/lib/exceptions/exchange/majestic_bank/mb_exception.dart new file mode 100644 index 000000000..d3130d874 --- /dev/null +++ b/lib/exceptions/exchange/majestic_bank/mb_exception.dart @@ -0,0 +1,5 @@ +import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; + +class MBException extends ExchangeException { + MBException(super.message, super.type); +} diff --git a/lib/models/exchange/majestic_bank/mb_limit.dart b/lib/models/exchange/majestic_bank/mb_limit.dart new file mode 100644 index 000000000..baa002d56 --- /dev/null +++ b/lib/models/exchange/majestic_bank/mb_limit.dart @@ -0,0 +1,19 @@ +import 'package:decimal/decimal.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_object.dart'; + +class MBLimit extends MBObject { + MBLimit({ + required this.currency, + required this.min, + required this.max, + }); + + final String currency; + final Decimal min; + final Decimal max; + + @override + String toString() { + return "MBLimit: { $currency: { min: $min, max: $max } }"; + } +} diff --git a/lib/models/exchange/majestic_bank/mb_object.dart b/lib/models/exchange/majestic_bank/mb_object.dart new file mode 100644 index 000000000..e3810131c --- /dev/null +++ b/lib/models/exchange/majestic_bank/mb_object.dart @@ -0,0 +1 @@ +abstract class MBObject {} diff --git a/lib/models/exchange/majestic_bank/mb_order.dart b/lib/models/exchange/majestic_bank/mb_order.dart new file mode 100644 index 000000000..f5dde038e --- /dev/null +++ b/lib/models/exchange/majestic_bank/mb_order.dart @@ -0,0 +1,43 @@ +import 'package:decimal/decimal.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_object.dart'; + +enum MBOrderType { + fixed, + floating, +} + +class MBOrder extends MBObject { + MBOrder({ + required this.orderId, + required this.fromCurrency, + required this.fromAmount, + required this.receiveCurrency, + required this.receiveAmount, + required this.address, + required this.orderType, + required this.expiration, + required this.createdAt, + }); + + final String orderId; + final String fromCurrency; + final Decimal fromAmount; + final String receiveCurrency; + final String address; + final Decimal receiveAmount; + final MBOrderType orderType; + + /// minutes + final int expiration; + + final DateTime createdAt; + + bool isExpired() => + (DateTime.now().difference(createdAt) >= Duration(minutes: expiration)); + + @override + String toString() { + // todo: full toString + return orderId; + } +} diff --git a/lib/models/exchange/majestic_bank/mb_order_calculation.dart b/lib/models/exchange/majestic_bank/mb_order_calculation.dart new file mode 100644 index 000000000..931ca440f --- /dev/null +++ b/lib/models/exchange/majestic_bank/mb_order_calculation.dart @@ -0,0 +1,21 @@ +import 'package:decimal/decimal.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_object.dart'; + +class MBOrderCalculation extends MBObject { + MBOrderCalculation({ + required this.fromCurrency, + required this.fromAmount, + required this.receiveCurrency, + required this.receiveAmount, + }); + + final String fromCurrency; + final Decimal fromAmount; + final String receiveCurrency; + final Decimal receiveAmount; + + @override + String toString() { + return "MBOrderCalculation: { $fromCurrency: $fromAmount, $receiveCurrency: $receiveAmount }"; + } +} diff --git a/lib/models/exchange/majestic_bank/mb_order_status.dart b/lib/models/exchange/majestic_bank/mb_order_status.dart new file mode 100644 index 000000000..5496aa5e2 --- /dev/null +++ b/lib/models/exchange/majestic_bank/mb_order_status.dart @@ -0,0 +1,32 @@ +import 'package:decimal/decimal.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_object.dart'; + +class MBOrderStatus extends MBObject { + MBOrderStatus({ + required this.orderId, + required this.status, + required this.fromCurrency, + required this.fromAmount, + required this.receiveCurrency, + required this.receiveAmount, + required this.address, + required this.received, + required this.confirmed, + }); + + final String orderId; + final String status; + final String fromCurrency; + final Decimal fromAmount; + final String receiveCurrency; + final Decimal receiveAmount; + final String address; + final Decimal received; + final Decimal confirmed; + + @override + String toString() { + // todo: full toString + return status; + } +} diff --git a/lib/models/exchange/majestic_bank/mb_rate.dart b/lib/models/exchange/majestic_bank/mb_rate.dart new file mode 100644 index 000000000..60d71cdf0 --- /dev/null +++ b/lib/models/exchange/majestic_bank/mb_rate.dart @@ -0,0 +1,15 @@ +import 'package:decimal/decimal.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_object.dart'; + +class MBRate extends MBObject { + MBRate({required this.fromCurrency, required this.toCurrency, required this.rate,}); + + final String fromCurrency; + final String toCurrency; + final Decimal rate; + + @override + String toString() { + return "MBRate: { $fromCurrency-$toCurrency: $rate }"; + } +} diff --git a/lib/pages/settings_views/global_settings_view/hidden_settings.dart b/lib/pages/settings_views/global_settings_view/hidden_settings.dart index d92b166d7..92b34e851 100644 --- a/lib/pages/settings_views/global_settings_view/hidden_settings.dart +++ b/lib/pages/settings_views/global_settings_view/hidden_settings.dart @@ -11,6 +11,8 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; +import '../../../services/exchange/majestic_bank/majestic_bank_api.dart'; + class HiddenSettings extends StatelessWidget { const HiddenSettings({Key? key}) : super(key: key); @@ -128,6 +130,48 @@ class HiddenSettings extends StatelessWidget { ), ); }), + // const SizedBox( + // height: 12, + // ), + // Consumer(builder: (_, ref, __) { + // return GestureDetector( + // onTap: () async { + // final x = + // await MajesticBankAPI.instance.getRates(); + // print(x); + // }, + // child: RoundedWhiteContainer( + // child: Text( + // "Click me", + // style: STextStyles.button(context).copyWith( + // color: Theme.of(context) + // .extension()! + // .accentColorDark), + // ), + // ), + // ); + // }), + const SizedBox( + height: 12, + ), + Consumer(builder: (_, ref, __) { + return GestureDetector( + onTap: () async { + final x = + await MajesticBankAPI.instance.getLimits(); + print(x); + }, + child: RoundedWhiteContainer( + child: Text( + "Click me", + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), + ), + ), + ); + }), const SizedBox( height: 12, ), diff --git a/lib/services/exchange/change_now/change_now_api.dart b/lib/services/exchange/change_now/change_now_api.dart index d957eaf1a..a9920bfb8 100644 --- a/lib/services/exchange/change_now/change_now_api.dart +++ b/lib/services/exchange/change_now/change_now_api.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; +import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; import 'package:stackwallet/external_api_keys.dart'; import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart'; import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart'; diff --git a/lib/services/exchange/exchange_data_loading_service.dart b/lib/services/exchange/exchange_data_loading_service.dart index d06f8b726..8d232e957 100644 --- a/lib/services/exchange/exchange_data_loading_service.dart +++ b/lib/services/exchange/exchange_data_loading_service.dart @@ -55,7 +55,7 @@ class ExchangeDataLoadingService { } } else { Logging.instance.log( - "Failed to load changeNOW fixed rate markets: ${response3.exception?.errorMessage}", + "Failed to load changeNOW fixed rate markets: ${response3.exception?.message}", level: LogLevel.Error); ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state = @@ -122,7 +122,7 @@ class ExchangeDataLoadingService { } } else { Logging.instance.log( - "Failed to load changeNOW available floating rate pairs: ${response2.exception?.errorMessage}", + "Failed to load changeNOW available floating rate pairs: ${response2.exception?.message}", level: LogLevel.Error); ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state = ChangeNowLoadStatus.failed; @@ -130,7 +130,7 @@ class ExchangeDataLoadingService { } } else { Logging.instance.log( - "Failed to load changeNOW currencies: ${response.exception?.errorMessage}", + "Failed to load changeNOW currencies: ${response.exception?.message}", level: LogLevel.Error); await Future.delayed(const Duration(seconds: 3)); ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state = diff --git a/lib/services/exchange/exchange_response.dart b/lib/services/exchange/exchange_response.dart index 59441fb9b..79339e5f7 100644 --- a/lib/services/exchange/exchange_response.dart +++ b/lib/services/exchange/exchange_response.dart @@ -1,15 +1,4 @@ -enum ExchangeExceptionType { generic, serializeResponseError } - -class ExchangeException implements Exception { - String errorMessage; - ExchangeExceptionType type; - ExchangeException(this.errorMessage, this.type); - - @override - String toString() { - return errorMessage; - } -} +import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; class ExchangeResponse { late final T? value; diff --git a/lib/services/exchange/majestic_bank/majestic_bank_api.dart b/lib/services/exchange/majestic_bank/majestic_bank_api.dart new file mode 100644 index 000000000..6d7e2ffe7 --- /dev/null +++ b/lib/services/exchange/majestic_bank/majestic_bank_api.dart @@ -0,0 +1,339 @@ +import 'dart:convert'; + +import 'package:decimal/decimal.dart'; +import 'package:http/http.dart' as http; +import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_limit.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_order.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_order_calculation.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_order_status.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_rate.dart'; +import 'package:stackwallet/services/exchange/exchange_response.dart'; +import 'package:stackwallet/utilities/logger.dart'; + +class MajesticBankAPI { + static const String scheme = "https"; + static const String authority = "majesticbank.sc"; + static const String version = "v1"; + static const String refCode = "fixme"; + + MajesticBankAPI._(); + + static final MajesticBankAPI _instance = MajesticBankAPI._(); + + static MajesticBankAPI get instance => _instance; + + /// set this to override using standard http client. Useful for testing + http.Client? client; + + Uri _buildUri({required String endpoint, Map? params}) { + return Uri.https(authority, "/api/$version/$endpoint", params); + } + + Future _makeGetRequest(Uri uri) async { + final client = this.client ?? http.Client(); + int code = -1; + try { + final response = await client.get( + uri, + ); + + code = response.statusCode; + print(response.body); + + final parsed = jsonDecode(response.body); + + return parsed; + } catch (e, s) { + Logging.instance.log( + "_makeRequest($uri) HTTP:$code threw: $e\n$s", + level: LogLevel.Error, + ); + rethrow; + } + } + + Future>> getRates() async { + final uri = _buildUri( + endpoint: "rates", + ); + + try { + final jsonObject = await _makeGetRequest(uri); + + final map = Map.from(jsonObject as Map); + final List rates = []; + for (final key in map.keys) { + final currencies = key.split("-"); + if (currencies.length == 2) { + final rate = MBRate( + fromCurrency: currencies.first, + toCurrency: currencies.last, + rate: Decimal.parse(map[key].toString()), + ); + rates.add(rate); + } + } + return ExchangeResponse(value: rates); + } catch (e, s) { + Logging.instance.log("getRates exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + Future> getLimit({ + required String fromCurrency, + }) async { + final uri = _buildUri( + endpoint: "limits", + params: { + "from_currency": fromCurrency, + }, + ); + + try { + final jsonObject = await _makeGetRequest(uri); + + final map = Map.from(jsonObject as Map); + + final limit = MBLimit( + currency: fromCurrency, + min: Decimal.parse(map["min"].toString()), + max: Decimal.parse(map["max"].toString()), + ); + + return ExchangeResponse(value: limit); + } catch (e, s) { + Logging.instance + .log("getLimits exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + Future>> getLimits() async { + final uri = _buildUri( + endpoint: + "rates", // limits are included in the rates call for some reason??? + ); + + try { + final jsonObject = await _makeGetRequest(uri); + + final map = Map.from(jsonObject as Map)["limits"] as Map; + final List limits = []; + for (final key in map.keys) { + final limit = MBLimit( + currency: key as String, + min: Decimal.parse(map[key]["min"].toString()), + max: Decimal.parse(map[key]["max"].toString()), + ); + limits.add(limit); + } + + return ExchangeResponse(value: limits); + } catch (e, s) { + Logging.instance + .log("getLimits exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + /// If [reversed] then the amount is the expected receive_amount, otherwise + /// the amount is assumed to be the from_amount. + Future> calculateOrder({ + required String amount, + required bool reversed, + required String fromCurrency, + required String receiveCurrency, + }) async { + final params = { + "from_currency": fromCurrency, + "receive_currency": receiveCurrency, + }; + + if (reversed) { + params["receive_amount"] = amount; + } else { + params["from_amount"] = amount; + } + + final uri = _buildUri( + endpoint: "calculate", + params: params, + ); + + try { + final jsonObject = await _makeGetRequest(uri); + final map = Map.from(jsonObject as Map); + final result = MBOrderCalculation( + fromCurrency: map["from_currency"] as String, + fromAmount: Decimal.parse(map["from_amount"].toString()), + receiveCurrency: map["receive_currency"] as String, + receiveAmount: Decimal.parse(map["receive_amount"].toString()), + ); + + return ExchangeResponse(value: result); + } catch (e, s) { + Logging.instance + .log("calculateOrder exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + Future> createOrder({ + required String fromAmount, + required String fromCurrency, + required String receiveCurrency, + required String receiveAddress, + }) async { + final params = { + "from_amount": fromAmount, + "from_currency": fromCurrency, + "receive_currency": receiveCurrency, + "receive_address": receiveAddress, + "referral_code": refCode, + }; + + final uri = _buildUri(endpoint: "exchange", params: params); + + try { + final now = DateTime.now(); + final jsonObject = await _makeGetRequest(uri); + final json = Map.from(jsonObject as Map); + + final order = MBOrder( + orderId: json["trx"] as String, + fromCurrency: json["from_currency"] as String, + fromAmount: Decimal.parse(json["from_amount"].toString()), + receiveCurrency: json["receive_currency"] as String, + receiveAmount: Decimal.parse(json["receive_amount"].toString()), + address: json["address"] as String, + orderType: MBOrderType.floating, + expiration: json["expiration"] as int, + createdAt: now, + ); + + return ExchangeResponse(value: order); + } catch (e, s) { + Logging.instance + .log("createOrder exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + /// Fixed rate for 10 minutes, useful for payments. + /// If [reversed] then the amount is the expected receive_amount, otherwise + /// the amount is assumed to be the from_amount. + Future> createFixedRateOrder({ + required String amount, + required String fromCurrency, + required String receiveCurrency, + required String receiveAddress, + required bool reversed, + }) async { + final params = { + "from_currency": fromCurrency, + "receive_currency": receiveCurrency, + "receive_address": receiveAddress, + "referral_code": refCode, + }; + + if (reversed) { + params["receive_amount"] = amount; + } else { + params["from_amount"] = amount; + } + + final uri = _buildUri(endpoint: "pay", params: params); + + try { + final now = DateTime.now(); + final jsonObject = await _makeGetRequest(uri); + final json = Map.from(jsonObject as Map); + + final order = MBOrder( + orderId: json["trx"] as String, + fromCurrency: json["from_currency"] as String, + fromAmount: Decimal.parse(json["from_amount"].toString()), + receiveCurrency: json["receive_currency"] as String, + receiveAmount: Decimal.parse(json["receive_amount"].toString()), + address: json["address"] as String, + orderType: MBOrderType.fixed, + expiration: json["expiration"] as int, + createdAt: now, + ); + + return ExchangeResponse(value: order); + } catch (e, s) { + Logging.instance + .log("createFixedRateOrder exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + Future> trackOrder({ + required String orderId, + }) async { + final uri = _buildUri(endpoint: "track", params: { + "trx": orderId, + }); + + try { + final jsonObject = await _makeGetRequest(uri); + final json = Map.from(jsonObject as Map); + + final status = MBOrderStatus( + orderId: json["trx"] as String, + status: json["status"] as String, + fromCurrency: json["from_currency"] as String, + fromAmount: Decimal.parse(json["from_amount"].toString()), + receiveCurrency: json["receive_currency"] as String, + receiveAmount: Decimal.parse(json["receive_amount"].toString()), + address: json["address"] as String, + received: Decimal.parse(json["received"].toString()), + confirmed: Decimal.parse(json["confirmed"].toString()), + ); + + return ExchangeResponse(value: status); + } catch (e, s) { + Logging.instance + .log("createOrder exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } +} diff --git a/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart b/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart new file mode 100644 index 000000000..4610f6c3d --- /dev/null +++ b/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart @@ -0,0 +1,263 @@ +import 'package:decimal/decimal.dart'; +import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; +import 'package:stackwallet/exceptions/exchange/majestic_bank/mb_exception.dart'; +import 'package:stackwallet/models/exchange/majestic_bank/mb_order.dart'; +import 'package:stackwallet/models/exchange/response_objects/currency.dart'; +import 'package:stackwallet/models/exchange/response_objects/estimate.dart'; +import 'package:stackwallet/models/exchange/response_objects/pair.dart'; +import 'package:stackwallet/models/exchange/response_objects/range.dart'; +import 'package:stackwallet/models/exchange/response_objects/trade.dart'; +import 'package:stackwallet/services/exchange/exchange.dart'; +import 'package:stackwallet/services/exchange/exchange_response.dart'; +import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_api.dart'; +import 'package:uuid/uuid.dart'; + +class MajesticBankExchange extends Exchange { + static const exchangeName = "MajesticBank"; + + @override + Future> createTrade({ + required String from, + required String to, + required bool fixedRate, + required Decimal amount, + required String addressTo, + String? extraId, + required String addressRefund, + required String refundExtraId, + String? rateId, + required bool reversed, + }) async { + ExchangeResponse? response; + + if (fixedRate) { + response = await MajesticBankAPI.instance.createFixedRateOrder( + amount: amount.toString(), + fromCurrency: from, + receiveCurrency: to, + receiveAddress: addressTo, + reversed: reversed, + ); + } else { + if (reversed) { + return ExchangeResponse( + exception: MBException( + "Reversed trade not available", + ExchangeExceptionType.generic, + ), + ); + } + response = await MajesticBankAPI.instance.createOrder( + fromAmount: amount.toString(), + fromCurrency: from, + receiveCurrency: to, + receiveAddress: addressTo, + ); + } + + if (response.value != null) { + final order = response.value!; + final trade = Trade( + uuid: const Uuid().v1(), + tradeId: order.orderId, + rateType: fixedRate ? "fixed" : "floating", + direction: reversed ? "reversed" : "direct", + timestamp: order.createdAt, + updatedAt: order.createdAt, + payInCurrency: order.fromCurrency, + payInAmount: order.fromAmount.toString(), + payInAddress: order.address, + payInNetwork: "", + payInExtraId: "", + payInTxid: "", + payOutCurrency: order.receiveCurrency, + payOutAmount: order.receiveAmount.toString(), + payOutAddress: addressTo, + payOutNetwork: "", + payOutExtraId: "", + payOutTxid: "", + refundAddress: addressRefund, + refundExtraId: refundExtraId, + status: "Waiting", + exchangeName: exchangeName, + ); + + return ExchangeResponse(value: trade); + } else { + return ExchangeResponse(exception: response.exception!); + } + } + + @override + Future>> getAllCurrencies( + bool fixedRate, + ) async { + final response = await MajesticBankAPI.instance.getLimits(); + if (response.value == null) { + return ExchangeResponse(exception: response.exception); + } + + final List currencies = []; + final limits = response.value!; + + for (final limit in limits) { + final currency = Currency( + ticker: limit.currency, + name: limit.currency, + network: "", + image: "", + hasExternalId: false, + isFiat: false, + featured: false, + isStable: false, + supportsFixedRate: true, + ); + currencies.add(currency); + } + + return ExchangeResponse(value: currencies); + } + + @override + Future>> getAllPairs(bool fixedRate) async { + final response = await MajesticBankAPI.instance.getRates(); + if (response.value == null) { + return ExchangeResponse(exception: response.exception); + } + + final List pairs = []; + final rates = response.value!; + + for (final rate in rates) { + final pair = Pair( + from: rate.fromCurrency, + fromNetwork: "", + to: rate.toCurrency, + toNetwork: "", + fixedRate: true, + floatingRate: true, + ); + pairs.add(pair); + } + + return ExchangeResponse(value: pairs); + } + + @override + Future> getEstimate( + String from, + String to, + Decimal amount, + bool fixedRate, + bool reversed, + ) async { + final response = await MajesticBankAPI.instance.calculateOrder( + amount: amount.toString(), + reversed: reversed, + fromCurrency: from, + receiveCurrency: to, + ); + if (response.value == null) { + return ExchangeResponse(exception: response.exception); + } + + final calc = response.value!; + final estimate = Estimate( + estimatedAmount: reversed ? calc.fromAmount : calc.receiveAmount, + fixedRate: fixedRate, + reversed: reversed, + ); + return ExchangeResponse(value: estimate); + } + + @override + Future>> getPairsFor( + String currency, + bool fixedRate, + ) async { + final response = await getAllPairs(fixedRate); + if (response.value == null) { + return ExchangeResponse(exception: response.exception); + } + + final pairs = response.value!.where( + (e) => + e.from.toUpperCase() == currency.toUpperCase() || + e.to.toUpperCase() == currency.toUpperCase(), + ); + + return ExchangeResponse(value: pairs.toList()); + } + + @override + Future> getRange( + String from, + String to, + bool fixedRate, + ) async { + final response = + await MajesticBankAPI.instance.getLimit(fromCurrency: from); + if (response.value == null) { + return ExchangeResponse(exception: response.exception); + } + + final limit = response.value!; + final range = Range(min: limit.min, max: limit.max); + + return ExchangeResponse(value: range); + } + + @override + Future> getTrade(String tradeId) async { + // TODO: implement getTrade + throw UnimplementedError(); + } + + @override + Future>> getTrades() async { + // TODO: implement getTrades + throw UnimplementedError(); + } + + @override + String get name => exchangeName; + + @override + Future> updateTrade(Trade trade) async { + final response = await MajesticBankAPI.instance.trackOrder( + orderId: trade.tradeId, + ); + + if (response.value != null) { + final status = response.value!; + final updatedTrade = Trade( + uuid: trade.uuid, + tradeId: status.orderId, + rateType: trade.rateType, + direction: trade.direction, + timestamp: trade.timestamp, + updatedAt: DateTime.now(), + payInCurrency: status.fromCurrency, + payInAmount: status.fromAmount.toString(), + payInAddress: status.address, + payInNetwork: trade.payInNetwork, + payInExtraId: trade.payInExtraId, + payInTxid: trade.payInTxid, + payOutCurrency: status.receiveCurrency, + payOutAmount: status.receiveAmount.toString(), + payOutAddress: trade.payOutAddress, + payOutNetwork: trade.payOutNetwork, + payOutExtraId: trade.payOutExtraId, + payOutTxid: trade.payOutTxid, + refundAddress: trade.refundAddress, + refundExtraId: trade.refundExtraId, + status: status.status, + exchangeName: exchangeName, + ); + + return ExchangeResponse(value: updatedTrade); + } else { + return ExchangeResponse(exception: response.exception); + } + } +} diff --git a/lib/services/exchange/simpleswap/simpleswap_api.dart b/lib/services/exchange/simpleswap/simpleswap_api.dart index 3d626b2eb..bd6e933fe 100644 --- a/lib/services/exchange/simpleswap/simpleswap_api.dart +++ b/lib/services/exchange/simpleswap/simpleswap_api.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; +import 'package:stackwallet/exceptions/exchange/exchange_exception.dart'; import 'package:stackwallet/external_api_keys.dart'; import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart'; import 'package:stackwallet/models/exchange/response_objects/pair.dart';