Version v1.0

Everything should be working, tested on ubuntu.
This commit is contained in:
twiddle 2024-08-22 18:25:41 -04:00
parent 12bbc76e26
commit 441aa24996
11 changed files with 96 additions and 67 deletions

View file

@ -51,7 +51,9 @@ void AtomicFundDialog::copyAddress(){
QMessageBox::information(this, "Information", "BTC deposit address copied to clipboard"); QMessageBox::information(this, "Information", "BTC deposit address copied to clipboard");
} }
void AtomicFundDialog::updateMin(QString min){
ui->label_status->setText("Deposit at least " + min + " BTC to cover fee");
}
AtomicFundDialog::~AtomicFundDialog() { AtomicFundDialog::~AtomicFundDialog() {
emit cleanProcs(); emit cleanProcs();

View file

@ -22,6 +22,7 @@ class AtomicFundDialog : public WindowModalDialog {
public: public:
explicit AtomicFundDialog(QWidget *parent, const QString &title = "Qr Code", const QString &btc_address = "Error Restart swap"); explicit AtomicFundDialog(QWidget *parent, const QString &title = "Qr Code", const QString &btc_address = "Error Restart swap");
~AtomicFundDialog() override; ~AtomicFundDialog() override;
void updateMin(QString min);
signals: signals:
void cleanProcs(); void cleanProcs();
private: private:

View file

@ -14,6 +14,13 @@
<string>Dialog</string> <string>Dialog</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_status">
<property name="text">
<string/>
</property>
</widget>
</item>
<item> <item>
<widget class="QrCodeWidget" name="qrWidget" native="true"> <widget class="QrCodeWidget" name="qrWidget" native="true">
<property name="sizePolicy"> <property name="sizePolicy">

View file

@ -6,10 +6,10 @@
#include "AtomicRecoverDialog.h" #include "AtomicRecoverDialog.h"
#include "ui_AtomicRecoverDialog.h" #include "ui_AtomicRecoverDialog.h"
#include "History.h"
#include "config.h" #include "config.h"
#include "AtomicSwap.h" #include "AtomicSwap.h"
#include "Utils.h" #include "Utils.h"
#include "constants.h"
#include <QStandardItemModel> #include <QStandardItemModel>
AtomicRecoverDialog::AtomicRecoverDialog(QWidget *parent) : AtomicRecoverDialog::AtomicRecoverDialog(QWidget *parent) :
@ -17,27 +17,33 @@ AtomicRecoverDialog::AtomicRecoverDialog(QWidget *parent) :
ui->setupUi(this); ui->setupUi(this);
auto model = new QStandardItemModel(); auto model = new QStandardItemModel();
ui->swap_history->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); ui->swap_history->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->swap_history->setModel(model); ui->swap_history->setSelectionMode(QAbstractItemView::SingleSelection);
ui->btn_refund_resume->setVisible(false); ui->btn_refund_resume->setVisible(false);
ui->swap_history->setSelectionBehavior(QAbstractItemView::SelectRows); ui->swap_history->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->swap_history->verticalHeader()->setVisible(false); ui->swap_history->verticalHeader()->setVisible(false);
// Makes it easy to see if button is in refund or resume mode // Makes it easy to see if button is in refund or resume mode
ui->btn_refund_resume->setProperty("Refund",0); ui->btn_refund_resume->setProperty("Refund",0);
this->setWindowFlag(Qt::WindowStaysOnTopHint); this->setWindowFlag(Qt::WindowStaysOnTopHint);
this->raise();
model->setHorizontalHeaderItem(0, new QStandardItem("Swap-Id")); model->setHorizontalHeaderItem(0, new QStandardItem("Swap-Id"));
model->setHorizontalHeaderItem(1, new QStandardItem("Timestamp swap started")); model->setHorizontalHeaderItem(1, new QStandardItem("Timestamp swap started"));
model->setHorizontalHeaderItem(2, new QStandardItem("Status")); model->setHorizontalHeaderItem(2, new QStandardItem("Status"));
QList<QStandardItem*> rowData; QList<QStandardItem*> rowData;
auto data = conf()->get(Config::pendingSwap).value<QVariantList>(); qDebug() << conf()->get(Config::pendingSwap);
QStringList data = conf()->get(Config::pendingSwap).toStringList();
qDebug() << data;
for(int i=0; i< data.size(); i++){ for(int i=0; i< data.size(); i++){
auto entry = data[i].value<HistoryEntry>(); QStringList entry = data[i].split(":");
qint64 difference = entry.timestamp.secsTo(QDateTime::currentDateTime()); qDebug() << "Swap-id - " + entry[0];
QString id = entry[0];
QDateTime timestamp = QDateTime::fromString(entry[1],"dd.MM.yyyy.hh.mm.ss");
qint64 difference = timestamp.secsTo(QDateTime::currentDateTime());
if (difference < 86400) { if (difference < 86400) {
rowData.clear(); rowData.clear();
rowData << new QStandardItem(entry.id); rowData << new QStandardItem(id);
rowData << new QStandardItem(entry.timestamp.toString("MM-dd-yyyy hh:mm")); rowData << new QStandardItem(timestamp.toString("MM-dd-yyyy hh:mm"));
if (difference > 43200){ if (difference > 43200){
rowData << new QStandardItem("Refundable"); rowData << new QStandardItem("Refundable");
} else } else
@ -47,27 +53,26 @@ AtomicRecoverDialog::AtomicRecoverDialog(QWidget *parent) :
data.remove(i); data.remove(i);
} }
} }
ui->swap_history->setModel(model);
conf()->set(Config::pendingSwap,data); conf()->set(Config::pendingSwap,data);
connect(ui->swap_history, &QAbstractItemView::clicked, this, &AtomicRecoverDialog::updateBtn); connect(ui->swap_history, &QAbstractItemView::clicked, this, &AtomicRecoverDialog::updateBtn);
connect(ui->btn_refund_resume, &QPushButton::clicked, this, [this]{ connect(ui->btn_refund_resume, &QPushButton::clicked, this, [this]{
QStringList arguments; QStringList arguments;
if (constants::networkType==NetworkType::STAGENET) {
arguments << "--testnet";
}
arguments << "-j";
arguments << "--debug";
arguments << "-d";
arguments << Config::defaultConfigDir().absolutePath();
if (ui->btn_refund_resume->property("Refund").toBool()){ if (ui->btn_refund_resume->property("Refund").toBool()){
arguments << "cancel-and-refund"; arguments << "cancel-and-refund";
} else { } else {
arguments << "resume"; arguments << "resume";
} }
arguments << "--swap-id"; arguments << "--swap-id";
arguments << ui->swap_history->selectionModel()->selectedRows().at(0).sibling(0,1).data().toString(); auto row = ui->swap_history->selectionModel()->selectedRows().at(0);
arguments << "--monero-daemon-address"; arguments << row.sibling(row.row(),0).data().toString();
auto nodes = conf()->get(Config::nodes).toJsonObject();
if (nodes.isEmpty()) {
auto jsonData = conf()->get(Config::nodes).toByteArray();
if (Utils::validateJSON(jsonData)) {
auto doc = QJsonDocument::fromJson(jsonData);
nodes = doc.object();
}
}
arguments << nodes.value("0").toObject()["ws"].toArray()[0].toString();
if(conf()->get(Config::proxy).toInt() != Config::Proxy::None) { if(conf()->get(Config::proxy).toInt() != Config::Proxy::None) {
arguments << "--tor-socks5-port"; arguments << "--tor-socks5-port";
arguments << conf()->get(Config::socks5Port).toString(); arguments << conf()->get(Config::socks5Port).toString();
@ -94,11 +99,9 @@ bool AtomicRecoverDialog::historyEmpty(){
} }
void AtomicRecoverDialog::appendHistory(HistoryEntry entry){ void AtomicRecoverDialog::appendHistory(QString entry){
auto current = conf()->get(Config::pendingSwap).value<QVariantList>(); auto current = conf()->get(Config::pendingSwap).value<QVariantList>();
auto var = QVariant(); current.append(entry);
var.setValue(entry);
current.append(var);
conf()->set(Config::pendingSwap, current); conf()->set(Config::pendingSwap, current);
} }
AtomicRecoverDialog::~AtomicRecoverDialog() { AtomicRecoverDialog::~AtomicRecoverDialog() {

View file

@ -7,7 +7,6 @@
#include <QDialog> #include <QDialog>
#include "components.h" #include "components.h"
#include "History.h"
#include "AtomicSwap.h" #include "AtomicSwap.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -20,7 +19,7 @@ Q_OBJECT
public: public:
explicit AtomicRecoverDialog(QWidget *parent = nullptr); explicit AtomicRecoverDialog(QWidget *parent = nullptr);
bool historyEmpty(); bool historyEmpty();
void appendHistory(HistoryEntry entry); void appendHistory(QString entry);
~AtomicRecoverDialog() override; ~AtomicRecoverDialog() override;
private slots: private slots:

View file

@ -10,6 +10,8 @@
#include <qt6/QtWidgets/QMessageBox> #include <qt6/QtWidgets/QMessageBox>
#include "ui_AtomicSwap.h" #include "ui_AtomicSwap.h"
#include "AtomicWidget.h" #include "AtomicWidget.h"
#include "constants.h"
#include "networktype.h"
AtomicSwap::AtomicSwap(QWidget *parent) : AtomicSwap::AtomicSwap(QWidget *parent) :
@ -20,7 +22,7 @@ AtomicSwap::AtomicSwap(QWidget *parent) :
int size=20; int size=20;
pixmapTarget = pixmapTarget.scaled(size-5, size-5, Qt::KeepAspectRatio, Qt::SmoothTransformation); pixmapTarget = pixmapTarget.scaled(size-5, size-5, Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->btc_hint->setPixmap(pixmapTarget); ui->btc_hint->setPixmap(pixmapTarget);
ui->btc_hint->setToolTip("Alice is expected to send monero lock after one btc confirmation,\nswap is cancelable after 72 btc confirmations,\nyou will lose your funds if you don't refund before 144 confirmations"); ui->btc_hint->setToolTip("Alice is expected to send monero lock after one btc confirmation,\nswap is cancelable after 72 btc confirmations,\nyou will lose your funds if you don't refund before 144 confirmations\n\nResumed swaps may not have accurate numbers for confirmations!!!");
this->setContentsMargins(3,3,3,3); this->setContentsMargins(3,3,3,3);
this->adjustSize(); this->adjustSize();
connect(ui->btn_cancel, &QPushButton::clicked, this, &AtomicSwap::cancel); connect(ui->btn_cancel, &QPushButton::clicked, this, &AtomicSwap::cancel);
@ -38,21 +40,25 @@ void AtomicSwap::runSwap(QStringList arguments){
QJsonDocument line = QJsonDocument::fromJson(rawline, &err); QJsonDocument line = QJsonDocument::fromJson(rawline, &err);
qDebug() << rawline; qDebug() << rawline;
bool check; bool check;
if (line["fields"]["message"].toString().contains("Connected to Alice")){ QString message = line["fields"]["message"].toString();
if (message.contains("Connected to Alice")){
qDebug() << "Successfully connected"; qDebug() << "Successfully connected";
this->logLine(line["fields"].toString()); this->logLine(line["fields"].toString());
} else if (!line["fields"]["deposit_address"].toString().isEmpty()){ } else if (!line["fields"]["deposit_address"].toString().isEmpty()){
qDebug() << "Deposit to btc to segwit address"; qDebug() << "Deposit to btc to segwit address";
QString address = line["fields"]["deposit_address"].toString(); QString address = line["fields"]["deposit_address"].toString();
fundDialog = new AtomicFundDialog(this, "Deposit BTC to this address", address); fundDialog = new AtomicFundDialog(this, "Deposit BTC to this address", address);
fundDialog->updateMin(min);
fundDialog->update();
//dialog->setModal(true); //dialog->setModal(true);
fundDialog->show(); fundDialog->show();
} else if (line["fields"]["message"].toString().startsWith("Received Bitcoin")){ } else if (message.startsWith("Received Bitcoin")){
this->updateStatus(line["fields"]["new_balance"].toString().split(" ")[0] + " BTC received, starting swap"); this->updateStatus(line["fields"]["new_balance"].toString().split(" ")[0] + " BTC received, starting swap");
QVariant var; QString entry = line["span"]["swap_id"].toString() + ":" + QDateTime::currentDateTime().toString("dd.MM.yyyy.hh.mm.ss");
var.setValue(HistoryEntry {QDateTime::currentDateTime(),line["span"]["swap_id"].toString()}); qDebug() << "Swap logged as ";
qDebug() << entry;
QVariantList past = conf()->get(Config::pendingSwap).toList(); QVariantList past = conf()->get(Config::pendingSwap).toList();
past.append(var); past.append(entry);
conf()->set(Config::pendingSwap,past); conf()->set(Config::pendingSwap,past);
fundDialog->close(); fundDialog->close();
qDebug() << "Spawn atomic swap progress dialog"; qDebug() << "Spawn atomic swap progress dialog";
@ -60,40 +66,46 @@ void AtomicSwap::runSwap(QStringList arguments){
} else if ( QString confs = line["fields"]["seen_confirmations"].toString(); !confs.isEmpty()){ } else if ( QString confs = line["fields"]["seen_confirmations"].toString(); !confs.isEmpty()){
qDebug() << "Updating xmrconfs " + confs; qDebug() << "Updating xmrconfs " + confs;
this->updateXMRConf(confs.toInt()); this->updateXMRConf(confs.toInt());
} else if (QString message = line["fields"]["message"].toString(); QString::compare(message, "Bitcoin transaction status changed")==0){ } else if (QString::compare(message, "Bitcoin transaction status changed")==0){
qDebug() << "Updating btconfs " + line["fields"]["new_status"].toString().split(" ")[2];
QString status = line["fields"]["new_status"].toString(); QString status = line["fields"]["new_status"].toString();
bool ok; auto parts = status.split(" ");
auto confirmations = status.split(" ")[2].toInt(&ok, 10); if (parts.length() == 2){
if(ok) {
this->updateBTCConf(confirmations);
} else {
this->updateStatus("Found txid " + line["fields"]["txid"].toString() + " in mempool"); this->updateStatus("Found txid " + line["fields"]["txid"].toString() + " in mempool");
}else {
auto confirmations = parts[2].toInt();
this->updateBTCConf(confirmations);
} }
} else if (QString message = line["fields"]["message"].toString(); message.startsWith("Swap completed")){ } else if (message.startsWith("Swap completed")){
QVariantList past = conf()->get(Config::pendingSwap).toList(); QVariantList past = conf()->get(Config::pendingSwap).toList();
past.removeLast(); past.removeLast();
conf()->set(Config::pendingSwap, past); conf()->set(Config::pendingSwap, past);
this->updateStatus("Swap has successfully completed you can close this window now"); this->updateStatus("Swap has successfully completed you can close this window now");
} else if (QString message = line["fields"]["message"].toString(); QString::compare(message,"Advancing state")==0){ } else if (QString::compare(message,"Advancing state")==0){
this->updateStatus("State of swap has advanced to " + line["fields"]["state"].toString()); this->updateStatus("State of swap has advanced to " + line["fields"]["state"].toString());
} else if (QString refund = line["fields"]["kind"].toString(); QString::compare(refund,"refund")==0){ } else if (QString refund = line["fields"]["kind"].toString(); QString::compare(refund,"refund")==0){
QString txid = line["fields"]["txid"].toString(); QString txid = line["fields"]["txid"].toString();
QString id = line["span"]["swap_id"].toString(); QString id = line["span"]["swap_id"].toString();
QVariantList past = conf()->get(Config::pendingSwap).toList(); QStringList past = conf()->get(Config::pendingSwap).toStringList();
for(int i=0;i<past.length();i++){ for(int i=0;i<past.length();i++){
if(QString::compare(past[i].value<HistoryEntry>().id,id)==0) { if(QString::compare(past[i].split(":")[0],id)==0) {
past.remove(i); past.remove(i);
break; break;
} }
} }
conf()->set(Config::pendingSwap, past); conf()->set(Config::pendingSwap, past);
QMessageBox::information(this,"Cancel and Refund","Swap refunded succesfully with txid " + txid); QMessageBox::information(this,"Cancel and Refund","Swap refunded succesfully with txid " + txid);
} else if (QString message = line["fields"]["message"].toString(); QString::compare(message, "API call resulted in an error")==0){ } else if ( QString::compare(message, "API call resulted in an error")==0){
QString err = line["fields"]["err"].toString().split("\n")[0].split(":")[1]; QString err = line["fields"]["err"].toString().split("\n")[0].split(":")[1];
QMessageBox::warning(this, "Cancel and Refund", "Time lock hasn't expired yet so cancel failed. Try again in " + err + "blocks"); QMessageBox::warning(this, "Cancel and Refund", "Time lock hasn't expired yet so cancel failed. Try again in " + err + "blocks");
} else if (QString message = line["fields"]["latest_version"].toString(); !message.isEmpty()){ } else if (QString latest_version = line["fields"]["latest_version"].toString(); !latest_version.isEmpty()){
conf()->set(Config::swapVersion,message); QMessageBox::warning(this, "Outdated swap version","A newer version of COMIT xmr-btc swap tool is available, delete current binary and re auto install to upgrade");
conf()->set(Config::swapVersion,latest_version);
} else if (message.startsWith("Acquiring swap lock") && QString::compare("Resume",line["span"]["method_name"].toString())==0){
updateStatus("Beginning resumption of previous swap");
this->show();
} else if (message.startsWith("Deposit at least")){
min = message.split(" ")[3];
} }
} }
}); });
@ -106,6 +118,16 @@ AtomicSwap::~AtomicSwap() {
for (const auto& proc : *procList){ for (const auto& proc : *procList){
proc->kill(); proc->kill();
} }
if(conf()->get(Config::operatingSystem)=="WINDOWS"){
(new QProcess)->start("tskill", QStringList{"monero-wallet-rpc"});
}else {
if (constants::networkType==NetworkType::STAGENET){
(new QProcess)->start("pkill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +"/testnet/monero/monero-wallet-rpc"});
} else {
(new QProcess)->start("pkill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +
"/mainnet/monero/monero-wallet-rpc"});
}
}
} }
void AtomicSwap::logLine(QString line){ void AtomicSwap::logLine(QString line){
this->update(); this->update();

View file

@ -34,6 +34,7 @@ signals:
private: private:
Ui::AtomicSwap *ui; Ui::AtomicSwap *ui;
QString id; QString id;
QString min;
AtomicFundDialog* fundDialog; AtomicFundDialog* fundDialog;
QList<QSharedPointer<QProcess>>* procList; QList<QSharedPointer<QProcess>>* procList;
int btc_confs; int btc_confs;

View file

@ -11,7 +11,6 @@
#include "AtomicConfigDialog.h" #include "AtomicConfigDialog.h"
#include "OfferModel.h" #include "OfferModel.h"
#include "utils/AppData.h" #include "utils/AppData.h"
#include "utils/nodes.h"
#include "utils/ColorScheme.h" #include "utils/ColorScheme.h"
#include "utils/WebsocketNotifier.h" #include "utils/WebsocketNotifier.h"
#include "AtomicFundDialog.h" #include "AtomicFundDialog.h"
@ -137,7 +136,6 @@ void AtomicWidget::runSwap(const QString& seller, const QString& btcChange, cons
QStringList arguments; QStringList arguments;
arguments << "--data-base-dir"; arguments << "--data-base-dir";
arguments << Config::defaultConfigDir().absolutePath(); arguments << Config::defaultConfigDir().absolutePath();
// Remove after testing
if (constants::networkType==NetworkType::STAGENET){ if (constants::networkType==NetworkType::STAGENET){
arguments << "--testnet"; arguments << "--testnet";
} }
@ -149,6 +147,8 @@ void AtomicWidget::runSwap(const QString& seller, const QString& btcChange, cons
arguments << "--receive-address"; arguments << "--receive-address";
arguments << xmrReceive; arguments << xmrReceive;
//Doesn't work cause wallet rpc
/*
auto nodes = conf()->get(Config::nodes).toJsonObject(); auto nodes = conf()->get(Config::nodes).toJsonObject();
if (nodes.isEmpty()) { if (nodes.isEmpty()) {
auto jsonData = conf()->get(Config::nodes).toByteArray(); auto jsonData = conf()->get(Config::nodes).toByteArray();
@ -159,6 +159,7 @@ void AtomicWidget::runSwap(const QString& seller, const QString& btcChange, cons
} }
arguments << "--monero-daemon-address"; arguments << "--monero-daemon-address";
arguments << nodes.value("0").toObject()["ws"].toArray()[0].toString(); arguments << nodes.value("0").toObject()["ws"].toArray()[0].toString();
*/
arguments << "--seller"; arguments << "--seller";
arguments << seller; arguments << seller;
if(conf()->get(Config::proxy).toInt() != Config::Proxy::None) { if(conf()->get(Config::proxy).toInt() != Config::Proxy::None) {
@ -235,6 +236,16 @@ void AtomicWidget::clean() {
for (const auto& proc : *procList){ for (const auto& proc : *procList){
proc->kill(); proc->kill();
} }
if(conf()->get(Config::operatingSystem)=="WINDOWS"){
(new QProcess)->start("tskill", QStringList{"monero-wallet-rpc"});
}else {
if (constants::networkType==NetworkType::STAGENET){
(new QProcess)->start("pkill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +"/testnet/monero/monero-wallet-rpc"});
} else {
(new QProcess)->start("pkill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +
"/mainnet/monero/monero-wallet-rpc"});
}
}
} }

View file

@ -31,7 +31,7 @@
<item> <item>
<widget class="QLineEdit" name="change_address"> <widget class="QLineEdit" name="change_address">
<property name="text"> <property name="text">
<string>bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
@ -49,7 +49,7 @@
<item> <item>
<widget class="QLineEdit" name="xmr_address"> <widget class="QLineEdit" name="xmr_address">
<property name="text"> <property name="text">
<string>888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -1,17 +0,0 @@
//
// Created by dev on 7/29/24.
//
#ifndef FEATHER_HISTORY_H
#define FEATHER_HISTORY_H
#include <QString>
#include <QDateTime>
struct HistoryEntry {
QDateTime timestamp;
QString id;
};
Q_DECLARE_METATYPE(HistoryEntry);
#endif //FEATHER_HISTORY_H

View file

@ -149,7 +149,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
"/dns4/swap.sethforprivacy.com/tcp/8888/p2p/12D3KooWCULyZKuV9YEkb6BX8FuwajdvktSzmMg4U5ZX2uYZjHeu"}}}, "/dns4/swap.sethforprivacy.com/tcp/8888/p2p/12D3KooWCULyZKuV9YEkb6BX8FuwajdvktSzmMg4U5ZX2uYZjHeu"}}},
{Config::swapPath, {QS("swapPath"), ""}}, {Config::swapPath, {QS("swapPath"), ""}},
{Config::operatingSystem, {QS("operatingSystem"), OS}}, {Config::operatingSystem, {QS("operatingSystem"), OS}},
{Config::pendingSwap, {QS("pendingSwap"), QVariantList{}}}, {Config::pendingSwap, {QS("pendingSwap"), QStringList{}}},
{Config::swapVersion, {QS("swapVersion"), "0.13.4"}}, {Config::swapVersion, {QS("swapVersion"), "0.13.4"}},
}; };