Skip to content

Commit 665e21c

Browse files
Merge pull request #1294 from cypherstack/fix/paynym
Fix PayNyms: use PayNym.rs
2 parents 2a37aeb + cf7251b commit 665e21c

13 files changed

Lines changed: 996 additions & 469 deletions

File tree

lib/models/paynym/paynym_account_lite.dart

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,57 @@
1-
/*
1+
/*
22
* This file is part of Stack Wallet.
3-
*
3+
*
44
* Copyright (c) 2023 Cypher Stack
55
* All Rights Reserved.
66
* The code is distributed under GPLv3 license, see LICENSE file for details.
77
* Generated by Cypher Stack on 2023-05-26
88
*
99
*/
1010

11+
import 'package:bip47/bip47.dart';
12+
import 'package:bitcoindart/bitcoindart.dart' as bitcoindart;
13+
1114
class PaynymAccountLite {
1215
final String nymId;
1316
final String nymName;
1417
final String code;
1518
final bool segwit;
19+
final bool taproot;
1620

1721
PaynymAccountLite(
1822
this.nymId,
1923
this.nymName,
2024
this.code,
21-
this.segwit,
22-
);
25+
this.segwit, {
26+
this.taproot = false,
27+
});
2328

2429
PaynymAccountLite.fromMap(Map<String, dynamic> map)
25-
: nymId = map["nymId"] as String,
26-
nymName = map["nymName"] as String,
27-
code = map["code"] as String,
28-
segwit = map["segwit"] as bool;
30+
: nymId = map["nymId"] as String,
31+
nymName = map["nymName"] as String,
32+
code = map["code"] as String,
33+
segwit = map["segwit"] as bool,
34+
taproot = map["taproot"] as bool? ?? inferTaproot(map["code"] as String);
35+
36+
static bool inferTaproot(String paymentCodeString) {
37+
try {
38+
final pCode = PaymentCode.fromPaymentCode(
39+
paymentCodeString,
40+
networkType: bitcoindart.bitcoin,
41+
);
42+
return pCode.isTaprootEnabled();
43+
} catch (_) {
44+
return false;
45+
}
46+
}
2947

3048
Map<String, dynamic> toMap() => {
31-
"nymId": nymId,
32-
"nymName": nymName,
33-
"code": code,
34-
"segwit": segwit,
35-
};
49+
"nymId": nymId,
50+
"nymName": nymName,
51+
"code": code,
52+
"segwit": segwit,
53+
"taproot": taproot,
54+
};
3655

