feat(dev): debug UR codes [skip ci]

This commit is contained in:
Czarek Nakamoto 2025-06-03 15:11:24 +02:00 committed by cyan
parent a4a40356a3
commit 9539327e17
4 changed files with 56 additions and 5 deletions

View file

@ -24,6 +24,7 @@ import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/payjoin_session.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_keys_file.dart';
import 'package:flutter/foundation.dart';
@ -32,6 +33,9 @@ import 'package:ledger_bitcoin/ledger_bitcoin.dart';
import 'package:ledger_bitcoin/psbt.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:mobx/mobx.dart';
import 'package:ur/cbor_lite.dart';
import 'package:ur/ur.dart';
import 'package:ur/ur_decoder.dart';
part 'bitcoin_wallet.g.dart';
@ -373,7 +377,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
masterFingerprint: Uint8List(0));
if (tx.shouldCommitUR()) {
tx.unsignedPsbt = transaction.serialize();
tx.unsignedPsbt = transaction.asPsbtV0();
return tx;
}
@ -436,6 +440,24 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
return base64Encode(psbt.asPsbtV0());
}
Future<void> commitPsbtUR(List<String> urCodes) async {
final ur = URDecoder();
for (final inp in urCodes) {
ur.receivePart(inp);
}
final result = (ur.result as UR);
final cbor = result.cbor;
final cborDecoder = CBORDecoder(cbor);
final out = cborDecoder.decodeBytes();
final bytes = out.$1;
final base64psbt = base64Encode(bytes);
final psbt = PsbtV2()..deserializeV0(base64Decode(base64psbt));
// psbt.finalize();
final finalized = base64Encode(psbt.serialize());
await commitPsbt(finalized);
}
@override
Future<String> signMessage(String message, {String? address = null}) async {
if (walletInfo.isHardwareWallet) {

View file

@ -723,6 +723,12 @@ class CWBitcoin extends Bitcoin {
}
}
@override
Future<void> commitPsbtUR(Object wallet, List<String> urCodes) {
final _wallet = wallet as BitcoinWalletBase;
return _wallet.commitPsbtUR(urCodes);
}
@override
String getPayjoinEndpoint(Object wallet) {
final _wallet = wallet as ElectrumWallet;

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart';
@ -7,9 +8,12 @@ import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/utils/clipboard_util.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/animated_ur_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// ur:xmr-txunsigned - unsigned transaction
// should show a scanner afterwards.
@ -46,8 +50,8 @@ class AnimatedURPage extends BasePage {
frames: urQr.trim().split("\n"),
),
),
if (["ur:xmr-txunsigned", "ur:xmr-output", "ur:psbt"].contains(urQrType)) ...{
SizedBox(height: 32),
if (urQrType == "ur:xmr-txunsigned" || urQrType == "ur:xmr-output")
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: SizedBox(
@ -60,8 +64,10 @@ class AnimatedURPage extends BasePage {
),
),
),
SizedBox(height: 32),
if (urQrType == "ur:xmr-output" && !isAll) Padding(
},
if (urQrType == "ur:xmr-output" && !isAll) ...{
SizedBox(height: 32),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: SizedBox(
width: double.maxFinite,
@ -73,6 +79,7 @@ class AnimatedURPage extends BasePage {
),
),
),
},
],
);
}
@ -106,6 +113,10 @@ class AnimatedURPage extends BasePage {
Navigator.of(context).pop(true);
}
break;
case "ur:psbt": // psbt
final ur = await presentQRScanner(context);
if (ur == null) return;
await bitcoin!.commitPsbtUR(animatedURmodel.wallet, ur.trim().split("\n"));
default:
throw UnimplementedError("unable to handle UR: ${urQrType}");
}
@ -168,10 +179,21 @@ class _URQRState extends State<URQR> {
children: [
Center(
child: QrImage(
data: widget.frames[frame % widget.frames.length], version: -1,
data: widget.frames[frame % widget.frames.length],
version: -1,
size: 400,
),
),
if (FeatureFlag.hasDevOptions) ...{
TextButton(
onPressed: () {
Clipboard.setData(ClipboardData(text: """Current frame (${frame % widget.frames.length}): ${widget.frames[frame % widget.frames.length]},
All frames:
- ${widget.frames.join("\n - ")}"""));
},
child: Text(widget.frames[frame % widget.frames.length]),
),
}
],
);
}

View file

@ -245,6 +245,7 @@ abstract class Bitcoin {
bool getMwebEnabled(Object wallet);
String? getUnusedMwebAddress(Object wallet);
String? getUnusedSegwitAddress(Object wallet);
Future<void> commitPsbtUR(Object wallet, List<String> urCodes);
void updatePayjoinState(Object wallet, bool state);
String getPayjoinEndpoint(Object wallet);