Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9952ac8
start adding support for subaddresses
Einliterflasche Oct 15, 2025
c3d489e
add happy_path_alice_developer_tip_subaddress
binarybaron Oct 15, 2025
854aaf5
remove redundant addSubaddressAccount bridge
binarybaron Oct 15, 2025
5e092df
document multiple tx keys
binarybaron Oct 15, 2025
53dc1c7
don't autoformat c++ files
Einliterflasche Oct 16, 2025
2f202d8
update PendingTransaction::txKeys() to return the output address and …
Einliterflasche Oct 16, 2025
3cc27ec
fix c++ include error, update bridge.rs
Einliterflasche Oct 16, 2025
8b108ff
Merge branch 'fix/monero-sys-multiple-tx-keys' of https://github.com/…
Einliterflasche Oct 16, 2025
9600894
make TxReceipt have a map of transfer keys
Einliterflasche Oct 16, 2025
61bf3a9
fix derive_puclic_key function call
Einliterflasche Oct 17, 2025
5fbc2b1
add undo-git-changes to justfile (restores unstaged changes in git su…
Einliterflasche Oct 24, 2025
e1e7ef2
don't autoformat c/c++ files
Einliterflasche Oct 24, 2025
a43e967
Change the txKeys method to correctly identify the tx key for each ou…
Einliterflasche Oct 24, 2025
ecf6fec
add a simple test casse
Einliterflasche Oct 24, 2025
e34bab5
update error message to reflect caviat of not beign able to send to y…
Einliterflasche Oct 24, 2025
4e8a6bb
Merge branch 'master' into fix/monero-sys-multiple-tx-keys
Einliterflasche Oct 24, 2025
b5c3937
un-hardcode path in transaction_keys.rs
Einliterflasche Oct 24, 2025
f0733c3
update patch to throw an exception in txKeys() when a crypto operatio…
Einliterflasche Oct 24, 2025
5fb8b39
cleanup
Einliterflasche Nov 3, 2025
9315938
add a new crate monero-tests for monero integration tests
Einliterflasche Nov 3, 2025
5d42351
add monero-tests/transactions to ci
Einliterflasche Nov 3, 2025
2fb2c98
add comment to tx_keys map
Einliterflasche Nov 3, 2025
51b6acf
Merge branch 'master' into fix/monero-sys-multiple-tx-keys
binarybaron Nov 4, 2025
0cd8fff
fix compilation, add test case for wrong transfer key
Einliterflasche Nov 6, 2025
4bb1514
fix ci
Einliterflasche Nov 6, 2025
cacb920
add new test and explanatory comments
Einliterflasche Nov 7, 2025
aba24fc
Add explanatory comment
Einliterflasche Nov 7, 2025
f733ede
rename test to avoid name abiguity
Einliterflasche Nov 8, 2025
816e334
silence some monero c++ spam
Einliterflasche Nov 8, 2025
b69ec7c
start updating distribute function to use integers
Einliterflasche Nov 8, 2025
f589564
Merge branch 'master' into fix/monero-sys-multiple-tx-keys
Einliterflasche Nov 9, 2025
97bd923
Revert "start updating distribute function to use integers"
Einliterflasche Nov 9, 2025
9f7039c
update rust to 1.88
Einliterflasche Nov 9, 2025
37af555
Merge branch 'master' into fix/monero-sys-multiple-tx-keys
Einliterflasche Nov 9, 2025
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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ jobs:
test_name: happy_path
- package: swap
test_name: happy_path_alice_developer_tip
- package: swap
test_name: happy_path_alice_developer_tip_subaddress
- package: swap
test_name: happy_path_restart_bob_after_xmr_locked
- package: swap
Expand Down
14 changes: 11 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,17 @@
"shared_mutex": "cpp",
"source_location": "cpp",
"strstream": "cpp",
"typeindex": "cpp"
"typeindex": "cpp",
"valarray": "cpp",
"*.ipp": "cpp"
},
"rust-analyzer.cargo.extraEnv": {
"CARGO_TARGET_DIR": "target-check"
}
}
},
"[cpp]": {
"editor.formatOnSave": false
},
"[c]": {
"editor.formatOnSave": false
},
}
3 changes: 3 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ monero_sys:
just update_submodules
cd monero-sys && cargo build

undo-monero-changes:
cd monero-sys/monero && git restore .

# Test the FFI bindings using various sanitizers, that can detect memory safety issues.
test-ffi: test-ffi-address

Expand Down
4 changes: 2 additions & 2 deletions monero-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ const EMBEDDED_PATCHES: &[EmbeddedPatch] = &[
"patches/eigenwallet_0002_wallet2_increase_rpc_retries.patch"
),
embedded_patch!(
"eigenwallet_0003_pendingTransaction_getTxKey",
"eigenwallet_0003_pending_transaction_tx_keys",
"Adds txKeys() to PendingTransaction in wallet2_api.h",
"patches/eigenwallet_0003_pendingTransaction_getTxKey.patch"
"patches/eigenwallet_0003_pending_transaction_tx_keys.patch"
),
];

Expand Down

This file was deleted.

140 changes: 140 additions & 0 deletions monero-sys/patches/eigenwallet_0003_pending_transaction_tx_keys.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
index 2dd118ea3..0972089d1 100644
--- a/src/wallet/api/pending_transaction.cpp
+++ b/src/wallet/api/pending_transaction.cpp
@@ -78,6 +78,103 @@ std::vector<std::string> PendingTransactionImpl::txid() const
return txid;
}