3756
@override
3857
String toString() {

lib/models/paynym/paynym_claim.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,10 @@ class PaynymClaim {
1515
PaynymClaim(this.claimed, this.token);
1616

1717
PaynymClaim.fromMap(Map<String, dynamic> map)
18-
: claimed = map["claimed"] as String,
19-
token = map["token"] as String;
18+
: claimed = map["claimed"].toString(),
19+
token = map["token"] as String;
2020

21-
Map<String, dynamic> toMap() => {
22-
"claimed": claimed,
23-
"token": token,
24-
};
21+
Map<String, dynamic> toMap() => {"claimed": claimed, "token": token};
2522

2623
@override
2724
String toString() {

lib/pages/paynym/paynym_claim_view.dart

Lines changed: 92 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,7 @@ import 'dialogs/claiming_paynym_dialog.dart';
3232
import 'paynym_home_view.dart';
3333

3434
class PaynymClaimView extends ConsumerStatefulWidget {
35-
const PaynymClaimView({
36-
super.key,
37-
required this.walletId,
38-
});
35+
const PaynymClaimView({super.key, required this.walletId});
3936

4037
final String walletId;
4138

@@ -80,23 +77,20 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
8077
leading: Row(
8178
children: [
8279
Padding(
83-
padding: const EdgeInsets.only(
84-
left: 24,
85-
right: 20,
86-
),
80+
padding: const EdgeInsets.only(left: 24, right: 20),
8781
child: AppBarIconButton(
8882
size: 32,
89-
color: Theme.of(context)
90-
.extension<StackColors>()!
91-
.textFieldDefaultBG,
83+
color: Theme.of(
84+
context,
85+
).extension<StackColors>()!.textFieldDefaultBG,
9286
shadows: const [],
9387
icon: SvgPicture.asset(
9488
Assets.svg.arrowLeft,
9589
width: 18,
9690
height: 18,
97-
color: Theme.of(context)
98-
.extension<StackColors>()!
99-
.topNavIconPrimary,
91+
color: Theme.of(
92+
context,
93+
).extension<StackColors>()!.topNavIconPrimary,
10094
),
10195
onPressed: Navigator.of(context).pop,
10296
),
@@ -107,13 +101,8 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
107101
height: 42,
108102
color: Theme.of(context).extension<StackColors>()!.textDark,
109103
),
110-
const SizedBox(
111-
width: 10,
112-
),
113-
Text(
114-
"PayNym",
115-
style: STextStyles.desktopH3(context),
116-
),
104+
const SizedBox(width: 10),
105+
Text("PayNym", style: STextStyles.desktopH3(context)),
117106
],
118107
),
119108
)
@@ -129,52 +118,36 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
129118
body: ConditionalParent(
130119
condition: !isDesktop,
131120
builder: (child) => SafeArea(
132-
child: Padding(
133-
padding: const EdgeInsets.all(16),
134-
child: child,
135-
),
121+
child: Padding(padding: const EdgeInsets.all(16), child: child),
136122
),
137123
child: ConditionalParent(
138124
condition: isDesktop,
139-
builder: (child) => SizedBox(
140-
width: 328,
141-
child: child,
142-
),
125+
builder: (child) => SizedBox(width: 328, child: child),
143126
child: Column(
144127
children: [
145-
const Spacer(
146-
flex: 1,
147-
),
128+
const Spacer(flex: 1),
148129
SvgPicture.asset(
149130
Assets.svg.unclaimedPaynym,
150131
width: MediaQuery.of(context).size.width / 2,
151132
),
152-
const SizedBox(
153-
height: 20,
154-
),
133+
const SizedBox(height: 20),
155134
Text(
156135
"You do not have a PayNym yet.\nClaim yours now!",
157136
style: isDesktop
158137
? STextStyles.desktopSubtitleH2(context).copyWith(
159-
color: Theme.of(context)
160-
.extension<StackColors>()!
161-
.textSubtitle1,
138+
color: Theme.of(
139+
context,
140+
).extension<StackColors>()!.textSubtitle1,
162141
)
163142
: STextStyles.baseXS(context).copyWith(
164-
color: Theme.of(context)
165-
.extension<StackColors>()!
166-
.textSubtitle1,
143+
color: Theme.of(
144+
context,
145+
).extension<StackColors>()!.textSubtitle1,
167146
),
168147
textAlign: TextAlign.center,
169148
),
170-
if (isDesktop)
171-
const SizedBox(
172-
height: 30,
173-
),
174-
if (!isDesktop)
175-
const Spacer(
176-
flex: 2,
177-
),
149+
if (isDesktop) const SizedBox(height: 30),
150+
if (!isDesktop) const Spacer(flex: 2),
178151
PrimaryButton(
179152
label: "Claim",
180153
onPressed: () async {
@@ -187,13 +160,17 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
187160
).then((value) => shouldCancel = value == true),
188161
);
189162

190-
final wallet = ref.read(pWallets).getWallet(widget.walletId)
191-
as PaynymInterface;
163+
final wallet =
164+
ref.read(pWallets).getWallet(widget.walletId)
165+
as PaynymInterface;
192166

193167
if (shouldCancel) return;
194168

195-
// get payment code
196-
final pCode = await wallet.getPaymentCode(isSegwit: false);
169+
// get payment code with taproot + segwit feature bits
170+
final pCode = await wallet.getPaymentCode(
171+
isSegwit: true,
172+
isTaproot: true,
173+
);
197174

198175
if (shouldCancel) return;
199176

@@ -206,45 +183,67 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
206183
if (shouldCancel) return;
207184

208185
if (created.value!.claimed) {
209-
// payment code already claimed
186+
// payment code already claimed — load account and navigate
210187
debugPrint("pcode already claimed!!");
211188

212-
// final account =
213-
// await ref.read(paynymAPIProvider).nym(pCode.toString());
214-
// if (!account.value!.segwit) {
215-
// for (int i = 0; i < 100; i++) {
216-
// final result = await _addSegwitCode(account.value!);
217-
// if (result == true) {
218-
// break;
219-
// }
220-
// }
221-
// }
189+
final account = await ref
190+
.read(paynymAPIProvider)
191+
.nym(pCode.toString());
222192

223-
if (mounted) {
193+
if (shouldCancel) return;
194+
195+
if (account.value != null && mounted) {
196+
ref.read(myPaynymAccountStateProvider.state).state =
197+
account.value!;
224198
if (isDesktop) {
225199
Navigator.of(context, rootNavigator: true).pop();
226200
Navigator.of(context).pop();
227201
} else {
228-
Navigator.of(context).popUntil(
229-
ModalRoute.withName(
230-
WalletView.routeName,
231-
),
232-
);
202+
Navigator.of(
203+
context,
204+
).popUntil(ModalRoute.withName(WalletView.routeName));
205+
}
206+
await Navigator.of(context).pushNamed(
207+
PaynymHomeView.routeName,
208+
arguments: widget.walletId,
209+
);
210+
} else if (mounted) {
211+
if (isDesktop) {
212+
Navigator.of(context, rootNavigator: true).pop();
213+
Navigator.of(context).pop();
214+
} else {
215+
Navigator.of(
216+
context,
217+
).popUntil(ModalRoute.withName(WalletView.routeName));
233218
}
234219
}
235220
return;
236221
}
237222

238223
if (shouldCancel) return;
239224

240-
final token =
241-
await ref.read(paynymAPIProvider).token(pCode.toString());
225+
final token = await ref
226+
.read(paynymAPIProvider)
227+
.token(pCode.toString());
228+
229+
debugPrint("token result: $token");
242230

243231
if (shouldCancel) return;
244232

233+
if (token.value == null) {
234+
debugPrint("token fetch failed: ${token.message}");
235+
if (mounted) {
236+
Navigator.of(context, rootNavigator: isDesktop).pop();
237+
}
238+
return;
239+
}
240+
245241
// sign token with notification private key
246-
final signature =
247-
await wallet.signStringWithNotificationKey(token.value!);
242+
final signature = await wallet.signStringWithNotificationKey(
243+
token.value!,
244+
);
245+
246+
debugPrint("signature: $signature");
248247

249248
if (shouldCancel) return;
250249

@@ -253,11 +252,16 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
253252
.read(paynymAPIProvider)
254253
.claim(token.value!, signature);
255254

255+
debugPrint("claim result: $claim");
256+
256257
if (shouldCancel) return;
257258

258-
if (claim.value?.claimed == pCode.toString()) {
259-
final account =
260-
await ref.read(paynymAPIProvider).nym(pCode.toString());
259+
if (claim.statusCode == 200 ||
260+
claim.value?.claimed == pCode.toString() ||
261+
claim.value?.claimed == "true") {
262+
final account = await ref
263+
.read(paynymAPIProvider)
264+
.nym(pCode.toString());
261265
// if (!account.value!.segwit) {
262266
// for (int i = 0; i < 100; i++) {
263267
// final result = await _addSegwitCode(account.value!);
@@ -274,26 +278,28 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
274278
Navigator.of(context, rootNavigator: true).pop();
275279
Navigator.of(context).pop();
276280
} else {
277-
Navigator.of(context).popUntil(
278-
ModalRoute.withName(
279-
WalletView.routeName,
280-
),
281-
);
281+
Navigator.of(
282+
context,
283+
).popUntil(ModalRoute.withName(WalletView.routeName));
282284
}
283285
await Navigator.of(context).pushNamed(
284286
PaynymHomeView.routeName,
285287
arguments: widget.walletId,
286288
);
287289
}
288290
} else if (mounted && !shouldCancel) {
291+
debugPrint(
292+
"claim failed or mismatch: "
293+
"claimed=${claim.value?.claimed}, "
294+
"expected=${pCode.toString()}, "
295+
"statusCode=${claim.statusCode}, "
296+
"message=${claim.message}",
297+
);
289298
Navigator.of(context, rootNavigator: isDesktop).pop();
290299
}
291300
},
292301
),
293-
if (isDesktop)
294-
const Spacer(
295-
flex: 2,
296-
),
302+
if (isDesktop) const Spacer(flex: 2),
297303
],
298304
),
299305
),

0 commit comments

Comments
 (0)