mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-11 05:04:35 +00:00
generic changenow impl
This commit is contained in:
parent
9af457d1c6
commit
807379f112
5 changed files with 213 additions and 12 deletions
|
@ -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/exchange_transaction_status.dart';
|
||||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.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/currency.dart';
|
||||||
|
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||||
import 'package:stackwallet/utilities/logger.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
|
/// Get estimated amount of [toTicker] cryptocurrency to receive
|
||||||
/// for [fromAmount] of [fromTicker]
|
/// for [fromAmount] of [fromTicker]
|
||||||
Future<ExchangeResponse<EstimatedExchangeAmount>> getEstimatedExchangeAmount({
|
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
|
// old v1 version
|
||||||
/// This API endpoint returns fixed-rate estimated exchange amount of
|
/// This API endpoint returns fixed-rate estimated exchange amount of
|
||||||
/// [toTicker] cryptocurrency to receive for [fromAmount] of [fromTicker]
|
/// [toTicker] cryptocurrency to receive for [fromAmount] of [fromTicker]
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import 'package:decimal/decimal.dart';
|
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/currency.dart';
|
||||||
import 'package:stackwallet/models/exchange/response_objects/pair.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/range.dart';
|
||||||
import 'package:stackwallet/models/exchange/response_objects/trade.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.dart';
|
||||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class ChangeNowExchange extends Exchange {
|
class ChangeNowExchange extends Exchange {
|
||||||
@override
|
@override
|
||||||
|
@ -25,8 +28,10 @@ class ChangeNowExchange extends Exchange {
|
||||||
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(
|
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(
|
||||||
bool fixedRate,
|
bool fixedRate,
|
||||||
) async {
|
) async {
|
||||||
// TODO: implement getAllCurrencies
|
return await ChangeNowAPI.instance.getAvailableCurrencies(
|
||||||
throw UnimplementedError();
|
fixedRate: fixedRate ? true : null,
|
||||||
|
active: true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -41,19 +46,41 @@ class ChangeNowExchange extends Exchange {
|
||||||
String to,
|
String to,
|
||||||
Decimal amount,
|
Decimal amount,
|
||||||
bool fixedRate,
|
bool fixedRate,
|
||||||
|
bool reversed,
|
||||||
) async {
|
) async {
|
||||||
// TODO: implement getEstimate
|
late final ExchangeResponse<EstimatedExchangeAmount> response;
|
||||||
throw UnimplementedError();
|
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
|
@override
|
||||||
Future<ExchangeResponse<Range>> getMinMaxExchangeAmounts(
|
Future<ExchangeResponse<Range>> getRange(
|
||||||
String from,
|
String from,
|
||||||
String to,
|
String to,
|
||||||
bool fixedRate,
|
bool fixedRate,
|
||||||
) async {
|
) async {
|
||||||
// TODO: implement getMinMaxExchangeAmounts
|
return await ChangeNowAPI.instance.getRange(
|
||||||
throw UnimplementedError();
|
fromTicker: from,
|
||||||
|
toTicker: to,
|
||||||
|
isFixedRate: fixedRate,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -67,8 +94,76 @@ class ChangeNowExchange extends Exchange {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ExchangeResponse<Trade>> getTrade(String tradeId) async {
|
Future<ExchangeResponse<Trade>> getTrade(String tradeId) async {
|
||||||
// TODO: implement getTrade
|
final response =
|
||||||
throw UnimplementedError();
|
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
|
@override
|
||||||
|
|
|
@ -18,10 +18,11 @@ abstract class Exchange {
|
||||||
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate);
|
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate);
|
||||||
|
|
||||||
Future<ExchangeResponse<Trade>> getTrade(String tradeId);
|
Future<ExchangeResponse<Trade>> getTrade(String tradeId);
|
||||||
|
Future<ExchangeResponse<Trade>> updateTrade(Trade trade);
|
||||||
|
|
||||||
Future<ExchangeResponse<List<Trade>>> getTrades();
|
Future<ExchangeResponse<List<Trade>>> getTrades();
|
||||||
|
|
||||||
Future<ExchangeResponse<Range>> getMinMaxExchangeAmounts(
|
Future<ExchangeResponse<Range>> getRange(
|
||||||
String from,
|
String from,
|
||||||
String to,
|
String to,
|
||||||
bool fixedRate,
|
bool fixedRate,
|
||||||
|
@ -32,6 +33,7 @@ abstract class Exchange {
|
||||||
String to,
|
String to,
|
||||||
Decimal amount,
|
Decimal amount,
|
||||||
bool fixedRate,
|
bool fixedRate,
|
||||||
|
bool reversed,
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<ExchangeResponse<Trade>> createTrade({
|
Future<ExchangeResponse<Trade>> createTrade({
|
||||||
|
|
|
@ -334,6 +334,7 @@ class SimpleSwapAPI {
|
||||||
Future<ExchangeResponse<Trade>> getExchange({
|
Future<ExchangeResponse<Trade>> getExchange({
|
||||||
required String exchangeId,
|
required String exchangeId,
|
||||||
String? apiKey,
|
String? apiKey,
|
||||||
|
Trade? oldTrade,
|
||||||
}) async {
|
}) async {
|
||||||
final uri = _buildUri(
|
final uri = _buildUri(
|
||||||
"/get_exchange",
|
"/get_exchange",
|
||||||
|
@ -349,7 +350,7 @@ class SimpleSwapAPI {
|
||||||
final json = Map<String, dynamic>.from(jsonObject as Map);
|
final json = Map<String, dynamic>.from(jsonObject as Map);
|
||||||
final ts = DateTime.parse(json["timestamp"] as String);
|
final ts = DateTime.parse(json["timestamp"] as String);
|
||||||
final trade = Trade(
|
final trade = Trade(
|
||||||
uuid: const Uuid().v1(),
|
uuid: oldTrade?.uuid ?? const Uuid().v1(),
|
||||||
tradeId: json["id"] as String,
|
tradeId: json["id"] as String,
|
||||||
rateType: json["type"] as String,
|
rateType: json["type"] as String,
|
||||||
direction: "direct",
|
direction: "direct",
|
||||||
|
|
|
@ -73,6 +73,7 @@ class SimpleSwapExchange extends Exchange {
|
||||||
String to,
|
String to,
|
||||||
Decimal amount,
|
Decimal amount,
|
||||||
bool fixedRate,
|
bool fixedRate,
|
||||||
|
bool reversed,
|
||||||
) async {
|
) async {
|
||||||
final response = await SimpleSwapAPI.instance.getEstimated(
|
final response = await SimpleSwapAPI.instance.getEstimated(
|
||||||
isFixedRate: fixedRate,
|
isFixedRate: fixedRate,
|
||||||
|
@ -88,7 +89,7 @@ class SimpleSwapExchange extends Exchange {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ExchangeResponse<Range>> getMinMaxExchangeAmounts(
|
Future<ExchangeResponse<Range>> getRange(
|
||||||
String from,
|
String from,
|
||||||
String to,
|
String to,
|
||||||
bool fixedRate,
|
bool fixedRate,
|
||||||
|
@ -114,6 +115,14 @@ class SimpleSwapExchange extends Exchange {
|
||||||
return await SimpleSwapAPI.instance.getExchange(exchangeId: tradeId);
|
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
|
@override
|
||||||
Future<ExchangeResponse<List<Trade>>> getTrades() async {
|
Future<ExchangeResponse<List<Trade>>> getTrades() async {
|
||||||
// TODO: implement getTrades
|
// TODO: implement getTrades
|
||||||
|
|
Loading…
Reference in a new issue