trocador api and response DTOs

This commit is contained in:
julian 2023-04-28 10:30:31 -06:00
parent 05dc2a23e6
commit 9c414068d3
7 changed files with 699 additions and 0 deletions

View file

@ -0,0 +1,44 @@
import 'package:decimal/decimal.dart';
class TrocadorCoin {
final String name;
final String ticker;
final String network;
final bool memo;
final String image;
final Decimal minimum;
final Decimal maximum;
TrocadorCoin({
required this.name,
required this.ticker,
required this.network,
required this.memo,
required this.image,
required this.minimum,
required this.maximum,
});
factory TrocadorCoin.fromMap(Map<String, dynamic> json) => TrocadorCoin(
name: json['name'] as String,
ticker: json['ticker'] as String,
network: json['network'] as String,
memo: json['memo'] as bool,
image: json['image'] as String,
minimum: Decimal.parse(json['minimum'].toString()),
maximum: Decimal.parse(json['maximum'].toString()),
);
@override
String toString() {
return 'TrocadorCoin( '
'name: $name, '
'ticker: $ticker, '
'network: $network, '
'memo: $memo, '
'image: $image, '
'minimum: $minimum, '
'maximum: $maximum '
')';
}
}

View file

@ -0,0 +1,43 @@
import 'package:decimal/decimal.dart';
class TrocadorQuote {
final String provider;
final String kycRating;
final int insurance;
final bool fixed;
final Decimal amountTo;
final Decimal waste;
TrocadorQuote({
required this.provider,
required this.kycRating,
required this.insurance,
required this.fixed,
required this.amountTo,
required this.waste,
});
factory TrocadorQuote.fromMap(Map<String, dynamic> map) {
return TrocadorQuote(
provider: map['provider'] as String,
kycRating: map['kycrating'] as String,
insurance: map['insurance'] as int,
// wtf trocador?
fixed: map['fixed'] == "True",
amountTo: Decimal.parse(map['amount_to'].toString()),
waste: Decimal.parse(map['waste'].toString()),
);
}
@override
String toString() {
return 'TrocadorQuote( '
'provider: $provider, '
'kycRating: $kycRating, '
'insurance: $insurance, '
'fixed: $fixed, '
'amountTo: $amountTo, '
'waste: $waste '
')';
}
}

View file

@ -0,0 +1,84 @@
import 'package:decimal/decimal.dart';
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_quote.dart';
class TrocadorRate {
final String tradeId;
final DateTime date;
final String tickerFrom;
final String tickerTo;
final String coinFrom;
final String coinTo;
final String networkFrom;
final String networkTo;
final Decimal amountFrom;
final Decimal amountTo;
final String provider;
final bool fixed;
final bool payment;
final String status;
final List<TrocadorQuote> quotes;
TrocadorRate({
required this.tradeId,
required this.date,
required this.tickerFrom,
required this.tickerTo,
required this.coinFrom,
required this.coinTo,
required this.networkFrom,
required this.networkTo,
required this.amountFrom,
required this.amountTo,
required this.provider,
required this.fixed,
required this.payment,
required this.status,
required this.quotes,
});
factory TrocadorRate.fromMap(Map<String, dynamic> map) {
final list =
List<Map<String, dynamic>>.from(map['quotes']['quotes'] as List);
final quotes = list.map((quote) => TrocadorQuote.fromMap(quote)).toList();
return TrocadorRate(
tradeId: map['trade_id'] as String,
date: DateTime.parse(map['date'] as String),
tickerFrom: map['ticker_from'] as String,
tickerTo: map['ticker_to'] as String,
coinFrom: map['coin_from'] as String,
coinTo: map['coin_to'] as String,
networkFrom: map['network_from'] as String,
networkTo: map['network_to'] as String,
amountFrom: Decimal.parse(map['amount_from'].toString()),
amountTo: Decimal.parse(map['amount_to'].toString()),
provider: map['provider'] as String,
fixed: map['fixed'] as bool,
payment: map['payment'] as bool,
status: map['status'] as String,
quotes: quotes,
);
}
@override
String toString() {
final quotesString = quotes.map((quote) => quote.toString()).join(', ');
return 'TrocadorRate('
'tradeId: $tradeId, '
'date: $date, '
'tickerFrom: $tickerFrom, '
'tickerTo: $tickerTo, '
'coinFrom: $coinFrom, '
'coinTo: $coinTo, '
'networkFrom: $networkFrom, '
'networkTo: $networkTo, '
'amountFrom: $amountFrom, '
'amountTo: $amountTo, '
'provider: $provider, '
'fixed: $fixed, '
'payment: $payment, '
'status: $status, '
'quotes: [$quotesString] '
')';
}
}

