Skip to content

Conversation

@rafael-xmr
Copy link

@rafael-xmr rafael-xmr commented Nov 6, 2025

Note

Add Monero subaddress listing (with received/tx counts), creation, and labeling, wired through FFI, Tauri commands/events, Redux, and a new UI modal/button.

  • Monero Core (FFI/Bindings):
    • Expose subaddress APIs in monero-sys (numSubaddresses, getSubaddressLabel, addSubaddress, setSubaddressLabel).
    • Add transaction helpers for subaddress account/indices.
    • Implement SubaddressSummary and wallet methods to compute summaries per account (address, label, received, tx_count) and create/update subaddresses.
  • Backend API / Commands:
    • New requests/commands: get_monero_subaddresses, create_monero_subaddress, set_monero_subaddress_label (wired in src-tauri/src/commands.rs).
    • Emit MoneroWalletUpdate::SubaddressesUpdate with current summaries.
  • Frontend (GUI):
    • New SubaddressesModal to list subaddresses, copy addresses, show received/tx count, create new subaddress, and edit labels.
    • Add "Subaddresses" action button in WalletActionButtons.
    • Redux: add subaddresses to wallet state and setSubaddresses action; handle SubaddressesUpdate in background.ts.
    • RPC helpers for fetching/creating/updating subaddresses in renderer/rpc.ts.

Written by Cursor Bugbot for commit d893570. This will update automatically on new commits. Configure here.

@binarybaron
Copy link

very cool! I'll review this ASAP

@binarybaron
Copy link

Compilations fails with this error on my machine:

/Users/_/Development/eigenwallet/wallet/target/debug/build/monero-sys-c81930dca039ffc4/out/cxxbridge/sources/monero-sys/src/bridge.rs.cc:1031:10: error: cannot initialize a variable of type 'bool (*)(::Monero::Wallet &, ::std::uint32_t, const ::std::string &)' (aka 'bool (*)(Monero::Wallet &, unsigned int, const basic_string<char> &)') with an lvalue of type 'bool (Wallet *, uint32_t, const std::string &)' (aka 'bool (Monero::Wallet *, unsigned int, const basic_string<char> &)'): type mismatch at 1st parameter ('::Monero::Wallet &' (aka 'Monero::Wallet &') vs 'Wallet *')
 1031 |   bool (*addSubaddress$)(::Monero::Wallet &, ::std::uint32_t, ::std::string const &) = ::Monero::addSubaddress;
      |          ^                                                                             ~~~~~~~~~~~~~~~~~~~~~~~
/Users/_/Development/eigenwallet/wallet/target/debug/build/monero-sys-c81930dca039ffc4/out/cxxbridge/sources/monero-sys/src/bridge.rs.cc:1043:10: error: cannot initialize a variable of type 'bool (*)(::Monero::Wallet &, ::std::uint32_t, ::std::uint32_t, const ::std::string &)' (aka 'bool (*)(Monero::Wallet &, unsigned int, unsigned int, const basic_string<char> &)') with an lvalue of type 'bool (Wallet *, uint32_t, uint32_t, const std::string &)' (aka 'bool (Monero::Wallet *, unsigned int, unsigned int, const basic_string<char> &)'): type mismatch at 1st parameter ('::Monero::Wallet &' (aka 'Monero::Wallet &') vs 'Wallet *')
 1043 |   bool (*setSubaddressLabel$)(::Monero::Wallet &, ::std::uint32_t, ::std::uint32_t, ::std::string const &) = ::Monero::setSubaddressLabel;
      |          ^                                                                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 warnings and 2 errors generated.

@binarybaron
Copy link

bugbot run

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no bugs!


Copy link

@binarybaron binarybaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some more comments

@binarybaron
Copy link

The changes look good! Please also write a test for the functionality that was added to monero-sys. See monero-tests/tests/transaction_keys.rs for ex example.

Copy link

@binarybaron binarybaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks promising! I'm impressed for quickly you got a hold of the codebase. This is definitely going into the right direction.

I'm reviewing this fairly strictly / in-depth because my hope is that I can pass onto you some of the unofficial and undocumented guidelines / best practices we have for the project.

Copy link

@Einliterflasche Einliterflasche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments I forgot to submit

@binarybaron
Copy link

The monero-sys crate fails with this error on my machine:

warning: monero-sys@0.1.0: monero/src/cryptonote_basic/cryptonote_boost_serialization.h:39:10: fatal error: 'boost/archive/portable_binary_iarchive.hpp' file not found
warning: monero-sys@0.1.0:    39 | #include <boost/archive/portable_binary_iarchive.hpp>
warning: monero-sys@0.1.0:       |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
warning: monero-sys@0.1.0: 41 warnings and 1 error generated.
error: failed to run custom build command for `monero-sys v0.1.0 (/Users/mohan/Development/eigenwallet/wallet/monero-sys)`

@binarybaron
Copy link

The monero-sys crate fails with this error on my machine:

warning: monero-sys@0.1.0: monero/src/cryptonote_basic/cryptonote_boost_serialization.h:39:10: fatal error: 'boost/archive/portable_binary_iarchive.hpp' file not found
warning: monero-sys@0.1.0:    39 | #include <boost/archive/portable_binary_iarchive.hpp>
warning: monero-sys@0.1.0:       |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
warning: monero-sys@0.1.0: 41 warnings and 1 error generated.
error: failed to run custom build command for `monero-sys v0.1.0 (/Users/mohan/Development/eigenwallet/wallet/monero-sys)`

Does this compile on your machine? @rafael-xmr

Copy link

@Einliterflasche Einliterflasche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am getting this error:

[monero-sys 0.1.0] cargo:warning=In file included from /Users/me/code/xmr-btc-swap/target/debug/build/monero-sys-b1c8e6bd6f43bf85/out/cxxbridge/sources/monero-sys/src/bridge.rs.cc:2:
[monero-sys 0.1.0] cargo:warning=src/bridge.h:686:48: error: functions that differ only in their return type cannot be overloaded
[monero-sys 0.1.0] cargo:warning=  686 |     inline std::unique_ptr<std::vector<TxKey>> pendingTransactionTxKeys(const PendingTransaction &tx, const std::string &tx_hash)
[monero-sys 0.1.0] cargo:warning=      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
[monero-sys 0.1.0] cargo:warning=src/bridge.h:384:54: note: previous definition is here
[monero-sys 0.1.0] cargo:warning=  384 |     inline std::unique_ptr<std::vector<std::string>> pendingTransactionTxKeys(const PendingTransaction &tx, const std::string &tx_hash)
[monero-sys 0.1.0] cargo:warning=      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^

It seems you added another pendingTxKeys function. But the existing one should work too. Getting rid of the new function should also remove the other two errors:

[monero-sys 0.1.0] cargo:warning=src/bridge.h:390:18: error: no matching member function for call to 'push_back'
[monero-sys 0.1.0] cargo:warning=  390 |             vec->push_back(std::move(key));
[monero-sys 0.1.0] cargo:warning=      |             ~~~~~^~~~~~~~~
[monero-sys 0.1.0] cargo:warning=/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__vector/vector.h:452:60: note: candidate function not viable: no known conversion from '__libcpp_remove_reference_t<tuple<string, string, string> &>' (aka 'std::tuple<std::string, std::string, std::string>') to 'const value_type' (aka 'const std::string') for 1st argument
[monero-sys 0.1.0] cargo:warning=  452 |   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void push_back(const_reference __x) { emplace_back(__x); }
[monero-sys 0.1.0] cargo:warning=      |                                                            ^         ~~~~~~~~~~~~~~~~~~~

C++ compilation errors in monero-sys are a bit hard to debug, because there is so much output. The gist is: compile with -vv (or -- -vv for tauri), scroll up until you see the colored warning: monero-sys@0.1.0: Applying patch to file: src/wallet/wallet2.h lines. Above that, when the colors stop are the real c++ compilation errors/warnings.

@binarybaron
Copy link

Ok cool, compiles on my machine. The Rust code looks fairly good to me but @Einliterflasche should give this another review since this is changing some things about monero-sys which is his area of expertise.

I really like how snappy it feels. It's good that the addresses are cached and I think it's good that you made a modal for the subaddresses.

Regarding the layout, I think we can still make some improvements:

I'm unsure if this is the best place to display the subaddress. We should also consider not displaying it if its just the primary address.

In its current form it is fairly wide and causes the column to be quite wide as well which leaves less space for the timestamp and the other things (which are arguably more important to the user).

Screenshot 2025-11-20 at 17 40 44

We may want to go into more of the direction of Feather Wallet here and use an actual table. I'm not a huge fan when clicking things changes the layout (when you click the "Edit label" button). The label could just be a TextField (like in Feather wallet). It'd have the current label pre-filled and editing would change it. You could do this by adding some logic that if the user did not change the text in the field for more than 5s, we save the label in the wallet. I'm also unsure if we even need to display the "tx count" for each subaddress.

Screenshot 2025-11-20 at 17 40 38 Screenshot 2025-11-20 at 17 50 55 Screenshot 2025-11-20 at 17 48 25

@Einliterflasche
Copy link

How about something like this for the subaddresses?

diff --git a/src-gui/src/renderer/components/pages/monero/components/TransactionItem.tsx b/src-gui/src/renderer/components/pages/monero/components/TransactionItem.tsx
index f6aef9d3..20ccb2b8 100644
--- a/src-gui/src/renderer/components/pages/monero/components/TransactionItem.tsx
+++ b/src-gui/src/renderer/components/pages/monero/components/TransactionItem.tsx
@@ -6,7 +6,7 @@ import {
   MenuItem,
   Typography,
 } from "@mui/material";
