Integrated addresses (standard address plus payment id)
This commit is contained in:
parent
d6ba5ef8c5
commit
63741d8264
@ -121,6 +121,7 @@ namespace config
|
|||||||
std::string const P2P_REMOTE_DEBUG_TRUSTED_PUB_KEY = "0000000000000000000000000000000000000000000000000000000000000000";
|
std::string const P2P_REMOTE_DEBUG_TRUSTED_PUB_KEY = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||||
|
|
||||||
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18;
|
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18;
|
||||||
|
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 19;
|
||||||
uint16_t const P2P_DEFAULT_PORT = 18080;
|
uint16_t const P2P_DEFAULT_PORT = 18080;
|
||||||
uint16_t const RPC_DEFAULT_PORT = 18081;
|
uint16_t const RPC_DEFAULT_PORT = 18081;
|
||||||
boost::uuids::uuid const NETWORK_ID = { {
|
boost::uuids::uuid const NETWORK_ID = { {
|
||||||
@ -132,6 +133,7 @@ namespace config
|
|||||||
namespace testnet
|
namespace testnet
|
||||||
{
|
{
|
||||||
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 53;
|
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 53;
|
||||||
|
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 54;
|
||||||
uint16_t const P2P_DEFAULT_PORT = 28080;
|
uint16_t const P2P_DEFAULT_PORT = 28080;
|
||||||
uint16_t const RPC_DEFAULT_PORT = 28081;
|
uint16_t const RPC_DEFAULT_PORT = 28081;
|
||||||
boost::uuids::uuid const NETWORK_ID = { {
|
boost::uuids::uuid const NETWORK_ID = { {
|
||||||
|
@ -104,4 +104,10 @@ DISABLE_VS_WARNINGS(4244 4345)
|
|||||||
return get_account_address_as_str(testnet, m_keys.m_account_address);
|
return get_account_address_as_str(testnet, m_keys.m_account_address);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
|
std::string account_base::get_public_integrated_address_str(const crypto::hash &payment_id, bool testnet)
|
||||||
|
{
|
||||||
|
//TODO: change this code into base 58
|
||||||
|
return get_account_integrated_address_as_str(testnet, m_keys.m_account_address, payment_id);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ namespace cryptonote
|
|||||||
crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
|
crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
|
||||||
const account_keys& get_keys() const;
|
const account_keys& get_keys() const;
|
||||||
std::string get_public_address_str(bool testnet);
|
std::string get_public_address_str(bool testnet);
|
||||||
|
std::string get_public_integrated_address_str(const crypto::hash &payment_id, bool testnet);
|
||||||
|
|
||||||
uint64_t get_createtime() const { return m_creation_timestamp; }
|
uint64_t get_createtime() const { return m_creation_timestamp; }
|
||||||
void set_createtime(uint64_t val) { m_creation_timestamp = val; }
|
void set_createtime(uint64_t val) { m_creation_timestamp = val; }
|
||||||
|
@ -44,6 +44,21 @@ using namespace epee;
|
|||||||
|
|
||||||
namespace cryptonote {
|
namespace cryptonote {
|
||||||
|
|
||||||
|
struct integrated_address {
|
||||||
|
account_public_address adr;
|
||||||
|
crypto::hash payment_id;
|
||||||
|
|
||||||
|
BEGIN_SERIALIZE_OBJECT()
|
||||||
|
FIELD(adr)
|
||||||
|
FIELD(payment_id)
|
||||||
|
END_SERIALIZE()
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(adr)
|
||||||
|
KV_SERIALIZE(payment_id)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Cryptonote helper functions */
|
/* Cryptonote helper functions */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
@ -106,6 +121,16 @@ namespace cryptonote {
|
|||||||
|
|
||||||
return summ;
|
return summ;
|
||||||
}
|
}
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl)
|
||||||
|
{
|
||||||
|
const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
|
||||||
|
uint8_t summ = 0;
|
||||||
|
for(size_t i = 0; i!= sizeof(public_integrated_address_outer_blob)-1; i++)
|
||||||
|
summ += pbuf[i];
|
||||||
|
|
||||||
|
return summ;
|
||||||
|
}
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
std::string get_account_address_as_str(
|
std::string get_account_address_as_str(
|
||||||
bool testnet
|
bool testnet
|
||||||
@ -118,6 +143,21 @@ namespace cryptonote {
|
|||||||
return tools::base58::encode_addr(address_prefix, t_serializable_object_to_blob(adr));
|
return tools::base58::encode_addr(address_prefix, t_serializable_object_to_blob(adr));
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
std::string get_account_integrated_address_as_str(
|
||||||
|
bool testnet
|
||||||
|
, account_public_address const & adr
|
||||||
|
, crypto::hash const & payment_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint64_t integrated_address_prefix = testnet ?
|
||||||
|
config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||||
|
|
||||||
|
integrated_address iadr = {
|
||||||
|
adr, payment_id
|
||||||
|
};
|
||||||
|
return tools::base58::encode_addr(integrated_address_prefix, t_serializable_object_to_blob(iadr));
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
bool is_coinbase(const transaction& tx)
|
bool is_coinbase(const transaction& tx)
|
||||||
{
|
{
|
||||||
if(tx.vin.size() != 1)
|
if(tx.vin.size() != 1)
|
||||||
@ -129,14 +169,18 @@ namespace cryptonote {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
bool get_account_address_from_str(
|
bool get_account_integrated_address_from_str(
|
||||||
account_public_address& adr
|
account_public_address& adr
|
||||||
|
, bool& has_payment_id
|
||||||
|
, crypto::hash& payment_id
|
||||||
, bool testnet
|
, bool testnet
|
||||||
, std::string const & str
|
, std::string const & str
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
uint64_t address_prefix = testnet ?
|
uint64_t address_prefix = testnet ?
|
||||||
config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
|
config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
|
||||||
|
uint64_t integrated_address_prefix = testnet ?
|
||||||
|
config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||||
|
|
||||||
if (2 * sizeof(public_address_outer_blob) != str.size())
|
if (2 * sizeof(public_address_outer_blob) != str.size())
|
||||||
{
|
{
|
||||||
@ -148,18 +192,29 @@ namespace cryptonote {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address_prefix != prefix)
|
if (integrated_address_prefix == prefix)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix);
|
has_payment_id = true;
|
||||||
|
}
|
||||||
|
else if (address_prefix == prefix)
|
||||||
|
{
|
||||||
|
has_payment_id = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix << " or " << integrated_address_prefix);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!::serialization::parse_binary(data, adr))
|
integrated_address iadr;
|
||||||
|
if (!::serialization::parse_binary(data, iadr))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("Account public address keys can't be parsed");
|
LOG_PRINT_L1("Account public address keys can't be parsed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adr = iadr.adr;
|
||||||
|
payment_id = iadr.payment_id;
|
||||||
|
|
||||||
if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key))
|
if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("Failed to validate address keys");
|
LOG_PRINT_L1("Failed to validate address keys");
|
||||||
@ -196,10 +251,22 @@ namespace cryptonote {
|
|||||||
|
|
||||||
//we success
|
//we success
|
||||||
adr = blob.m_address;
|
adr = blob.m_address;
|
||||||
|
has_payment_id = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
bool get_account_address_from_str(
|
||||||
|
account_public_address& adr
|
||||||
|
, bool testnet
|
||||||
|
, std::string const & str
|
||||||
|
)
|
||||||
|
{
|
||||||
|
bool has_payment_id;
|
||||||
|
crypto::hash payment_id;
|
||||||
|
return get_account_integrated_address_from_str(adr, has_payment_id, payment_id, testnet, str);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {
|
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {
|
||||||
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b);
|
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b);
|
||||||
|
@ -56,6 +56,13 @@ namespace cryptonote {
|
|||||||
account_public_address m_address;
|
account_public_address m_address;
|
||||||
uint8_t check_sum;
|
uint8_t check_sum;
|
||||||
};
|
};
|
||||||
|
struct public_integrated_address_outer_blob
|
||||||
|
{
|
||||||
|
uint8_t m_ver;
|
||||||
|
account_public_address m_address;
|
||||||
|
crypto::hash payment_id;
|
||||||
|
uint8_t check_sum;
|
||||||
|
};
|
||||||
#pragma pack (pop)
|
#pragma pack (pop)
|
||||||
|
|
||||||
|
|
||||||
@ -66,12 +73,27 @@ namespace cryptonote {
|
|||||||
size_t get_max_tx_size();
|
size_t get_max_tx_size();
|
||||||
bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward);
|
bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward);
|
||||||
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
|
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
|
||||||
|
uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl);
|
||||||
|
|
||||||
std::string get_account_address_as_str(
|
std::string get_account_address_as_str(
|
||||||
bool testnet
|
bool testnet
|
||||||
, const account_public_address& adr
|
, const account_public_address& adr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
std::string get_account_integrated_address_as_str(
|
||||||
|
bool testnet
|
||||||
|
, const account_public_address& adr
|
||||||
|
, const crypto::hash& payment_id
|
||||||
|
);
|
||||||
|
|
||||||
|
bool get_account_integrated_address_from_str(
|
||||||
|
account_public_address& adr
|
||||||
|
, bool& has_payment_id
|
||||||
|
, crypto::hash& payment_id
|
||||||
|
, bool testnet
|
||||||
|
, const std::string& str
|
||||||
|
);
|
||||||
|
|
||||||
bool get_account_address_from_str(
|
bool get_account_address_from_str(
|
||||||
account_public_address& adr
|
account_public_address& adr
|
||||||
, bool testnet
|
, bool testnet
|
||||||
|
@ -298,6 +298,7 @@ simple_wallet::simple_wallet()
|
|||||||
m_cmd_binder.set_handler("sweep_dust", boost::bind(&simple_wallet::sweep_dust, this, _1), "Send all dust outputs to the same address with mixin 0");
|
m_cmd_binder.set_handler("sweep_dust", boost::bind(&simple_wallet::sweep_dust, this, _1), "Send all dust outputs to the same address with mixin 0");
|
||||||
m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
|
m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
|
||||||
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
|
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
|
||||||
|
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::print_integrated_address, this, _1), "Show an integrated address for the current wallet public address and a payment id");
|
||||||
m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
|
m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
|
||||||
m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "Save watch only keys file");
|
m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "Save watch only keys file");
|
||||||
m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), "Get viewkey");
|
m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), "Get viewkey");
|
||||||
@ -1137,6 +1138,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> extra;
|
std::vector<uint8_t> extra;
|
||||||
|
bool payment_id_seen = false;
|
||||||
if (1 == local_args.size() % 2)
|
if (1 == local_args.size() % 2)
|
||||||
{
|
{
|
||||||
std::string payment_id_str = local_args.back();
|
std::string payment_id_str = local_args.back();
|
||||||
@ -1156,13 +1158,17 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
|||||||
fail_msg_writer() << "payment id has invalid format: \"" << payment_id_str << "\", expected 64-character string";
|
fail_msg_writer() << "payment id has invalid format: \"" << payment_id_str << "\", expected 64-character string";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
payment_id_seen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<cryptonote::tx_destination_entry> dsts;
|
vector<cryptonote::tx_destination_entry> dsts;
|
||||||
|
crypto::hash payment_id = null_hash;
|
||||||
for (size_t i = 0; i < local_args.size(); i += 2)
|
for (size_t i = 0; i < local_args.size(); i += 2)
|
||||||
{
|
{
|
||||||
cryptonote::tx_destination_entry de;
|
cryptonote::tx_destination_entry de;
|
||||||
if(!get_account_address_from_str(de.addr, m_wallet->testnet(), local_args[i]))
|
bool has_payment_id;
|
||||||
|
crypto::hash new_payment_id;
|
||||||
|
if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i]))
|
||||||
{
|
{
|
||||||
// if treating as an address fails, try as url
|
// if treating as an address fails, try as url
|
||||||
bool dnssec_ok = false;
|
bool dnssec_ok = false;
|
||||||
@ -1174,7 +1180,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
|||||||
// for now, move on only if one address found
|
// for now, move on only if one address found
|
||||||
if (addresses_from_dns.size() == 1)
|
if (addresses_from_dns.size() == 1)
|
||||||
{
|
{
|
||||||
if (get_account_address_from_str(de.addr, m_wallet->testnet(), addresses_from_dns[0]))
|
if (get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), addresses_from_dns[0]))
|
||||||
{
|
{
|
||||||
// if it was an address, prompt user for confirmation.
|
// if it was an address, prompt user for confirmation.
|
||||||
// inform user of DNSSEC validation status as well.
|
// inform user of DNSSEC validation status as well.
|
||||||
@ -1221,6 +1227,26 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_payment_id) {
|
||||||
|
if (payment_id_seen && payment_id != new_payment_id) {
|
||||||
|
fail_msg_writer() << "A single transaction cannot use more than one payment id: " << local_args[i];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!payment_id_seen)
|
||||||
|
{
|
||||||
|
std::string extra_nonce;
|
||||||
|
set_payment_id_to_tx_extra_nonce(extra_nonce, new_payment_id);
|
||||||
|
bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
|
||||||
|
if(!r)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << "Failed to set up payment id, though it was decoded correctly";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
payment_id = new_payment_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
|
bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
|
||||||
if(!ok || 0 == de.amount)
|
if(!ok || 0 == de.amount)
|
||||||
{
|
{
|
||||||
@ -1491,6 +1517,40 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
bool simple_wallet::print_integrated_address(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||||
|
{
|
||||||
|
if (args.size() != 1)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << "Missing payment id or address";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
crypto::hash payment_id;
|
||||||
|
if(tools::wallet2::parse_payment_id(args.back(), payment_id))
|
||||||
|
{
|
||||||
|
success_msg_writer() << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool has_payment_id;
|
||||||
|
crypto::hash payment_id;
|
||||||
|
account_public_address addr;
|
||||||
|
if(get_account_integrated_address_from_str(addr, has_payment_id, payment_id, m_wallet->testnet(), args.back()))
|
||||||
|
{
|
||||||
|
if (has_payment_id)
|
||||||
|
{
|
||||||
|
success_msg_writer() << "Integrated address: account " << get_account_address_as_str(m_wallet->testnet(),addr) << ", payment id " << payment_id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success_msg_writer() << "Standard address: account " << get_account_address_as_str(m_wallet->testnet(),addr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fail_msg_writer() << "Failed to parse payment id or address";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool simple_wallet::process_command(const std::vector<std::string> &args)
|
bool simple_wallet::process_command(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
return m_cmd_binder.process_command_vec(args);
|
return m_cmd_binder.process_command_vec(args);
|
||||||
|
@ -108,6 +108,7 @@ namespace cryptonote
|
|||||||
std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits
|
std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits
|
||||||
);
|
);
|
||||||
bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
|
bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
|
||||||
|
bool print_integrated_address(const std::vector<std::string> &args = std::vector<std::string>());
|
||||||
bool save(const std::vector<std::string> &args);
|
bool save(const std::vector<std::string> &args);
|
||||||
bool save_watch_only(const std::vector<std::string> &args);
|
bool save_watch_only(const std::vector<std::string> &args);
|
||||||
bool set_variable(const std::vector<std::string> &args);
|
bool set_variable(const std::vector<std::string> &args);
|
||||||
|
@ -117,12 +117,15 @@ namespace tools
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination> destinations, const std::string payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er)
|
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination> destinations, std::string payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
|
crypto::hash integrated_payment_id = cryptonote::null_hash;
|
||||||
for (auto it = destinations.begin(); it != destinations.end(); it++)
|
for (auto it = destinations.begin(); it != destinations.end(); it++)
|
||||||
{
|
{
|
||||||
cryptonote::tx_destination_entry de;
|
cryptonote::tx_destination_entry de;
|
||||||
if(!get_account_address_from_str(de.addr, m_wallet.testnet(), it->address))
|
bool has_payment_id;
|
||||||
|
crypto::hash new_payment_id;
|
||||||
|
if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet.testnet(), it->address))
|
||||||
{
|
{
|
||||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
|
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
|
||||||
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
|
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
|
||||||
@ -130,6 +133,17 @@ namespace tools
|
|||||||
}
|
}
|
||||||
de.amount = it->amount;
|
de.amount = it->amount;
|
||||||
dsts.push_back(de);
|
dsts.push_back(de);
|
||||||
|
|
||||||
|
if (has_payment_id)
|
||||||
|
{
|
||||||
|
if (!payment_id.empty() || integrated_payment_id != cryptonote::null_hash)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
|
||||||
|
er.message = "A single payment id is allowed per transaction";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
integrated_payment_id = new_payment_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!payment_id.empty())
|
if (!payment_id.empty())
|
||||||
|
Loading…
Reference in New Issue
Block a user