From 5af973e45aec5474b59ed72e79fb3945e91fa272 Mon Sep 17 00:00:00 2001 From: Mika Lindqvist Date: Mon, 1 Apr 2024 00:11:45 +0300 Subject: [PATCH] [SimpleWalle] Allow using more than one subwallet for "transfer" command * If current subwallet doesn't have enough available balance but there is other subwallets that total up to needed amount, SimpleWallet will ask if user wants to use available balance from other subwallets. Subwallets are selected by index until total balance is higher than needed balance. --- src/SimpleWallet/SubWallet.cpp | 22 +++++++++++- src/SimpleWallet/SubWallet.h | 4 ++- src/SimpleWallet/Transfer.cpp | 61 +++++++++++++++++++++++++++++----- src/SimpleWallet/Transfer.h | 6 ++-- 4 files changed, 80 insertions(+), 13 deletions(-) diff --git a/src/SimpleWallet/SubWallet.cpp b/src/SimpleWallet/SubWallet.cpp index 9f280a94..e99faccc 100644 --- a/src/SimpleWallet/SubWallet.cpp +++ b/src/SimpleWallet/SubWallet.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2021, The Talleo developers +Copyright (C) 2021-2024, The Talleo developers This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,6 +17,16 @@ along with this program. If not, see . #include "SubWallet.h" +uint64_t getTotalActualBalance(CryptoNote::WalletGreen &wallet) { + uint64_t balance = 0; + size_t numWallets = wallet.getAddressCount(); + for (size_t i = 0; i < numWallets; i++) { + std::string address = wallet.getAddress(i); + balance += wallet.getActualBalance(address); + } + return balance; +} + uint64_t getTotalActualBalance(CryptoNote::WalletGreen &wallet, const std::vector &addresses) { uint64_t balance = 0; for (auto address : addresses) { @@ -25,6 +35,16 @@ uint64_t getTotalActualBalance(CryptoNote::WalletGreen &wallet, const std::vecto return balance; } +uint64_t getTotalPendingBalance(CryptoNote::WalletGreen &wallet) { + uint64_t balance = 0; + size_t numWallets = wallet.getAddressCount(); + for (size_t i = 0; i < numWallets; i++) { + std::string address = wallet.getAddress(i); + balance += wallet.getPendingBalance(address); + } + return balance; +} + uint64_t getTotalPendingBalance(CryptoNote::WalletGreen &wallet, const std::vector &addresses) { uint64_t balance = 0; for (auto address: addresses) { diff --git a/src/SimpleWallet/SubWallet.h b/src/SimpleWallet/SubWallet.h index 3ae95494..9bfcd334 100644 --- a/src/SimpleWallet/SubWallet.h +++ b/src/SimpleWallet/SubWallet.h @@ -1,5 +1,5 @@ /* -Copyright (C) 2021, The Talleo developers +Copyright (C) 2021-2024, The Talleo developers This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,5 +19,7 @@ along with this program. If not, see . #include "Wallet/WalletGreen.h" +uint64_t getTotalActualBalance(CryptoNote::WalletGreen &wallet); uint64_t getTotalActualBalance(CryptoNote::WalletGreen &wallet, const std::vector &addresses); +uint64_t getTotalPendingBalance(CryptoNote::WalletGreen &wallet); uint64_t getTotalPendingBalance(CryptoNote::WalletGreen &wallet, const std::vector &addresses); diff --git a/src/SimpleWallet/Transfer.cpp b/src/SimpleWallet/Transfer.cpp index 68a94dbc..67d83dd2 100644 --- a/src/SimpleWallet/Transfer.cpp +++ b/src/SimpleWallet/Transfer.cpp @@ -542,6 +542,9 @@ void fusionTX(CryptoNote::WalletGreen &wallet, CryptoNote::TransactionParameters void transfer(System::Dispatcher& dispatcher, std::shared_ptr walletInfo, std::vector args) { uint16_t mixin; + std::string sourceAddress = walletInfo->wallet.getAddress(subWallet); + std::vector sourceAddresses; + sourceAddresses.push_back(sourceAddress); std::string address; uint64_t amount; uint64_t fee = CryptoNote::parameters::MINIMUM_FEE; @@ -607,7 +610,7 @@ void transfer(System::Dispatcher& dispatcher, std::shared_ptr wallet } } - doTransfer(dispatcher, mixin, address, amount, fee, extra, walletInfo); + doTransfer(dispatcher, mixin, sourceAddresses, address, amount, fee, extra, walletInfo); } void transfer(System::Dispatcher& dispatcher, std::shared_ptr walletInfo) { @@ -616,6 +619,8 @@ void transfer(System::Dispatcher& dispatcher, std::shared_ptr wallet std::string sourceAddress = walletInfo->wallet.getAddress(subWallet); uint64_t balance = walletInfo->wallet.getActualBalance(sourceAddress); + std::vector sourceAddresses; + sourceAddresses.push_back(sourceAddress); auto maybeAddress = getDestinationAddress(dispatcher); @@ -635,6 +640,25 @@ void transfer(System::Dispatcher& dispatcher, std::shared_ptr wallet uint64_t amount = maybeAmount.x; + if (balance < amount && getTotalActualBalance(walletInfo->wallet) > amount) { + std::cout << WarningMsg("Current subwallet doesn't have enough funds to cover this transaction,") << std::endl; + if (confirm("do you want to use other subwallets?")) { + size_t numWallets = walletInfo->wallet.getAddressCount(); + for (size_t i = 0; i < numWallets; i++) { + std::string subaddress = walletInfo->wallet.getAddress(i); + uint64_t subbalance = walletInfo->wallet.getActualBalance(subaddress); + if (subaddress != sourceAddress && subbalance > 0) { + balance += subbalance; + sourceAddresses.push_back(subaddress); + // We need at least amount + 0.01 TLO + if (balance > amount) { + break; + } + } + } + } + } + if (balance < amount) { size_t totalLen = formatAmount(amount).length(); // Funds needed is always the widest string @@ -653,6 +677,27 @@ void transfer(System::Dispatcher& dispatcher, std::shared_ptr wallet uint64_t fee = maybeFee.x; + if (balance < amount + fee && sourceAddresses.size() > 1 && getTotalActualBalance(walletInfo->wallet) >= amount + fee) { + size_t numWallets = walletInfo->wallet.getAddressCount(); + uint64_t needed = amount + fee; + // We need to consider remote node fee already here as it could be more than remaining balance of already selected subwallets + if (!remote_fee_address.empty()) { + // Remote node fee is between 0.01 and 1.00 TLO depending on transfer amount + needed += std::min(UINT64_C(1), std::max(static_cast(amount * 0.000025), UINT64_C(100))); + } + for (size_t i = 0; i < numWallets; i++) { + std::string subaddress = walletInfo->wallet.getAddress(i); + uint64_t subbalance = walletInfo->wallet.getActualBalance(subaddress); + if (std::find(sourceAddresses.begin(), sourceAddresses.end(), subaddress) == sourceAddresses.end() && subbalance > 0) { + balance += subbalance; + sourceAddresses.push_back(subaddress); + if (balance >= needed) { + break; + } + } + } + } + if (balance < amount + fee) { size_t totalLen = formatAmount(amount + fee).length(); // Funds needed is always the widest string @@ -680,12 +725,12 @@ void transfer(System::Dispatcher& dispatcher, std::shared_ptr wallet std::string extra = maybeExtra.x; - doTransfer(dispatcher, mixin, address, amount, fee, extra, walletInfo); + doTransfer(dispatcher, mixin, sourceAddresses, address, amount, fee, extra, walletInfo); } -void doTransfer(System::Dispatcher& dispatcher, uint16_t mixin, std::string address, uint64_t amount, uint64_t fee, std::string extra, std::shared_ptr walletInfo) { - std::string sourceAddress = walletInfo->wallet.getAddress(subWallet); - uint64_t balance = walletInfo->wallet.getActualBalance(sourceAddress); +void doTransfer(System::Dispatcher& dispatcher, uint16_t mixin, std::vector sourceAddresses, std::string address, uint64_t amount, uint64_t fee, std::string extra, std::shared_ptr walletInfo) { + std::string changeAddress = walletInfo->wallet.getAddress(subWallet); + uint64_t balance = getTotalActualBalance(walletInfo->wallet, sourceAddresses); uint64_t remote_node_fee = 0; if (!remote_fee_address.empty()) { // Remote node fee is between 0.01 and 1.00 TLO depending on transfer amount @@ -726,12 +771,12 @@ void doTransfer(System::Dispatcher& dispatcher, uint16_t mixin, std::string addr } CryptoNote::TransactionParameters p; - p.sourceAddresses.push_back(sourceAddress); + p.sourceAddresses = sourceAddresses; p.destinations = transfers; p.fee = fee; p.mixIn = mixin; p.extra = extra; - p.changeDestination = sourceAddress; + p.changeDestination = changeAddress; if (!confirmTransaction(p, walletInfo)) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; @@ -1088,4 +1133,4 @@ std::string resolveAddress(System::Dispatcher& dispatcher, const std::string& em return address; -} \ No newline at end of file +} diff --git a/src/SimpleWallet/Transfer.h b/src/SimpleWallet/Transfer.h index f14a59e4..e684d38a 100644 --- a/src/SimpleWallet/Transfer.h +++ b/src/SimpleWallet/Transfer.h @@ -58,8 +58,8 @@ void transfer(System::Dispatcher& dispatcher, std::shared_ptr wallet void transfer(System::Dispatcher& dispatcher, std::shared_ptr walletInfo, std::vector args); -void doTransfer(System::Dispatcher& dispatcher, uint16_t mixin, std::string address, uint64_t amount, - uint64_t fee, std::string extra, +void doTransfer(System::Dispatcher& dispatcher, uint16_t mixin, std::vector sourceAddresses, + std::string address, uint64_t amount, uint64_t fee, std::string extra, std::shared_ptr walletInfo); void fusionTX(CryptoNote::WalletGreen &wallet, @@ -107,4 +107,4 @@ Maybe getMixin(); size_t makeFusionTransaction(CryptoNote::WalletGreen &wallet, const std::vector &sourceAddresses, const std::string &destinationAddress, uint64_t threshold); -std::string resolveAddress(System::Dispatcher& dispatcher, const std::string& email); \ No newline at end of file +std::string resolveAddress(System::Dispatcher& dispatcher, const std::string& email);