WIP connect tx flow

This commit is contained in:
julian 2023-01-06 16:31:36 -06:00
parent 0177784c22
commit e8ef0be977
2 changed files with 159 additions and 22 deletions

View file

@ -2,11 +2,18 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:stackwallet/models/paynym/paynym_account_lite.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/paynym/dialogs/confirm_paynym_connect_dialog.dart';
import 'package:stackwallet/pages/paynym/subwidgets/paynym_bot.dart';
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/services/coins/coin_paynym_extension.dart';
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -14,8 +21,9 @@ import 'package:stackwallet/widgets/custom_buttons/paynym_follow_toggle_button.d
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/loading_indicator.dart';
class PaynymDetailsPopup extends StatefulWidget {
class PaynymDetailsPopup extends ConsumerStatefulWidget {
const PaynymDetailsPopup({
Key? key,
required this.walletId,
@ -26,10 +34,103 @@ class PaynymDetailsPopup extends StatefulWidget {
final PaynymAccountLite accountLite;
@override
State<PaynymDetailsPopup> createState() => _PaynymDetailsPopupState();
ConsumerState<PaynymDetailsPopup> createState() => _PaynymDetailsPopupState();
}
class _PaynymDetailsPopupState extends ConsumerState<PaynymDetailsPopup> {
Future<void> _onConnectPressed() async {
bool canPop = false;
unawaited(
showDialog<void>(
context: context,
builder: (context) => WillPopScope(
onWillPop: () async => canPop,
child: const LoadingIndicator(
width: 200,
),
),
),
);
final wallet = ref
.read(walletsChangeNotifierProvider)
.getManager(widget.walletId)
.wallet as DogecoinWallet;
// sanity check to prevent second notifcation tx
if (wallet.hasConnectedConfirmed(widget.accountLite.code)) {
canPop = true;
Navigator.of(context).pop();
// TODO show info popup
return;
} else if (wallet.hasConnected(widget.accountLite.code)) {
canPop = true;
Navigator.of(context).pop();
// TODO show info popup
return;
}
final rates = await wallet.fees;
Map<String, dynamic> preparedTx;
try {
preparedTx = await wallet.buildNotificationTx(
selectedTxFeeRate: rates.medium,
targetPaymentCodeString: widget.accountLite.code,
);
} on InsufficientBalanceException catch (e) {
if (mounted) {
canPop = true;
Navigator.of(context).pop();
}
// TODO show info popup
print(e);
return;
}
if (mounted) {
// We have enough balance and prepared tx should be good to go.
canPop = true;
// close loading
Navigator.of(context).pop();
// Close details
Navigator.of(context).pop();
// show info pop up
await showDialog<void>(
context: context,
builder: (context) => ConfirmPaynymConnectDialog(
nymName: widget.accountLite.nymName,
onConfirmPressed: () {
//
print("CONFIRM NOTIF TX: $preparedTx");
Navigator.of(context).push(
RouteGenerator.getRoute(
builder: (_) => ConfirmTransactionView(
walletId: wallet.walletId,
transactionInfo: {
"hex": preparedTx["hex"],
"recipient": preparedTx["recipientPaynym"],
"recipientAmt": preparedTx["amount"],
"fee": preparedTx["fee"],
"vSize": preparedTx["vSize"],
"note": "PayNym connect"
},
),
),
);
},
amount: (preparedTx["amount"] as int) + (preparedTx["fee"] as int),
coin: wallet.coin,
),
);
}
}
class _PaynymDetailsPopupState extends State<PaynymDetailsPopup> {
@override
Widget build(BuildContext context) {
return DesktopDialog(
@ -75,9 +176,7 @@ class _PaynymDetailsPopupState extends State<PaynymDetailsPopup> {
),
iconSpacing: 4,
width: 86,
onPressed: () {
// todo notification tx
},
onPressed: _onConnectPressed,
),
],
),

View file

@ -15,6 +15,8 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:tuple/tuple.dart';
import '../../utilities/logger.dart';
class SWException with Exception {
SWException(this.message);
@ -180,7 +182,7 @@ extension PayNym on DogecoinWallet {
Map<String, dynamic> transactionObject = {
"hex": txn.item1,
"recipientPaynym": targetPaymentCodeString,
// "recipientAmt": recipientsAmtArray[0],
"amount": amountToSend,
"fee": feeBeingPaid,
"vSize": txn.item2,
};
@ -200,7 +202,7 @@ extension PayNym on DogecoinWallet {
Map<String, dynamic> transactionObject = {
"hex": txn.item1,
"recipientPaynym": targetPaymentCodeString,
// "recipientAmt": recipientsAmtArray[0],
"amount": amountToSend,
"fee": feeBeingPaid,
"vSize": txn.item2,
};
@ -221,7 +223,7 @@ extension PayNym on DogecoinWallet {
Map<String, dynamic> transactionObject = {
"hex": txn.item1,
"recipientPaynym": targetPaymentCodeString,
// "recipientAmt": recipientsAmtArray[0],
"amount": amountToSend,
"fee": feeBeingPaid,
"vSize": txn.item2,
};
@ -290,7 +292,7 @@ extension PayNym on DogecoinWallet {
final notificationScript = bscript.compile([bobP2PKH.output]);
// build a notification tx
final txb = TransactionBuilder();
final txb = TransactionBuilder(network: network);
txb.setVersion(1);
txb.addInput(
@ -330,20 +332,56 @@ extension PayNym on DogecoinWallet {
return Tuple2(builtTx.toHex(), builtTx.virtualSize());
}
Future<bool> hasConfirmedNotificationTxSentTo(
String paymentCodeString) async {
final targetPaymentCode =
PaymentCode.fromPaymentCode(paymentCodeString, network);
final targetNotificationAddress = targetPaymentCode.notificationAddress();
Future<String> confirmNotificationTx(
{required Map<String, dynamic> preparedTx}) async {
try {
Logging.instance.log("confirmNotificationTx txData: $preparedTx",
level: LogLevel.Info);
final txHash = await electrumXClient.broadcastTransaction(
rawTx: preparedTx["hex"] as String);
Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info);
final myTxHistory = (await transactionData)
.getAllTransactions()
.entries
.map((e) => e.value)
await updatePaynymNotificationInfo(
txid: txHash,
confirmed: false,
paymentCodeString: preparedTx["paymentCodeString"] as String,
);
return txHash;
} catch (e, s) {
Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s",
level: LogLevel.Error);
rethrow;
}
}
// Future<bool> hasConfirmedNotificationTxSentTo(
// String paymentCodeString) async {
// final targetPaymentCode =
// PaymentCode.fromPaymentCode(paymentCodeString, network);
// final targetNotificationAddress = targetPaymentCode.notificationAddress();
//
// final myTxHistory = (await transactionData)
// .getAllTransactions()
// .entries
// .map((e) => e.value)
// .where((e) =>
// e.txType == "Sent" && e.address == targetNotificationAddress);
//
// return myTxHistory.isNotEmpty;
// }
bool hasConnected(String paymentCodeString) {
return getPaynymNotificationTxInfo()
.where((e) => e["paymentCodeString"] == paymentCodeString)
.isNotEmpty;
}
bool hasConnectedConfirmed(String paymentCodeString) {
return getPaynymNotificationTxInfo()
.where((e) =>
e.txType == "Sent" && e.address == targetNotificationAddress);
return myTxHistory.isNotEmpty;
e["paymentCodeString"] == paymentCodeString &&
e["confirmed"] == true)
.isNotEmpty;
}
// fetch paynym notification tx meta data