stack_wallet/lib/services/exchange/trocador/trocador_api.dart

357 lines
9.9 KiB
Dart
Raw Normal View History

2023-05-26 21:21:16 +00:00
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
2023-04-28 16:30:31 +00:00
import 'dart:convert';
2023-04-28 21:27:38 +00:00
import 'package:flutter/foundation.dart';
import '../../../exceptions/exchange/exchange_exception.dart';
import '../../../networking/http.dart';
import '../../../utilities/extensions/extensions.dart';
import '../../../utilities/logger.dart';
import '../../../utilities/prefs.dart';
import '../../tor_service.dart';
import '../exchange_response.dart';
import 'response_objects/trocador_coin.dart';
import 'response_objects/trocador_rate.dart';
import 'response_objects/trocador_trade.dart';
import 'response_objects/trocador_trade_new.dart';
2023-04-28 16:30:31 +00:00
const kTrocadorApiKey = "8rFqf7QLxX1mUBiNPEMaLUpV2biz6n";
const kTrocadorRefCode = "9eHm9BkQfS";
abstract class TrocadorAPI {
static const String authority = "trocador.app";
static const String onionAuthority =
"trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion";
static const String markup = "1";
static const String minKYCRating = "C";
2023-09-08 21:09:59 +00:00
static HTTP client = HTTP();
2023-04-28 16:30:31 +00:00
static Uri _buildUri({
required String method,
required bool isOnion,
Map<String, String>? params,
}) {
return isOnion
? Uri.http(onionAuthority, "api/$method", params)
: Uri.https(authority, "api/$method", params);
}
static Future<dynamic> _makeGetRequest(Uri uri) async {
int code = -1;
try {
2023-04-28 21:27:38 +00:00
debugPrint("URI: $uri");
2023-09-08 21:09:59 +00:00
final response = await client.get(
url: uri,
2023-04-28 16:30:31 +00:00
headers: {'Content-Type': 'application/json'},
2023-09-15 19:51:20 +00:00
proxyInfo: Prefs.instance.useTor
? TorService.sharedInstance.getProxyInfo()
: null,
2023-04-28 16:30:31 +00:00
);
2023-09-08 21:09:59 +00:00
code = response.code;
2023-04-28 16:30:31 +00:00
2023-11-06 17:23:16 +00:00
// debugPrint("CODE: $code");
// debugPrint("BODY: ${response.body}");
2023-04-28 16:30:31 +00:00
final json = jsonDecode(response.body);
return json;
} catch (e, s) {
Logging.instance.log(
"_makeRequest($uri) HTTP:$code threw: $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
}
/// fetch all supported coins
static Future<ExchangeResponse<List<TrocadorCoin>>> getCoins({
required bool isOnion,
}) async {
final uri = _buildUri(
isOnion: isOnion,
method: "coins",
params: {
"api_key": kTrocadorApiKey,
"ref": kTrocadorRefCode,
},
);
try {
final json = await _makeGetRequest(uri);
if (json is List) {
final list = List<Map<String, dynamic>>.from(json);
final List<TrocadorCoin> coins = list
.map(
(e) => TrocadorCoin.fromMap(e),
)
.toList();
return ExchangeResponse(value: coins);
} else {
throw Exception("unexpected json: $json");
}
} catch (e, s) {
Logging.instance.log("getCoins exception: $e\n$s", level: LogLevel.Error);
return ExchangeResponse(
exception: ExchangeException(
e.toString(),
ExchangeExceptionType.generic,
),
);
}
}
/// get trade info
static Future<ExchangeResponse<TrocadorTrade>> getTrade({
required bool isOnion,
required String tradeId,
}) async {
final uri = _buildUri(
isOnion: isOnion,
method: "trade",
params: {
"api_key": kTrocadorApiKey,
"ref": kTrocadorRefCode,
"id": tradeId,
},
);
try {
final json = await _makeGetRequest(uri);
2023-04-28 20:26:51 +00:00
final map = Map<String, dynamic>.from((json as List).first as Map);
2023-04-28 16:30:31 +00:00
return ExchangeResponse(value: TrocadorTrade.fromMap(map));
} catch (e, s) {
Logging.instance.log("getTrade exception: $e\n$s", level: LogLevel.Error);
return ExchangeResponse(
exception: ExchangeException(
e.toString(),
ExchangeExceptionType.generic,
),
);
}
}
/// get standard/floating rate
2023-04-28 20:26:51 +00:00
static Future<ExchangeResponse<TrocadorRate>> getNewStandardRate({
2023-04-28 16:30:31 +00:00
required bool isOnion,
required String fromTicker,
required String fromNetwork,
required String toTicker,
required String toNetwork,
required String fromAmount,
}) async {
final params = {
"api_key": kTrocadorApiKey,
"ref": kTrocadorRefCode,
2023-04-28 20:26:51 +00:00
"ticker_from": fromTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_from": fromNetwork,
2023-04-28 20:26:51 +00:00
"ticker_to": toTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_to": toNetwork,
"amount_from": fromAmount,
2023-04-28 20:26:51 +00:00
"payment": "false",
2023-04-28 16:30:31 +00:00
"min_kycrating": minKYCRating,
"markup": markup,
};
return await _getNewRate(isOnion: isOnion, params: params);
}
/// get fixed rate/payment rate
2023-04-28 20:26:51 +00:00
static Future<ExchangeResponse<TrocadorRate>> getNewPaymentRate({
2023-04-28 16:30:31 +00:00
required bool isOnion,
required String fromTicker,
required String fromNetwork,
required String toTicker,
required String toNetwork,
required String toAmount,
}) async {
final params = {
"api_key": kTrocadorApiKey,
"ref": kTrocadorRefCode,
2023-04-28 20:26:51 +00:00
"ticker_from": fromTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_from": fromNetwork,
2023-04-28 20:26:51 +00:00
"ticker_to": toTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_to": toNetwork,
"amount_to": toAmount,
2023-04-28 20:26:51 +00:00
"payment": "true",
2023-04-28 16:30:31 +00:00
"min_kycrating": minKYCRating,
"markup": markup,
};
return await _getNewRate(isOnion: isOnion, params: params);
}
static Future<ExchangeResponse<TrocadorRate>> _getNewRate({
required bool isOnion,
required Map<String, String> params,
}) async {
final uri = _buildUri(
isOnion: isOnion,
method: "new_rate",
params: params,
);
try {
final json = await _makeGetRequest(uri);
final map = Map<String, dynamic>.from(json as Map);
return ExchangeResponse(value: TrocadorRate.fromMap(map));
} catch (e, s) {
Logging.instance
.log("getNewRate exception: $e\n$s", level: LogLevel.Error);
return ExchangeResponse(
exception: ExchangeException(
e.toString(),
ExchangeExceptionType.generic,
),
);
}
}
/// create new floating rate/standard trade
static Future<ExchangeResponse<TrocadorTradeNew>> createNewStandardRateTrade({
required bool isOnion,
required String? rateId,
required String fromTicker,
required String fromNetwork,
required String toTicker,
required String toNetwork,
required String fromAmount,
required String receivingAddress,
required String? receivingMemo,
required String refundAddress,
required String? refundMemo,
required String exchangeProvider,
required bool isFixedRate,
}) async {
final Map<String, String> params = {
"api_key": kTrocadorApiKey,
"ref": kTrocadorRefCode,
2023-04-28 20:26:51 +00:00
"ticker_from": fromTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_from": fromNetwork,
2023-04-28 20:26:51 +00:00
"ticker_to": toTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_to": toNetwork,
"amount_from": fromAmount,
"address": receivingAddress,
"address_memo": receivingMemo ?? "0",
"refund": refundAddress,
"refund_memo": refundMemo ?? "0",
"provider": exchangeProvider,
"fixed": isFixedRate.toString().capitalize(),
"payment": "False",
"min_kycrating": minKYCRating,
"markup": markup,
};
2023-04-28 20:26:51 +00:00
if (rateId != null) {
params["id"] = rateId;
}
2023-04-28 16:30:31 +00:00
return await _getNewTrade(isOnion: isOnion, params: params);
}
static Future<ExchangeResponse<TrocadorTradeNew>> createNewPaymentRateTrade({
required bool isOnion,
2023-04-28 20:26:51 +00:00
required String? rateId,
2023-04-28 16:30:31 +00:00
required String fromTicker,
required String fromNetwork,
required String toTicker,
required String toNetwork,
required String toAmount,
required String receivingAddress,
required String? receivingMemo,
required String refundAddress,
required String? refundMemo,
required String exchangeProvider,
required bool isFixedRate,
}) async {
final params = {
"api_key": kTrocadorApiKey,
"ref": kTrocadorRefCode,
2023-04-28 20:26:51 +00:00
"ticker_from": fromTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_from": fromNetwork,
2023-04-28 20:26:51 +00:00
"ticker_to": toTicker.toLowerCase(),
2023-04-28 16:30:31 +00:00
"network_to": toNetwork,
"amount_to": toAmount,
"address": receivingAddress,
"address_memo": receivingMemo ?? "0",
"refund": refundAddress,
"refund_memo": refundMemo ?? "0",
"provider": exchangeProvider,
"fixed": isFixedRate.toString().capitalize(),
"payment": "True",
"min_kycrating": minKYCRating,
"markup": markup,
};
2023-04-28 20:26:51 +00:00
if (rateId != null) {
params["id"] = rateId;
}
2023-04-28 16:30:31 +00:00
return await _getNewTrade(isOnion: isOnion, params: params);
}
static Future<ExchangeResponse<TrocadorTradeNew>> _getNewTrade({
required bool isOnion,
required Map<String, String> params,
}) async {
final uri = _buildUri(
isOnion: isOnion,
method: "new_trade",
params: params,
);
try {
final json = await _makeGetRequest(uri);
final map = Map<String, dynamic>.from(json as Map);
try {
return ExchangeResponse(value: TrocadorTradeNew.fromMap(map));
} catch (e, s) {
String error = map["error"] as String? ?? json.toString();
if (error ==
"trade could not be generated, some unknown error happened") {
error =
"This trade couldn't be completed. Please select another provider.";
}
Logging.instance.log(
"_getNewTrade failed to parse response: $json\n$e\n$s",
level: LogLevel.Error,
);
return ExchangeResponse(
exception: ExchangeException(
error,
ExchangeExceptionType.serializeResponseError,
),
);
}
2023-04-28 16:30:31 +00:00
} catch (e, s) {
Logging.instance.log(
"_getNewTrade exception: $e\n$s",
level: LogLevel.Error,
);
2023-04-28 16:30:31 +00:00
return ExchangeResponse(
exception: ExchangeException(
e.toString(),
ExchangeExceptionType.generic,
),
);
}
}
}