changenow reverse fixed rate trade support

This commit is contained in:
julian 2022-10-03 18:55:12 -06:00
parent bb12e149f6
commit a8396977ef
11 changed files with 54 additions and 102 deletions

View file

@ -13,6 +13,8 @@ class IncompleteExchangeModel {
final ExchangeRateType rateType;
final bool reversed;
String? recipientAddress;
String? refundAddress;
@ -27,6 +29,7 @@ class IncompleteExchangeModel {
required this.sendAmount,
required this.receiveAmount,
required this.rateType,
required this.reversed,
this.rateId,
});
}

View file

@ -202,12 +202,13 @@ class Trade {
);
}
factory Trade.fromExchangeTransaction(ExchangeTransaction exTx) {
factory Trade.fromExchangeTransaction(
ExchangeTransaction exTx, bool reversed) {
return Trade(
uuid: exTx.uuid,
tradeId: exTx.id,
rateType: "",
direction: "direct",
direction: reversed ? "reverse" : "direct",
timestamp: exTx.date,
updatedAt: DateTime.tryParse(exTx.statusObject!.updatedAt) ?? exTx.date,
payInCurrency: exTx.fromCurrency,

View file

@ -21,7 +21,6 @@ import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.
import 'package:stackwallet/pages/exchange_view/sub_widgets/rate_type_toggle.dart';
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
import 'package:stackwallet/providers/providers.dart';
@ -530,37 +529,20 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
final rateType = ref.read(prefsChangeNotifierProvider).exchangeRateType;
final response = await ref.read(changeNowProvider).getEstimate(
fromTicker,
toTicker,
sendAmount,
false,
false,
);
if (response.value == null) {
unawaited(showDialog<dynamic>(
context: context,
barrierDismissible: true,
builder: (_) => StackDialog(
title: "Failed to update trade estimate",
message: response.exception?.toString(),
),
));
return;
}
final estimate = ref.read(exchangeFormStateProvider).estimate!;
String rate =
"1 ${fromTicker.toUpperCase()} ~${(response.value!.estimatedAmount / sendAmount).toDecimal(scaleOnInfinitePrecision: 8).toStringAsFixed(8)} ${toTicker.toUpperCase()}";
"1 ${fromTicker.toUpperCase()} ~${(estimate.estimatedAmount / sendAmount).toDecimal(scaleOnInfinitePrecision: 8).toStringAsFixed(8)} ${toTicker.toUpperCase()}";
final model = IncompleteExchangeModel(
sendTicker: fromTicker.toUpperCase(),
receiveTicker: toTicker.toUpperCase(),
rateInfo: rate,
sendAmount: sendAmount,
receiveAmount: response.value!.estimatedAmount,
receiveAmount: estimate.estimatedAmount,
rateType: rateType,
rateId: response.value!.rateId,
rateId: estimate.rateId,
reversed: estimate.reversed,
);
if (mounted) {
@ -587,35 +569,19 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
final rateType = ref.read(prefsChangeNotifierProvider).exchangeRateType;
final response = await ref.read(changeNowProvider).getEstimate(
fromTicker,
toTicker,
sendAmount,
true,
false,
);
final estimate = ref.read(exchangeFormStateProvider).estimate!;
bool? shouldCancel;
if (response.value == null) {
unawaited(showDialog<dynamic>(
context: context,
barrierDismissible: true,
builder: (_) => StackDialog(
title: "Failed to update trade estimate",
message: response.exception?.toString(),
),
));
return;
} else if (response.value!.warningMessage != null &&
response.value!.warningMessage!.isNotEmpty) {
if (estimate.warningMessage != null &&
estimate.warningMessage!.isNotEmpty) {
shouldCancel = await showDialog<bool?>(
context: context,
barrierDismissible: true,
builder: (_) => StackDialog(
title: "Failed to update trade estimate",
message:
"${response.value!.warningMessage!}\n\nDo you want to attempt trade anyways?",
"${estimate.warningMessage!}\n\nDo you want to attempt trade anyways?",
leftButton: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
@ -657,10 +623,13 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
sendTicker: fromTicker,
receiveTicker: toTicker,
rateInfo: rate,
sendAmount: sendAmount,
receiveAmount: response.value!.estimatedAmount,
sendAmount: estimate.reversed ? estimate.estimatedAmount : sendAmount,
receiveAmount: estimate.reversed
? ref.read(exchangeFormStateProvider).toAmount!
: estimate.estimatedAmount,
rateType: rateType,
rateId: response.value!.rateId,
rateId: estimate.rateId,
reversed: estimate.reversed,
);
if (mounted) {

View file

@ -348,23 +348,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
"sendViewScanQrButtonKey"),
onTap: () async {
try {
// ref
// .read(
// shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = false;
final qrResult =
await scanner.scan();
// Future<void>.delayed(
// const Duration(seconds: 2),
// () => ref
// .read(
// shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = true,
// );
final results =
AddressUtils.parseUri(
qrResult.rawContent);
@ -385,16 +371,10 @@ class _Step2ViewState extends ConsumerState<Step2View> {
setState(() {});
}
} on PlatformException catch (e, s) {
// ref
// .read(
// shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = true;
// here we ignore the exception caused by not giving permission
// to use the camera to scan a qr code
Logging.instance.log(
"Failed to get camera permissions while trying to scan qr code in SendView: $e\n$s",
level: LogLevel.Warning);
"Failed to get camera permissions while trying to scan qr code in SendView: $e\n$s",
level: LogLevel.Warning,
);
}
},
child: const QrCodeIcon(),
@ -585,23 +565,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
"sendViewScanQrButtonKey"),
onTap: () async {
try {
// ref
// .read(
// shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = false;
final qrResult =
await scanner.scan();
// Future<void>.delayed(
// const Duration(seconds: 2),
// () => ref
// .read(
// shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = true,
// );
final results =
AddressUtils.parseUri(
qrResult.rawContent);
@ -622,16 +588,10 @@ class _Step2ViewState extends ConsumerState<Step2View> {
setState(() {});
}
} on PlatformException catch (e, s) {
// ref
// .read(
// shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = true;
// here we ignore the exception caused by not giving permission
// to use the camera to scan a qr code
Logging.instance.log(
"Failed to get camera permissions while trying to scan qr code in SendView: $e\n$s",
level: LogLevel.Warning);
"Failed to get camera permissions while trying to scan qr code in SendView: $e\n$s",
level: LogLevel.Warning,
);
}
},
child: const QrCodeIcon(),
@ -680,8 +640,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
child: TextButton(
onPressed: () {
Navigator.of(context).pushNamed(
Step3View.routeName,
arguments: model);
Step3View.routeName,
arguments: model,
);
},
style: Theme.of(context)
.extension<StackColors>()!

View file

@ -251,10 +251,15 @@ class _Step3ViewState extends ConsumerState<Step3View> {
to: model.receiveTicker,
fixedRate: model.rateType !=
ExchangeRateType.estimated,
amount: model.sendAmount,
amount: model.reversed
? model.receiveAmount
: model.sendAmount,
addressTo: model.recipientAddress!,
extraId: null,
addressRefund: model.refundAddress!,
refundExtraId: "",
rateId: model.rateId,
reversed: model.reversed,
);
if (response.value == null) {

View file

@ -1198,7 +1198,7 @@ abstract class SWB {
Trade trade;
if (exTx != null) {
trade = Trade.fromExchangeTransaction(exTx);
trade = Trade.fromExchangeTransaction(exTx, false);
} else {
trade = Trade.fromMap(trades[i] as Map<String, dynamic>);
}
@ -1220,7 +1220,7 @@ abstract class SWB {
Trade trade;
if (exTx != null) {
trade = Trade.fromExchangeTransaction(exTx);
trade = Trade.fromExchangeTransaction(exTx, false);
} else {
trade = Trade.fromMap(trades.last as Map<String, dynamic>);
}

View file

@ -678,6 +678,7 @@ class ChangeNowAPI {
required String receivingAddress,
required Decimal amount,
required String rateId,
required bool reversed,
String extraId = "",
String userId = "",
String contactEmail = "",
@ -689,7 +690,6 @@ class ChangeNowAPI {
"from": fromTicker,
"to": toTicker,
"address": receivingAddress,
"amount": amount.toString(),
"flow": "fixed-rate",
"extraId": extraId,
"userId": userId,
@ -699,8 +699,16 @@ class ChangeNowAPI {
"rateId": rateId,
};
if (reversed) {
map["result"] = amount.toString();
} else {
map["amount"] = amount.toString();
}
final uri = _buildUri(
"/transactions/fixed-rate/${apiKey ?? kChangeNowApiKey}", null);
"/transactions/fixed-rate${reversed ? "/from-result" : ""}/${apiKey ?? kChangeNowApiKey}",
null,
);
try {
// simple json object is expected here

View file

@ -27,6 +27,7 @@ class ChangeNowExchange extends Exchange {
required String addressRefund,
required String refundExtraId,
String? rateId,
required bool reversed,
}) async {
late final ExchangeResponse<ExchangeTransaction> response;
if (fixedRate) {
@ -39,6 +40,7 @@ class ChangeNowExchange extends Exchange {
extraId: extraId ?? "",
refundAddress: addressRefund,
refundExtraId: refundExtraId,
reversed: reversed,
);
} else {
response = await ChangeNowAPI.instance.createStandardExchangeTransaction(
@ -66,6 +68,7 @@ class ChangeNowExchange extends Exchange {
response.value!.copyWith(
statusObject: statusResponse.value!,
),
reversed,
),
);
}

View file

@ -47,5 +47,6 @@ abstract class Exchange {
required String addressRefund,
required String refundExtraId,
String? rateId,
required bool reversed,
});
}

View file

@ -25,6 +25,7 @@ class SimpleSwapExchange extends Exchange {
required String addressRefund,
required String refundExtraId,
String? rateId,
required bool reversed,
}) async {
return await SimpleSwapAPI.instance.createNewExchange(
isFixedRate: fixedRate,

View file

@ -128,7 +128,7 @@ class DbVersionMigrator {
for (final old in trades) {
if (old.statusObject != null) {
final trade = Trade.fromExchangeTransaction(old);
final trade = Trade.fromExchangeTransaction(old, false);
await DB.instance.put<Trade>(
boxName: DB.boxNameTradesV2,
key: trade.uuid,