mirror of
https://github.com/monero-project/monero.git
synced 2025-10-11 10:58:31 -04:00
Subaddresses
This commit is contained in:
parent
86e9de588c
commit
53ad5a0f42
66 changed files with 3224 additions and 868 deletions
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
91
src/wallet/api/subaddress.cpp
Normal file
91
src/wallet/api/subaddress.cpp
Normal file
|
@ -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
|
56
src/wallet/api/subaddress.h
Normal file
56
src/wallet/api/subaddress.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
90
src/wallet/api/subaddress_account.cpp
Normal file
90
src/wallet/api/subaddress_account.cpp
Normal file
|
@ -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
|
56
src/wallet/api/subaddress_account.h
Normal file
56
src/wallet/api/subaddress_account.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
if (i == dests.end())
|
||||
dests.insert(std::make_pair(address, entry.amount));
|
||||
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
|
||||
i->second += entry.amount;
|
||||
address = standard_address;
|
||||
auto i = dests.find(entry.addr);
|
||||
if (i == dests.end())
|
||||
dests.insert(std::make_pair(entry.addr, std::make_pair(address, entry.amount)));
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue