diff options
author | kenshi84 <kenshi84@protonmail.ch> | 2017-02-19 11:42:10 +0900 |
---|---|---|
committer | kenshi84 <kenshi84@protonmail.ch> | 2017-10-07 13:06:21 +0900 |
commit | 53ad5a0f42174bca57e24485ef3d40e4b9cf5599 (patch) | |
tree | afc13a3ee6a049ec78ac234e2d55ff46e992b457 /src/wallet/api | |
parent | Merge pull request #2548 (diff) | |
download | monero-53ad5a0f42174bca57e24485ef3d40e4b9cf5599.tar.xz |
Subaddresses
Diffstat (limited to 'src/wallet/api')
-rw-r--r-- | src/wallet/api/address_book.cpp | 18 | ||||
-rw-r--r-- | src/wallet/api/pending_transaction.cpp | 16 | ||||
-rw-r--r-- | src/wallet/api/pending_transaction.h | 2 | ||||
-rw-r--r-- | src/wallet/api/subaddress.cpp | 91 | ||||
-rw-r--r-- | src/wallet/api/subaddress.h | 56 | ||||
-rw-r--r-- | src/wallet/api/subaddress_account.cpp | 90 | ||||
-rw-r--r-- | src/wallet/api/subaddress_account.h | 56 | ||||
-rw-r--r-- | src/wallet/api/transaction_history.cpp | 16 | ||||
-rw-r--r-- | src/wallet/api/transaction_info.cpp | 17 | ||||
-rw-r--r-- | src/wallet/api/transaction_info.h | 6 | ||||
-rw-r--r-- | src/wallet/api/unsigned_transaction.cpp | 63 | ||||
-rw-r--r-- | src/wallet/api/wallet.cpp | 178 | ||||
-rw-r--r-- | src/wallet/api/wallet.h | 27 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.cpp | 16 |
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) { |