add initial segwit paynym support

This commit is contained in:
julian 2023-04-25 10:45:02 -06:00
parent 6fb93b00ff
commit 5ad161e6a9
3 changed files with 316 additions and 253 deletions

View file

@ -20,7 +20,6 @@ import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/bip47_utils.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/logger.dart';
@ -30,9 +29,10 @@ const String kPaynymDerivePath = "m/47'/0'/0'";
const String kPaynymNotificationDerivationPath = "$kPaynymDerivePath/0";
const String kPCodeKeyPrefix = "pCode_key_";
String _receivingPaynymAddressDerivationPath(int index) {
return "$kPaynymDerivePath/$index/0";
}
String _receivingPaynymAddressDerivationPath(int index) =>
"$kPaynymDerivePath/$index/0";
String _sendPaynymAddressDerivationPath(int index) =>
"$kPaynymDerivePath/0/$index";
mixin PaynymWalletInterface {
// passed in wallet data
@ -43,6 +43,7 @@ mixin PaynymWalletInterface {
late final MainDB _db;
late final ElectrumX _electrumXClient;
late final SecureStorageInterface _secureStorage;
late final int _dustLimit;
late final int _dustLimitP2PKH;
late final int _minConfirms;
@ -78,6 +79,7 @@ mixin PaynymWalletInterface {
required MainDB db,
required ElectrumX electrumXClient,
required SecureStorageInterface secureStorage,
required int dustLimit,
required int dustLimitP2PKH,
required int minConfirms,
required Future<String?> Function() getMnemonicString,
@ -113,6 +115,7 @@ mixin PaynymWalletInterface {
_db = db;
_electrumXClient = electrumXClient;
_secureStorage = secureStorage;
_dustLimitP2PKH = dustLimit;
_dustLimitP2PKH = dustLimitP2PKH;
_minConfirms = minConfirms;
_getMnemonicString = getMnemonicString;
@ -130,19 +133,38 @@ mixin PaynymWalletInterface {
// convenience getter
btc_dart.NetworkType get networkType => _network;
Future<Address> currentReceivingPaynymAddress(PaymentCode sender) async {
Future<Address> currentReceivingPaynymAddress({
required PaymentCode sender,
required bool isSegwit,
}) async {
final keys = await lookupKey(sender.toString());
final address = await _db
.getAddresses(_walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymReceive)
.and()
.group((q) {
if (isSegwit) {
return q
.typeEqualTo(AddressType.p2sh)
.or()
.typeEqualTo(AddressType.p2wpkh);
} else {
return q.typeEqualTo(AddressType.p2pkh);
}
})
.and()
.anyOf<String, Address>(keys, (q, String e) => q.otherDataEqualTo(e))
.sortByDerivationIndexDesc()
.findFirst();
if (address == null) {
final generatedAddress = await _generatePaynymReceivingAddress(sender, 0);
final generatedAddress = await _generatePaynymReceivingAddress(
sender: sender,
index: 0,
generateSegwitAddress: isSegwit,
);
final existing = await _db
.getAddresses(_walletId)
@ -158,16 +180,20 @@ mixin PaynymWalletInterface {
await _db.updateAddress(existing, generatedAddress);
}
return currentReceivingPaynymAddress(sender);
return currentReceivingPaynymAddress(
isSegwit: isSegwit,
sender: sender,
);
} else {
return address;
}
}
Future<Address> _generatePaynymReceivingAddress(
PaymentCode sender,
int index,
) async {
Future<Address> _generatePaynymReceivingAddress({
required PaymentCode sender,
required int index,
required bool generateSegwitAddress,
}) async {
final myPrivateKeyNode = await deriveReceivingPrivateKeyNode(
mnemonic: (await _getMnemonicString())!,
mnemonicPassphrase: (await _getMnemonicPassphrase())!,
@ -184,21 +210,27 @@ mixin PaynymWalletInterface {
final address = await generatePaynymReceivingAddressFromKeyPair(
pair: pair,
derivationIndex: index,
derivePathType: DerivePathType.bip44,
isSegwit: generateSegwitAddress,
fromPaymentCode: sender,
);
return address;
}
Future<void> checkCurrentPaynymReceivingAddressForTransactions(
PaymentCode sender) async {
final address = await currentReceivingPaynymAddress(sender);
Future<void> checkCurrentPaynymReceivingAddressForTransactions({
required PaymentCode sender,
required bool isSegwit,
}) async {
final address = await currentReceivingPaynymAddress(
sender: sender,
isSegwit: isSegwit,
);
final txCount = await _getTxCount(address: address.value);
if (txCount > 0) {
// generate next address and add to db
final nextAddress = await _generatePaynymReceivingAddress(
sender,
address.derivationIndex + 1,
sender: sender,
index: address.derivationIndex + 1,
generateSegwitAddress: isSegwit,
);
final existing = await _db
@ -215,7 +247,10 @@ mixin PaynymWalletInterface {
await _db.updateAddress(existing, nextAddress);
}
// keep checking until address with no tx history is set as current
await checkCurrentPaynymReceivingAddressForTransactions(sender);
await checkCurrentPaynymReceivingAddressForTransactions(
sender: sender,
isSegwit: isSegwit,
);
}
}
@ -223,7 +258,14 @@ mixin PaynymWalletInterface {
final codes = await getAllPaymentCodesFromNotificationTransactions();
final List<Future<void>> futures = [];
for (final code in codes) {
futures.add(checkCurrentPaynymReceivingAddressForTransactions(code));
futures.add(checkCurrentPaynymReceivingAddressForTransactions(
sender: code,
isSegwit: true,
));
futures.add(checkCurrentPaynymReceivingAddressForTransactions(
sender: code,
isSegwit: false,
));
}
await Future.wait(futures);
}
@ -233,14 +275,15 @@ mixin PaynymWalletInterface {
required String mnemonic,
required String mnemonicPassphrase,
}) async {
final root = await Bip32Utils.getBip32Root(
return _cachedRootNode ??= await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
return root;
}
bip32.BIP32? _cachedRootNode;
Future<bip32.BIP32> deriveNotificationBip32Node({
required String mnemonic,
required String mnemonicPassphrase,
@ -267,15 +310,16 @@ mixin PaynymWalletInterface {
}
/// fetch or generate this wallet's bip47 payment code
Future<PaymentCode> getPaymentCode(
DerivePathType derivePathType, [
bip32.BIP32? bip32Root,
]) async {
final address = await getMyNotificationAddress(derivePathType, bip32Root);
Future<PaymentCode> getPaymentCode({
required bool isSegwit,
}) async {
final address = await getMyNotificationAddress(
isSegwit: isSegwit,
);
final pCodeString = await paymentCodeStringByKey(address.otherData!);
final paymentCode = PaymentCode.fromPaymentCode(
pCodeString!,
_network,
networkType: _network,
);
return paymentCode;
}
@ -299,6 +343,7 @@ mixin PaynymWalletInterface {
Future<Map<String, dynamic>> preparePaymentCodeSend({
required PaymentCode paymentCode,
required bool isSegwit,
required Amount amount,
Map<String, dynamic>? args,
}) async {
@ -313,6 +358,7 @@ mixin PaynymWalletInterface {
final sendToAddress = await nextUnusedSendAddressFrom(
pCode: paymentCode,
privateKeyNode: myPrivateKeyNode,
isSegwit: isSegwit,
);
return _prepareSend(
@ -327,6 +373,7 @@ mixin PaynymWalletInterface {
/// and your own private key
Future<Address> nextUnusedSendAddressFrom({
required PaymentCode pCode,
required bool isSegwit,
required bip32.BIP32 privateKeyNode,
int startIndex = 0,
}) async {
@ -363,8 +410,8 @@ mixin PaynymWalletInterface {
final address = await generatePaynymSendAddressFromKeyPair(
pair: pair,
derivationIndex: i,
derivePathType: DerivePathType.bip44,
toPaymentCode: pCode,
isSegwit: isSegwit,
);
final storedAddress = await _db.getAddress(_walletId, address.value);
@ -387,6 +434,7 @@ mixin PaynymWalletInterface {
Future<Map<String, dynamic>> prepareNotificationTx({
required int selectedTxFeeRate,
required String targetPaymentCodeString,
required bool isSegwit,
int additionalOutputs = 0,
List<UTXO>? utxos,
}) async {
@ -449,8 +497,7 @@ mixin PaynymWalletInterface {
targetPaymentCodeString: targetPaymentCodeString,
utxoSigningData: utxoSigningData,
change: 0,
dustLimit:
satoshisBeingUsed, // override amount to get around absurd fees error
isSegwit: isSegwit,
))
.item2;
@ -458,6 +505,7 @@ mixin PaynymWalletInterface {
targetPaymentCodeString: targetPaymentCodeString,
utxoSigningData: utxoSigningData,
change: satoshisBeingUsed - amountToSend,
isSegwit: isSegwit,
))
.item2;
@ -495,6 +543,7 @@ mixin PaynymWalletInterface {
targetPaymentCodeString: targetPaymentCodeString,
utxoSigningData: utxoSigningData,
change: changeAmount,
isSegwit: isSegwit,
);
int feeBeingPaid = satoshisBeingUsed - amountToSend - changeAmount;
@ -507,6 +556,7 @@ mixin PaynymWalletInterface {
targetPaymentCodeString: targetPaymentCodeString,
utxoSigningData: utxoSigningData,
change: changeAmount,
isSegwit: isSegwit,
);
}
@ -526,6 +576,7 @@ mixin PaynymWalletInterface {
targetPaymentCodeString: targetPaymentCodeString,
utxoSigningData: utxoSigningData,
change: 0,
isSegwit: isSegwit,
);
int feeBeingPaid = satoshisBeingUsed - amountToSend;
@ -547,6 +598,7 @@ mixin PaynymWalletInterface {
targetPaymentCodeString: targetPaymentCodeString,
utxoSigningData: utxoSigningData,
change: 0,
isSegwit: isSegwit,
);
int feeBeingPaid = satoshisBeingUsed - amountToSend;
@ -568,6 +620,7 @@ mixin PaynymWalletInterface {
selectedTxFeeRate: selectedTxFeeRate,
targetPaymentCodeString: targetPaymentCodeString,
additionalOutputs: additionalOutputs + 1,
isSegwit: isSegwit,
);
} else {
throw InsufficientBalanceException(
@ -583,14 +636,16 @@ mixin PaynymWalletInterface {
// equal to its vSize
Future<Tuple2<String, int>> _createNotificationTx({
required String targetPaymentCodeString,
required bool isSegwit,
required List<SigningData> utxoSigningData,
required int change,
int? dustLimit,
}) async {
try {
final targetPaymentCode =
PaymentCode.fromPaymentCode(targetPaymentCodeString, _network);
final myCode = await getPaymentCode(DerivePathType.bip44);
final targetPaymentCode = PaymentCode.fromPaymentCode(
targetPaymentCodeString,
networkType: _network,
);
final myCode = await getPaymentCode(isSegwit: isSegwit);
final utxo = utxoSigningData.first.utxo;
final txPoint = utxo.txid.fromHex.reversed.toList();
@ -642,11 +697,21 @@ mixin PaynymWalletInterface {
utxoSigningData[i].output!,
);
}
final String notificationAddress;
if (isSegwit) {
final publicKey = targetPaymentCode.derivePublicKey(0);
final data = btc_dart.P2WPKH(
data: btc_dart.PaymentData(pubkey: publicKey),
network: networkType,
);
notificationAddress = data.data.address!;
} else {
notificationAddress = targetPaymentCode.notificationAddressP2PKH();
}
// todo: modify address once segwit support is in our bip47
txb.addOutput(
targetPaymentCode.notificationAddressP2PKH(),
dustLimit ?? _dustLimitP2PKH,
notificationAddress,
isSegwit ? _dustLimit : _dustLimitP2PKH,
);
txb.addOutput(opReturnScript, 0);
@ -687,8 +752,9 @@ mixin PaynymWalletInterface {
}
}
Future<String> broadcastNotificationTx(
{required Map<String, dynamic> preparedTx}) async {
Future<String> broadcastNotificationTx({
required Map<String, dynamic> preparedTx,
}) async {
try {
Logging.instance.log("confirmNotificationTx txData: $preparedTx",
level: LogLevel.Info);
@ -750,7 +816,9 @@ mixin PaynymWalletInterface {
// .findAll();
final myNotificationAddress =
await getMyNotificationAddress(DerivePathTypeExt.primaryFor(_coin));
await getMyNotificationAddress(isSegwit: false);
final myNotificationAddressSegwit =
await getMyNotificationAddress(isSegwit: true);
final txns = await _db
.getTransactions(_walletId)
@ -760,10 +828,10 @@ mixin PaynymWalletInterface {
for (final tx in txns) {
if (tx.type == TransactionType.incoming &&
tx.address.value?.value == myNotificationAddress.value) {
(tx.address.value?.value == myNotificationAddress.value ||
tx.address.value?.value == myNotificationAddressSegwit.value)) {
final unBlindedPaymentCode = await unBlindedPaymentCodeFromTransaction(
transaction: tx,
myNotificationAddress: myNotificationAddress,
);
if (unBlindedPaymentCode != null &&
@ -775,7 +843,6 @@ mixin PaynymWalletInterface {
final unBlindedPaymentCodeBad =
await unBlindedPaymentCodeFromTransactionBad(
transaction: tx,
myNotificationAddress: myNotificationAddress,
);
if (unBlindedPaymentCodeBad != null &&
@ -820,13 +887,7 @@ mixin PaynymWalletInterface {
Future<PaymentCode?> unBlindedPaymentCodeFromTransaction({
required Transaction transaction,
required Address myNotificationAddress,
}) async {
if (transaction.address.value != null &&
transaction.address.value!.value != myNotificationAddress.value) {
return null;
}
try {
final blindedCodeBytes =
Bip47Utils.getBlindedPaymentCodeBytesFrom(transaction);
@ -864,7 +925,10 @@ mixin PaynymWalletInterface {
unBlind: true,
);
final unBlindedPaymentCode = PaymentCode.fromPayload(unBlindedPayload);
final unBlindedPaymentCode = PaymentCode.fromPayload(
unBlindedPayload,
networkType: _network,
);
return unBlindedPaymentCode;
} catch (e) {
@ -878,13 +942,7 @@ mixin PaynymWalletInterface {
Future<PaymentCode?> unBlindedPaymentCodeFromTransactionBad({
required Transaction transaction,
required Address myNotificationAddress,
}) async {
if (transaction.address.value != null &&
transaction.address.value!.value != myNotificationAddress.value) {
return null;
}
try {
final blindedCodeBytes =
Bip47Utils.getBlindedPaymentCodeBytesFrom(transaction);
@ -922,7 +980,10 @@ mixin PaynymWalletInterface {
unBlind: true,
);
final unBlindedPaymentCode = PaymentCode.fromPayload(unBlindedPayload);
final unBlindedPaymentCode = PaymentCode.fromPayload(
unBlindedPayload,
networkType: _network,
);
return unBlindedPaymentCode;
} catch (e) {
@ -936,8 +997,6 @@ mixin PaynymWalletInterface {
Future<List<PaymentCode>>
getAllPaymentCodesFromNotificationTransactions() async {
final myAddress =
await getMyNotificationAddress(DerivePathTypeExt.primaryFor(_coin));
final txns = await _db
.getTransactions(_walletId)
.filter()
@ -954,13 +1013,17 @@ mixin PaynymWalletInterface {
await paymentCodeStringByKey(tx.address.value!.otherData!);
if (codeString != null &&
codes.where((e) => e.toString() == codeString).isEmpty) {
codes.add(PaymentCode.fromPaymentCode(codeString, _network));
codes.add(
PaymentCode.fromPaymentCode(
codeString,
networkType: _network,
),
);
}
} else {
// otherwise we need to un blind the code
final unBlinded = await unBlindedPaymentCodeFromTransaction(
transaction: tx,
myNotificationAddress: myAddress,
);
if (unBlinded != null &&
codes.where((e) => e.toString() == unBlinded.toString()).isEmpty) {
@ -969,7 +1032,6 @@ mixin PaynymWalletInterface {
final unBlindedBad = await unBlindedPaymentCodeFromTransactionBad(
transaction: tx,
myNotificationAddress: myAddress,
);
if (unBlindedBad != null &&
codes
@ -995,7 +1057,7 @@ mixin PaynymWalletInterface {
final List<PaymentCode> codes = [];
for (final codeString in otherCodeStrings) {
codes.add(PaymentCode.fromPaymentCode(codeString, _network));
codes.add(PaymentCode.fromPaymentCode(codeString, networkType: _network));
}
for (final tx in sentNotificationTransactions) {
@ -1031,7 +1093,10 @@ mixin PaynymWalletInterface {
final List<PaymentCode> extraCodes = [];
for (final codeString in paymentCodeStrings) {
if (codes.where((e) => e.toString() == codeString).isEmpty) {
final extraCode = PaymentCode.fromPaymentCode(codeString, _network);
final extraCode = PaymentCode.fromPaymentCode(
codeString,
networkType: _network,
);
if (extraCode.isValid()) {
extraCodes.add(extraCode);
}
@ -1044,9 +1109,10 @@ mixin PaynymWalletInterface {
for (final code in codes) {
futures.add(
restoreHistoryWith(
code,
maxUnusedAddressGap,
maxNumberOfIndexesToCheck,
other: code,
maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
checkSegwitAsWell: code.isSegWitEnabled(),
),
);
}
@ -1054,11 +1120,12 @@ mixin PaynymWalletInterface {
await Future.wait(futures);
}
Future<void> restoreHistoryWith(
PaymentCode other,
int maxUnusedAddressGap,
int maxNumberOfIndexesToCheck,
) async {
Future<void> restoreHistoryWith({
required PaymentCode other,
required bool checkSegwitAsWell,
required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck,
}) async {
// https://en.bitcoin.it/wiki/BIP_0047#Path_levels
const maxCount = 2147483647;
assert(maxNumberOfIndexesToCheck < maxCount);
@ -1080,36 +1147,11 @@ mixin PaynymWalletInterface {
int receivingGapCounter = 0;
int outgoingGapCounter = 0;
// non segwit receiving
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
(receivingGapCounter < maxUnusedAddressGap ||
outgoingGapCounter < maxUnusedAddressGap);
receivingGapCounter < maxUnusedAddressGap;
i++) {
if (outgoingGapCounter < maxUnusedAddressGap) {
final paymentAddressSending = PaymentAddress(
paymentCode: other,
bip32Node: mySendBip32Node,
index: i,
networkType: networkType,
);
final pair = paymentAddressSending.getSendAddressKeyPair();
final address = await generatePaynymSendAddressFromKeyPair(
pair: pair,
derivationIndex: i,
derivePathType: DerivePathType.bip44,
toPaymentCode: other,
);
addresses.add(address);
final count = await _getTxCount(address: address.value);
if (count > 0) {
outgoingGapCounter = 0;
} else {
outgoingGapCounter++;
}
}
if (receivingGapCounter < maxUnusedAddressGap) {
final paymentAddressReceiving = PaymentAddress(
paymentCode: other,
@ -1122,7 +1164,7 @@ mixin PaynymWalletInterface {
final address = await generatePaynymReceivingAddressFromKeyPair(
pair: pair,
derivationIndex: i,
derivePathType: DerivePathType.bip44,
isSegwit: false,
fromPaymentCode: other,
);
addresses.add(address);
@ -1136,52 +1178,131 @@ mixin PaynymWalletInterface {
}
}
}
// non segwit sends
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
outgoingGapCounter < maxUnusedAddressGap;
i++) {
if (outgoingGapCounter < maxUnusedAddressGap) {
final pair = PaymentAddress(
paymentCode: other,
bip32Node: mySendBip32Node,
index: i,
networkType: networkType,
).getSendAddressKeyPair();
final address = await generatePaynymSendAddressFromKeyPair(
pair: pair,
derivationIndex: i,
isSegwit: false,
toPaymentCode: other,
);
addresses.add(address);
final count = await _getTxCount(address: address.value);
if (count > 0) {
outgoingGapCounter = 0;
} else {
outgoingGapCounter++;
}
}
}
if (checkSegwitAsWell) {
int receivingGapCounterSegwit = 0;
int outgoingGapCounterSegwit = 0;
// segwit receiving
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
receivingGapCounterSegwit < maxUnusedAddressGap;
i++) {
if (receivingGapCounterSegwit < maxUnusedAddressGap) {
final paymentAddressReceiving = PaymentAddress(
paymentCode: other,
bip32Node: receivingNode.derive(i),
index: 0,
networkType: networkType,
);
final pair = paymentAddressReceiving.getReceiveAddressKeyPair();
final address = await generatePaynymReceivingAddressFromKeyPair(
pair: pair,
derivationIndex: i,
isSegwit: true,
fromPaymentCode: other,
);
addresses.add(address);
final count = await _getTxCount(address: address.value);
if (count > 0) {
receivingGapCounterSegwit = 0;
} else {
receivingGapCounterSegwit++;
}
}
}
// segwit sends
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
outgoingGapCounterSegwit < maxUnusedAddressGap;
i++) {
if (outgoingGapCounterSegwit < maxUnusedAddressGap) {
final pair = PaymentAddress(
paymentCode: other,
bip32Node: mySendBip32Node,
index: i,
networkType: networkType,
).getSendAddressKeyPair();
final address = await generatePaynymSendAddressFromKeyPair(
pair: pair,
derivationIndex: i,
isSegwit: true,
toPaymentCode: other,
);
addresses.add(address);
final count = await _getTxCount(address: address.value);
if (count > 0) {
outgoingGapCounterSegwit = 0;
} else {
outgoingGapCounterSegwit++;
}
}
}
}
await _db.updateOrPutAddresses(addresses);
}
Future<Address> generatePaynymSendAddressFromKeyPair({
required btc_dart.ECPair pair,
required int derivationIndex,
required DerivePathType derivePathType,
required bool isSegwit,
required PaymentCode toPaymentCode,
}) async {
final data = btc_dart.PaymentData(pubkey: pair.publicKey);
String addressString;
switch (derivePathType) {
case DerivePathType.bip44:
addressString =
btc_dart.P2PKH(data: data, network: _network).data.address!;
break;
final String addressString;
// The following doesn't apply currently
// case DerivePathType.bip49:
// addressString = btc_dart
// .P2SH(
// data: btc_dart.PaymentData(
// redeem: btc_dart
// .P2WPKH(
// data: data,
// network: network,
// )
// .data),
// network: network,
// )
// .data
// .address!;
// break;
//
// case DerivePathType.bip84:
// addressString = btc_dart
// .P2WPKH(
// network: network,
// data: data,
// )
// .data
// .address!;
// break;
default:
throw UnimplementedError("segwit paynyms not implemented yet");
if (isSegwit) {
addressString = btc_dart
.P2WPKH(
network: _network,
data: data,
)
.data
.address!;
} else {
addressString = btc_dart
.P2PKH(
data: data,
network: _network,
)
.data
.address!;
}
final address = Address(
@ -1189,8 +1310,8 @@ mixin PaynymWalletInterface {
value: addressString,
publicKey: pair.publicKey,
derivationIndex: derivationIndex,
derivationPath:
null, // might as well use null due to complexity of context
derivationPath: DerivationPath()
..value = _sendPaynymAddressDerivationPath(derivationIndex),
type: AddressType.nonWallet,
subType: AddressSubType.paynymSend,
otherData: await storeCode(toPaymentCode.toString()),
@ -1202,15 +1323,24 @@ mixin PaynymWalletInterface {
Future<Address> generatePaynymReceivingAddressFromKeyPair({
required btc_dart.ECPair pair,
required int derivationIndex,
required DerivePathType derivePathType,
required bool isSegwit,
required PaymentCode fromPaymentCode,
}) async {
final data = btc_dart.PaymentData(pubkey: pair.publicKey);
String addressString;
AddressType addrType;
switch (derivePathType) {
case DerivePathType.bip44:
final String addressString;
final AddressType addressType;
if (isSegwit) {
addressString = btc_dart
.P2WPKH(
network: _network,
data: data,
)
.data
.address!;
addressType = AddressType.p2wpkh;
} else {
addressString = btc_dart
.P2PKH(
data: data,
@ -1218,39 +1348,7 @@ mixin PaynymWalletInterface {
)
.data
.address!;
addrType = AddressType.p2pkh;
break;
// The following doesn't apply currently
// case DerivePathType.bip49:
// addressString = btc_dart
// .P2SH(
// data: btc_dart.PaymentData(
// redeem: btc_dart
// .P2WPKH(
// data: data,
// network: network,
// )
// .data),
// network: network,
// )
// .data
// .address!;
// addrType = AddressType.p2sh;
// break;
//
// case DerivePathType.bip84:
// addressString = btc_dart
// .P2WPKH(
// network: network,
// data: data,
// )
// .data
// .address!;
// addrType = AddressType.p2wpkh;
// break;
default:
throw UnimplementedError("segwit paynyms not implemented yet");
addressType = AddressType.p2pkh;
}
final address = Address(
@ -1260,12 +1358,12 @@ mixin PaynymWalletInterface {
derivationIndex: derivationIndex,
derivationPath: DerivationPath()
..value = _receivingPaynymAddressDerivationPath(derivationIndex),
type: addrType,
type: addressType,
subType: AddressSubType.paynymReceive,
otherData: await storeCode(fromPaymentCode.toString()),
);
final myCode = await getPaymentCode(DerivePathType.bip44);
final myCode = await getPaymentCode(isSegwit: isSegwit);
final bip32NetworkType = bip32.NetworkType(
wif: _network.wif,
@ -1284,27 +1382,10 @@ mixin PaynymWalletInterface {
return address;
}
Future<Address> getMyNotificationAddress(
DerivePathType derivePathType, [
bip32.BIP32? bip32Root,
]) async {
// TODO: fix when segwit is here
derivePathType = DerivePathType.bip44;
AddressType type;
switch (derivePathType) {
case DerivePathType.bip44:
type = AddressType.p2pkh;
break;
case DerivePathType.bip49:
type = AddressType.p2sh;
break;
case DerivePathType.bip84:
type = AddressType.p2wpkh;
break;
default:
throw Exception("DerivePathType $derivePathType not supported");
}
Future<Address> getMyNotificationAddress({
required bool isSegwit,
}) async {
final AddressType type = isSegwit ? AddressType.p2wpkh : AddressType.p2pkh;
final storedAddress = await _db
.getAddresses(_walletId)
@ -1320,22 +1401,31 @@ mixin PaynymWalletInterface {
if (storedAddress != null) {
return storedAddress;
} else {
final root = bip32Root ??
await _getRootNode(
final root = await _getRootNode(
mnemonic: (await _getMnemonicString())!,
mnemonicPassphrase: (await _getMnemonicPassphrase())!,
);
final node = root.derivePath(kPaynymDerivePath);
final paymentCode = PaymentCode.fromBip32Node(
node,
_network,
networkType: _network,
shouldSetSegwitBit: isSegwit,
);
String addressString;
final data =
btc_dart.PaymentData(pubkey: paymentCode.notificationPublicKey());
switch (derivePathType) {
case DerivePathType.bip44:
final String addressString;
final data = btc_dart.PaymentData(
pubkey: paymentCode.notificationPublicKey(),
);
if (isSegwit) {
addressString = btc_dart
.P2WPKH(
network: _network,
data: data,
)
.data
.address!;
} else {
addressString = btc_dart
.P2PKH(
data: data,
@ -1343,33 +1433,6 @@ mixin PaynymWalletInterface {
)
.data
.address!;
break;
// case DerivePathType.bip49:
// addressString = btc_dart
// .P2SH(
// data: btc_dart.PaymentData(
// redeem: btc_dart
// .P2WPKH(
// data: data,
// network: network,
// )
// .data),
// network: network,
// )
// .data
// .address!;
// break;
// case DerivePathType.bip84:
// addressString = btc_dart
// .P2WPKH(
// network: network,
// data: data,
// )
// .data
// .address!;
// break;
default:
throw UnimplementedError("segwit paynyms not implemented yet");
}
final address = Address(

View file

@ -111,11 +111,11 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "48dd65f88822fba8543826274f6d51c17f735f93"
resolved-ref: "48dd65f88822fba8543826274f6d51c17f735f93"
ref: "3e27b910d92e2ab816d589d202161490c00f986b"
resolved-ref: "3e27b910d92e2ab816d589d202161490c00f986b"
url: "https://github.com/cypherstack/bip47.git"
source: git
version: "1.0.0"
version: "2.0.0"
bitbox:
dependency: "direct main"
description:

View file

@ -60,7 +60,7 @@ dependencies:
bip47:
git:
url: https://github.com/cypherstack/bip47.git
ref: 48dd65f88822fba8543826274f6d51c17f735f93
ref: 3e27b910d92e2ab816d589d202161490c00f986b
# Utility plugins
# provider: ^6.0.1