Skip to content

Commit

Permalink
Minor cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
konstantinullrich committed Jan 8, 2025
1 parent 6c9e99e commit a9a3043
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 152 deletions.
2 changes: 1 addition & 1 deletion cw_bitcoin/lib/bitcoin_payjoin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ class BitcoinPayjoin {
Object credentials,
dynamic pjUri
) async {
final bitcoinWallet = wallet as ElectrumWallet;
final bitcoinWallet = wallet as BitcoinWallet;

final pendingTx =
await bitcoinWallet.psbtToPendingTx(psbtString, credentials, pjUri);
Expand Down
102 changes: 101 additions & 1 deletion cw_bitcoin/lib/bitcoin_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
import 'package:cw_bitcoin/psbt_finalizer_v0.dart';
import 'package:cw_bitcoin/psbt_signer.dart';
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
import 'package:cw_bitcoin/psbt_v0_deserialize.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
Expand Down Expand Up @@ -252,7 +255,6 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
derivationPath: walletInfo.derivationInfo!.derivationPath!);
}

@override
Future<PSBTTransactionBuild> buildPayjoinTransaction({
required List<BitcoinBaseOutput> outputs,
required BigInt fee,
Expand Down Expand Up @@ -421,6 +423,104 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
}
}

Future<PendingBitcoinTransaction> psbtToPendingTx(
String preProcessedPsbt,
Object credentials,
dynamic pjUri,
) async {

final unspent = unspentCoins.where((e) => (e.isSending || !e.isFrozen));

List<UtxoWithPrivateKey> utxos = [];

for (BitcoinUnspent input in unspent) {
final address = RegexUtils.addressTypeFromStr(input.address, BitcoinNetwork.mainnet);

final newHd = input.bitcoinAddressRecord.isHidden
? sideHd
: hd;

ECPrivate privkey;
if (input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
final unspentAddress = input.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
privkey = walletAddresses.silentAddress!.b_spend.tweakAdd(
BigintUtils.fromBytes(
BytesUtils.fromHexString(unspentAddress.silentPaymentTweak!),
),
);
} else {
privkey =
generateECPrivate(hd: newHd, index: input.bitcoinAddressRecord.index, network: BitcoinNetwork.mainnet);
}

utxos.add(
UtxoWithPrivateKey(
utxo: BitcoinUtxo(
txHash: input.hash,
value: BigInt.from(input.value),
vout: input.vout,
scriptType: input.bitcoinAddressRecord.type,
isSilentPayment: input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord,
),
ownerDetails: UtxoAddressDetails(
publicKey: newHd.publicKey.toHex(),
address: address,
),
privateKey: privkey
),
);
}

final psbt = PsbtV2()..deserializeV0(base64.decode(preProcessedPsbt));

final inputCount = psbt.getGlobalInputCount();

final unsignedTx = [];
for (var i = 0; i < inputCount; i++) {
if (psbt.getInputFinalScriptsig(i) == null) {
try {
psbt.getInputFinalScriptwitness(i);
} catch (_) {
unsignedTx.add(BytesUtils.toHexString(psbt.getInputPreviousTxid(i).reversed.toList()));
}
}
}

psbt.signWithUTXO(utxos.where((e) => unsignedTx.contains(e.utxo.txHash)).toList(), (txDigest, utxo, key, sighash) {
if (utxo.utxo.isP2tr()) {
return key.signTapRoot(
txDigest,
sighash: sighash,
tweak: utxo.utxo.isSilentPayment != true,
);
} else {
return key.signInput(txDigest, sigHash: sighash);
}
});

psbt.finalizeV0();

final btcTx = BtcTransaction.fromRaw(hex.encode(psbt.extract()));

return PendingBitcoinTransaction(
btcTx,
type,
electrumClient: electrumClient,
amount: psbt.getOutputAmount(0), // ToDo
fee: 0,// ToDo
feeRate: "Payjoin", // ToDo
network: network,
hasChange: true,
isSendAll: true,
hasTaprootInputs: false, // ToDo: (Konsti) Support Taproot
)..addListener(
(transaction) async {
transactionHistory.addOne(transaction);
await updateBalance();
},
);
}

Future<String> signPsbt(String preProcessedPsbt, List<UtxoWithPrivateKey> utxos) async {
final psbt = PsbtV2()..deserializeV0(base64Decode(preProcessedPsbt));

Expand Down
122 changes: 0 additions & 122 deletions cw_bitcoin/lib/electrum_wallet.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:isolate';

import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/psbt_finalizer_v0.dart';
import 'package:cw_bitcoin/psbt_signer.dart';
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
import 'package:cw_bitcoin/psbt_v0_deserialize.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_bitcoin/litecoin_wallet.dart';
import 'package:ledger_bitcoin/psbt.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:collection/collection.dart';
Expand Down Expand Up @@ -1208,122 +1202,6 @@ abstract class ElectrumWalletBase
}
}

