status-desktop/libs/Wallet/src/NewWalletAccountController.cpp

227 lines
8.2 KiB
C++
Raw Normal View History

#include "Status/Wallet/NewWalletAccountController.h"
#include <StatusGo/Wallet/WalletApi.h>
#include <StatusGo/Accounts/Accounts.h>
2022-10-19 15:41:53 +02:00
#include <StatusGo/Accounts/AccountsAPI.h>
#include <StatusGo/Accounts/accounts_types.h>
#include <StatusGo/Metadata/api_response.h>
#include <StatusGo/Types.h>
2022-10-19 15:41:53 +02:00
#include <StatusGo/Utils.h>
#include <Onboarding/Common/Constants.h>
#include <QJSEngine>
2022-10-19 15:41:53 +02:00
#include <QQmlEngine>
#include <ranges>
namespace GoAccounts = Status::StatusGo::Accounts;
namespace WalletGo = Status::StatusGo::Wallet;
namespace UtilsSG = Status::StatusGo::Utils;
namespace StatusGo = Status::StatusGo;
2022-10-19 15:41:53 +02:00
namespace Status::Wallet
{
2022-10-19 15:41:53 +02:00
NewWalletAccountController::NewWalletAccountController(
std::shared_ptr<Helpers::QObjectVectorModel<WalletAccount>> accounts)
: m_accounts(accounts)
, m_mainAccounts(std::move(filterMainAccounts(*accounts)), "account")
, m_derivedAddress("derivedAddress")
, m_derivationPath(Status::Constants::General::PathWalletRoot)
2022-10-19 15:41:53 +02:00
{ }
QAbstractListModel* NewWalletAccountController::mainAccountsModel()
{
return &m_mainAccounts;
}
2022-10-19 15:41:53 +02:00
QAbstractItemModel* NewWalletAccountController::currentDerivedAddressModel()
{
return &m_derivedAddress;
}
QString NewWalletAccountController::derivationPath() const
{
return m_derivationPath.get();
}
2022-10-19 15:41:53 +02:00
void NewWalletAccountController::setDerivationPath(const QString& newDerivationPath)
{
2022-10-19 15:41:53 +02:00
if(m_derivationPath.get() == newDerivationPath) return;
m_derivationPath = GoAccounts::DerivationPath(newDerivationPath);
emit derivationPathChanged();
auto oldCustom = m_customDerivationPath;
2022-10-19 15:41:53 +02:00
const auto& [derivedPath, index] = searchDerivationPath(m_derivationPath);
m_customDerivationPath = derivedPath == nullptr;
if(!m_customDerivationPath && !derivedPath.get()->alreadyCreated())
updateSelectedDerivedAddress(index, derivedPath);
2022-10-19 15:41:53 +02:00
if(m_customDerivationPath != oldCustom) emit customDerivationPathChanged();
}
2022-10-19 15:41:53 +02:00
void NewWalletAccountController::createAccountAsync(const QString& password,
const QString& name,
const QColor& color,
const QString& path,
const WalletAccount* derivedFrom)
{
2022-10-19 15:41:53 +02:00
try
{
GoAccounts::generateAccountWithDerivedPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
2022-10-19 15:41:53 +02:00
name,
color,
"",
GoAccounts::DerivationPath(path),
derivedFrom->data().derivedFrom.value());
addNewlyCreatedAccount(findMissingAccount());
}
2022-10-19 15:41:53 +02:00
catch(const StatusGo::CallPrivateRpcError& e)
{
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
emit accountCreatedStatus(false);
}
}
2022-10-19 15:41:53 +02:00
void NewWalletAccountController::addWatchOnlyAccountAsync(const QString& address,
const QString& name,
const QColor& color)
{
2022-10-19 15:41:53 +02:00
try
{
GoAccounts::addAccountWatch(Accounts::EOAddress(address), name, color, u""_qs);
addNewlyCreatedAccount(findMissingAccount());
}
2022-10-19 15:41:53 +02:00
catch(const StatusGo::CallPrivateRpcError& e)
{
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
emit accountCreatedStatus(false);
}
}
2022-10-19 15:41:53 +02:00
bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString& password,
const WalletAccount* derivedFrom)
{
assert(derivedFrom->data().derivedFrom.has_value());
2022-10-19 15:41:53 +02:00
try
{
int currentPage = 1;
int foundIndex = -1;
int currentIndex = 0;
2022-10-19 15:41:53 +02:00
auto maxPageCount = static_cast<int>(
std::ceil(static_cast<double>(m_maxDerivedAddresses) / static_cast<double>(m_derivedAddressesPageSize)));
std::shared_ptr<DerivedWalletAddress> foundEntry;
2022-10-19 15:41:53 +02:00
while(currentPage <= maxPageCount && foundIndex < 0)
{
auto all = WalletGo::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
derivedFrom->data().derivedFrom.value(),
Status::Constants::General::PathWalletRoot,
2022-10-19 15:41:53 +02:00
m_derivedAddressesPageSize,
currentPage);
if((currentIndex + all.size()) > m_derivedAddress.size())
m_derivedAddress.resize(currentIndex + all.size());
2022-10-19 15:41:53 +02:00
for(auto newDerived : all)
{
auto newEntry = Helpers::makeSharedQObject<DerivedWalletAddress>(std::move(newDerived));
m_derivedAddress.set(currentIndex, newEntry);
2022-10-19 15:41:53 +02:00
if(foundIndex < 0 && !newEntry->data().alreadyCreated)
{
foundIndex = currentIndex;
foundEntry = newEntry;
}
currentIndex++;
}
currentPage++;
}
2022-10-19 15:41:53 +02:00
if(foundIndex > 0) updateSelectedDerivedAddress(foundIndex, foundEntry);
return true;
2022-10-19 15:41:53 +02:00
}
catch(const StatusGo::CallPrivateRpcError& e)
{
return false;
}
}
void NewWalletAccountController::clearDerivedAddresses()
{
m_derivedAddress.clear();
}
WalletAccountPtr NewWalletAccountController::findMissingAccount()
{
auto accounts = GoAccounts::getAccounts();
// TODO: consider using a QObjectSetModel and a proxy sort model on top instead
2022-10-19 15:41:53 +02:00
auto it = std::find_if(accounts.begin(), accounts.end(), [this](const auto& a) {
return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(), [&a](const auto& eA) {
return a.address == eA->data().address;
});
});
return it != accounts.end() ? Helpers::makeSharedQObject<WalletAccount>(*it) : nullptr;
}
NewWalletAccountController::AccountsModel::ObjectContainer
2022-10-19 15:41:53 +02:00
NewWalletAccountController::filterMainAccounts(const AccountsModel& accounts)
{
AccountsModel::ObjectContainer out;
2022-10-19 15:41:53 +02:00
const auto& c = accounts.objects();
std::copy_if(c.begin(), c.end(), std::back_inserter(out), [](const auto& a) { return a->data().isWallet; });
return out;
}
void NewWalletAccountController::addNewlyCreatedAccount(WalletAccountPtr newAccount)
{
if(newAccount)
m_accounts->push_back(newAccount);
else
qWarning() << "No new account to add. Creation failed";
emit accountCreatedStatus(newAccount != nullptr);
}
2022-10-19 15:41:53 +02:00
DerivedWalletAddress* NewWalletAccountController::selectedDerivedAddress() const
{
return m_selectedDerivedAddress.get();
}
2022-10-19 15:41:53 +02:00
void NewWalletAccountController::setSelectedDerivedAddress(DerivedWalletAddress* newSelectedDerivedAddress)
{
2022-10-19 15:41:53 +02:00
if(m_selectedDerivedAddress.get() == newSelectedDerivedAddress) return;
auto& objs = m_derivedAddress.objects();
auto foundIt = std::find_if(objs.begin(), objs.end(), [newSelectedDerivedAddress](const auto& a) {
return a.get() == newSelectedDerivedAddress;
});
updateSelectedDerivedAddress(std::distance(objs.begin(), foundIt), *foundIt);
}
2022-10-19 15:41:53 +02:00
void NewWalletAccountController::updateSelectedDerivedAddress(int index, std::shared_ptr<DerivedWalletAddress> newEntry)
{
m_derivedAddressIndex = index;
m_selectedDerivedAddress = newEntry;
emit selectedDerivedAddressChanged();
2022-10-19 15:41:53 +02:00
if(m_derivationPath != newEntry->data().path)
{
m_derivationPath = newEntry->data().path;
emit derivationPathChanged();
}
}
2022-10-19 15:41:53 +02:00
std::tuple<DerivedWalletAddressPtr, int>
NewWalletAccountController::searchDerivationPath(const GoAccounts::DerivationPath& derivationPath)
{
const auto& c = m_derivedAddress.objects();
auto foundIt =
find_if(c.begin(), c.end(), [&derivationPath](const auto& a) { return a->data().path == derivationPath; });
if(foundIt != c.end()) return {*foundIt, std::distance(c.begin(), foundIt)};
return {nullptr, -1};
}
2022-10-19 15:41:53 +02:00
} // namespace Status::Wallet