3

I'm interested in implementing a view wallet in code. I've seen this example which worked great, however the only problem is it also requires a public spend key.

I saw this question but I can't really follow what steps I would have to take to extract all that data from a transaction.

Can somone layout in psuedo or actual code the process needed to tell if an output belongs to you in a given transaction? Here's what I have so far, adapted from the github example:

void printTxOutputs(Crypto::Hash transactionHash)
{
  std::vector<TransactionDetails> transactions;
  std::vector<Crypto::Hash> transactionHashes;
  transactionHashes.push_back(transactionHash);

  m_node->getTransactions(transactionHashes, transactions, callback);

  TransactionDetails ourTransaction = transactions[0];

  AccountKeys keys;
  m_wallet->getAccountKeys(keys);

  Crypto::SecretKey privateViewKey = keys.viewSecretKey;
  Crypto::SecretKey privateSpendKey = keys.spendSecretKey;

  /* The transaction public key */
  Crypto::PublicKey publicTransactionKey = ourTransaction.extra.publicKey;

  /* The users public spend key */
  Crypto::PublicKey publicSpendKey;
  Crypto::secret_key_to_public_key(privateSpendKey, publicSpendKey);

  /* Derived key is created from the users private view key and the public
     transaction key */
  Crypto::KeyDerivation derivation;
  Crypto::generate_key_derivation(publicTransactionKey, privateViewKey, derivation);

  Crypto::PublicKey outputPublicKey;

  bool found = false;
  uint64_t sum = 0;

  /* Loop through each output in the transaction */
  for (size_t i = 0; i < ourTransaction.outputs.size(); ++i)
  {
    Crypto::derive_public_key(derivation, i, publicSpendKey, outputPublicKey);

    TransactionOutputTarget target = ourTransaction.outputs[i].output.target;

    KeyOutput targetPubKey = boost::get<CryptoNote::KeyOutput>(target);

    if (targetPubKey.key == outputPublicKey)
    {
      uint64_t amount = ourTransaction.outputs[i].output.amount; 

      std::string xmr = m_currency.formatAmount(amount);

      sum += amount;

      found = true;

      logger(INFO, GREEN) << "The transaction output of " << xmr << " XMR belongs to you!";
    }
  }

  if (!found)
  {
    logger(ERROR, BRIGHT_RED) << "No outputs were found that belong to you, searched " << ourTransaction.outputs.size() << " outputs.";
  }
  else
  {
    std::string xmr = m_currency.formatAmount(sum);

    logger(INFO, GREEN) << "Outputs totalling " << xmr << " XMR were sent to your wallet!";
  }
}

The code is slightly pruned to remove cruft.

  • 2
    It is mathematically impossible to check for incoming transactions without knowing your public spend key. Your public spend key is half of your public Monero wallet address, so there shouldn't be a problem in requiring knowledge of it. – knaccc Mar 15 '18 at 10:11
2

Your code looks fine to me. Here is an explanation of what it's doing:

  1. For each transaction, get the public key of each output listed in the transaction. Call the public key P.

  2. We need to check whether this output was destined for us. We do this by calculating P' as P' = Hs(aR || i)G + B. If P' == P then the output is destined for us.

The generate_key_derivation method in your code produces aR. The derive_public_key uses that to then calculate P' as Hs(aR || i)G + B.

The only step that I think seems to be missing is to decrypt the amount of the output. For details, see my answer here How the receiver knows the amount that he received from the sender?

You probably also want to extract the public spend key from the user's public wallet address, rather than require that you know their private spend key to derive it. For information on how to extract it, see https://xmr.llcoins.net/addresstests.html

  • Ah, I didn't realise you could get the public spend key from the user's public wallet address. Thanks! This seems pretty easy to do. Is my code not correctly calculating the amount that is received? On the small tests I have done it appears correct. – Zpalmtree Mar 15 '18 at 18:01
  • @Zpalmtree if you're getting the correct amount, then some part of your code must be successfully decrypting it. Otherwise you'd get gibberish. – knaccc Mar 15 '18 at 19:36
  • Thanks for the help. Just tried out extracting the public keys from the address and it's really easy to do. – Zpalmtree Mar 15 '18 at 19:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.