mirror of
				https://git.wownero.com/wowlet/wowlet.git
				synced 2024-08-15 01:03:14 +00:00 
			
		
		
		
	Import wallet from keys (view-only)
Signed-off-by: dsc <dsc@xmr.pm>
This commit is contained in:
		
							parent
							
								
									d465639d2a
								
							
						
					
					
						commit
						eac29cd0b6
					
				
					 19 changed files with 619 additions and 23 deletions
				
			
		| 
						 | 
					@ -341,6 +341,13 @@ void AppContext::onWalletOpened(Wallet *wallet) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // force trigger preferredFiat signal for history model
 | 
					    // force trigger preferredFiat signal for history model
 | 
				
			||||||
    this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
 | 
					    this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // (window) title
 | 
				
			||||||
 | 
					    QFileInfo fileInfo(this->walletPath);
 | 
				
			||||||
 | 
					    auto title = QString("Feather - [%1]").arg(fileInfo.fileName());
 | 
				
			||||||
 | 
					    if(this->currentWallet->viewOnly())
 | 
				
			||||||
 | 
					        title += " [view-only]";
 | 
				
			||||||
 | 
					    emit setTitle(title);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AppContext::onWSMessage(const QJsonObject &msg) {
 | 
					void AppContext::onWSMessage(const QJsonObject &msg) {
 | 
				
			||||||
| 
						 | 
					@ -541,6 +548,43 @@ void AppContext::createWallet(FeatherSeed seed, const QString &path, const QStri
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this->createWalletFinish(password);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AppContext::createWalletViewOnly(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight) {
 | 
				
			||||||
 | 
					    if(Utils::fileExists(path)) {
 | 
				
			||||||
 | 
					        auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
 | 
				
			||||||
 | 
					        qCritical() << err;
 | 
				
			||||||
 | 
					        emit walletCreatedError(err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!this->walletManager->addressValid(address, this->networkType)) {
 | 
				
			||||||
 | 
					        auto err = QString("Failed to create wallet. Invalid address provided.").arg(path);
 | 
				
			||||||
 | 
					        qCritical() << err;
 | 
				
			||||||
 | 
					        emit walletCreatedError(err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!this->walletManager->keyValid(viewkey, address, true, this->networkType)) {
 | 
				
			||||||
 | 
					        auto err = QString("Failed to create wallet. Invalid viewkey provided.").arg(path);
 | 
				
			||||||
 | 
					        qCritical() << err;
 | 
				
			||||||
 | 
					        emit walletCreatedError(err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!spendkey.isEmpty() && !this->walletManager->keyValid(spendkey, address, false, this->networkType)) {
 | 
				
			||||||
 | 
					        auto err = QString("Failed to create wallet. Invalid spendkey provided.").arg(path);
 | 
				
			||||||
 | 
					        qCritical() << err;
 | 
				
			||||||
 | 
					        emit walletCreatedError(err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this->currentWallet = this->walletManager->createWalletFromKeys(path, this->seedLanguage, this->networkType, address, viewkey, spendkey, restoreHeight);
 | 
				
			||||||
 | 
					    this->createWalletFinish(password);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AppContext::createWalletFinish(const QString &password) {
 | 
				
			||||||
    this->currentWallet->setPassword(password);
 | 
					    this->currentWallet->setPassword(password);
 | 
				
			||||||
    this->currentWallet->store();
 | 
					    this->currentWallet->store();
 | 
				
			||||||
    this->walletPassword = password;
 | 
					    this->walletPassword = password;
 | 
				
			||||||
| 
						 | 
					@ -614,8 +658,9 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AppContext::donateBeg() {
 | 
					void AppContext::donateBeg() {
 | 
				
			||||||
    if(this->networkType != NetworkType::Type::MAINNET)
 | 
					    if(this->currentWallet == nullptr) return;
 | 
				
			||||||
        return;
 | 
					    if(this->networkType != NetworkType::Type::MAINNET) return;
 | 
				
			||||||
 | 
					    if(this->currentWallet->viewOnly()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto donationCounter = config()->get(Config::donateBeg).toInt();
 | 
					    auto donationCounter = config()->get(Config::donateBeg).toInt();
 | 
				
			||||||
    if(donationCounter == -1)
 | 
					    if(donationCounter == -1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +68,7 @@ public:
 | 
				
			||||||
    PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
 | 
					    PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
 | 
				
			||||||
    quint32 tx_mixin = static_cast<const quint32 &>(10);
 | 
					    quint32 tx_mixin = static_cast<const quint32 &>(10);
 | 
				
			||||||
    static constexpr const double cdiv = 1e12;
 | 
					    static constexpr const double cdiv = 1e12;
 | 
				
			||||||
 | 
					    QString seedLanguage = "English";  // 14 word `monero-seed` only has English
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QNetworkAccessManager *network;
 | 
					    QNetworkAccessManager *network;
 | 
				
			||||||
    QNetworkAccessManager *networkClearnet;
 | 
					    QNetworkAccessManager *networkClearnet;
 | 
				
			||||||
| 
						 | 
					@ -89,6 +90,8 @@ public:
 | 
				
			||||||
    WalletManager *walletManager;
 | 
					    WalletManager *walletManager;
 | 
				
			||||||
    Wallet *currentWallet = nullptr;
 | 
					    Wallet *currentWallet = nullptr;
 | 
				
			||||||
    void createWallet(FeatherSeed seed, const QString &path, const QString &password);
 | 
					    void createWallet(FeatherSeed seed, const QString &path, const QString &password);
 | 
				
			||||||
 | 
					    void createWalletViewOnly(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight);
 | 
				
			||||||
 | 
					    void createWalletFinish(const QString &password);
 | 
				
			||||||
    void syncStatusUpdated(quint64 height, quint64 target);
 | 
					    void syncStatusUpdated(quint64 height, quint64 target);
 | 
				
			||||||
    void updateBalance();
 | 
					    void updateBalance();
 | 
				
			||||||
    void initTor();
 | 
					    void initTor();
 | 
				
			||||||
| 
						 | 
					@ -160,6 +163,7 @@ signals:
 | 
				
			||||||
    void initiateTransaction();
 | 
					    void initiateTransaction();
 | 
				
			||||||
    void endTransaction();
 | 
					    void endTransaction();
 | 
				
			||||||
    void walletClosing();
 | 
					    void walletClosing();
 | 
				
			||||||
 | 
					    void setTitle(const QString &title); // set window title
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    void sorry();
 | 
					    void sorry();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/dialog/viewonlydialog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/dialog/viewonlydialog.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: BSD-3-Clause
 | 
				
			||||||
 | 
					// Copyright (c) 2020, The Monero Project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QFileDialog>
 | 
				
			||||||
 | 
					#include <QInputDialog>
 | 
				
			||||||
 | 
					#include <QMessageBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "viewonlydialog.h"
 | 
				
			||||||
 | 
					#include "ui_viewonlydialog.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent)
 | 
				
			||||||
 | 
					        : QDialog(parent)
 | 
				
			||||||
 | 
					        , ui(new Ui::ViewOnlyDialog), m_ctx(ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ui->setupUi(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight()));
 | 
				
			||||||
 | 
					    ui->label_primaryAddress->setText(ctx->currentWallet->address(0, 0));
 | 
				
			||||||
 | 
					    ui->label_secretViewKey->setText(ctx->currentWallet->getSecretViewKey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboad);
 | 
				
			||||||
 | 
					    connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui->btn_Save->setEnabled(!m_ctx->currentWallet->viewOnly());
 | 
				
			||||||
 | 
					    this->adjustSize();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ViewOnlyDialog::onWriteViewOnlyWallet(){
 | 
				
			||||||
 | 
					    QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", QDir::homePath(), "Monero wallet (*.keys)");
 | 
				
			||||||
 | 
					    if(fn.isEmpty()) return;
 | 
				
			||||||
 | 
					    if(!fn.endsWith(".keys")) fn += ".keys";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString passwd;
 | 
				
			||||||
 | 
					    QInputDialog passwordDialog(this);
 | 
				
			||||||
 | 
					    passwordDialog.setInputMode(QInputDialog::TextInput);
 | 
				
			||||||
 | 
					    passwordDialog.setTextEchoMode(QLineEdit::Password);
 | 
				
			||||||
 | 
					    passwordDialog.setWindowTitle("View-Only wallet password");
 | 
				
			||||||
 | 
					    passwordDialog.setLabelText("Protect this view-only wallet with a password?");
 | 
				
			||||||
 | 
					    passwordDialog.resize(300, 100);
 | 
				
			||||||
 | 
					    if((bool)passwordDialog.exec())
 | 
				
			||||||
 | 
					        passwd = passwordDialog.textValue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_ctx->currentWallet->createViewOnly(fn, passwd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMessageBox::information(this, "Information", "View-only wallet successfully written to disk.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ViewOnlyDialog::copyToClipboad() {
 | 
				
			||||||
 | 
					    QString text = "";
 | 
				
			||||||
 | 
					    text += QString("Address: %1\n").arg(ui->label_primaryAddress->text());
 | 
				
			||||||
 | 
					    text += QString("Secret view key: %1\n").arg(ui->label_secretViewKey->text());
 | 
				
			||||||
 | 
					    text += QString("Restore height: %1\n").arg(ui->label_restoreHeight->text());
 | 
				
			||||||
 | 
					    Utils::copyToClipboard(text);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ViewOnlyDialog::~ViewOnlyDialog()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    delete ui;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/dialog/viewonlydialog.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/dialog/viewonlydialog.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: BSD-3-Clause
 | 
				
			||||||
 | 
					// Copyright (c) 2020, The Monero Project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef FEATHER_VIEWONLYDIALOG_H
 | 
				
			||||||
 | 
					#define FEATHER_VIEWONLYDIALOG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDialog>
 | 
				
			||||||
 | 
					#include "appcontext.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ui {
 | 
				
			||||||
 | 
					    class ViewOnlyDialog;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ViewOnlyDialog : public QDialog
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit ViewOnlyDialog(AppContext *ctx, QWidget *parent = nullptr);
 | 
				
			||||||
 | 
					    ~ViewOnlyDialog() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
					    void onWriteViewOnlyWallet();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    Ui::ViewOnlyDialog *ui;
 | 
				
			||||||
 | 
					    AppContext *m_ctx = nullptr;
 | 
				
			||||||
 | 
					    void copyToClipboad();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //FEATHER_KEYSDIALOG_H
 | 
				
			||||||
							
								
								
									
										139
									
								
								src/dialog/viewonlydialog.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/dialog/viewonlydialog.ui
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,139 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>ViewOnlyDialog</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="ViewOnlyDialog">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>659</width>
 | 
				
			||||||
 | 
					    <height>254</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>View-Only</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QGroupBox" name="groupBox_6">
 | 
				
			||||||
 | 
					     <property name="title">
 | 
				
			||||||
 | 
					      <string>Restore height</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QHBoxLayout" name="horizontalLayout_6">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="label_restoreHeight">
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>TextLabel</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="textInteractionFlags">
 | 
				
			||||||
 | 
					         <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QGroupBox" name="groupBox">
 | 
				
			||||||
 | 
					     <property name="title">
 | 
				
			||||||
 | 
					      <string>Primary address</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QHBoxLayout" name="horizontalLayout">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="label_primaryAddress">
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>TextLabel</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="textInteractionFlags">
 | 
				
			||||||
 | 
					         <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QGroupBox" name="groupBox_2">
 | 
				
			||||||
 | 
					     <property name="title">
 | 
				
			||||||
 | 
					      <string>Secret view key</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QHBoxLayout" name="horizontalLayout_3">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="label_secretViewKey">
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>TextLabel</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="textInteractionFlags">
 | 
				
			||||||
 | 
					         <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QPushButton" name="btn_Copy">
 | 
				
			||||||
 | 
					       <property name="text">
 | 
				
			||||||
 | 
					        <string>Copy</string>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QPushButton" name="btn_Save">
 | 
				
			||||||
 | 
					       <property name="text">
 | 
				
			||||||
 | 
					        <string>Create view-only wallet</string>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					       <property name="orientation">
 | 
				
			||||||
 | 
					        <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <property name="standardButtons">
 | 
				
			||||||
 | 
					        <set>QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
 | 
					    </layout>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>ViewOnlyDialog</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>ViewOnlyDialog</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@
 | 
				
			||||||
#include "dialog/debuginfodialog.h"
 | 
					#include "dialog/debuginfodialog.h"
 | 
				
			||||||
#include "dialog/walletinfodialog.h"
 | 
					#include "dialog/walletinfodialog.h"
 | 
				
			||||||
#include "dialog/torinfodialog.h"
 | 
					#include "dialog/torinfodialog.h"
 | 
				
			||||||
 | 
					#include "dialog/viewonlydialog.h"
 | 
				
			||||||
#include "utils/utils.h"
 | 
					#include "utils/utils.h"
 | 
				
			||||||
#include "utils/config.h"
 | 
					#include "utils/config.h"
 | 
				
			||||||
#include "components.h"
 | 
					#include "components.h"
 | 
				
			||||||
| 
						 | 
					@ -325,6 +326,10 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
 | 
				
			||||||
    connect(m_ctx, &AppContext::walletClosing, [=]{
 | 
					    connect(m_ctx, &AppContext::walletClosing, [=]{
 | 
				
			||||||
        ui->tabWidget->setCurrentIndex(0);
 | 
					        ui->tabWidget->setCurrentIndex(0);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // window title
 | 
				
			||||||
 | 
					    connect(m_ctx, &AppContext::setTitle, this, &QMainWindow::setWindowTitle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // setup some UI
 | 
					    // setup some UI
 | 
				
			||||||
    this->initMain();
 | 
					    this->initMain();
 | 
				
			||||||
    this->initWidgets();
 | 
					    this->initWidgets();
 | 
				
			||||||
| 
						 | 
					@ -389,6 +394,7 @@ void MainWindow::initMenu() {
 | 
				
			||||||
    connect(ui->actionSeed, &QAction::triggered, this, &MainWindow::showSeedDialog);
 | 
					    connect(ui->actionSeed, &QAction::triggered, this, &MainWindow::showSeedDialog);
 | 
				
			||||||
    connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog);
 | 
					    connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog);
 | 
				
			||||||
    connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog);
 | 
					    connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog);
 | 
				
			||||||
 | 
					    connect(ui->actionViewOnly, &QAction::triggered, this, &MainWindow::showViewOnlyDialog);
 | 
				
			||||||
    connect(ui->actionStore_wallet, &QAction::triggered, [&]{
 | 
					    connect(ui->actionStore_wallet, &QAction::triggered, [&]{
 | 
				
			||||||
        m_ctx->currentWallet->store();
 | 
					        m_ctx->currentWallet->store();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -412,7 +418,8 @@ void MainWindow::initMenu() {
 | 
				
			||||||
    connect(ui->actionExport_CSV, &QAction::triggered, [=]{
 | 
					    connect(ui->actionExport_CSV, &QAction::triggered, [=]{
 | 
				
			||||||
        if(m_ctx->currentWallet == nullptr) return;
 | 
					        if(m_ctx->currentWallet == nullptr) return;
 | 
				
			||||||
        QString fn = QFileDialog::getSaveFileName(this, "Save CSV file", QDir::homePath(), "CSV (*.csv)");
 | 
					        QString fn = QFileDialog::getSaveFileName(this, "Save CSV file", QDir::homePath(), "CSV (*.csv)");
 | 
				
			||||||
        if(!fn.startsWith(".csv")) fn += ".csv";
 | 
					        if(fn.isEmpty()) return;
 | 
				
			||||||
 | 
					        if(!fn.endsWith(".csv")) fn += ".csv";
 | 
				
			||||||
        m_ctx->currentWallet->history()->writeCSV(fn);
 | 
					        m_ctx->currentWallet->history()->writeCSV(fn);
 | 
				
			||||||
        Utils::showMessageBox("CSV export", QString("Transaction history exported to %1").arg(fn), false);
 | 
					        Utils::showMessageBox("CSV export", QString("Transaction history exported to %1").arg(fn), false);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -543,10 +550,6 @@ void MainWindow::onWalletOpened() {
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        m_statusLabelStatus->setText("Wallet opened - Searching for node");
 | 
					        m_statusLabelStatus->setText("Wallet opened - Searching for node");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // window title as wallet name
 | 
					 | 
				
			||||||
    QFileInfo fileInfo(m_ctx->walletPath);
 | 
					 | 
				
			||||||
    this->setWindowTitle(QString("Feather - [%1]").arg(fileInfo.fileName()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    connect(m_ctx->currentWallet, &Wallet::connectionStatusChanged, this, &MainWindow::onConnectionStatusChanged);
 | 
					    connect(m_ctx->currentWallet, &Wallet::connectionStatusChanged, this, &MainWindow::onConnectionStatusChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // receive page
 | 
					    // receive page
 | 
				
			||||||
| 
						 | 
					@ -850,6 +853,12 @@ void MainWindow::showKeysDialog() {
 | 
				
			||||||
    dialog->deleteLater();
 | 
					    dialog->deleteLater();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWindow::showViewOnlyDialog() {
 | 
				
			||||||
 | 
					    auto *dialog = new ViewOnlyDialog(m_ctx, this);
 | 
				
			||||||
 | 
					    dialog->exec();
 | 
				
			||||||
 | 
					    dialog->deleteLater();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MainWindow::menuTorClicked() {
 | 
					void MainWindow::menuTorClicked() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto *dialog = new TorInfoDialog(m_ctx, this);
 | 
					    auto *dialog = new TorInfoDialog(m_ctx, this);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,6 +79,7 @@ public slots:
 | 
				
			||||||
    void showConnectionStatusDialog();
 | 
					    void showConnectionStatusDialog();
 | 
				
			||||||
    void showPasswordDialog();
 | 
					    void showPasswordDialog();
 | 
				
			||||||
    void showKeysDialog();
 | 
					    void showKeysDialog();
 | 
				
			||||||
 | 
					    void showViewOnlyDialog();
 | 
				
			||||||
    void donateButtonClicked();
 | 
					    void donateButtonClicked();
 | 
				
			||||||
    void showCalcWindow();
 | 
					    void showCalcWindow();
 | 
				
			||||||
    void showSendTab();
 | 
					    void showSendTab();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -291,7 +291,7 @@
 | 
				
			||||||
     <x>0</x>
 | 
					     <x>0</x>
 | 
				
			||||||
     <y>0</y>
 | 
					     <y>0</y>
 | 
				
			||||||
     <width>894</width>
 | 
					     <width>894</width>
 | 
				
			||||||
     <height>30</height>
 | 
					     <height>22</height>
 | 
				
			||||||
    </rect>
 | 
					    </rect>
 | 
				
			||||||
   </property>
 | 
					   </property>
 | 
				
			||||||
   <widget class="QMenu" name="menuFile">
 | 
					   <widget class="QMenu" name="menuFile">
 | 
				
			||||||
| 
						 | 
					@ -335,6 +335,7 @@
 | 
				
			||||||
    <addaction name="actionPassword"/>
 | 
					    <addaction name="actionPassword"/>
 | 
				
			||||||
    <addaction name="actionSeed"/>
 | 
					    <addaction name="actionSeed"/>
 | 
				
			||||||
    <addaction name="actionKeys"/>
 | 
					    <addaction name="actionKeys"/>
 | 
				
			||||||
 | 
					    <addaction name="actionViewOnly"/>
 | 
				
			||||||
    <addaction name="separator"/>
 | 
					    <addaction name="separator"/>
 | 
				
			||||||
    <addaction name="menuHistory"/>
 | 
					    <addaction name="menuHistory"/>
 | 
				
			||||||
    <addaction name="menuContacts"/>
 | 
					    <addaction name="menuContacts"/>
 | 
				
			||||||
| 
						 | 
					@ -518,6 +519,21 @@
 | 
				
			||||||
    <string>Debug info</string>
 | 
					    <string>Debug info</string>
 | 
				
			||||||
   </property>
 | 
					   </property>
 | 
				
			||||||
  </action>
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionCreate_view_only_details">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Details</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionCreate_view_only_wallet_file">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Export wallet file</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionViewOnly">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>View-Only</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 </widget>
 | 
					 </widget>
 | 
				
			||||||
 <layoutdefault spacing="6" margin="11"/>
 | 
					 <layoutdefault spacing="6" margin="11"/>
 | 
				
			||||||
 <customwidgets>
 | 
					 <customwidgets>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,16 +84,16 @@ struct FeatherSeed {
 | 
				
			||||||
    time_t time = 0;
 | 
					    time_t time = 0;
 | 
				
			||||||
    unsigned int restoreHeight = 0;
 | 
					    unsigned int restoreHeight = 0;
 | 
				
			||||||
    RestoreHeightLookup *lookup = nullptr;
 | 
					    RestoreHeightLookup *lookup = nullptr;
 | 
				
			||||||
    QString language = "English";
 | 
					    QString language;
 | 
				
			||||||
    std::string coinName;
 | 
					    std::string coinName;
 | 
				
			||||||
    explicit FeatherSeed(RestoreHeightLookup *lookup, const std::string &coinName = "monero") : lookup(lookup), coinName(coinName) {}
 | 
					    explicit FeatherSeed(RestoreHeightLookup *lookup, const std::string &coinName = "monero", const QString &language = "English") : lookup(lookup), coinName(coinName), language(language) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static FeatherSeed fromSeed(RestoreHeightLookup *lookup,
 | 
					    static FeatherSeed fromSeed(RestoreHeightLookup *lookup,
 | 
				
			||||||
                                const std::string &coinName,
 | 
					                                const std::string &coinName,
 | 
				
			||||||
 | 
					                                const QString &seedLanguage,
 | 
				
			||||||
                                const std::string &mnemonicSeed) {
 | 
					                                const std::string &mnemonicSeed) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto rtn = FeatherSeed(lookup, coinName);
 | 
					        auto rtn = FeatherSeed(lookup, coinName, seedLanguage);
 | 
				
			||||||
        rtn.coinName = coinName;
 | 
					 | 
				
			||||||
        rtn.lookup = lookup;
 | 
					        rtn.lookup = lookup;
 | 
				
			||||||
        rtn.mnemonicSeed = QString::fromStdString(mnemonicSeed);
 | 
					        rtn.mnemonicSeed = QString::fromStdString(mnemonicSeed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,8 +108,8 @@ struct FeatherSeed {
 | 
				
			||||||
        return rtn;
 | 
					        return rtn;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static FeatherSeed generate(RestoreHeightLookup *lookup, const std::string &coinName) {
 | 
					    static FeatherSeed generate(RestoreHeightLookup *lookup, const std::string &coinName, const QString &language) {
 | 
				
			||||||
        auto rtn = FeatherSeed(lookup, coinName);
 | 
					        auto rtn = FeatherSeed(lookup, coinName, language);
 | 
				
			||||||
        time_t _time = std::time(nullptr);
 | 
					        time_t _time = std::time(nullptr);
 | 
				
			||||||
        monero_seed seed(_time, coinName);
 | 
					        monero_seed seed(_time, coinName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,7 +130,7 @@ struct FeatherSeed {
 | 
				
			||||||
        if(this->lookup == nullptr) return wallet;
 | 
					        if(this->lookup == nullptr) return wallet;
 | 
				
			||||||
        if(this->mnemonicSeed.split(" ").count() == 14) {
 | 
					        if(this->mnemonicSeed.split(" ").count() == 14) {
 | 
				
			||||||
            if(this->spendKey.isEmpty()) {
 | 
					            if(this->spendKey.isEmpty()) {
 | 
				
			||||||
                auto _seed = FeatherSeed::fromSeed(this->lookup, this->coinName, this->mnemonicSeed.toStdString());
 | 
					                auto _seed = FeatherSeed::fromSeed(this->lookup, this->coinName, this->language, this->mnemonicSeed.toStdString());
 | 
				
			||||||
                _seed.setRestoreHeight();
 | 
					                _seed.setRestoreHeight();
 | 
				
			||||||
                this->time = _seed.time;
 | 
					                this->time = _seed.time;
 | 
				
			||||||
                this->restoreHeight = _seed.restoreHeight;
 | 
					                this->restoreHeight = _seed.restoreHeight;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,7 +82,12 @@ bool CreateWalletPage::validateWidgets(){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int CreateWalletPage::nextId() const {
 | 
					int CreateWalletPage::nextId() const {
 | 
				
			||||||
    auto restoredSeed = this->field("mnemonicRestoredSeed").toString();
 | 
					    auto restoredSeed = this->field("mnemonicRestoredSeed").toString();
 | 
				
			||||||
    return restoredSeed.isEmpty() ? WalletWizard::Page_CreateWalletSeed : -1;
 | 
					    auto restoredViewOnlyKey = this->field("viewOnlyViewKey").toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!restoredSeed.isEmpty() || !restoredViewOnlyKey.isEmpty())
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return WalletWizard::Page_CreateWalletSeed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool CreateWalletPage::validatePage() {
 | 
					bool CreateWalletPage::validatePage() {
 | 
				
			||||||
| 
						 | 
					@ -93,6 +98,7 @@ bool CreateWalletPage::validatePage() {
 | 
				
			||||||
    ui->walletName->setStyleSheet("");
 | 
					    ui->walletName->setStyleSheet("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto restoredSeed = this->field("mnemonicRestoredSeed").toString();
 | 
					    auto restoredSeed = this->field("mnemonicRestoredSeed").toString();
 | 
				
			||||||
    if(!restoredSeed.isEmpty()) emit createWallet();
 | 
					    auto restoredViewOnlyKey = this->field("viewOnlyViewKey").toString();
 | 
				
			||||||
 | 
					    if(!restoredSeed.isEmpty() || !restoredViewOnlyKey.isEmpty()) emit createWallet();
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,7 @@ CreateWalletSeedPage::CreateWalletSeedPage(AppContext *ctx, QWidget *parent) :
 | 
				
			||||||
void CreateWalletSeedPage::seedRoulette(int count) {
 | 
					void CreateWalletSeedPage::seedRoulette(int count) {
 | 
				
			||||||
    count += 1;
 | 
					    count += 1;
 | 
				
			||||||
    if(count > m_rouletteSpin) return;
 | 
					    if(count > m_rouletteSpin) return;
 | 
				
			||||||
    auto seed = FeatherSeed::generate(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString());
 | 
					    auto seed = FeatherSeed::generate(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString(), m_ctx->seedLanguage);
 | 
				
			||||||
    m_mnemonic = seed.mnemonicSeed;
 | 
					    m_mnemonic = seed.mnemonicSeed;
 | 
				
			||||||
    m_restoreHeight = seed.restoreHeight;
 | 
					    m_restoreHeight = seed.restoreHeight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,8 @@ int MenuPage::nextId() const {
 | 
				
			||||||
        return WalletWizard::Page_CreateWallet;
 | 
					        return WalletWizard::Page_CreateWallet;
 | 
				
			||||||
    if(ui->radioSeed->isChecked())
 | 
					    if(ui->radioSeed->isChecked())
 | 
				
			||||||
        return WalletWizard::Page_Restore;
 | 
					        return WalletWizard::Page_Restore;
 | 
				
			||||||
 | 
					    if(ui->radioViewOnly->isChecked())
 | 
				
			||||||
 | 
					        return WalletWizard::Page_ViewOnly;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +48,13 @@
 | 
				
			||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QRadioButton" name="radioViewOnly">
 | 
				
			||||||
 | 
					     <property name="text">
 | 
				
			||||||
 | 
					      <string>Import from keys</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
   <item>
 | 
					   <item>
 | 
				
			||||||
    <spacer name="verticalSpacer">
 | 
					    <spacer name="verticalSpacer">
 | 
				
			||||||
     <property name="orientation">
 | 
					     <property name="orientation">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,7 +130,7 @@ bool RestorePage::validatePage() {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto _seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], "monero", seed.toStdString());
 | 
					        auto _seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString(), m_ctx->seedLanguage, seed.toStdString());
 | 
				
			||||||
        restoreHeight = _seed.restoreHeight;
 | 
					        restoreHeight = _seed.restoreHeight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this->setField("restoreHeight", restoreHeight);
 | 
					        this->setField("restoreHeight", restoreHeight);
 | 
				
			||||||
| 
						 | 
					@ -153,7 +153,7 @@ bool RestorePage::validatePage() {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto _seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], "monero", seed.toStdString());
 | 
					        auto _seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString(), m_ctx->seedLanguage, seed.toStdString());
 | 
				
			||||||
        _seed.setRestoreHeight(restoreHeight);
 | 
					        _seed.setRestoreHeight(restoreHeight);
 | 
				
			||||||
        this->setField("restoreHeight", restoreHeight);
 | 
					        this->setField("restoreHeight", restoreHeight);
 | 
				
			||||||
        this->setField("mnemonicSeed", seed);
 | 
					        this->setField("mnemonicSeed", seed);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										106
									
								
								src/wizard/viewonlywallet.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/wizard/viewonlywallet.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,106 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: BSD-3-Clause
 | 
				
			||||||
 | 
					// Copyright (c) 2020, The Monero Project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "wizard/viewonlywallet.h"
 | 
				
			||||||
 | 
					#include "wizard/walletwizard.h"
 | 
				
			||||||
 | 
					#include "ui_viewonlywallet.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QLineEdit>
 | 
				
			||||||
 | 
					#include <QPlainTextEdit>
 | 
				
			||||||
 | 
					#include <QTextCharFormat>
 | 
				
			||||||
 | 
					#include <QPushButton>
 | 
				
			||||||
 | 
					#include <QButtonGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <monero_seed/wordlist.hpp>  // tevador 14 word
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libwalletqt/WalletManager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ViewOnlyPage::ViewOnlyPage(AppContext *ctx, QWidget *parent) :
 | 
				
			||||||
 | 
					        QWizardPage(parent),
 | 
				
			||||||
 | 
					        ui(new Ui::ViewOnlyPage),
 | 
				
			||||||
 | 
					        m_ctx(ctx) {
 | 
				
			||||||
 | 
					    ui->setupUi(this);
 | 
				
			||||||
 | 
					    this->setTitle("Import view only wallet");
 | 
				
			||||||
 | 
					    ui->label_errorString->hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFont f("feather");
 | 
				
			||||||
 | 
					    f.setStyleHint(QFont::Monospace);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto *viewOnlyViewKeyDummy = new QLineEdit(this);
 | 
				
			||||||
 | 
					    viewOnlyViewKeyDummy->setVisible(false);
 | 
				
			||||||
 | 
					    auto *viewOnlySpendKeyDummy = new QLineEdit(this);
 | 
				
			||||||
 | 
					    viewOnlySpendKeyDummy->setVisible(false);
 | 
				
			||||||
 | 
					    auto *viewOnlyAddressDummy = new QLineEdit(this);
 | 
				
			||||||
 | 
					    viewOnlyAddressDummy->setVisible(false);
 | 
				
			||||||
 | 
					    auto *restoreHeightDummy = new QLineEdit(this);
 | 
				
			||||||
 | 
					    restoreHeightDummy->setVisible(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this->registerField("viewOnlySpendKey", viewOnlySpendKeyDummy);
 | 
				
			||||||
 | 
					    this->registerField("viewOnlyViewKey", viewOnlyViewKeyDummy);
 | 
				
			||||||
 | 
					    this->registerField("viewOnlyAddress", viewOnlyAddressDummy);
 | 
				
			||||||
 | 
					    this->registerField("viewOnlyHeight", restoreHeightDummy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef QT_NO_CURSOR
 | 
				
			||||||
 | 
					    QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
 | 
				
			||||||
 | 
					    QGuiApplication::restoreOverrideCursor();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(m_ctx->networkType == NetworkType::Type::TESTNET) {
 | 
				
			||||||
 | 
					        ui->restoreHeightWidget->hideSlider();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // load restoreHeight lookup db
 | 
				
			||||||
 | 
					        ui->restoreHeightWidget->initRestoreHeights(m_ctx->restoreHeights[m_ctx->networkType]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(m_ctx->networkType == NetworkType::Type::MAINNET) {
 | 
				
			||||||
 | 
					        ui->lineEdit_address->setPlaceholderText("4...");
 | 
				
			||||||
 | 
					    } else if (m_ctx->networkType == NetworkType::Type::STAGENET) {
 | 
				
			||||||
 | 
					        ui->lineEdit_address->setPlaceholderText("5...");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ViewOnlyPage::nextId() const {
 | 
				
			||||||
 | 
					    return WalletWizard::Page_CreateWallet;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ViewOnlyPage::cleanupPage() const {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ViewOnlyPage::validatePage() {
 | 
				
			||||||
 | 
					    auto errStyle = "QLineEdit{border: 1px solid red;}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui->lineEdit_address->setStyleSheet("");
 | 
				
			||||||
 | 
					    ui->lineEdit_viewkey->setStyleSheet("");
 | 
				
			||||||
 | 
					    ui->label_errorString->hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned int restoreHeight = ui->restoreHeightWidget->getHeight();
 | 
				
			||||||
 | 
					    auto spendkey = ui->lineEdit_spendkey->text().trimmed();
 | 
				
			||||||
 | 
					    auto viewkey = ui->lineEdit_viewkey->text().trimmed();
 | 
				
			||||||
 | 
					    auto address = ui->lineEdit_address->text().trimmed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!m_ctx->walletManager->addressValid(address, m_ctx->networkType)){
 | 
				
			||||||
 | 
					        ui->label_errorString->show();
 | 
				
			||||||
 | 
					        ui->label_errorString->setText("Invalid address.");
 | 
				
			||||||
 | 
					        ui->lineEdit_address->setStyleSheet(errStyle);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!m_ctx->walletManager->keyValid(viewkey, address, true, m_ctx->networkType)) {
 | 
				
			||||||
 | 
					        ui->label_errorString->show();
 | 
				
			||||||
 | 
					        ui->label_errorString->setText("Invalid key.");
 | 
				
			||||||
 | 
					        ui->lineEdit_viewkey->setStyleSheet(errStyle);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!spendkey.isEmpty() && !m_ctx->walletManager->keyValid(spendkey, address, false, m_ctx->networkType)) {
 | 
				
			||||||
 | 
					        ui->label_errorString->show();
 | 
				
			||||||
 | 
					        ui->label_errorString->setText("Invalid key.");
 | 
				
			||||||
 | 
					        ui->lineEdit_viewkey->setStyleSheet(errStyle);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this->setField("viewOnlyViewKey", viewkey);
 | 
				
			||||||
 | 
					    this->setField("viewOnlySpendKey", spendkey);
 | 
				
			||||||
 | 
					    this->setField("viewOnlyAddress", address);
 | 
				
			||||||
 | 
					    this->setField("viewOnlyHeight", restoreHeight);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								src/wizard/viewonlywallet.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/wizard/viewonlywallet.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: BSD-3-Clause
 | 
				
			||||||
 | 
					// Copyright (c) 2020, The Monero Project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef FEATHER_WIZARDVIEWONLY_H
 | 
				
			||||||
 | 
					#define FEATHER_WIZARDVIEWONLY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QtCore>
 | 
				
			||||||
 | 
					#include <QLabel>
 | 
				
			||||||
 | 
					#include <QWizardPage>
 | 
				
			||||||
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					#include <QTextEdit>
 | 
				
			||||||
 | 
					#include <QCompleter>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "appcontext.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ui {
 | 
				
			||||||
 | 
					    class ViewOnlyPage;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ViewOnlyPage : public QWizardPage
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit ViewOnlyPage(AppContext *ctx, QWidget *parent = nullptr);
 | 
				
			||||||
 | 
					    bool validatePage() override;
 | 
				
			||||||
 | 
					    int nextId() const override;
 | 
				
			||||||
 | 
					    void cleanupPage() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    AppContext *m_ctx;
 | 
				
			||||||
 | 
					    QLabel *topLabel;
 | 
				
			||||||
 | 
					    Ui::ViewOnlyPage *ui;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										119
									
								
								src/wizard/viewonlywallet.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/wizard/viewonlywallet.ui
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,119 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>ViewOnlyPage</class>
 | 
				
			||||||
 | 
					 <widget class="QWizardPage" name="ViewOnlyPage">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>502</width>
 | 
				
			||||||
 | 
					    <height>506</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>ViewOnlyPage</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLabel" name="label">
 | 
				
			||||||
 | 
					     <property name="text">
 | 
				
			||||||
 | 
					      <string>Standard address</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLineEdit" name="lineEdit_address"/>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLabel" name="label_2">
 | 
				
			||||||
 | 
					     <property name="text">
 | 
				
			||||||
 | 
					      <string>Secret view key</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLineEdit" name="lineEdit_viewkey"/>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLabel" name="label_3">
 | 
				
			||||||
 | 
					     <property name="text">
 | 
				
			||||||
 | 
					      <string>Secret spend key (optional)</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLineEdit" name="lineEdit_spendkey"/>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="restoreFrame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::NoFrame</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Plain</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="lineWidth">
 | 
				
			||||||
 | 
					      <number>0</number>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <property name="leftMargin">
 | 
				
			||||||
 | 
					       <number>0</number>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <property name="topMargin">
 | 
				
			||||||
 | 
					       <number>0</number>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <property name="rightMargin">
 | 
				
			||||||
 | 
					       <number>0</number>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <property name="bottomMargin">
 | 
				
			||||||
 | 
					       <number>0</number>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="RestoreHeightWidget" name="restoreHeightWidget" native="true"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="label_restoreHeightInfo">
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>You may specify the "restore height". This is the moment the wallet was created, expressed through a blockheight (number). This speeds up wallet refreshes. If you don't know, leave it empty.</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="wordWrap">
 | 
				
			||||||
 | 
					         <bool>true</bool>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLabel" name="label_errorString">
 | 
				
			||||||
 | 
					     <property name="text">
 | 
				
			||||||
 | 
					      <string>errorString</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <spacer name="verticalSpacer">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Vertical</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="sizeHint" stdset="0">
 | 
				
			||||||
 | 
					      <size>
 | 
				
			||||||
 | 
					       <width>20</width>
 | 
				
			||||||
 | 
					       <height>40</height>
 | 
				
			||||||
 | 
					      </size>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </spacer>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <customwidgets>
 | 
				
			||||||
 | 
					  <customwidget>
 | 
				
			||||||
 | 
					   <class>RestoreHeightWidget</class>
 | 
				
			||||||
 | 
					   <extends>QWidget</extends>
 | 
				
			||||||
 | 
					   <header>widgets/restoreheightwidget.h</header>
 | 
				
			||||||
 | 
					   <container>1</container>
 | 
				
			||||||
 | 
					  </customwidget>
 | 
				
			||||||
 | 
					 </customwidgets>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections/>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
| 
						 | 
					@ -9,9 +9,11 @@
 | 
				
			||||||
#include "wizard/network.h"
 | 
					#include "wizard/network.h"
 | 
				
			||||||
#include "wizard/createwalletseed.h"
 | 
					#include "wizard/createwalletseed.h"
 | 
				
			||||||
#include "wizard/restorewallet.h"
 | 
					#include "wizard/restorewallet.h"
 | 
				
			||||||
 | 
					#include "wizard/viewonlywallet.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QStyle>
 | 
					#include <QStyle>
 | 
				
			||||||
#include <QLabel>
 | 
					#include <QLabel>
 | 
				
			||||||
 | 
					#include <QLineEdit>
 | 
				
			||||||
#include <QVBoxLayout>
 | 
					#include <QVBoxLayout>
 | 
				
			||||||
#include <QScreen>
 | 
					#include <QScreen>
 | 
				
			||||||
#include <QApplication>
 | 
					#include <QApplication>
 | 
				
			||||||
| 
						 | 
					@ -29,6 +31,7 @@ WalletWizard::WalletWizard(AppContext *ctx, WalletWizard::Page startPage, QWidge
 | 
				
			||||||
    setPage(Page_CreateWalletSeed, createWalletSeed);
 | 
					    setPage(Page_CreateWalletSeed, createWalletSeed);
 | 
				
			||||||
    setPage(Page_Network, new NetworkPage(m_ctx, this));
 | 
					    setPage(Page_Network, new NetworkPage(m_ctx, this));
 | 
				
			||||||
    setPage(Page_Restore, new RestorePage(m_ctx, this));
 | 
					    setPage(Page_Restore, new RestorePage(m_ctx, this));
 | 
				
			||||||
 | 
					    setPage(Page_ViewOnly, new ViewOnlyPage(m_ctx, this));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(config()->get(Config::firstRun).toUInt())
 | 
					    if(config()->get(Config::firstRun).toUInt())
 | 
				
			||||||
        setStartId(Page_Network);
 | 
					        setStartId(Page_Network);
 | 
				
			||||||
| 
						 | 
					@ -58,8 +61,20 @@ void WalletWizard::createWallet() {
 | 
				
			||||||
    const auto walletPath = this->field("walletPath").toString();
 | 
					    const auto walletPath = this->field("walletPath").toString();
 | 
				
			||||||
    const auto walletPasswd = this->field("walletPasswd").toString();
 | 
					    const auto walletPasswd = this->field("walletPasswd").toString();
 | 
				
			||||||
    auto restoreHeight = this->field("restoreHeight").toUInt();
 | 
					    auto restoreHeight = this->field("restoreHeight").toUInt();
 | 
				
			||||||
 | 
					    auto viewKey = this->field("viewOnlyViewKey").toString();
 | 
				
			||||||
 | 
					    auto spendKey = this->field("viewOnlySpendKey").toString();
 | 
				
			||||||
 | 
					    auto viewAddress = this->field("viewOnlyAddress").toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString(), mnemonicSeed.toStdString());
 | 
					    if(!viewKey.isEmpty() && !viewAddress.isEmpty()) {
 | 
				
			||||||
 | 
					        auto viewHeight = this->field("viewOnlyHeight").toUInt();
 | 
				
			||||||
 | 
					        m_ctx->createWalletViewOnly(walletPath,
 | 
				
			||||||
 | 
					                                    walletPasswd,
 | 
				
			||||||
 | 
					                                    viewAddress,
 | 
				
			||||||
 | 
					                                    viewKey, spendKey, viewHeight);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto seed = FeatherSeed::fromSeed(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName.toStdString(), m_ctx->seedLanguage, mnemonicSeed.toStdString());
 | 
				
			||||||
    if(restoreHeight > 0)
 | 
					    if(restoreHeight > 0)
 | 
				
			||||||
        seed.setRestoreHeight(restoreHeight);
 | 
					        seed.setRestoreHeight(restoreHeight);
 | 
				
			||||||
    m_ctx->createWallet(seed, walletPath, walletPasswd);
 | 
					    m_ctx->createWallet(seed, walletPath, walletPasswd);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@ class WalletWizard : public QWizard
 | 
				
			||||||
    Q_OBJECT
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    enum Page { Page_Menu, Page_CreateWallet, Page_CreateWalletSeed, Page_OpenWallet, Page_Network, Page_Restore };
 | 
					    enum Page { Page_Menu, Page_CreateWallet, Page_CreateWalletSeed, Page_OpenWallet, Page_Network, Page_Restore, Page_ViewOnly };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    explicit WalletWizard(AppContext *ctx, WalletWizard::Page startPage = WalletWizard::Page::Page_Menu, QWidget *parent = nullptr);
 | 
					    explicit WalletWizard(AppContext *ctx, WalletWizard::Page startPage = WalletWizard::Page::Page_Menu, QWidget *parent = nullptr);
 | 
				
			||||||
signals:
 | 
					signals:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue