detect paynym notification transactions

This commit is contained in:
julian 2023-01-23 16:11:24 -06:00
parent 6498e1926c
commit 6253652c21
3 changed files with 71 additions and 20 deletions

View file

@ -28,7 +28,7 @@ extension PayNym on DogecoinWallet {
return root;
}
// fetch or generate this wallet's bip47 payment code
/// fetch or generate this wallet's bip47 payment code
Future<PaymentCode> getPaymentCode() async {
final address = await db
.getAddresses(walletId)
@ -75,7 +75,7 @@ extension PayNym on DogecoinWallet {
}
void preparePaymentCodeSend(PaymentCode pCode) async {
if (!hasConnected(pCode.notificationAddress())) {
if (!(await hasConnected(pCode.notificationAddress()))) {
throw PaynymSendException("No notification transaction sent to $pCode");
} else {
final root = await getRootNode(mnemonic: await mnemonic);
@ -433,12 +433,56 @@ extension PayNym on DogecoinWallet {
}
}
bool hasConnected(String paymentCodeString) {
return db
.getTransactions(walletId)
.filter()
.address((q) => q.valueEqualTo(paymentCodeString))
.countSync() >
0;
// TODO optimize
Future<bool> hasConnected(String paymentCodeString) async {
final myCode = await getPaymentCode();
final myNotificationAddress = myCode.notificationAddress();
final txns = await db
.getTransactions(walletId)
.filter()
.subTypeEqualTo(TransactionSubType.bip47Notification)
.findAll();
for (final tx in txns) {
if (tx.address.value?.value == myNotificationAddress) {
return true;
}
final blindedCode =
tx.outputs.elementAt(1).scriptPubKeyAsm!.split(" ")[1];
final designatedInput = tx.inputs.first;
final txPoint = designatedInput.txid.fromHex.toList();
final txPointIndex = designatedInput.vout;
final rev = Uint8List(txPoint.length + 4);
Util.copyBytes(Uint8List.fromList(txPoint), 0, rev, 0, txPoint.length);
final buffer = rev.buffer.asByteData();
buffer.setUint32(txPoint.length, txPointIndex, Endian.little);
final pubKey = designatedInput.scriptSigAsm!.split(" ")[1].fromHex;
final root = await getRootNode(mnemonic: await mnemonic);
final myPrivateKey =
root.derivePath(kPaynymDerivePath).derive(0).privateKey!;
final S = SecretPoint(myPrivateKey, pubKey);
final mask = PaymentCode.getMask(S.ecdhSecret(), rev);
final unBlindedPayload = PaymentCode.blind(blindedCode.fromHex, mask);
final unBlindedPaymentCode =
PaymentCode.initFromPayload(unBlindedPayload);
if (paymentCodeString == unBlindedPaymentCode.toString()) {
return true;
}
}
// otherwise return no
return false;
}
}

View file

@ -1162,10 +1162,8 @@ class DogecoinWallet extends CoinServiceAPI
.not()
.typeEqualTo(isar_models.AddressType.nonWallet)
.and()
.group((q) => q
.subTypeEqualTo(isar_models.AddressSubType.receiving)
.or()
.subTypeEqualTo(isar_models.AddressSubType.change))
.not()
.subTypeEqualTo(isar_models.AddressSubType.nonWallet)
.findAll();
return allAddresses;
}

View file

@ -1,3 +1,4 @@
import 'package:bip47/src/util.dart';
import 'package:decimal/decimal.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -148,10 +149,6 @@ mixin ElectrumXParsing {
amount = amountReceivedInWallet;
}
bool isNotificationTx = coin.hasPaynymSupport &&
type == TransactionType.incoming &&
transactionAddress.subType == AddressSubType.paynymNotification;
List<Output> outs = [];
List<Input> ins = [];
@ -188,15 +185,27 @@ mixin ElectrumXParsing {
outs.add(output);
}
TransactionSubType txSubType = TransactionSubType.none;
if (coin.hasPaynymSupport && outs.length > 1) {
List<String>? scriptChunks = outs[1].scriptPubKeyAsm?.split(" ");
if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") {
final blindedPaymentCode = scriptChunks![1];
final bytes = blindedPaymentCode.fromHex;
// https://en.bitcoin.it/wiki/BIP_0047#Sending
if (bytes.length == 80 && bytes.first == 1) {
txSubType = TransactionSubType.bip47Notification;
}
}
}
final tx = Transaction(
walletId: walletId,
txid: txData["txid"] as String,
timestamp: txData["blocktime"] as int? ??
(DateTime.now().millisecondsSinceEpoch ~/ 1000),
type: type,
subType: isNotificationTx
? TransactionSubType.bip47Notification
: TransactionSubType.none,
subType: txSubType,
amount: amount,
fee: fee,
height: txData["height"] as int?,