mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 01:37:54 +00:00
WIP paynym ui and claim process
This commit is contained in:
parent
bbd04f46bb
commit
a491bfd70f
7 changed files with 218 additions and 27 deletions
|
@ -1,6 +1,12 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/pages/paynym/dialogs/claiming_paynym_dialog.dart';
|
||||
import 'package:stackwallet/providers/global/paynym_api_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.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';
|
||||
|
@ -9,18 +15,21 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
|||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
|
||||
import 'dialogs/claiming_paynym_dialog.dart';
|
||||
class PaynymClaimView extends ConsumerStatefulWidget {
|
||||
const PaynymClaimView({
|
||||
Key? key,
|
||||
required this.walletId,
|
||||
}) : super(key: key);
|
||||
|
||||
class PaynymClaimView extends StatefulWidget {
|
||||
const PaynymClaimView({Key? key}) : super(key: key);
|
||||
final String walletId;
|
||||
|
||||
static const String routeName = "/claimPaynym";
|
||||
|
||||
@override
|
||||
State<PaynymClaimView> createState() => _PaynymClaimViewState();
|
||||
ConsumerState<PaynymClaimView> createState() => _PaynymClaimViewState();
|
||||
}
|
||||
|
||||
class _PaynymClaimViewState extends State<PaynymClaimView> {
|
||||
class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
@ -81,6 +90,50 @@ class _PaynymClaimViewState extends State<PaynymClaimView> {
|
|||
);
|
||||
// generate and submit paynym to api
|
||||
|
||||
final wallet = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(widget.walletId)
|
||||
.wallet as DogecoinWallet;
|
||||
final pCode = await wallet.getPaymentCode();
|
||||
|
||||
final result = await ref
|
||||
.read(paynymAPIProvider)
|
||||
.create(pCode.toString());
|
||||
|
||||
// final result =
|
||||
// await ref.read(paynymAPIProvider).token(pCode.toString());
|
||||
|
||||
// final token =
|
||||
// "IlBNOFRKWWt1U2RZWEpud0RCcThDaGZpbmZYdjNzcnhoUXJ4M2VvRXdiU3c1MXdNamRvOUpKMkRzeWN3VDNndDN6SFE3Y1YxZ3J2YWJNbW1mMUJ0ajZmWTd0Z2tnU3o5QjhNWnVSM2tqWWZnTUxNVVJKQ1hOIg.FoPF3g.KUMZDC4U_ek-B6cqPLYilXniQv8";
|
||||
//
|
||||
// print("======================");
|
||||
// print(token);
|
||||
// print(token.codeUnits);
|
||||
// print(utf8.encode(token));
|
||||
// print(utf8.decode(token.codeUnits));
|
||||
//
|
||||
// print("======================");
|
||||
//
|
||||
// final signed = await wallet.signWithNotificationKey(
|
||||
// Uint8List.fromList(token.codeUnits));
|
||||
//
|
||||
// final signedString = Format.uint8listToString(signed);
|
||||
//
|
||||
// print("======================");
|
||||
// print(signed);
|
||||
// print(signedString);
|
||||
//
|
||||
// print("======================");
|
||||
|
||||
// final result2 = await ref
|
||||
// .read(paynymAPIProvider)
|
||||
// .claim(token, signedString);
|
||||
|
||||
// print("======================");
|
||||
// print(
|
||||
// result2); // {claimed: PM8TJYkuSdYXJnwDBq8ChfinfXv3srxhQrx3eoEwbSw51wMjdo9JJ2DsycwT3gt3zHQ7cV1grvabMmmf1Btj6fY7tgkgSz9B8MZuR3kjYfgMLMURJCXN, token: IlBNOFRKWWt1U2RZWEpud0RCcThDaGZpbmZYdjNzcnhoUXJ4M2VvRXdiU3c1MXdNamRvOUpKMkRzeWN3VDNndDN6SFE3Y1YxZ3J2YWJNbW1mMUJ0ajZmWTd0Z2tnU3o5QjhNWnVSM2tqWWZnTUxNVVJKQ1hOIg.FoPF3g.KUMZDC4U_ek-B6cqPLYilXniQv8}
|
||||
// print("======================");
|
||||
|
||||
await Future<void>.delayed(const Duration(seconds: 3));
|
||||
|
||||
if (mounted && !shouldCancel) {
|
||||
|
|
72
lib/pages/paynym/paynym_home_view.dart
Normal file
72
lib/pages/paynym/paynym_home_view.dart
Normal file
|
@ -0,0 +1,72 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||
|
||||
class PaynymHomeView extends StatefulWidget {
|
||||
const PaynymHomeView({
|
||||
Key? key,
|
||||
required this.walletId,
|
||||
required this.paymentCodeString,
|
||||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
final String paymentCodeString;
|
||||
|
||||
static const String routeName = "/paynymHome";
|
||||
|
||||
@override
|
||||
State<PaynymHomeView> createState() => _PaynymHomeViewState();
|
||||
}
|
||||
|
||||
class _PaynymHomeViewState extends State<PaynymHomeView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
final isDesktop = Util.isDesktop;
|
||||
|
||||
return MasterScaffold(
|
||||
isDesktop: isDesktop,
|
||||
appBar: AppBar(
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
titleSpacing: 0,
|
||||
title: Text(
|
||||
"PayNym",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
PayNymBot(
|
||||
paymentCodeString: widget.paymentCodeString,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PayNymBot extends StatelessWidget {
|
||||
const PayNymBot({
|
||||
Key? key,
|
||||
required this.paymentCodeString,
|
||||
}) : super(key: key);
|
||||
|
||||
final String paymentCodeString;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Image.network("https://paynym.is/$paymentCodeString/avatar");
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ class WalletNavigationBar extends StatefulWidget {
|
|||
required this.height,
|
||||
required this.enableExchange,
|
||||
required this.coin,
|
||||
required this.walletId,
|
||||
}) : super(key: key);
|
||||
|
||||
final VoidCallback onReceivePressed;
|
||||
|
@ -25,6 +26,7 @@ class WalletNavigationBar extends StatefulWidget {
|
|||
final double height;
|
||||
final bool enableExchange;
|
||||
final Coin coin;
|
||||
final String walletId;
|
||||
|
||||
@override
|
||||
State<WalletNavigationBar> createState() => _WalletNavigationBarState();
|
||||
|
@ -91,7 +93,10 @@ class _WalletNavigationBarState extends State<WalletNavigationBar> {
|
|||
setState(() {
|
||||
scale = 0;
|
||||
});
|
||||
Navigator.of(context).pushNamed(PaynymClaimView.routeName);
|
||||
Navigator.of(context).pushNamed(
|
||||
PaynymClaimView.routeName,
|
||||
arguments: widget.walletId,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
|
|
|
@ -716,6 +716,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
right: 16,
|
||||
),
|
||||
child: WalletNavigationBar(
|
||||
walletId: widget.walletId,
|
||||
coin: ref.watch(managerProvider
|
||||
.select((value) => value.coin)),
|
||||
enableExchange: Constants.enableExchange &&
|
||||
|
|
|
@ -37,6 +37,7 @@ import 'package:stackwallet/pages/intro_view.dart';
|
|||
import 'package:stackwallet/pages/manage_favorites_view/manage_favorites_view.dart';
|
||||
import 'package:stackwallet/pages/notification_views/notifications_view.dart';
|
||||
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
|
||||
import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
|
||||
import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart';
|
||||
import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart';
|
||||
import 'package:stackwallet/pages/receive_view/receive_view.dart';
|
||||
|
@ -189,10 +190,33 @@ class RouteGenerator {
|
|||
settings: RouteSettings(name: settings.name));
|
||||
|
||||
case PaynymClaimView.routeName:
|
||||
return getRoute(
|
||||
if (args is String) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => const PaynymClaimView(),
|
||||
settings: RouteSettings(name: settings.name));
|
||||
builder: (_) => PaynymClaimView(
|
||||
walletId: args,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case PaynymHomeView.routeName:
|
||||
if (args is Tuple2<String, String>) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => PaynymHomeView(
|
||||
walletId: args.item1,
|
||||
paymentCodeString: args.item2,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case GlobalSettingsView.routeName:
|
||||
return getRoute(
|
||||
|
|
37
lib/services/coins/coin_paynym_extension.dart
Normal file
37
lib/services/coins/coin_paynym_extension.dart
Normal file
|
@ -0,0 +1,37 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bip47/bip47.dart';
|
||||
import 'package:bitcoindart/bitcoindart.dart';
|
||||
import 'package:pointycastle/digests/sha256.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
||||
|
||||
extension PayNym on DogecoinWallet {
|
||||
// fetch or generate this wallet's bip47 payment code
|
||||
Future<PaymentCode> getPaymentCode() async {
|
||||
final paymentCodeString = DB.instance
|
||||
.get<dynamic>(boxName: walletId, key: "paymentCodeString") as String?;
|
||||
PaymentCode paymentCode;
|
||||
if (paymentCodeString == null) {
|
||||
final node = getBip32Root((await mnemonic).join(" "), network)
|
||||
.derivePath("m/47'/0'/0'");
|
||||
paymentCode =
|
||||
PaymentCode.initFromPubKey(node.publicKey, node.chainCode, network);
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: walletId,
|
||||
key: "paymentCodeString",
|
||||
value: paymentCode.toString());
|
||||
} else {
|
||||
paymentCode = PaymentCode.fromPaymentCode(paymentCodeString, network);
|
||||
}
|
||||
return paymentCode;
|
||||
}
|
||||
|
||||
Future<Uint8List> signWithNotificationKey(Uint8List data) async {
|
||||
final node = getBip32Root((await mnemonic).join(" "), network)
|
||||
.derivePath("m/47'/0'/0'");
|
||||
final pair = ECPair.fromPrivateKey(node.privateKey!, network: network);
|
||||
final signed = pair.sign(SHA256Digest().process(data));
|
||||
return signed;
|
||||
}
|
||||
}
|
|
@ -135,7 +135,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
|
||||
late final TransactionNotificationTracker txTracker;
|
||||
|
||||
NetworkType get _network {
|
||||
NetworkType get network {
|
||||
switch (coin) {
|
||||
case Coin.dogecoin:
|
||||
return dogecoin;
|
||||
|
@ -266,7 +266,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
// Base58check decode fail
|
||||
}
|
||||
if (decodeBase58 != null) {
|
||||
if (decodeBase58[0] == _network.pubKeyHash) {
|
||||
if (decodeBase58[0] == network.pubKeyHash) {
|
||||
// P2PKH
|
||||
return DerivePathType.bip44;
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
} catch (err) {
|
||||
// Bech32 decode fail
|
||||
}
|
||||
if (_network.bech32 != decodeBech32!.hrp) {
|
||||
if (network.bech32 != decodeBech32!.hrp) {
|
||||
throw ArgumentError('Invalid prefix or Network mismatch');
|
||||
}
|
||||
if (decodeBech32.version != 0) {
|
||||
|
@ -385,8 +385,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
switch (type) {
|
||||
case DerivePathType.bip44:
|
||||
address = P2PKH(
|
||||
data: PaymentData(pubkey: node.publicKey),
|
||||
network: _network)
|
||||
data: PaymentData(pubkey: node.publicKey), network: network)
|
||||
.data
|
||||
.address!;
|
||||
break;
|
||||
|
@ -472,7 +471,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
Map<String, Map<String, String>> p2pkhReceiveDerivations = {};
|
||||
Map<String, Map<String, String>> p2pkhChangeDerivations = {};
|
||||
|
||||
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network));
|
||||
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, network));
|
||||
|
||||
List<String> p2pkhReceiveAddressArray = [];
|
||||
int p2pkhReceiveIndex = -1;
|
||||
|
@ -1104,7 +1103,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
|
||||
@override
|
||||
bool validateAddress(String address) {
|
||||
return Address.validateAddress(address, _network);
|
||||
return Address.validateAddress(address, network);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1358,7 +1357,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
chain,
|
||||
index,
|
||||
mnemonic!,
|
||||
_network,
|
||||
network,
|
||||
derivePathType,
|
||||
),
|
||||
);
|
||||
|
@ -1367,7 +1366,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
|
||||
switch (derivePathType) {
|
||||
case DerivePathType.bip44:
|
||||
address = P2PKH(data: data, network: _network).data.address!;
|
||||
address = P2PKH(data: data, network: network).data.address!;
|
||||
break;
|
||||
// default:
|
||||
// // should never hit this due to all enum cases handled
|
||||
|
@ -1601,7 +1600,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
if (batches[batchNumber] == null) {
|
||||
batches[batchNumber] = {};
|
||||
}
|
||||
final scripthash = _convertToScriptHash(allAddresses[i], _network);
|
||||
final scripthash = _convertToScriptHash(allAddresses[i], network);
|
||||
batches[batchNumber]!.addAll({
|
||||
scripthash: [scripthash]
|
||||
});
|
||||
|
@ -1761,7 +1760,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
Future<int> getTxCount({required String address}) async {
|
||||
String? scripthash;
|
||||
try {
|
||||
scripthash = _convertToScriptHash(address, _network);
|
||||
scripthash = _convertToScriptHash(address, network);
|
||||
final transactions =
|
||||
await electrumXClient.getHistory(scripthash: scripthash);
|
||||
return transactions.length;
|
||||
|
@ -1779,7 +1778,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
try {
|
||||
final Map<String, List<dynamic>> args = {};
|
||||
for (final entry in addresses.entries) {
|
||||
args[entry.key] = [_convertToScriptHash(entry.value, _network)];
|
||||
args[entry.key] = [_convertToScriptHash(entry.value, network)];
|
||||
}
|
||||
final response = await electrumXClient.getBatchHistory(args: args);
|
||||
|
||||
|
@ -1971,7 +1970,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
if (batches[batchNumber] == null) {
|
||||
batches[batchNumber] = {};
|
||||
}
|
||||
final scripthash = _convertToScriptHash(allAddresses[i], _network);
|
||||
final scripthash = _convertToScriptHash(allAddresses[i], network);
|
||||
final id = Logger.isTestEnv ? "$i" : const Uuid().v1();
|
||||
requestIdToAddressMap[id] = allAddresses[i];
|
||||
batches[batchNumber]!.addAll({
|
||||
|
@ -2746,7 +2745,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(
|
||||
receiveDerivation["pubKey"] as String)),
|
||||
network: _network,
|
||||
network: network,
|
||||
).data;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
|
@ -2754,7 +2753,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
receiveDerivation["wif"] as String,
|
||||
network: _network,
|
||||
network: network,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
@ -2767,7 +2766,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
network: _network,
|
||||
network: network,
|
||||
).data;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
|
@ -2775,7 +2774,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
changeDerivation["wif"] as String,
|
||||
network: _network,
|
||||
network: network,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
@ -2802,7 +2801,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
Logging.instance
|
||||
.log("Starting buildTransaction ----------", level: LogLevel.Info);
|
||||
|
||||
final txb = TransactionBuilder(network: _network);
|
||||
final txb = TransactionBuilder(network: network);
|
||||
txb.setVersion(1);
|
||||
|
||||
// Add transaction inputs
|
||||
|
|
Loading…
Reference in a new issue