View file

@ -0,0 +1,116 @@
import 'package:decimal/decimal.dart';
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_quote.dart';
class TrocadorTrade {
final String tradeId;
final DateTime date;
final String tickerFrom;
final String tickerTo;
final String coinFrom;
final String coinTo;
final String networkFrom;
final String networkTo;
final Decimal amountFrom;
final Decimal amountTo;
final String provider;
final bool fixed;
final String status;
final String addressProvider;
final String addressProviderMemo;
final String addressUser;
final String addressUserMemo;
final String refundAddress;
final String refundAddressMemo;
final String password;
final String idProvider;
final List<TrocadorQuote> quotes;
final bool payment;
TrocadorTrade({
required this.tradeId,
required this.date,
required this.tickerFrom,
required this.tickerTo,
required this.coinFrom,
required this.coinTo,
required this.networkFrom,
required this.networkTo,
required this.amountFrom,
required this.amountTo,
required this.provider,
required this.fixed,
required this.status,
required this.addressProvider,
required this.addressProviderMemo,
required this.addressUser,
required this.addressUserMemo,
required this.refundAddress,
required this.refundAddressMemo,
required this.password,
required this.idProvider,
required this.quotes,
required this.payment,
});
factory TrocadorTrade.fromMap(Map<String, dynamic> map) {
final list =
List<Map<String, dynamic>>.from(map['quotes']['quotes'] as List);
final quotes = list.map((quote) => TrocadorQuote.fromMap(quote)).toList();
return TrocadorTrade(
tradeId: map['trade_id'] as String,
date: DateTime.parse(map['date'] as String),
tickerFrom: map['ticker_from'] as String,
tickerTo: map['ticker_to'] as String,
coinFrom: map['coin_from'] as String,
coinTo: map['coin_to'] as String,
networkFrom: map['network_from'] as String,
networkTo: map['network_to'] as String,
amountFrom: Decimal.parse(map['amount_from'].toString()),
amountTo: Decimal.parse(map['amount_to'].toString()),
provider: map['provider'] as String,
fixed: map['fixed'] as bool,
status: map['status'] as String,
addressProvider: map['address_provider'] as String,
addressProviderMemo: map['address_provider_memo'] as String,
addressUser: map['address_user'] as String,
addressUserMemo: map['address_user_memo'] as String,
refundAddress: map['refund_address'] as String,
refundAddressMemo: map['refund_address_memo'] as String,
password: map['password'] as String,
idProvider: map['id_provider'] as String,
quotes: quotes,
payment: map['payment'] as bool,
);
}
@override
String toString() {
final quotesString = quotes.map((quote) => quote.toString()).join(', ');
return 'TrocadorTrade( '
'tradeId: $tradeId, '
'date: $date, '
'tickerFrom: $tickerFrom, '
'tickerTo: $tickerTo, '
'coinFrom: $coinFrom, '
'coinTo: $coinTo, '
'networkFrom: $networkFrom, '
'networkTo: $networkTo, '
'amountFrom: $amountFrom, '
'amountTo: $amountTo, '
'provider: $provider, '
'fixed: $fixed, '
'status: $status, '
'addressProvider: $addressProvider, '
'addressProviderMemo: $addressProviderMemo, '
'addressUser: $addressUser, '
'addressUserMemo: $addressUserMemo, '
'refundAddress: $refundAddress, '
'refundAddressMemo: $refundAddressMemo, '
'password: $password, '
'idProvider: $idProvider, '
'quotes: [ $quotesString ], '
'payment: $payment '
')';
}
}

View file

