diff --git a/include/IWalletLegacy.h b/include/IWalletLegacy.h index 073ff02c3e..fc00907f15 100644 --- a/include/IWalletLegacy.h +++ b/include/IWalletLegacy.h @@ -138,10 +138,17 @@ class IWalletLegacy { virtual void getAccountKeys(AccountKeys& keys) = 0; virtual bool getSeed(std::string& electrum_words) = 0; + virtual std::vector getOutputs() = 0; + virtual std::vector getLockedOutputs() = 0; + virtual std::vector getUnlockedOutputs() = 0; + virtual std::vector getSpentOutputs() = 0; + virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0; virtual TransactionId sendTransaction(const std::vector& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0; + virtual TransactionId sendTransaction(const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0; virtual TransactionId sendFusionTransaction(const std::list& fusionInputs, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0; virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) = 0; + virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) = 0; virtual std::string prepareRawTransaction(TransactionId& transactionId, const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) = 0; virtual std::error_code cancelTransaction(size_t transferId) = 0; diff --git a/src/WalletLegacy/WalletLegacy.cpp b/src/WalletLegacy/WalletLegacy.cpp index f78690df1b..7ef98cef9f 100644 --- a/src/WalletLegacy/WalletLegacy.cpp +++ b/src/WalletLegacy/WalletLegacy.cpp @@ -643,6 +643,28 @@ size_t WalletLegacy::getUnlockedOutputsCount() { return outputs.size(); } +std::vector WalletLegacy::getOutputs() { + std::vector outputs; + m_transferDetails->getOutputs(outputs, ITransfersContainer::IncludeAll); + return outputs; +} + +std::vector WalletLegacy::getLockedOutputs() { + std::vector outputs; + m_transferDetails->getOutputs(outputs, ITransfersContainer::IncludeAllLocked); + return outputs; +} + +std::vector WalletLegacy::getUnlockedOutputs() { + std::vector outputs; + m_transferDetails->getOutputs(outputs, ITransfersContainer::IncludeAllUnlocked); + return outputs; +} + +std::vector WalletLegacy::getSpentOutputs() { + return m_transferDetails->getSpentOutputs(); +} + size_t WalletLegacy::estimateFusion(const uint64_t& threshold) { size_t fusionReadyCount = 0; std::vector outputs; @@ -747,9 +769,11 @@ TransactionId WalletLegacy::sendTransaction(const std::vector> events; throwIfNotInitialised(); + std::list _selectedOuts = {}; + { std::unique_lock lock(m_cacheMutex); - request = m_sender->makeSendRequest(txId, events, transfers, fee, extra, mixIn, unlockTimestamp); + request = m_sender->makeSendRequest(txId, events, transfers, _selectedOuts, fee, extra, mixIn, unlockTimestamp); } notifyClients(events); @@ -762,8 +786,46 @@ TransactionId WalletLegacy::sendTransaction(const std::vector& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) { +TransactionId WalletLegacy::sendTransaction(const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) { TransactionId txId = 0; + std::shared_ptr request; + std::deque> events; + throwIfNotInitialised(); + + { + std::unique_lock lock(m_cacheMutex); + request = m_sender->makeSendRequest(txId, events, transfers, selectedOuts, fee, extra, mixIn, unlockTimestamp); + } + + notifyClients(events); + + if (request) { + m_asyncContextCounter.addAsyncContext(); + request->perform(m_node, std::bind(&WalletLegacy::sendTransactionCallback, this, std::placeholders::_1, std::placeholders::_2)); + } + + return txId; +} + +std::string WalletLegacy::prepareRawTransaction(TransactionId& transactionId, const std::vector& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) { + std::deque> events; + throwIfNotInitialised(); + + std::list _selectedOuts = {}; + + std::string tx_as_hex; + + { + std::unique_lock lock(m_cacheMutex); + tx_as_hex = m_sender->makeRawTransaction(transactionId, events, transfers, _selectedOuts, fee, extra, mixIn, unlockTimestamp); + } + + notifyClients(events); + + return tx_as_hex; +} + +std::string WalletLegacy::prepareRawTransaction(TransactionId& transactionId, const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) { std::deque> events; throwIfNotInitialised(); @@ -771,7 +833,7 @@ std::string WalletLegacy::prepareRawTransaction(TransactionId& transactionId, co { std::unique_lock lock(m_cacheMutex); - tx_as_hex = m_sender->makeRawTransaction(transactionId, events, transfers, fee, extra, mixIn, unlockTimestamp); + tx_as_hex = m_sender->makeRawTransaction(transactionId, events, transfers, selectedOuts, fee, extra, mixIn, unlockTimestamp); } notifyClients(events); diff --git a/src/WalletLegacy/WalletLegacy.h b/src/WalletLegacy/WalletLegacy.h index abfa91444e..8222895a49 100644 --- a/src/WalletLegacy/WalletLegacy.h +++ b/src/WalletLegacy/WalletLegacy.h @@ -107,10 +107,17 @@ class WalletLegacy : virtual void getAccountKeys(AccountKeys& keys) override; virtual bool getSeed(std::string& electrum_words) override; + virtual std::vector getOutputs() override; + virtual std::vector getLockedOutputs() override; + virtual std::vector getUnlockedOutputs() override; + virtual std::vector getSpentOutputs() override; + virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override; virtual TransactionId sendTransaction(const std::vector& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override; + virtual TransactionId sendTransaction(const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override; virtual TransactionId sendFusionTransaction(const std::list& fusionInputs, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override; virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) override; + virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) override; virtual std::string prepareRawTransaction(TransactionId& transactionId, const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) override; virtual std::error_code cancelTransaction(size_t transactionId) override; diff --git a/src/WalletLegacy/WalletTransactionSender.cpp b/src/WalletLegacy/WalletTransactionSender.cpp index a96d9bafe2..2549fff44e 100644 --- a/src/WalletLegacy/WalletTransactionSender.cpp +++ b/src/WalletLegacy/WalletTransactionSender.cpp @@ -107,7 +107,7 @@ void WalletTransactionSender::validateTransfersAddresses(const std::vector WalletTransactionSender::makeSendRequest(TransactionId& transactionId, std::deque>& events, - const std::vector& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) { + const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) { using namespace CryptoNote; @@ -117,7 +117,16 @@ std::shared_ptr WalletTransactionSender::makeSendRequest(Transact std::shared_ptr context = std::make_shared(); - context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers); + if (selectedOuts.size() > 0) { + for (auto& out : selectedOuts) { + context->foundMoney += out.amount; + } + context->selectedTransfers = selectedOuts; + } + else { + context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers); + } + throwIf(context->foundMoney < neededMoney, error::WRONG_AMOUNT); transactionId = m_transactionsCache.addNewTransaction(neededMoney, fee, extra, transfers, unlockTimestamp); @@ -162,7 +171,9 @@ std::shared_ptr WalletTransactionSender::makeSendFusionRequest(Tr } std::string WalletTransactionSender::makeRawTransaction(TransactionId& transactionId, std::deque>& events, - const std::vector& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) { + const std::vector& transfers, const std::list& selectedOuts, + uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) +{ std::string raw_tx; @@ -174,7 +185,16 @@ std::string WalletTransactionSender::makeRawTransaction(TransactionId& transacti std::shared_ptr context = std::make_shared(); - context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers); + if (selectedOuts.size() > 0) { + for (auto& out : selectedOuts) { + context->foundMoney += out.amount; + } + context->selectedTransfers = selectedOuts; + } + else { + context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers); + } + throwIf(context->foundMoney < neededMoney, error::WRONG_AMOUNT); // add tx to wallet cache to prevent reuse of outputs used in this tx @@ -182,7 +202,7 @@ std::string WalletTransactionSender::makeRawTransaction(TransactionId& transacti context->transactionId = transactionId; context->mixIn = mixIn; - if (context->mixIn) { + if (context->mixIn) { uint64_t outsCount = mixIn + 1; // add one to make possible (if need) to skip real output key std::vector amounts; diff --git a/src/WalletLegacy/WalletTransactionSender.h b/src/WalletLegacy/WalletTransactionSender.h index 57c93bf182..32642b346c 100644 --- a/src/WalletLegacy/WalletTransactionSender.h +++ b/src/WalletLegacy/WalletTransactionSender.h @@ -41,10 +41,13 @@ class WalletTransactionSender std::shared_ptr makeSendRequest(TransactionId& transactionId, std::deque>& events, const std::vector& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0); + std::shared_ptr makeSendRequest(TransactionId& transactionId, std::deque>& events, + const std::vector& transfers, const std::list& selectedOuts, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0); + std::shared_ptr makeSendFusionRequest(TransactionId& transactionId, std::deque>& events, const std::vector& transfers, const std::list& fusionInputs, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0); - std::string makeRawTransaction(TransactionId& transactionId, std::deque>& events, const std::vector& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp); + std::string makeRawTransaction(TransactionId& transactionId, std::deque>& events, const std::vector& transfers, const std::list& _selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp); private: std::shared_ptr makeGetRandomOutsRequest(std::shared_ptr context);