Future<PendingBitcoinTransaction> psbtToPendingTx(
String preProcessedPsbt,
Object credentials,
dynamic pjUri,
) async {

final unspent = unspentCoins.where((e) => (e.isSending || !e.isFrozen));

List<UtxoWithPrivateKey> utxos = [];

for (BitcoinUnspent input in unspent) {
final address = RegexUtils.addressTypeFromStr(input.address, BitcoinNetwork.mainnet);

final newHd = input.bitcoinAddressRecord.isHidden
? sideHd
: hd;

ECPrivate privkey;
if (input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
final unspentAddress = input.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
privkey = walletAddresses.silentAddress!.b_spend.tweakAdd(
BigintUtils.fromBytes(
BytesUtils.fromHexString(unspentAddress.silentPaymentTweak!),
),
);
} else {
privkey =
generateECPrivate(hd: newHd, index: input.bitcoinAddressRecord.index, network: BitcoinNetwork.mainnet);
}

utxos.add(
UtxoWithPrivateKey(
utxo: BitcoinUtxo(
txHash: input.hash,
value: BigInt.from(input.value),
vout: input.vout,
scriptType: input.bitcoinAddressRecord.type,
isSilentPayment: input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord,
),
ownerDetails: UtxoAddressDetails(
publicKey: newHd.publicKey.toHex(),
address: address,
),
privateKey: privkey
),
);
}

log(preProcessedPsbt);
final psbt = PsbtV2()..deserializeV0(base64.decode(preProcessedPsbt));

final inputCount = psbt.getGlobalInputCount();

final unsignedTx = [];
for (var i = 0; i < inputCount; i++) {
if (psbt.getInputFinalScriptsig(i) == null) {
try {
psbt.getInputFinalScriptwitness(i);
} catch (_) {
unsignedTx.add(BytesUtils.toHexString(psbt.getInputPreviousTxid(i).reversed.toList()));
}
}
}

psbt.signWithUTXO(utxos.where((e) => unsignedTx.contains(e.utxo.txHash)).toList(), (txDigest, utxo, key, sighash) {
if (utxo.utxo.isP2tr()) {
return key.signTapRoot(
txDigest,
sighash: sighash,
tweak: utxo.utxo.isSilentPayment != true,
);
} else {
return key.signInput(txDigest, sigHash: sighash);
}
});

psbt.finalizeV0();

final btcTx = BtcTransaction.fromRaw(hex.encode(psbt.extract()));

return PendingBitcoinTransaction(
btcTx,
type,
electrumClient: electrumClient,
amount: psbt.getOutputAmount(0), // ToDo
fee: 0,// ToDo
feeRate: "Payjoin", // ToDo
network: network,
hasChange: true,
isSendAll: true,
hasTaprootInputs: false, // ToDo: (Konsti) Support Taproot
)..addListener(
(transaction) async {
transactionHistory.addOne(transaction);
await updateBalance();
},
);
}

Future<BtcTransaction> getBtcTransactionFromPsbt(
String preProcessedPsbt) async =>
throw UnimplementedError();

Future<PSBTTransactionBuild> buildPayjoinTransaction({
required List<BitcoinBaseOutput> outputs,
required BigInt fee,
required BasedUtxoNetwork network,
required List<UtxoWithAddress> utxos,
required Map<String, PublicKeyWithDerivationPath> publicKeys,
String? memo,
bool enableRBF = false,
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
}) async =>
throw UnimplementedError();

void setLedgerConnection(ledger.LedgerConnection connection) => throw UnimplementedError();

Future<BtcTransaction> buildHardwareWalletTransaction({
Expand Down
4 changes: 1 addition & 3 deletions lib/src/screens/send/widgets/send_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
controller: addressController,
onURIScanned: (uri) {
final paymentRequest = PaymentRequest.fromUri(uri);
if (paymentRequest.pjUri?.trim().isNotEmpty == true) {
sendViewModel.pjUri = paymentRequest.pjUri;
}
sendViewModel.pjUri = paymentRequest.pjUri;
addressController.text = paymentRequest.address;
cryptoAmountController.text = paymentRequest.amount;
noteController.text = paymentRequest.note;
Expand Down
10 changes: 3 additions & 7 deletions lib/utils/payment_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ class PaymentRequest {
}

address = uri.queryParameters['address'] ?? uri.path;
amount =
uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ??
"";
note = uri.queryParameters['tx_description'] ??
uri.queryParameters['message'] ?? "";
amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? "";
note = uri.queryParameters['tx_description'] ?? uri.queryParameters['message'] ?? "";
scheme = uri.scheme;
callbackUrl = uri.queryParameters['callback'];
callbackMessage = uri.queryParameters['callbackMessage'];
Expand All @@ -39,8 +36,7 @@ class PaymentRequest {
if (address.contains("nano")) {
amount = nanoUtil!.getRawAsUsableString(amount, nanoUtil!.rawPerNano);
} else if (address.contains("ban")) {
amount =
nanoUtil!.getRawAsUsableString(amount, nanoUtil!.rawPerBanano);
amount = nanoUtil!.getRawAsUsableString(amount, nanoUtil!.rawPerBanano);
}
}
}
Expand Down
13 changes: 0 additions & 13 deletions lib/view_model/dashboard/dashboard_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -461,19 +461,6 @@ abstract class DashboardViewModelBase with Store {
}
}

@computed
bool get showPayjoinPaymentsCard => wallet.type == WalletType.bitcoin;

@observable
bool payjoinPaymentsScanningActive = false;

@action
void setPayjoinPaymentsScanning(bool active) {
payjoinPaymentsScanningActive = active;

/// TODO: Set Payjoin receive polling
}

@computed
bool get hasMweb =>
wallet.type == WalletType.litecoin &&
Expand Down
6 changes: 1 addition & 5 deletions lib/view_model/send/send_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -390,11 +390,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor

@action
Future<PendingTransaction?> createTransaction({ExchangeProvider? provider}) async {
if (pjUri != null) {
debugPrint(
'[+] SENDPAGE => onAuthSuccess - INITIATE PAYJOIN SEND');
return performPayjoinSend();
}
if (pjUri != null) return performPayjoinSend(); // ToDo: Remove

try {
state = IsExecutingState();
Expand Down

0 comments on commit a9a3043

Please sign in to comment.