@ -0,0 +1,106 @@
import 'package:decimal/decimal.dart';
class TrocadorTradeNew {
final String tradeId;
final DateTime date;
final String tickerFrom;
final String tickerTo;
final String coinFrom;
final String coinTo;
final String networkFrom;
final String networkTo;
final Decimal amountFrom;
final Decimal amountTo;
final String provider;
final bool fixed;
final String status;
final String? addressProvider;
final String? addressProviderMemo;
final String addressUser;
final String addressUserMemo;
final String refundAddress;
final String refundAddressMemo;
final String password;
final String idProvider;
final bool payment;
TrocadorTradeNew({
required this.tradeId,
required this.date,
required this.tickerFrom,
required this.tickerTo,
required this.coinFrom,
required this.coinTo,
required this.networkFrom,
required this.networkTo,
required this.amountFrom,
required this.amountTo,
required this.provider,
required this.fixed,
required this.status,
required this.addressProvider,
required this.addressProviderMemo,
required this.addressUser,
required this.addressUserMemo,
required this.refundAddress,
required this.refundAddressMemo,
required this.password,
required this.idProvider,
required this.payment,
});
factory TrocadorTradeNew.fromMap(Map<String, dynamic> map) {
return TrocadorTradeNew(
tradeId: map['trade_id'] as String,
date: DateTime.parse(map['date'] as String),
tickerFrom: map['ticker_from'] as String,
tickerTo: map['ticker_to'] as String,
coinFrom: map['coin_from'] as String,
coinTo: map['coin_to'] as String,
networkFrom: map['network_from'] as String,
networkTo: map['network_to'] as String,
amountFrom: Decimal.parse(map['amount_from'].toString()),
amountTo: Decimal.parse(map['amount_to'].toString()),
provider: map['provider'] as String,
fixed: map['fixed'] as bool,
status: map['status'] as String,
addressProvider: map['address_provider'] as String,
addressProviderMemo: map['address_provider_memo'] as String,
addressUser: map['address_user'] as String,
addressUserMemo: map['address_user_memo'] as String,
refundAddress: map['refund_address'] as String,
refundAddressMemo: map['refund_address_memo'] as String,
password: map['password'] as String,
idProvider: map['id_provider'] as String,
payment: map['payment'] as bool,
);
}
@override
String toString() {
return 'TrocadorTradeNew( '
'tradeId: $tradeId, '
'date: $date, '
'tickerFrom: $tickerFrom, '
'tickerTo: $tickerTo, '
'coinFrom: $coinFrom, '
'coinTo: $coinTo, '
'networkFrom: $networkFrom, '
'networkTo: $networkTo, '
'amountFrom: $amountFrom, '
'amountTo: $amountTo, '
'provider: $provider, '
'fixed: $fixed, '
'status: $status, '
'addressProvider: $addressProvider, '
'addressProviderMemo: $addressProviderMemo, '
'addressUser: $addressUser, '
'addressUserMemo: $addressUserMemo, '
'refundAddress: $refundAddress, '
'refundAddressMemo: $refundAddressMemo, '
'password: $password, '
'idProvider: $idProvider, '
'payment: $payment '
')';
}
}

View file

@ -0,0 +1,306 @@
import 'dart:convert';
import 'package:flutter_native_splash/cli_commands.dart';
import 'package:http/http.dart' as http;
import 'package:stackwallet/exceptions/exchange/exchange_exception.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_coin.dart';
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_rate.dart';
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_trade.dart';
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_trade_new.dart';
import 'package:stackwallet/utilities/logger.dart';
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";
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 {
print("URI: $uri");
final response = await http.get(
uri,
headers: {'Content-Type': 'application/json'},
);
code = response.statusCode;
print("CODE: $code");
print("BODY: ${response.body}");
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);
final map = Map<String, dynamic>.from(json as Map);
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
static Future<ExchangeResponse<dynamic>> getNewStandardRate({
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,
"ticker_from": fromTicker,
"network_from": fromNetwork,
"ticker_to": toTicker,
"network_to": toNetwork,
"amount_from": fromAmount,
"min_kycrating": minKYCRating,
"markup": markup,
};
return await _getNewRate(isOnion: isOnion, params: params);
}
/// get fixed rate/payment rate
static Future<ExchangeResponse<dynamic>> getNewPaymentRate({
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,
"ticker_from": fromTicker,
"network_from": fromNetwork,
"ticker_to": toTicker,
"network_to": toNetwork,
"amount_to": toAmount,
"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,
"id": rateId ?? "",
"ticker_from": fromTicker,
"network_from": fromNetwork,
"ticker_to": toTicker,
"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,
};
return await _getNewTrade(isOnion: isOnion, params: params);
}
static Future<ExchangeResponse<TrocadorTradeNew>> createNewPaymentRateTrade({
required bool isOnion,
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,
"ticker_from": fromTicker,
"network_from": fromNetwork,
"ticker_to": toTicker,
"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,
};
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);
return ExchangeResponse(value: TrocadorTradeNew.fromMap(map));
} catch (e, s) {
Logging.instance
.log("_getNewTrade exception: $e\n$s", level: LogLevel.Error);
return ExchangeResponse(
exception: ExchangeException(
e.toString(),
ExchangeExceptionType.generic,
),
);
}
}
}