diff --git a/src/wallet/MoneroWallet.cpp b/src/wallet/MoneroWallet.cpp index 032655d..3d9d5bd 100644 --- a/src/wallet/MoneroWallet.cpp +++ b/src/wallet/MoneroWallet.cpp @@ -960,9 +960,15 @@ namespace monero { //cout << "6" << endl; - // get unconfirmed outgoing transfers + // get unconfirmed or failed outgoing transfers if (isPending || isFailed) { - //throw runtime_error("isPending || isFailed not implemented"); + std::list> upayments; + wallet2->get_unconfirmed_payments_out(upayments, accountIndex, subaddressIndices); + for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { + shared_ptr tx = buildTxWithOutgoingTransferUnconfirmed(i->first, i->second); + if (txReq.isFailed != boost::none && txReq.isFailed.get() != tx->isFailed.get()) continue; // skip merging if tx unrequested + mergeTx(tx, txMap, blockMap, false); + } } // get unconfirmed incoming transfers @@ -1378,6 +1384,68 @@ namespace monero { return tx; } + shared_ptr MoneroWallet::buildTxWithOutgoingTransferUnconfirmed(const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd) const { + //cout << "buildTxWithOutgoingTransferUnconfirmed()" << endl; + + // construct tx + shared_ptr tx = shared_ptr(new MoneroTxWallet()); + tx->isFailed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed; + tx->id = string_tools::pod_to_hex(txid); + tx->paymentId = string_tools::pod_to_hex(pd.m_payment_id); + if (tx->paymentId->substr(16).find_first_not_of('0') == std::string::npos) tx->paymentId = tx->paymentId->substr(0, 16); // TODO monero core: this should be part of core wallet + if (tx->paymentId == MoneroTx::DEFAULT_PAYMENT_ID) tx->paymentId = boost::none; // clear default payment id + tx->unlockTime = pd.m_tx.unlock_time; + tx->fee = pd.m_amount_in - pd.m_amount_out; + tx->note = wallet2->get_tx_note(txid); + if (tx->note->empty()) tx->note = boost::none; // clear empty note + tx->isCoinbase = false; + tx->isConfirmed = false; + tx->isRelayed = !tx->isFailed.get(); + tx->inTxPool = !tx->isFailed.get(); + tx->doNotRelay = false; + tx->isDoubleSpend = false; // TODO: test, detect, and set double spend + tx->numConfirmations = 0; + + // construct transfer + shared_ptr outgoingTransfer = shared_ptr(new MoneroOutgoingTransfer()); + outgoingTransfer->tx = tx; + tx->outgoingTransfer = outgoingTransfer; + outgoingTransfer->amount = pd.m_amount_in - pd.m_change - tx->fee.get(); + outgoingTransfer->accountIndex = pd.m_subaddr_account; + vector subaddressIndices; + vector addresses; + for (uint32_t i: pd.m_subaddr_indices) { + subaddressIndices.push_back(i); + addresses.push_back(wallet2->get_subaddress_as_str({pd.m_subaddr_account, i})); + } + outgoingTransfer->subaddressIndices = subaddressIndices; + outgoingTransfer->addresses = addresses; + + // initialize destinations + for (const auto &d: pd.m_dests) { + shared_ptr destination = shared_ptr(new MoneroDestination()); + destination->amount = d.amount; + destination->address = d.original.empty() ? cryptonote::get_account_address_as_str(wallet2->nettype(), d.is_subaddress, d.addr) : d.original; + outgoingTransfer->destinations.push_back(destination); + } + + // replace transfer amount with destination sum + // TODO monero core: confirmed tx from/to same account has amount 0 but cached transfer destinations + if (*outgoingTransfer->amount == 0 && !outgoingTransfer->destinations.empty()) { + uint64_t amount = 0; + for (const shared_ptr& destination : outgoingTransfer->destinations) amount += *destination->amount; + outgoingTransfer->amount = amount; + } + + // compute numSuggestedConfirmations TODO monero core: this logic is based on wallet_rpc_server.cpp:87 but it should be encapsulated in wallet2 + uint64_t blockReward = wallet2->get_last_block_reward(); + if (blockReward == 0) outgoingTransfer->numSuggestedConfirmations = 0; + else outgoingTransfer->numSuggestedConfirmations = (*outgoingTransfer->amount + blockReward - 1) / blockReward; + + // return pointer to new tx + return tx; + } + shared_ptr MoneroWallet::buildTxWithVout(const tools::wallet2::transfer_details& td) const { // construct block diff --git a/src/wallet/MoneroWallet.h b/src/wallet/MoneroWallet.h index 8391367..565f6f9 100644 --- a/src/wallet/MoneroWallet.h +++ b/src/wallet/MoneroWallet.h @@ -1075,6 +1075,7 @@ namespace monero { vector getSubaddressesAux(uint32_t accountIdx, vector subaddressIndices, vector transfers) const; shared_ptr buildTxWithIncomingTransfer(const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) const; // TODO: these could be made inner anonymous by moving to top of .cpp shared_ptr buildTxWithOutgoingTransfer(const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) const; + shared_ptr buildTxWithOutgoingTransferUnconfirmed(const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd) const; shared_ptr buildTxWithVout(const tools::wallet2::transfer_details& outputW2) const; }; }