aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/api
diff options
context:
space:
mode:
authorkenshi84 <kenshi84@protonmail.ch>2017-02-19 11:42:10 +0900
committerkenshi84 <kenshi84@protonmail.ch>2017-10-07 13:06:21 +0900
commit53ad5a0f42174bca57e24485ef3d40e4b9cf5599 (patch)
treeafc13a3ee6a049ec78ac234e2d55ff46e992b457 /src/wallet/api
parentMerge pull request #2548 (diff)
downloadmonero-53ad5a0f42174bca57e24485ef3d40e4b9cf5599.tar.xz
Subaddresses
Diffstat (limited to 'src/wallet/api')
-rw-r--r--src/wallet/api/address_book.cpp18
-rw-r--r--src/wallet/api/pending_transaction.cpp16
-rw-r--r--src/wallet/api/pending_transaction.h2
-rw-r--r--src/wallet/api/subaddress.cpp91
-rw-r--r--src/wallet/api/subaddress.h56
-rw-r--r--src/wallet/api/subaddress_account.cpp90
-rw-r--r--src/wallet/api/subaddress_account.h56
-rw-r--r--src/wallet/api/transaction_history.cpp16
-rw-r--r--src/wallet/api/transaction_info.cpp17
-rw-r--r--src/wallet/api/transaction_info.h6
-rw-r--r--src/wallet/api/unsigned_transaction.cpp63
-rw-r--r--src/wallet/api/wallet.cpp178
-rw-r--r--src/wallet/api/wallet.h27
-rw-r--r--src/wallet/api/wallet_manager.cpp16
14 files changed, 552 insertions, 100 deletions
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index 9605047b7..da412cd4b 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -48,10 +48,8 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
{
clearStatus();
- cryptonote::account_public_address addr;
- bool has_short_pid;
- crypto::hash8 payment_id_short;
- if(!cryptonote::get_account_integrated_address_from_str(addr, has_short_pid, payment_id_short, m_wallet->m_wallet->testnet(), dst_addr)) {
+ cryptonote::address_parse_info info;
+ if(!cryptonote::get_account_address_from_str(info, m_wallet->m_wallet->testnet(), dst_addr)) {
m_errorString = tr("Invalid destination address");
m_errorCode = Invalid_Address;
return false;
@@ -75,19 +73,19 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
}
// integrated + long payment id provided
- if(has_long_pid && has_short_pid) {
+ if(has_long_pid && info.has_payment_id) {
m_errorString = tr("Integrated address and long payment id can't be used at the same time");
m_errorCode = Invalid_Payment_Id;
return false;
}
// Pad short pid with zeros
- if (has_short_pid)
+ if (info.has_payment_id)
{
- memcpy(payment_id.data, payment_id_short.data, 8);
+ memcpy(payment_id.data, info.payment_id.data, 8);
}
- bool r = m_wallet->m_wallet->add_address_book_row(addr,payment_id,description);
+ bool r = m_wallet->m_wallet->add_address_book_row(info.address,payment_id,description,info.is_subaddress);
if (r)
refresh();
else
@@ -107,9 +105,9 @@ void AddressBookImpl::refresh()
tools::wallet2::address_book_row * row = &rows.at(i);
std::string payment_id = (row->m_payment_id == crypto::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id);
- std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(),row->m_address);
+ std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(), row->m_is_subaddress, row->m_address);
// convert the zero padded short payment id to integrated address
- if (payment_id.length() > 16 && payment_id.substr(16).find_first_not_of('0') == std::string::npos) {
+ if (!row->m_is_subaddress && payment_id.length() > 16 && payment_id.substr(16).find_first_not_of('0') == std::string::npos) {
payment_id = payment_id.substr(0,16);
crypto::hash8 payment_id_short;
if(tools::wallet2::parse_short_payment_id(payment_id, payment_id_short)) {
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
index c98a599e7..e17931de1 100644
--- a/src/wallet/api/pending_transaction.cpp
+++ b/src/wallet/api/pending_transaction.cpp
@@ -172,6 +172,22 @@ uint64_t PendingTransactionImpl::txCount() const
return m_pending_tx.size();
}
+std::vector<uint32_t> PendingTransactionImpl::subaddrAccount() const
+{
+ std::vector<uint32_t> result;
+ for (const auto& ptx : m_pending_tx)
+ result.push_back(ptx.construction_data.subaddr_account);
+ return result;
+}
+
+std::vector<std::set<uint32_t>> PendingTransactionImpl::subaddrIndices() const
+{
+ std::vector<std::set<uint32_t>> result;
+ for (const auto& ptx : m_pending_tx)
+ result.push_back(ptx.construction_data.subaddr_indices);
+ return result;
+}
+
}
namespace Bitmonero = Monero;
diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h
index 0c3e95a85..e5b33ac01 100644
--- a/src/wallet/api/pending_transaction.h
+++ b/src/wallet/api/pending_transaction.h
@@ -51,6 +51,8 @@ public:
uint64_t fee() const;
std::vector<std::string> txid() const;
uint64_t txCount() const;
+ std::vector<uint32_t> subaddrAccount() const;
+ std::vector<std::set<uint32_t>> subaddrIndices() const;
// TODO: continue with interface;
private:
diff --git a/src/wallet/api/subaddress.cpp b/src/wallet/api/subaddress.cpp
new file mode 100644
index 000000000..ceda9a9da
--- /dev/null
+++ b/src/wallet/api/subaddress.cpp
@@ -0,0 +1,91 @@
+// Copyright (c) 2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "subaddress.h"
+#include "wallet.h"
+#include "crypto/hash.h"
+#include "wallet/wallet2.h"
+#include "common_defines.h"
+
+#include <vector>
+
+namespace Monero {
+
+Subaddress::~Subaddress() {}
+
+SubaddressImpl::SubaddressImpl(WalletImpl *wallet)
+ : m_wallet(wallet) {}
+
+void SubaddressImpl::addRow(uint32_t accountIndex, const std::string &label)
+{
+ m_wallet->m_wallet->add_subaddress(accountIndex, label);
+ refresh(accountIndex);
+}
+
+void SubaddressImpl::setLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label)
+{
+ try
+ {
+ m_wallet->m_wallet->set_subaddress_label({accountIndex, addressIndex}, label);
+ refresh(accountIndex);
+ }
+ catch (const std::exception& e)
+ {
+ LOG_ERROR("setLabel: " << e.what());
+ }
+}
+
+void SubaddressImpl::refresh(uint32_t accountIndex)
+{
+ LOG_PRINT_L2("Refreshing subaddress");
+
+ clearRows();
+ for (size_t i = 0; i < m_wallet->m_wallet->get_num_subaddresses(accountIndex); ++i)
+ {
+ m_rows.push_back(new SubaddressRow(i, m_wallet->m_wallet->get_subaddress_as_str({accountIndex, (uint32_t)i}), m_wallet->m_wallet->get_subaddress_label({accountIndex, (uint32_t)i})));
+ }
+}
+
+void SubaddressImpl::clearRows() {
+ for (auto r : m_rows) {
+ delete r;
+ }
+ m_rows.clear();
+}
+
+std::vector<SubaddressRow*> SubaddressImpl::getAll() const
+{
+ return m_rows;
+}
+
+SubaddressImpl::~SubaddressImpl()
+{
+ clearRows();
+}
+
+} // namespace
diff --git a/src/wallet/api/subaddress.h b/src/wallet/api/subaddress.h
new file mode 100644
index 000000000..e3e28eba1
--- /dev/null
+++ b/src/wallet/api/subaddress.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "wallet/wallet2_api.h"
+#include "wallet/wallet2.h"
+
+namespace Monero {
+
+class WalletImpl;
+
+class SubaddressImpl : public Subaddress
+{
+public:
+ SubaddressImpl(WalletImpl * wallet);
+ ~SubaddressImpl();
+
+ // Fetches addresses from Wallet2
+ void refresh(uint32_t accountIndex);
+ std::vector<SubaddressRow*> getAll() const;
+ void addRow(uint32_t accountIndex, const std::string &label);
+ void setLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label);
+
+private:
+ void clearRows();
+
+private:
+ WalletImpl *m_wallet;
+ std::vector<SubaddressRow*> m_rows;
+};
+
+}
diff --git a/src/wallet/api/subaddress_account.cpp b/src/wallet/api/subaddress_account.cpp
new file mode 100644
index 000000000..736ef874e
--- /dev/null
+++ b/src/wallet/api/subaddress_account.cpp
@@ -0,0 +1,90 @@
+// Copyright (c) 2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "subaddress_account.h"
+#include "wallet.h"
+#include "crypto/hash.h"
+#include "wallet/wallet2.h"
+#include "common_defines.h"
+
+#include <vector>
+
+namespace Monero {
+
+SubaddressAccount::~SubaddressAccount() {}
+
+SubaddressAccountImpl::SubaddressAccountImpl(WalletImpl *wallet)
+ : m_wallet(wallet) {}
+
+void SubaddressAccountImpl::addRow(const std::string &label)
+{
+ m_wallet->m_wallet->add_subaddress_account(label);
+ refresh();
+}
+
+void SubaddressAccountImpl::setLabel(uint32_t accountIndex, const std::string &label)
+{
+ m_wallet->m_wallet->set_subaddress_label({accountIndex, 0}, label);
+ refresh();
+}
+
+void SubaddressAccountImpl::refresh()
+{
+ LOG_PRINT_L2("Refreshing subaddress account");
+
+ clearRows();
+ for (uint32_t i = 0; i < m_wallet->m_wallet->get_num_subaddress_accounts(); ++i)
+ {
+ m_rows.push_back(new SubaddressAccountRow(
+ i,
+ m_wallet->m_wallet->get_subaddress_as_str({i,0}).substr(0,6),
+ m_wallet->m_wallet->get_subaddress_label({i,0}),
+ cryptonote::print_money(m_wallet->m_wallet->balance(i)),
+ cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i))
+ ));
+ }
+}
+
+void SubaddressAccountImpl::clearRows() {
+ for (auto r : m_rows) {
+ delete r;
+ }
+ m_rows.clear();
+}
+
+std::vector<SubaddressAccountRow*> SubaddressAccountImpl::getAll() const
+{
+ return m_rows;
+}
+
+SubaddressAccountImpl::~SubaddressAccountImpl()
+{
+ clearRows();
+}
+
+} // namespace
diff --git a/src/wallet/api/subaddress_account.h b/src/wallet/api/subaddress_account.h
new file mode 100644
index 000000000..107d7f87f
--- /dev/null
+++ b/src/wallet/api/subaddress_account.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "wallet/wallet2_api.h"
+#include "wallet/wallet2.h"
+
+namespace Monero {
+
+class WalletImpl;
+
+class SubaddressAccountImpl : public SubaddressAccount
+{
+public:
+ SubaddressAccountImpl(WalletImpl * wallet);
+ ~SubaddressAccountImpl();
+
+ // Fetches addresses from Wallet2
+ void refresh();
+ std::vector<SubaddressAccountRow*> getAll() const;
+ void addRow(const std::string &label);
+ void setLabel(uint32_t accountIndex, const std::string &label);
+
+private:
+ void clearRows();
+
+private:
+ WalletImpl *m_wallet;
+ std::vector<SubaddressAccountRow*> m_rows;
+};
+
+}
diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp
index 23d3905b2..b6ba8c359 100644
--- a/src/wallet/api/transaction_history.cpp
+++ b/src/wallet/api/transaction_history.cpp
@@ -130,6 +130,9 @@ void TransactionHistoryImpl::refresh()
ti->m_direction = TransactionInfo::Direction_In;
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
ti->m_blockheight = pd.m_block_height;
+ ti->m_subaddrIndex = { pd.m_subaddr_index.minor };
+ ti->m_subaddrAccount = pd.m_subaddr_index.major;
+ ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index);
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = wallet_height - pd.m_block_height;
ti->m_unlock_time = pd.m_unlock_time;
@@ -174,12 +177,15 @@ void TransactionHistoryImpl::refresh()
ti->m_direction = TransactionInfo::Direction_Out;
ti->m_hash = string_tools::pod_to_hex(hash);
ti->m_blockheight = pd.m_block_height;
+ ti->m_subaddrIndex = pd.m_subaddr_indices;
+ ti->m_subaddrAccount = pd.m_subaddr_account;
+ ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = wallet_height - pd.m_block_height;
// single output transaction might contain multiple transfers
for (const auto &d: pd.m_dests) {
- ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->testnet(), d.addr)});
+ ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->testnet(), d.is_subaddress, d.addr)});
}
m_history.push_back(ti);
}
@@ -199,12 +205,15 @@ void TransactionHistoryImpl::refresh()
TransactionInfoImpl * ti = new TransactionInfoImpl();
ti->m_paymentid = payment_id;
- ti->m_amount = amount - pd.m_change;
+ ti->m_amount = amount - pd.m_change - fee;
ti->m_fee = fee;
ti->m_direction = TransactionInfo::Direction_Out;
ti->m_failed = is_failed;
ti->m_pending = true;
ti->m_hash = string_tools::pod_to_hex(hash);
+ ti->m_subaddrIndex = pd.m_subaddr_indices;
+ ti->m_subaddrAccount = pd.m_subaddr_account;
+ ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = 0;
m_history.push_back(ti);
@@ -226,6 +235,9 @@ void TransactionHistoryImpl::refresh()
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
ti->m_blockheight = pd.m_block_height;
ti->m_pending = true;
+ ti->m_subaddrIndex = { pd.m_subaddr_index.minor };
+ ti->m_subaddrAccount = pd.m_subaddr_index.major;
+ ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index);
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = 0;
m_history.push_back(ti);
diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp
index 171272265..1a5df454c 100644
--- a/src/wallet/api/transaction_info.cpp
+++ b/src/wallet/api/transaction_info.cpp
@@ -48,6 +48,7 @@ TransactionInfoImpl::TransactionInfoImpl()
, m_amount(0)
, m_fee(0)
, m_blockheight(0)
+ , m_subaddrAccount(0)
, m_timestamp(0)
, m_confirmations(0)
, m_unlock_time(0)
@@ -91,6 +92,22 @@ uint64_t TransactionInfoImpl::blockHeight() const
return m_blockheight;
}
+std::set<uint32_t> TransactionInfoImpl::subaddrIndex() const
+{
+ return m_subaddrIndex;
+}
+
+uint32_t TransactionInfoImpl::subaddrAccount() const
+{
+ return m_subaddrAccount;
+}
+
+string TransactionInfoImpl::label() const
+{
+ return m_label;
+}
+
+
string TransactionInfoImpl::hash() const
{
return m_hash;
diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h
index ee56b859f..d19ef8899 100644
--- a/src/wallet/api/transaction_info.h
+++ b/src/wallet/api/transaction_info.h
@@ -50,6 +50,9 @@ public:
//! always 0 for incoming txes
virtual uint64_t fee() const;
virtual uint64_t blockHeight() const;
+ virtual std::set<uint32_t> subaddrIndex() const;
+ virtual uint32_t subaddrAccount() const;
+ virtual std::string label() const;
virtual std::string hash() const;
virtual std::time_t timestamp() const;
@@ -65,6 +68,9 @@ private:
uint64_t m_amount;
uint64_t m_fee;
uint64_t m_blockheight;
+ std::set<uint32_t> m_subaddrIndex; // always unique index for incoming transfers; can be multiple indices for outgoing transfers
+ uint32_t m_subaddrAccount;
+ std::string m_label;
std::string m_hash;
std::time_t m_timestamp;
std::string m_paymentid;
diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp
index 5105278e4..4c8c5ade2 100644
--- a/src/wallet/api/unsigned_transaction.cpp
+++ b/src/wallet/api/unsigned_transaction.cpp
@@ -102,12 +102,38 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu
// gather info to ask the user
uint64_t amount = 0, amount_to_dests = 0, change = 0;
size_t min_ring_size = ~0;
- std::unordered_map<std::string, uint64_t> dests;
- const std::string wallet_address = m_wallet.m_wallet->get_account().get_public_address_str(m_wallet.m_wallet->testnet());
+ std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> dests;
int first_known_non_zero_change_index = -1;
+ std::string payment_id_string = "";
for (size_t n = 0; n < get_num_txes(); ++n)
{
const tools::wallet2::tx_construction_data &cd = get_tx(n);
+
+ std::vector<cryptonote::tx_extra_field> tx_extra_fields;
+ bool has_encrypted_payment_id = false;
+ crypto::hash8 payment_id8 = crypto::null_hash8;
+ if (cryptonote::parse_tx_extra(cd.extra, tx_extra_fields))
+ {
+ cryptonote::tx_extra_nonce extra_nonce;
+ if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
+ {
+ crypto::hash payment_id;
+ if(cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
+ {
+ if (!payment_id_string.empty())
+ payment_id_string += ", ";
+ payment_id_string = std::string("encrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id8);
+ has_encrypted_payment_id = true;
+ }
+ else if (cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
+ {
+ if (!payment_id_string.empty())
+ payment_id_string += ", ";
+ payment_id_string = std::string("unencrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id);
+ }
+ }
+ }
+
for (size_t s = 0; s < cd.sources.size(); ++s)
{
amount += cd.sources[s].amount;
@@ -118,24 +144,31 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu
for (size_t d = 0; d < cd.splitted_dsts.size(); ++d)
{
const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d];
- std::string address = get_account_address_as_str(m_wallet.m_wallet->testnet(), entry.addr);
- std::unordered_map<std::string,uint64_t>::iterator i = dests.find(address);
+ std::string address, standard_address = get_account_address_as_str(m_wallet.testnet(), entry.is_subaddress, entry.addr);
+ if (has_encrypted_payment_id && !entry.is_subaddress)
+ {
+ address = get_account_integrated_address_as_str(m_wallet.testnet(), entry.addr, payment_id8);
+ address += std::string(" (" + standard_address + " with encrypted payment id " + epee::string_tools::pod_to_hex(payment_id8) + ")");
+ }
+ else
+ address = standard_address;
+ auto i = dests.find(entry.addr);
if (i == dests.end())
- dests.insert(std::make_pair(address, entry.amount));
+ dests.insert(std::make_pair(entry.addr, std::make_pair(address, entry.amount)));
else
- i->second += entry.amount;
+ i->second.second += entry.amount;
amount_to_dests += entry.amount;
}
if (cd.change_dts.amount > 0)
{
- std::unordered_map<std::string, uint64_t>::iterator it = dests.find(get_account_address_as_str(m_wallet.m_wallet->testnet(), cd.change_dts.addr));
+ auto it = dests.find(cd.change_dts.addr);
if (it == dests.end())
{
m_status = Status_Error;
m_errorString = tr("Claimed change does not go to a paid address");
return false;
}
- if (it->second < cd.change_dts.amount)
+ if (it->second.second < cd.change_dts.amount)
{
m_status = Status_Error;
m_errorString = tr("Claimed change is larger than payment to the change address");
@@ -153,15 +186,15 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu
}
}
change += cd.change_dts.amount;
- it->second -= cd.change_dts.amount;
- if (it->second == 0)
- dests.erase(get_account_address_as_str(m_wallet.m_wallet->testnet(), cd.change_dts.addr));
+ it->second.second -= cd.change_dts.amount;
+ if (it->second.second == 0)
+ dests.erase(cd.change_dts.addr);
}
}
std::string dest_string;
- for (std::unordered_map<std::string, uint64_t>::const_iterator i = dests.begin(); i != dests.end(); )
+ for (auto i = dests.begin(); i != dests.end(); )
{
- dest_string += (boost::format(tr("sending %s to %s")) % cryptonote::print_money(i->second) % i->first).str();
+ dest_string += (boost::format(tr("sending %s to %s")) % cryptonote::print_money(i->second.second) % i->second.first).str();
++i;
if (i != dests.end())
dest_string += ", ";
@@ -172,7 +205,7 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu
std::string change_string;
if (change > 0)
{
- std::string address = get_account_address_as_str(m_wallet.m_wallet->testnet(), get_tx(0).change_dts.addr);
+ std::string address = get_account_address_as_str(m_wallet.m_wallet->testnet(), get_tx(0).subaddr_account > 0, get_tx(0).change_dts.addr);
change_string += (boost::format(tr("%s change to %s")) % cryptonote::print_money(change) % address).str();
}
else
@@ -260,7 +293,7 @@ std::vector<std::string> UnsignedTransactionImpl::recipientAddress() const
// TODO: return integrated address if short payment ID exists
std::vector<string> result;
for (const auto &utx: m_unsigned_tx_set.txes) {
- result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].addr));
+ result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].is_subaddress, utx.dests[0].addr));
}
return result;
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 9cd72b543..a932d9d6f 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -34,6 +34,8 @@
#include "unsigned_transaction.h"
#include "transaction_history.h"
#include "address_book.h"
+#include "subaddress.h"
+#include "subaddress_account.h"
#include "common_defines.h"
#include "common/util.h"
@@ -100,14 +102,15 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount)
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
{
std::string tx_hash = epee::string_tools::pod_to_hex(txid);
LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height
<< ", tx: " << tx_hash
- << ", amount: " << print_money(amount));
+ << ", amount: " << print_money(amount)
+ << ", idx: " << subaddr_index);
// do not signal on received tx if wallet is not syncronized completely
if (m_listener && m_wallet->synchronized()) {
m_listener->moneyReceived(tx_hash, amount);
@@ -115,14 +118,15 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount)
+ virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
{
std::string tx_hash = epee::string_tools::pod_to_hex(txid);
LOG_PRINT_L3(__FUNCTION__ << ": unconfirmed money received. height: " << height
<< ", tx: " << tx_hash
- << ", amount: " << print_money(amount));
+ << ", amount: " << print_money(amount)
+ << ", idx: " << subaddr_index);
// do not signal on received tx if wallet is not syncronized completely
if (m_listener && m_wallet->synchronized()) {
m_listener->unconfirmedMoneyReceived(tx_hash, amount);
@@ -131,13 +135,14 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx,
- uint64_t amount, const cryptonote::transaction& spend_tx)
+ uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index)
{
// TODO;
std::string tx_hash = epee::string_tools::pod_to_hex(txid);
LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height
<< ", tx: " << tx_hash
- << ", amount: " << print_money(amount));
+ << ", amount: " << print_money(amount)
+ << ", idx: " << subaddr_index);
// do not signal on sent tx if wallet is not syncronized completely
if (m_listener && m_wallet->synchronized()) {
m_listener->moneySpent(tx_hash, amount);
@@ -198,18 +203,14 @@ bool Wallet::paymentIdValid(const string &paiment_id)
bool Wallet::addressValid(const std::string &str, bool testnet)
{
- bool has_payment_id;
- cryptonote::account_public_address address;
- crypto::hash8 pid;
- return get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str);
+ cryptonote::address_parse_info info;
+ return get_account_address_from_str(info, testnet, str);
}
bool Wallet::keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error)
{
- bool has_payment_id;
- cryptonote::account_public_address address;
- crypto::hash8 pid;
- if(!get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, address_string)) {
+ cryptonote::address_parse_info info;
+ if(!get_account_address_from_str(info, testnet, address_string)) {
error = tr("Failed to parse address");
return false;
}
@@ -230,9 +231,9 @@ bool Wallet::keyValid(const std::string &secret_key_string, const std::string &a
}
bool matchAddress = false;
if(isViewKey)
- matchAddress = address.m_view_public_key == pkey;
+ matchAddress = info.address.m_view_public_key == pkey;
else
- matchAddress = address.m_spend_public_key == pkey;
+ matchAddress = info.address.m_spend_public_key == pkey;
if(!matchAddress) {
error = tr("key does not match address");
@@ -244,14 +245,12 @@ bool Wallet::keyValid(const std::string &secret_key_string, const std::string &a
std::string Wallet::paymentIdFromAddress(const std::string &str, bool testnet)
{
- bool has_payment_id;
- cryptonote::account_public_address address;
- crypto::hash8 pid;
- if (!get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str))
+ cryptonote::address_parse_info info;
+ if (!get_account_address_from_str(info, testnet, str))
return "";
- if (!has_payment_id)
+ if (!info.has_payment_id)
return "";
- return epee::string_tools::pod_to_hex(pid);
+ return epee::string_tools::pod_to_hex(info.payment_id);
}
uint64_t Wallet::maximumAllowedAmount()
@@ -286,6 +285,8 @@ WalletImpl::WalletImpl(bool testnet)
m_refreshThreadDone = false;
m_refreshEnabled = false;
m_addressBook = new AddressBookImpl(this);
+ m_subaddress = new SubaddressImpl(this);
+ m_subaddressAccount = new SubaddressAccountImpl(this);
m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS;
@@ -309,6 +310,8 @@ WalletImpl::~WalletImpl()
delete m_wallet2Callback;
delete m_history;
delete m_addressBook;
+ delete m_subaddress;
+ delete m_subaddressAccount;
delete m_wallet;
LOG_PRINT_L1(__FUNCTION__ << " finished");
}
@@ -423,10 +426,8 @@ bool WalletImpl::recoverFromKeys(const std::string &path,
const std::string &viewkey_string,
const std::string &spendkey_string)
{
- cryptonote::account_public_address address;
- bool has_payment_id;
- crypto::hash8 new_payment_id;
- if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, m_wallet->testnet(), address_string))
+ cryptonote::address_parse_info info;
+ if(!get_account_address_from_str(info, m_wallet->testnet(), address_string))
{
m_errorString = tr("failed to parse address");
m_status = Status_Error;
@@ -471,7 +472,7 @@ bool WalletImpl::recoverFromKeys(const std::string &path,
m_status = Status_Error;
return false;
}
- if (address.m_spend_public_key != pkey) {
+ if (info.address.m_spend_public_key != pkey) {
m_errorString = tr("spend key does not match address");
m_status = Status_Error;
return false;
@@ -482,7 +483,7 @@ bool WalletImpl::recoverFromKeys(const std::string &path,
m_status = Status_Error;
return false;
}
- if (address.m_view_public_key != pkey) {
+ if (info.address.m_view_public_key != pkey) {
m_errorString = tr("view key does not match address");
m_status = Status_Error;
return false;
@@ -491,12 +492,12 @@ bool WalletImpl::recoverFromKeys(const std::string &path,
try
{
if (has_spendkey) {
- m_wallet->generate(path, "", address, spendkey, viewkey);
+ m_wallet->generate(path, "", info.address, spendkey, viewkey);
setSeedLanguage(language);
LOG_PRINT_L1("Generated new wallet from keys with seed language: " + language);
}
else {
- m_wallet->generate(path, "", address, viewkey);
+ m_wallet->generate(path, "", info.address, viewkey);
LOG_PRINT_L1("Generated new view only wallet from keys");
}
@@ -635,9 +636,9 @@ bool WalletImpl::setPassword(const std::string &password)
return m_status == Status_Ok;
}
-std::string WalletImpl::address() const
+std::string WalletImpl::address(uint32_t accountIndex, uint32_t addressIndex) const
{
- return m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+ return m_wallet->get_subaddress_as_str({accountIndex, addressIndex});
}
std::string WalletImpl::integratedAddress(const std::string &payment_id) const
@@ -646,7 +647,7 @@ std::string WalletImpl::integratedAddress(const std::string &payment_id) const
if (!tools::wallet2::parse_short_payment_id(payment_id, pid)) {
return "";
}
- return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet());
+ return m_wallet->get_integrated_address_as_str(pid);
}
std::string WalletImpl::secretViewKey() const
@@ -720,14 +721,14 @@ void WalletImpl::setRecoveringFromSeed(bool recoveringFromSeed)
m_recoveringFromSeed = recoveringFromSeed;
}
-uint64_t WalletImpl::balance() const
+uint64_t WalletImpl::balance(uint32_t accountIndex) const
{
- return m_wallet->balance();
+ return m_wallet->balance(accountIndex);
}
-uint64_t WalletImpl::unlockedBalance() const
+uint64_t WalletImpl::unlockedBalance(uint32_t accountIndex) const
{
- return m_wallet->unlocked_balance();
+ return m_wallet->unlocked_balance(accountIndex);
}
uint64_t WalletImpl::blockChainHeight() const
@@ -914,6 +915,50 @@ bool WalletImpl::importKeyImages(const string &filename)
return true;
}
+void WalletImpl::addSubaddressAccount(const std::string& label)
+{
+ m_wallet->add_subaddress_account(label);
+}
+size_t WalletImpl::numSubaddressAccounts() const
+{
+ return m_wallet->get_num_subaddress_accounts();
+}
+size_t WalletImpl::numSubaddresses(uint32_t accountIndex) const
+{
+ return m_wallet->get_num_subaddresses(accountIndex);
+}
+void WalletImpl::addSubaddress(uint32_t accountIndex, const std::string& label)
+{
+ m_wallet->add_subaddress(accountIndex, label);
+}
+std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const
+{
+ try
+ {
+ return m_wallet->get_subaddress_label({accountIndex, addressIndex});
+ }
+ catch (const std::exception &e)
+ {
+ LOG_ERROR("Error getting subaddress label: ") << e.what();
+ m_errorString = string(tr("Failed to get subaddress label: ")) + e.what();
+ m_status = Status_Error;
+ return "";
+ }
+}
+void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label)
+{
+ try
+ {
+ return m_wallet->set_subaddress_label({accountIndex, addressIndex}, label);
+ }
+ catch (const std::exception &e)
+ {
+ LOG_ERROR("Error setting subaddress label: ") << e.what();
+ m_errorString = string(tr("Failed to set subaddress label: ")) + e.what();
+ m_status = Status_Error;
+ }
+}
+
// TODO:
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
// 2 - check / design how "Transaction" can be single interface
@@ -925,6 +970,7 @@ bool WalletImpl::importKeyImages(const string &filename)
// - confirmed_transfer_details)
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
+ uint32_t subaddr_account, std::set<uint32_t> subaddr_indices,
PendingTransaction::Priority priority)
{
@@ -932,11 +978,9 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
// Pause refresh thread while creating transaction
pauseRefresh();
- cryptonote::account_public_address addr;
+ cryptonote::address_parse_info info;
// indicates if dst_addr is integrated address (address + payment_id)
- bool has_payment_id;
- crypto::hash8 payment_id_short;
// TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441)
size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin();
if (fake_outs_count == 0)
@@ -945,7 +989,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
do {
- if(!cryptonote::get_account_integrated_address_from_str(addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) {
+ if(!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), dst_addr)) {
// TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
m_status = Status_Error;
m_errorString = "Invalid destination address";
@@ -955,7 +999,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
std::vector<uint8_t> extra;
// if dst_addr is not an integrated address, parse payment_id
- if (!has_payment_id && !payment_id.empty()) {
+ if (!info.has_payment_id && !payment_id.empty()) {
// copy-pasted from simplewallet.cpp:2212
crypto::hash payment_id_long;
bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long);
@@ -964,10 +1008,10 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
} else {
- r = tools::wallet2::parse_short_payment_id(payment_id, payment_id_short);
+ r = tools::wallet2::parse_short_payment_id(payment_id, info.payment_id);
if (r) {
std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_short);
+ set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
}
}
@@ -978,13 +1022,13 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
break;
}
}
- else if (has_payment_id) {
+ else if (info.has_payment_id) {
std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_short);
+ set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
if (!r) {
m_status = Status_Error;
- m_errorString = tr("Failed to add short payment id: ") + epee::string_tools::pod_to_hex(payment_id_short);
+ m_errorString = tr("Failed to add short payment id: ") + epee::string_tools::pod_to_hex(info.payment_id);
break;
}
}
@@ -996,16 +1040,23 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
if (amount) {
vector<cryptonote::tx_destination_entry> dsts;
cryptonote::tx_destination_entry de;
- de.addr = addr;
+ de.addr = info.address;
de.amount = *amount;
+ de.is_subaddress = info.is_subaddress;
dsts.push_back(de);
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
static_cast<uint32_t>(priority),
- extra, m_trustedDaemon);
+ extra, subaddr_account, subaddr_indices, m_trustedDaemon);
} else {
- transaction->m_pending_tx = m_wallet->create_transactions_all(0, addr, fake_outs_count, 0 /* unlock_time */,
+ // for the GUI, sweep_all (i.e. amount set as "(all)") will always sweep all the funds in all the addresses
+ if (subaddr_indices.empty())
+ {
+ for (uint32_t index = 0; index < m_wallet->get_num_subaddresses(subaddr_account); ++index)
+ subaddr_indices.insert(index);
+ }
+ transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */,
static_cast<uint32_t>(priority),
- extra, m_trustedDaemon);
+ extra, subaddr_account, subaddr_indices, m_trustedDaemon);
}
} catch (const tools::error::daemon_busy&) {
@@ -1186,16 +1237,26 @@ void WalletImpl::disposeTransaction(PendingTransaction *t)
delete t;
}
-TransactionHistory *WalletImpl::history() const
+TransactionHistory *WalletImpl::history()
{
return m_history;
}
-AddressBook *WalletImpl::addressBook() const
+AddressBook *WalletImpl::addressBook()
{
return m_addressBook;
}
+Subaddress *WalletImpl::subaddress()
+{
+ return m_subaddress;
+}
+
+SubaddressAccount *WalletImpl::subaddressAccount()
+{
+ return m_subaddressAccount;
+}
+
void WalletImpl::setListener(WalletListener *l)
{
// TODO thread synchronization;
@@ -1243,7 +1304,8 @@ std::string WalletImpl::getTxKey(const std::string &txid) const
const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
crypto::secret_key tx_key;
- if (m_wallet->get_tx_key(htxid, tx_key))
+ std::vector<crypto::secret_key> additional_tx_keys;
+ if (m_wallet->get_tx_key(htxid, tx_key, additional_tx_keys))
{
return epee::string_tools::pod_to_hex(tx_key);
}
@@ -1260,14 +1322,12 @@ std::string WalletImpl::signMessage(const std::string &message)
bool WalletImpl::verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const
{
- cryptonote::account_public_address addr;
- bool has_payment_id;
- crypto::hash8 payment_id;
+ cryptonote::address_parse_info info;
- if (!cryptonote::get_account_integrated_address_from_str(addr, has_payment_id, payment_id, m_wallet->testnet(), address))
+ if (!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), address))
return false;
- return m_wallet->verify(message, addr, signature);
+ return m_wallet->verify(message, info.address, signature);
}
bool WalletImpl::connectToDaemon()
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 1e3d1e600..020c5e46a 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -45,6 +45,8 @@ class TransactionHistoryImpl;
class PendingTransactionImpl;
class UnsignedTransactionImpl;
class AddressBookImpl;
+class SubaddressImpl;
+class SubaddressAccountImpl;
struct Wallet2CallbackImpl;
class WalletImpl : public Wallet
@@ -71,7 +73,7 @@ public:
int status() const;
std::string errorString() const;
bool setPassword(const std::string &password);
- std::string address() const;
+ std::string address(uint32_t accountIndex, uint32_t addressIndex) const;
std::string integratedAddress(const std::string &payment_id) const;
std::string secretViewKey() const;
std::string publicViewKey() const;
@@ -86,8 +88,8 @@ public:
ConnectionStatus connected() const;
void setTrustedDaemon(bool arg);
bool trustedDaemon() const;
- uint64_t balance() const;
- uint64_t unlockedBalance() const;
+ uint64_t balance(uint32_t accountIndex) const;
+ uint64_t unlockedBalance(uint32_t accountIndex) const;
uint64_t blockChainHeight() const;
uint64_t approximateBlockChainHeight() const;
uint64_t daemonBlockChainHeight() const;
@@ -106,8 +108,17 @@ public:
void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const;
bool useForkRules(uint8_t version, int64_t early_blocks) const;
+ void addSubaddressAccount(const std::string& label);
+ size_t numSubaddressAccounts() const;
+ size_t numSubaddresses(uint32_t accountIndex) const;
+ void addSubaddress(uint32_t accountIndex, const std::string& label);
+ std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const;
+ void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label);
+
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
optional<uint64_t> amount, uint32_t mixin_count,
+ uint32_t subaddr_account,
+ std::set<uint32_t> subaddr_indices,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low);
virtual PendingTransaction * createSweepUnmixableTransaction();
bool submitTransaction(const std::string &fileName);
@@ -116,8 +127,10 @@ public:
bool importKeyImages(const std::string &filename);
virtual void disposeTransaction(PendingTransaction * t);
- virtual TransactionHistory * history() const;
- virtual AddressBook * addressBook() const;
+ virtual TransactionHistory * history();
+ virtual AddressBook * addressBook();
+ virtual Subaddress * subaddress();
+ virtual SubaddressAccount * subaddressAccount();
virtual void setListener(WalletListener * l);
virtual uint32_t defaultMixin() const;
virtual void setDefaultMixin(uint32_t arg);
@@ -146,6 +159,8 @@ private:
friend class TransactionHistoryImpl;
friend struct Wallet2CallbackImpl;
friend class AddressBookImpl;
+ friend class SubaddressImpl;
+ friend class SubaddressAccountImpl;
tools::wallet2 * m_wallet;
mutable std::atomic<int> m_status;
@@ -155,6 +170,8 @@ private:
bool m_trustedDaemon;
Wallet2CallbackImpl * m_wallet2Callback;
AddressBookImpl * m_addressBook;
+ SubaddressImpl * m_subaddress;
+ SubaddressAccountImpl * m_subaddressAccount;
// multi-threaded refresh stuff
std::atomic<bool> m_refreshEnabled;
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 897137d35..a64766c84 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -215,10 +215,8 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
tx_key = *reinterpret_cast<const crypto::secret_key*>(tx_key_data.data());
bool testnet = address_text[0] != '4';
- cryptonote::account_public_address address;
- bool has_payment_id;
- crypto::hash8 payment_id;
- if(!cryptonote::get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_text))
+ cryptonote::address_parse_info info;
+ if(!cryptonote::get_account_address_from_str(info, testnet, address_text))
{
error = tr("failed to parse address");
return false;
@@ -258,7 +256,7 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
}
crypto::key_derivation derivation;
- if (!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation))
+ if (!crypto::generate_key_derivation(info.address.m_view_public_key, tx_key, derivation))
{
error = tr("failed to generate key derivation from supplied parameters");
return false;
@@ -272,7 +270,7 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
continue;
const cryptonote::txout_to_key tx_out_to_key = boost::get<cryptonote::txout_to_key>(tx.vout[n].target);
crypto::public_key pubkey;
- derive_public_key(derivation, n, address.m_spend_public_key, pubkey);
+ derive_public_key(derivation, n, info.address.m_spend_public_key, pubkey);
if (pubkey == tx_out_to_key.key)
{
uint64_t amount;
@@ -287,7 +285,7 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
rct::key Ctmp;
//rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key)));
crypto::key_derivation derivation;
- bool r = crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation);
+ bool r = crypto::generate_key_derivation(info.address.m_view_public_key, tx_key, derivation);
if (!r)
{
LOG_ERROR("Failed to generate key derivation to decode rct output " << n);
@@ -322,11 +320,11 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
if (received > 0)
{
- LOG_PRINT_L1(get_account_address_as_str(testnet, address) << " " << tr("received") << " " << cryptonote::print_money(received) << " " << tr("in txid") << " " << txid);
+ LOG_PRINT_L1(get_account_address_as_str(testnet, info.is_subaddress, info.address) << " " << tr("received") << " " << cryptonote::print_money(received) << " " << tr("in txid") << " " << txid);
}
else
{
- LOG_PRINT_L1(get_account_address_as_str(testnet, address) << " " << tr("received nothing in txid") << " " << txid);
+ LOG_PRINT_L1(get_account_address_as_str(testnet, info.is_subaddress, info.address) << " " << tr("received nothing in txid") << " " << txid);
}
if (res.txs.front().in_pool)
{