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..58333b807 --- /dev/null +++ b/lib/services/exchange/majestic_bank/majestic_bank_api.dart @@ -0,0 +1,240 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; +import 'package:stackwallet/models/exchange/response_objects/trade.dart'; +import 'package:stackwallet/services/exchange/exchange_response.dart'; +import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; +import 'package:stackwallet/utilities/logger.dart'; +import 'package:uuid/uuid.dart'; + +class MajesticBankAPI { + static const String scheme = "https"; + static const String authority = "majesticbank.sc"; + static const String version = "v1"; + static const String refCode = ""; + + 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); + } + + String getPrettyJSONString(jsonObject) { + var encoder = const JsonEncoder.withIndent(" "); + return encoder.convert(jsonObject); + } + + 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); + + return getPrettyJSONString(jsonObject); + } catch (e, s) { + Logging.instance.log("getRates exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + Future calculateOrder() async { + final uri = _buildUri( + endpoint: "calculate", + ); + + try { + final jsonObject = await _makeGetRequest(uri); + + return getPrettyJSONString(jsonObject); + } 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 amount, + required String fromCurrency, + required String receiveCurrency, + required String receiveAddress, + }) async { + final params = { + "from_amount": amount, + "from_currency": fromCurrency, + "receive_currency": receiveCurrency, + "receive_address": receiveAddress, + "referral_code": refCode, + }; + + final uri = _buildUri(endpoint: "create", params: params); + + try { + final now = DateTime.now(); + final jsonObject = await _makeGetRequest(uri); + final json = Map.from(jsonObject as Map); + + final trade = Trade( + uuid: const Uuid().v1(), + tradeId: json["trx"] as String, + rateType: "floating-rate", + direction: "direct", + timestamp: now, + updatedAt: now, + payInCurrency: json["from_currency"] as String, + payInAmount: json["from_amount"] as String, + payInAddress: json["address"] as String, + payInNetwork: "", + payInExtraId: "", + payInTxid: "", + payOutCurrency: json["receive_currency"] as String, + payOutAmount: json["receive_amount"] as String, + payOutAddress: json["receive_address"] as String, + payOutNetwork: "", + payOutExtraId: "", + payOutTxid: "", + refundAddress: "", + refundExtraId: "", + status: "Waiting", + exchangeName: MajesticBankExchange.exchangeName, + ); + return ExchangeResponse(value: trade); + } catch (e, s) { + Logging.instance + .log("createOrder exception: $e\n$s", level: LogLevel.Error); + return ExchangeResponse( + exception: ExchangeException( + e.toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + 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 trade = Trade( + uuid: const Uuid().v1(), + tradeId: json["trx"] as String, + rateType: "fixed-rate", + direction: reversed ? "reversed" : "direct", + timestamp: now, + updatedAt: now, + payInCurrency: json["from_currency"] as String, + payInAmount: json["from_amount"] as String, + payInAddress: json["address"] as String, + payInNetwork: "", + payInExtraId: "", + payInTxid: "", + payOutCurrency: json["receive_currency"] as String, + payOutAmount: json["receive_amount"] as String, + payOutAddress: json["receive_address"] as String, + payOutNetwork: "", + payOutExtraId: "", + payOutTxid: "", + refundAddress: "", + refundExtraId: "", + status: "Waiting", + exchangeName: MajesticBankExchange.exchangeName, + ); + return ExchangeResponse(value: trade); + } 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", + ); + + try { + final jsonObject = await _makeGetRequest(uri); + + return getPrettyJSONString(jsonObject); + } 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..978ffb914 --- /dev/null +++ b/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart @@ -0,0 +1,82 @@ +import 'package:decimal/decimal.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'; + +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}) { + // TODO: implement createTrade + throw UnimplementedError(); + } + + @override + Future>> getAllCurrencies(bool fixedRate) { + // TODO: implement getAllCurrencies + throw UnimplementedError(); + } + + @override + Future>> getAllPairs(bool fixedRate) { + // TODO: implement getAllPairs + throw UnimplementedError(); + } + + @override + Future> getEstimate( + String from, String to, Decimal amount, bool fixedRate, bool reversed) { + // TODO: implement getEstimate + throw UnimplementedError(); + } + + @override + Future>> getPairsFor( + String currency, bool fixedRate) { + // TODO: implement getPairsFor + throw UnimplementedError(); + } + + @override + Future> getRange( + String from, String to, bool fixedRate) { + // TODO: implement getRange + throw UnimplementedError(); + } + + @override + Future> getTrade(String tradeId) { + // TODO: implement getTrade + throw UnimplementedError(); + } + + @override + Future>> getTrades() { + // TODO: implement getTrades + throw UnimplementedError(); + } + + @override + String get name => exchangeName; + + @override + Future> updateTrade(Trade trade) { + // TODO: implement updateTrade + throw UnimplementedError(); + } +}