-import { TransactionDirection, TransactionInfo } from "models/tauriModel";
+import { SubaddressSummary, TransactionDirection, TransactionInfo } from "models/tauriModel";
 import {
   CallReceived as IncomingIcon,
   MoreVert as MoreVertIcon,
@@ -22,6 +22,8 @@ import { isTestnet } from "store/config";
 import { open } from "@tauri-apps/plugin-shell";
 import dayjs from "dayjs";
 import { useState } from "react";
+import { useAppSelector } from "store/hooks";
+import _ from "lodash";
 
 interface TransactionItemProps {
   transaction: TransactionInfo;
@@ -40,6 +42,21 @@ export default function TransactionItem({ transaction }: TransactionItemProps) {
   const [menuAnchorEl, setMenuAnchorEl] = useState<null | HTMLElement>(null);
   const menuOpen = Boolean(menuAnchorEl);
 
+  // Show the subaddress label if we have one, else the truncated address
+  const subaddresses: SubaddressSummary[] = useAppSelector((s) => s.wallet.state.subaddresses);
+  const subaddress: SubaddressSummary | undefined = subaddresses.find((s) => s.address === transaction.received_address);
+
+  let addressLabel: string | null = null;
+  if (isIncoming && transaction.received_address) {
+
+    if (subaddress) {
+      addressLabel = subaddress.label;
+    } else {
+      addressLabel = _.truncate(transaction.received_address, { length: 6 });
+    }
+  }
+
+
   return (
     <Box
       sx={{
@@ -107,11 +124,11 @@ export default function TransactionItem({ transaction }: TransactionItemProps) {
           <Typography variant="caption" sx={{ gridArea: "2 / 2" }}>
             <FiatPiconeroAmount amount={transaction.amount} />
           </Typography>
-          {isIncoming && transaction.received_address && (
+          {isIncoming && transaction.received_address && subaddress && (
             <Chip
               size="small"
               variant="outlined"
-              label={transaction.received_address}
+              label={<>{`Address #${subaddress.address_index}`}<i>{`"${addressLabel}"`}</i></>}
               sx={{ gridArea: "3 / 2", maxWidth: 360 }}
             />
           )}
diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs
index 7225cf35..ef7da39c 100644
--- a/src-tauri/src/commands.rs
+++ b/src-tauri/src/commands.rs
@@ -7,16 +7,16 @@ use swap::cli::{
         request::{
             BalanceArgs, BuyXmrArgs, CancelAndRefundArgs, ChangeMoneroNodeArgs,
             CheckElectrumNodeArgs, CheckElectrumNodeResponse, CheckMoneroNodeArgs,
-            CheckMoneroNodeResponse, CheckSeedArgs, CheckSeedResponse, DfxAuthenticateResponse,
-            ExportBitcoinWalletArgs, GetBitcoinAddressArgs, GetCurrentSwapArgs, GetDataDirArgs,
-            GetHistoryArgs, GetLogsArgs, GetMoneroAddressesArgs, GetMoneroBalanceArgs,
-            GetMoneroHistoryArgs, GetMoneroMainAddressArgs, GetMoneroSeedArgs,
-            GetMoneroSubaddressesArgs, GetMoneroSyncProgressArgs, GetPendingApprovalsResponse,
-            GetRestoreHeightArgs, GetSwapInfoArgs, GetSwapInfosAllArgs, ListSellersArgs,
-            MoneroRecoveryArgs, RedactArgs, RejectApprovalArgs, RejectApprovalResponse,
-            ResolveApprovalArgs, ResumeSwapArgs, SendMoneroArgs, SetMoneroSubaddressLabelArgs,
-            SetMoneroWalletPasswordArgs, SetRestoreHeightArgs, SuspendCurrentSwapArgs,
-            WithdrawBtcArgs,
+            CheckMoneroNodeResponse, CheckSeedArgs, CheckSeedResponse, CreateMoneroSubaddressArgs,
+            DfxAuthenticateResponse, ExportBitcoinWalletArgs, GetBitcoinAddressArgs,
+            GetCurrentSwapArgs, GetDataDirArgs, GetHistoryArgs, GetLogsArgs,
+            GetMoneroAddressesArgs, GetMoneroBalanceArgs, GetMoneroHistoryArgs,
+            GetMoneroMainAddressArgs, GetMoneroSeedArgs, GetMoneroSubaddressesArgs,
+            GetMoneroSyncProgressArgs, GetPendingApprovalsResponse, GetRestoreHeightArgs,
+            GetSwapInfoArgs, GetSwapInfosAllArgs, ListSellersArgs, MoneroRecoveryArgs, RedactArgs,
+            RejectApprovalArgs, RejectApprovalResponse, ResolveApprovalArgs, ResumeSwapArgs,
+            SendMoneroArgs, SetMoneroSubaddressLabelArgs, SetMoneroWalletPasswordArgs,
+            SetRestoreHeightArgs, SuspendCurrentSwapArgs, WithdrawBtcArgs,
         },
         tauri_bindings::{ContextStatus, TauriSettings},
         ContextBuilder,

@binarybaron
Copy link

I apologize that this is taking so long to be merged... we were a bit overwhelmed with the p2p improvements and protocol changes. Should get better fairly soon.

I think the UI is still a bit too cluttered. The add address button doesn't need a label field in my opinion and can be integrated into the table itself in some way. I don't think most users think about subaddresses in the way of "creating them". You usually expect them to just be present and to be able to give them labels. Similiar to how Feather Wallet does it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants