diff --git a/src/wallet/MoneroWallet.cpp b/src/wallet/MoneroWallet.cpp index ea97980..742b3b0 100644 --- a/src/wallet/MoneroWallet.cpp +++ b/src/wallet/MoneroWallet.cpp @@ -831,6 +831,14 @@ namespace monero { 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; diff --git a/src/wallet/MoneroWalletModel.cpp b/src/wallet/MoneroWalletModel.cpp index 8266154..b2c35b0 100644 --- a/src/wallet/MoneroWalletModel.cpp +++ b/src/wallet/MoneroWalletModel.cpp @@ -15,8 +15,7 @@ namespace monero { // ----------------------- UNDECLARED PRIVATE HELPERS ----------------------- - - // -------------------------- MODEL SERIALIZATION --------------------------- + // ---------------------------- MONERO ACCOUNT ------------------------------ // TODO: ensure return object is not being unecessarily copied boost::property_tree::ptree MoneroAccount::toPropertyTree() const { @@ -37,6 +36,8 @@ namespace monero { return node; } + // -------------------------- MONERO SUBADDRESS ----------------------------- + boost::property_tree::ptree MoneroSubaddress::toPropertyTree() const { //cout << "MoneroSubaddress::toPropertyTree(node)" << endl; boost::property_tree::ptree node; @@ -52,6 +53,8 @@ namespace monero { return node; } + // --------------------------- MONERO TX WALLET ----------------------------- + boost::property_tree::ptree MoneroTxWallet::toPropertyTree() const { //cout << "MoneroTxWallet::toPropertyTree(node)" << endl; boost::property_tree::ptree node = MoneroTx::toPropertyTree(); @@ -62,80 +65,6 @@ namespace monero { return node; } - boost::property_tree::ptree MoneroTxRequest::toPropertyTree() const { - //cout << "MoneroTxRequest::toPropertyTree(node)" << endl; - throw runtime_error("Not implemented"); - } - - boost::property_tree::ptree MoneroTransfer::toPropertyTree() const { - //cout << "MoneroTransfer::toPropertyTree(node)" << endl; - boost::property_tree::ptree node; - if (amount != boost::none) node.put("amount", *amount); - if (accountIndex != boost::none) node.put("accountIndex", *accountIndex); - if (numSuggestedConfirmations != boost::none) node.put("numSuggestedConfirmations", *numSuggestedConfirmations); - return node; - } - - boost::property_tree::ptree MoneroDestination::toPropertyTree() const { - //cout << "MoneroDestination::toPropertyTree(node)" << endl; - boost::property_tree::ptree node; - if (address != boost::none) node.put("address", *address); - if (amount != boost::none) node.put("amount", *amount); - return node; - } - - boost::property_tree::ptree MoneroIncomingTransfer::toPropertyTree() const { - //cout << "MoneroIncomingTransfer::toPropertyTree(node)" << endl; - boost::property_tree::ptree node = MoneroTransfer::toPropertyTree(); - if (subaddressIndex != boost::none) node.put("subaddressIndex", *subaddressIndex); - if (address != boost::none) node.put("address", *address); - return node; - } - - boost::property_tree::ptree MoneroOutgoingTransfer::toPropertyTree() const { - //cout << "MoneroOutgoingTransfer::toPropertyTree(node)" << endl; - boost::property_tree::ptree node = MoneroTransfer::toPropertyTree(); - if (!subaddressIndices.empty()) node.add_child("subaddressIndices", MoneroUtils::toPropertyTree(subaddressIndices)); - if (!addresses.empty()) node.add_child("addresses", MoneroUtils::toPropertyTree(addresses)); - if (!destinations.empty()) node.add_child("destinations", MoneroUtils::toPropertyTree(destinations)); - return node; - } - - boost::property_tree::ptree MoneroTransferRequest::toPropertyTree() const { - //cout << "MoneroTransferRequest::toPropertyTree(node)" << endl; - boost::property_tree::ptree node = MoneroTransfer::toPropertyTree(); - if (isIncoming != boost::none) node.put("isIncoming", *isIncoming); - if (address != boost::none) node.put("address", *address); - if (subaddressIndex != boost::none) node.put("subaddressIndex", *subaddressIndex); - if (hasDestinations != boost::none) node.put("hasDestinations", *hasDestinations); - if (txRequest != boost::none) node.add_child("txRequest", (*txRequest)->toPropertyTree()); - if (!subaddressIndices.empty()) node.add_child("subaddressIndices", MoneroUtils::toPropertyTree(subaddressIndices)); - if (!addresses.empty()) node.add_child("addresses", MoneroUtils::toPropertyTree(addresses)); - if (!destinations.empty()) node.add_child("destinations", MoneroUtils::toPropertyTree(destinations)); - return node; - -// TODO: if (!addresses.empty()) node.add_child("addresses", MoneroUtils::toPropertyTree(subaddresses)); -// -// convert addresses -// -// boost::property_tree::ptree addressesNode; -// for (const string& address : addresses) { -// boost::property_tree::ptree addressNode; -// addressNode.put("", address); -// addressesNode.push_back(std::make_pair("", addressNode)); -// } -// node.add_child("addresses", addressesNode); -// -// // convert subaddress indices -// boost::property_tree::ptree subaddressIndicesNode; -// for (const uint32_t& subaddressIndex : subaddressIndices) { -// boost::property_tree::ptree subaddressIndexNode; -// subaddressIndexNode.put("", subaddressIndex); -// subaddressIndicesNode.push_back(std::make_pair("", subaddressIndexNode)); -// } -// node.add_child("subaddressIndices", subaddressIndicesNode); - } - //boost::property_tree::ptree MoneroUtils::txWalletToPropertyTree(const MoneroTxWallet& tx) { // cout << "txWalletToPropertyTree(tx)" << endl; // boost::property_tree::ptree txNode = txToPropertyTree(tx); @@ -147,6 +76,14 @@ namespace monero { // return txNode; //} // + + // -------------------------- MONERO TX REQUEST ----------------------------- + + boost::property_tree::ptree MoneroTxRequest::toPropertyTree() const { + //cout << "MoneroTxRequest::toPropertyTree(node)" << endl; + throw runtime_error("Not implemented"); + } + //boost::property_tree::ptree MoneroUtils::txRequestToPropertyTree(const MoneroTxRequest& tx) { // cout << "txWalletToPropertyTree(tx)" << endl; // boost::property_tree::ptree txNode = txWalletToPropertyTree(tx); @@ -162,16 +99,77 @@ namespace monero { // return txNode; //} - // --------------------------------- REQUESTS ------------------------------- + // ----------------------- MONERO DESTINATION ------------------------- + + boost::property_tree::ptree MoneroDestination::toPropertyTree() const { + //cout << "MoneroDestination::toPropertyTree(node)" << endl; + boost::property_tree::ptree node; + if (address != boost::none) node.put("address", *address); + if (amount != boost::none) node.put("amount", *amount); + return node; + } + + // ---------------------------- MONERO TRANSFER ----------------------------- + + boost::property_tree::ptree MoneroTransfer::toPropertyTree() const { + //cout << "MoneroTransfer::toPropertyTree(node)" << endl; + boost::property_tree::ptree node; + if (amount != boost::none) node.put("amount", *amount); + if (accountIndex != boost::none) node.put("accountIndex", *accountIndex); + if (numSuggestedConfirmations != boost::none) node.put("numSuggestedConfirmations", *numSuggestedConfirmations); + return node; + } + + // ----------------------- MONERO INCOMING TRANSFER ------------------------- + + boost::optional MoneroIncomingTransfer::getIsIncoming() const { return true; } + + boost::property_tree::ptree MoneroIncomingTransfer::toPropertyTree() const { + //cout << "MoneroIncomingTransfer::toPropertyTree(node)" << endl; + boost::property_tree::ptree node = MoneroTransfer::toPropertyTree(); + if (subaddressIndex != boost::none) node.put("subaddressIndex", *subaddressIndex); + if (address != boost::none) node.put("address", *address); + return node; + } + + // ----------------------- MONERO OUTGOING TRANSFER ------------------------- + + boost::optional MoneroOutgoingTransfer::getIsIncoming() const { return false; } + + boost::property_tree::ptree MoneroOutgoingTransfer::toPropertyTree() const { + //cout << "MoneroOutgoingTransfer::toPropertyTree(node)" << endl; + boost::property_tree::ptree node = MoneroTransfer::toPropertyTree(); + if (!subaddressIndices.empty()) node.add_child("subaddressIndices", MoneroUtils::toPropertyTree(subaddressIndices)); + if (!addresses.empty()) node.add_child("addresses", MoneroUtils::toPropertyTree(addresses)); + if (!destinations.empty()) node.add_child("destinations", MoneroUtils::toPropertyTree(destinations)); + return node; + } + + // ----------------------- MONERO TRANSFER REQUEST -------------------------- + + boost::optional MoneroTransferRequest::getIsIncoming() const { return false; } + + boost::property_tree::ptree MoneroTransferRequest::toPropertyTree() const { + //cout << "MoneroTransferRequest::toPropertyTree(node)" << endl; + boost::property_tree::ptree node = MoneroTransfer::toPropertyTree(); + if (getIsIncoming() != boost::none) node.put("isIncoming", *getIsIncoming()); + if (address != boost::none) node.put("address", *address); + if (subaddressIndex != boost::none) node.put("subaddressIndex", *subaddressIndex); + if (hasDestinations != boost::none) node.put("hasDestinations", *hasDestinations); + if (txRequest != boost::none) node.add_child("txRequest", (*txRequest)->toPropertyTree()); + if (!subaddressIndices.empty()) node.add_child("subaddressIndices", MoneroUtils::toPropertyTree(subaddressIndices)); + if (!addresses.empty()) node.add_child("addresses", MoneroUtils::toPropertyTree(addresses)); + if (!destinations.empty()) node.add_child("destinations", MoneroUtils::toPropertyTree(destinations)); + return node; + } bool MoneroTransferRequest::meetsCriteria(MoneroTransfer* transfer) const { - //cout << "meetsCriteria()" << endl; // filter on common fields - if (isIncoming != boost::none && *isIncoming != *transfer->isIncoming) return false; - if (getIsOutgoing() != boost::none && *getIsOutgoing() != *transfer->getIsOutgoing()) return false; - if (amount != boost::none && *amount != *transfer->amount) return false; - if (accountIndex != boost::none && *accountIndex != *transfer->accountIndex) return false; + if (getIsIncoming() != boost::none && *getIsIncoming() != *transfer->getIsIncoming()) return false; + if (getIsOutgoing() != boost::none && getIsOutgoing() != transfer->getIsOutgoing()) return false; + if (amount != boost::none && amount != transfer->amount) return false; + if (accountIndex != boost::none && accountIndex != transfer->accountIndex) return false; // filter on incoming fields MoneroIncomingTransfer* inTransfer = dynamic_cast(transfer); diff --git a/src/wallet/MoneroWalletModel.h b/src/wallet/MoneroWalletModel.h index e3a3412..a860706 100644 --- a/src/wallet/MoneroWalletModel.h +++ b/src/wallet/MoneroWalletModel.h @@ -92,16 +92,16 @@ namespace monero { */ struct MoneroTransfer : SerializableStruct { shared_ptr tx; - boost::optional isIncoming; boost::optional amount; boost::optional accountIndex; boost::optional numSuggestedConfirmations; - boost::property_tree::ptree toPropertyTree() const; + virtual boost::optional getIsIncoming() const = 0; // derived class must implement boost::optional getIsOutgoing() const { - if (isIncoming == boost::none ) return boost::none; - return !(*isIncoming); + if (getIsIncoming() == boost::none) return boost::none; + return !(*getIsIncoming()); } + boost::property_tree::ptree toPropertyTree() const; }; /** @@ -111,6 +111,7 @@ namespace monero { boost::optional subaddressIndex; boost::optional address; + boost::optional getIsIncoming() const; boost::property_tree::ptree toPropertyTree() const; }; @@ -122,9 +123,29 @@ namespace monero { vector addresses; vector> destinations; + boost::optional getIsIncoming() const; boost::property_tree::ptree toPropertyTree() const; }; + /** + * Configures a request to retrieve transfers. + * + * All transfers are returned except those that do not meet the criteria defined in this request. + */ + struct MoneroTransferRequest : public MoneroTransfer { + boost::optional isIncoming; + boost::optional address; + vector addresses; + boost::optional subaddressIndex; + vector subaddressIndices; + vector> destinations; + boost::optional hasDestinations; + boost::optional> txRequest; + boost::optional getIsIncoming() const; + boost::property_tree::ptree toPropertyTree() const; + bool meetsCriteria(MoneroTransfer* transfer) const; + }; + /** * Models a Monero output with wallet extensions. */ @@ -147,24 +168,6 @@ namespace monero { boost::property_tree::ptree toPropertyTree() const; }; - /** - * Configures a request to retrieve transfers. - * - * All transfers are returned except those that do not meet the criteria defined in this request. - */ - struct MoneroTransferRequest : public MoneroTransfer { - boost::optional isIncoming; - boost::optional address; - vector addresses; - boost::optional subaddressIndex; - vector subaddressIndices; - vector> destinations; - boost::optional hasDestinations; - boost::optional> txRequest; - boost::property_tree::ptree toPropertyTree() const; - bool meetsCriteria(MoneroTransfer* transfer) const; - }; - /** * Configures a request to retrieve transactions. *