Skip to content

Chore: build features #2469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ lib/core/secure_storage.dart

lib/core/secure_storage.dart

lib/dnssec_proof/dnssec_proof.dart

macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
Expand Down
6 changes: 6 additions & 0 deletions cw_bitcoin/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,9 @@ build/
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3

/lib/payjoin/payjoin.dart
/lib/silent_payments/sp.dart

/pubspec.yaml
/pubspec.lock
76 changes: 32 additions & 44 deletions cw_bitcoin/lib/bitcoin_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
import 'package:cw_bitcoin/payjoin/manager.dart';
import 'package:cw_bitcoin/payjoin/storage.dart';
import 'package:cw_bitcoin/payjoin/payjoin.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
import 'package:cw_bitcoin/psbt/signer.dart';
import 'package:cw_bitcoin/psbt/transaction_builder.dart';
Expand All @@ -25,7 +24,6 @@ import 'package:cw_core/output_info.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';
Expand Down Expand Up @@ -78,9 +76,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
initialBalance: initialBalance,
seedBytes: seedBytes,
encryptionFileUtils: encryptionFileUtils,
currency: networkParam == BitcoinNetwork.testnet
? CryptoCurrency.tbtc
: CryptoCurrency.btc,
currency:
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
alwaysScan: alwaysScan,
) {
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
Expand All @@ -89,7 +86,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
// String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1";
// final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);

payjoinManager = PayjoinManager(PayjoinStorage(payjoinBox), this);
payjoinManager = cwPayjoinManager;

if (payjoinManager != null) {
payjoinManager!.init(payjoinStorage: payjoinBox, wallet: this);
}

walletAddresses = BitcoinWalletAddresses(walletInfo,
initialAddresses: initialAddresses,
initialRegularAddressIndex: initialRegularAddressIndex,
Expand All @@ -99,14 +101,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
mainHd: hd,
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
network: networkParam ?? network,
masterHd:
seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
isHardwareWallet: walletInfo.isHardwareWallet,
payjoinManager: payjoinManager);

autorun((_) {
this.walletAddresses.isEnabledAutoGenerateSubaddress =
this.isEnabledAutoGenerateSubaddress;
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
});
}

Expand Down Expand Up @@ -141,8 +141,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
break;
case DerivationType.electrum:
default:
seedBytes =
await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
break;
}

Expand Down Expand Up @@ -214,10 +213,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
walletInfo.derivationInfo ??= DerivationInfo();

// set the default if not present:
walletInfo.derivationInfo!.derivationPath ??=
snp?.derivationPath ?? electrum_path;
walletInfo.derivationInfo!.derivationType ??=
snp?.derivationType ?? DerivationType.electrum;
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;

