Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 30 additions & 0 deletions monero-harness/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ use monero::{Address, Amount};
use monero_rpc::monerod::MonerodRpc as _;
use monero_rpc::monerod::{self, GenerateBlocks};
use monero_sys::{no_listener, Daemon, SyncProgress, TxReceipt, TxStatus, WalletHandle};
use std::collections::HashMap;
use monero_sys::SubaddressSummary;

use crate::image::{MONEROD_DAEMON_CONTAINER_NAME, MONEROD_DEFAULT_NETWORK, RPC_PORT};

Expand Down Expand Up @@ -475,6 +477,11 @@ impl MoneroWallet {
Ok(self.wallet.main_address().await)
}

/// Get address at a given account and subaddress index.
pub async fn address_at(&self, account_index: u32, address_index: u32) -> Result<Address> {
Ok(self.wallet.address(account_index, address_index).await)
}

pub async fn balance(&self) -> Result<u64> {
// First make sure we're connected to the daemon
let connected = self.wallet.connected().await;
Expand Down Expand Up @@ -507,6 +514,29 @@ impl MoneroWallet {
Ok(self.wallet.unlocked_balance().await.as_pico())
}

/// Create a new subaddress for the given account with the provided label.
pub async fn create_subaddress(
&self,
account_index: u32,
label: impl Into<String>,
) -> Result<()> {
self
.wallet
.create_subaddress(account_index, label.into())
.await?;
Ok(())
}

/// Get summaries for subaddresses within a given account.
pub async fn subaddress_summaries(&self, account_index: u32) -> Result<Vec<SubaddressSummary>> {
Ok(self.wallet.subaddress_summaries(account_index).await?)
}

/// Get non-strict balance per subaddress for main account (index 0).
pub async fn balance_per_subaddress(&self) -> Result<HashMap<u32, u64>> {
Ok(self.wallet.balance_per_subaddress().await)
}

pub async fn refresh(&self) -> Result<()> {
let name = self.name.clone();

Expand Down
5 changes: 5 additions & 0 deletions monero-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ const EMBEDDED_PATCHES: &[EmbeddedPatch] = &[
"Adds txKeys() to PendingTransaction in wallet2_api.h",
"patches/eigenwallet_0003_pending_transaction_tx_keys.patch"
),
embedded_patch!(
"eigenwallet_0004_wallet_impl_balance_per_subaddress.patch",
"Adds balancePerSubaddress() and unlockedBalancePerSubaddress() to wallet::WalletImpl in api/wallet.h",
"patches/eigenwallet_0004_wallet_impl_balance_per_subaddress.patch"
),
];

fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index b7f77a186..0a8cfb0b8 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -238,6 +238,9 @@ public:
virtual uint64_t getBytesReceived() override;
virtual uint64_t getBytesSent() override;

+ std::map<uint32_t, uint64_t> balancePerSubaddress(uint32_t accountIndex, bool strict) const;
+ std::map<uint32_t, uint64_t> unlockedBalancePerSubaddress(uint32_t accountIndex, bool strict) const;
+
std::string getMultisigSeed(const std::string &seed_offset) const override;
std::pair<std::uint32_t, std::uint32_t> getSubaddressIndex(const std::string &address) const override;
void freeze(const std::string &key_image) override;
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 96393eaaa..3dd62e7d2 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1102,6 +1106,20 @@ uint64_t WalletImpl::unlockedBalance(uint32_t accountIndex) const
return m_wallet->unlocked_balance(accountIndex, false);
}

