generic changenow impl

This commit is contained in:
julian 2022-10-02 15:48:43 -06:00
parent 9af457d1c6
commit 807379f112
5 changed files with 213 additions and 12 deletions

View file

@ -11,6 +11,7 @@ import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/utilities/logger.dart';
@ -266,6 +267,46 @@ class ChangeNowAPI {
}
}
/// The API endpoint returns minimal payment amount and maximum payment amount
/// required to make an exchange. If you try to exchange less than minimum or
/// more than maximum, the transaction will most likely fail. Any pair of
/// assets has minimum amount and some of pairs have maximum amount.
Future<ExchangeResponse<Range>> getRange({
required String fromTicker,
required String toTicker,
required bool isFixedRate,
String? apiKey,
}) async {
Map<String, dynamic>? params = {"api_key": apiKey ?? kChangeNowApiKey};
final uri = _buildUri(
"/exchange-range${isFixedRate ? "/fixed-rate" : ""}/${fromTicker}_$toTicker",
params);
try {
final jsonObject = await _makeGetRequest(uri);
final json = Map<String, dynamic>.from(jsonObject as Map);
return ExchangeResponse(
value: Range(
max: Decimal.tryParse(json["maxAmount"] as String? ?? ""),
min: Decimal.tryParse(json["minAmount"] as String? ?? ""),
),
);
} catch (e, s) {
Logging.instance.log(
"getRange exception: $e\n$s",
level: LogLevel.Error,
);
return ExchangeResponse(
exception: ExchangeException(
e.toString(),
ExchangeExceptionType.generic,
),
);
}
}
/// Get estimated amount of [toTicker] cryptocurrency to receive
/// for [fromAmount] of [fromTicker]
Future<ExchangeResponse<EstimatedExchangeAmount>> getEstimatedExchangeAmount({
@ -309,6 +350,59 @@ class ChangeNowAPI {
}
}
/// Get estimated amount of [toTicker] cryptocurrency to receive
/// for [fromAmount] of [fromTicker]
Future<ExchangeResponse<EstimatedExchangeAmount>>
getEstimatedExchangeAmountFixedRate({
required String fromTicker,
required String toTicker,
required Decimal fromAmount,
required bool reversed,
String? apiKey,
}) async {
Map<String, dynamic> params = {"api_key": apiKey ?? kChangeNowApiKey};
late final Uri uri;
if (reversed) {
uri = _buildUri(
"/exchange-deposit/fixed-rate/${fromAmount.toString()}/${fromTicker}_$toTicker",
params,
);
} else {
uri = _buildUri(
"/exchange-amount/fixed-rate/${fromAmount.toString()}/${fromTicker}_$toTicker",
params,
);
}
try {
// simple json object is expected here
final json = await _makeGetRequest(uri);
try {
final value = EstimatedExchangeAmount.fromJson(
Map<String, dynamic>.from(json as Map));
return ExchangeResponse(value: value);
} catch (_) {
return ExchangeResponse(
exception: ExchangeException(
"Failed to serialize $json",
ExchangeExceptionType.serializeResponseError,
),
);
}
} catch (e, s) {
Logging.instance.log("getEstimatedExchangeAmount exception: $e\n$s",
level: LogLevel.Error);
return ExchangeResponse(
exception: ExchangeException(
e.toString(),
ExchangeExceptionType.generic,
),
);
}
}
// old v1 version
/// This API endpoint returns fixed-rate estimated exchange amount of
/// [toTicker] cryptocurrency to receive for [fromAmount] of [fromTicker]

View file

@ -1,10 +1,13 @@
import 'package:decimal/decimal.dart';
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
import 'package:stackwallet/models/exchange/response_objects/currency.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/change_now/change_now_api.dart';
import 'package:stackwallet/services/exchange/exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:uuid/uuid.dart';
class ChangeNowExchange extends Exchange {
@override
@ -25,8 +28,10 @@ class ChangeNowExchange extends Exchange {
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(
bool fixedRate,
) async {
// TODO: implement getAllCurrencies
throw UnimplementedError();
return await ChangeNowAPI.instance.getAvailableCurrencies(
fixedRate: fixedRate ? true : null,
active: true,
);
}
@override
@ -41,19 +46,41 @@ class ChangeNowExchange extends Exchange {
String to,
Decimal amount,
bool fixedRate,
bool reversed,
) async {
// TODO: implement getEstimate
throw UnimplementedError();
late final ExchangeResponse<EstimatedExchangeAmount> response;
if (fixedRate) {
response =
await ChangeNowAPI.instance.getEstimatedExchangeAmountFixedRate(
fromTicker: from,
toTicker: to,
fromAmount: amount,
reversed: reversed,
);
} else {
response = await ChangeNowAPI.instance.getEstimatedExchangeAmount(
fromTicker: from,
toTicker: to,
fromAmount: amount,
);
}
if (response.exception != null) {
return ExchangeResponse(exception: response.exception);
}
return ExchangeResponse(value: response.value?.estimatedAmount);
}
@override
Future<ExchangeResponse<Range>> getMinMaxExchangeAmounts(
Future<ExchangeResponse<Range>> getRange(
String from,
String to,
bool fixedRate,
) async {
// TODO: implement getMinMaxExchangeAmounts
throw UnimplementedError();
return await ChangeNowAPI.instance.getRange(
fromTicker: from,
toTicker: to,
isFixedRate: fixedRate,
);
}
@override
@ -67,8 +94,76 @@ class ChangeNowExchange extends Exchange {
@override
Future<ExchangeResponse<Trade>> getTrade(String tradeId) async {
// TODO: implement getTrade
throw UnimplementedError();
final response =
await ChangeNowAPI.instance.getTransactionStatus(id: tradeId);
if (response.exception != null) {
return ExchangeResponse(exception: response.exception);
}
final t = response.value!;
final timestamp = DateTime.tryParse(t.createdAt) ?? DateTime.now();
final trade = Trade(
uuid: const Uuid().v1(),
tradeId: tradeId,
rateType: "",
direction: "",
timestamp: timestamp,
updatedAt: DateTime.tryParse(t.updatedAt) ?? timestamp,
payInCurrency: t.fromCurrency,
payInAmount: t.expectedSendAmountDecimal,
payInAddress: t.payinAddress,
payInNetwork: "",
payInExtraId: t.payinExtraId,
payInTxid: "",
payOutCurrency: t.toCurrency,
payOutAmount: t.expectedReceiveAmountDecimal,
payOutAddress: t.payoutAddress,
payOutNetwork: "",
payOutExtraId: t.payoutExtraId,
payOutTxid: "",
refundAddress: t.refundAddress,
refundExtraId: t.refundExtraId,
status: t.status.name,
);
return ExchangeResponse(value: trade);
}
@override
Future<ExchangeResponse<Trade>> updateTrade(Trade trade) async {
final response =
await ChangeNowAPI.instance.getTransactionStatus(id: trade.tradeId);
if (response.exception != null) {
return ExchangeResponse(exception: response.exception);
}
final t = response.value!;
final timestamp = DateTime.tryParse(t.createdAt) ?? DateTime.now();
final _trade = Trade(
uuid: trade.uuid,
tradeId: trade.tradeId,
rateType: "",
direction: "",
timestamp: timestamp,
updatedAt: DateTime.tryParse(t.updatedAt) ?? timestamp,
payInCurrency: t.fromCurrency,
payInAmount: t.expectedSendAmountDecimal,
payInAddress: t.payinAddress,
payInNetwork: "",
payInExtraId: t.payinExtraId,
payInTxid: "",
payOutCurrency: t.toCurrency,
payOutAmount: t.expectedReceiveAmountDecimal,
payOutAddress: t.payoutAddress,
payOutNetwork: "",
payOutExtraId: t.payoutExtraId,
payOutTxid: "",
refundAddress: t.refundAddress,
refundExtraId: t.refundExtraId,
status: t.status.name,
);
return ExchangeResponse(value: _trade);
}
@override

View file

@ -18,10 +18,11 @@ abstract class Exchange {
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate);
Future<ExchangeResponse<Trade>> getTrade(String tradeId);
Future<ExchangeResponse<Trade>> updateTrade(Trade trade);
Future<ExchangeResponse<List<Trade>>> getTrades();
Future<ExchangeResponse<Range>> getMinMaxExchangeAmounts(
Future<ExchangeResponse<Range>> getRange(
String from,
String to,
bool fixedRate,
@ -32,6 +33,7 @@ abstract class Exchange {
String to,
Decimal amount,
bool fixedRate,
bool reversed,
);
Future<ExchangeResponse<Trade>> createTrade({

View file

@ -334,6 +334,7 @@ class SimpleSwapAPI {
Future<ExchangeResponse<Trade>> getExchange({
required String exchangeId,
String? apiKey,
Trade? oldTrade,
}) async {
final uri = _buildUri(
"/get_exchange",
@ -349,7 +350,7 @@ class SimpleSwapAPI {
final json = Map<String, dynamic>.from(jsonObject as Map);
final ts = DateTime.parse(json["timestamp"] as String);
final trade = Trade(
uuid: const Uuid().v1(),
uuid: oldTrade?.uuid ?? const Uuid().v1(),
tradeId: json["id"] as String,
rateType: json["type"] as String,
direction: "direct",

View file

@ -73,6 +73,7 @@ class SimpleSwapExchange extends Exchange {
String to,
Decimal amount,
bool fixedRate,
bool reversed,
) async {
final response = await SimpleSwapAPI.instance.getEstimated(
isFixedRate: fixedRate,
@ -88,7 +89,7 @@ class SimpleSwapExchange extends Exchange {
}
@override
Future<ExchangeResponse<Range>> getMinMaxExchangeAmounts(
Future<ExchangeResponse<Range>> getRange(
String from,
String to,
bool fixedRate,
@ -114,6 +115,14 @@ class SimpleSwapExchange extends Exchange {
return await SimpleSwapAPI.instance.getExchange(exchangeId: tradeId);
}
@override
Future<ExchangeResponse<Trade>> updateTrade(Trade trade) async {
return await SimpleSwapAPI.instance.getExchange(
exchangeId: trade.tradeId,
oldTrade: trade,
);
}
@override
Future<ExchangeResponse<List<Trade>>> getTrades() async {
// TODO: implement getTrades