import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; // import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.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/models/buy/response_objects/fiat.dart'; // import 'package:stackwallet/models/buy/response_objects/crypto.dart'; import 'package:stackwallet/services/buy/buy_response.dart'; import 'package:stackwallet/utilities/logger.dart'; class SimplexAPI { static const String scheme = "https"; static const String authority = "sandbox-api.stackwallet.com"; SimplexAPI._(); static final SimplexAPI _instance = SimplexAPI._(); static SimplexAPI get instance => _instance; /// set this to override using standard http client. Useful for testing http.Client? client; Uri _buildUri(String path, Map? params) { return Uri.https(authority, path, 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; 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 _makePostRequest( Uri uri, Map body, ) async { final client = this.client ?? http.Client(); try { final response = await client.post( uri, headers: {'Content-Type': 'application/json'}, body: jsonEncode(body), ); if (response.statusCode == 200) { final parsed = jsonDecode(response.body); return parsed; } throw Exception("response: ${response.body}"); } catch (e, s) { Logging.instance .log("_makeRequest($uri) threw: $e\n$s", level: LogLevel.Error); rethrow; } } // Future> createNewExchange({ // required bool isFixedRate, // required String currencyFrom, // required String currencyTo, // required String addressTo, // required String userRefundAddress, // required String userRefundExtraId, // required String amount, // String? extraIdTo, // String? apiKey, // }) async { // Map body = { // "fixed": isFixedRate, // "currency_from": currencyFrom, // "currency_to": currencyTo, // "addressTo": addressTo, // "userRefundAddress": userRefundAddress, // "userRefundExtraId": userRefundExtraId, // "amount": double.parse(amount), // "extraIdTo": extraIdTo, // }; // // final uri = // _buildUri("/create_exchange", {"api_key": apiKey ?? kSimplexApiKey}); // // try { // final jsonObject = await _makePostRequest(uri, body); // // final json = Map.from(jsonObject as Map); // final trade = Trade( // uuid: const Uuid().v1(), // tradeId: json["id"] as String, // rateType: json["type"] as String, // direction: "direct", // timestamp: DateTime.parse(json["timestamp"] as String), // updatedAt: DateTime.parse(json["updated_at"] as String), // payInCurrency: json["currency_from"] as String, // payInAmount: json["amount_from"] as String, // payInAddress: json["address_from"] as String, // payInNetwork: "", // payInExtraId: json["extra_id_from"] as String? ?? "", // payInTxid: json["tx_from"] as String? ?? "", // payOutCurrency: json["currency_to"] as String, // payOutAmount: json["amount_to"] as String, // payOutAddress: json["address_to"] as String, // payOutNetwork: "", // payOutExtraId: json["extra_id_to"] as String? ?? "", // payOutTxid: json["tx_to"] as String? ?? "", // refundAddress: json["user_refund_address"] as String, // refundExtraId: json["user_refund_extra_id"] as String, // status: json["status"] as String, // exchangeName: SimplexExchange.exchangeName, // ); // return ExchangeResponse(value: trade, exception: null); // } catch (e, s) { // Logging.instance.log("getAvailableCurrencies exception: $e\n$s", // level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // value: null, // ); // } // } Future>> getAllCurrencies({ String? apiKey, required bool fixedRate, }) async { final uri = _buildUri("/quote", {}); try { final jsonArray = await _makeGetRequest(uri); return await compute(_parseAvailableCurrenciesJson, jsonArray as List); } catch (e, s) { Logging.instance.log("getAvailableCurrencies exception: $e\n$s", level: LogLevel.Error); return BuyResponse( exception: BuyException( e.toString(), BuyExceptionType.generic, ), ); } } BuyResponse> _parseAvailableCurrenciesJson( List jsonArray) { try { List currencies = []; for (final json in jsonArray) { try { currencies.add(Fiat.fromJson(Map.from(json as Map))); } catch (_) { return BuyResponse( exception: BuyException("Failed to serialize $json", BuyExceptionType.serializeResponseError)); } } return BuyResponse(value: currencies); } catch (e, s) { Logging.instance.log("_parseAvailableCurrenciesJson exception: $e\n$s", level: LogLevel.Error); return BuyResponse( exception: BuyException( e.toString(), BuyExceptionType.generic, ), ); } } // Future> getCurrency({ // required String symbol, // String? apiKey, // }) async { // final uri = _buildUri( // "/get_currency", // { // "api_key": apiKey ?? kSimplexApiKey, // "symbol": symbol, // }, // ); // // try { // final jsonObject = await _makeGetRequest(uri); // // return ExchangeResponse( // value: SPCurrency.fromJson( // Map.from(jsonObject as Map))); // } catch (e, s) { // Logging.instance // .log("getCurrency exception: $e\n$s", level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // ); // } // } // // /// returns a map where the key currency symbol is a valid pair with any of // /// the symbols in its value list // Future>> getAllPairs({ // required bool isFixedRate, // String? apiKey, // }) async { // final uri = _buildUri( // "/get_all_pairs", // { // "api_key": apiKey ?? kSimplexApiKey, // "fixed": isFixedRate.toString(), // }, // ); // // try { // final jsonObject = await _makeGetRequest(uri); // final result = await compute( // _parseAvailablePairsJson, // Tuple2(jsonObject as Map, isFixedRate), // ); // return result; // } catch (e, s) { // Logging.instance // .log("getAllPairs exception: $e\n$s", level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // ); // } // } // // ExchangeResponse> _parseAvailablePairsJson( // Tuple2, bool> args, // ) { // try { // List pairs = []; // // for (final entry in args.item1.entries) { // try { // final from = entry.key as String; // for (final to in entry.value as List) { // pairs.add( // Pair( // from: from, // fromNetwork: "", // to: to as String, // toNetwork: "", // fixedRate: args.item2, // floatingRate: !args.item2, // ), // ); // } // } catch (_) { // return ExchangeResponse( // exception: ExchangeException("Failed to serialize $json", // ExchangeExceptionType.serializeResponseError)); // } // } // // return ExchangeResponse(value: pairs); // } catch (e, s) { // Logging.instance.log("_parseAvailableCurrenciesJson exception: $e\n$s", // level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // ); // } // } // // /// returns the estimated amount as a string // Future> getEstimated({ // required bool isFixedRate, // required String currencyFrom, // required String currencyTo, // required String amount, // String? apiKey, // }) async { // final uri = _buildUri( // "/get_estimated", // { // "api_key": apiKey ?? kSimplexApiKey, // "fixed": isFixedRate.toString(), // "currency_from": currencyFrom, // "currency_to": currencyTo, // "amount": amount, // }, // ); // // try { // final jsonObject = await _makeGetRequest(uri); // // return ExchangeResponse(value: jsonObject as String); // } catch (e, s) { // Logging.instance // .log("getEstimated exception: $e\n$s", level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // ); // } // } // // /// returns the exchange for the given id // Future> getExchange({ // required String exchangeId, // String? apiKey, // Trade? oldTrade, // }) async { // final uri = _buildUri( // "/get_exchange", // { // "api_key": apiKey ?? kSimplexApiKey, // "id": exchangeId, // }, // ); // // try { // final jsonObject = await _makeGetRequest(uri); // // final json = Map.from(jsonObject as Map); // final ts = DateTime.parse(json["timestamp"] as String); // final trade = Trade( // uuid: oldTrade?.uuid ?? const Uuid().v1(), // tradeId: json["id"] as String, // rateType: json["type"] as String, // direction: "direct", // timestamp: ts, // updatedAt: DateTime.tryParse(json["updated_at"] as String? ?? "") ?? ts, // payInCurrency: json["currency_from"] as String, // payInAmount: json["amount_from"] as String, // payInAddress: json["address_from"] as String, // payInNetwork: "", // payInExtraId: json["extra_id_from"] as String? ?? "", // payInTxid: json["tx_from"] as String? ?? "", // payOutCurrency: json["currency_to"] as String, // payOutAmount: json["amount_to"] as String, // payOutAddress: json["address_to"] as String, // payOutNetwork: "", // payOutExtraId: json["extra_id_to"] as String? ?? "", // payOutTxid: json["tx_to"] as String? ?? "", // refundAddress: json["user_refund_address"] as String, // refundExtraId: json["user_refund_extra_id"] as String, // status: json["status"] as String, // exchangeName: SimplexExchange.exchangeName, // ); // // return ExchangeResponse(value: trade); // } catch (e, s) { // Logging.instance // .log("getExchange exception: $e\n$s", level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // ); // } // } // // /// returns the minimal exchange amount // Future> getRange({ // required bool isFixedRate, // required String currencyFrom, // required String currencyTo, // String? apiKey, // }) async { // final uri = _buildUri( // "/get_ranges", // { // "api_key": apiKey ?? kSimplexApiKey, // "fixed": isFixedRate.toString(), // "currency_from": currencyFrom, // "currency_to": currencyTo, // }, // ); // // try { // final jsonObject = await _makeGetRequest(uri); // // final json = Map.from(jsonObject as Map); // return ExchangeResponse( // value: Range( // max: Decimal.tryParse(json["max"] as String? ?? ""), // min: Decimal.tryParse(json["min"] as String? ?? ""), // ), // ); // } catch (e, s) { // Logging.instance.log("getRange exception: $e\n$s", level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // ); // } // } // // Future>> getFixedRateMarketInfo({ // String? apiKey, // }) async { // final uri = _buildUri( // "/get_market_info", // null, // // { // // "api_key": apiKey ?? kSimplexApiKey, // // "fixed": isFixedRate.toString(), // // "currency_from": currencyFrom, // // "currency_to": currencyTo, // // }, // ); // // try { // final jsonArray = await _makeGetRequest(uri); // // try { // final result = await compute( // _parseFixedRateMarketsJson, // jsonArray as List, // ); // return result; // } catch (e, s) { // Logging.instance.log("getAvailableFixedRateMarkets exception: $e\n$s", // level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // "Error: $jsonArray", // ExchangeExceptionType.serializeResponseError, // ), // ); // } // } catch (e, s) { // Logging.instance.log("getAvailableFixedRateMarkets exception: $e\n$s", // level: LogLevel.Error); // return ExchangeResponse( // exception: ExchangeException( // e.toString(), // ExchangeExceptionType.generic, // ), // ); // } // } // // ExchangeResponse> _parseFixedRateMarketsJson( // List jsonArray) { // try { // final List markets = []; // for (final json in jsonArray) { // try { // final map = Map.from(json as Map); // markets.add(FixedRateMarket( // from: map["currency_from"] as String, // to: map["currency_to"] as String, // min: Decimal.parse(map["min"] as String), // max: Decimal.parse(map["max"] as String), // rate: Decimal.parse(map["rate"] as String), // minerFee: null, // )); // } catch (_) { // return ExchangeResponse( // exception: ExchangeException("Failed to serialize $json", // ExchangeExceptionType.serializeResponseError)); // } // } // return ExchangeResponse(value: markets); // } catch (_) { // rethrow; // } // } }