+std::map<uint32_t, uint64_t> WalletImpl::balancePerSubaddress(uint32_t accountIndex, bool strict) const
+{
+ return m_wallet->balance_per_subaddress(accountIndex, strict);
+}
+
+std::map<uint32_t, uint64_t> WalletImpl::unlockedBalancePerSubaddress(uint32_t accountIndex, bool strict) const
+{
+ auto full = m_wallet->unlocked_balance_per_subaddress(accountIndex, strict);
+ std::map<uint32_t, uint64_t> result;
+ for (const auto &p : full)
+ result[p.first] = p.second.first; // extract the unlocked amount only
+ return result;
+}
+
uint64_t WalletImpl::blockChainHeight() const
{
if(m_wallet->light_wallet()) {
119 changes: 118 additions & 1 deletion monero-sys/src/bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "../monero/src/wallet/api/wallet2_api.h"
#include "../monero/src/wallet/api/wallet_manager.h"
#include "../monero/src/wallet/api/wallet.h"


/**
Expand Down Expand Up @@ -82,6 +83,19 @@ namespace Monero
wallet.startRefresh();
}

inline size_t numSubaddresses(const Wallet &wallet, uint32_t account_index)
{
return wallet.numSubaddresses(account_index);
}

inline std::unique_ptr<std::string> getSubaddressLabel(const Wallet &wallet,
uint32_t account_index,
uint32_t address_index)
{
auto label = wallet.getSubaddressLabel(account_index, address_index);
return std::make_unique<std::string>(label);
}

/**
* Same as for [`address`]
*/
Expand Down Expand Up @@ -282,9 +296,112 @@ namespace Monero
return static_cast<uint64_t>(tx_info.timestamp());
}


inline uint32_t transactionInfoSubaddrAccount(const TransactionInfo &tx_info)
{
return tx_info.subaddrAccount();
}

inline std::unique_ptr<std::vector<uint32_t>> transactionInfoSubaddrIndices(const TransactionInfo &tx_info)
{
auto indices_set = tx_info.subaddrIndex();
auto vec = std::make_unique<std::vector<uint32_t>>();
vec->reserve(indices_set.size());
for (auto const &idx : indices_set) {
vec->push_back(idx);
}
return vec;
}

// Method-style overloads so Rust can call via `wallet.pinned().transactionInfoSubaddr*(&tx_info)`
inline uint32_t transactionInfoSubaddrAccount(Wallet & /*wallet*/, const TransactionInfo &tx_info)
{
return transactionInfoSubaddrAccount(tx_info);
}

inline std::unique_ptr<std::vector<uint32_t>> transactionInfoSubaddrIndices(Wallet & /*wallet*/, const TransactionInfo &tx_info)
{
return transactionInfoSubaddrIndices(tx_info);
}

/**
* Get subaddress indices for a given account with balance.
* strict: If true, only includes confirmed and unlocked balance.
* If false, pending and unconfirmed transactions are also included.
*/
inline std::unique_ptr<std::vector<uint32_t>> walletBalancePerSubaddrIndices(Wallet &wallet, uint32_t account_index, bool strict)
{
auto *impl = dynamic_cast<WalletImpl*>(&wallet);
auto indices = std::make_unique<std::vector<uint32_t>>();
if (!impl) return indices;

auto map = impl->balancePerSubaddress(account_index, strict);
indices->reserve(map.size());
for (const auto &p : map) indices->push_back(p.first);
return indices;
}

/*
* Get balance amounts received by subaddresses by a given account.
* strict: If true, only includes confirmed and unlocked balance.
* If false, pending and unconfirmed transactions are also included.
*/
inline std::unique_ptr<std::vector<uint64_t>> walletBalancePerSubaddrAmounts(Wallet &wallet, uint32_t account_index, bool strict)
{
auto *impl = dynamic_cast<WalletImpl*>(&wallet);
auto amounts = std::make_unique<std::vector<uint64_t>>();
if (!impl) return amounts;

auto map = impl->balancePerSubaddress(account_index, strict);
amounts->reserve(map.size());
for (const auto &p : map) amounts->push_back(p.second);
return amounts;
}

inline std::unique_ptr<std::vector<uint32_t>> walletUnlockedBalancePerSubaddrIndices(Wallet &wallet, uint32_t account_index, bool strict)
{
auto *impl = dynamic_cast<WalletImpl*>(&wallet);
auto indices = std::make_unique<std::vector<uint32_t>>();
if (!impl) return indices;

auto map = impl->unlockedBalancePerSubaddress(account_index, strict);
indices->reserve(map.size());
for (const auto &p : map) indices->push_back(p.first);
return indices;
}

inline std::unique_ptr<std::vector<uint64_t>> walletUnlockedBalancePerSubaddrAmounts(Wallet &wallet, uint32_t account_index, bool strict)
{
auto *impl = dynamic_cast<WalletImpl*>(&wallet);
auto amounts = std::make_unique<std::vector<uint64_t>>();
if (!impl) return amounts;

auto map = impl->unlockedBalancePerSubaddress(account_index, strict);
amounts->reserve(map.size());
for (const auto &p : map) amounts->push_back(p.second);
return amounts;
}

inline std::unique_ptr<std::vector<std::string>> pendingTransactionTxKeys(const PendingTransaction &tx, const std::string &tx_hash)
{
auto keys = tx.txKeys(tx_hash);
auto vec = std::make_unique<std::vector<std::string>>();
vec->reserve(keys.size());
for (auto &key : keys)
vec->push_back(std::move(key));
return vec;
}

inline void addSubaddress(Wallet &wallet, uint32_t account_index, const std::string &label)
{
auto *sub = wallet.subaddress();
sub->addRow(account_index, label);
}

inline void setSubaddressLabel(Wallet &wallet, uint32_t account_index, uint32_t address_index, const std::string &label)
{
auto *sub = wallet.subaddress();
sub->setLabel(account_index, address_index, label);
}

// bridge.h
#pragma once
Expand Down
59 changes: 59 additions & 0 deletions monero-sys/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,13 +347,72 @@ pub mod ffi {
/// Get the timestamp of the transaction.
fn transactionInfoTimestamp(tx_info: &TransactionInfo) -> u64;

/// Get the subaddress account of a transaction (free function form).
fn transactionInfoSubaddrAccount(tx_info: &TransactionInfo) -> u32;

/// Get the subaddress indices of a transaction as a vector (free function form).
fn transactionInfoSubaddrIndices(tx_info: &TransactionInfo) -> UniquePtr<CxxVector<u32>>;

/// Get subaddress indices for a given account with balance.
/// strict: If true, only includes confirmed and unlocked balance.
/// If false, pending and unconfirmed transactions are also included.
fn walletBalancePerSubaddrIndices(
wallet: Pin<&mut Wallet>,
account_index: u32,
strict: bool,
) -> UniquePtr<CxxVector<u32>>;
/// Get balance amounts received by subaddresses by a given account.
/// strict: If true, only includes confirmed and unlocked balance.
/// If false, pending and unconfirmed transactions are also included.
fn walletBalancePerSubaddrAmounts(
wallet: Pin<&mut Wallet>,
account_index: u32,
strict: bool,
) -> UniquePtr<CxxVector<u64>>;
/// Get non-strict or strict unlocked balance per subaddress for a given account (indices).
fn walletUnlockedBalancePerSubaddrIndices(
wallet: Pin<&mut Wallet>,
account_index: u32,
strict: bool,
) -> UniquePtr<CxxVector<u32>>;
/// Get non-strict or strict unlocked balance per subaddress for a given account (amounts).
fn walletUnlockedBalancePerSubaddrAmounts(
wallet: Pin<&mut Wallet>,
account_index: u32,
strict: bool,
) -> UniquePtr<CxxVector<u64>>;
/// Sign a message with the wallet's private key.
fn signMessage(
wallet: Pin<&mut Wallet>,
message: &CxxString,
address: &CxxString,
sign_with_view_key: bool,
) -> Result<UniquePtr<CxxString>>;

/// Get the number of subaddresses for a given account index.
fn numSubaddresses(wallet: &Wallet, account_index: u32) -> usize;

/// Get the label for a given subaddress.
fn getSubaddressLabel(
wallet: &Wallet,
account_index: u32,
address_index: u32,
) -> Result<UniquePtr<CxxString>>;

/// Create a new subaddress for the given account with an optional label.
fn addSubaddress(
self: Pin<&mut Wallet>,
account_index: u32,
label: &CxxString,
) -> Result<()>;

/// Set a label for a specific subaddress.
fn setSubaddressLabel(
self: Pin<&mut Wallet>,
account_index: u32,
address_index: u32,
label: &CxxString,
) -> Result<()>;
}
}

Expand Down
Loading
Loading