mirror of
https://git.wownero.com/wownero/wownero.git
synced 2024-08-15 01:03:23 +00:00
WalletApi: getMultisigInfo entry for gui wallets
WalletApi: makeMultisig call introduced WalletApi: finalizeMultisig call introduced WalletApi: new calls exportMultisigImages and importMultisigImages WalletApi: method to return multisig wallet creation state WalletApi: create multisig transaction, sign multisig transaction, commit transaction and get multisig data are added WalletApi: identation and style fixes
This commit is contained in:
parent
47fdb74273
commit
5a96056600
7 changed files with 308 additions and 2 deletions
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||||
|
#include "common/base58.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -102,6 +103,11 @@ bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite)
|
||||||
}
|
}
|
||||||
// Commit tx
|
// Commit tx
|
||||||
else {
|
else {
|
||||||
|
auto multisigState = m_wallet.multisig();
|
||||||
|
if (multisigState.isMultisig && m_signers.size() < multisigState.threshold) {
|
||||||
|
throw runtime_error("Not enough signers to send multisig transaction");
|
||||||
|
}
|
||||||
|
|
||||||
m_wallet.pauseRefresh();
|
m_wallet.pauseRefresh();
|
||||||
while (!m_pending_tx.empty()) {
|
while (!m_pending_tx.empty()) {
|
||||||
auto & ptx = m_pending_tx.back();
|
auto & ptx = m_pending_tx.back();
|
||||||
|
@ -188,6 +194,53 @@ std::vector<std::set<uint32_t>> PendingTransactionImpl::subaddrIndices() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string PendingTransactionImpl::multisigSignData() {
|
||||||
|
try {
|
||||||
|
if (!m_wallet.multisig().isMultisig) {
|
||||||
|
throw std::runtime_error("wallet is not multisig");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cipher = m_wallet.m_wallet->save_multisig_tx(m_pending_tx);
|
||||||
|
return epee::string_tools::buff_to_hex_nodelimer(cipher);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = std::string(tr("Couldn't multisig sign data: ")) + e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PendingTransactionImpl::signMultisigTx() {
|
||||||
|
try {
|
||||||
|
std::vector<crypto::hash> ignore;
|
||||||
|
|
||||||
|
tools::wallet2::multisig_tx_set txSet;
|
||||||
|
txSet.m_ptx = m_pending_tx;
|
||||||
|
txSet.m_signers = m_signers;
|
||||||
|
|
||||||
|
if (!m_wallet.m_wallet->sign_multisig_tx(txSet, ignore)) {
|
||||||
|
throw std::runtime_error("couldn't sign multisig transaction");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::swap(m_pending_tx, txSet.m_ptx);
|
||||||
|
std::swap(m_signers, txSet.m_signers);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = std::string(tr("Couldn't sign multisig transaction: ")) + e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> PendingTransactionImpl::signersKeys() const {
|
||||||
|
std::vector<std::string> keys;
|
||||||
|
keys.reserve(m_signers.size());
|
||||||
|
|
||||||
|
for (const auto& signer: m_signers) {
|
||||||
|
keys.emplace_back(tools::base58::encode(cryptonote::t_serializable_object_to_blob(signer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Bitmonero = Monero;
|
namespace Bitmonero = Monero;
|
||||||
|
|
|
@ -55,6 +55,10 @@ public:
|
||||||
std::vector<std::set<uint32_t>> subaddrIndices() const;
|
std::vector<std::set<uint32_t>> subaddrIndices() const;
|
||||||
// TODO: continue with interface;
|
// TODO: continue with interface;
|
||||||
|
|
||||||
|
std::string multisigSignData();
|
||||||
|
void signMultisigTx();
|
||||||
|
std::vector<std::string> signersKeys() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class WalletImpl;
|
friend class WalletImpl;
|
||||||
WalletImpl &m_wallet;
|
WalletImpl &m_wallet;
|
||||||
|
@ -62,6 +66,7 @@ private:
|
||||||
int m_status;
|
int m_status;
|
||||||
std::string m_errorString;
|
std::string m_errorString;
|
||||||
std::vector<tools::wallet2::pending_tx> m_pending_tx;
|
std::vector<tools::wallet2::pending_tx> m_pending_tx;
|
||||||
|
std::unordered_set<crypto::public_key> m_signers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,36 @@ namespace {
|
||||||
dir /= ".shared-ringdb";
|
dir /= ".shared-ringdb";
|
||||||
return dir.string();
|
return dir.string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkMultisigWalletReady(const tools::wallet2* wallet) {
|
||||||
|
if (!wallet) {
|
||||||
|
throw runtime_error("Wallet is not initialized yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ready;
|
||||||
|
if (!wallet->multisig(&ready)) {
|
||||||
|
throw runtime_error("Wallet is not multisig");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ready) {
|
||||||
|
throw runtime_error("Multisig wallet is not finalized yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkMultisigWalletNotReady(const tools::wallet2* wallet) {
|
||||||
|
if (!wallet) {
|
||||||
|
throw runtime_error("Wallet is not initialized yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ready;
|
||||||
|
if (!wallet->multisig(&ready)) {
|
||||||
|
throw runtime_error("Wallet is not multisig");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ready) {
|
||||||
|
throw runtime_error("Multisig wallet is already finalized");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
||||||
|
@ -1058,6 +1088,132 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MultisigState WalletImpl::multisig() const {
|
||||||
|
MultisigState state;
|
||||||
|
state.isMultisig = m_wallet->multisig(&state.isReady, &state.threshold, &state.total);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
string WalletImpl::getMultisigInfo() const {
|
||||||
|
try {
|
||||||
|
clearStatus();
|
||||||
|
return m_wallet->get_multisig_info();
|
||||||
|
} catch (const exception& e) {
|
||||||
|
LOG_ERROR("Error on generating multisig info: ") << e.what();
|
||||||
|
setStatusError(string(tr("Failed to get multisig info: ")) + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return string();
|
||||||
|
}
|
||||||
|
|
||||||
|
string WalletImpl::makeMultisig(const vector<string>& info, uint32_t threshold) {
|
||||||
|
try {
|
||||||
|
clearStatus();
|
||||||
|
|
||||||
|
if (m_wallet->multisig()) {
|
||||||
|
throw runtime_error("Wallet is already multisig");
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_wallet->make_multisig(epee::wipeable_string(m_password), info, threshold);
|
||||||
|
} catch (const exception& e) {
|
||||||
|
LOG_ERROR("Error on making multisig wallet: ") << e.what();
|
||||||
|
setStatusError(string(tr("Failed to make multisig: ")) + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WalletImpl::finalizeMultisig(const vector<string>& extraMultisigInfo) {
|
||||||
|
try {
|
||||||
|
clearStatus();
|
||||||
|
checkMultisigWalletNotReady(m_wallet);
|
||||||
|
|
||||||
|
if (m_wallet->finalize_multisig(epee::wipeable_string(m_password), extraMultisigInfo)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatusError(tr("Failed to finalize multisig wallet creation"));
|
||||||
|
} catch (const exception& e) {
|
||||||
|
LOG_ERROR("Error on finalizing multisig wallet creation: ") << e.what();
|
||||||
|
setStatusError(string(tr("Failed to finalize multisig wallet creation: ")) + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WalletImpl::exportMultisigImages(string& images) {
|
||||||
|
try {
|
||||||
|
clearStatus();
|
||||||
|
checkMultisigWalletReady(m_wallet);
|
||||||
|
|
||||||
|
auto blob = m_wallet->export_multisig();
|
||||||
|
images = epee::string_tools::buff_to_hex_nodelimer(blob);
|
||||||
|
return true;
|
||||||
|
} catch (const exception& e) {
|
||||||
|
LOG_ERROR("Error on exporting multisig images: ") << e.what();
|
||||||
|
setStatusError(string(tr("Failed to export multisig images: ")) + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WalletImpl::importMultisigImages(const vector<string>& images) {
|
||||||
|
try {
|
||||||
|
clearStatus();
|
||||||
|
checkMultisigWalletReady(m_wallet);
|
||||||
|
|
||||||
|
std::vector<std::string> blobs;
|
||||||
|
blobs.reserve(images.size());
|
||||||
|
|
||||||
|
for (const auto& image: images) {
|
||||||
|
std::string blob;
|
||||||
|
if (!epee::string_tools::parse_hexstr_to_binbuff(image, blob)) {
|
||||||
|
LOG_ERROR("Failed to parse imported multisig images");
|
||||||
|
setStatusError(tr("Failed to parse imported multisig images"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blobs.emplace_back(std::move(blob));
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_wallet->import_multisig(blobs);
|
||||||
|
} catch (const exception& e) {
|
||||||
|
LOG_ERROR("Error on importing multisig images: ") << e.what();
|
||||||
|
setStatusError(string(tr("Failed to import multisig images: ")) + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signData) {
|
||||||
|
try {
|
||||||
|
clearStatus();
|
||||||
|
checkMultisigWalletReady(m_wallet);
|
||||||
|
|
||||||
|
string binary;
|
||||||
|
if (!epee::string_tools::parse_hexstr_to_binbuff(signData, binary)) {
|
||||||
|
throw runtime_error("Failed to deserialize multisig transaction");
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::wallet2::multisig_tx_set txSet;
|
||||||
|
if (!m_wallet->load_multisig_tx(binary, txSet, {})) {
|
||||||
|
throw runtime_error("couldn't parse multisig transaction data");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptx = new PendingTransactionImpl(*this);
|
||||||
|
ptx->m_pending_tx = txSet.m_ptx;
|
||||||
|
ptx->m_signers = txSet.m_signers;
|
||||||
|
|
||||||
|
return ptx;
|
||||||
|
} catch (exception& e) {
|
||||||
|
LOG_ERROR("Error on restoring multisig transaction: ") << e.what();
|
||||||
|
setStatusError(string(tr("Failed to restore multisig transaction: ")) + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
|
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
|
||||||
// 2 - check / design how "Transaction" can be single interface
|
// 2 - check / design how "Transaction" can be single interface
|
||||||
|
@ -1095,6 +1251,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<uint8_t> extra;
|
std::vector<uint8_t> extra;
|
||||||
// if dst_addr is not an integrated address, parse payment_id
|
// if dst_addr is not an integrated address, parse payment_id
|
||||||
if (!info.has_payment_id && !payment_id.empty()) {
|
if (!info.has_payment_id && !payment_id.empty()) {
|
||||||
|
@ -1155,6 +1312,9 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
|
||||||
extra, subaddr_account, subaddr_indices, m_trustedDaemon);
|
extra, subaddr_account, subaddr_indices, m_trustedDaemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (multisig().isMultisig) {
|
||||||
|
transaction->m_signers = m_wallet->make_multisig_tx_set(transaction->m_pending_tx).m_signers;
|
||||||
|
}
|
||||||
} catch (const tools::error::daemon_busy&) {
|
} catch (const tools::error::daemon_busy&) {
|
||||||
// TODO: make it translatable with "tr"?
|
// TODO: make it translatable with "tr"?
|
||||||
setStatusError(tr("daemon is busy. Please try again later."));
|
setStatusError(tr("daemon is busy. Please try again later."));
|
||||||
|
|
|
@ -127,6 +127,14 @@ public:
|
||||||
std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const;
|
std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const;
|
||||||
void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label);
|
void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label);
|
||||||
|
|
||||||
|
MultisigState multisig() const override;
|
||||||
|
std::string getMultisigInfo() const override;
|
||||||
|
std::string makeMultisig(const std::vector<std::string>& info, uint32_t threshold) override;
|
||||||
|
bool finalizeMultisig(const std::vector<std::string>& extraMultisigInfo) override;
|
||||||
|
bool exportMultisigImages(std::string& images) override;
|
||||||
|
size_t importMultisigImages(const std::vector<std::string>& images) override;
|
||||||
|
PendingTransaction* restoreMultisigTransaction(const std::string& signData) override;
|
||||||
|
|
||||||
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
||||||
optional<uint64_t> amount, uint32_t mixin_count,
|
optional<uint64_t> amount, uint32_t mixin_count,
|
||||||
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
||||||
|
|
|
@ -100,6 +100,30 @@ struct PendingTransaction
|
||||||
virtual uint64_t txCount() const = 0;
|
virtual uint64_t txCount() const = 0;
|
||||||
virtual std::vector<uint32_t> subaddrAccount() const = 0;
|
virtual std::vector<uint32_t> subaddrAccount() const = 0;
|
||||||
virtual std::vector<std::set<uint32_t>> subaddrIndices() const = 0;
|
virtual std::vector<std::set<uint32_t>> subaddrIndices() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief multisigSignData
|
||||||
|
* @return encoded multisig transaction with signers' keys.
|
||||||
|
* Transfer this data to another wallet participant to sign it.
|
||||||
|
* Assumed use case is:
|
||||||
|
* 1. Initiator:
|
||||||
|
* auto data = pendingTransaction->multisigSignData();
|
||||||
|
* 2. Signer1:
|
||||||
|
* pendingTransaction = wallet->restoreMultisigTransaction(data);
|
||||||
|
* pendingTransaction->signMultisigTx();
|
||||||
|
* auto signed = pendingTransaction->multisigSignData();
|
||||||
|
* 3. Signer2:
|
||||||
|
* pendingTransaction = wallet->restoreMultisigTransaction(signed);
|
||||||
|
* pendingTransaction->signMultisigTx();
|
||||||
|
* pendingTransaction->commit();
|
||||||
|
*/
|
||||||
|
virtual std::string multisigSignData() = 0;
|
||||||
|
virtual void signMultisigTx() = 0;
|
||||||
|
/**
|
||||||
|
* @brief signersKeys
|
||||||
|
* @return vector of base58-encoded signers' public keys
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::string> signersKeys() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -291,6 +315,15 @@ struct SubaddressAccount
|
||||||
virtual void refresh() = 0;
|
virtual void refresh() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MultisigState {
|
||||||
|
MultisigState() : isMultisig(false), isReady(false), threshold(0), total(0) {}
|
||||||
|
|
||||||
|
bool isMultisig;
|
||||||
|
bool isReady;
|
||||||
|
uint32_t threshold;
|
||||||
|
uint32_t total;
|
||||||
|
};
|
||||||
|
|
||||||
struct WalletListener
|
struct WalletListener
|
||||||
{
|
{
|
||||||
virtual ~WalletListener() = 0;
|
virtual ~WalletListener() = 0;
|
||||||
|
@ -630,6 +663,48 @@ struct Wallet
|
||||||
*/
|
*/
|
||||||
virtual void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) = 0;
|
virtual void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief multisig - returns current state of multisig wallet creation process
|
||||||
|
* @return MultisigState struct
|
||||||
|
*/
|
||||||
|
virtual MultisigState multisig() const = 0;
|
||||||
|
/**
|
||||||
|
* @brief getMultisigInfo
|
||||||
|
* @return serialized and signed multisig info string
|
||||||
|
*/
|
||||||
|
virtual std::string getMultisigInfo() const = 0;
|
||||||
|
/**
|
||||||
|
* @brief makeMultisig - switches wallet in multisig state. The one and only creation phase for N / N wallets
|
||||||
|
* @param info - vector of multisig infos from other participants obtained with getMulitisInfo call
|
||||||
|
* @param threshold - number of required signers to make valid transaction. Must be equal to number of participants (N) or N - 1
|
||||||
|
* @return in case of N / N wallets returns empty string since no more key exchanges needed. For N - 1 / N wallets returns base58 encoded extra multisig info
|
||||||
|
*/
|
||||||
|
virtual std::string makeMultisig(const std::vector<std::string>& info, uint32_t threshold) = 0;
|
||||||
|
/**
|
||||||
|
* @brief finalizeMultisig - finalizes N - 1 / N multisig wallets creation
|
||||||
|
* @param extraMultisigInfo - wallet participants' extra multisig info obtained with makeMultisig call
|
||||||
|
* @return true if success
|
||||||
|
*/
|
||||||
|
virtual bool finalizeMultisig(const std::vector<std::string>& extraMultisigInfo) = 0;
|
||||||
|
/**
|
||||||
|
* @brief exportMultisigImages - exports transfers' key images
|
||||||
|
* @param images - output paramter for hex encoded array of images
|
||||||
|
* @return true if success
|
||||||
|
*/
|
||||||
|
virtual bool exportMultisigImages(std::string& images) = 0;
|
||||||
|
/**
|
||||||
|
* @brief importMultisigImages - imports other participants' multisig images
|
||||||
|
* @param images - array of hex encoded arrays of images obtained with exportMultisigImages
|
||||||
|
* @return number of imported images
|
||||||
|
*/
|
||||||
|
virtual size_t importMultisigImages(const std::vector<std::string>& images) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief restoreMultisigTransaction creates PendingTransaction from signData
|
||||||
|
* @param signData encrypted unsigned transaction. Obtained with PendingTransaction::multisigSignData
|
||||||
|
* @return PendingTransaction
|
||||||
|
*/
|
||||||
|
virtual PendingTransaction* restoreMultisigTransaction(const std::string& signData) = 0;
|
||||||
/*!
|
/*!
|
||||||
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
|
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
|
||||||
* \param dst_addr destination address as string
|
* \param dst_addr destination address as string
|
||||||
|
|
|
@ -4955,7 +4955,7 @@ bool wallet2::save_multisig_tx(const multisig_tx_set &txs, const std::string &fi
|
||||||
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
|
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
std::string wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector)
|
wallet2::multisig_tx_set wallet2::make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const
|
||||||
{
|
{
|
||||||
multisig_tx_set txs;
|
multisig_tx_set txs;
|
||||||
txs.m_ptx = ptx_vector;
|
txs.m_ptx = ptx_vector;
|
||||||
|
@ -4967,8 +4967,12 @@ std::string wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector)
|
||||||
}
|
}
|
||||||
|
|
||||||
txs.m_signers.insert(get_multisig_signer_public_key());
|
txs.m_signers.insert(get_multisig_signer_public_key());
|
||||||
|
return txs;
|
||||||
|
}
|
||||||
|
|
||||||
return save_multisig_tx(txs);
|
std::string wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector)
|
||||||
|
{
|
||||||
|
return save_multisig_tx(make_multisig_tx_set(ptx_vector));
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename)
|
bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename)
|
||||||
|
|
|
@ -686,6 +686,7 @@ namespace tools
|
||||||
bool save_multisig_tx(const multisig_tx_set &txs, const std::string &filename);
|
bool save_multisig_tx(const multisig_tx_set &txs, const std::string &filename);
|
||||||
std::string save_multisig_tx(const std::vector<pending_tx>& ptx_vector);
|
std::string save_multisig_tx(const std::vector<pending_tx>& ptx_vector);
|
||||||
bool save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename);
|
bool save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename);
|
||||||
|
multisig_tx_set make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const;
|
||||||
// load unsigned tx from file and sign it. Takes confirmation callback as argument. Used by the cli wallet
|
// load unsigned tx from file and sign it. Takes confirmation callback as argument. Used by the cli wallet
|
||||||
bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, std::function<bool(const unsigned_tx_set&)> accept_func = NULL, bool export_raw = false);
|
bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, std::function<bool(const unsigned_tx_set&)> accept_func = NULL, bool export_raw = false);
|
||||||
// sign unsigned tx. Takes unsigned_tx_set as argument. Used by GUI
|
// sign unsigned tx. Takes unsigned_tx_set as argument. Used by GUI
|
||||||
|
|
Loading…
Reference in a new issue