Uint8List? seedBytes = null;
final mnemonic = keysData.mnemonic;
Expand All @@ -226,8 +223,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
if (mnemonic != null) {
switch (walletInfo.derivationInfo!.derivationType) {
case DerivationType.electrum:
seedBytes =
await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
break;
case DerivationType.bip39:
default:
Expand Down Expand Up @@ -272,15 +268,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {

@override
Future<void> close({bool shouldCleanup = false}) async {
payjoinManager.cleanupSessions();
payjoinManager?.cleanupSessions();
super.close(shouldCleanup: shouldCleanup);
}

late final PayjoinManager payjoinManager;
late final PayjoinManager? payjoinManager;

bool get isPayjoinAvailable => unspentCoinsInfo.values
.where((element) =>
element.walletId == id && element.isSending && !element.isFrozen)
.where((element) => element.walletId == id && element.isSending && !element.isFrozen)
.isNotEmpty;

Future<PsbtV2> buildPsbt({
Expand All @@ -298,10 +293,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
}) async {
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
for (final utxo in utxos) {
final rawTx =
await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
final publicKeyAndDerivationPath =
publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;

psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
utxo: utxo.utxo,
Expand Down Expand Up @@ -355,8 +348,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
Future<PendingTransaction> createTransaction(Object credentials) async {
credentials = credentials as BitcoinTransactionCredentials;

final tx = (await super.createTransaction(credentials))
as PendingBitcoinTransaction;
final tx = (await super.createTransaction(credentials)) as PendingBitcoinTransaction;

final payjoinUri = credentials.payjoinUri;
if (payjoinUri == null && !tx.shouldCommitUR()) return tx;
Expand All @@ -381,18 +373,18 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
masterFingerprint: Uint8List.fromList([0, 0, 0, 0]));

if (tx.shouldCommitUR()) {
tx.unsignedPsbt = transaction.asPsbtV0();
return tx;
tx.unsignedPsbt = transaction.asPsbtV0();
return tx;
}

final originalPsbt =
await signPsbt(base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys());

tx.commitOverride = () async {
final sender =
await payjoinManager.initSender(payjoinUri!, originalPsbt, int.parse(tx.feeRate));
payjoinManager.spawnNewSender(
sender: sender, pjUrl: payjoinUri, amount: BigInt.from(tx.amount));
await payjoinManager!.initSender(payjoinUri!, originalPsbt, int.parse(tx.feeRate));
payjoinManager!
.spawnNewSender(sender: sender, pjUrl: payjoinUri, amount: BigInt.from(tx.amount));
};

return tx;
Expand All @@ -406,8 +398,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
Future<void> commitPsbt(String finalizedPsbt) {
final psbt = PsbtV2()..deserializeV0(base64.decode(finalizedPsbt));

final btcTx =
BtcTransaction.fromRaw(BytesUtils.toHexString(psbt.extract()));
final btcTx = BtcTransaction.fromRaw(BytesUtils.toHexString(psbt.extract()));

return PendingBitcoinTransaction(
btcTx,
Expand All @@ -422,8 +413,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
).commit();
}

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

await psbt.signWithUTXO(utxos, (txDigest, utxo, key, sighash) {
Expand Down Expand Up @@ -486,17 +476,15 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
Future<String> signMessage(String message, {String? address = null}) async {
if (walletInfo.isHardwareWallet) {
final addressEntry = address != null
? walletAddresses.allAddresses
.firstWhere((element) => element.address == address)
? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
: null;
final index = addressEntry?.index ?? 0;
final isChange = addressEntry?.isHidden == true ? 1 : 0;
final accountPath = walletInfo.derivationInfo?.derivationPath;
final derivationPath =
accountPath != null ? "$accountPath/$isChange/$index" : null;
final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;

final signature = await _bitcoinLedgerApp!.signMessage(
message: ascii.encode(message), signDerivationPath: derivationPath);
final signature = await _bitcoinLedgerApp!
.signMessage(message: ascii.encode(message), signDerivationPath: derivationPath);
return base64Encode(signature);
}

Expand Down
25 changes: 13 additions & 12 deletions cw_bitcoin/lib/bitcoin_wallet_addresses.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/bip/bip/bip32/bip32.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_bitcoin/payjoin/manager.dart';
import 'package:cw_bitcoin/payjoin/payjoin.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart';
import 'package:payjoin_flutter/receive.dart' as payjoin;

part 'bitcoin_wallet_addresses.g.dart';

Expand All @@ -29,9 +28,7 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
super.masterHd,
}) : super(walletInfo);

final PayjoinManager payjoinManager;

payjoin.Receiver? currentPayjoinReceiver;
final PayjoinManager? payjoinManager;

@observable
String? payjoinEndpoint = null;
Expand Down Expand Up @@ -63,11 +60,13 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
@action
Future<void> initPayjoin() async {
try {
await payjoinManager.initPayjoin();
currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
await payjoinManager!.initPayjoin();
payjoinManager!.currentPayjoinReceiver =
await payjoinManager!.getUnusedReceiver(primaryAddress);
payjoinEndpoint =
(await payjoinManager!.currentPayjoinReceiver?.pjUri())?.pjEndpoint() as String;

payjoinManager.resumeSessions();
payjoinManager!.resumeSessions();
} catch (e) {
printV(e);
// Ignore Connectivity errors
Expand All @@ -78,10 +77,12 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
@action
Future<void> newPayjoinReceiver() async {
try {
currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
payjoinManager!.currentPayjoinReceiver =
await payjoinManager!.getUnusedReceiver(primaryAddress);
payjoinEndpoint =
(await payjoinManager!.currentPayjoinReceiver?.pjUri())?.pjEndpoint() as String;

payjoinManager.spawnReceiver(receiver: currentPayjoinReceiver!);
payjoinManager!.spawnReceiver(receiver: payjoinManager!.currentPayjoinReceiver!);
} catch (e) {
printV(e);
// Ignore Connectivity errors
Expand Down
Loading
Loading