+// This function returns **all** tx keys for the transaction with the given tx hash in the [`PendingTransaction`].
+// A [`PendingTransaction`] can contain multiple transactions. A single transaction can have multiple tx keys.
+std::vector<std::tuple<std::string, std::string, std::string>> PendingTransactionImpl::txKeys(const std::string &tx_hash) const
+{
+ std::vector<std::tuple<std::string, std::string, std::string>> keys;
+
+ for (const auto &ptx : m_pending_tx)
+ {
+ const std::string current_tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx));
+
+ if (current_tx_hash != tx_hash)
+ {
+ continue;
+ }
+
+ const std::string main_tx_key = epee::string_tools::pod_to_hex(unwrap(unwrap(ptx.tx_key)));
+
+ if (ptx.tx.vout.size() != ptx.construction_data.splitted_dsts.size()) {
+ throw std::runtime_error(
+ "Number of outputs in transaction "
+ + current_tx_hash
+ + " (" + std::to_string(ptx.tx.vout.size()) + ")"
+ + " does not match number of destinations ("
+ + std::to_string(ptx.construction_data.splitted_dsts.size()) + ")");
+ }
+
+ // Prepare change-derivation data for change detection
+ const crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(ptx.tx);
+ const crypto::secret_key &view_secret_key = m_wallet.m_wallet->get_account().get_keys().m_view_secret_key;
+ crypto::key_derivation change_derivation;
+ if (!crypto::generate_key_derivation(tx_pub_key, view_secret_key, change_derivation)) {
+ throw std::runtime_error("Failed to generate change derivation");
+ }
+ const crypto::public_key change_spend_pub = ptx.construction_data.change_dts.addr.m_spend_public_key;
+
+ for (size_t i = 0; i < ptx.tx.vout.size(); i++) {
+ const cryptonote::tx_out tx_output = ptx.tx.vout[i];
+ const cryptonote::tx_destination_entry dest_entry = ptx.construction_data.splitted_dsts[i];
+
+ crypto::public_key out_pk;
+ if (!cryptonote::get_output_public_key(ptx.tx.vout[i], out_pk)) {
+ throw std::runtime_error("Unable to get output public key from transaction out");
+ }
+
+ // Detect change outputs by checking if the output public key matches our private view key.
+ crypto::public_key expected_change_pk;
+ if (!crypto::derive_public_key(change_derivation, i, change_spend_pub, expected_change_pk)) {
+ throw std::runtime_error("Failed to derive change public key");
+ }
+ // If it's a change output, skip it. Otherwise look for the tx key.
+ if (expected_change_pk == out_pk) {
+ continue;
+ }
+
+ std::vector<crypto::secret_key> keys_to_try = ptx.additional_tx_keys;
+ keys_to_try.push_back(ptx.tx_key);
+
+ bool found_key = false;
+ crypto::secret_key matched_key = crypto::null_skey;
+
+ for (const auto &candidate_key: keys_to_try) {
+ // compute derivation from recipient view pubkey and our tx secret key
+ crypto::key_derivation derivation;
+ if (!crypto::generate_key_derivation(dest_entry.addr.m_view_public_key, candidate_key, derivation)) {
+ continue;
+ }
+
+ // derive expected output public key and compare
+ crypto::public_key expected_out_pk;
+ if (!crypto::derive_public_key(derivation, i, dest_entry.addr.m_spend_public_key, expected_out_pk)) {
+ continue;
+ }
+
+ if (expected_out_pk == out_pk) {
+ found_key = true;
+ matched_key = candidate_key;
+ break;
+ }
+ }
+
+ if (!found_key) {
+ throw std::runtime_error("No matching tx key found for output");
+ }
+
+ // push (txid, destination address (human-readable), hex(tx_secret_key))
+ const std::string dest_addr_str = dest_entry.address(m_wallet.m_wallet->nettype(), crypto::null_hash);
+ keys.emplace_back(
+ current_tx_hash,
+ dest_addr_str,
+ epee::string_tools::pod_to_hex(unwrap(unwrap(matched_key)))
+ );
+ }
+ }
+
+ return keys;
+}
+
bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite)
{

diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h
index c5f4328a8..0377eb79c 100644
--- a/src/wallet/api/pending_transaction.h
+++ b/src/wallet/api/pending_transaction.h
@@ -33,6 +33,7 @@

#include <string>
#include <vector>
+#include <tuple>


namespace Monero {
@@ -50,6 +51,7 @@ public:
uint64_t dust() const override;
uint64_t fee() const override;
std::vector<std::string> txid() const override;
+ std::vector<std::tuple<std::string, std::string, std::string>> txKeys(const std::string &tx_hash) const override;
uint64_t txCount() const override;
std::vector<uint32_t> subaddrAccount() const override;
std::vector<std::set<uint32_t>> subaddrIndices() const override;
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index ca807ac87..29a89f273 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -131,6 +131,7 @@ struct PendingTransaction
virtual uint64_t dust() const = 0;
virtual uint64_t fee() const = 0;
virtual std::vector<std::string> txid() const = 0;
+ virtual std::vector<std::tuple<std::string, std::string, std::string>> txKeys(const std::string &tx_hash) const = 0;
/*!
* \brief txCount - number of transactions current transaction will be splitted to
* \return
Loading
Loading