Implement HTTP sending and use Julian's error checking

This commit is contained in:
Likho 2022-09-01 16:17:46 -05:00
parent 91b4fdf450
commit cfcd7a7928
2 changed files with 152 additions and 53 deletions

View file

@ -1,12 +1,17 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
@ -40,25 +45,25 @@ class _ConfirmTransactionViewState
late final String routeOnSuccessName; late final String routeOnSuccessName;
Future<void> _attemptSend(BuildContext context) async { Future<void> _attemptSend(BuildContext context) async {
showDialog<dynamic>( unawaited(showDialog<dynamic>(
context: context, context: context,
useSafeArea: false, useSafeArea: false,
barrierDismissible: false, barrierDismissible: false,
builder: (context) { builder: (context) {
return const SendingTransactionDialog(); return const SendingTransactionDialog();
}, },
); ));
final note = transactionInfo["note"] as String? ?? ""; final note = transactionInfo["note"] as String? ?? "";
final manager = final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId); ref.read(walletsChangeNotifierProvider).getManager(walletId);
try { try {
final txid = await manager.confirmSend(txData: transactionInfo); final txid = await manager.confirmSend(txData: transactionInfo);
manager.refresh(); unawaited(manager.refresh());
// save note // save note
ref await ref
.read(notesServiceChangeNotifierProvider(walletId)) .read(notesServiceChangeNotifierProvider(walletId))
.editOrAddNote(txid: txid, note: note); .editOrAddNote(txid: txid, note: note);
@ -66,12 +71,26 @@ class _ConfirmTransactionViewState
if (mounted) { if (mounted) {
Navigator.of(context).popUntil(ModalRoute.withName(routeOnSuccessName)); Navigator.of(context).popUntil(ModalRoute.withName(routeOnSuccessName));
} }
} on BadEpicHttpAddressException catch (_) {
if (mounted) {
// pop building dialog
Navigator.of(context).pop();
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message:
"Connection failed. Please check the address and try again.",
context: context,
),
);
return;
}
} catch (e, s) { } catch (e, s) {
debugPrint("$e\n$s"); debugPrint("$e\n$s");
// pop sending dialog // pop sending dialog
Navigator.of(context).pop(); Navigator.of(context).pop();
showDialog<void>( await showDialog<void>(
context: context, context: context,
useSafeArea: false, useSafeArea: false,
barrierDismissible: true, barrierDismissible: true,
@ -81,10 +100,10 @@ class _ConfirmTransactionViewState
message: e.toString(), message: e.toString(),
rightButton: TextButton( rightButton: TextButton(
style: Theme.of(context).textButtonTheme.style?.copyWith( style: Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>( backgroundColor: MaterialStateProperty.all<Color>(
CFColors.buttonGray, CFColors.buttonGray,
), ),
), ),
child: Text( child: Text(
"Ok", "Ok",
style: STextStyles.button.copyWith( style: STextStyles.button.copyWith(
@ -193,9 +212,9 @@ class _ConfirmTransactionViewState
.select((value) => value.locale), .select((value) => value.locale),
), ),
)} ${ref.watch( )} ${ref.watch(
managerProvider managerProvider
.select((value) => value.coin), .select((value) => value.coin),
).ticker}", ).ticker}",
style: STextStyles.itemSubtitle12, style: STextStyles.itemSubtitle12,
textAlign: TextAlign.right, textAlign: TextAlign.right,
), ),
@ -221,9 +240,9 @@ class _ConfirmTransactionViewState
.select((value) => value.locale), .select((value) => value.locale),
), ),
)} ${ref.watch( )} ${ref.watch(
managerProvider managerProvider
.select((value) => value.coin), .select((value) => value.coin),
).ticker}", ).ticker}",
style: STextStyles.itemSubtitle12, style: STextStyles.itemSubtitle12,
textAlign: TextAlign.right, textAlign: TextAlign.right,
), ),
@ -273,9 +292,9 @@ class _ConfirmTransactionViewState
.select((value) => value.locale), .select((value) => value.locale),
), ),
)} ${ref.watch( )} ${ref.watch(
managerProvider managerProvider
.select((value) => value.coin), .select((value) => value.coin),
).ticker}", ).ticker}",
style: STextStyles.itemSubtitle12, style: STextStyles.itemSubtitle12,
textAlign: TextAlign.right, textAlign: TextAlign.right,
), ),
@ -287,18 +306,18 @@ class _ConfirmTransactionViewState
), ),
TextButton( TextButton(
style: style:
Theme.of(context).textButtonTheme.style?.copyWith( Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: backgroundColor:
MaterialStateProperty.all<Color>( MaterialStateProperty.all<Color>(
CFColors.stackAccent, CFColors.stackAccent,
), ),
), ),
onPressed: () async { onPressed: () async {
final unlocked = await Navigator.push( final unlocked = await Navigator.push(
context, context,
RouteGenerator.getRoute( RouteGenerator.getRoute(
shouldUseMaterialRoute: shouldUseMaterialRoute:
RouteGenerator.useMaterialPageRoute, RouteGenerator.useMaterialPageRoute,
builder: (_) => const LockscreenView( builder: (_) => const LockscreenView(
showBackButton: true, showBackButton: true,
popOnSuccess: true, popOnSuccess: true,
@ -306,9 +325,9 @@ class _ConfirmTransactionViewState
routeOnSuccess: "", routeOnSuccess: "",
biometricsCancelButtonString: "CANCEL", biometricsCancelButtonString: "CANCEL",
biometricsLocalizedReason: biometricsLocalizedReason:
"Authenticate to send transaction", "Authenticate to send transaction",
biometricsAuthenticationTitle: biometricsAuthenticationTitle:
"Confirm Transaction", "Confirm Transaction",
), ),
settings: const RouteSettings( settings: const RouteSettings(
name: "/confirmsendlockscreen"), name: "/confirmsendlockscreen"),
@ -316,7 +335,7 @@ class _ConfirmTransactionViewState
); );
if (unlocked is bool && unlocked && mounted) { if (unlocked is bool && unlocked && mounted) {
_attemptSend(context); unawaited(_attemptSend(context));
} }
}, },
child: Text( child: Text(

View file

@ -40,6 +40,17 @@ const int MINIMUM_CONFIRMATIONS = 10;
const String GENESIS_HASH_MAINNET = ""; const String GENESIS_HASH_MAINNET = "";
const String GENESIS_HASH_TESTNET = ""; const String GENESIS_HASH_TESTNET = "";
class BadEpicHttpAddressException implements Exception {
final String? message;
BadEpicHttpAddressException({this.message});
@override
String toString() {
return "BadEpicHttpAddressException: $message";
}
}
// isolate // isolate
Map<ReceivePort, Isolate> isolates = {}; Map<ReceivePort, Isolate> isolates = {};
@ -185,6 +196,29 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
sendPort.send(result); sendPort.send(result);
return; return;
} }
} else if (function == "txHttpSend") {
final wallet = arguments['wallet'] as String?;
final selectionStrategyIsAll = arguments['selectionStrategyIsAll'] as int?;
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
final message = arguments['message'] as String?;
final amount = arguments['amount'] as int?;
final address = arguments['address'] as String?;
Map<String, dynamic> result = {};
if (!(wallet == null ||
selectionStrategyIsAll == null ||
minimumConfirmations == null ||
message == null ||
amount == null ||
address == null)) {
var res = await txHttpSend(wallet, selectionStrategyIsAll,
minimumConfirmations, message, amount, address);
result['result'] = res;
sendPort.send(result);
return;
}
} }
Logging.instance.log( Logging.instance.log(
"Error Arguments for $function not formatted correctly", "Error Arguments for $function not formatted correctly",
@ -717,32 +751,67 @@ class EpicCashWallet extends CoinServiceAPI {
// TODO determine whether it is worth sending change to a change address. // TODO determine whether it is worth sending change to a change address.
dynamic message; dynamic message;
await m.protect(() async {
ReceivePort receivePort = await getIsolate({
"function": "createTransaction",
"wallet": wallet!,
"amount": txData['recipientAmt'],
"address": txData['addresss'],
"secretKeyIndex": 0,
"epicboxConfig": epicboxConfig!,
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
}, name: walletName);
message = await receivePort.first; String receiverAddress = txData['addresss'] as String;
if (message is String) { await m.protect(() async {
Logging.instance
.log("this is a string $message", level: LogLevel.Error); if (receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://")) {
const int selectionStrategyIsAll = 0;
ReceivePort receivePort = await getIsolate({
"function": "txHttpSend",
"wallet": wallet!,
"selectionStrategyIsAll": selectionStrategyIsAll,
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
"message": "",
"amount": txData['recipientAmt'],
"address": txData['addresss']
}, name: walletName);
message = await receivePort.first;
if (message is String) {
Logging.instance
.log("this is a string $message", level: LogLevel.Error);
stop(receivePort);
throw Exception("txHttpSend isolate failed");
}
stop(receivePort); stop(receivePort);
throw Exception("createTransaction isolate failed"); Logging.instance.log('Closing txHttpSend!\n $message',
level: LogLevel.Info);
} else {
ReceivePort receivePort = await getIsolate({
"function": "createTransaction",
"wallet": wallet!,
"amount": txData['recipientAmt'],
"address": txData['addresss'],
"secretKeyIndex": 0,
"epicboxConfig": epicboxConfig!,
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
}, name: walletName);
message = await receivePort.first;
if (message is String) {
Logging.instance
.log("this is a string $message", level: LogLevel.Error);
stop(receivePort);
throw Exception("createTransaction isolate failed");
}
stop(receivePort);
Logging.instance.log('Closing createTransaction!\n $message',
level: LogLevel.Info);
} }
stop(receivePort);
Logging.instance.log('Closing createTransaction!\n $message',
level: LogLevel.Info);
}); });
// return message; // return message;
final String sendTx = message['result'] as String; final String sendTx = message['result'] as String;
await putSendToAddresses(sendTx); if (sendTx.contains("Error")) {
throw BadEpicHttpAddressException(message: sendTx);
}
if (!(receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://"))) {
await putSendToAddresses(sendTx);
}
Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info); Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info);
@ -752,11 +821,16 @@ class EpicCashWallet extends CoinServiceAPI {
String errorMessage = decodeData[1] as String; String errorMessage = decodeData[1] as String;
throw Exception("Transaction failed with error code $errorMessage"); throw Exception("Transaction failed with error code $errorMessage");
} else { } else {
final postSlateRequest = decodeData[1];
final postToServer = await postSlate( //If it's HTTP send no need to post to epicbox
txData['addresss'] as String, postSlateRequest as String); if (!(receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://"))) {
Logging.instance final postSlateRequest = decodeData[1];
.log("POST_SLATE_IS $postToServer", level: LogLevel.Info); final postToServer = await postSlate(
txData['addresss'] as String, postSlateRequest as String);
Logging.instance
.log("POST_SLATE_IS $postToServer", level: LogLevel.Info);
}
final txCreateResult = decodeData[0]; final txCreateResult = decodeData[0];
// //TODO: second problem // //TODO: second problem
final transaction = json.decode(txCreateResult as String); final transaction = json.decode(txCreateResult as String);
@ -2195,6 +2269,12 @@ class EpicCashWallet extends CoinServiceAPI {
@override @override
bool validateAddress(String address) { bool validateAddress(String address) {
if (address.startsWith("http://") || address.startsWith("https://")) {
if (Uri.tryParse(address) != null) {
return true;
}
}
String validate = validateSendAddress(address); String validate = validateSendAddress(address);
if (int.parse(validate) == 1) { if (int.parse(validate) == 1) {
return true; return true;