-Subproject commit f7705c2c6740699a3fa47895473f79c006624559
+Subproject commit 772d207026dac31f927efa733fda3f73b103e71a
#include "dialog/OutputInfoDialog.h"
#include "dialog/OutputSweepDialog.h"
#include "utils/Icons.h"
+#include "utils/Utils.h"
-CoinsWidget::CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
+CoinsWidget::CoinsWidget(Wallet *wallet, QWidget *parent)
: QWidget(parent)
, ui(new Ui::CoinsWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
, m_headerMenu(new QMenu(this))
, m_copyMenu(new QMenu("Copy",this))
{
connect(ui->search, &QLineEdit::textChanged, this, &CoinsWidget::setSearchFilter);
- connect(m_ctx.get(), &AppContext::selectedInputsChanged, this, &CoinsWidget::selectCoins);
+ connect(m_wallet, &Wallet::selectedInputsChanged, this, &CoinsWidget::selectCoins);
}
void CoinsWidget::setModel(CoinsModel * model, Coins * coins) {
ui->coins->setColumnHidden(CoinsModel::SpentHeight, true);
ui->coins->setColumnHidden(CoinsModel::Frozen, true);
- if (!m_ctx->wallet->viewOnly()) {
+ if (!m_wallet->viewOnly()) {
ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, true);
} else {
ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, false);
keyimages << m_model->entryFromIndex(m_proxyModel->mapToSource(index))->keyImage();
}
- m_ctx->setSelectedInputs(keyimages);
+ m_wallet->setSelectedInputs(keyimages);
this->selectCoins(keyimages);
}
int ret = dialog.exec();
if (!ret) return;
- m_ctx->onSweepOutputs(keyImages, dialog.address(), dialog.churn(), dialog.outputs());
+ m_wallet->sweepOutputs(keyImages, dialog.address(), dialog.churn(), dialog.outputs());
}
void CoinsWidget::copy(copyField field) {
void CoinsWidget::freezeCoins(QStringList &pubkeys) {
for (auto &pubkey : pubkeys) {
- m_ctx->wallet->coins()->freeze(pubkey);
+ m_wallet->coins()->freeze(pubkey);
}
- m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount());
- m_ctx->updateBalance();
+ m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
+ m_wallet->updateBalance();
}
void CoinsWidget::thawCoins(QStringList &pubkeys) {
for (auto &pubkey : pubkeys) {
- m_ctx->wallet->coins()->thaw(pubkey);
+ m_wallet->coins()->thaw(pubkey);
}
- m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount());
- m_ctx->updateBalance();
+ m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
+ m_wallet->updateBalance();
}
void CoinsWidget::selectCoins(const QStringList &keyimages) {
#include <QWidget>
#include <QSvgWidget>
-#include "appcontext.h"
#include "model/CoinsModel.h"
#include "model/CoinsProxyModel.h"
#include "libwalletqt/Coins.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class CoinsWidget;
Q_OBJECT
public:
- explicit CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit CoinsWidget(Wallet *wallet, QWidget *parent = nullptr);
void setModel(CoinsModel * model, Coins * coins);
~CoinsWidget() override;
};
QScopedPointer<Ui::CoinsWidget> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
QMenu *m_contextMenu;
QMenu *m_headerMenu;
#include "dialog/ContactsDialog.h"
#include "libwalletqt/AddressBook.h"
+#include "libwalletqt/WalletManager.h"
#include "model/ModelUtils.h"
#include "utils/Icons.h"
-ContactsWidget::ContactsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
+ContactsWidget::ContactsWidget(Wallet *wallet, QWidget *parent)
: QWidget(parent)
, ui(new Ui::ContactsWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
ui->searchLayout->addWidget(m_btn_addContact, 0, Qt::AlignRight);
connect(m_btn_addContact, &QPushButton::clicked, [this]{this->newContact();});
- m_model = m_ctx->wallet->addressBookModel();
+ m_model = m_wallet->addressBookModel();
m_proxyModel = new AddressBookProxyModel;
m_proxyModel->setSourceModel(m_model);
ui->contacts->setModel(m_proxyModel);
address = dialog.getAddress();
name = dialog.getName();
- bool addressValid = WalletManager::addressValid(address, m_ctx->wallet->nettype());
+ bool addressValid = WalletManager::addressValid(address, m_wallet->nettype());
if (!addressValid) {
QMessageBox::warning(this, "Invalid address", "Invalid address");
return;
}
- int num_addresses = m_ctx->wallet->addressBook()->count();
+ int num_addresses = m_wallet->addressBook()->count();
QString address_entry;
QString name_entry;
for (int i=0; i<num_addresses; i++) {
- m_ctx->wallet->addressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){
+ m_wallet->addressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){
address_entry = entry.address();
name_entry = entry.description();
});
}
}
- m_ctx->wallet->addressBook()->addRow(address, "", name);
+ m_wallet->addressBook()->addRow(address, "", name);
}
void ContactsWidget::deleteContact()
#include <QWidget>
#include <QMenu>
-#include "appcontext.h"
#include "model/AddressBookModel.h"
#include "model/AddressBookProxyModel.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class ContactsWidget;
Q_OBJECT
public:
- explicit ContactsWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit ContactsWidget(Wallet *wallet, QWidget *parent = nullptr);
~ContactsWidget() override;
void setSearchbarVisible(bool visible);
private:
QScopedPointer<Ui::ContactsWidget> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
QAction *m_showFullAddressesAction;
QMenu *m_rowMenu;
#include <QMessageBox>
-#include "appcontext.h"
#include "dialog/TxInfoDialog.h"
#include "dialog/TxProofDialog.h"
+#include "libwalletqt/WalletManager.h"
#include "utils/config.h"
#include "utils/Icons.h"
#include "WebsocketNotifier.h"
-HistoryWidget::HistoryWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
+HistoryWidget::HistoryWidget(Wallet *wallet, QWidget *parent)
: QWidget(parent)
, ui(new Ui::HistoryWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
, m_contextMenu(new QMenu(this))
, m_copyMenu(new QMenu("Copy", this))
- , m_model(m_ctx->wallet->historyModel())
+ , m_model(wallet->historyModel())
{
ui->setupUi(this);
m_contextMenu->addMenu(m_copyMenu);
ui->syncNotice->hide();
});
- connect(m_ctx.get(), &AppContext::walletRefreshed, this, &HistoryWidget::onWalletRefreshed);
+ connect(m_wallet, &Wallet::walletRefreshed, this, &HistoryWidget::onWalletRefreshed);
ui->syncNotice->setVisible(config()->get(Config::showHistorySyncNotice).toBool());
ui->history->setHistoryModel(m_model);
auto *tx = ui->history->currentEntry();
if (!tx) return;
- auto *dialog = new TxInfoDialog(m_ctx, tx, this);
+ auto *dialog = new TxInfoDialog(m_wallet, tx, this);
connect(dialog, &TxInfoDialog::resendTranscation, [this](const QString &txid){
emit resendTransaction(txid);
});
auto *tx = ui->history->currentEntry();
if (!tx) return;
- TxProofDialog dialog{this, m_ctx, tx};
+ TxProofDialog dialog{this, m_wallet, tx};
dialog.getTxKey();
dialog.exec();
}
#include <QWidget>
#include <QMenu>
-#include "appcontext.h"
#include "libwalletqt/Coins.h"
#include "libwalletqt/Wallet.h"
#include "model/TransactionHistoryModel.h"
Q_OBJECT
public:
- explicit HistoryWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit HistoryWidget(Wallet *wallet, QWidget *parent = nullptr);
~HistoryWidget() override;
void setSearchbarVisible(bool visible);
void showSyncNoticeMsg();
QScopedPointer<Ui::HistoryWidget> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
QMenu *m_contextMenu;
QMenu *m_copyMenu;
TransactionHistoryProxyModel *m_model;
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, m_windowManager(windowManager)
- , m_ctx(new AppContext(wallet))
+ , m_wallet(wallet)
+ , m_nodes(new Nodes(this, wallet))
+ , m_rpc(new DaemonRpc(this, ""))
{
ui->setupUi(this);
m_windowCalc = new CalcWindow(this);
m_splashDialog = new SplashDialog(this);
- m_accountSwitcherDialog = new AccountSwitcherDialog(m_ctx, this);
+ m_accountSwitcherDialog = new AccountSwitcherDialog(m_wallet, this);
m_updater = QSharedPointer<Updater>(new Updater(this));
connect(m_windowManager, &WindowManager::websocketStatusChanged, this, &MainWindow::onWebsocketStatusChanged);
this->onWebsocketStatusChanged(!config()->get(Config::disableWebsocket).toBool());
- connect(m_windowManager, &WindowManager::proxySettingsChanged, [this]{
- m_ctx->onProxySettingsChanged();
- this->onProxySettingsChanged();
- });
- connect(m_windowManager, &WindowManager::updateBalance, m_ctx.data(), &AppContext::updateBalance);
- connect(m_windowManager, &WindowManager::offlineMode, [this](bool offline){
- if (!m_ctx->wallet) {
- return;
- }
- m_ctx->wallet->setOffline(offline);
- this->onConnectionStatusChanged(Wallet::ConnectionStatus_Disconnected);
- });
+ connect(m_windowManager, &WindowManager::proxySettingsChanged, this, &MainWindow::onProxySettingsChanged);
+ connect(m_windowManager, &WindowManager::updateBalance, m_wallet, &Wallet::updateBalance);
+ connect(m_windowManager, &WindowManager::offlineMode, this, &MainWindow::onOfflineMode);
connect(torManager(), &TorManager::connectionStateChanged, this, &MainWindow::onTorConnectionStateChanged);
this->onTorConnectionStateChanged(torManager()->torConnected);
ui->tabHomeWidget->setCurrentIndex(TabsHome(homeWidget));
// [History]
- m_historyWidget = new HistoryWidget(m_ctx, this);
+ m_historyWidget = new HistoryWidget(m_wallet, this);
ui->historyWidgetLayout->addWidget(m_historyWidget);
connect(m_historyWidget, &HistoryWidget::viewOnBlockExplorer, this, &MainWindow::onViewOnBlockExplorer);
connect(m_historyWidget, &HistoryWidget::resendTransaction, this, &MainWindow::onResendTransaction);
// [Send]
- m_sendWidget = new SendWidget(m_ctx, this);
+ m_sendWidget = new SendWidget(m_wallet, this);
ui->sendWidgetLayout->addWidget(m_sendWidget);
// --------------
- m_contactsWidget = new ContactsWidget(m_ctx, this);
+ m_contactsWidget = new ContactsWidget(m_wallet, this);
ui->contactsWidgetLayout->addWidget(m_contactsWidget);
// [Receive]
- m_receiveWidget = new ReceiveWidget(m_ctx, this);
+ m_receiveWidget = new ReceiveWidget(m_wallet, this);
ui->receiveWidgetLayout->addWidget(m_receiveWidget);
connect(m_receiveWidget, &ReceiveWidget::showTransactions, [this](const QString &text) {
m_historyWidget->setSearchText(text);
connect(m_contactsWidget, &ContactsWidget::fillAddress, m_sendWidget, &SendWidget::fillAddress);
// [Coins]
- m_coinsWidget = new CoinsWidget(m_ctx, this);
+ m_coinsWidget = new CoinsWidget(m_wallet, this);
ui->coinsWidgetLayout->addWidget(m_coinsWidget);
#ifdef HAS_LOCALMONERO
- m_localMoneroWidget = new LocalMoneroWidget(this, m_ctx);
+ m_localMoneroWidget = new LocalMoneroWidget(this, m_wallet);
ui->localMoneroLayout->addWidget(m_localMoneroWidget);
#else
ui->tabWidgetExchanges->setTabVisible(0, false);
#endif
#ifdef HAS_XMRIG
- m_xmrig = new XMRigWidget(m_ctx, this);
+ m_xmrig = new XMRigWidget(m_wallet, this);
ui->xmrRigLayout->addWidget(m_xmrig);
connect(m_xmrig, &XMRigWidget::miningStarted, [this]{ this->updateTitle(); });
ui->frame_coinControl->setVisible(false);
connect(ui->btn_resetCoinControl, &QPushButton::clicked, [this]{
- m_ctx->setSelectedInputs({});
+ m_wallet->setSelectedInputs({});
});
m_walletUnlockWidget = new WalletUnlockWidget(this);
// [Wallet] -> [Advanced]
connect(ui->actionStore_wallet, &QAction::triggered, this, &MainWindow::tryStoreWallet);
- connect(ui->actionUpdate_balance, &QAction::triggered, [this]{m_ctx->updateBalance();});
- connect(ui->actionRefresh_tabs, &QAction::triggered, [this]{m_ctx->refreshModels();});
+ connect(ui->actionUpdate_balance, &QAction::triggered, [this]{m_wallet->updateBalance();});
+ connect(ui->actionRefresh_tabs, &QAction::triggered, [this]{m_wallet->refreshModels();});
connect(ui->actionRescan_spent, &QAction::triggered, this, &MainWindow::rescanSpent);
connect(ui->actionWallet_cache_debug, &QAction::triggered, this, &MainWindow::showWalletCacheDebugDialog);
void MainWindow::initHome() {
// Ticker widgets
- m_tickerWidgets.append(new PriceTickerWidget(this, m_ctx, "XMR"));
- m_tickerWidgets.append(new PriceTickerWidget(this, m_ctx, "BTC"));
- m_tickerWidgets.append(new RatioTickerWidget(this, m_ctx, "XMR", "BTC"));
+ m_tickerWidgets.append(new PriceTickerWidget(this, m_wallet, "XMR"));
+ m_tickerWidgets.append(new PriceTickerWidget(this, m_wallet, "BTC"));
+ m_tickerWidgets.append(new RatioTickerWidget(this, m_wallet, "XMR", "BTC"));
for (const auto &widget : m_tickerWidgets) {
ui->tickerLayout->addWidget(widget);
}
- m_balanceTickerWidget = new BalanceTickerWidget(this, m_ctx, false);
+ m_balanceTickerWidget = new BalanceTickerWidget(this, m_wallet, false);
ui->fiatTickerLayout->addWidget(m_balanceTickerWidget);
connect(ui->ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen);
}
void MainWindow::initWalletContext() {
- connect(m_ctx.get(), &AppContext::balanceUpdated, this, &MainWindow::onBalanceUpdated);
- connect(m_ctx.get(), &AppContext::synchronized, this, &MainWindow::onSynchronized);
- connect(m_ctx.get(), &AppContext::blockchainSync, this, &MainWindow::onBlockchainSync);
- connect(m_ctx.get(), &AppContext::refreshSync, this, &MainWindow::onRefreshSync);
- connect(m_ctx.get(), &AppContext::createTransactionError, this, &MainWindow::onCreateTransactionError);
- connect(m_ctx.get(), &AppContext::createTransactionSuccess, this, &MainWindow::onCreateTransactionSuccess);
- connect(m_ctx.get(), &AppContext::transactionCommitted, this, &MainWindow::onTransactionCommitted);
- connect(m_ctx.get(), &AppContext::deviceError, this, &MainWindow::onDeviceError);
- connect(m_ctx.get(), &AppContext::deviceButtonRequest, this, &MainWindow::onDeviceButtonRequest);
- connect(m_ctx.get(), &AppContext::deviceButtonPressed, this, &MainWindow::onDeviceButtonPressed);
- connect(m_ctx.get(), &AppContext::initiateTransaction, this, &MainWindow::onInitiateTransaction);
- connect(m_ctx.get(), &AppContext::endTransaction, this, &MainWindow::onEndTransaction);
- connect(m_ctx.get(), &AppContext::keysCorrupted, this, &MainWindow::onKeysCorrupted);
- connect(m_ctx.get(), &AppContext::selectedInputsChanged, this, &MainWindow::onSelectedInputsChanged);
+ connect(m_wallet, &Wallet::balanceUpdated, this, &MainWindow::onBalanceUpdated);
+ connect(m_wallet, &Wallet::synchronized, this, &MainWindow::onSynchronized); //TODO
+ connect(m_wallet, &Wallet::blockchainSync, this, &MainWindow::onBlockchainSync);
+ connect(m_wallet, &Wallet::refreshSync, this, &MainWindow::onRefreshSync);
+ connect(m_wallet, &Wallet::createTransactionError, this, &MainWindow::onCreateTransactionError);
+ connect(m_wallet, &Wallet::createTransactionSuccess, this, &MainWindow::onCreateTransactionSuccess);
+ connect(m_wallet, &Wallet::transactionCommitted, this, &MainWindow::onTransactionCommitted);
+ connect(m_wallet, &Wallet::initiateTransaction, this, &MainWindow::onInitiateTransaction);
+ connect(m_wallet, &Wallet::endTransaction, this, &MainWindow::onEndTransaction);
+ connect(m_wallet, &Wallet::keysCorrupted, this, &MainWindow::onKeysCorrupted);
+ connect(m_wallet, &Wallet::selectedInputsChanged, this, &MainWindow::onSelectedInputsChanged);
// Wallet
- connect(m_ctx->wallet, &Wallet::connectionStatusChanged, [this](int status){
+ connect(m_wallet, &Wallet::connectionStatusChanged, [this](int status){
// Order is important, first inform UI about a potential disconnect, then reconnect
this->onConnectionStatusChanged(status);
- this->m_ctx->nodes->autoConnect();
+ m_nodes->autoConnect();
+ });
+ connect(m_wallet, &Wallet::currentSubaddressAccountChanged, this, &MainWindow::updateTitle);
+ connect(m_wallet, &Wallet::walletPassphraseNeeded, this, &MainWindow::onWalletPassphraseNeeded);
+
+ connect(m_wallet, &Wallet::unconfirmedMoneyReceived, this, [this](const QString &txId, uint64_t amount){
+ if (m_wallet->isSynchronized()) {
+ auto notify = QString("%1 XMR (pending)").arg(WalletManager::displayAmount(amount, false));
+ Utils::desktopNotify("Payment received", notify, 5000);
+ }
+ });
+
+ // Device
+ connect(m_wallet, &Wallet::deviceButtonRequest, this, &MainWindow::onDeviceButtonRequest);
+ connect(m_wallet, &Wallet::deviceButtonPressed, this, &MainWindow::onDeviceButtonPressed);
+ connect(m_wallet, &Wallet::deviceError, this, &MainWindow::onDeviceError);
+
+ connect(m_wallet, &Wallet::donationSent, this, []{
+ config()->set(Config::donateBeg, -1);
+ });
+
+ connect(m_wallet, &Wallet::multiBroadcast, this, [this](PendingTransaction *tx){
+ quint64 count = tx->txCount();
+ for (quint64 i = 0; i < count; i++) {
+ QString txData = tx->signedTxToHex(i);
+
+ for (const auto& node: m_nodes->nodes()) {
+ QString address = node.toURL();
+ qDebug() << QString("Relaying %1 to: %2").arg(tx->txid()[i], address);
+ m_rpc->setDaemonAddress(address);
+ m_rpc->sendRawTransaction(txData);
+ }
+ }
});
- connect(m_ctx->wallet, &Wallet::currentSubaddressAccountChanged, this, &MainWindow::updateTitle);
- connect(m_ctx->wallet, &Wallet::walletPassphraseNeeded, this, &MainWindow::onWalletPassphraseNeeded);
}
void MainWindow::menuToggleTabVisible(const QString &key){
}
QString MainWindow::walletName() {
- return QFileInfo(m_ctx->wallet->cachePath()).fileName();
+ return QFileInfo(m_wallet->cachePath()).fileName();
}
QString MainWindow::walletCachePath() {
- return m_ctx->wallet->cachePath();
+ return m_wallet->cachePath();
}
QString MainWindow::walletKeysPath() {
- return m_ctx->wallet->keysPath();
+ return m_wallet->keysPath();
}
void MainWindow::displayWalletErrorMsg(const QString &err) {
qDebug() << Q_FUNC_INFO;
m_splashDialog->hide();
- m_ctx->wallet->setRingDatabase(Utils::ringDatabasePath());
+ m_wallet->setRingDatabase(Utils::ringDatabasePath());
- m_ctx->updateBalance();
- if (m_ctx->wallet->isHwBacked()) {
+ m_wallet->updateBalance();
+ if (m_wallet->isHwBacked()) {
m_statusBtnHwDevice->show();
}
this->setEnabled(true);
// receive page
- m_ctx->wallet->subaddress()->refresh(m_ctx->wallet->currentSubaddressAccount());
- if (m_ctx->wallet->subaddress()->count() == 1) {
+ m_wallet->subaddress()->refresh(m_wallet->currentSubaddressAccount());
+ if (m_wallet->subaddress()->count() == 1) {
for (int i = 0; i < 10; i++) {
- m_ctx->wallet->subaddress()->addRow(m_ctx->wallet->currentSubaddressAccount(), "");
+ m_wallet->subaddress()->addRow(m_wallet->currentSubaddressAccount(), "");
}
}
- m_ctx->wallet->subaddressModel()->setCurrentSubaddressAccount(m_ctx->wallet->currentSubaddressAccount());
+ m_wallet->subaddressModel()->setCurrentSubaddressAccount(m_wallet->currentSubaddressAccount());
// history page
- m_ctx->wallet->history()->refresh(m_ctx->wallet->currentSubaddressAccount());
+ m_wallet->history()->refresh(m_wallet->currentSubaddressAccount());
// coins page
- m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount());
- m_coinsWidget->setModel(m_ctx->wallet->coinsModel(), m_ctx->wallet->coins());
- m_ctx->wallet->coinsModel()->setCurrentSubaddressAccount(m_ctx->wallet->currentSubaddressAccount());
+ m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
+ m_coinsWidget->setModel(m_wallet->coinsModel(), m_wallet->coins());
+ m_wallet->coinsModel()->setCurrentSubaddressAccount(m_wallet->currentSubaddressAccount());
// Coin labeling uses set_tx_note, so we need to refresh history too
- connect(m_ctx->wallet->coins(), &Coins::descriptionChanged, [this] {
- m_ctx->wallet->history()->refresh(m_ctx->wallet->currentSubaddressAccount());
+ connect(m_wallet->coins(), &Coins::descriptionChanged, [this] {
+ m_wallet->history()->refresh(m_wallet->currentSubaddressAccount());
});
// Vice versa
- connect(m_ctx->wallet->history(), &TransactionHistory::txNoteChanged, [this] {
- m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount());
+ connect(m_wallet->history(), &TransactionHistory::txNoteChanged, [this] {
+ m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
});
this->updatePasswordIcon();
this->updateTitle();
- m_ctx->nodes->connectToNode();
+ m_nodes->allowConnection();
+ m_nodes->connectToNode();
m_updateBytes.start(250);
if (config()->get(Config::writeRecentlyOpenedWallets).toBool()) {
- this->addToRecentlyOpened(m_ctx->wallet->cachePath());
+ this->addToRecentlyOpened(m_wallet->cachePath());
}
}
}
void MainWindow::tryStoreWallet() {
- if (m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus::ConnectionStatus_Synchronizing) {
+ if (m_wallet->connectionStatus() == Wallet::ConnectionStatus::ConnectionStatus_Synchronizing) {
QMessageBox::warning(this, "Save wallet", "Unable to save wallet during synchronization.\n\n"
"Wait until synchronization is finished and try again.");
return;
}
- m_ctx->wallet->store();
+ m_wallet->store();
}
void MainWindow::onWebsocketStatusChanged(bool enabled) {
}
void MainWindow::onProxySettingsChanged() {
+ m_nodes->connectToNode();
+
int proxy = config()->get(Config::proxy).toInt();
if (proxy == Config::Proxy::Tor) {
m_statusBtnProxySettings->hide();
}
+void MainWindow::onOfflineMode(bool offline) {
+ if (!m_wallet) {
+ return;
+ }
+ m_wallet->setOffline(offline);
+ this->onConnectionStatusChanged(Wallet::ConnectionStatus_Disconnected);
+}
+
void MainWindow::onSynchronized() {
this->updateNetStats();
this->setStatusText("Synchronized");
QString tx_err = tx->errorString();
qCritical() << tx_err;
- if (m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_WrongVersion)
+ if (m_wallet->connectionStatus() == Wallet::ConnectionStatus_WrongVersion)
err = QString("%1 Wrong node version: %2").arg(err, tx_err);
else
err = QString("%1 %2").arg(err, tx_err);
if (tx_err.contains("Node response did not include the requested real output")) {
- QString currentNode = m_ctx->nodes->connection().toAddress();
+ QString currentNode = m_nodes->connection().toAddress();
err += QString("\nYou are currently connected to: %1\n\n"
"This node may be acting maliciously. You are strongly recommended to disconnect from this node."
qDebug() << Q_FUNC_INFO << err;
this->displayWalletErrorMsg(err);
- m_ctx->wallet->disposeTransaction(tx);
+ m_wallet->disposeTransaction(tx);
return;
}
else if (tx->txCount() == 0) {
err = QString("%1 %2").arg(err, "No unmixable outputs to sweep.");
qDebug() << Q_FUNC_INFO << err;
this->displayWalletErrorMsg(err);
- m_ctx->wallet->disposeTransaction(tx);
+ m_wallet->disposeTransaction(tx);
return;
}
else if (tx->txCount() > 1) {
err = QString("%1 %2").arg(err, "Split transactions are not supported. Try sending a smaller amount.");
qDebug() << Q_FUNC_INFO << err;
this->displayWalletErrorMsg(err);
- m_ctx->wallet->disposeTransaction(tx);
+ m_wallet->disposeTransaction(tx);
return;
}
err = QString("%1 %2").arg(err, "Constructed transaction doesn't appear to send to (all) specified destination address(es). Try creating the transaction again.");
qDebug() << Q_FUNC_INFO << err;
this->displayWalletErrorMsg(err);
- m_ctx->wallet->disposeTransaction(tx);
+ m_wallet->disposeTransaction(tx);
return;
}
- m_ctx->addCacheTransaction(tx->txid()[0], tx->signedTxToHex(0));
+ m_wallet->addCacheTransaction(tx->txid()[0], tx->signedTxToHex(0));
// Show advanced dialog on multi-destination transactions
- if (address.size() > 1 || m_ctx->wallet->viewOnly()) {
- TxConfAdvDialog dialog_adv{m_ctx, m_ctx->tmpTxDescription, this};
- dialog_adv.setTransaction(tx, !m_ctx->wallet->viewOnly());
+ if (address.size() > 1 || m_wallet->viewOnly()) {
+ TxConfAdvDialog dialog_adv{m_wallet, m_wallet->tmpTxDescription, this};
+ dialog_adv.setTransaction(tx, !m_wallet->viewOnly());
dialog_adv.exec();
return;
}
- TxConfDialog dialog{m_ctx, tx, address[0], m_ctx->tmpTxDescription, this};
+ TxConfDialog dialog{m_wallet, tx, address[0], m_wallet->tmpTxDescription, this};
switch (dialog.exec()) {
case QDialog::Rejected:
{
- if (!dialog.showAdvanced)
- m_ctx->onCancelTransaction(tx, address);
+ if (!dialog.showAdvanced) {
+ m_wallet->disposeTransaction(tx);
+ }
break;
}
case QDialog::Accepted:
- m_ctx->commitTransaction(tx, m_ctx->tmpTxDescription);
+ m_wallet->commitTransaction(tx, m_wallet->tmpTxDescription);
break;
}
if (dialog.showAdvanced) {
- TxConfAdvDialog dialog_adv{m_ctx, m_ctx->tmpTxDescription, this};
+ TxConfAdvDialog dialog_adv{m_wallet, m_wallet->tmpTxDescription, this};
dialog_adv.setTransaction(tx);
dialog_adv.exec();
}
msgBox.exec();
if (msgBox.clickedButton() == showDetailsButton) {
this->showHistoryTab();
- TransactionInfo *txInfo = m_ctx->wallet->history()->transaction(txid.first());
- auto *dialog = new TxInfoDialog(m_ctx, txInfo, this);
+ TransactionInfo *txInfo = m_wallet->history()->transaction(txid.first());
+ auto *dialog = new TxInfoDialog(m_wallet, txInfo, this);
connect(dialog, &TxInfoDialog::resendTranscation, this, &MainWindow::onResendTransaction);
dialog->show();
dialog->setAttribute(Qt::WA_DeleteOnClose);
}
void MainWindow::showWalletInfoDialog() {
- WalletInfoDialog dialog{m_ctx, this};
+ WalletInfoDialog dialog{m_wallet, this};
dialog.exec();
}
void MainWindow::showSeedDialog() {
- if (m_ctx->wallet->isHwBacked()) {
+ if (m_wallet->isHwBacked()) {
QMessageBox::information(this, "Information", "Seed unavailable: Wallet keys are stored on hardware device.");
return;
}
- if (m_ctx->wallet->viewOnly()) {
+ if (m_wallet->viewOnly()) {
QMessageBox::information(this, "Information", "Wallet is view-only and has no seed.\n\nTo obtain wallet keys go to Wallet -> View-Only");
return;
}
- if (!m_ctx->wallet->isDeterministic()) {
+ if (!m_wallet->isDeterministic()) {
QMessageBox::information(this, "Information", "Wallet is non-deterministic and has no seed.\n\nTo obtain wallet keys go to Wallet -> Keys");
return;
}
return;
}
- SeedDialog dialog{m_ctx, this};
+ SeedDialog dialog{m_wallet, this};
dialog.exec();
}
void MainWindow::showPasswordDialog() {
- PasswordChangeDialog dialog{this, m_ctx->wallet};
+ PasswordChangeDialog dialog{this, m_wallet};
dialog.exec();
this->updatePasswordIcon();
}
void MainWindow::updatePasswordIcon() {
- bool emptyPassword = m_ctx->wallet->verifyPassword("");
+ bool emptyPassword = m_wallet->verifyPassword("");
QIcon icon = emptyPassword ? icons()->icon("unlock.svg") : icons()->icon("lock.svg");
m_statusBtnPassword->setIcon(icon);
}
return;
}
- KeysDialog dialog{m_ctx, this};
+ KeysDialog dialog{m_wallet, this};
dialog.exec();
}
void MainWindow::showViewOnlyDialog() {
- ViewOnlyDialog dialog{m_ctx, this};
+ ViewOnlyDialog dialog{m_wallet, this};
dialog.exec();
}
}
void MainWindow::menuSettingsClicked(bool showProxyTab) {
- m_windowManager->showSettings(m_ctx, this, showProxyTab);
+ m_windowManager->showSettings(m_nodes, this, showProxyTab);
}
void MainWindow::menuSignVerifyClicked() {
- SignVerifyDialog dialog{m_ctx->wallet, this};
+ SignVerifyDialog dialog{m_wallet, this};
dialog.exec();
}
void MainWindow::menuVerifyTxProof() {
- VerifyProofDialog dialog{m_ctx->wallet, this};
+ VerifyProofDialog dialog{m_wallet, this};
dialog.exec();
}
QIcon MainWindow::hardwareDevicePairedIcon() {
QString filename;
- if (m_ctx->wallet->isLedger())
+ if (m_wallet->isLedger())
filename = "ledger.png";
- else if (m_ctx->wallet->isTrezor())
+ else if (m_wallet->isTrezor())
filename = ColorScheme::darkScheme ? "trezor_white.png" : "trezor.png";
return icons()->icon(filename);
}
QIcon MainWindow::hardwareDeviceUnpairedIcon() {
QString filename;
- if (m_ctx->wallet->isLedger())
+ if (m_wallet->isLedger())
filename = "ledger_unpaired.png";
- else if (m_ctx->wallet->isTrezor())
+ else if (m_wallet->isTrezor())
filename = ColorScheme::darkScheme ? "trezor_unpaired_white.png" : "trezor_unpaired.png";
return icons()->icon(filename);
}
m_updateBytes.stop();
m_txTimer.stop();
- m_ctx->stopTimers();
// Wallet signal may fire after AppContext is gone, causing segv
- m_ctx->wallet->disconnect();
+ m_wallet->disconnect();
+ this->disconnect();
this->saveGeo();
m_windowManager->closeWindow(this);
}
void MainWindow::onResendTransaction(const QString &txid) {
- QString txHex = m_ctx->getCacheTransaction(txid);
+ QString txHex = m_wallet->getCacheTransaction(txid);
if (txHex.isEmpty()) {
QMessageBox::warning(this, "Unable to resend transaction", "Transaction was not found in transaction cache. Unable to resend.");
return;
}
// Connect to a different node so chances of successful relay are higher
- m_ctx->nodes->autoConnect(true);
+ m_nodes->autoConnect(true);
- TxBroadcastDialog dialog{this, m_ctx, txHex};
+ TxBroadcastDialog dialog{this, m_nodes, txHex};
dialog.exec();
}
const QString targetFile = QFileDialog::getOpenFileName(this, "Import CSV file", QDir::homePath(), "CSV Files (*.csv)");
if(targetFile.isEmpty()) return;
- auto *model = m_ctx->wallet->addressBookModel();
+ auto *model = m_wallet->addressBookModel();
QMapIterator<QString, QString> i(model->readCSV(targetFile));
int inserts = 0;
while (i.hasNext()) {
i.next();
- bool addressValid = WalletManager::addressValid(i.value(), m_ctx->wallet->nettype());
+ bool addressValid = WalletManager::addressValid(i.value(), m_wallet->nettype());
if(addressValid) {
- m_ctx->wallet->addressBook()->addRow(i.value(), "", i.key());
+ m_wallet->addressBook()->addRow(i.value(), "", i.key());
inserts++;
}
}
}
void MainWindow::showDebugInfo() {
- DebugInfoDialog dialog{m_ctx, this};
+ DebugInfoDialog dialog{m_wallet, m_nodes, this};
dialog.exec();
}
return;
}
- WalletCacheDebugDialog dialog{m_ctx, this};
+ WalletCacheDebugDialog dialog{m_wallet, this};
dialog.exec();
}
return;
}
- SubaddressIndex index = m_ctx->wallet->subaddressIndex(address);
+ SubaddressIndex index = m_wallet->subaddressIndex(address);
if (!index.isValid()) {
// TODO: probably mention lookahead here
QMessageBox::warning(this, "Address Checker", "This address does not belong to this wallet.");
QString fn = QFileDialog::getSaveFileName(this, "Save key images to file", QString("%1/%2_%3").arg(QDir::homePath(), this->walletName(), QString::number(QDateTime::currentSecsSinceEpoch())), "Key Images (*_keyImages)");
if (fn.isEmpty()) return;
if (!fn.endsWith("_keyImages")) fn += "_keyImages";
- bool r = m_ctx->wallet->exportKeyImages(fn, true);
+ bool r = m_wallet->exportKeyImages(fn, true);
if (!r) {
- QMessageBox::warning(this, "Key image export", QString("Failed to export key images.\nReason: %1").arg(m_ctx->wallet->errorString()));
+ QMessageBox::warning(this, "Key image export", QString("Failed to export key images.\nReason: %1").arg(m_wallet->errorString()));
} else {
QMessageBox::information(this, "Key image export", "Successfully exported key images.");
}
void MainWindow::importKeyImages() {
QString fn = QFileDialog::getOpenFileName(this, "Import key image file", QDir::homePath(), "Key Images (*_keyImages)");
if (fn.isEmpty()) return;
- bool r = m_ctx->wallet->importKeyImages(fn);
+ bool r = m_wallet->importKeyImages(fn);
if (!r) {
- QMessageBox::warning(this, "Key image import", QString("Failed to import key images.\n\n%1").arg(m_ctx->wallet->errorString()));
+ QMessageBox::warning(this, "Key image import", QString("Failed to import key images.\n\n%1").arg(m_wallet->errorString()));
} else {
QMessageBox::information(this, "Key image import", "Successfully imported key images");
- m_ctx->refreshModels();
+ m_wallet->refreshModels();
}
}
QString fn = QFileDialog::getSaveFileName(this, "Save outputs to file", QString("%1/%2_%3").arg(QDir::homePath(), this->walletName(), QString::number(QDateTime::currentSecsSinceEpoch())), "Outputs (*_outputs)");
if (fn.isEmpty()) return;
if (!fn.endsWith("_outputs")) fn += "_outputs";
- bool r = m_ctx->wallet->exportOutputs(fn, true);
+ bool r = m_wallet->exportOutputs(fn, true);
if (!r) {
- QMessageBox::warning(this, "Outputs export", QString("Failed to export outputs.\nReason: %1").arg(m_ctx->wallet->errorString()));
+ QMessageBox::warning(this, "Outputs export", QString("Failed to export outputs.\nReason: %1").arg(m_wallet->errorString()));
} else {
QMessageBox::information(this, "Outputs export", "Successfully exported outputs.");
}
void MainWindow::importOutputs() {
QString fn = QFileDialog::getOpenFileName(this, "Import outputs file", QDir::homePath(), "Outputs (*_outputs)");
if (fn.isEmpty()) return;
- bool r = m_ctx->wallet->importOutputs(fn);
+ bool r = m_wallet->importOutputs(fn);
if (!r) {
- QMessageBox::warning(this, "Outputs import", QString("Failed to import outputs.\n\n%1").arg(m_ctx->wallet->errorString()));
+ QMessageBox::warning(this, "Outputs import", QString("Failed to import outputs.\n\n%1").arg(m_wallet->errorString()));
} else {
QMessageBox::information(this, "Outputs import", "Successfully imported outputs");
- m_ctx->refreshModels();
+ m_wallet->refreshModels();
}
}
void MainWindow::loadUnsignedTx() {
QString fn = QFileDialog::getOpenFileName(this, "Select transaction to load", QDir::homePath(), "Transaction (*unsigned_monero_tx)");
if (fn.isEmpty()) return;
- UnsignedTransaction *tx = m_ctx->wallet->loadTxFile(fn);
- auto err = m_ctx->wallet->errorString();
+ UnsignedTransaction *tx = m_wallet->loadTxFile(fn);
+ auto err = m_wallet->errorString();
if (!err.isEmpty()) {
QMessageBox::warning(this, "Load transaction from file", QString("Failed to load transaction.\n\n%1").arg(err));
return;
QMessageBox::warning(this, "Load unsigned transaction from clipboard", "Clipboard is empty");
return;
}
- UnsignedTransaction *tx = m_ctx->wallet->loadTxFromBase64Str(unsigned_tx);
- auto err = m_ctx->wallet->errorString();
+ UnsignedTransaction *tx = m_wallet->loadTxFromBase64Str(unsigned_tx);
+ auto err = m_wallet->errorString();
if (!err.isEmpty()) {
QMessageBox::warning(this, "Load unsigned transaction from clipboard", QString("Failed to load transaction.\n\n%1").arg(err));
return;
void MainWindow::loadSignedTx() {
QString fn = QFileDialog::getOpenFileName(this, "Select transaction to load", QDir::homePath(), "Transaction (*signed_monero_tx)");
if (fn.isEmpty()) return;
- PendingTransaction *tx = m_ctx->wallet->loadSignedTxFile(fn);
- auto err = m_ctx->wallet->errorString();
+ PendingTransaction *tx = m_wallet->loadSignedTxFile(fn);
+ auto err = m_wallet->errorString();
if (!err.isEmpty()) {
QMessageBox::warning(this, "Load signed transaction from file", err);
return;
}
- TxConfAdvDialog dialog{m_ctx, "", this};
+ TxConfAdvDialog dialog{m_wallet, "", this};
dialog.setTransaction(tx);
dialog.exec();
}
void MainWindow::loadSignedTxFromText() {
- TxBroadcastDialog dialog{this, m_ctx};
+ TxBroadcastDialog dialog{this, m_nodes};
dialog.exec();
}
void MainWindow::createUnsignedTxDialog(UnsignedTransaction *tx) {
- TxConfAdvDialog dialog{m_ctx, "", this};
+ TxConfAdvDialog dialog{m_wallet, "", this};
dialog.setUnsignedTransaction(tx);
dialog.exec();
}
}
}
- TxImportDialog dialog(this, m_ctx);
+ TxImportDialog dialog(this, m_wallet);
dialog.exec();
}
void MainWindow::onDeviceError(const QString &error) {
+ qCritical() << "Device error: " << error;
+
if (m_showDeviceError) {
return;
}
m_showDeviceError = true;
auto result = QMessageBox::question(this, "Hardware device", "Lost connection to hardware device. Attempt to reconnect?");
if (result == QMessageBox::Yes) {
- bool r = m_ctx->wallet->reconnectDevice();
+ bool r = m_wallet->reconnectDevice();
if (r) {
break;
}
}
}
m_statusBtnHwDevice->setIcon(this->hardwareDevicePairedIcon());
- m_ctx->wallet->startRefresh();
+ m_wallet->startRefresh();
m_showDeviceError = false;
}
void MainWindow::onDeviceButtonRequest(quint64 code) {
qDebug() << "DeviceButtonRequest, code: " << code;
- if (m_ctx->wallet->isTrezor()) {
+ if (m_wallet->isTrezor()) {
switch (code) {
case 1:
{
"the hardware wallet for better security.",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (button == QMessageBox::Yes) {
- m_ctx->wallet->onPassphraseEntered("", true, false);
+ m_wallet->onPassphraseEntered("", true, false);
return;
}
bool ok;
QString passphrase = QInputDialog::getText(nullptr, "Wallet Passphrase Needed", "Enter passphrase:", QLineEdit::EchoMode::Password, "", &ok);
if (ok) {
- m_ctx->wallet->onPassphraseEntered(passphrase, false, false);
+ m_wallet->onPassphraseEntered(passphrase, false, false);
} else {
- m_ctx->wallet->onPassphraseEntered(passphrase, false, true);
+ m_wallet->onPassphraseEntered(passphrase, false, true);
}
}
void MainWindow::updateNetStats() {
- if (!m_ctx->wallet || m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected
- || m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_Synchronized)
+ if (!m_wallet || m_wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected
+ || m_wallet->connectionStatus() == Wallet::ConnectionStatus_Synchronized)
{
m_statusLabelNetStats->hide();
return;
}
m_statusLabelNetStats->show();
- m_statusLabelNetStats->setText(QString("(D: %1)").arg(Utils::formatBytes(m_ctx->wallet->getBytesReceived())));
+ m_statusLabelNetStats->setText(QString("(D: %1)").arg(Utils::formatBytes(m_wallet->getBytesReceived())));
}
void MainWindow::rescanSpent() {
- if (!m_ctx->wallet->rescanSpent()) {
- QMessageBox::warning(this, "Rescan spent", m_ctx->wallet->errorString());
+ if (!m_wallet->rescanSpent()) {
+ QMessageBox::warning(this, "Rescan spent", m_wallet->errorString());
} else {
QMessageBox::information(this, "Rescan spent", "Successfully rescanned spent outputs.");
}
}
void MainWindow::showBalanceDialog() {
- BalanceDialog dialog{this, m_ctx->wallet};
+ BalanceDialog dialog{this, m_wallet};
dialog.exec();
}
m_constructingTransaction = true;
m_txTimer.start(1000);
- if (m_ctx->wallet->isHwBacked()) {
+ if (m_wallet->isHwBacked()) {
QString message = "Constructing transaction: action may be required on device.";
m_splashDialog->setMessage(message);
m_splashDialog->setIcon(QPixmap(":/assets/images/unconfirmed.png"));
m_txTimer.stop();
this->setStatusText(m_statusText);
- if (m_ctx->wallet->isHwBacked()) {
+ if (m_wallet->isHwBacked()) {
m_splashDialog->hide();
}
}
if (numInputs > 0) {
quint64 totalAmount = 0;
- auto coins = m_ctx->wallet->coins()->coinsFromKeyImage(selectedInputs);
+ auto coins = m_wallet->coins()->coinsFromKeyImage(selectedInputs);
for (const auto coin : coins) {
totalAmount += coin->amount();
}
}
void MainWindow::onExportHistoryCSV(bool checked) {
- if (m_ctx->wallet == nullptr)
+ if (m_wallet == nullptr)
return;
QString fn = QFileDialog::getSaveFileName(this, "Save CSV file", QDir::homePath(), "CSV (*.csv)");
if (fn.isEmpty())
return;
if (!fn.endsWith(".csv"))
fn += ".csv";
- m_ctx->wallet->history()->writeCSV(fn);
+ m_wallet->history()->writeCSV(fn);
QMessageBox::information(this, "CSV export", QString("Transaction history exported to %1").arg(fn));
}
void MainWindow::onExportContactsCSV(bool checked) {
- if (m_ctx->wallet == nullptr) return;
- auto *model = m_ctx->wallet->addressBookModel();
+ if (m_wallet == nullptr) return;
+ auto *model = m_wallet->addressBookModel();
if (model->rowCount() <= 0){
QMessageBox::warning(this, "Error", "Addressbook empty");
return;
}
QString MainWindow::getHardwareDevice() {
- if (!m_ctx->wallet->isHwBacked())
+ if (!m_wallet->isHwBacked())
return "";
- if (m_ctx->wallet->isTrezor())
+ if (m_wallet->isTrezor())
return "Trezor";
- if (m_ctx->wallet->isLedger())
+ if (m_wallet->isLedger())
return "Ledger";
return "Unknown";
}
void MainWindow::updateTitle() {
- QString title = QString("%1 (#%2)").arg(this->walletName(), QString::number(m_ctx->wallet->currentSubaddressAccount()));
+ QString title = QString("%1 (#%2)").arg(this->walletName(), QString::number(m_wallet->currentSubaddressAccount()));
- if (m_ctx->wallet->viewOnly())
+ if (m_wallet->viewOnly())
title += " [view-only]";
#ifdef HAS_XMRIG
if (m_xmrig->isMining())
}
void MainWindow::donationNag() {
- if (m_ctx->networkType != NetworkType::Type::MAINNET)
+ if (m_wallet->nettype() != NetworkType::Type::MAINNET)
return;
- if (m_ctx->wallet->viewOnly())
+ if (m_wallet->viewOnly())
return;
- if (m_ctx->wallet->balanceAll() == 0)
+ if (m_wallet->balanceAll() == 0)
return;
auto donationCounter = config()->get(Config::donateBeg).toInt();
return false;
}
- if (!m_ctx->wallet->verifyPassword(passwordDialog.password)) {
+ if (!m_wallet->verifyPassword(passwordDialog.password)) {
incorrectPassword = true;
continue;
}
return;
}
- if (!m_ctx->wallet->verifyPassword(password)) {
+ if (!m_wallet->verifyPassword(password)) {
m_walletUnlockWidget->incorrectPassword();
return;
}
m_coinsWidget->focusSearchbar();
}
-MainWindow::~MainWindow() = default;
\ No newline at end of file
+MainWindow::~MainWindow() {
+ qDebug() << "~MainWindow";
+};
\ No newline at end of file
#include <QSystemTrayIcon>
#include <QMenu>
-#include "appcontext.h"
#include "components.h"
#include "CalcWindow.h"
#include "SettingsDialog.h"
#include "model/CoinsProxyModel.h"
#include "utils/networking.h"
#include "utils/config.h"
+#include "utils/daemonrpc.h"
#include "utils/EventFilter.h"
#include "utils/Updater.h"
#include "widgets/CCSWidget.h"
void onWebsocketStatusChanged(bool enabled);
void showUpdateNotification();
void onProxySettingsChanged();
+ void onOfflineMode(bool offline);
private:
friend WindowManager;
QScopedPointer<Ui::MainWindow> ui;
WindowManager *m_windowManager;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet = nullptr;
+ Nodes *m_nodes;
+ DaemonRpc *m_rpc;
CalcWindow *m_windowCalc = nullptr;
SplashDialog *m_splashDialog = nullptr;
#include "model/ModelUtils.h"
#include "utils/Icons.h"
-ReceiveWidget::ReceiveWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
+ReceiveWidget::ReceiveWidget(Wallet *wallet, QWidget *parent)
: QWidget(parent)
, ui(new Ui::ReceiveWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
- m_model = m_ctx->wallet->subaddressModel();
- m_proxyModel = new SubaddressProxyModel(this, m_ctx->wallet->subaddress());
+ m_model = m_wallet->subaddressModel();
+ m_proxyModel = new SubaddressProxyModel(this, m_wallet->subaddress());
m_proxyModel->setSourceModel(m_model);
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
menu->addAction("Hide address", this, &ReceiveWidget::hideAddress);
}
- if (m_ctx->wallet->isHwBacked()) {
+ if (m_wallet->isHwBacked()) {
menu->addAction("Show on device", this, &ReceiveWidget::showOnDevice);
}
QString address = index.model()->data(index.siblingAtColumn(SubaddressModel::Address), Qt::UserRole).toString();
- PaymentRequestDialog dialog{this, m_ctx, address};
+ PaymentRequestDialog dialog{this, m_wallet, address};
dialog.exec();
}
void ReceiveWidget::showOnDevice() {
Monero::SubaddressRow* row = this->currentEntry();
if (!row) return;
- m_ctx->wallet->deviceShowAddressAsync(m_ctx->wallet->currentSubaddressAccount(), row->getRowId(), "");
+ m_wallet->deviceShowAddressAsync(m_wallet->currentSubaddressAccount(), row->getRowId(), "");
}
void ReceiveWidget::generateSubaddress() {
- bool r = m_ctx->wallet->subaddress()->addRow(m_ctx->wallet->currentSubaddressAccount(), "");
+ bool r = m_wallet->subaddress()->addRow(m_wallet->currentSubaddressAccount(), "");
if (!r) {
- QMessageBox::warning(this, "Warning", QString("Failed to generate subaddress:\n\n%1").arg(m_ctx->wallet->subaddress()->errorString()));
+ QMessageBox::warning(this, "Warning", QString("Failed to generate subaddress:\n\n%1").arg(m_wallet->subaddress()->errorString()));
}
}
}
QStringList ReceiveWidget::getHiddenAddresses() {
- QString data = m_ctx->wallet->getCacheAttribute("feather.hiddenaddresses");
+ QString data = m_wallet->getCacheAttribute("feather.hiddenaddresses");
return data.split(",");
}
hiddenAddresses.append(address);
}
QString data = hiddenAddresses.join(",");
- m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data);
+ m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
}
void ReceiveWidget::removeHiddenAddress(const QString &address) {
QStringList hiddenAddresses = this->getHiddenAddresses();
hiddenAddresses.removeAll(address);
QString data = hiddenAddresses.join(",");
- m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data);
+ m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
}
Monero::SubaddressRow* ReceiveWidget::currentEntry() {
#include <QWidget>
#include <QSvgWidget>
-#include "appcontext.h"
#include "libwalletqt/Subaddress.h"
+#include "libwalletqt/Wallet.h"
#include "model/SubaddressProxyModel.h"
#include "model/SubaddressModel.h"
#include "qrcode/QrCode.h"
Q_OBJECT
public:
- explicit ReceiveWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit ReceiveWidget(Wallet *wallet, QWidget *parent = nullptr);
~ReceiveWidget() override;
void setSearchbarVisible(bool visible);
private:
QScopedPointer<Ui::ReceiveWidget> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
QMenu *m_headerMenu;
QAction *m_showFullAddressesAction;
QAction *m_showUsedAddressesAction;
#include "ColorScheme.h"
#include "constants.h"
#include "utils/AppData.h"
+#include "utils/config.h"
#include "Icons.h"
+#include "libwalletqt/WalletManager.h"
#if defined(WITH_SCANNER) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include "qrcode_scanner/QrCodeScanDialog.h"
#include <QMediaDevices>
#endif
-SendWidget::SendWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
+SendWidget::SendWidget(Wallet *wallet, QWidget *parent)
: QWidget(parent)
, ui(new Ui::SendWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
QValidator *validator = new QRegularExpressionValidator(rx, this);
ui->lineAmount->setValidator(validator);
- connect(m_ctx.get(), &AppContext::initiateTransaction, this, &SendWidget::onInitiateTransaction);
- connect(m_ctx.get(), &AppContext::endTransaction, this, &SendWidget::onEndTransaction);
+ connect(m_wallet, &Wallet::initiateTransaction, this, &SendWidget::onInitiateTransaction);
+ connect(m_wallet, &Wallet::endTransaction, this, &SendWidget::onEndTransaction);
connect(WalletManager::instance(), &WalletManager::openAliasResolved, this, &SendWidget::onOpenAliasResolved);
}
void SendWidget::sendClicked() {
- if (!m_ctx->wallet->isConnected()) {
+ if (!m_wallet->isConnected()) {
QMessageBox::warning(this, "Error", "Unable to create transaction:\n\n"
"Wallet is not connected to a node.\n"
"Go to File -> Settings -> Node to manually connect to a node.");
return;
}
- if (!m_ctx->wallet->isSynchronized()) {
+ if (!m_wallet->isSynchronized()) {
QMessageBox::warning(this, "Error", "Wallet is not synchronized, unable to create transaction.\n\n"
"Wait for synchronization to complete.");
return;
amounts.push_back(output.amount);
}
- m_ctx->onCreateTransactionMultiDest(addresses, amounts, description);
+ m_wallet->createTransactionMultiDest(addresses, amounts, description);
return;
}
amount = WalletManager::amountFromDouble(this->conversionAmount());
}
- m_ctx->onCreateTransaction(recipient, amount, description, sendAll);
+ m_wallet->createTransaction(recipient, amount, description, sendAll);
}
void SendWidget::aliasClicked() {
void SendWidget::onDataPasted(const QString &data) {
if (!data.isEmpty()) {
- QVariantMap uriData = m_ctx->wallet->parse_uri_to_object(data);
+ QVariantMap uriData = m_wallet->parse_uri_to_object(data);
if (!uriData.contains("error")) {
ui->lineAddress->setText(uriData.value("address").toString());
ui->lineDescription->setText(uriData.value("tx_description").toString());
#include <QWidget>
-#include "appcontext.h"
+#include "libwalletqt/Wallet.h"
#include "widgets/CCSWidget.h"
namespace Ui {
Q_OBJECT
public:
- explicit SendWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit SendWidget(Wallet *wallet, QWidget *parent = nullptr);
void fill(const QString &address, const QString &description, double amount = 0);
void fill(double amount);
void clearFields();
double conversionAmount();
QScopedPointer<Ui::SendWidget> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
bool m_sendDisabled = false;
};
#include <QFileDialog>
#include <QMessageBox>
+#include "libwalletqt/WalletManager.h"
+#include "utils/AppData.h"
#include "utils/Icons.h"
#include "utils/WebsocketNotifier.h"
#include "widgets/NetworkProxyWidget.h"
-Settings::Settings(QSharedPointer<AppContext> ctx, QWidget *parent)
+Settings::Settings(Nodes *nodes, QWidget *parent)
: QDialog(parent)
, ui(new Ui::Settings)
- , m_ctx(std::move(ctx))
+ , m_nodes(nodes)
{
ui->setupUi(this);
void Settings::setupNetworkTab() {
// Node
- if (m_ctx) {
- ui->nodeWidget->setupUI(m_ctx->nodes);
- connect(ui->nodeWidget, &NodeWidget::nodeSourceChanged, m_ctx->nodes, &Nodes::onNodeSourceChanged);
- connect(ui->nodeWidget, &NodeWidget::connectToNode, m_ctx->nodes, QOverload<const FeatherNode&>::of(&Nodes::connectToNode));
+ if (m_nodes) {
+ ui->nodeWidget->setupUI(m_nodes);
+ connect(ui->nodeWidget, &NodeWidget::nodeSourceChanged, m_nodes, &Nodes::onNodeSourceChanged);
+ connect(ui->nodeWidget, &NodeWidget::connectToNode, m_nodes, QOverload<const FeatherNode&>::of(&Nodes::connectToNode));
} else {
- m_nodes = new Nodes(this);
+ m_nodes = new Nodes(this, nullptr);
ui->nodeWidget->setupUI(m_nodes);
ui->nodeWidget->setCanConnect(false);
}
#include <QDialog>
#include <QSettings>
-#include "appcontext.h"
#include "widgets/NodeWidget.h"
namespace Ui {
Q_OBJECT
public:
- explicit Settings(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit Settings(Nodes *nodes, QWidget *parent = nullptr);
~Settings() override;
void showNetworkProxyTab();
void enableWebsocket(bool enabled);
QScopedPointer<Ui::Settings> ui;
- QSharedPointer<AppContext> m_ctx;
Nodes *m_nodes = nullptr;
QStringList m_themes{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"};
#include "utils/Icons.h"
#include "utils/NetworkManager.h"
#include "utils/os/tails.h"
+#include "utils/os/whonix.h"
#include "utils/TorManager.h"
#include "utils/WebsocketNotifier.h"
-WindowManager::WindowManager(EventFilter *eventFilter)
- : eventFilter(eventFilter)
+WindowManager::WindowManager(QObject *parent, EventFilter *eventFilter)
+ : QObject(parent)
+ , eventFilter(eventFilter)
{
m_walletManager = WalletManager::instance();
m_splashDialog = new SplashDialog;
}
void WindowManager::closeWindow(MainWindow *window) {
+ qDebug() << "closing Window";
m_windows.removeOne(window);
- // Move Wallet to a different thread for cleanup so it doesn't block GUI thread
- window->m_ctx->wallet->moveToThread(m_cleanupThread);
+ // Move Wallet to a different thread for cleanup, so it doesn't block GUI thread
+ window->m_wallet->moveToThread(m_cleanupThread);
m_cleanupThread->start();
- window->m_ctx->wallet->deleteLater();
+ window->m_wallet->deleteLater();
+
+ window->deleteLater();
}
void WindowManager::restartApplication(const QString &binaryFilename) {
// ######################## SETTINGS ########################
-void WindowManager::showSettings(QSharedPointer<AppContext> ctx, QWidget *parent, bool showProxyTab) {
- Settings settings{ctx, parent};
+void WindowManager::showSettings(Nodes *nodes, QWidget *parent, bool showProxyTab) {
+ Settings settings{nodes, parent};
connect(&settings, &Settings::preferredFiatCurrencyChanged, [this]{
for (const auto &window : m_windows) {
wallet->setCacheAttribute("feather.seed", seed.mnemonic.join(" "));
wallet->setCacheAttribute("feather.seedoffset", seedOffset);
+ wallet->setNewWallet();
this->onWalletOpened(wallet);
}
// Currently only called when a wallet is created from device.
auto state = wallet->status();
if (state != Wallet::Status_Ok) {
+ wallet->setNewWallet();
qDebug() << Q_FUNC_INFO << QString("Wallet open error: %1").arg(wallet->errorString());
this->displayWalletErrorMessage(wallet->errorString());
m_splashDialog->hide();
#include "libwalletqt/WalletManager.h"
#include "libwalletqt/Wallet.h"
#include "MainWindow.h"
+#include "utils/nodes.h"
#include "wizard/WalletWizard.h"
class MainWindow;
Q_OBJECT
public:
- explicit WindowManager(EventFilter *eventFilter);
+ explicit WindowManager(QObject *parent, EventFilter *eventFilter);
~WindowManager() override;
void wizardOpenWallet();
void restartApplication(const QString &binaryFilename);
void raise();
- void showSettings(QSharedPointer<AppContext> ctx, QWidget *parent, bool showProxyTab = false);
+ void showSettings(Nodes *nodes, QWidget *parent, bool showProxyTab = false);
EventFilter *eventFilter;
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: 2020-2023 The Monero Project
-
-#include <QDir>
-
-#include "appcontext.h"
-#include "constants.h"
-
-// libwalletqt
-#include "libwalletqt/TransactionHistory.h"
-#include "libwalletqt/Subaddress.h"
-#include "libwalletqt/Coins.h"
-#include "model/TransactionHistoryModel.h"
-#include "model/SubaddressModel.h"
-#include "utils/NetworkManager.h"
-#include "utils/WebsocketClient.h"
-#include "utils/WebsocketNotifier.h"
-
-// This class serves as a business logic layer between MainWindow and libwalletqt.
-// This way we don't clutter the GUI with wallet logic,
-// and keep libwalletqt (mostly) clean of Feather specific implementation details
-
-AppContext::AppContext(Wallet *wallet)
- : wallet(wallet)
- , nodes(new Nodes(this))
- , networkType(constants::networkType)
- , m_rpc(new DaemonRpc{this, ""})
-{
- connect(this->wallet, &Wallet::moneySpent, this, &AppContext::onMoneySpent);
- connect(this->wallet, &Wallet::moneyReceived, this, &AppContext::onMoneyReceived);
- connect(this->wallet, &Wallet::unconfirmedMoneyReceived, this, &AppContext::onUnconfirmedMoneyReceived);
- connect(this->wallet, &Wallet::newBlock, this, &AppContext::onWalletNewBlock);
- connect(this->wallet, &Wallet::updated, this, &AppContext::onWalletUpdate);
- connect(this->wallet, &Wallet::refreshed, this, &AppContext::onWalletRefreshed);
- connect(this->wallet, &Wallet::transactionCommitted, this, &AppContext::onTransactionCommitted);
- connect(this->wallet, &Wallet::heightRefreshed, this, &AppContext::onHeightRefreshed);
- connect(this->wallet, &Wallet::transactionCreated, this, &AppContext::onTransactionCreated);
- connect(this->wallet, &Wallet::deviceError, this, &AppContext::onDeviceError);
- connect(this->wallet, &Wallet::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest);
- connect(this->wallet, &Wallet::deviceButtonPressed, this, &AppContext::onDeviceButtonPressed);
- connect(this->wallet, &Wallet::currentSubaddressAccountChanged, [this]{
- this->updateBalance();
- });
-
- connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError);
-
- nodes->setContext(this);
-
- // Store the wallet every 2 minutes
- m_storeTimer.start(2 * 60 * 1000);
- connect(&m_storeTimer, &QTimer::timeout, [this](){
- this->storeWallet();
- });
-
- this->updateBalance();
-
- connect(this->wallet->history(), &TransactionHistory::txNoteChanged, [this]{
- this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
- });
-}
-
-// ################## Transaction creation ##################
-
-void AppContext::onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all) {
- this->tmpTxDescription = description;
-
- if (!all && amount == 0) {
- emit createTransactionError("Cannot send nothing");
- return;
- }
-
- quint64 unlocked_balance = this->wallet->unlockedBalance();
- if (!all && amount > unlocked_balance) {
- emit createTransactionError(QString("Not enough money to spend.\n\n"
- "Spendable balance: %1").arg(WalletManager::displayAmount(unlocked_balance)));
- return;
- } else if (unlocked_balance == 0) {
- emit createTransactionError("No money to spend");
- return;
- }
-
- qInfo() << "Creating transaction";
- if (all)
- this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority, m_selectedInputs);
- else
- this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority, m_selectedInputs);
-
- emit initiateTransaction();
-}
-
-void AppContext::onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description) {
- this->tmpTxDescription = description;
-
- quint64 total_amount = 0;
- for (auto &amount : amounts) {
- total_amount += amount;
- }
-
- auto unlocked_balance = this->wallet->unlockedBalance();
- if (total_amount > unlocked_balance) {
- emit createTransactionError("Not enough money to spend");
- }
-
- qInfo() << "Creating transaction";
- this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority, m_selectedInputs);
-
- emit initiateTransaction();
-}
-
-void AppContext::onSweepOutputs(const QVector<QString> &keyImages, QString address, bool churn, int outputs) {
- if (churn) {
- address = this->wallet->address(0, 0);
- }
-
- qInfo() << "Creating transaction";
- this->wallet->createTransactionSelectedAsync(keyImages, address, outputs, this->tx_priority);
-
- emit initiateTransaction();
-}
-
-void AppContext::onCreateTransactionError(const QString &msg) {
- this->tmpTxDescription = "";
- emit endTransaction();
-}
-
-void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address) {
- // tx cancelled by user
- emit createTransactionCancelled(address, tx->amount());
- this->wallet->disposeTransaction(tx);
-}
-
-void AppContext::commitTransaction(PendingTransaction *tx, const QString &description) {
- // Clear list of selected transfers
- this->setSelectedInputs({});
-
- // Nodes - even well-connected, properly configured ones - consistently fail to relay transactions
- // To mitigate transactions failing we just send the transaction to every node we know about over Tor
- if (config()->get(Config::multiBroadcast).toBool()) {
- this->onMultiBroadcast(tx);
- }
-
- this->wallet->commitTransactionAsync(tx, description);
-}
-
-void AppContext::onMultiBroadcast(PendingTransaction *tx) {
- quint64 count = tx->txCount();
- for (quint64 i = 0; i < count; i++) {
- QString txData = tx->signedTxToHex(i);
-
- for (const auto& node: this->nodes->nodes()) {
- QString address = node.toURL();
- qDebug() << QString("Relaying %1 to: %2").arg(tx->txid()[i], address);
- m_rpc->setDaemonAddress(address);
- m_rpc->sendRawTransaction(txData);
- }
- }
-}
-
-void AppContext::addCacheTransaction(const QString &txid, const QString &txHex) const {
- this->wallet->setCacheAttribute(QString("tx:%1").arg(txid), txHex);
-}
-
-QString AppContext::getCacheTransaction(const QString &txid) const {
- QString txHex = this->wallet->getCacheAttribute(QString("tx:%1").arg(txid));
- return txHex;
-}
-
-// ################## Device ##################
-
-void AppContext::onDeviceButtonRequest(quint64 code) {
- emit deviceButtonRequest(code);
-}
-
-void AppContext::onDeviceButtonPressed() {
- emit deviceButtonPressed();
-}
-
-void AppContext::onDeviceError(const QString &message) {
- qCritical() << "Device error: " << message;
- emit deviceError(message);
-}
-
-// ################## Misc ##################
-
-void AppContext::setSelectedInputs(const QStringList &selectedInputs) {
- m_selectedInputs = selectedInputs;
- emit selectedInputsChanged(selectedInputs);
-}
-
-void AppContext::onProxySettingsChanged() {
- if (Utils::isTorsocks()) {
- return;
- }
-
- this->nodes->connectToNode();
-}
-
-void AppContext::stopTimers() {
- m_storeTimer.stop();
-}
-
-// ########################################## LIBWALLET QT SIGNALS ####################################################
-
-void AppContext::onMoneySpent(const QString &txId, quint64 amount) {
- // Outgoing tx included in a block
- qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount);
-}
-
-void AppContext::onMoneyReceived(const QString &txId, quint64 amount) {
- // Incoming tx included in a block.
- qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount);
-}
-
-void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) {
- // Incoming tx in pool
- qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount);
-
- if (this->wallet->synchronized()) {
- auto notify = QString("%1 XMR (pending)").arg(WalletManager::displayAmount(amount, false));
- Utils::desktopNotify("Payment received", notify, 5000);
- }
-}
-
-void AppContext::onWalletUpdate() {
- if (this->wallet->synchronized()) {
- this->refreshModels();
- this->storeWallet();
- }
-
- this->updateBalance();
-}
-
-void AppContext::onWalletRefreshed(bool success, const QString &message) {
- if (!success) {
- // Something went wrong during refresh, in some cases we need to notify the user
- qCritical() << "Exception during refresh: " << message; // Can't use ->errorString() here, other SLOT might snipe it first
- return;
- }
-
- if (!this->refreshed) {
- refreshModels();
- this->refreshed = true;
- emit walletRefreshed();
- // store wallet immediately upon finishing synchronization
- this->wallet->store();
- }
-}
-
-void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) {
- // Called whenever a new block gets scanned by the wallet
- this->syncStatusUpdated(blockheight, targetHeight);
-
- if (this->wallet->isSynchronized()) {
- this->wallet->coins()->refreshUnlocked();
- this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
- // Todo: only refresh tx confirmations
- }
-}
-
-void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) {
- if (this->wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected)
- return;
-
- if (daemonHeight < targetHeight) {
- emit blockchainSync(daemonHeight, targetHeight);
- }
- else {
- this->syncStatusUpdated(walletHeight, daemonHeight);
- }
-}
-
-void AppContext::onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address) {
- qDebug() << Q_FUNC_INFO;
-
- for (auto &addr : address) {
- if (addr == constants::donationAddress) {
- this->donationSending = true;
- }
- }
-
- // Let UI know that the transaction was constructed
- emit endTransaction();
-
- // tx created, but not sent yet. ask user to verify first.
- emit createTransactionSuccess(tx, address);
-}
-
-void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){
- // Store wallet immediately so we don't risk losing tx key if wallet crashes
- this->wallet->store();
-
- this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
- this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount());
-
- this->updateBalance();
-
- // this tx was a donation to Feather, stop our nagging
- if (this->donationSending) {
- this->donationSending = false;
- config()->set(Config::donateBeg, -1);
- }
-
- emit transactionCommitted(status, tx, txid);
-}
-
-void AppContext::storeWallet() {
- // Do not store a synchronizing wallet: store() is NOT thread safe and may crash the wallet
- if (!this->wallet->isSynchronized())
- return;
-
- qDebug() << "Storing wallet";
- this->wallet->store();
-}
-
-void AppContext::updateBalance() {
- quint64 balance = this->wallet->balance();
- quint64 spendable = this->wallet->unlockedBalance();
-
- emit balanceUpdated(balance, spendable);
-}
-
-void AppContext::syncStatusUpdated(quint64 height, quint64 target) {
- if (height < (target - 1)) {
- emit refreshSync(height, target);
- }
- else {
- this->updateBalance();
- emit synchronized();
- }
-}
-
-void AppContext::refreshModels() {
- this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
- this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount());
- bool r = this->wallet->subaddress()->refresh(this->wallet->currentSubaddressAccount());
-
- if (!r) {
- // This should only happen if wallet keys got corrupted or were tampered with
- // The list of subaddresses is wiped to prevent loss of funds
- // Notify MainWindow to display an error message
- emit keysCorrupted();
- }
-}
+++ /dev/null
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: 2020-2023 The Monero Project
-
-#ifndef FEATHER_APPCONTEXT_H
-#define FEATHER_APPCONTEXT_H
-
-#include <QObject>
-#include <QTimer>
-
-#include "utils/os/whonix.h"
-#include "utils/networking.h"
-#include "utils/Seed.h"
-#include "utils/daemonrpc.h"
-#include "utils/RestoreHeightLookup.h"
-#include "utils/nodes.h"
-
-#include "libwalletqt/WalletManager.h"
-#include "PendingTransaction.h"
-
-class AppContext : public QObject
-{
-Q_OBJECT
-
-public:
- explicit AppContext(Wallet *wallet);
-
- Wallet *wallet;
- Nodes *nodes;
-
- bool donationSending = false;
-
- QString tmpTxDescription; // TODO: remove the need for this var
-
- NetworkType::Type networkType;
- PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
-
- // libwalletqt
- bool refreshed = false;
-
- void commitTransaction(PendingTransaction *tx, const QString &description="");
- void syncStatusUpdated(quint64 height, quint64 target);
- void updateBalance();
- void refreshModels();
-
- void storeWallet();
-
- void stopTimers();
-
- void addCacheTransaction(const QString &txid, const QString &txHex) const;
- QString getCacheTransaction(const QString &txid) const;
-
- void setSelectedInputs(const QStringList &selectedInputs);
-
-public slots:
- void onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all);
- void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
- void onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address);
- void onSweepOutputs(const QVector<QString> &keyImages, QString address, bool churn, int outputs);
- void onCreateTransactionError(const QString &msg);
- void onMultiBroadcast(PendingTransaction *tx);
- void onDeviceButtonRequest(quint64 code);
- void onDeviceButtonPressed();
- void onDeviceError(const QString &message);
-
- void onProxySettingsChanged(); // should not be here
-
-private slots:
- void onMoneySpent(const QString &txId, quint64 amount);
- void onMoneyReceived(const QString &txId, quint64 amount);
- void onUnconfirmedMoneyReceived(const QString &txId, quint64 amount);
- void onWalletUpdate();
- void onWalletRefreshed(bool success, const QString &message);
-
- void onWalletNewBlock(quint64 blockheight, quint64 targetHeight);
- void onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight);
- void onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address);
- void onTransactionCommitted(bool status, PendingTransaction *t, const QStringList& txid);
-
-signals:
- void balanceUpdated(quint64 balance, quint64 spendable);
- void blockchainSync(int height, int target);
- void refreshSync(int height, int target);
- void synchronized();
- void walletRefreshed();
- void transactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid);
- void createTransactionError(QString message);
- void createTransactionCancelled(const QVector<QString> &address, quint64 amount);
- void createTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address);
- void initiateTransaction();
- void endTransaction();
- void deviceButtonRequest(quint64 code);
- void deviceButtonPressed();
- void deviceError(const QString &message);
- void keysCorrupted();
- void selectedInputsChanged(const QStringList &selectedInputs);
-
-private:
- DaemonRpc *m_rpc;
- QTimer m_storeTimer;
- QStringList m_selectedInputs;
-};
-
-#endif //FEATHER_APPCONTEXT_H
#include <QMenu>
#include "libwalletqt/SubaddressAccount.h"
+#include "libwalletqt/WalletManager.h"
#include "model/ModelUtils.h"
#include "utils/Icons.h"
+#include "utils/Utils.h"
-AccountSwitcherDialog::AccountSwitcherDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
+AccountSwitcherDialog::AccountSwitcherDialog(Wallet *wallet, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::AccountSwitcherDialog)
- , m_ctx(std::move(ctx))
- , m_model(m_ctx->wallet->subaddressAccountModel())
+ , m_wallet(wallet)
+ , m_model(wallet->subaddressAccountModel())
, m_proxyModel(new SubaddressAccountProxyModel(this))
{
ui->setupUi(this);
- m_ctx->wallet->subaddressAccount()->refresh();
+ m_wallet->subaddressAccount()->refresh();
m_proxyModel->setSourceModel(m_model);
ui->label_totalBalance->setFont(ModelUtils::getMonospaceFont());
- ui->label_totalBalance->setText(WalletManager::displayAmount(m_ctx->wallet->balanceAll()));
+ ui->label_totalBalance->setText(WalletManager::displayAmount(m_wallet->balanceAll()));
this->setWindowModality(Qt::WindowModal);
connect(ui->accounts, &QTreeView::customContextMenuRequested, this, &AccountSwitcherDialog::showContextMenu);
connect(ui->btn_newAccount, &QPushButton::clicked, [this]{
- m_ctx->wallet->addSubaddressAccount("New account");
- m_ctx->wallet->subaddressAccount()->refresh();
+ m_wallet->addSubaddressAccount("New account");
+ m_wallet->subaddressAccount()->refresh();
});
- connect(m_ctx->wallet, &Wallet::currentSubaddressAccountChanged, this, &AccountSwitcherDialog::updateSelection);
- connect(m_ctx->wallet->subaddressAccount(), &SubaddressAccount::refreshFinished, this, &AccountSwitcherDialog::updateSelection);
+ connect(m_wallet, &Wallet::currentSubaddressAccountChanged, this, &AccountSwitcherDialog::updateSelection);
+ connect(m_wallet->subaddressAccount(), &SubaddressAccount::refreshFinished, this, &AccountSwitcherDialog::updateSelection);
this->updateSelection();
}
return;
}
- m_ctx->wallet->switchSubaddressAccount(row->getRowId());
+ m_wallet->switchSubaddressAccount(row->getRowId());
}
void AccountSwitcherDialog::copyLabel() {
}
void AccountSwitcherDialog::editLabel() {
- QModelIndex index = ui->accounts->currentIndex().siblingAtColumn(m_ctx->wallet->subaddressAccountModel()->Column::Label);
+ QModelIndex index = ui->accounts->currentIndex().siblingAtColumn(m_wallet->subaddressAccountModel()->Column::Label);
ui->accounts->setCurrentIndex(index);
ui->accounts->edit(index);
}
void AccountSwitcherDialog::updateSelection() {
- QModelIndex index = m_model->index(m_ctx->wallet->currentSubaddressAccount(), 0);
+ QModelIndex index = m_model->index(m_wallet->currentSubaddressAccount(), 0);
ui->accounts->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}
Monero::SubaddressAccountRow* AccountSwitcherDialog::currentEntry() {
QModelIndex index = m_proxyModel->mapToSource(ui->accounts->currentIndex());
- return m_ctx->wallet->subaddressAccountModel()->entryFromIndex(index);
+ return m_wallet->subaddressAccountModel()->entryFromIndex(index);
}
AccountSwitcherDialog::~AccountSwitcherDialog() = default;
#include <QDialog>
-#include "appcontext.h"
+#include "libwalletqt/Wallet.h"
#include "components.h"
#include "model/SubaddressAccountModel.h"
Q_OBJECT
public:
- explicit AccountSwitcherDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit AccountSwitcherDialog(Wallet *wallet, QWidget *parent = nullptr);
~AccountSwitcherDialog() override;
private slots:
Monero::SubaddressAccountRow* currentEntry();
QScopedPointer<Ui::AccountSwitcherDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
SubaddressAccountModel *m_model;
SubaddressAccountProxyModel *m_proxyModel;
};
#include "ui_DebugInfoDialog.h"
#include "config-feather.h"
+#include "utils/AppData.h"
#include "utils/os/tails.h"
+#include "utils/os/whonix.h"
#include "utils/TorManager.h"
#include "utils/WebsocketClient.h"
#include "utils/WebsocketNotifier.h"
-DebugInfoDialog::DebugInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
+DebugInfoDialog::DebugInfoDialog(Wallet *wallet, Nodes *nodes, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::DebugInfoDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
+ , m_nodes(nodes)
{
ui->setupUi(this);
ui->label_featherVersion->setText(QString("%1-%2").arg(FEATHER_VERSION, FEATHER_COMMIT));
- ui->label_walletHeight->setText(QString::number(m_ctx->wallet->blockChainHeight()));
- ui->label_daemonHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainHeight()));
- ui->label_targetHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainTargetHeight()));
- QDateTime restoreDate = appData()->restoreHeights[constants::networkType]->heightToDate(m_ctx->wallet->getWalletCreationHeight());
- ui->label_restoreHeight->setText(QString("%1 (%2)").arg(QString::number(m_ctx->wallet->getWalletCreationHeight()), restoreDate.toString("yyyy-MM-dd")));
- ui->label_synchronized->setText(m_ctx->wallet->isSynchronized() ? "True" : "False");
+ ui->label_walletHeight->setText(QString::number(m_wallet->blockChainHeight()));
+ ui->label_daemonHeight->setText(QString::number(m_wallet->daemonBlockChainHeight()));
+ ui->label_targetHeight->setText(QString::number(m_wallet->daemonBlockChainTargetHeight()));
+ QDateTime restoreDate = appData()->restoreHeights[constants::networkType]->heightToDate(m_wallet->getWalletCreationHeight());
+ ui->label_restoreHeight->setText(QString("%1 (%2)").arg(QString::number(m_wallet->getWalletCreationHeight()), restoreDate.toString("yyyy-MM-dd")));
+ ui->label_synchronized->setText(m_wallet->isSynchronized() ? "True" : "False");
- auto node = m_ctx->nodes->connection();
+ auto node = m_nodes->connection();
ui->label_remoteNode->setText(node.toAddress());
- ui->label_walletStatus->setText(this->statusToString(m_ctx->wallet->connectionStatus()));
+ ui->label_walletStatus->setText(this->statusToString(m_wallet->connectionStatus()));
QString websocketStatus = Utils::QtEnumToString(websocketNotifier()->websocketClient.webSocket.state()).remove("State");
if (config()->get(Config::disableWebsocket).toBool()) {
websocketStatus = "Disabled";
ui->label_torLevel->setText(config()->get(Config::torPrivacyLevel).toString());
QString seedType = [this](){
- if (m_ctx->wallet->isHwBacked())
+ if (m_wallet->isHwBacked())
return QString("Hardware");
- return QString("%1 word").arg(m_ctx->wallet->seedLength());
+ return QString("%1 word").arg(m_wallet->seedLength());
}();
QString deviceType = [this](){
- if (m_ctx->wallet->isHwBacked()) {
- if (m_ctx->wallet->isLedger())
+ if (m_wallet->isHwBacked()) {
+ if (m_wallet->isLedger())
return "Ledger";
- else if (m_ctx->wallet->isTrezor())
+ else if (m_wallet->isTrezor())
return "Trezor";
else
return "Unknown";
}
}();
- QString networkType = Utils::QtEnumToString(m_ctx->wallet->nettype());
+ QString networkType = Utils::QtEnumToString(m_wallet->nettype());
if (config()->get(Config::offlineMode).toBool()) {
networkType += " (offline)";
}
ui->label_netType->setText(networkType);
ui->label_seedType->setText(seedType);
ui->label_deviceType->setText(deviceType);
- ui->label_viewOnly->setText(m_ctx->wallet->viewOnly() ? "True" : "False");
- ui->label_primaryOnly->setText(m_ctx->wallet->balance(0) == m_ctx->wallet->balanceAll() ? "True" : "False");
+ ui->label_viewOnly->setText(m_wallet->viewOnly() ? "True" : "False");
+ ui->label_primaryOnly->setText(m_wallet->balance(0) == m_wallet->balanceAll() ? "True" : "False");
QString os = QSysInfo::prettyProductName();
if (TailsOS::detect()) {
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
#include "libwalletqt/Wallet.h"
+#include "utils/nodes.h"
namespace Ui {
class DebugInfoDialog;
Q_OBJECT
public:
- explicit DebugInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit DebugInfoDialog(Wallet *wallet, Nodes *nodes, QWidget *parent = nullptr);
~DebugInfoDialog() override;
private:
void updateInfo();
QScopedPointer<Ui::DebugInfoDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
+ Nodes *m_nodes;
QTimer m_updateTimer;
};
#include "KeysDialog.h"
#include "ui_KeysDialog.h"
-KeysDialog::KeysDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
+KeysDialog::KeysDialog(Wallet *wallet, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::KeysDialog)
{
QString unavailable = "Unavailable: Key is stored on hardware device";
- ui->label_restoreHeight->setText(QString::number(ctx->wallet->getWalletCreationHeight()));
- ui->label_primaryAddress->setText(ctx->wallet->address(0, 0));
- ui->label_secretSpendKey->setText(ctx->wallet->isHwBacked() ? unavailable : ctx->wallet->getSecretSpendKey());
- ui->label_secretViewKey->setText(ctx->wallet->getSecretViewKey());
- ui->label_publicSpendKey->setText(ctx->wallet->getPublicSpendKey());
- ui->label_publicViewKey->setText(ctx->wallet->getPublicViewKey());
+ ui->label_restoreHeight->setText(QString::number(wallet->getWalletCreationHeight()));
+ ui->label_primaryAddress->setText(wallet->address(0, 0));
+ ui->label_secretSpendKey->setText(wallet->isHwBacked() ? unavailable : wallet->getSecretSpendKey());
+ ui->label_secretViewKey->setText(wallet->getSecretViewKey());
+ ui->label_publicSpendKey->setText(wallet->getPublicSpendKey());
+ ui->label_publicViewKey->setText(wallet->getPublicViewKey());
this->adjustSize();
}
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class KeysDialog;
Q_OBJECT
public:
- explicit KeysDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit KeysDialog(Wallet *wallet, QWidget *parent = nullptr);
~KeysDialog() override;
private:
#include <QRegularExpressionValidator>
#include "WalletManager.h"
+#include "utils/Utils.h"
-PaymentRequestDialog::PaymentRequestDialog(QWidget *parent, QSharedPointer<AppContext> ctx, QString address)
+PaymentRequestDialog::PaymentRequestDialog(QWidget *parent, Wallet *wallet, QString address)
: WindowModalDialog(parent)
, ui(new Ui::PaymentRequestDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
, m_address(std::move(address))
{
ui->setupUi(this);
QString recipient = ui->line_recipient->text();
quint64 amount = WalletManager::amountFromString(ui->line_amountXMR->text());
- QString uri = m_ctx->wallet->make_uri(m_address, amount, description, recipient);
+ QString uri = m_wallet->make_uri(m_address, amount, description, recipient);
ui->line_paymentRequestUri->setText(uri);
ui->line_paymentRequestUri->setCursorPosition(0);
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
+#include "libwalletqt/Wallet.h"
#include "qrcode/QrCode.h"
namespace Ui {
Q_OBJECT
public:
- explicit PaymentRequestDialog(QWidget *parent, QSharedPointer<AppContext> ctx, QString address);
+ explicit PaymentRequestDialog(QWidget *parent, Wallet *wallet, QString address);
~PaymentRequestDialog() override;
private slots:
private:
QScopedPointer<Ui::PaymentRequestDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
QString m_address;
QrCode *m_qrCode;
};
#include "constants.h"
-SeedDialog::SeedDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
+SeedDialog::SeedDialog(Wallet *wallet, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::SeedDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
ui->label_seedIcon->setPixmap(QPixmap(":/assets/images/seed.png").scaledToWidth(64, Qt::SmoothTransformation));
- ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight()));
+ ui->label_restoreHeight->setText(QString::number(m_wallet->getWalletCreationHeight()));
- if (m_ctx->wallet->getSeedLanguage().isEmpty()) {
+ if (m_wallet->getSeedLanguage().isEmpty()) {
qDebug() << "No seed language set, using default";
- m_ctx->wallet->setSeedLanguage(constants::seedLanguage);
+ m_wallet->setSeedLanguage(constants::seedLanguage);
}
- QString seedOffset = m_ctx->wallet->getCacheAttribute("feather.seedoffset");
- QString seed = m_ctx->wallet->getCacheAttribute("feather.seed");
- auto seedLength = m_ctx->wallet->seedLength();
+ QString seedOffset = m_wallet->getCacheAttribute("feather.seedoffset");
+ QString seed = m_wallet->getCacheAttribute("feather.seed");
+ auto seedLength = m_wallet->seedLength();
- QString seed_25_words = m_ctx->wallet->getSeed(seedOffset);
+ QString seed_25_words = m_wallet->getSeed(seedOffset);
if (seedLength >= 24) {
ui->check_toggleSeedType->hide();
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class SeedDialog;
Q_OBJECT
public:
- explicit SeedDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit SeedDialog(Wallet *wallet, QWidget *parent = nullptr);
~SeedDialog() override;
private:
void setSeed(const QString &seed);
QScopedPointer<Ui::SeedDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
};
#include "utils/NetworkManager.h"
-TxBroadcastDialog::TxBroadcastDialog(QWidget *parent, QSharedPointer<AppContext> ctx, const QString &transactionHex)
+TxBroadcastDialog::TxBroadcastDialog(QWidget *parent, Nodes *nodes, const QString &transactionHex)
: WindowModalDialog(parent)
, ui(new Ui::TxBroadcastDialog)
- , m_ctx(std::move(ctx))
+ , m_nodes(nodes)
{
ui->setupUi(this);
- auto node = m_ctx->nodes->connection();
+ auto node = m_nodes->connection();
m_rpc = new DaemonRpc(this, node.toAddress());
connect(ui->btn_Broadcast, &QPushButton::clicked, this, &TxBroadcastDialog::broadcastTx);
void TxBroadcastDialog::broadcastTx() {
QString tx = ui->transaction->toPlainText();
- FeatherNode node = ui->radio_useCustom->isChecked() ? FeatherNode(ui->customNode->text()) : m_ctx->nodes->connection();
+ FeatherNode node = ui->radio_useCustom->isChecked() ? FeatherNode(ui->customNode->text()) : m_nodes->connection();
m_rpc->setDaemonAddress(node.toURL());
m_rpc->sendRawTransaction(tx);
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
#include "utils/daemonrpc.h"
+#include "utils/nodes.h"
namespace Ui {
class TxBroadcastDialog;
Q_OBJECT
public:
- explicit TxBroadcastDialog(QWidget *parent, QSharedPointer<AppContext> ctx, const QString &transactionHex = "");
+ explicit TxBroadcastDialog(QWidget *parent, Nodes *nodes, const QString &transactionHex = "");
~TxBroadcastDialog() override;
private slots:
private:
QScopedPointer<Ui::TxBroadcastDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Nodes *m_nodes;
DaemonRpc *m_rpc;
};
#include "dialog/QrCodeDialog.h"
#include "libwalletqt/Input.h"
#include "libwalletqt/Transfer.h"
+#include "libwalletqt/WalletManager.h"
#include "model/ModelUtils.h"
#include "qrcode/QrCode.h"
+#include "utils/AppData.h"
+#include "utils/config.h"
+#include "utils/Utils.h"
-TxConfAdvDialog::TxConfAdvDialog(QSharedPointer<AppContext> ctx, const QString &description, QWidget *parent)
+TxConfAdvDialog::TxConfAdvDialog(Wallet *wallet, const QString &description, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::TxConfAdvDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
, m_exportUnsignedMenu(new QMenu(this))
, m_exportSignedMenu(new QMenu(this))
, m_exportTxKeyMenu(new QMenu(this))
PendingTransactionInfo *ptx = m_tx->transaction(0); //Todo: support split transactions
// TODO: implement hasTxKey()
- if (!m_ctx->wallet->isHwBacked() && m_tx->transaction(0)->txKey() == "0100000000000000000000000000000000000000000000000000000000000000") {
+ if (!m_wallet->isHwBacked() && m_tx->transaction(0)->txKey() == "0100000000000000000000000000000000000000000000000000000000000000") {
ui->btn_exportTxKey->hide();
}
for (const auto& o: outputs) {
auto address = o->address();
auto amount = WalletManager::displayAmount(o->amount());
- auto index = m_ctx->wallet->subaddressIndex(address);
+ auto index = m_wallet->subaddressIndex(address);
cursor.insertText(address, Utils::addressTextFormat(index, o->amount()));
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
cursor.insertBlock();
}
void TxConfAdvDialog::txKeyCopy() {
- if (m_ctx->wallet->isHwBacked()) {
+ if (m_wallet->isHwBacked()) {
QMessageBox::warning(this, "Unable to get tx private key", "Unable to get tx secret key: wallet is backed by hardware device");
return;
}
void TxConfAdvDialog::broadcastTransaction() {
if (m_tx == nullptr) return;
- m_ctx->commitTransaction(m_tx, ui->line_description->text());
+ m_wallet->commitTransaction(m_tx, ui->line_description->text());
QDialog::accept();
}
void TxConfAdvDialog::closeDialog() {
if (m_tx != nullptr)
- m_ctx->wallet->disposeTransaction(m_tx);
+ m_wallet->disposeTransaction(m_tx);
if (m_utx != nullptr)
- m_ctx->wallet->disposeTransaction(m_utx);
+ m_wallet->disposeTransaction(m_utx);
QDialog::reject();
}
#include <QStandardItemModel>
#include <QTextCharFormat>
-#include "appcontext.h"
#include "components.h"
#include "libwalletqt/PendingTransaction.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class TxConfAdvDialog;
Q_OBJECT
public:
- explicit TxConfAdvDialog(QSharedPointer<AppContext> ctx, const QString &description, QWidget *parent = nullptr);
+ explicit TxConfAdvDialog(Wallet *wallet, const QString &description, QWidget *parent = nullptr);
~TxConfAdvDialog() override;
void setTransaction(PendingTransaction *tx, bool isSigned = true); // #TODO: have libwallet return a UnsignedTransaction, this is just dumb
void txKeyCopy();
QScopedPointer<Ui::TxConfAdvDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
PendingTransaction *m_tx = nullptr;
UnsignedTransaction *m_utx = nullptr;
QMenu *m_exportUnsignedMenu;
#include "TxConfAdvDialog.h"
#include "utils/AppData.h"
#include "utils/ColorScheme.h"
+#include "utils/config.h"
-TxConfDialog::TxConfDialog(QSharedPointer<AppContext> ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent)
+TxConfDialog::TxConfDialog(Wallet *wallet, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::TxConfDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
, m_tx(tx)
, m_address(address)
, m_description(description)
ui->label_fee->setText(QString("%1 (%2 %3)").arg(amounts[1], amounts_fiat[1], preferredCur));
ui->label_total->setText(QString("%1 (%2 %3)").arg(amounts[2], amounts_fiat[2], preferredCur));
- auto subaddressIndex = m_ctx->wallet->subaddressIndex(address);
+ auto subaddressIndex = m_wallet->subaddressIndex(address);
QString addressExtra;
ui->label_address->setText(ModelUtils::displayAddress(address, 2));
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
#include "libwalletqt/PendingTransaction.h"
#include "libwalletqt/WalletManager.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class TxConfDialog;
Q_OBJECT
public:
- explicit TxConfDialog(QSharedPointer<AppContext> ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent = nullptr);
+ explicit TxConfDialog(Wallet *wallet, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent = nullptr);
~TxConfDialog() override;
bool showAdvanced = false;
void setShowAdvanced();
QScopedPointer<Ui::TxConfDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
PendingTransaction *m_tx;
QString m_address;
QString m_description;
#include "utils/NetworkManager.h"
-TxImportDialog::TxImportDialog(QWidget *parent, QSharedPointer<AppContext> ctx)
+TxImportDialog::TxImportDialog(QWidget *parent, Wallet *wallet)
: WindowModalDialog(parent)
, ui(new Ui::TxImportDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
void TxImportDialog::onImport() {
QString txid = ui->line_txid->text();
- if (m_ctx->wallet->haveTransaction(txid)) {
+ if (m_wallet->haveTransaction(txid)) {
QMessageBox::warning(this, "Warning", "This transaction already exists in the wallet. "
"If you can't find it in your history, "
"check if it belongs to a different account (Wallet -> Account)");
return;
}
- if (m_ctx->wallet->importTransaction(txid)) {
- if (!m_ctx->wallet->haveTransaction(txid)) {
+ if (m_wallet->importTransaction(txid)) {
+ if (!m_wallet->haveTransaction(txid)) {
QMessageBox::warning(this, "Import transaction", "This transaction does not belong to this wallet.");
return;
}
} else {
QMessageBox::warning(this, "Import transaction", "Transaction import failed.");
}
- m_ctx->refreshModels();
+ m_wallet->refreshModels();
}
TxImportDialog::~TxImportDialog() = default;
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
#include "utils/daemonrpc.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class TxImportDialog;
Q_OBJECT
public:
- explicit TxImportDialog(QWidget *parent, QSharedPointer<AppContext> ctx);
+ explicit TxImportDialog(QWidget *parent, Wallet *wallet);
~TxImportDialog() override;
private slots:
private:
QScopedPointer<Ui::TxImportDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
};
#include <QMessageBox>
#include <QScrollBar>
-#include "appcontext.h"
#include "config.h"
#include "constants.h"
#include "libwalletqt/Coins.h"
#include "Utils.h"
#include "utils/Icons.h"
-TxInfoDialog::TxInfoDialog(QSharedPointer<AppContext> ctx, TransactionInfo *txInfo, QWidget *parent)
+TxInfoDialog::TxInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent)
: QDialog(parent)
, ui(new Ui::TxInfoDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
, m_txInfo(txInfo)
- , m_txProofDialog(new TxProofDialog(this, m_ctx, txInfo))
+ , m_txProofDialog(new TxProofDialog(this, wallet, txInfo))
{
ui->setupUi(this);
connect(ui->btn_CopyTxKey, &QPushButton::clicked, this, &TxInfoDialog::copyTxKey);
connect(ui->btn_createTxProof, &QPushButton::clicked, this, &TxInfoDialog::createTxProof);
- connect(m_ctx->wallet, &Wallet::newBlock, this, &TxInfoDialog::updateData);
+ connect(m_wallet, &Wallet::newBlock, this, &TxInfoDialog::updateData);
this->setData(txInfo);
for (const auto& transfer : transfers) {
auto address = transfer->address();
auto amount = WalletManager::displayAmount(transfer->amount());
- auto index = m_ctx->wallet->subaddressIndex(address);
+ auto index = m_wallet->subaddressIndex(address);
cursor.insertText(address, Utils::addressTextFormat(index, transfer->amount()));
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
cursor.insertBlock();
}
void TxInfoDialog::updateData() {
- TransactionInfo *tx = m_ctx->wallet->history()->transaction(m_txid);
+ TransactionInfo *tx = m_wallet->history()->transaction(m_txid);
if (!tx) return;
this->setData(tx);
}
}
void TxInfoDialog::copyTxKey() {
- if (m_ctx->wallet->isHwBacked()) {
+ if (m_wallet->isHwBacked()) {
QMessageBox::warning(this, "Unable to get tx private key", "Unable to get tx secret key: wallet is backed by hardware device");
return;
}
- m_ctx->wallet->getTxKeyAsync(m_txid, [this](QVariantMap map){
+ m_wallet->getTxKeyAsync(m_txid, [this](QVariantMap map){
QString txKey = map.value("tx_key").toString();
if (txKey.isEmpty()) {
QMessageBox::warning(this, "Unable to copy transaction key", "Transaction key unknown");
#include <QTextEdit>
#include <QSvgWidget>
-#include "appcontext.h"
#include "dialog/TxProofDialog.h"
namespace Ui {
Q_OBJECT
public:
- explicit TxInfoDialog(QSharedPointer<AppContext> ctx, TransactionInfo *txInfo, QWidget *parent = nullptr);
+ explicit TxInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
~TxInfoDialog() override;
signals:
void viewOnBlockExplorer();
QScopedPointer<Ui::TxInfoDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
TransactionInfo *m_txInfo;
TxProofDialog *m_txProofDialog;
QString m_txid;
#include "utils/Icons.h"
#include "utils/Utils.h"
-TxProofDialog::TxProofDialog(QWidget *parent, QSharedPointer<AppContext> ctx, TransactionInfo *txInfo)
+TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txInfo)
: WindowModalDialog(parent)
, ui(new Ui::TxProofDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
}
for (auto const &s: txInfo->subaddrIndex()) {
- m_InDestinations.push_back(m_ctx->wallet->address(txInfo->subaddrAccount(), s));
+ m_InDestinations.push_back(m_wallet->address(txInfo->subaddrAccount(), s));
}
// Due to some logic in core we can't create OutProofs
void TxProofDialog::getTxKey() {
if (!m_txKey.isEmpty()) return;
- m_ctx->wallet->getTxKeyAsync(m_txid, [this](QVariantMap map){
+ m_wallet->getTxKeyAsync(m_txid, [this](QVariantMap map){
m_txKey = map.value("tx_key").toString();
});
}
return;
}
- if (m_ctx->wallet->isHwBacked()) {
+ if (m_wallet->isHwBacked()) {
this->showWarning("SpendProof creation is not supported on this hardware device.");
return;
}
void TxProofDialog::getFormattedProof() {
QString message = ui->message->toPlainText();
QString address = ui->combo_address->currentText();
- QString nettype = Utils::QtEnumToString(m_ctx->wallet->nettype()).toLower();
+ QString nettype = Utils::QtEnumToString(m_wallet->nettype()).toLower();
nettype = nettype.replace(0, 1, nettype[0].toUpper()); // Capitalize first letter
TxProof proof = this->getProof();
TxProof proof = [this, message, address]{
switch (m_mode) {
case Mode::SpendProof: {
- return m_ctx->wallet->getSpendProof(m_txid, message);
+ return m_wallet->getSpendProof(m_txid, message);
}
case Mode::OutProof:
case Mode::InProof:
default: { // Todo: split this into separate functions
- return m_ctx->wallet->getTxProof(m_txid, address, message);
+ return m_wallet->getTxProof(m_txid, address, message);
}
}
}();
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
#include "libwalletqt/TransactionInfo.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class TxProofDialog;
Q_OBJECT
public:
- explicit TxProofDialog(QWidget *parent, QSharedPointer<AppContext> ctx, TransactionInfo *txid);
+ explicit TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txid);
~TxProofDialog() override;
void setTxId(const QString &txid);
void getTxKey();
void showWarning(const QString &message);
QScopedPointer<Ui::TxProofDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
QStringList m_OutDestinations;
QStringList m_InDestinations;
#include <QInputDialog>
#include <QMessageBox>
-ViewOnlyDialog::ViewOnlyDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
+#include "utils/Utils.h"
+
+ViewOnlyDialog::ViewOnlyDialog(Wallet *wallet, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::ViewOnlyDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
- ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight()));
- ui->label_primaryAddress->setText(m_ctx->wallet->address(0, 0));
- ui->label_secretViewKey->setText(m_ctx->wallet->getSecretViewKey());
+ ui->label_restoreHeight->setText(QString::number(m_wallet->getWalletCreationHeight()));
+ ui->label_primaryAddress->setText(m_wallet->address(0, 0));
+ ui->label_secretViewKey->setText(m_wallet->getSecretViewKey());
connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboard);
connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet);
- if (m_ctx->wallet->viewOnly()) {
+ if (m_wallet->viewOnly()) {
ui->btn_Save->setEnabled(false);
ui->btn_Save->setToolTip("Wallet is already view-only");
}
if((bool)passwordDialog.exec())
passwd = passwordDialog.textValue();
- m_ctx->wallet->createViewOnly(fn, passwd);
+ m_wallet->createViewOnly(fn, passwd);
QMessageBox::information(this, "Information", "View-only wallet successfully written to disk.");
}
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class ViewOnlyDialog;
Q_OBJECT
public:
- explicit ViewOnlyDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit ViewOnlyDialog(Wallet *wallet, QWidget *parent = nullptr);
~ViewOnlyDialog() override;
private slots:
void copyToClipboard();
QScopedPointer<Ui::ViewOnlyDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
};
#include "model/ModelUtils.h"
-WalletCacheDebugDialog::WalletCacheDebugDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
+WalletCacheDebugDialog::WalletCacheDebugDialog(Wallet *wallet, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::WalletCacheDebugDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
ui->output->setFont(ModelUtils::getMonospaceFont());
connect(ui->m_blockchain, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printBlockchain());
+ this->setOutput(m_wallet->printBlockchain());
});
connect(ui->m_transfers, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printTransfers());
+ this->setOutput(m_wallet->printTransfers());
});
connect(ui->m_unconfirmed_payments, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printUnconfirmedPayments());
+ this->setOutput(m_wallet->printUnconfirmedPayments());
});
connect(ui->m_confirmed_txs, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printConfirmedTransferDetails());
+ this->setOutput(m_wallet->printConfirmedTransferDetails());
});
connect(ui->m_unconfirmed_txs, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printUnconfirmedTransferDetails());
+ this->setOutput(m_wallet->printUnconfirmedTransferDetails());
});
connect(ui->m_payments, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printPayments());
+ this->setOutput(m_wallet->printPayments());
});
connect(ui->m_pub_keys, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printPubKeys());
+ this->setOutput(m_wallet->printPubKeys());
});
connect(ui->m_tx_notes, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printTxNotes());
+ this->setOutput(m_wallet->printTxNotes());
});
connect(ui->m_subaddresses, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printSubaddresses());
+ this->setOutput(m_wallet->printSubaddresses());
});
connect(ui->m_subaddress_labels, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printSubaddressLabels());
+ this->setOutput(m_wallet->printSubaddressLabels());
});
connect(ui->m_additional_tx_keys, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printAdditionalTxKeys());
+ this->setOutput(m_wallet->printAdditionalTxKeys());
});
connect(ui->m_attributes, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printAttributes());
+ this->setOutput(m_wallet->printAttributes());
});
connect(ui->m_key_images, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printKeyImages());
+ this->setOutput(m_wallet->printKeyImages());
});
connect(ui->m_account_tags, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printAccountTags());
+ this->setOutput(m_wallet->printAccountTags());
});
connect(ui->m_tx_keys, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printTxKeys());
+ this->setOutput(m_wallet->printTxKeys());
});
connect(ui->m_address_book, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printAddressBook());
+ this->setOutput(m_wallet->printAddressBook());
});
connect(ui->m_scanned_pool_txs, &QRadioButton::pressed, [this]{
- this->setOutput(m_ctx->wallet->printScannedPoolTxs());
+ this->setOutput(m_wallet->printScannedPoolTxs());
});
this->adjustSize();
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class WalletCacheDebugDialog;
Q_OBJECT
public:
- explicit WalletCacheDebugDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit WalletCacheDebugDialog(Wallet *wallet, QWidget *parent = nullptr);
~WalletCacheDebugDialog() override;
private:
void setOutput(const QString &output);
QScopedPointer<Ui::WalletCacheDebugDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
};
#include <QDesktopServices>
-WalletInfoDialog::WalletInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
+#include "utils/Utils.h"
+
+WalletInfoDialog::WalletInfoDialog(Wallet *wallet, QWidget *parent)
: WindowModalDialog(parent)
, ui(new Ui::WalletInfoDialog)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
- QFileInfo cache(m_ctx->wallet->cachePath());
+ QFileInfo cache(m_wallet->cachePath());
- ui->label_walletName->setText(QFileInfo(m_ctx->wallet->cachePath()).fileName());
- ui->label_netType->setText(Utils::QtEnumToString(m_ctx->wallet->nettype()));
- ui->label_seedType->setText(QString("%1 word").arg(m_ctx->wallet->seedLength()));
- ui->label_viewOnly->setText(m_ctx->wallet->viewOnly() ? "True" : "False");
- ui->label_subaddressLookahead->setText(m_ctx->wallet->getSubaddressLookahead());
- ui->label_keysFile->setText(m_ctx->wallet->keysPath());
- ui->label_cacheFile->setText(m_ctx->wallet->cachePath());
+ ui->label_walletName->setText(QFileInfo(m_wallet->cachePath()).fileName());
+ ui->label_netType->setText(Utils::QtEnumToString(m_wallet->nettype()));
+ ui->label_seedType->setText(QString("%1 word").arg(m_wallet->seedLength()));
+ ui->label_viewOnly->setText(m_wallet->viewOnly() ? "True" : "False");
+ ui->label_subaddressLookahead->setText(m_wallet->getSubaddressLookahead());
+ ui->label_keysFile->setText(m_wallet->keysPath());
+ ui->label_cacheFile->setText(m_wallet->cachePath());
ui->label_cacheSize->setText(QString("%1 MB").arg(QString::number(cache.size() / 1e6, 'f', 2)));
connect(ui->btn_openWalletDir, &QPushButton::clicked, this, &WalletInfoDialog::openWalletDir);
}
void WalletInfoDialog::openWalletDir() {
- QFileInfo file(m_ctx->wallet->keysPath());
+ QFileInfo file(m_wallet->keysPath());
QDesktopServices::openUrl(QUrl::fromLocalFile(file.absolutePath()));
}
#include <QDialog>
-#include "appcontext.h"
#include "components.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class WalletInfoDialog;
Q_OBJECT
public:
- explicit WalletInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit WalletInfoDialog(Wallet *wallet, QWidget *parent = nullptr);
~WalletInfoDialog() override;
private:
void openWalletDir();
QScopedPointer<Ui::WalletInfoDialog> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
};
#endif //FEATHER_WALLETINFODIALOG_H
#include <chrono>
#include <thread>
-#include "TransactionHistory.h"
#include "AddressBook.h"
+#include "Coins.h"
#include "Subaddress.h"
#include "SubaddressAccount.h"
-#include "Coins.h"
+#include "TransactionHistory.h"
+#include "WalletManager.h"
+
+#include "config.h"
+#include "constants.h"
+
#include "model/TransactionHistoryModel.h"
#include "model/TransactionHistoryProxyModel.h"
#include "model/AddressBookModel.h"
#include "utils/ScopeGuard.h"
namespace {
- static constexpr char ATTRIBUTE_SUBADDRESS_ACCOUNT[] = "feather.subaddress_account";
+ constexpr char ATTRIBUTE_SUBADDRESS_ACCOUNT[] = "feather.subaddress_account";
}
-Wallet::Wallet(QObject * parent)
- : Wallet(nullptr, parent)
-{
-}
-
-Wallet::ConnectionStatus Wallet::connectionStatus() const
+Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
+ : QObject(parent)
+ , m_walletImpl(wallet)
+ , m_history(new TransactionHistory(m_walletImpl->history(), this))
+ , m_historyModel(nullptr)
+ , m_addressBook(new AddressBook(m_walletImpl->addressBook(), this))
+ , m_addressBookModel(nullptr)
+ , m_daemonBlockChainHeight(0)
+ , m_daemonBlockChainTargetHeight(0)
+ , m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
+ , m_currentSubaddressAccount(0)
+ , m_subaddress(new Subaddress(m_walletImpl->subaddress(), this))
+ , m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this))
+ , m_refreshNow(false)
+ , m_refreshEnabled(false)
+ , m_scheduler(this)
+ , m_useSSL(true)
+ , m_coins(new Coins(m_walletImpl->coins(), this))
+ , m_storeTimer(new QTimer(this))
{
- return m_connectionStatus;
-}
+ m_walletListener = new WalletListenerImpl(this);
+ m_walletImpl->setListener(m_walletListener);
+ m_currentSubaddressAccount = getCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT).toUInt();
-QString Wallet::getSeed(const QString &seedOffset) const
-{
- return QString::fromStdString(m_walletImpl->seed(seedOffset.toStdString()));
-}
+ m_addressBookModel = new AddressBookModel(this, m_addressBook);
+ m_subaddressModel = new SubaddressModel(this, m_subaddress);
+ m_subaddressAccountModel = new SubaddressAccountModel(this, m_subaddressAccount);
+ m_coinsModel = new CoinsModel(this, m_coins);
-qsizetype Wallet::seedLength() const
-{
- auto seedLength = this->getCacheAttribute("feather.seed").split(" ", Qt::SkipEmptyParts).length();
- return seedLength ? seedLength : 25;
-}
+ if (this->status() == Status_Ok) {
+ startRefreshThread();
-QString Wallet::getSeedLanguage() const
-{
- return QString::fromStdString(m_walletImpl->getSeedLanguage());
-}
+ // Store the wallet every 2 minutes
+ m_storeTimer->start(2 * 60 * 1000);
+ connect(m_storeTimer, &QTimer::timeout, [this](){
+ this->storeSafer();
+ });
-void Wallet::setSeedLanguage(const QString &lang)
-{
- m_walletImpl->setSeedLanguage(lang.toStdString());
-}
+ this->updateBalance();
+ }
-Wallet::Status Wallet::status() const
-{
- return static_cast<Status>(m_walletImpl->status());
-}
+ connect(this->history(), &TransactionHistory::txNoteChanged, [this]{
+ this->history()->refresh(this->currentSubaddressAccount());
+ });
-NetworkType::Type Wallet::nettype() const
-{
- return static_cast<NetworkType::Type>(m_walletImpl->nettype());
+ connect(this, &Wallet::createTransactionError, this, &Wallet::onCreateTransactionError);
+ connect(this, &Wallet::refreshed, this, &Wallet::onRefreshed);
+ connect(this, &Wallet::newBlock, this, &Wallet::onNewBlock);
+ connect(this, &Wallet::updated, this, &Wallet::onUpdated);
+ connect(this, &Wallet::heightsRefreshed, this, &Wallet::onHeightsRefreshed);
+ connect(this, &Wallet::transactionCreated, this, &Wallet::onTransactionCreated);
}
-bool Wallet::disconnected() const
-{
- return m_disconnected;
-}
+// #################### Status ####################
-bool Wallet::refreshing() const
-{
- return m_refreshing;
+Wallet::Status Wallet::status() const {
+ return static_cast<Status>(m_walletImpl->status());
}
-void Wallet::refreshingSet(bool value)
-{
- if (m_refreshing.exchange(value) != value)
- {
- emit refreshingChanged();
- }
+Wallet::ConnectionStatus Wallet::connectionStatus() const {
+ return m_connectionStatus;
}
-void Wallet::setConnectionStatus(ConnectionStatus value)
-{
- if (m_connectionStatus == value)
- {
+void Wallet::setConnectionStatus(ConnectionStatus value) {
+ if (m_connectionStatus == value) {
return;
}
m_connectionStatus = value;
emit connectionStatusChanged(m_connectionStatus);
+}
- bool disconnected = m_connectionStatus == Wallet::ConnectionStatus_Connecting ||
- m_connectionStatus == Wallet::ConnectionStatus_Disconnected;
+bool Wallet::isSynchronized() const {
+ return connectionStatus() == ConnectionStatus_Synchronized;
+}
- if (m_disconnected != disconnected)
- {
- m_disconnected = disconnected;
- emit disconnectedChanged();
- }
+bool Wallet::isConnected() const {
+ auto status = connectionStatus();
+ return status == ConnectionStatus_Synchronizing || status == ConnectionStatus_Synchronized;
}
-void Wallet::onNewBlock(uint64_t walletHeight) {
- // Called whenever a new block gets scanned by the wallet
- quint64 daemonHeight = m_daemonBlockChainTargetHeight;
+QString Wallet::errorString() const {
+ return QString::fromStdString(m_walletImpl->errorString());
+}
- if (walletHeight < (daemonHeight - 1)) {
- setConnectionStatus(ConnectionStatus_Synchronizing);
- } else {
- setConnectionStatus(ConnectionStatus_Synchronized);
- }
+NetworkType::Type Wallet::nettype() const {
+ return static_cast<NetworkType::Type>(m_walletImpl->nettype());
}
-QString Wallet::getProxyAddress() const
-{
- QMutexLocker locker(&m_proxyMutex);
- return m_proxyAddress;
+bool Wallet::viewOnly() const {
+ return m_walletImpl->watchOnly();
}
-void Wallet::setProxyAddress(QString address)
-{
- m_scheduler.run([this, address] {
- {
- QMutexLocker locker(&m_proxyMutex);
+bool Wallet::isDeterministic() const {
+ return m_walletImpl->isDeterministic();
+}
- if (!m_walletImpl->setProxy(address.toStdString()))
- {
- qCritical() << "failed to set proxy" << address;
- }
+// #################### Balance ####################
- m_proxyAddress = address;
- }
- emit proxyAddressChanged();
- });
+quint64 Wallet::balance() const {
+ return balance(m_currentSubaddressAccount);
}
-bool Wallet::synchronized() const
-{
- // Misleading: this will return true if wallet has synchronized at least once even if it isn't currently synchronized
- return m_walletImpl->synchronized();
+quint64 Wallet::balance(quint32 accountIndex) const {
+ return m_walletImpl->balance(accountIndex);
}
-bool Wallet::isSynchronized() const
-{
- return connectionStatus() == ConnectionStatus_Synchronized;
+quint64 Wallet::balanceAll() const {
+ return m_walletImpl->balanceAll();
}
-bool Wallet::isConnected() const
-{
- auto status = connectionStatus();
- return status == ConnectionStatus_Synchronizing || status == ConnectionStatus_Synchronized;
+quint64 Wallet::unlockedBalance() const {
+ return unlockedBalance(m_currentSubaddressAccount);
}
-void Wallet::setOffline(bool offline) const
-{
- return m_walletImpl->setOffline(offline);
+quint64 Wallet::unlockedBalance(quint32 accountIndex) const {
+ return m_walletImpl->unlockedBalance(accountIndex);
}
-QString Wallet::errorString() const
-{
- return QString::fromStdString(m_walletImpl->errorString());
+quint64 Wallet::unlockedBalanceAll() const {
+ return m_walletImpl->unlockedBalanceAll();
}
-bool Wallet::setPassword(const QString &oldPassword, const QString &newPassword)
-{
- return m_walletImpl->setPassword(oldPassword.toStdString(), newPassword.toStdString());
-}
+void Wallet::updateBalance() {
+ quint64 balance = this->balance();
+ quint64 spendable = this->unlockedBalance();
-bool Wallet::verifyPassword(const QString &password)
-{
- return m_walletImpl->verifyPassword(password.toStdString());
+ emit balanceUpdated(balance, spendable);
}
-QString Wallet::address(quint32 accountIndex, quint32 addressIndex) const
-{
+// #################### Subaddresses and Accounts ####################
+
+QString Wallet::address(quint32 accountIndex, quint32 addressIndex) const {
return QString::fromStdString(m_walletImpl->address(accountIndex, addressIndex));
}
-SubaddressIndex Wallet::subaddressIndex(const QString &address) const
-{
+SubaddressIndex Wallet::subaddressIndex(const QString &address) const {
std::pair<uint32_t, uint32_t> i;
if (!m_walletImpl->subaddressIndex(address.toStdString(), i)) {
return SubaddressIndex(-1, -1);
return SubaddressIndex(i.first, i.second);
}
-QString Wallet::cachePath() const
-{
- return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->filename()));
+quint32 Wallet::currentSubaddressAccount() const {
+ return m_currentSubaddressAccount;
}
-QString Wallet::keysPath() const
-{
- return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->keysFilename()));;
+void Wallet::switchSubaddressAccount(quint32 accountIndex) {
+ if (accountIndex < numSubaddressAccounts())
+ {
+ m_currentSubaddressAccount = accountIndex;
+ if (!setCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT, QString::number(m_currentSubaddressAccount)))
+ {
+ qWarning() << "failed to set " << ATTRIBUTE_SUBADDRESS_ACCOUNT << " cache attribute";
+ }
+ m_subaddress->refresh(m_currentSubaddressAccount);
+ m_history->refresh(m_currentSubaddressAccount);
+ m_coins->refresh(m_currentSubaddressAccount);
+ this->subaddressModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount);
+ this->coinsModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount);
+ this->updateBalance();
+ emit currentSubaddressAccountChanged();
+ }
+}
+void Wallet::addSubaddressAccount(const QString& label) {
+ m_walletImpl->addSubaddressAccount(label.toStdString());
+ switchSubaddressAccount(numSubaddressAccounts() - 1);
+}
+
+quint32 Wallet::numSubaddressAccounts() const {
+ return m_walletImpl->numSubaddressAccounts();
+}
+
+quint32 Wallet::numSubaddresses(quint32 accountIndex) const {
+ return m_walletImpl->numSubaddresses(accountIndex);
+}
+
+void Wallet::addSubaddress(const QString& label) {
+ m_walletImpl->addSubaddress(currentSubaddressAccount(), label.toStdString());
+}
+
+QString Wallet::getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const {
+ return QString::fromStdString(m_walletImpl->getSubaddressLabel(accountIndex, addressIndex));
+}
+
+void Wallet::setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label) {
+ m_walletImpl->setSubaddressLabel(accountIndex, addressIndex, label.toStdString());
+}
+
+void Wallet::deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId) {
+ m_scheduler.run([this, accountIndex, addressIndex, paymentId] {
+ m_walletImpl->deviceShowAddress(accountIndex, addressIndex, paymentId.toStdString());
+ emit deviceShowAddressShowed();
+ });
+}
+
+QString Wallet::getSubaddressLookahead() const {
+ auto lookahead = m_walletImpl->getSubaddressLookahead();
+
+ return QString("%1:%2").arg(QString::number(lookahead.first), QString::number(lookahead.second));
}
-void Wallet::store()
+// #################### Seed ####################
+
+QString Wallet::getSeed(const QString &seedOffset) const {
+ return QString::fromStdString(m_walletImpl->seed(seedOffset.toStdString()));
+}
+
+qsizetype Wallet::seedLength() const {
+ auto seedLength = this->getCacheAttribute("feather.seed").split(" ", Qt::SkipEmptyParts).length();
+ return seedLength ? seedLength : 25;
+}
+
+QString Wallet::getSeedLanguage() const
{
- m_walletImpl->store();
+ return QString::fromStdString(m_walletImpl->getSeedLanguage());
}
-bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight, const QString& proxyAddress)
+void Wallet::setSeedLanguage(const QString &lang)
{
- qDebug() << "init non async";
- if (isRecovering){
- qDebug() << "RESTORING";
- m_walletImpl->setRecoveringFromSeed(true);
- }
- if (isRecoveringFromDevice){
- qDebug() << "RESTORING FROM DEVICE";
- m_walletImpl->setRecoveringFromDevice(true);
- }
- if (isRecovering || isRecoveringFromDevice) {
- m_walletImpl->setRefreshFromBlockHeight(restoreHeight);
- }
+ m_walletImpl->setSeedLanguage(lang.toStdString());
+}
- {
- QMutexLocker locker(&m_proxyMutex);
+// #################### Node connection ####################
- if (!m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), m_useSSL, false, proxyAddress.toStdString()))
- {
- return false;
- }
+void Wallet::setOffline(bool offline) const {
+ return m_walletImpl->setOffline(offline);
+}
- m_proxyAddress = proxyAddress;
- }
- emit proxyAddressChanged();
+void Wallet::setTrustedDaemon(bool arg) {
+ m_walletImpl->setTrustedDaemon(arg);
+}
- setTrustedDaemon(trustedDaemon);
- return true;
+void Wallet::setUseSSL(bool ssl) {
+ m_useSSL = ssl;
}
-void Wallet::setDaemonLogin(const QString &daemonUsername, const QString &daemonPassword)
-{
- // store daemon login
+void Wallet::setDaemonLogin(const QString &daemonUsername, const QString &daemonPassword) {
m_daemonUsername = daemonUsername;
m_daemonPassword = daemonPassword;
}
-void Wallet::initAsync(
- const QString &daemonAddress,
- bool trustedDaemon /* = false */,
- quint64 upperTransactionLimit /* = 0 */,
- bool isRecovering /* = false */,
- bool isRecoveringFromDevice /* = false */,
- quint64 restoreHeight /* = 0 */,
- const QString &proxyAddress /* = "" */)
+void Wallet::initAsync(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, const QString &proxyAddress)
{
qDebug() << "initAsync: " + daemonAddress;
- const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress] {
- bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress);
- if (success)
+ const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, proxyAddress] {
+ // Beware! This code does not run in the GUI thread.
+
+ bool success;
{
- emit walletCreationHeightChanged();
+ QMutexLocker locker(&m_proxyMutex);
+ success = m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), m_useSSL, false, proxyAddress.toStdString());
+ }
+
+ setTrustedDaemon(trustedDaemon);
+
+ if (success) {
qDebug() << "init async finished - starting refresh";
startRefresh();
}
}
}
-bool Wallet::setDaemon(const QString &daemonAddress)
-{
- qDebug() << "setDaemon: " + daemonAddress;
- return m_walletImpl->setDaemon(daemonAddress.toStdString(), m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), m_useSSL);
-}
+// #################### Synchronization (Refresh) ####################
+
+void Wallet::startRefresh() {
+ m_refreshEnabled = true;
+ m_refreshNow = true;
+}
+
+void Wallet::pauseRefresh() {
+ m_refreshEnabled = false;
+}
+
+void Wallet::startRefreshThread()
+{
+ const auto future = m_scheduler.run([this] {
+ // Beware! This code does not run in the GUI thread.
+
+ constexpr const std::chrono::seconds refreshInterval{10};
+ constexpr const std::chrono::milliseconds intervalResolution{100};
+
+ auto last = std::chrono::steady_clock::now();
+ while (!m_scheduler.stopping())
+ {
+ if (m_refreshEnabled && (!isHwBacked() || isDeviceConnected()))
+ {
+ const auto now = std::chrono::steady_clock::now();
+ const auto elapsed = now - last;
+ if (elapsed >= refreshInterval || m_refreshNow)
+ {
+ m_refreshNow = false;
+
+ // get daemonHeight and targetHeight
+ // daemonHeight and targetHeight will be 0 if call to get_info fails
+ quint64 daemonHeight = m_walletImpl->daemonBlockChainHeight();
+ bool success = daemonHeight > 0;
+
+ quint64 targetHeight = 0;
+ if (success) {
+ targetHeight = m_walletImpl->daemonBlockChainTargetHeight();
+ }
+ bool haveHeights = (daemonHeight > 0 && targetHeight > 0);
+
+ emit heightsRefreshed(haveHeights, daemonHeight, targetHeight);
+
+ // Don't call refresh function if we don't have the daemon and target height
+ // We do this to prevent to UI from getting confused about the amount of blocks that are still remaining
+ if (haveHeights) {
+ QMutexLocker locker(&m_asyncMutex);
+
+ if (m_newWallet) {
+ // Set blockheight to daemonHeight for newly created wallets to speed up initial sync
+ m_walletImpl->setRefreshFromBlockHeight(daemonHeight);
+ m_newWallet = false;
+ }
+
+ m_walletImpl->refresh();
+ }
+ last = std::chrono::steady_clock::now();
+ }
+ }
+
+ std::this_thread::sleep_for(intervalResolution);
+ }
+ });
+ if (!future.first)
+ {
+ throw std::runtime_error("failed to start auto refresh thread");
+ }
+}
+
+void Wallet::onHeightsRefreshed(bool success, quint64 daemonHeight, quint64 targetHeight) {
+ m_daemonBlockChainHeight = daemonHeight;
+ m_daemonBlockChainTargetHeight = targetHeight;
+
+ if (success) {
+ quint64 walletHeight = blockChainHeight();
+
+ if (this->connectionStatus() != Wallet::ConnectionStatus_Disconnected) {
+ if (daemonHeight < targetHeight) {
+ emit blockchainSync(daemonHeight, targetHeight);
+ }
+ else {
+ this->syncStatusUpdated(walletHeight, daemonHeight);
+ }
+ }
+
+ if (walletHeight < (daemonHeight - 1)) {
+ setConnectionStatus(ConnectionStatus_Synchronizing);
+ } else {
+ setConnectionStatus(ConnectionStatus_Synchronized);
+ }
+ } else {
+ setConnectionStatus(ConnectionStatus_Disconnected);
+ }
+}
+
+quint64 Wallet::blockChainHeight() const {
+ // Can not block UI
+ return m_walletImpl->blockChainHeight();
+}
+
+quint64 Wallet::daemonBlockChainHeight() const {
+ return m_daemonBlockChainHeight;
+}
+
+quint64 Wallet::daemonBlockChainTargetHeight() const {
+ return m_daemonBlockChainTargetHeight;
+}
+
+void Wallet::syncStatusUpdated(quint64 height, quint64 target) {
+ if (height < (target - 1)) {
+ emit refreshSync(height, target);
+ }
+ else {
+ this->updateBalance();
+ emit synchronized();
+ }
+}
+
+void Wallet::onNewBlock(uint64_t walletHeight) {
+ // Called whenever a new block gets scanned by the wallet
+ quint64 daemonHeight = m_daemonBlockChainTargetHeight;
+
+ if (walletHeight < (daemonHeight - 1)) {
+ setConnectionStatus(ConnectionStatus_Synchronizing);
+ } else {
+ setConnectionStatus(ConnectionStatus_Synchronized);
+ }
+
+ this->syncStatusUpdated(walletHeight, daemonHeight);
+
+ if (this->isSynchronized()) {
+ this->coins()->refreshUnlocked();
+ this->history()->refresh(this->currentSubaddressAccount());
+ // Todo: only refresh tx confirmations
+ }
+}
+
+void Wallet::onUpdated() {
+ if (m_walletImpl->synchronized()) {
+ this->refreshModels();
+ this->storeSafer();
+ }
+
+ this->updateBalance();
+}
+
+void Wallet::onRefreshed(bool success, const QString &message) {
+ qDebug() << "onRefreshed";
+
+ if (!success) {
+ setConnectionStatus(ConnectionStatus_Disconnected);
+ // Something went wrong during refresh, in some cases we need to notify the user
+ qCritical() << "Exception during refresh: " << message; // Can't use ->errorString() here, other SLOT might snipe it first
+ return;
+ }
+
+ if (!this->refreshedOnce) {
+ this->refreshModels();
+ this->refreshedOnce = true;
+ emit walletRefreshed();
+ // store wallet immediately upon finishing synchronization
+ this->storeSafer();
+ }
+}
+
+void Wallet::refreshModels() {
+ m_history->refresh(this->currentSubaddressAccount());
+ m_coins->refresh(this->currentSubaddressAccount());
+ bool r = this->subaddress()->refresh(this->currentSubaddressAccount());
+
+ if (!r) {
+ // This should only happen if wallet keys got corrupted or were tampered with
+ // The list of subaddresses is wiped to prevent loss of funds
+ // Notify MainWindow to display an error message
+ emit keysCorrupted();
+ }
+}
+
+// #################### Hardware wallet ####################
-bool Wallet::isHwBacked() const
-{
+bool Wallet::isHwBacked() const {
return m_walletImpl->getDeviceType() != Monero::Wallet::Device_Software;
}
-bool Wallet::isLedger() const
-{
+bool Wallet::isLedger() const {
return m_walletImpl->getDeviceType() == Monero::Wallet::Device_Ledger;
}
-bool Wallet::isTrezor() const
-{
+bool Wallet::isTrezor() const {
return m_walletImpl->getDeviceType() == Monero::Wallet::Device_Trezor;
}
-bool Wallet::reconnectDevice()
-{
- return m_walletImpl->reconnectDevice();
-}
-
-//! create a view only wallet
-bool Wallet::createViewOnly(const QString &path, const QString &password) const
-{
- // Create path
- QDir d = QFileInfo(path).absoluteDir();
- d.mkpath(d.absolutePath());
- return m_walletImpl->createWatchOnly(path.toStdString(),password.toStdString(),m_walletImpl->getSeedLanguage());
+bool Wallet::isDeviceConnected() const {
+ return m_walletImpl->isDeviceConnected();
}
-bool Wallet::connectToDaemon()
-{
- return m_walletImpl->connectToDaemon();
+bool Wallet::reconnectDevice() {
+ return m_walletImpl->reconnectDevice();
}
-void Wallet::setTrustedDaemon(bool arg)
-{
- m_walletImpl->setTrustedDaemon(arg);
+void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) {
+ if (m_walletListener != nullptr) {
+ m_walletListener->onPassphraseEntered(passphrase, enter_on_device, entry_abort);
+ }
}
-void Wallet::setUseSSL(bool ssl)
-{
- m_useSSL = ssl;
+void Wallet::onWalletPassphraseNeeded(bool on_device) {
+ emit this->walletPassphraseNeeded(on_device);
}
-bool Wallet::viewOnly() const
-{
- return m_walletImpl->watchOnly();
-}
+// #################### Import / Export ####################
-bool Wallet::isDeterministic() const
-{
- return m_walletImpl->isDeterministic();
+bool Wallet::exportKeyImages(const QString& path, bool all) {
+ return m_walletImpl->exportKeyImages(path.toStdString(), all);
}
-quint64 Wallet::balance() const
-{
- return balance(m_currentSubaddressAccount);
+bool Wallet::importKeyImages(const QString& path) {
+ return m_walletImpl->importKeyImages(path.toStdString());
}
-quint64 Wallet::balance(quint32 accountIndex) const
-{
- return m_walletImpl->balance(accountIndex);
+bool Wallet::exportOutputs(const QString& path, bool all) {
+ return m_walletImpl->exportOutputs(path.toStdString(), all);
}
-quint64 Wallet::balanceAll() const
-{
- return m_walletImpl->balanceAll();
+bool Wallet::importOutputs(const QString& path) {
+ return m_walletImpl->importOutputs(path.toStdString());
}
-quint64 Wallet::unlockedBalance() const
-{
- return unlockedBalance(m_currentSubaddressAccount);
+bool Wallet::importTransaction(const QString& txid) {
+ std::vector<std::string> txids = {txid.toStdString()};
+ return m_walletImpl->scanTransactions(txids);
}
-quint64 Wallet::unlockedBalance(quint32 accountIndex) const
-{
- return m_walletImpl->unlockedBalance(accountIndex);
-}
+// #################### Wallet cache ####################
-quint64 Wallet::unlockedBalanceAll() const
-{
- return m_walletImpl->unlockedBalanceAll();
+void Wallet::store() {
+ m_walletImpl->store();
}
-quint32 Wallet::currentSubaddressAccount() const
-{
- return m_currentSubaddressAccount;
-}
-void Wallet::switchSubaddressAccount(quint32 accountIndex)
-{
- if (accountIndex < numSubaddressAccounts())
- {
- m_currentSubaddressAccount = accountIndex;
- if (!setCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT, QString::number(m_currentSubaddressAccount)))
- {
- qWarning() << "failed to set " << ATTRIBUTE_SUBADDRESS_ACCOUNT << " cache attribute";
- }
- m_subaddress->refresh(m_currentSubaddressAccount);
- m_history->refresh(m_currentSubaddressAccount);
- m_coins->refresh(m_currentSubaddressAccount);
- this->subaddressModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount);
- this->coinsModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount);
- emit currentSubaddressAccountChanged();
+void Wallet::storeSafer() {
+ // Do not store a synchronizing wallet: store() is NOT thread safe and may crash the wallet
+ if (!this->isSynchronized()) {
+ return;
}
-}
-void Wallet::addSubaddressAccount(const QString& label)
-{
- m_walletImpl->addSubaddressAccount(label.toStdString());
- switchSubaddressAccount(numSubaddressAccounts() - 1);
-}
-quint32 Wallet::numSubaddressAccounts() const
-{
- return m_walletImpl->numSubaddressAccounts();
-}
-quint32 Wallet::numSubaddresses(quint32 accountIndex) const
-{
- return m_walletImpl->numSubaddresses(accountIndex);
-}
-void Wallet::addSubaddress(const QString& label)
-{
- m_walletImpl->addSubaddress(currentSubaddressAccount(), label.toStdString());
-}
-QString Wallet::getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const
-{
- return QString::fromStdString(m_walletImpl->getSubaddressLabel(accountIndex, addressIndex));
-}
-void Wallet::setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label)
-{
- m_walletImpl->setSubaddressLabel(accountIndex, addressIndex, label.toStdString());
- emit currentSubaddressAccountChanged();
-}
-void Wallet::deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId)
-{
- m_scheduler.run([this, accountIndex, addressIndex, paymentId] {
- m_walletImpl->deviceShowAddress(accountIndex, addressIndex, paymentId.toStdString());
- emit deviceShowAddressShowed();
- });
-}
-
-QString Wallet::getSubaddressLookahead() const
-{
- auto lookahead = m_walletImpl->getSubaddressLookahead();
- return QString("%1:%2").arg(QString::number(lookahead.first), QString::number(lookahead.second));
+ qDebug() << "Storing wallet";
+ this->store();
}
-bool Wallet::refreshHeights()
-{
- // daemonHeight and targetHeight will be 0 if call to get_info fails
-
- quint64 daemonHeight;
- QPair<bool, QFuture<void>> daemonHeightFuture = m_scheduler.run([this, &daemonHeight] {
- daemonHeight = m_walletImpl->daemonBlockChainHeight();;
- });
- if (!daemonHeightFuture.first)
- {
- return false;
- }
- // We must wait here for get_info to return, otherwise targetHeight will get cache value of 0
- daemonHeightFuture.second.waitForFinished();
- bool success = daemonHeight > 0;
-
- quint64 targetHeight = 0;
- if (success) {
- QPair<bool, QFuture<void>> targetHeightFuture = m_scheduler.run([this, &targetHeight] {
- targetHeight = m_walletImpl->daemonBlockChainTargetHeight();
- });
- if (!targetHeightFuture.first)
- {
- return false;
- }
- targetHeightFuture.second.waitForFinished();
- }
-
- m_daemonBlockChainHeight = daemonHeight;
- m_daemonBlockChainTargetHeight = targetHeight;
-
- success = (daemonHeight > 0 && targetHeight > 0);
-
- if (success) {
- quint64 walletHeight = blockChainHeight();
- emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
+QString Wallet::cachePath() const {
+ return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->filename()));
+}
- if (walletHeight < (daemonHeight - 1)) {
- setConnectionStatus(ConnectionStatus_Synchronizing);
- } else {
- setConnectionStatus(ConnectionStatus_Synchronized);
- }
- } else {
- setConnectionStatus(ConnectionStatus_Disconnected);
- }
+QString Wallet::keysPath() const {
+ return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->keysFilename()));;
+}
- return success;
+bool Wallet::setPassword(const QString &oldPassword, const QString &newPassword) {
+ return m_walletImpl->setPassword(oldPassword.toStdString(), newPassword.toStdString());
}
-quint64 Wallet::blockChainHeight() const
-{
- return m_walletImpl->blockChainHeight();
+bool Wallet::verifyPassword(const QString &password) {
+ return m_walletImpl->verifyPassword(password.toStdString());
}
-quint64 Wallet::daemonBlockChainHeight() const
-{
- // Can not block UI
- return m_daemonBlockChainHeight;
+bool Wallet::cacheAttributeExists(const QString &key) {
+ return m_walletImpl->cacheAttributeExists(key.toStdString());
}
-quint64 Wallet::daemonBlockChainTargetHeight() const
-{
- // Can not block UI
- return m_daemonBlockChainTargetHeight;
+bool Wallet::setCacheAttribute(const QString &key, const QString &val) {
+ return m_walletImpl->setCacheAttribute(key.toStdString(), val.toStdString());
}
-bool Wallet::exportKeyImages(const QString& path, bool all)
-{
- return m_walletImpl->exportKeyImages(path.toStdString(), all);
+QString Wallet::getCacheAttribute(const QString &key) const {
+ return QString::fromStdString(m_walletImpl->getCacheAttribute(key.toStdString()));
}
-bool Wallet::importKeyImages(const QString& path)
-{
- return m_walletImpl->importKeyImages(path.toStdString());
+void Wallet::addCacheTransaction(const QString &txid, const QString &txHex) {
+ this->setCacheAttribute(QString("tx:%1").arg(txid), txHex);
}
-bool Wallet::exportOutputs(const QString& path, bool all) {
- return m_walletImpl->exportOutputs(path.toStdString(), all);
+QString Wallet::getCacheTransaction(const QString &txid) const {
+ return this->getCacheAttribute(QString("tx:%1").arg(txid));
}
-bool Wallet::importOutputs(const QString& path) {
- return m_walletImpl->importOutputs(path.toStdString());
+bool Wallet::setUserNote(const QString &txid, const QString ¬e) {
+ return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString());
}
-bool Wallet::importTransaction(const QString& txid) {
- std::vector<std::string> txids = {txid.toStdString()};
- return m_walletImpl->scanTransactions(txids);
+QString Wallet::getUserNote(const QString &txid) const {
+ return QString::fromStdString(m_walletImpl->getUserNote(txid.toStdString()));
}
-QString Wallet::printBlockchain()
-{
+QString Wallet::printBlockchain() {
return QString::fromStdString(m_walletImpl->printBlockchain());
}
-QString Wallet::printTransfers()
-{
+QString Wallet::printTransfers() {
return QString::fromStdString(m_walletImpl->printTransfers());
}
-QString Wallet::printPayments()
-{
+QString Wallet::printPayments() {
return QString::fromStdString(m_walletImpl->printPayments());
}
-QString Wallet::printUnconfirmedPayments()
-{
+QString Wallet::printUnconfirmedPayments() {
return QString::fromStdString(m_walletImpl->printUnconfirmedPayments());
}
-QString Wallet::printConfirmedTransferDetails()
-{
+QString Wallet::printConfirmedTransferDetails() {
return QString::fromStdString(m_walletImpl->printConfirmedTransferDetails());
}
-QString Wallet::printUnconfirmedTransferDetails()
-{
+QString Wallet::printUnconfirmedTransferDetails() {
return QString::fromStdString(m_walletImpl->printUnconfirmedTransferDetails());
}
-QString Wallet::printPubKeys()
-{
+QString Wallet::printPubKeys() {
return QString::fromStdString(m_walletImpl->printPubKeys());
}
-QString Wallet::printTxNotes()
-{
+QString Wallet::printTxNotes() {
return QString::fromStdString(m_walletImpl->printTxNotes());
}
-QString Wallet::printSubaddresses()
-{
+QString Wallet::printSubaddresses() {
return QString::fromStdString(m_walletImpl->printSubaddresses());
}
-QString Wallet::printSubaddressLabels()
-{
+QString Wallet::printSubaddressLabels() {
return QString::fromStdString(m_walletImpl->printSubaddressLabels());
}
-QString Wallet::printAdditionalTxKeys()
-{
+QString Wallet::printAdditionalTxKeys() {
return QString::fromStdString(m_walletImpl->printAdditionalTxKeys());
}
-QString Wallet::printAttributes()
-{
+QString Wallet::printAttributes() {
return QString::fromStdString(m_walletImpl->printAttributes());
}
-QString Wallet::printKeyImages()
-{
+QString Wallet::printKeyImages() {
return QString::fromStdString(m_walletImpl->printKeyImages());
}
-QString Wallet::printAccountTags()
-{
+QString Wallet::printAccountTags() {
return QString::fromStdString(m_walletImpl->printAccountTags());
}
-QString Wallet::printTxKeys()
-{
+QString Wallet::printTxKeys() {
return QString::fromStdString(m_walletImpl->printTxKeys());
}
-QString Wallet::printAddressBook()
-{
+QString Wallet::printAddressBook() {
return QString::fromStdString(m_walletImpl->printAddressBook());
}
-QString Wallet::printScannedPoolTxs()
-{
+QString Wallet::printScannedPoolTxs() {
return QString::fromStdString(m_walletImpl->printScannedPoolTxs());
}
-bool Wallet::haveTransaction(const QString &txid)
-{
- return m_walletImpl->haveTransaction(txid.toStdString());
-}
+// #################### Transactions ####################
-void Wallet::startRefresh()
-{
- m_refreshEnabled = true;
- m_refreshNow = true;
-}
+// Phase 0: Pre-construction setup
-void Wallet::pauseRefresh()
-{
- m_refreshEnabled = false;
+void Wallet::setSelectedInputs(const QStringList &selectedInputs) {
+ m_selectedInputs.clear();
+ for (const auto &input : selectedInputs) {
+ m_selectedInputs.insert(input.toStdString());
+ }
+ emit selectedInputsChanged(selectedInputs);
}
-PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
- quint64 amount, quint32 mixin_count,
- PendingTransaction::Priority priority, const QStringList &preferredInputs)
-{
-// pauseRefresh();
- std::set<std::string> preferred_inputs;
- for (const auto &input : preferredInputs) {
- preferred_inputs.insert(input.toStdString());
+// Phase 1: Transaction creation
+// Pick one:
+// - createTransaction
+// - createTransactionMultiDest
+// - sweepOutputs
+
+void Wallet::createTransaction(const QString &address, quint64 amount, const QString &description, bool all) {
+ this->tmpTxDescription = description;
+
+ if (!all && amount == 0) {
+ emit createTransactionError("Cannot send nothing");
+ return;
}
- std::set<uint32_t> subaddr_indices;
- Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
- dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count,
- static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
- PendingTransaction * result = new PendingTransaction(ptImpl, nullptr);
+ quint64 unlocked_balance = this->unlockedBalance();
+ if (!all && amount > unlocked_balance) {
+ emit createTransactionError(QString("Not enough money to spend.\n\n"
+ "Spendable balance: %1").arg(WalletManager::displayAmount(unlocked_balance)));
+ return;
+ } else if (unlocked_balance == 0) {
+ emit createTransactionError("No money to spend");
+ return;
+ }
-// startRefresh();
- return result;
-}
+ qInfo() << "Creating transaction";
-void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id,
- quint64 amount, quint32 mixin_count,
- PendingTransaction::Priority priority, const QStringList &preferredInputs)
-{
- m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority, preferredInputs] {
- PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority, preferredInputs);
- QVector<QString> address {dst_addr};
- emit transactionCreated(tx, address);
+ m_scheduler.run([this, all, address, amount] {
+ std::set<uint32_t> subaddr_indices;
+
+ Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(address.toStdString(), "", all ? Monero::optional<uint64_t>() : Monero::optional<uint64_t>(amount), constants::mixin,
+ static_cast<Monero::PendingTransaction::Priority>(this->tx_priority),
+ currentSubaddressAccount(), subaddr_indices, m_selectedInputs);
+ PendingTransaction *tx = new PendingTransaction(ptImpl, this);
+
+ QVector<QString> addresses{address};
+ emit transactionCreated(tx, addresses);
});
+
+ emit initiateTransaction();
}
-PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
- PendingTransaction::Priority priority, const QStringList &preferredInputs)
-{
-// pauseRefresh();
+void Wallet::createTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description) {
+ this->tmpTxDescription = description;
- std::vector<std::string> dests;
- for (auto &addr : dst_addr) {
- dests.push_back(addr.toStdString());
+ quint64 total_amount = 0;
+ for (auto &amount : amounts) {
+ total_amount += amount;
}
- std::vector<uint64_t> amounts;
- for (auto &a : amount) {
- amounts.push_back(a);
+ auto unlocked_balance = this->unlockedBalance();
+ if (total_amount > unlocked_balance) {
+ emit createTransactionError("Not enough money to spend");
}
- std::set<std::string> preferred_inputs;
- for (const auto &input : preferredInputs) {
- preferred_inputs.insert(input.toStdString());
- }
+ qInfo() << "Creating transaction";
+ m_scheduler.run([this, addresses, amounts] {
+ std::vector<std::string> dests;
+ for (auto &addr : addresses) {
+ dests.push_back(addr.toStdString());
+ }
- // TODO: remove mixin count
- std::set<uint32_t> subaddr_indices;
- Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionMultDest(dests, "", amounts, 11, static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
- PendingTransaction * result = new PendingTransaction(ptImpl);
+ std::vector<uint64_t> amount;
+ for (auto &a : amounts) {
+ amount.push_back(a);
+ }
-// startRefresh();
- return result;
+ std::set<uint32_t> subaddr_indices;
+ Monero::PendingTransaction *ptImpl = m_walletImpl->createTransactionMultDest(dests, "", amount, constants::mixin,
+ static_cast<Monero::PendingTransaction::Priority>(this->tx_priority),
+ currentSubaddressAccount(), subaddr_indices, m_selectedInputs);
+ PendingTransaction *tx = new PendingTransaction(ptImpl);
+ emit transactionCreated(tx, addresses);
+ });
+
+ emit initiateTransaction();
}
-void Wallet::createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
- PendingTransaction::Priority priority, const QStringList &preferredInputs)
-{
- m_scheduler.run([this, dst_addr, amount, priority, preferredInputs] {
- PendingTransaction *tx = createTransactionMultiDest(dst_addr, amount, priority, preferredInputs);
- QVector<QString> addresses;
- for (auto &addr : dst_addr) {
- addresses.push_back(addr);
+void Wallet::sweepOutputs(const QVector<QString> &keyImages, QString address, bool churn, int outputs) {
+ if (churn) {
+ address = this->address(0, 0);
+ }
+
+ qInfo() << "Creating transaction";
+ m_scheduler.run([this, keyImages, address, outputs] {
+ std::vector<std::string> kis;
+ for (const auto &key_image : keyImages) {
+ kis.push_back(key_image.toStdString());
}
+ Monero::PendingTransaction *ptImpl = m_walletImpl->createTransactionSelected(kis, address.toStdString(), outputs, static_cast<Monero::PendingTransaction::Priority>(this->tx_priority));
+ PendingTransaction *tx = new PendingTransaction(ptImpl, this);
+
+ QVector<QString> addresses {address};
emit transactionCreated(tx, addresses);
});
+
+ emit initiateTransaction();
}
-PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const QString &payment_id,
- quint32 mixin_count, PendingTransaction::Priority priority,
- const QStringList &preferredInputs)
-{
-// pauseRefresh();
+// Phase 2: Transaction construction completed
+
+void Wallet::onCreateTransactionError(const QString &msg) {
+ this->tmpTxDescription = "";
+ emit endTransaction();
+}
+
+void Wallet::onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address) {
+ qDebug() << Q_FUNC_INFO;
- std::set<std::string> preferred_inputs;
- for (const auto &input : preferredInputs) {
- preferred_inputs.insert(input.toStdString());
+ for (auto &addr : address) {
+ if (addr == constants::donationAddress) {
+ this->donationSending = true;
+ }
}
- std::set<uint32_t> subaddr_indices;
- Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
- dst_addr.toStdString(), payment_id.toStdString(), Monero::optional<uint64_t>(), mixin_count,
- static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
- PendingTransaction * result = new PendingTransaction(ptImpl, this);
+ // Let UI know that the transaction was constructed
+ emit endTransaction();
-// startRefresh();
- return result;
+ // tx created, but not sent yet. ask user to verify first.
+ emit createTransactionSuccess(tx, address);
}
-void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
- quint32 mixin_count,
- PendingTransaction::Priority priority, const QStringList &preferredInputs)
-{
- m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority, preferredInputs] {
- PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority, preferredInputs);
- QVector<QString> address {dst_addr};
- emit transactionCreated(tx, address);
- });
-}
+// Phase 3: Commit or dispose
-PendingTransaction *Wallet::createTransactionSingle(const QString &key_image, const QString &dst_addr, const size_t outputs,
- PendingTransaction::Priority priority)
-{
-// pauseRefresh();
+void Wallet::commitTransaction(PendingTransaction *tx, const QString &description) {
+ // Clear list of selected transfers
+ this->setSelectedInputs({});
- Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionSingle(key_image.toStdString(), dst_addr.toStdString(),
- outputs, static_cast<Monero::PendingTransaction::Priority>(priority));
- PendingTransaction * result = new PendingTransaction(ptImpl, this);
+ // Nodes - even well-connected, properly configured ones - consistently fail to relay transactions
+ // To mitigate transactions failing we just send the transaction to every node we know about over Tor
+ if (config()->get(Config::multiBroadcast).toBool()) {
+ // Let MainWindow handle this
+ emit multiBroadcast(tx);
+ }
-// startRefresh();
- return result;
-}
+ m_scheduler.run([this, tx, description] {
+ auto txIdList = tx->txid(); // retrieve before commit
+ bool success = tx->commit();
-void Wallet::createTransactionSingleAsync(const QString &key_image, const QString &dst_addr, const size_t outputs,
- PendingTransaction::Priority priority)
-{
- m_scheduler.run([this, key_image, dst_addr, outputs, priority] {
- PendingTransaction *tx = createTransactionSingle(key_image, dst_addr, outputs, priority);
- QVector<QString> address {dst_addr};
- emit transactionCreated(tx, address);
- });
-}
+ if (success && !description.isEmpty()) {
+ for (const auto &txid : txIdList) {
+ this->setUserNote(txid, description);
+ }
+ }
-PendingTransaction *Wallet::createTransactionSelected(const QVector<QString> &key_images, const QString &dst_addr,
- size_t outputs, PendingTransaction::Priority priority)
-{
- std::vector<std::string> kis;
- for (const auto &key_image : key_images) {
- kis.push_back(key_image.toStdString());
- }
- Monero::PendingTransaction *ptImpl = m_walletImpl->createTransactionSelected(kis, dst_addr.toStdString(), outputs, static_cast<Monero::PendingTransaction::Priority>(priority));
- PendingTransaction *result = new PendingTransaction(ptImpl, this);
+ // Store wallet immediately, so we don't risk losing tx key if wallet crashes
+ this->storeSafer();
- return result;
-}
+ this->history()->refresh(this->currentSubaddressAccount());
+ this->coins()->refresh(this->currentSubaddressAccount());
-void Wallet::createTransactionSelectedAsync(const QVector<QString> &key_images, const QString &dst_addr,
- size_t outputs, PendingTransaction::Priority priority)
-{
- m_scheduler.run([this, key_images, dst_addr, outputs, priority] {
- PendingTransaction *tx = createTransactionSelected(key_images, dst_addr, outputs, priority);
- QVector<QString> address {dst_addr};
- emit transactionCreated(tx, address);
+ this->updateBalance();
+
+ // this tx was a donation to Feather, stop our nagging
+ if (this->donationSending) {
+ this->donationSending = false;
+ emit donationSent();
+ }
+
+ emit transactionCommitted(success, tx, txIdList);
});
}
-PendingTransaction *Wallet::createSweepUnmixableTransaction()
-{
-// pauseRefresh();
-
- Monero::PendingTransaction * ptImpl = m_walletImpl->createSweepUnmixableTransaction();
- PendingTransaction * result = new PendingTransaction(ptImpl, this);
+void Wallet::disposeTransaction(PendingTransaction *t) {
+ m_walletImpl->disposeTransaction(t->m_pimpl);
+ delete t;
+}
-// startRefresh();
- return result;
+void Wallet::disposeTransaction(UnsignedTransaction *t) {
+ delete t;
}
-void Wallet::createSweepUnmixableTransactionAsync()
+// #################### Transaction import ####################
+
+bool Wallet::haveTransaction(const QString &txid)
{
- m_scheduler.run([this] {
- PendingTransaction *tx = createSweepUnmixableTransaction();
- QVector<QString> address {""};
- emit transactionCreated(tx, address);
- });
+ return m_walletImpl->haveTransaction(txid.toStdString());
}
UnsignedTransaction * Wallet::loadTxFile(const QString &fileName)
{
qDebug() << "Trying to sign " << fileName;
- Monero::UnsignedTransaction * ptImpl = m_walletImpl->loadUnsignedTx(fileName.toStdString());
- UnsignedTransaction * result = new UnsignedTransaction(ptImpl, m_walletImpl, this);
+ Monero::UnsignedTransaction *ptImpl = m_walletImpl->loadUnsignedTx(fileName.toStdString());
+ UnsignedTransaction *result = new UnsignedTransaction(ptImpl, m_walletImpl, this);
return result;
}
UnsignedTransaction * Wallet::loadTxFromBase64Str(const QString &unsigned_tx)
{
- Monero::UnsignedTransaction * ptImpl = m_walletImpl->loadUnsignedTxFromBase64Str(unsigned_tx.toStdString());
- UnsignedTransaction * result = new UnsignedTransaction(ptImpl, m_walletImpl, this);
+ Monero::UnsignedTransaction *ptImpl = m_walletImpl->loadUnsignedTxFromBase64Str(unsigned_tx.toStdString());
+ UnsignedTransaction *result = new UnsignedTransaction(ptImpl, m_walletImpl, this);
return result;
}
PendingTransaction * Wallet::loadSignedTxFile(const QString &fileName)
{
qDebug() << "Tying to load " << fileName;
- Monero::PendingTransaction * ptImpl = m_walletImpl->loadSignedTx(fileName.toStdString());
- PendingTransaction * result = new PendingTransaction(ptImpl, this);
+ Monero::PendingTransaction *ptImpl = m_walletImpl->loadSignedTx(fileName.toStdString());
+ PendingTransaction *result = new PendingTransaction(ptImpl, this);
return result;
}
return m_walletImpl->importKeyImages(fileName.toStdString() + "_keyImages");
}
-bool Wallet::refresh(bool historyAndSubaddresses /* = true */)
-{
- refreshingSet(true);
- const auto cleanup = sg::make_scope_guard([this]() noexcept {
- refreshingSet(false);
- });
-
- {
- QMutexLocker locker(&m_asyncMutex);
-
- bool result = m_walletImpl->refresh();
- if (historyAndSubaddresses)
- {
- m_history->refresh(currentSubaddressAccount());
- m_subaddress->refresh(currentSubaddressAccount());
- m_subaddressAccount->getAll();
- }
-
- return result;
- }
-}
-
-void Wallet::commitTransactionAsync(PendingTransaction *t, const QString &description)
-{
- m_scheduler.run([this, t, description] {
- auto txIdList = t->txid(); // retrieve before commit
- bool success = t->commit();
-
- if (success && !description.isEmpty()) {
- for (const auto &txid : txIdList) {
- this->setUserNote(txid, description);
- }
- }
-
- emit transactionCommitted(success, t, txIdList);
- });
-}
-
-void Wallet::disposeTransaction(PendingTransaction *t)
-{
- m_walletImpl->disposeTransaction(t->m_pimpl);
- delete t;
-}
-
-void Wallet::disposeTransaction(UnsignedTransaction *t)
-{
- delete t;
-}
+// #################### Models ####################
-//void Wallet::estimateTransactionFeeAsync(const QString &destination,
-// quint64 amount,
-// PendingTransaction::Priority priority,
-// const QJSValue &callback)
-//{
-// m_scheduler.run([this, destination, amount, priority] {
-// const uint64_t fee = m_walletImpl->estimateTransactionFee(
-// {std::make_pair(destination.toStdString(), amount)},
-// static_cast<Monero::PendingTransaction::Priority>(priority));
-// return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))});
-// }, callback);
-//}
-
-TransactionHistory *Wallet::history() const
-{
+TransactionHistory *Wallet::history() const {
return m_history;
}
-TransactionHistoryProxyModel *Wallet::historyModel() const
+TransactionHistoryProxyModel *Wallet::historyModel()
{
if (!m_historyModel) {
- Wallet * w = const_cast<Wallet*>(this);
+ Wallet *w = const_cast<Wallet*>(this);
m_historyModel = new TransactionHistoryModel(w);
m_historyModel->setTransactionHistory(this->history());
m_historySortFilterModel = new TransactionHistoryProxyModel(w);
return m_historySortFilterModel;
}
-TransactionHistoryModel *Wallet::transactionHistoryModel() const
-{
+TransactionHistoryModel* Wallet::transactionHistoryModel() const {
return m_historyModel;
}
-AddressBook *Wallet::addressBook() const
-{
+AddressBook* Wallet::addressBook() const {
return m_addressBook;
}
-AddressBookModel *Wallet::addressBookModel() const
-{
-
- if (!m_addressBookModel) {
- Wallet * w = const_cast<Wallet*>(this);
- m_addressBookModel = new AddressBookModel(w,m_addressBook);
- }
-
+AddressBookModel* Wallet::addressBookModel() const {
return m_addressBookModel;
}
-Subaddress *Wallet::subaddress()
-{
+Subaddress* Wallet::subaddress() const {
return m_subaddress;
}
-SubaddressModel *Wallet::subaddressModel()
-{
- if (!m_subaddressModel) {
- m_subaddressModel = new SubaddressModel(this, m_subaddress);
- }
+SubaddressModel* Wallet::subaddressModel() const {
return m_subaddressModel;
}
-SubaddressAccount *Wallet::subaddressAccount() const
-{
+SubaddressAccount* Wallet::subaddressAccount() const {
return m_subaddressAccount;
}
-SubaddressAccountModel *Wallet::subaddressAccountModel() const
-{
- if (!m_subaddressAccountModel) {
- Wallet * w = const_cast<Wallet*>(this);
- m_subaddressAccountModel = new SubaddressAccountModel(w,m_subaddressAccount);
- }
+SubaddressAccountModel* Wallet::subaddressAccountModel() const {
return m_subaddressAccountModel;
}
-Coins *Wallet::coins() const
-{
+Coins* Wallet::coins() const {
return m_coins;
}
-CoinsModel *Wallet::coinsModel() const
-{
- if (!m_coinsModel) {
- Wallet * w = const_cast<Wallet*>(this);
- m_coinsModel = new CoinsModel(w, m_coins);
- }
+CoinsModel* Wallet::coinsModel() const {
return m_coinsModel;
}
-QString Wallet::generatePaymentId() const
-{
- return QString::fromStdString(Monero::Wallet::genPaymentId());
-}
-
-QString Wallet::integratedAddress(const QString &paymentId) const
-{
- return QString::fromStdString(m_walletImpl->integratedAddress(paymentId.toStdString()));
-}
-
-bool Wallet::cacheAttributeExists(const QString &key) {
- return m_walletImpl->cacheAttributeExists(key.toStdString());
-}
-
-QString Wallet::getCacheAttribute(const QString &key) const {
- return QString::fromStdString(m_walletImpl->getCacheAttribute(key.toStdString()));
-}
-
-bool Wallet::setCacheAttribute(const QString &key, const QString &val)
-{
- return m_walletImpl->setCacheAttribute(key.toStdString(), val.toStdString());
-}
-
-bool Wallet::setUserNote(const QString &txid, const QString ¬e)
-{
- return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString());
-}
-
-QString Wallet::getUserNote(const QString &txid) const
-{
- return QString::fromStdString(m_walletImpl->getUserNote(txid.toStdString()));
-}
+// #################### Transaction proofs ####################
-QString Wallet::getTxKey(const QString &txid) const
-{
+QString Wallet::getTxKey(const QString &txid) const {
return QString::fromStdString(m_walletImpl->getTxKey(txid.toStdString()));
}
-void Wallet::getTxKeyAsync(const QString &txid, const std::function<void (QVariantMap)> &callback)
-{
+void Wallet::getTxKeyAsync(const QString &txid, const std::function<void (QVariantMap)> &callback) {
m_scheduler.run([this, txid] {
QVariantMap map;
map["tx_key"] = getTxKey(txid);
}, callback);
}
-TxKeyResult Wallet::checkTxKey(const QString &txid, const QString &tx_key, const QString &address)
-{
+TxKeyResult Wallet::checkTxKey(const QString &txid, const QString &tx_key, const QString &address) {
uint64_t received;
bool in_pool;
uint64_t confirmations;
+
bool success = m_walletImpl->checkTxKey(txid.toStdString(), tx_key.toStdString(), address.toStdString(), received, in_pool, confirmations);
QString errorString = success ? "" : this->errorString();
bool good = received > 0;
return {success, good, QString::fromStdString(Monero::Wallet::displayAmount(received)), in_pool, confirmations, errorString};
}
-TxProof Wallet::getTxProof(const QString &txid, const QString &address, const QString &message) const
-{
+TxProof Wallet::getTxProof(const QString &txid, const QString &address, const QString &message) const {
std::string result = m_walletImpl->getTxProof(txid.toStdString(), address.toStdString(), message.toStdString());
return TxProof(QString::fromStdString(result), QString::fromStdString(m_walletImpl->errorString()));
}
-//void Wallet::getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback)
-//{
-// m_scheduler.run([this, txid, address, message] {
-// return QJSValueList({txid, getTxProof(txid, address, message)});
-// }, callback);
-//}
-
-TxProofResult Wallet::checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature)
-{
+TxProofResult Wallet::checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature) {
bool good;
uint64_t received;
bool in_pool;
return {success, good, received, in_pool, confirmations};
}
-void Wallet::checkTxProofAsync(const QString &txid, const QString &address, const QString &message,
- const QString &signature) {
+void Wallet::checkTxProofAsync(const QString &txid, const QString &address, const QString &message, const QString &signature) {
m_scheduler.run([this, txid, address, message, signature] {
auto result = this->checkTxProof(txid, address, message, signature);
emit transactionProofVerified(result);
});
}
-Q_INVOKABLE TxProof Wallet::getSpendProof(const QString &txid, const QString &message) const
-{
+TxProof Wallet::getSpendProof(const QString &txid, const QString &message) const {
std::string result = m_walletImpl->getSpendProof(txid.toStdString(), message.toStdString());
return TxProof(QString::fromStdString(result), QString::fromStdString(m_walletImpl->errorString()));
}
-//void Wallet::getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback)
-//{
-// m_scheduler.run([this, txid, message] {
-// return QJSValueList({txid, getSpendProof(txid, message)});
-// }, callback);
-//}
-
-Q_INVOKABLE QPair<bool, bool> Wallet::checkSpendProof(const QString &txid, const QString &message,
- const QString &signature) const {
+QPair<bool, bool> Wallet::checkSpendProof(const QString &txid, const QString &message, const QString &signature) const {
bool good;
bool success = m_walletImpl->checkSpendProof(txid.toStdString(), message.toStdString(), signature.toStdString(), good);
return {success, good};
});
}
-QString Wallet::signMessage(const QString &message, bool filename, const QString &address) const
-{
- if (filename) {
- QFile file(message);
- uchar *data = NULL;
+// #################### Sign / Verify message ####################
- try {
- if (!file.open(QIODevice::ReadOnly))
- return "";
- quint64 size = file.size();
- if (size == 0) {
- file.close();
- return QString::fromStdString(m_walletImpl->signMessage(std::string()));
- }
- data = file.map(0, size);
- if (!data) {
- file.close();
- return "";
- }
- std::string signature = m_walletImpl->signMessage(std::string(reinterpret_cast<const char*>(data), size), address.toStdString());
- file.unmap(data);
- file.close();
- return QString::fromStdString(signature);
+QString Wallet::signMessage(const QString &message, bool filename, const QString &address) const {
+ if (filename) {
+ QFile file(message);
+ uchar *data = nullptr;
+
+ try {
+ if (!file.open(QIODevice::ReadOnly))
+ return "";
+ quint64 size = file.size();
+ if (size == 0) {
+ file.close();
+ return QString::fromStdString(m_walletImpl->signMessage(std::string()));
+ }
+ data = file.map(0, size);
+ if (!data) {
+ file.close();
+ return "";
+ }
+ std::string signature = m_walletImpl->signMessage(std::string(reinterpret_cast<const char*>(data), size), address.toStdString());
+ file.unmap(data);
+ file.close();
+ return QString::fromStdString(signature);
+ }
+ catch (const std::exception &e) {
+ if (data)
+ file.unmap(data);
+ file.close();
+ return "";
+ }
}
- catch (const std::exception &e) {
- if (data)
- file.unmap(data);
- file.close();
- return "";
+ else {
+ return QString::fromStdString(m_walletImpl->signMessage(message.toStdString(), address.toStdString()));
}
- }
- else {
- return QString::fromStdString(m_walletImpl->signMessage(message.toStdString(), address.toStdString()));
- }
}
-bool Wallet::verifySignedMessage(const QString &message, const QString &address, const QString &signature, bool filename) const
-{
- if (filename) {
- QFile file(message);
- uchar *data = NULL;
+bool Wallet::verifySignedMessage(const QString &message, const QString &address, const QString &signature, bool filename) const {
+ if (filename) {
+ QFile file(message);
+ uchar *data = nullptr;
- try {
- if (!file.open(QIODevice::ReadOnly))
- return false;
- quint64 size = file.size();
- if (size == 0) {
- file.close();
- return m_walletImpl->verifySignedMessage(std::string(), address.toStdString(), signature.toStdString());
- }
- data = file.map(0, size);
- if (!data) {
- file.close();
- return false;
- }
- bool ret = m_walletImpl->verifySignedMessage(std::string(reinterpret_cast<const char*>(data), size), address.toStdString(), signature.toStdString());
- file.unmap(data);
- file.close();
- return ret;
+ try {
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+ quint64 size = file.size();
+ if (size == 0) {
+ file.close();
+ return m_walletImpl->verifySignedMessage(std::string(), address.toStdString(), signature.toStdString());
+ }
+ data = file.map(0, size);
+ if (!data) {
+ file.close();
+ return false;
+ }
+ bool ret = m_walletImpl->verifySignedMessage(std::string(reinterpret_cast<const char*>(data), size), address.toStdString(), signature.toStdString());
+ file.unmap(data);
+ file.close();
+ return ret;
+ }
+ catch (const std::exception &e) {
+ if (data)
+ file.unmap(data);
+ file.close();
+ return false;
+ }
}
- catch (const std::exception &e) {
- if (data)
- file.unmap(data);
- file.close();
- return false;
+ else {
+ return m_walletImpl->verifySignedMessage(message.toStdString(), address.toStdString(), signature.toStdString());
}
- }
- else {
- return m_walletImpl->verifySignedMessage(message.toStdString(), address.toStdString(), signature.toStdString());
- }
}
-bool Wallet::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const
-{
+// #################### URI Parsing ####################
+
+bool Wallet::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const {
std::string s_address, s_payment_id, s_tx_description, s_recipient_name, s_error;
std::vector<std::string> s_unknown_parameters;
bool res= m_walletImpl->parse_uri(uri.toStdString(), s_address, s_payment_id, amount, s_tx_description, s_recipient_name, s_unknown_parameters, s_error);
return res;
}
-QVariantMap Wallet::parse_uri_to_object(const QString &uri) const
-{
+QVariantMap Wallet::parse_uri_to_object(const QString &uri) const {
QString address;
QString payment_id;
uint64_t amount = 0;
return result;
}
-QString Wallet::make_uri(const QString &address, quint64 &amount, const QString &description,
- const QString &recipient) const
-{
+QString Wallet::make_uri(const QString &address, quint64 &amount, const QString &description, const QString &recipient) const {
std::string error;
std::string uri = m_walletImpl->make_uri(address.toStdString(), "", amount, description.toStdString(), recipient.toStdString(), error);
return QString::fromStdString(uri);
}
-bool Wallet::rescanSpent()
-{
- QMutexLocker locker(&m_asyncMutex);
-
- return m_walletImpl->rescanSpent();
-}
-
-bool Wallet::useForkRules(quint8 required_version, quint64 earlyBlocks) const
-{
- if(m_connectionStatus == Wallet::ConnectionStatus_Disconnected)
- return false;
- try {
- return m_walletImpl->useForkRules(required_version,earlyBlocks);
- } catch (const std::exception &e) {
- qDebug() << e.what();
- return false;
- }
-}
-
-void Wallet::setWalletCreationHeight(quint64 height)
-{
- m_walletImpl->setRefreshFromBlockHeight(height);
- emit walletCreationHeightChanged();
-}
-
-QString Wallet::getDaemonLogPath() const
-{
- return QString::fromStdString(m_walletImpl->getDefaultDataDir()) + "/bitmonero.log";
-}
-
-bool Wallet::blackballOutput(const QString &amount, const QString &offset)
-{
- return m_walletImpl->blackballOutput(amount.toStdString(), offset.toStdString());
-}
-
-bool Wallet::blackballOutputs(const QList<QString> &pubkeys, bool add)
-{
- std::vector<std::string> std_pubkeys;
- foreach (const QString &pubkey, pubkeys) {
- std_pubkeys.push_back(pubkey.toStdString());
- }
- return m_walletImpl->blackballOutputs(std_pubkeys, add);
-}
-
-bool Wallet::blackballOutputs(const QString &filename, bool add)
-{
- QFile file(filename);
-
- try {
- if (!file.open(QIODevice::ReadOnly))
- return false;
- QList<QString> outputs;
- QTextStream in(&file);
- while (!in.atEnd()) {
- outputs.push_back(in.readLine());
- }
- file.close();
- return blackballOutputs(outputs, add);
- }
- catch (const std::exception &e) {
- file.close();
- return false;
- }
-}
-
-bool Wallet::unblackballOutput(const QString &amount, const QString &offset)
-{
- return m_walletImpl->unblackballOutput(amount.toStdString(), offset.toStdString());
-}
-
-QString Wallet::getRing(const QString &key_image)
-{
- std::vector<uint64_t> cring;
- if (!m_walletImpl->getRing(key_image.toStdString(), cring))
- return "";
- QString ring = "";
- for (uint64_t out: cring)
- {
- if (!ring.isEmpty())
- ring = ring + " ";
- QString s;
- s.setNum(out);
- ring = ring + s;
- }
- return ring;
-}
-
-QString Wallet::getRings(const QString &txid)
-{
- std::vector<std::pair<std::string, std::vector<uint64_t>>> crings;
- if (!m_walletImpl->getRings(txid.toStdString(), crings))
- return "";
- QString ring = "";
- for (const auto &cring: crings)
- {
- if (!ring.isEmpty())
- ring = ring + "|";
- ring = ring + QString::fromStdString(cring.first) + " absolute";
- for (uint64_t out: cring.second)
- {
- ring = ring + " ";
- QString s;
- s.setNum(out);
- ring = ring + s;
- }
- }
- return ring;
-}
-
-bool Wallet::setRing(const QString &key_image, const QString &ring, bool relative)
-{
- std::vector<uint64_t> cring;
- QStringList strOuts = ring.split(" ");
- foreach(QString str, strOuts)
- {
- uint64_t out;
- bool ok;
- out = str.toULong(&ok);
- if (ok)
- cring.push_back(out);
- }
- return m_walletImpl->setRing(key_image.toStdString(), cring, relative);
-}
-
-void Wallet::segregatePreForkOutputs(bool segregate)
-{
- m_walletImpl->segregatePreForkOutputs(segregate);
-}
-
-void Wallet::segregationHeight(quint64 height)
-{
- m_walletImpl->segregationHeight(height);
-}
-
-void Wallet::keyReuseMitigation2(bool mitigation)
-{
- m_walletImpl->keyReuseMitigation2(mitigation);
-}
-
-void Wallet::onWalletPassphraseNeeded(bool on_device)
-{
- emit this->walletPassphraseNeeded(on_device);
-}
+// #################### Misc / Unused ####################
quint64 Wallet::getBytesReceived() const {
// TODO: this can segfault. Unclear why.
return m_walletImpl->getBytesSent();
}
-bool Wallet::isDeviceConnected() const {
- return m_walletImpl->isDeviceConnected();
+QString Wallet::getDaemonLogPath() const {
+ return QString::fromStdString(m_walletImpl->getDefaultDataDir()) + "/bitmonero.log";
}
bool Wallet::setRingDatabase(const QString &path) {
return m_walletImpl->setRingDatabase(path.toStdString());
}
-void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort)
-{
- if (m_walletListener != nullptr)
- {
- m_walletListener->onPassphraseEntered(passphrase, enter_on_device, entry_abort);
- }
+void Wallet::setWalletCreationHeight(quint64 height) {
+ m_walletImpl->setRefreshFromBlockHeight(height);
}
-Wallet::Wallet(Monero::Wallet *w, QObject *parent)
- : QObject(parent)
- , m_walletImpl(w)
- , m_history(new TransactionHistory(m_walletImpl->history(), this))
- , m_historyModel(nullptr)
- , m_addressBook(new AddressBook(m_walletImpl->addressBook(), this))
- , m_addressBookModel(nullptr)
- , m_daemonBlockChainHeight(0)
- , m_daemonBlockChainTargetHeight(0)
- , m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
- , m_disconnected(true)
- , m_currentSubaddressAccount(0)
- , m_subaddress(new Subaddress(m_walletImpl->subaddress(), this))
- , m_subaddressModel(nullptr)
- , m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this))
- , m_subaddressAccountModel(nullptr)
- , m_coinsModel(nullptr)
- , m_refreshNow(false)
- , m_refreshEnabled(false)
- , m_refreshing(false)
- , m_scheduler(this)
- , m_useSSL(true)
- , m_coins(new Coins(m_walletImpl->coins(), this))
-{
- m_walletListener = new WalletListenerImpl(this);
- m_walletImpl->setListener(m_walletListener);
- m_currentSubaddressAccount = getCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT).toUInt();
- // start cache timers
- m_initialized = false;
- m_daemonUsername = "";
- m_daemonPassword = "";
+//! create a view only wallet
+bool Wallet::createViewOnly(const QString &path, const QString &password) const {
+ // Create path
+ QDir d = QFileInfo(path).absoluteDir();
+ d.mkpath(d.absolutePath());
+ return m_walletImpl->createWatchOnly(path.toStdString(),password.toStdString(),m_walletImpl->getSeedLanguage());
+}
- if (this->status() == Status_Ok) {
- startRefreshThread();
- }
+bool Wallet::rescanSpent() {
+ QMutexLocker locker(&m_asyncMutex);
+
+ return m_walletImpl->rescanSpent();
+}
+
+void Wallet::setNewWallet() {
+ m_newWallet = true;
}
Wallet::~Wallet()
m_scheduler.shutdownWaitForFinished();
- //Monero::WalletManagerFactory::getWalletManager()->closeWallet(m_walletImpl);
- if(status() == Status_Critical || status() == Status_BadPassword)
+ if (status() == Status_Critical || status() == Status_BadPassword) {
qDebug("Not storing wallet cache");
- else if( m_walletImpl->store())
- qDebug("Wallet cache stored successfully");
- else
- qDebug("Error storing wallet cache");
+ }
+ else {
+ bool success = m_walletImpl->store();
+ success ? qDebug("Wallet cache stored successfully") : qDebug("Error storing wallet cache");
+ }
+
delete m_walletImpl;
m_walletImpl = nullptr;
- delete m_walletListener;
- m_walletListener = NULL;
qDebug("m_walletImpl deleted");
}
-
-void Wallet::startRefreshThread()
-{
- const auto future = m_scheduler.run([this] {
- constexpr const std::chrono::seconds refreshInterval{10};
- constexpr const std::chrono::milliseconds intervalResolution{100};
-
- auto last = std::chrono::steady_clock::now();
- while (!m_scheduler.stopping())
- {
- if (m_refreshEnabled && (!isHwBacked() || isDeviceConnected()))
- {
- const auto now = std::chrono::steady_clock::now();
- const auto elapsed = now - last;
- if (elapsed >= refreshInterval || m_refreshNow)
- {
- m_refreshNow = false;
- // Don't call refresh function if we don't have the daemon and target height
- // We do this to prevent to UI from getting confused about the amount of blocks that are still remaining
- bool haveHeights = refreshHeights();
- if (haveHeights) {
- refresh(false);
- }
- last = std::chrono::steady_clock::now();
- }
- }
-
- std::this_thread::sleep_for(intervalResolution);
- }
- });
- if (!future.first)
- {
- throw std::runtime_error("failed to start auto refresh thread");
- }
-}
-
-void Wallet::onRefreshed(bool success) {
- if (!success) {
- setConnectionStatus(ConnectionStatus_Disconnected);
- }
-}
\ No newline at end of file
#include <QList>
#include <QtConcurrent/QtConcurrent>
-#include "wallet/api/wallet2_api.h" // we need to have an access to the Monero::Wallet::Status enum here;
+#include "wallet/api/wallet2_api.h"
#include "utils/scheduler.h"
-#include "PendingTransaction.h" // we need to have an access to the PendingTransaction::Priority enum here;
+#include "PendingTransaction.h"
#include "UnsignedTransaction.h"
#include "utils/networktype.h"
#include "PassphraseHelper.h"
Q_OBJECT
public:
- explicit Wallet(QObject *parent = nullptr);
- explicit Wallet(Monero::Wallet *w, QObject * parent = nullptr);
+ explicit Wallet(Monero::Wallet *w, QObject *parent = nullptr);
~Wallet() override;
enum Status {
Q_ENUM(ConnectionStatus)
- //! return connection status
- ConnectionStatus connectionStatus() const;
-
- //! returns mnemonic seed
- QString getSeed(const QString &seedOffset) const;
-
- qsizetype seedLength() const;
-
- //! returns seed language
- QString getSeedLanguage() const;
-
- //! set seed language
- void setSeedLanguage(const QString &lang);
-
+ // ##### Status #####
//! returns last operation's status
Status status() const;
- //! returns network type of the wallet.
- NetworkType::Type nettype() const;
-
- //! returns true if wallet was ever synchronized
- bool synchronized() const;
+ //! return connection status
+ ConnectionStatus connectionStatus() const;
//! returns true if wallet is currently synchronized
bool isSynchronized() const;
//! return true if wallet is connected to a node
bool isConnected() const;
- void setOffline(bool offline) const;
-
//! returns last operation's error message
QString errorString() const;
- //! changes the password using existing parameters (path, seed, seed lang)
- bool setPassword(const QString &oldPassword, const QString &newPassword);
-
- //! verify wallet password
- bool verifyPassword(const QString &password);
-
- //! returns wallet's public address
- QString address(quint32 accountIndex, quint32 addressIndex) const;
-
- //! returns the subaddress index of the address
- SubaddressIndex subaddressIndex(const QString &address) const;
-
- //! returns wallet cache file path
- QString cachePath() const;
-
- //! returns wallet keys file path
- QString keysPath() const;
-
- //! saves wallet to the file by given path
- //! empty path stores in current location
- void store();
- // void storeAsync(const QJSValue &callback, const QString &path = "");
-
- //! initializes wallet asynchronously
- void initAsync(
- const QString &daemonAddress,
- bool trustedDaemon = false,
- quint64 upperTransactionLimit = 0,
- bool isRecovering = false,
- bool isRecoveringFromDevice = false,
- quint64 restoreHeight = 0,
- const QString &proxyAddress = "");
-
- bool setDaemon(const QString &daemonAddress);
-
- // Set daemon rpc user/pass
- void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = "");
-
- //! create a view only wallet
- bool createViewOnly(const QString &path, const QString &password) const;
-
- //! connects to daemon
- bool connectToDaemon();
+ //! returns network type of the wallet.
+ NetworkType::Type nettype() const;
- //! indicates if daemon is trusted
- void setTrustedDaemon(bool arg);
+ //! returns if view only wallet
+ bool viewOnly() const;
- //! indicates if ssl should be used to connect to daemon
- void setUseSSL(bool ssl);
+ //! return true if deterministic keys
+ bool isDeterministic() const;
+ // ##### Balance #####
//! returns balance
quint64 balance() const;
quint64 balance(quint32 accountIndex) const;
quint64 unlockedBalance(quint32 accountIndex) const;
quint64 unlockedBalanceAll() const;
- //! account/address management
+ void updateBalance();
+
+ // ##### Subaddresses and Accounts #####
+ //! returns wallet's public address
+ QString address(quint32 accountIndex, quint32 addressIndex) const;
+
+ //! returns the subaddress index of the address
+ SubaddressIndex subaddressIndex(const QString &address) const;
+
quint32 currentSubaddressAccount() const;
void switchSubaddressAccount(quint32 accountIndex);
void addSubaddressAccount(const QString& label);
void deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId);
QString getSubaddressLookahead() const;
- //! hw-device backed wallets
+ // ##### Seed #####
+
+ //! returns mnemonic seed
+ QString getSeed(const QString &seedOffset) const;
+
+ qsizetype seedLength() const;
+
+ //! returns seed language
+ QString getSeedLanguage() const;
+
+ //! set seed language
+ void setSeedLanguage(const QString &lang);
+
+ //! Get wallet keys
+ QString getSecretViewKey() const {return QString::fromStdString(m_walletImpl->secretViewKey());}
+ QString getPublicViewKey() const {return QString::fromStdString(m_walletImpl->publicViewKey());}
+ QString getSecretSpendKey() const {return QString::fromStdString(m_walletImpl->secretSpendKey());}
+ QString getPublicSpendKey() const {return QString::fromStdString(m_walletImpl->publicSpendKey());}
+
+ // ##### Node connection #####
+
+ void setOffline(bool offline) const;
+
+ //! indicates if daemon is trusted
+ void setTrustedDaemon(bool arg);
+
+ //! indicates if ssl should be used to connect to daemon
+ void setUseSSL(bool ssl);
+
+ //! Set daemon rpc user/pass
+ void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = "");
+
+ //! initializes wallet asynchronously
+ void initAsync(const QString &daemonAddress,
+ bool trustedDaemon = false,
+ quint64 upperTransactionLimit = 0,
+ const QString &proxyAddress = "");
+
+ // ##### Synchronization (Refresh) #####
+ void startRefresh();
+ void pauseRefresh();
+
+ //! returns current wallet's block height
+ //! (can be less than daemon's blockchain height when wallet sync in progress)
+ quint64 blockChainHeight() const;
+
+ //! returns daemon's blockchain height
+ quint64 daemonBlockChainHeight() const;
+
+ //! returns daemon's blockchain target height
+ quint64 daemonBlockChainTargetHeight() const;
+
+ void syncStatusUpdated(quint64 height, quint64 target);
+
+ void refreshModels();
+
+ // ##### Hardware wallet #####
bool isHwBacked() const;
bool isLedger() const;
bool isTrezor() const;
+ bool isDeviceConnected() const;
+
//! attempt to reconnect to hw-device
bool reconnectDevice();
- //! returns if view only wallet
- bool viewOnly() const;
-
- //! return true if deterministic keys
- bool isDeterministic() const;
-
- //! refresh daemon blockchain and target height
- bool refreshHeights();
+ // Passphrase entry for hardware wallets
+ void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
+ void onWalletPassphraseNeeded(bool on_device) override;
+ // ##### Import / Export #####
//! export/import key images
bool exportKeyImages(const QString& path, bool all = false);
bool importKeyImages(const QString& path);
//! import a transaction
bool importTransaction(const QString& txid);
+ // ##### Wallet cache #####
+ //! saves wallet to the file by given path
+ //! empty path stores in current location
+ void store();
+ void storeSafer();
+
+ //! returns wallet cache file path
+ QString cachePath() const;
+
+ //! returns wallet keys file path
+ QString keysPath() const;
+
+ //! changes the password using existing parameters (path, seed, seed lang)
+ bool setPassword(const QString &oldPassword, const QString &newPassword);
+
+ //! verify wallet password
+ bool verifyPassword(const QString &password);
+
+ //! Namespace your cacheAttribute keys to avoid collisions
+ bool cacheAttributeExists(const QString &key);
+ bool setCacheAttribute(const QString &key, const QString &val);
+ QString getCacheAttribute(const QString &key) const;
+
+ void addCacheTransaction(const QString &txid, const QString &txHex);
+ QString getCacheTransaction(const QString &txid) const;
+
+ bool setUserNote(const QString &txid, const QString ¬e);
+ QString getUserNote(const QString &txid) const;
+
QString printBlockchain();
QString printTransfers();
QString printPayments();
QString printAddressBook();
QString printScannedPoolTxs();
- //! does wallet have txid
- bool haveTransaction(const QString &txid);
-
- //! refreshes the wallet
- bool refresh(bool historyAndSubaddresses = false);
-
- // pause/resume refresh
- void startRefresh();
- void pauseRefresh();
-
- //! returns current wallet's block height
- //! (can be less than daemon's blockchain height when wallet sync in progress)
- quint64 blockChainHeight() const;
-
- //! returns daemon's blockchain height
- quint64 daemonBlockChainHeight() const;
-
- //! returns daemon's blockchain target height
- quint64 daemonBlockChainTargetHeight() const;
-
- //! creates transaction
- PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
- quint64 amount, quint32 mixin_count,
- PendingTransaction::Priority priority,
- const QStringList &preferredInputs);
+ // ##### Transactions #####
+ void setSelectedInputs(const QStringList &selected);
- //! creates async transaction
- void createTransactionAsync(const QString &dst_addr, const QString &payment_id,
- quint64 amount, quint32 mixin_count,
- PendingTransaction::Priority priority, const QStringList &preferredInputs);
+ void createTransaction(const QString &address, quint64 amount, const QString &description, bool all);
+ void createTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
+ void sweepOutputs(const QVector<QString> &keyImages, QString address, bool churn, int outputs);
- //! creates multi-destination transaction
- PendingTransaction * createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
- PendingTransaction::Priority priority, const QStringList &preferredInputs);
+ void onCreateTransactionError(const QString &msg);
+ void commitTransaction(PendingTransaction *tx, const QString &description="");
- //! creates async multi-destination transaction
- void createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
- PendingTransaction::Priority priority, const QStringList &preferredInputs);
-
-
- //! creates transaction with all outputs
- PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
- quint32 mixin_count, PendingTransaction::Priority priority,
- const QStringList &preferredInputs);
-
- //! creates async transaction with all outputs
- void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
- quint32 mixin_count, PendingTransaction::Priority priority,
- const QStringList &preferredInputs);
-
- //! creates transaction with single input
- PendingTransaction * createTransactionSingle(const QString &key_image, const QString &dst_addr,
- size_t outputs, PendingTransaction::Priority priority);
-
- //! creates async transaction with single input
- void createTransactionSingleAsync(const QString &key_image, const QString &dst_addr,
- size_t outputs, PendingTransaction::Priority priority);
-
- //! creates transaction with selected inputs
- PendingTransaction * createTransactionSelected(const QVector<QString> &key_images, const QString &dst_addr,
- size_t outputs, PendingTransaction::Priority priority);
-
- //! creates async transaction with selected inputs
- void createTransactionSelectedAsync(const QVector<QString> &key_images, const QString &dst_addr,
- size_t outputs, PendingTransaction::Priority priority);
+ //! deletes transaction and frees memory
+ void disposeTransaction(PendingTransaction * t);
- //! creates sweep unmixable transaction
- PendingTransaction * createSweepUnmixableTransaction();
+ //! deletes unsigned transaction and frees memory
+ void disposeTransaction(UnsignedTransaction * t);
- //! creates async sweep unmixable transaction
- void createSweepUnmixableTransactionAsync();
+ // ##### Transaction import #####
+ //! does wallet have txid
+ bool haveTransaction(const QString &txid);
//! Sign a transfer from file
UnsignedTransaction * loadTxFile(const QString &fileName);
//! Submit a transfer from file
bool submitTxFile(const QString &fileName) const;
- //! asynchronous transaction commit
- void commitTransactionAsync(PendingTransaction * t, const QString &description="");
+ // ##### Models #####
+ TransactionHistory* history() const;
+ TransactionHistoryProxyModel* historyModel();
+ TransactionHistoryModel* transactionHistoryModel() const;
+ AddressBook* addressBook() const;
+ AddressBookModel* addressBookModel() const;
+ Subaddress* subaddress() const;
+ SubaddressModel* subaddressModel() const;
+ SubaddressAccount* subaddressAccount() const;
+ SubaddressAccountModel* subaddressAccountModel() const;
+ Coins* coins() const;
+ CoinsModel* coinsModel() const;
+
+ // ##### Transaction proofs #####
- //! deletes transaction and frees memory
- void disposeTransaction(PendingTransaction * t);
-
- //! deletes unsigned transaction and frees memory
- void disposeTransaction(UnsignedTransaction * t);
-
-// void estimateTransactionFeeAsync(const QString &destination,
-// quint64 amount,
-// PendingTransaction::Priority priority,
-// const QJSValue &callback);
-
- //! returns transaction history
- TransactionHistory * history() const;
-
- //! returns transaction history model
- TransactionHistoryProxyModel *historyModel() const;
-
- //! returns transaction history model (the real one)
- TransactionHistoryModel *transactionHistoryModel() const;
-
- //! returns Address book
- AddressBook *addressBook() const;
-
- //! returns address book model
- AddressBookModel *addressBookModel() const;
-
- //! returns subaddress
- Subaddress *subaddress();
-
- //! returns subaddress model
- SubaddressModel *subaddressModel();
-
- //! returns subaddress account
- SubaddressAccount *subaddressAccount() const;
-
- //! returns subaddress account model
- SubaddressAccountModel *subaddressAccountModel() const;
-
- //! returns coins
- Coins *coins() const;
-
- //! return coins model
- CoinsModel *coinsModel() const;
-
- //! generate payment id
- QString generatePaymentId() const;
+ QString getTxKey(const QString &txid) const;
+ void getTxKeyAsync(const QString &txid, const std::function<void (QVariantMap)> &callback);
- //! integrated address
- QString integratedAddress(const QString &paymentId) const;
+ TxKeyResult checkTxKey(const QString &txid, const QString &tx_key, const QString &address);
+ TxProof getTxProof(const QString &txid, const QString &address, const QString &message) const;
+ TxProofResult checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
+ void checkTxProofAsync(const QString &txid, const QString &address, const QString &message, const QString &signature);
+ TxProof getSpendProof(const QString &txid, const QString &message) const;
+ QPair<bool, bool> checkSpendProof(const QString &txid, const QString &message, const QString &signature) const;
+ void checkSpendProofAsync(const QString &txid, const QString &message, const QString &signature);
+ // ##### Sign / Verify message #####
//! signing a message
QString signMessage(const QString &message, bool filename = false, const QString &address = "") const;
//! verify a signed message
bool verifySignedMessage(const QString &message, const QString &address, const QString &signature, bool filename = false) const;
- //! Parse URI
+ // ##### URI Parsing #####
bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const;
QVariantMap parse_uri_to_object(const QString &uri) const;
QString make_uri(const QString &address, quint64 &amount, const QString &description, const QString &recipient) const;
- //! Namespace your cacheAttribute keys to avoid collisions
- bool cacheAttributeExists(const QString &key);
- bool setCacheAttribute(const QString &key, const QString &val);
- QString getCacheAttribute(const QString &key) const;
-
- bool setUserNote(const QString &txid, const QString ¬e);
- QString getUserNote(const QString &txid) const;
- QString getTxKey(const QString &txid) const;
- void getTxKeyAsync(const QString &txid, const std::function<void (QVariantMap)> &callback);
+ // ##### Misc / Unused #####
- TxKeyResult checkTxKey(const QString &txid, const QString &tx_key, const QString &address);
- TxProof getTxProof(const QString &txid, const QString &address, const QString &message) const;
- // void getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback);
- //QString checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
- TxProofResult checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
- void checkTxProofAsync(const QString &txid, const QString &address, const QString &message, const QString &signature);
- TxProof getSpendProof(const QString &txid, const QString &message) const;
- // void getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback);
- QPair<bool, bool> checkSpendProof(const QString &txid, const QString &message, const QString &signature) const;
- void checkSpendProofAsync(const QString &txid, const QString &message, const QString &signature);
- // Rescan spent outputs
- bool rescanSpent();
+ quint64 getBytesReceived() const;
+ quint64 getBytesSent() const;
- // check if fork rules should be used
- bool useForkRules(quint8 version, quint64 earlyBlocks = 0) const;
+ QString getDaemonLogPath() const;
- //! Get wallet keys
- QString getSecretViewKey() const {return QString::fromStdString(m_walletImpl->secretViewKey());}
- QString getPublicViewKey() const {return QString::fromStdString(m_walletImpl->publicViewKey());}
- QString getSecretSpendKey() const {return QString::fromStdString(m_walletImpl->secretSpendKey());}
- QString getPublicSpendKey() const {return QString::fromStdString(m_walletImpl->publicSpendKey());}
+ bool setRingDatabase(const QString &path);
quint64 getWalletCreationHeight() const {return m_walletImpl->getRefreshFromBlockHeight();}
void setWalletCreationHeight(quint64 height);
- QString getDaemonLogPath() const;
+ //! Rescan spent outputs
+ bool rescanSpent();
- // Blackballed outputs
- bool blackballOutput(const QString &amount, const QString &offset);
- bool blackballOutputs(const QList<QString> &outputs, bool add);
- bool blackballOutputs(const QString &filename, bool add);
- bool unblackballOutput(const QString &amount, const QString &offset);
+ //! Indicates that the wallet is new
+ void setNewWallet();
- // Rings
- QString getRing(const QString &key_image);
- QString getRings(const QString &txid);
- bool setRing(const QString &key_image, const QString &ring, bool relative);
+ //! create a view only wallet
+ bool createViewOnly(const QString &path, const QString &password) const;
- // key reuse mitigation options
- void segregatePreForkOutputs(bool segregate);
- void segregationHeight(quint64 height);
- void keyReuseMitigation2(bool mitigation);
+ PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
- // Passphrase entry for hardware wallets
- void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
- void onWalletPassphraseNeeded(bool on_device) override;
+ QString tmpTxDescription; // TODO: remove the need for this var
+ bool refreshedOnce = false;
- quint64 getBytesReceived() const;
- quint64 getBytesSent() const;
+ void onHeightsRefreshed(bool success, quint64 daemonHeight, quint64 targetHeight);
- bool isDeviceConnected() const;
-
- bool setRingDatabase(const QString &path);
-
- // TODO: setListener() when it implemented in API
signals:
// emitted on every event happened with wallet
// (money sent/received, new block)
void moneyReceived(const QString &txId, quint64 amount);
void unconfirmedMoneyReceived(const QString &txId, quint64 amount);
void newBlock(quint64 height, quint64 targetHeight);
- void addressBookChanged() const;
- void historyModelChanged() const;
void walletCreationHeightChanged();
void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed();
void deviceError(const QString &message);
void walletPassphraseNeeded(bool onDevice);
void transactionCommitted(bool status, PendingTransaction *t, const QStringList& txid);
- void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const;
void deviceShowAddressShowed();
void transactionProofVerified(TxProofResult result);
void spendProofVerified(QPair<bool, bool> result);
void connectionStatusChanged(int status) const;
void currentSubaddressAccountChanged() const;
- void disconnectedChanged() const;
- void proxyAddressChanged() const;
- void refreshingChanged() const;
-private:
- //! initializes wallet
- bool init(
- const QString &daemonAddress,
- bool trustedDaemon,
- quint64 upperTransactionLimit,
- bool isRecovering,
- bool isRecoveringFromDevice,
- quint64 restoreHeight,
- const QString& proxyAddress);
-
- bool disconnected() const;
- bool refreshing() const;
- void refreshingSet(bool value);
- void onRefreshed(bool success);
+ void refreshSync(int height, int target);
+ void blockchainSync(int height, int target);
+ void synchronized();
+ void balanceUpdated(quint64 balance, quint64 spendable);
+ void keysCorrupted();
+
+ void endTransaction();
+ void createTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address);
+ void donationSent();
+ void walletRefreshed();
+
+ void initiateTransaction();
+ void createTransactionError(QString message);
+
+ void selectedInputsChanged(const QStringList &selectedInputs);
+ void multiBroadcast(PendingTransaction *tx);
+ void heightsRefreshed(bool success, quint64 daemonHeight, quint64 targetHeight);
+
+private:
+ // ###### Status ######
void setConnectionStatus(ConnectionStatus value);
- QString getProxyAddress() const;
- void setProxyAddress(QString address);
- void startRefreshThread();
+ // ##### Synchronization (Refresh) #####
+ void startRefreshThread();
void onNewBlock(uint64_t height);
+ void onUpdated();
+ void onRefreshed(bool success, const QString &message);
+
+ // ##### Transactions #####
+ void onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address);
private:
friend class WalletManager;
friend class WalletListenerImpl;
- //! libwallet's
- Monero::Wallet * m_walletImpl;
- // history lifetime managed by wallet;
- TransactionHistory * m_history;
- // Used for UI history view
- mutable TransactionHistoryModel * m_historyModel;
- mutable TransactionHistoryProxyModel * m_historySortFilterModel;
- QString m_paymentId;
- AddressBook * m_addressBook;
- mutable AddressBookModel * m_addressBookModel;
- mutable quint64 m_daemonBlockChainHeight;
- mutable quint64 m_daemonBlockChainTargetHeight;
-
- mutable ConnectionStatus m_connectionStatus;
-
- bool m_disconnected;
- mutable bool m_initialized;
+
+ Monero::Wallet *m_walletImpl;
+
+ TransactionHistory *m_history;
+ TransactionHistoryModel *m_historyModel;
+ TransactionHistoryProxyModel *m_historySortFilterModel;
+
+ AddressBook *m_addressBook;
+ AddressBookModel *m_addressBookModel;
+
+ quint64 m_daemonBlockChainHeight;
+ quint64 m_daemonBlockChainTargetHeight;
+
+ ConnectionStatus m_connectionStatus;
+
uint32_t m_currentSubaddressAccount;
- Subaddress * m_subaddress;
- mutable SubaddressModel * m_subaddressModel;
- SubaddressAccount * m_subaddressAccount;
- mutable SubaddressAccountModel * m_subaddressAccountModel;
- Coins * m_coins;
- mutable CoinsModel * m_coinsModel;
+ Subaddress *m_subaddress;
+ SubaddressModel *m_subaddressModel;
+ SubaddressAccount *m_subaddressAccount;
+ SubaddressAccountModel *m_subaddressAccountModel;
+
+ Coins *m_coins;
+ CoinsModel *m_coinsModel;
+
QMutex m_asyncMutex;
QString m_daemonUsername;
QString m_daemonPassword;
- QString m_proxyAddress;
- mutable QMutex m_proxyMutex;
+
+ QMutex m_proxyMutex;
std::atomic<bool> m_refreshNow;
std::atomic<bool> m_refreshEnabled;
- std::atomic<bool> m_refreshing;
WalletListenerImpl *m_walletListener;
FutureScheduler m_scheduler;
- int m_connectionTimeout = 30;
+
bool m_useSSL;
+ bool donationSending = false;
+ bool m_newWallet = false;
+
+ QTimer *m_storeTimer = nullptr;
+ std::set<std::string> m_selectedInputs;
};
#include "WalletListenerImpl.h"
#include "Wallet.h"
+#include "WalletManager.h"
WalletListenerImpl::WalletListenerImpl(Wallet * w)
: m_wallet(w)
}
+// Beware!
+// Do not call non-signal m_wallet functions here
+// Nothing here runs in the GUI thread
+
void WalletListenerImpl::moneySpent(const std::string &txId, uint64_t amount)
{
- qDebug() << __FUNCTION__;
- emit m_wallet->moneySpent(QString::fromStdString(txId), amount);
+ // Outgoing tx included in a block
+ QString qTxId = QString::fromStdString(txId);
+ qDebug() << Q_FUNC_INFO << qTxId << " " << WalletManager::displayAmount(amount);
+
+ emit m_wallet->moneySpent(qTxId, amount);
}
void WalletListenerImpl::moneyReceived(const std::string &txId, uint64_t amount)
{
- qDebug() << __FUNCTION__;
- emit m_wallet->moneyReceived(QString::fromStdString(txId), amount);
+ // Incoming tx included in a block.
+ QString qTxId = QString::fromStdString(txId);
+ qDebug() << Q_FUNC_INFO << qTxId << " " << WalletManager::displayAmount(amount);
+
+ emit m_wallet->moneyReceived(qTxId, amount);
}
void WalletListenerImpl::unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
{
- qDebug() << __FUNCTION__;
- emit m_wallet->unconfirmedMoneyReceived(QString::fromStdString(txId), amount);
+ // Incoming tx in pool
+ QString qTxId = QString::fromStdString(txId);
+ qDebug() << Q_FUNC_INFO << qTxId << " " << WalletManager::displayAmount(amount);
+
+ emit m_wallet->unconfirmedMoneyReceived(qTxId, amount);
}
void WalletListenerImpl::newBlock(uint64_t height)
{
- // qDebug() << __FUNCTION__;
- m_wallet->onNewBlock(height);
+ // Called whenever a new block gets scanned by the wallet
emit m_wallet->newBlock(height, m_wallet->daemonBlockChainTargetHeight());
}
void WalletListenerImpl::refreshed(bool success)
{
QString message = m_wallet->errorString();
- m_wallet->onRefreshed(success);
emit m_wallet->refreshed(success, message);
}
EventFilter filter;
app.installEventFilter(&filter);
- WindowManager windowManager(&filter);
+ WindowManager windowManager(QCoreApplication::instance(), &filter);
QObject::connect(&app, &SingleApplication::instanceStarted, [&windowManager]() {
windowManager.raise();
#include <QDesktopServices>
#include <QRegularExpression>
+#include "utils/config.h"
#include "utils/Utils.h"
#include "utils/os/tails.h"
-#include "appcontext.h"
+#include "utils/os/whonix.h"
#include "config-feather.h"
TorManager::TorManager(QObject *parent)
}
return m_instance;
-}
\ No newline at end of file
+}
+
+TorManager::~TorManager() {
+ qDebug() << "~TorManager";
+}
public:
explicit TorManager(QObject *parent = nullptr);
+ ~TorManager() override;
void init();
void start();
#include <QObject>
#include "nodes.h"
+#include "utils/AppData.h"
#include "utils/Utils.h"
#include "utils/os/tails.h"
-#include "appcontext.h"
+#include "utils/os/whonix.h"
#include "constants.h"
#include "utils/WebsocketNotifier.h"
#include "utils/TorManager.h"
obj[networkTypeStr] = netTypeObj;
}
-Nodes::Nodes(QObject *parent)
+Nodes::Nodes(QObject *parent, Wallet *wallet)
: QObject(parent)
, modelWebsocket(new NodeModel(NodeSource::websocket, this))
, modelCustom(new NodeModel(NodeSource::custom, this))
, m_connection(FeatherNode())
+ , m_wallet(wallet)
{
// TODO: This class is in desperate need of refactoring
this->loadConfig();
connect(websocketNotifier(), &WebsocketNotifier::NodesReceived, this, &Nodes::onWSNodesReceived);
-}
-void Nodes::setContext(AppContext *ctx) {
- m_ctx = ctx;
- connect(m_ctx, &AppContext::walletRefreshed, this, &Nodes::onWalletRefreshed);
+ if (m_wallet) {
+ connect(m_wallet, &Wallet::walletRefreshed, this, &Nodes::onWalletRefreshed);
+ }
}
void Nodes::loadConfig() {
}
void Nodes::connectToNode(const FeatherNode &node) {
- if (!m_ctx) {
+ if (!m_wallet) {
+ return;
+ }
+
+ if (!m_allowConnection) {
return;
}
qInfo() << QString("Attempting to connect to %1 (%2)").arg(node.toAddress(), node.custom ? "custom" : "ws");
if (!node.url.userName().isEmpty() && !node.url.password().isEmpty()) {
- m_ctx->wallet->setDaemonLogin(node.url.userName(), node.url.password());
+ m_wallet->setDaemonLogin(node.url.userName(), node.url.password());
}
// Don't use SSL over Tor/i2p
- m_ctx->wallet->setUseSSL(!node.isAnonymityNetwork());
+ m_wallet->setUseSSL(!node.isAnonymityNetwork());
QString proxyAddress;
if (useSocks5Proxy(node)) {
}
}
- m_ctx->wallet->initAsync(node.toAddress(), true, 0, false, false, 0, proxyAddress);
+ m_wallet->initAsync(node.toAddress(), true, 0, proxyAddress);
m_connection = node;
m_connection.isActive = false;
}
void Nodes::autoConnect(bool forceReconnect) {
- if (!m_ctx) {
+ if (!m_wallet) {
return;
}
// this function is responsible for automatically connecting to a daemon.
- if (m_ctx->wallet == nullptr || !m_enableAutoconnect) {
+ if (m_wallet == nullptr || !m_enableAutoconnect) {
return;
}
- Wallet::ConnectionStatus status = m_ctx->wallet->connectionStatus();
+ Wallet::ConnectionStatus status = m_wallet->connectionStatus();
bool wsMode = (this->source() == NodeSource::websocket);
if (wsMode && !m_wsNodesReceived && websocketNodes().count() == 0) {
}
if (privacyLevel == Config::allTorExceptInitSync) {
- if (m_ctx && m_ctx->refreshed) {
+ if (m_wallet && m_wallet->refreshedOnce) {
return true;
}
int initSyncThreshold = config()->get(Config::initSyncThreshold).toInt();
int networkHeight = appData()->heights[constants::networkType];
- if (m_ctx && m_ctx->wallet->blockChainHeight() > (networkHeight - initSyncThreshold)) {
+ if (m_wallet && m_wallet->blockChainHeight() > (networkHeight - initSyncThreshold)) {
return true;
}
}
}
return mode_height;
-}
\ No newline at end of file
+}
+
+void Nodes::allowConnection() {
+ m_allowConnection = true;
+}
+
+Nodes::~Nodes() {
+ qDebug() << "~Nodes";
+}
Q_OBJECT
public:
- explicit Nodes(QObject *parent = nullptr);
- void setContext(AppContext *ctx);
+ explicit Nodes(QObject *parent, Wallet *wallet);
+ ~Nodes() override;
+
void loadConfig();
+ void allowConnection();
NodeSource source();
FeatherNode connection();
void onWalletRefreshed();
private:
- AppContext *m_ctx = nullptr;
+ Wallet *m_wallet = nullptr;
QJsonObject m_configJson;
NodeList m_nodes;
bool m_wsNodesReceived = false;
bool m_enableAutoconnect = true;
+ bool m_allowConnection = false;
+
FeatherNode pickEligibleNode();
bool useOnionNodes();
#include <QScreen>
#include <QDesktopServices>
+#include "utils/config.h"
#include "utils/Utils.h"
#include "utils/xmrig.h"
#include "utils/TorManager.h"
-#include "appcontext.h"
XmRig::XmRig(const QString &configDir, QObject *parent)
: QObject(parent)
#include <QTableWidget>
#include "CCSProgressDelegate.h"
+#include "utils/Utils.h"
CCSWidget::CCSWidget(QWidget *parent)
: QWidget(parent)
QModelIndex index = ui->tableView->currentIndex();
auto entry = m_model->entry(index.row());
- if (entry)
+ if (entry) {
Utils::externalLinkWarning(this, entry->url);
+ }
}
void CCSWidget::donateClicked() {
#include <QProgressBar>
#include <QWidget>
-#include "appcontext.h"
#include "model/CCSModel.h"
#include "widgets/CCSEntry.h"
#include "utils/NetworkManager.h"
#include "utils/WebsocketNotifier.h"
-LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, QSharedPointer<AppContext> ctx)
+LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, Wallet *wallet)
: QWidget(parent)
, ui(new Ui::LocalMoneroWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
#include <QWidget>
#include "api/LocalMoneroApi.h"
-#include "appcontext.h"
#include "model/LocalMoneroModel.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class LocalMoneroWidget;
Q_OBJECT
public:
- explicit LocalMoneroWidget(QWidget *parent, QSharedPointer<AppContext> ctx);
+ explicit LocalMoneroWidget(QWidget *parent, Wallet *wallet);
~LocalMoneroWidget() override;
public slots:
void updatePaymentMethods();
QScopedPointer<Ui::LocalMoneroWidget> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
int m_currentPage = 0;
#include <QTreeView>
#include <QWidget>
-#include "appcontext.h"
#include "model/NodeModel.h"
#include "utils/nodes.h"
#include "constants.h"
#include "utils/AppData.h"
+#include "utils/config.h"
-TickerWidgetBase::TickerWidgetBase(QWidget *parent, QSharedPointer<AppContext> ctx)
+TickerWidgetBase::TickerWidgetBase(QWidget *parent, Wallet *wallet)
: QWidget(parent)
, ui(new Ui::TickerWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
{
ui->setupUi(this);
}
// BalanceTickerWidget
-BalanceTickerWidget::BalanceTickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, bool totalBalance)
- : TickerWidgetBase(parent, std::move(ctx))
+BalanceTickerWidget::BalanceTickerWidget(QWidget *parent, Wallet *wallet, bool totalBalance)
+ : TickerWidgetBase(parent, wallet)
, m_totalBalance(totalBalance)
{
if (totalBalance)
this->setPercentageVisible(false);
- connect(m_ctx.get(), &AppContext::balanceUpdated, this, &BalanceTickerWidget::updateDisplay);
+ connect(m_wallet, &Wallet::balanceUpdated, this, &BalanceTickerWidget::updateDisplay);
connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &BalanceTickerWidget::updateDisplay);
connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &BalanceTickerWidget::updateDisplay);
}
void BalanceTickerWidget::updateDisplay() {
- double balance = (m_totalBalance ? m_ctx->wallet->balanceAll() : m_ctx->wallet->balance()) / constants::cdiv;
+ double balance = (m_totalBalance ? m_wallet->balanceAll() : m_wallet->balance()) / constants::cdiv;
QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString();
double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balance);
if (balanceFiatAmount < 0)
}
// PriceTickerWidget
-PriceTickerWidget::PriceTickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, QString symbol)
- : TickerWidgetBase(parent, std::move(ctx))
+PriceTickerWidget::PriceTickerWidget(QWidget *parent, Wallet *wallet, QString symbol)
+ : TickerWidgetBase(parent, wallet)
, m_symbol(std::move(symbol))
{
this->setTitle(m_symbol);
}
//RatioTickerWidget
-RatioTickerWidget::RatioTickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, QString symbol1, QString symbol2)
- : TickerWidgetBase(parent, std::move(ctx))
+RatioTickerWidget::RatioTickerWidget(QWidget *parent, Wallet *wallet, QString symbol1, QString symbol2)
+ : TickerWidgetBase(parent, wallet)
, m_symbol1(std::move(symbol1))
, m_symbol2(std::move(symbol2))
{
#include <QWidget>
-#include "appcontext.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class TickerWidget;
Q_OBJECT
public:
- explicit TickerWidgetBase(QWidget *parent, QSharedPointer<AppContext> ctx);
+ explicit TickerWidgetBase(QWidget *parent, Wallet *wallet);
~TickerWidgetBase() override;
void setTitle(const QString &title);
QScopedPointer<Ui::TickerWidget> ui;
protected:
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
};
class BalanceTickerWidget : public TickerWidgetBase
Q_OBJECT
public:
- explicit BalanceTickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, bool totalBalance);
+ explicit BalanceTickerWidget(QWidget *parent, Wallet *wallet, bool totalBalance);
public slots:
void updateDisplay() override;
Q_OBJECT
public:
- explicit PriceTickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, QString symbol);
+ explicit PriceTickerWidget(QWidget *parent, Wallet *wallet, QString symbol);
public slots:
void updateDisplay() override;
Q_OBJECT
public:
- explicit RatioTickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, QString symbol1, QString symbol2);
+ explicit RatioTickerWidget(QWidget *parent, Wallet *wallet, QString symbol1, QString symbol2);
public slots:
void updateDisplay() override;
#include <QTableWidget>
#include "utils/Icons.h"
+#include "utils/Utils.h"
-XMRigWidget::XMRigWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
+XMRigWidget::XMRigWidget(Wallet *wallet, QWidget *parent)
: QWidget(parent)
, ui(new Ui::XMRigWidget)
- , m_ctx(std::move(ctx))
+ , m_wallet(wallet)
, m_XMRig(new XmRig(Config::defaultConfigDir().path()))
, m_model(new QStandardItemModel(this))
, m_contextMenu(new QMenu(this))
ui->relayTor->setChecked(config()->get(Config::xmrigNetworkTor).toBool());
// Receiving address
- auto username = m_ctx->wallet->getCacheAttribute("feather.xmrig_username");
+ auto username = m_wallet->getCacheAttribute("feather.xmrig_username");
if (!username.isEmpty()) {
ui->lineEdit_address->setText(username);
}
connect(ui->lineEdit_address, &QLineEdit::textChanged, [=]() {
- m_ctx->wallet->setCacheAttribute("feather.xmrig_username", ui->lineEdit_address->text());
+ m_wallet->setCacheAttribute("feather.xmrig_username", ui->lineEdit_address->text());
});
connect(ui->btn_fillPrimaryAddress, &QPushButton::clicked, this, &XMRigWidget::onUsePrimaryAddressClicked);
// Password
- auto password = m_ctx->wallet->getCacheAttribute("feather.xmrig_password");
+ auto password = m_wallet->getCacheAttribute("feather.xmrig_password");
if (!password.isEmpty()) {
ui->lineEdit_password->setText(password);
} else {
ui->lineEdit_password->setText("featherwallet");
- m_ctx->wallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text());
+ m_wallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text());
}
connect(ui->lineEdit_password, &QLineEdit::textChanged, [=]() {
- m_ctx->wallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text());
+ m_wallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text());
});
// [Status] tab
}
void XMRigWidget::onUsePrimaryAddressClicked() {
- ui->lineEdit_address->setText(m_ctx->wallet->address(0, 0));
+ ui->lineEdit_address->setText(m_wallet->address(0, 0));
}
void XMRigWidget::onStartClicked() {
}
// username is receiving address usually
- auto username = m_ctx->wallet->getCacheAttribute("feather.xmrig_username");
- auto password = m_ctx->wallet->getCacheAttribute("feather.xmrig_password");
+ auto username = m_wallet->getCacheAttribute("feather.xmrig_username");
+ auto password = m_wallet->getCacheAttribute("feather.xmrig_password");
if (username.isEmpty()) {
ui->console->appendPlainText("Please specify a receiving address on the Settings screen.");
if (address.contains("cryptonote.social") && !username.contains(".")) {
// cryptonote social requires <addr>.<username>, we'll just grab a few chars from primary addy
- username = QString("%1.%2").arg(username, m_ctx->wallet->address(0, 0).mid(0, 6));
+ username = QString("%1.%2").arg(username, m_wallet->address(0, 0).mid(0, 6));
}
int threads = ui->threadSlider->value();
#include <QMenu>
#include <QWidget>
#include <QItemSelection>
+#include <QStandardItemModel>
-#include "appcontext.h"
#include "utils/xmrig.h"
#include "utils/config.h"
+#include "libwalletqt/Wallet.h"
namespace Ui {
class XMRigWidget;
Q_OBJECT
public:
- explicit XMRigWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
+ explicit XMRigWidget(Wallet *wallet, QWidget *parent = nullptr);
~XMRigWidget() override;
QStandardItemModel *model();
bool checkXMRigPath();
QScopedPointer<Ui::XMRigWidget> ui;
- QSharedPointer<AppContext> m_ctx;
+ Wallet *m_wallet;
XmRig *m_XMRig;
QStandardItemModel *m_model;
QMenu *m_contextMenu;
#include <QWidget>
#include <QDir>
-#include "appcontext.h"
#include "WalletWizard.h"
namespace Ui {
#include <QWizardPage>
#include <QWidget>
-#include "appcontext.h"
-
namespace Ui {
class PageMenu;
}
#include <QWizardPage>
#include <QWidget>
-#include "appcontext.h"
#include "utils/nodes.h"
namespace Ui {
#include <QWizardPage>
-#include "appcontext.h"
-
namespace Ui {
class PageNetworkProxy;
}
#include <QWizardPage>
-#include "appcontext.h"
-
namespace Ui {
class PageNetworkWebsocket;
}
#define FEATHER_OPENWALLET_H
#include <QLabel>
+#include <QStandardItemModel>
#include <QWizardPage>
#include <QWidget>
-#include "appcontext.h"
#include "model/WalletKeysFilesModel.h"
namespace Ui {
#include <QWizardPage>
#include <QWidget>
-#include "appcontext.h"
#include "WalletWizard.h"
namespace Ui {
#include <QWizardPage>
#include <QWidget>
-#include "appcontext.h"
#include "WalletWizard.h"
namespace Ui {
#include <QWizardPage>
#include <QWidget>
-#include "appcontext.h"
#include "WalletWizard.h"
namespace Ui {
#include <QWizardPage>
#include <QWidget>
-#include "appcontext.h"
#include "WalletWizard.h"
namespace Ui {
#include <QWidget>
#include <QDir>
-#include "appcontext.h"
-
namespace Ui {
class PageWalletFile;
}
#include "WalletWizard.h"
#include "constants.h"
+#include "libwalletqt/WalletManager.h"
PageWalletRestoreKeys::PageWalletRestoreKeys(WizardFields *fields, QWidget *parent)
: QWizardPage(parent)
#include <QTextEdit>
#include <QCompleter>
-#include "appcontext.h"
#include "WalletWizard.h"
namespace Ui {
#include <QCompleter>
#include "utils/textedit.h"
-#include "appcontext.h"
namespace Ui {
class PageWalletRestoreSeed;
#include <QLabel>
#include <QRadioButton>
-#include "appcontext.h"
#include "model/WalletKeysFilesModel.h"
#include "utils/RestoreHeightLookup.h"
#include "utils/config.h"
+#include "utils/Seed.h"
#include "constants.h"
enum WizardMode {