mirror of
https://github.com/monero-project/monero-gui.git
synced 2024-11-16 15:58:11 +00:00
GUI cold signing
This commit is contained in:
parent
fd983955b4
commit
15c79df378
10 changed files with 454 additions and 35 deletions
4
main.cpp
4
main.cpp
|
@ -40,6 +40,7 @@
|
||||||
#include "Wallet.h"
|
#include "Wallet.h"
|
||||||
#include "QRCodeImageProvider.h"
|
#include "QRCodeImageProvider.h"
|
||||||
#include "PendingTransaction.h"
|
#include "PendingTransaction.h"
|
||||||
|
#include "UnsignedTransaction.h"
|
||||||
#include "TranslationManager.h"
|
#include "TranslationManager.h"
|
||||||
#include "TransactionInfo.h"
|
#include "TransactionInfo.h"
|
||||||
#include "TransactionHistory.h"
|
#include "TransactionHistory.h"
|
||||||
|
@ -72,6 +73,9 @@ int main(int argc, char *argv[])
|
||||||
qmlRegisterUncreatableType<PendingTransaction>("moneroComponents.PendingTransaction", 1, 0, "PendingTransaction",
|
qmlRegisterUncreatableType<PendingTransaction>("moneroComponents.PendingTransaction", 1, 0, "PendingTransaction",
|
||||||
"PendingTransaction can't be instantiated directly");
|
"PendingTransaction can't be instantiated directly");
|
||||||
|
|
||||||
|
qmlRegisterUncreatableType<UnsignedTransaction>("moneroComponents.UnsignedTransaction", 1, 0, "UnsignedTransaction",
|
||||||
|
"UnsignedTransaction can't be instantiated directly");
|
||||||
|
|
||||||
qmlRegisterUncreatableType<WalletManager>("moneroComponents.WalletManager", 1, 0, "WalletManager",
|
qmlRegisterUncreatableType<WalletManager>("moneroComponents.WalletManager", 1, 0, "WalletManager",
|
||||||
"WalletManager can't be instantiated directly");
|
"WalletManager can't be instantiated directly");
|
||||||
|
|
||||||
|
|
64
main.qml
64
main.qml
|
@ -228,6 +228,8 @@ ApplicationWindow {
|
||||||
currentWallet = wallet
|
currentWallet = wallet
|
||||||
updateSyncing(false)
|
updateSyncing(false)
|
||||||
|
|
||||||
|
viewOnly = currentWallet.viewOnly;
|
||||||
|
|
||||||
// connect handlers
|
// connect handlers
|
||||||
currentWallet.refreshed.connect(onWalletRefresh)
|
currentWallet.refreshed.connect(onWalletRefresh)
|
||||||
currentWallet.updated.connect(onWalletUpdate)
|
currentWallet.updated.connect(onWalletUpdate)
|
||||||
|
@ -293,7 +295,6 @@ ApplicationWindow {
|
||||||
|
|
||||||
// wallet opened successfully, subscribing for wallet updates
|
// wallet opened successfully, subscribing for wallet updates
|
||||||
connectWallet(wallet)
|
connectWallet(wallet)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -474,7 +475,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
|
|
||||||
// called on "transfer"
|
// called on "transfer"
|
||||||
function handlePayment(address, paymentId, amount, mixinCount, priority, description) {
|
function handlePayment(address, paymentId, amount, mixinCount, priority, description, createFile) {
|
||||||
console.log("Creating transaction: ")
|
console.log("Creating transaction: ")
|
||||||
console.log("\taddress: ", address,
|
console.log("\taddress: ", address,
|
||||||
", payment_id: ", paymentId,
|
", payment_id: ", paymentId,
|
||||||
|
@ -522,6 +523,24 @@ ApplicationWindow {
|
||||||
currentWallet.createTransactionAsync(address, paymentId, amountxmr, mixinCount, priority);
|
currentWallet.createTransactionAsync(address, paymentId, amountxmr, mixinCount, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Choose where to save transaction
|
||||||
|
FileDialog {
|
||||||
|
id: saveTxDialog
|
||||||
|
title: "Please choose a location"
|
||||||
|
folder: "file://" +moneroAccountsDir
|
||||||
|
selectExisting: false;
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
handleTransactionConfirmed()
|
||||||
|
}
|
||||||
|
onRejected: {
|
||||||
|
// do nothing
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function handleSweepUnmixable() {
|
function handleSweepUnmixable() {
|
||||||
console.log("Creating transaction: ")
|
console.log("Creating transaction: ")
|
||||||
|
|
||||||
|
@ -562,7 +581,7 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
// called after user confirms transaction
|
// called after user confirms transaction
|
||||||
function handleTransactionConfirmed() {
|
function handleTransactionConfirmed(fileName) {
|
||||||
// grab transaction.txid before commit, since it clears it.
|
// grab transaction.txid before commit, since it clears it.
|
||||||
// we actually need to copy it, because QML will incredibly
|
// we actually need to copy it, because QML will incredibly
|
||||||
// call the function multiple times when the variable is used
|
// call the function multiple times when the variable is used
|
||||||
|
@ -573,6 +592,20 @@ ApplicationWindow {
|
||||||
for (var i = 0; i < txid_org.length; ++i)
|
for (var i = 0; i < txid_org.length; ++i)
|
||||||
txid[i] = txid_org[i]
|
txid[i] = txid_org[i]
|
||||||
|
|
||||||
|
// View only wallet - we save the tx
|
||||||
|
if(viewOnly && saveTxDialog.fileUrl){
|
||||||
|
// No file specified - abort
|
||||||
|
if(!saveTxDialog.fileUrl) {
|
||||||
|
currentWallet.disposeTransaction(transaction)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = walletManager.urlToLocalPath(saveTxDialog.fileUrl)
|
||||||
|
|
||||||
|
// Store to file
|
||||||
|
transaction.setFilename(path);
|
||||||
|
}
|
||||||
|
|
||||||
if (!transaction.commit()) {
|
if (!transaction.commit()) {
|
||||||
console.log("Error committing transaction: " + transaction.errorString);
|
console.log("Error committing transaction: " + transaction.errorString);
|
||||||
informationPopup.title = qsTr("Error") + translationManager.emptyString
|
informationPopup.title = qsTr("Error") + translationManager.emptyString
|
||||||
|
@ -585,7 +618,7 @@ ApplicationWindow {
|
||||||
txid_text += ", "
|
txid_text += ", "
|
||||||
txid_text += txid[i]
|
txid_text += txid[i]
|
||||||
}
|
}
|
||||||
informationPopup.text = qsTr("Money sent successfully: %1 transaction(s) ").arg(txid.length) + txid_text + translationManager.emptyString
|
informationPopup.text = (viewOnly)? qsTr("Transaction saved to file: %1").arg(path) : qsTr("Money sent successfully: %1 transaction(s) ").arg(txid.length) + txid_text + translationManager.emptyString
|
||||||
informationPopup.icon = StandardIcon.Information
|
informationPopup.icon = StandardIcon.Information
|
||||||
if (transactionDescription.length > 0) {
|
if (transactionDescription.length > 0) {
|
||||||
for (var i = 0; i < txid.length; ++i)
|
for (var i = 0; i < txid.length; ++i)
|
||||||
|
@ -771,10 +804,31 @@ ApplicationWindow {
|
||||||
id: transactionConfirmationPopup
|
id: transactionConfirmationPopup
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
close();
|
close();
|
||||||
handleTransactionConfirmed()
|
|
||||||
|
// Save transaction to file if view only wallet
|
||||||
|
if(viewOnly) {
|
||||||
|
saveTxDialog.open();
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
handleTransactionConfirmed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardDialog {
|
||||||
|
id: confirmationDialog
|
||||||
|
property var onAcceptedCallback
|
||||||
|
property var onRejectedCallback
|
||||||
|
onAccepted: {
|
||||||
|
if (onAcceptedCallback)
|
||||||
|
onAcceptedCallback()
|
||||||
|
}
|
||||||
|
onRejected: {
|
||||||
|
if (onRejectedCallback)
|
||||||
|
onRejectedCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Open Wallet from file
|
//Open Wallet from file
|
||||||
FileDialog {
|
FileDialog {
|
||||||
id: fileDialog
|
id: fileDialog
|
||||||
|
|
|
@ -9,7 +9,7 @@ CONFIG += c++11
|
||||||
# cleaning "auto-generated" bitmonero directory on "make distclean"
|
# cleaning "auto-generated" bitmonero directory on "make distclean"
|
||||||
QMAKE_DISTCLEAN += -r $$WALLET_ROOT
|
QMAKE_DISTCLEAN += -r $$WALLET_ROOT
|
||||||
|
|
||||||
INCLUDEPATH += $$WALLET_ROOT/include \
|
INCLUDEPATH += $$WALLET_ROOT/include \
|
||||||
$$PWD/src/libwalletqt \
|
$$PWD/src/libwalletqt \
|
||||||
$$PWD/src/QR-Code-generator \
|
$$PWD/src/QR-Code-generator \
|
||||||
$$PWD/src \
|
$$PWD/src \
|
||||||
|
@ -36,7 +36,8 @@ HEADERS += \
|
||||||
src/daemon/DaemonManager.h \
|
src/daemon/DaemonManager.h \
|
||||||
src/model/AddressBookModel.h \
|
src/model/AddressBookModel.h \
|
||||||
src/libwalletqt/AddressBook.h \
|
src/libwalletqt/AddressBook.h \
|
||||||
src/zxcvbn-c/zxcvbn.h
|
src/zxcvbn-c/zxcvbn.h \
|
||||||
|
src/libwalletqt/UnsignedTransaction.h
|
||||||
|
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
|
@ -59,7 +60,8 @@ SOURCES += main.cpp \
|
||||||
src/daemon/DaemonManager.cpp \
|
src/daemon/DaemonManager.cpp \
|
||||||
src/model/AddressBookModel.cpp \
|
src/model/AddressBookModel.cpp \
|
||||||
src/libwalletqt/AddressBook.cpp \
|
src/libwalletqt/AddressBook.cpp \
|
||||||
src/zxcvbn-c/zxcvbn.c
|
src/zxcvbn-c/zxcvbn.c \
|
||||||
|
src/libwalletqt/UnsignedTransaction.cpp
|
||||||
|
|
||||||
lupdate_only {
|
lupdate_only {
|
||||||
SOURCES = *.qml \
|
SOURCES = *.qml \
|
||||||
|
@ -289,7 +291,8 @@ OTHER_FILES += \
|
||||||
$$TRANSLATIONS
|
$$TRANSLATIONS
|
||||||
|
|
||||||
DISTFILES += \
|
DISTFILES += \
|
||||||
notes.txt
|
notes.txt \
|
||||||
|
monero/src/wallet/CMakeLists.txt
|
||||||
|
|
||||||
|
|
||||||
# windows application icon
|
# windows application icon
|
||||||
|
|
|
@ -92,7 +92,10 @@ Rectangle {
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: pageRoot
|
id: pageRoot
|
||||||
anchors.fill: parent
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height:550
|
||||||
Label {
|
Label {
|
||||||
id: amountLabel
|
id: amountLabel
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
@ -381,7 +384,7 @@ Rectangle {
|
||||||
shadowPressedColor: "#B32D00"
|
shadowPressedColor: "#B32D00"
|
||||||
releasedColor: "#FF6C3C"
|
releasedColor: "#FF6C3C"
|
||||||
pressedColor: "#FF4304"
|
pressedColor: "#FF4304"
|
||||||
enabled : pageRoot.checkInformation(amountLine.text, addressLine.text, paymentIdLine.text, appWindow.persistentSettings.testnet)
|
enabled : !appWindow.viewOnly && pageRoot.checkInformation(amountLine.text, addressLine.text, paymentIdLine.text, appWindow.persistentSettings.testnet)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
console.log("Transfer: paymentClicked")
|
console.log("Transfer: paymentClicked")
|
||||||
var priority = priorityModel.get(priorityDropdown.currentIndex).priority
|
var priority = priorityModel.get(priorityDropdown.currentIndex).priority
|
||||||
|
@ -395,25 +398,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardButton {
|
} // pageRoot
|
||||||
id: sweepUnmixableButton
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: descriptionLine.bottom
|
|
||||||
anchors.rightMargin: 17
|
|
||||||
anchors.topMargin: 17
|
|
||||||
width: 60*2
|
|
||||||
text: qsTr("SWEEP UNMIXABLE") + translationManager.emptyString
|
|
||||||
shadowReleasedColor: "#FF4304"
|
|
||||||
shadowPressedColor: "#B32D00"
|
|
||||||
releasedColor: "#FF6C3C"
|
|
||||||
pressedColor: "#FF4304"
|
|
||||||
enabled : true
|
|
||||||
onClicked: {
|
|
||||||
console.log("Transfer: sweepUnmixableClicked")
|
|
||||||
root.sweepUnmixableClicked()
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id:desaturate
|
id:desaturate
|
||||||
|
@ -422,7 +407,192 @@ Rectangle {
|
||||||
opacity: 0.1
|
opacity: 0.1
|
||||||
visible: (pageRoot.enabled)? 0 : 1;
|
visible: (pageRoot.enabled)? 0 : 1;
|
||||||
}
|
}
|
||||||
} // Rectangle
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.top: pageRoot.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: 17
|
||||||
|
spacing:10
|
||||||
|
enabled: !viewOnly || pageRoot.enabled
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
id: manageWalletLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: "#4A4949"
|
||||||
|
text: qsTr("Advanced") + translationManager.emptyString
|
||||||
|
fontSize: 16
|
||||||
|
Layout.topMargin: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 1
|
||||||
|
color: "#DEDEDE"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
StandardButton {
|
||||||
|
id: sweepUnmixableButton
|
||||||
|
text: qsTr("SWEEP UNMIXABLE") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
enabled : pageRoot.enabled
|
||||||
|
onClicked: {
|
||||||
|
console.log("Transfer: sweepUnmixableClicked")
|
||||||
|
root.sweepUnmixableClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
id: saveTxButton
|
||||||
|
text: qsTr("create tx file") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
visible: appWindow.viewOnly
|
||||||
|
enabled: pageRoot.checkInformation(amountLine.text, addressLine.text, paymentIdLine.text, appWindow.persistentSettings.testnet)
|
||||||
|
onClicked: {
|
||||||
|
console.log("Transfer: saveTx Clicked")
|
||||||
|
var priority = priorityModel.get(priorityDropdown.currentIndex).priority
|
||||||
|
console.log("priority: " + priority)
|
||||||
|
console.log("amount: " + amountLine.text)
|
||||||
|
addressLine.text = addressLine.text.trim()
|
||||||
|
paymentIdLine.text = paymentIdLine.text.trim()
|
||||||
|
root.paymentClicked(addressLine.text, paymentIdLine.text, amountLine.text, scaleValueToMixinCount(privacyLevelItem.fillLevel),
|
||||||
|
priority, descriptionLine.text)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
id: signTxButton
|
||||||
|
text: qsTr("sign tx file") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
visible: !appWindow.viewOnly
|
||||||
|
onClicked: {
|
||||||
|
console.log("Transfer: sign tx clicked")
|
||||||
|
signTxDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
id: submitTxButton
|
||||||
|
text: qsTr("submit tx file") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
visible: appWindow.viewOnly
|
||||||
|
enabled: pageRoot.enabled
|
||||||
|
onClicked: {
|
||||||
|
console.log("Transfer: submit tx clicked")
|
||||||
|
submitTxDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//SignTxDialog
|
||||||
|
FileDialog {
|
||||||
|
id: signTxDialog
|
||||||
|
title: "Please choose a file"
|
||||||
|
folder: "file://" +moneroAccountsDir
|
||||||
|
nameFilters: [ "Unsigned transfers (*)"]
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
var path = walletManager.urlToLocalPath(fileUrl);
|
||||||
|
// Load the unsigned tx from file
|
||||||
|
var transaction = currentWallet.loadTxFile(path);
|
||||||
|
|
||||||
|
if (transaction.status !== PendingTransaction.Status_Ok) {
|
||||||
|
console.error("Can't load unsigned transaction: ", transaction.errorString);
|
||||||
|
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||||
|
informationPopup.text = qsTr("Can't load unsigned transaction: ") + transaction.errorString
|
||||||
|
informationPopup.icon = StandardIcon.Critical
|
||||||
|
informationPopup.onCloseCallback = null
|
||||||
|
informationPopup.open();
|
||||||
|
// deleting transaction object, we don't want memleaks
|
||||||
|
transaction.destroy();
|
||||||
|
} else {
|
||||||
|
confirmationDialog.text = qsTr("\nNumber of transactions: ") + transaction.txCount
|
||||||
|
for (var i = 0; i < transaction.txCount; ++i) {
|
||||||
|
confirmationDialog.text += qsTr("\nTransaction #%1").arg(i+1)
|
||||||
|
+qsTr("\nRecipient: ") + transaction.recipientAddress[i]
|
||||||
|
+ (transaction.paymentId[i] == "" ? "" : qsTr("\n\payment ID: ") + transaction.paymentId[i])
|
||||||
|
+ qsTr("\nAmount: ") + walletManager.displayAmount(transaction.amount(i))
|
||||||
|
+ qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee(i))
|
||||||
|
+ qsTr("\nMixin: ") + transaction.mixin(i)
|
||||||
|
|
||||||
|
// TODO: add descriptions to unsigned_tx_set?
|
||||||
|
// + (transactionDescription === "" ? "" : (qsTr("\n\nDescription: ") + transactionDescription))
|
||||||
|
+ translationManager.emptyString
|
||||||
|
if (i > 0) {
|
||||||
|
confirmationDialog.text += "\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(transaction.confirmationMessage);
|
||||||
|
|
||||||
|
// Show confirmation dialog
|
||||||
|
confirmationDialog.title = qsTr("Confirmation") + translationManager.emptyString
|
||||||
|
confirmationDialog.icon = StandardIcon.Question
|
||||||
|
confirmationDialog.onAcceptedCallback = function() {
|
||||||
|
transaction.sign(path+"_signed");
|
||||||
|
transaction.destroy();
|
||||||
|
};
|
||||||
|
confirmationDialog.onRejectedCallback = transaction.destroy;
|
||||||
|
|
||||||
|
confirmationDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
onRejected: {
|
||||||
|
// File dialog closed
|
||||||
|
console.log("Canceled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//SignTxDialog
|
||||||
|
FileDialog {
|
||||||
|
id: submitTxDialog
|
||||||
|
title: "Please choose a file"
|
||||||
|
folder: "file://" +moneroAccountsDir
|
||||||
|
nameFilters: [ "signed transfers (*)"]
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
if(!currentWallet.submitTxFile(walletManager.urlToLocalPath(fileUrl))){
|
||||||
|
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||||
|
informationPopup.text = qsTr("Can't submit transaction: ") + currentWallet.errorString
|
||||||
|
informationPopup.icon = StandardIcon.Critical
|
||||||
|
informationPopup.onCloseCallback = null
|
||||||
|
informationPopup.open();
|
||||||
|
} else {
|
||||||
|
informationPopup.title = qsTr("Information") + translationManager.emptyString
|
||||||
|
informationPopup.text = qsTr("Money sent successfully") + translationManager.emptyString
|
||||||
|
informationPopup.icon = StandardIcon.Information
|
||||||
|
informationPopup.onCloseCallback = null
|
||||||
|
informationPopup.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onRejected: {
|
||||||
|
console.log("Canceled")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
x: root.width/2 - width/2
|
x: root.width/2 - width/2
|
||||||
|
@ -465,9 +635,10 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentWallet.viewOnly) {
|
if (currentWallet.viewOnly) {
|
||||||
statusText.text = qsTr("Wallet is view only.")
|
// statusText.text = qsTr("Wallet is view only.")
|
||||||
return;
|
//return;
|
||||||
}
|
}
|
||||||
|
pageRoot.enabled = false;
|
||||||
|
|
||||||
switch (currentWallet.connected) {
|
switch (currentWallet.connected) {
|
||||||
case Wallet.ConnectionStatus_Disconnected:
|
case Wallet.ConnectionStatus_Disconnected:
|
||||||
|
|
|
@ -13,7 +13,10 @@ QString PendingTransaction::errorString() const
|
||||||
|
|
||||||
bool PendingTransaction::commit()
|
bool PendingTransaction::commit()
|
||||||
{
|
{
|
||||||
return m_pimpl->commit();
|
// Save transaction to file if fileName is set.
|
||||||
|
if(!m_fileName.isEmpty())
|
||||||
|
return m_pimpl->commit(m_fileName.toStdString());
|
||||||
|
return m_pimpl->commit(m_fileName.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 PendingTransaction::amount() const
|
quint64 PendingTransaction::amount() const
|
||||||
|
@ -47,6 +50,11 @@ quint64 PendingTransaction::txCount() const
|
||||||
return m_pimpl->txCount();
|
return m_pimpl->txCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PendingTransaction::setFilename(const QString &fileName)
|
||||||
|
{
|
||||||
|
m_fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
PendingTransaction::PendingTransaction(Monero::PendingTransaction *pt, QObject *parent)
|
PendingTransaction::PendingTransaction(Monero::PendingTransaction *pt, QObject *parent)
|
||||||
: QObject(parent), m_pimpl(pt)
|
: QObject(parent), m_pimpl(pt)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
quint64 fee() const;
|
quint64 fee() const;
|
||||||
QStringList txid() const;
|
QStringList txid() const;
|
||||||
quint64 txCount() const;
|
quint64 txCount() const;
|
||||||
|
Q_INVOKABLE void setFilename(const QString &fileName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit PendingTransaction(Monero::PendingTransaction * pt, QObject *parent = 0);
|
explicit PendingTransaction(Monero::PendingTransaction * pt, QObject *parent = 0);
|
||||||
|
@ -51,6 +52,7 @@ private:
|
||||||
private:
|
private:
|
||||||
friend class Wallet;
|
friend class Wallet;
|
||||||
Monero::PendingTransaction * m_pimpl;
|
Monero::PendingTransaction * m_pimpl;
|
||||||
|
QString m_fileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PENDINGTRANSACTION_H
|
#endif // PENDINGTRANSACTION_H
|
||||||
|
|
89
src/libwalletqt/UnsignedTransaction.cpp
Normal file
89
src/libwalletqt/UnsignedTransaction.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include "UnsignedTransaction.h"
|
||||||
|
#include <QVector>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
UnsignedTransaction::Status UnsignedTransaction::status() const
|
||||||
|
{
|
||||||
|
return static_cast<Status>(m_pimpl->status());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString UnsignedTransaction::errorString() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(m_pimpl->errorString());
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 UnsignedTransaction::amount(int index) const
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> arr = m_pimpl->amount();
|
||||||
|
if(index > arr.size() - 1)
|
||||||
|
return 0;
|
||||||
|
return arr[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 UnsignedTransaction::fee(int index) const
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> arr = m_pimpl->fee();
|
||||||
|
if(index > arr.size() - 1)
|
||||||
|
return 0;
|
||||||
|
return arr[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 UnsignedTransaction::mixin(int index) const
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> arr = m_pimpl->mixin();
|
||||||
|
if(index > arr.size() - 1)
|
||||||
|
return 0;
|
||||||
|
return arr[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 UnsignedTransaction::txCount() const
|
||||||
|
{
|
||||||
|
return m_pimpl->txCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 UnsignedTransaction::minMixinCount() const
|
||||||
|
{
|
||||||
|
return m_pimpl->minMixinCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString UnsignedTransaction::confirmationMessage() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(m_pimpl->confirmationMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList UnsignedTransaction::paymentId() const
|
||||||
|
{
|
||||||
|
QList<QString> list;
|
||||||
|
for (const auto &t: m_pimpl->paymentId())
|
||||||
|
list.append(QString::fromStdString(t));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList UnsignedTransaction::recipientAddress() const
|
||||||
|
{
|
||||||
|
QList<QString> list;
|
||||||
|
for (const auto &t: m_pimpl->recipientAddress())
|
||||||
|
list.append(QString::fromStdString(t));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnsignedTransaction::sign(const QString &fileName) const
|
||||||
|
{
|
||||||
|
return m_pimpl->sign(fileName.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsignedTransaction::setFilename(const QString &fileName)
|
||||||
|
{
|
||||||
|
m_fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnsignedTransaction::UnsignedTransaction(Monero::UnsignedTransaction *pt, QObject *parent)
|
||||||
|
: QObject(parent), m_pimpl(pt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
UnsignedTransaction::~UnsignedTransaction()
|
||||||
|
{
|
||||||
|
delete m_pimpl;
|
||||||
|
}
|
58
src/libwalletqt/UnsignedTransaction.h
Normal file
58
src/libwalletqt/UnsignedTransaction.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef UNSIGNEDTRANSACTION_H
|
||||||
|
#define UNSIGNEDTRANSACTION_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <wallet/wallet2_api.h>
|
||||||
|
|
||||||
|
class UnsignedTransaction : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(Status status READ status)
|
||||||
|
Q_PROPERTY(QString errorString READ errorString)
|
||||||
|
// Q_PROPERTY(QList<qulonglong> amount READ amount)
|
||||||
|
// Q_PROPERTY(QList<qulonglong> fee READ fee)
|
||||||
|
Q_PROPERTY(quint64 txCount READ txCount)
|
||||||
|
Q_PROPERTY(QString confirmationMessage READ confirmationMessage)
|
||||||
|
Q_PROPERTY(QStringList recipientAddress READ recipientAddress)
|
||||||
|
Q_PROPERTY(QStringList paymentId READ paymentId)
|
||||||
|
Q_PROPERTY(quint64 minMixinCount READ minMixinCount)
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Status {
|
||||||
|
Status_Ok = Monero::UnsignedTransaction::Status_Ok,
|
||||||
|
Status_Error = Monero::UnsignedTransaction::Status_Error,
|
||||||
|
Status_Critical = Monero::UnsignedTransaction::Status_Critical
|
||||||
|
};
|
||||||
|
Q_ENUM(Status)
|
||||||
|
|
||||||
|
enum Priority {
|
||||||
|
Priority_Low = Monero::UnsignedTransaction::Priority_Low,
|
||||||
|
Priority_Medium = Monero::UnsignedTransaction::Priority_Medium,
|
||||||
|
Priority_High = Monero::UnsignedTransaction::Priority_High
|
||||||
|
};
|
||||||
|
Q_ENUM(Priority)
|
||||||
|
|
||||||
|
Status status() const;
|
||||||
|
QString errorString() const;
|
||||||
|
Q_INVOKABLE quint64 amount(int index) const;
|
||||||
|
Q_INVOKABLE quint64 fee(int index) const;
|
||||||
|
Q_INVOKABLE quint64 mixin(int index) const;
|
||||||
|
QStringList recipientAddress() const;
|
||||||
|
QStringList paymentId() const;
|
||||||
|
quint64 txCount() const;
|
||||||
|
QString confirmationMessage() const;
|
||||||
|
quint64 minMixinCount() const;
|
||||||
|
Q_INVOKABLE bool sign(const QString &fileName) const;
|
||||||
|
Q_INVOKABLE void setFilename(const QString &fileName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit UnsignedTransaction(Monero::UnsignedTransaction * pt, QObject *parent = 0);
|
||||||
|
~UnsignedTransaction();
|
||||||
|
private:
|
||||||
|
friend class Wallet;
|
||||||
|
Monero::UnsignedTransaction * m_pimpl;
|
||||||
|
QString m_fileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // UNSIGNEDTRANSACTION_H
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Wallet.h"
|
#include "Wallet.h"
|
||||||
#include "PendingTransaction.h"
|
#include "PendingTransaction.h"
|
||||||
|
#include "UnsignedTransaction.h"
|
||||||
#include "TransactionHistory.h"
|
#include "TransactionHistory.h"
|
||||||
#include "AddressBook.h"
|
#include "AddressBook.h"
|
||||||
#include "model/TransactionHistoryModel.h"
|
#include "model/TransactionHistoryModel.h"
|
||||||
|
@ -211,7 +212,6 @@ quint64 Wallet::daemonBlockChainHeight() const
|
||||||
|
|
||||||
quint64 Wallet::daemonBlockChainTargetHeight() const
|
quint64 Wallet::daemonBlockChainTargetHeight() const
|
||||||
{
|
{
|
||||||
|
|
||||||
if (m_daemonBlockChainTargetHeight == 0
|
if (m_daemonBlockChainTargetHeight == 0
|
||||||
|| m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl) {
|
|| m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl) {
|
||||||
m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight();
|
m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight();
|
||||||
|
@ -323,12 +323,31 @@ void Wallet::createSweepUnmixableTransactionAsync()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnsignedTransaction * Wallet::loadTxFile(const QString &fileName)
|
||||||
|
{
|
||||||
|
qDebug() << "Trying to sign " << fileName;
|
||||||
|
Monero::UnsignedTransaction * ptImpl = m_walletImpl->loadUnsignedTx(fileName.toStdString());
|
||||||
|
UnsignedTransaction * result = new UnsignedTransaction(ptImpl, this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Wallet::submitTxFile(const QString &fileName) const
|
||||||
|
{
|
||||||
|
qDebug() << "Trying to submit " << fileName;
|
||||||
|
return m_walletImpl->submitTransaction(fileName.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
void Wallet::disposeTransaction(PendingTransaction *t)
|
void Wallet::disposeTransaction(PendingTransaction *t)
|
||||||
{
|
{
|
||||||
m_walletImpl->disposeTransaction(t->m_pimpl);
|
m_walletImpl->disposeTransaction(t->m_pimpl);
|
||||||
delete t;
|
delete t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Wallet::disposeTransaction(UnsignedTransaction *t)
|
||||||
|
{
|
||||||
|
delete t;
|
||||||
|
}
|
||||||
|
|
||||||
TransactionHistory *Wallet::history() const
|
TransactionHistory *Wallet::history() const
|
||||||
{
|
{
|
||||||
return m_history;
|
return m_history;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "wallet/wallet2_api.h" // we need to have an access to the Monero::Wallet::Status enum here;
|
#include "wallet/wallet2_api.h" // we need to have an access to the Monero::Wallet::Status enum here;
|
||||||
#include "PendingTransaction.h" // we need to have an access to the PendingTransaction::Priority enum here;
|
#include "PendingTransaction.h" // we need to have an access to the PendingTransaction::Priority enum here;
|
||||||
|
#include "UnsignedTransaction.h"
|
||||||
|
|
||||||
namespace Monero {
|
namespace Monero {
|
||||||
class Wallet; // forward declaration
|
class Wallet; // forward declaration
|
||||||
|
@ -162,9 +163,19 @@ public:
|
||||||
//! creates async sweep unmixable transaction
|
//! creates async sweep unmixable transaction
|
||||||
Q_INVOKABLE void createSweepUnmixableTransactionAsync();
|
Q_INVOKABLE void createSweepUnmixableTransactionAsync();
|
||||||
|
|
||||||
|
//! Sign a transfer from file
|
||||||
|
Q_INVOKABLE UnsignedTransaction * loadTxFile(const QString &fileName);
|
||||||
|
|
||||||
|
//! Submit a transfer from file
|
||||||
|
Q_INVOKABLE bool submitTxFile(const QString &fileName) const;
|
||||||
|
|
||||||
|
|
||||||
//! deletes transaction and frees memory
|
//! deletes transaction and frees memory
|
||||||
Q_INVOKABLE void disposeTransaction(PendingTransaction * t);
|
Q_INVOKABLE void disposeTransaction(PendingTransaction * t);
|
||||||
|
|
||||||
|
//! deletes unsigned transaction and frees memory
|
||||||
|
Q_INVOKABLE void disposeTransaction(UnsignedTransaction * t);
|
||||||
|
|
||||||
//! returns transaction history
|
//! returns transaction history
|
||||||
TransactionHistory * history() const;
|
TransactionHistory * history() const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue