mirror of
https://github.com/feather-wallet/feather.git
synced 2025-01-22 18:54:33 +00:00
Version 0.9
DONE: 1. Connect signals to make status of swap reflected in AtomicSwap dialog 2. Add informational tabs to AtomicSwap dialog 3. Add cancel and refund functionality to AtomicSwap when things go wrong 4. Add recovery to atomic widget 5. Refactor AtomicWidget so AtomicSwap handles parsing of swap binary output. TODO: Test for bugs, make custom readme, build for other systems
This commit is contained in:
parent
41f78b5f89
commit
12bbc76e26
8 changed files with 91 additions and 74 deletions
|
@ -58,13 +58,14 @@ void AtomicConfigDialog::downloadBinary() {
|
|||
tempFile = download->fileName();
|
||||
QString url;
|
||||
auto operatingSystem = Config::instance()->get(Config::operatingSystem).toString().toStdString();
|
||||
QString firstPart = "https://github.com/comit-network/xmr-btc-swap/releases/download/" + conf()->get(Config::swapVersion).toString();
|
||||
if(strcmp("WIN",operatingSystem.c_str()) == 0) {
|
||||
// HARD CODED DOWNload URL CHANGE IF PROBLEMS
|
||||
url = QString("https://github.com/comit-network/xmr-btc-swap/releases/download/0.13.1/swap_0.13.1_Windows_x86_64.zip");
|
||||
url = QString(firstPart+"/swap_"+conf()->get(Config::swapVersion).toString()+"_Windows_x86_64.zip");
|
||||
} else if (strcmp("LINUX",operatingSystem.c_str())==0){
|
||||
url = QString("https://github.com/comit-network/xmr-btc-swap/releases/download/0.13.1/swap_0.13.1_Linux_x86_64.tar");
|
||||
url = QString(firstPart+"/swap_"+conf()->get(Config::swapVersion).toString()+"_Linux_x86_64.tar");
|
||||
} else {
|
||||
url = QString("https://github.com/comit-network/xmr-btc-swap/releases/download/0.13.1/swap_0.13.1_Linux_x86_64.tar");
|
||||
url = QString(firstPart + "/swap_" + conf()->get(Config::swapVersion).toString() + "_Darwin_x86_64.tar");
|
||||
}
|
||||
|
||||
archive = network->get(this, url);
|
||||
|
@ -72,7 +73,6 @@ void AtomicConfigDialog::downloadBinary() {
|
|||
QStringList answer;
|
||||
connect(archive,&QNetworkReply::readyRead, this, [this]{
|
||||
QByteArray data= archive->readAll();
|
||||
qDebug() << "received data of size: " << data.size();
|
||||
download->write(data.constData(), data.size());
|
||||
});
|
||||
connect(archive, &QNetworkReply::finished,
|
||||
|
@ -82,7 +82,6 @@ void AtomicConfigDialog::downloadBinary() {
|
|||
void AtomicConfigDialog::extract() {
|
||||
|
||||
ui->downloadLabel->setText("Download Successful, extracting binary to final destination");
|
||||
qDebug() << "extracting";
|
||||
download->close();
|
||||
archive->deleteLater();
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "History.h"
|
||||
#include "config.h"
|
||||
#include "AtomicSwap.h"
|
||||
#include "Utils.h"
|
||||
#include <QStandardItemModel>
|
||||
|
||||
AtomicRecoverDialog::AtomicRecoverDialog(QWidget *parent) :
|
||||
|
@ -57,8 +58,20 @@ AtomicRecoverDialog::AtomicRecoverDialog(QWidget *parent) :
|
|||
}
|
||||
arguments << "--swap-id";
|
||||
arguments << ui->swap_history->selectionModel()->selectedRows().at(0).sibling(0,1).data().toString();
|
||||
arguments << "--monero-daemon-address";
|
||||
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) {
|
||||
arguments << "--tor-socks5-port";
|
||||
arguments << conf()->get(Config::socks5Port).toString();
|
||||
}
|
||||
swapDialog->runSwap(arguments);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#include "AtomicSwap.h"
|
||||
|
||||
#include <utility>
|
||||
#include <QJsonParseError>
|
||||
#include <qt6/QtWidgets/QMessageBox>
|
||||
#include "ui_AtomicSwap.h"
|
||||
#include "AtomicWidget.h"
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
|||
AtomicSwap::AtomicSwap(QWidget *parent) :
|
||||
WindowModalDialog(parent), ui(new Ui::AtomicSwap), fundDialog( new AtomicFundDialog(this)), procList(new QList<QSharedPointer<QProcess>>()) {
|
||||
ui->setupUi(this);
|
||||
//ui->debug_log->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
ui->label_status->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
|
||||
QPixmap pixmapTarget = QPixmap(":/assets/images/hint-icon.png");
|
||||
int size=20;
|
||||
|
@ -33,7 +32,6 @@ void AtomicSwap::runSwap(QStringList arguments){
|
|||
swap->setProcessChannelMode(QProcess::MergedChannels);
|
||||
swap->setReadChannel(QProcess::StandardOutput);
|
||||
connect(swap, &QProcess::readyRead,this, [this, swap] {
|
||||
//Refactor and move this to a slot in atomicswap, move fund dialog to be part of atomic swap
|
||||
while(swap->canReadLine()){
|
||||
QJsonParseError err;
|
||||
const QByteArray& rawline = swap->readLine();
|
||||
|
@ -51,14 +49,18 @@ void AtomicSwap::runSwap(QStringList arguments){
|
|||
fundDialog->show();
|
||||
} else if (line["fields"]["message"].toString().startsWith("Received Bitcoin")){
|
||||
this->updateStatus(line["fields"]["new_balance"].toString().split(" ")[0] + " BTC received, starting swap");
|
||||
this->setSwap(line["span"]["swap_id"].toString());
|
||||
QVariant var;
|
||||
var.setValue(HistoryEntry {QDateTime::currentDateTime(),line["span"]["swap_id"].toString()});
|
||||
QVariantList past = conf()->get(Config::pendingSwap).toList();
|
||||
past.append(var);
|
||||
conf()->set(Config::pendingSwap,past);
|
||||
fundDialog->close();
|
||||
qDebug() << "Spawn atomic swap progress dialog";
|
||||
this->show();
|
||||
} else if ( QString confs = line["fields"]["seen_confirmations"].toString(); !confs.isEmpty()){
|
||||
qDebug() << "Updating xmrconfs " + confs;
|
||||
this->updateXMRConf(confs.toInt());
|
||||
} else if (QString message = line["fields"]["message"].toString(); !QString::compare(message, "Bitcoin transaction status changed")){
|
||||
} else if (QString message = line["fields"]["message"].toString(); 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();
|
||||
bool ok;
|
||||
|
@ -68,9 +70,31 @@ void AtomicSwap::runSwap(QStringList arguments){
|
|||
} else {
|
||||
this->updateStatus("Found txid " + line["fields"]["txid"].toString() + " in mempool");
|
||||
}
|
||||
|
||||
} else if (QString message = line["fields"]["message"].toString(); message.startsWith("Swap completed")){
|
||||
QVariantList past = conf()->get(Config::pendingSwap).toList();
|
||||
past.removeLast();
|
||||
conf()->set(Config::pendingSwap, past);
|
||||
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){
|
||||
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){
|
||||
QString txid = line["fields"]["txid"].toString();
|
||||
QString id = line["span"]["swap_id"].toString();
|
||||
QVariantList past = conf()->get(Config::pendingSwap).toList();
|
||||
for(int i=0;i<past.length();i++){
|
||||
if(QString::compare(past[i].value<HistoryEntry>().id,id)==0) {
|
||||
past.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
conf()->set(Config::pendingSwap, past);
|
||||
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){
|
||||
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");
|
||||
} else if (QString message = line["fields"]["latest_version"].toString(); !message.isEmpty()){
|
||||
conf()->set(Config::swapVersion,message);
|
||||
}
|
||||
//Insert line conditionals here
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -82,18 +106,8 @@ AtomicSwap::~AtomicSwap() {
|
|||
for (const auto& proc : *procList){
|
||||
proc->kill();
|
||||
}
|
||||
if(QString::compare("WINDOWS",conf()->get(Config::operatingSystem).toString()) != 0) {
|
||||
qDebug() << "Closing monero-wallet-rpc";
|
||||
(new QProcess)->start("kill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +
|
||||
"/mainnet/monero/monero-wallet-rpc"});
|
||||
(new QProcess)->start("kill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +
|
||||
"/testnet/monero/monero-wallet-rpc"});
|
||||
}
|
||||
|
||||
}
|
||||
void AtomicSwap::logLine(QString line){
|
||||
//ui->debug_log->setText(ui->debug_log->toPlainText().append(QTime::currentTime().toString() + ":" + line));
|
||||
|
||||
this->update();
|
||||
}
|
||||
void AtomicSwap::updateStatus(QString status){
|
||||
|
@ -117,9 +131,6 @@ void AtomicSwap::setTitle(QString title) {
|
|||
this->update();
|
||||
}
|
||||
|
||||
void AtomicSwap::setSwap(QString swapId){
|
||||
id = std::move(swapId);
|
||||
}
|
||||
|
||||
void AtomicSwap::cancel(){
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ public:
|
|||
void updateBTCConf(int confs);
|
||||
void updateXMRConf(int confs);
|
||||
void setTitle(QString title);
|
||||
void setSwap(QString swapId);
|
||||
public slots:
|
||||
void runSwap(QStringList swap);
|
||||
signals:
|
||||
|
|
|
@ -61,19 +61,45 @@ AtomicWidget::AtomicWidget(QWidget *parent)
|
|||
connect(ui->btn_swap, &QPushButton::clicked, this, [this]{
|
||||
auto rows = ui->offerBookTable->selectionModel()->selectedRows();
|
||||
clean();
|
||||
// UNCOMENT after testing
|
||||
//if (rows.size() < 1){
|
||||
// ui->meta_label->setText("You must select an offer to use for swap, refresh if there aren't any");
|
||||
//} else {
|
||||
//QModelIndex index = rows.at(0);
|
||||
//QString seller = index.sibling(index.row(), 3).data().toString();
|
||||
QString seller = "test";
|
||||
if (rows.size() < 1){
|
||||
ui->meta_label->setText("You must select an offer to use for swap, refresh if there aren't any");
|
||||
} else {
|
||||
QModelIndex index = rows.at(0);
|
||||
QString seller = index.sibling(index.row(), 3).data().toString();
|
||||
//Add proper error checking on ui input after rest of swap is implemented
|
||||
QString btcChange = ui->change_address->text();
|
||||
QRegularExpression btcMain("^(bc1)[a-zA-HJ-NP-Z0-9]{39}$");
|
||||
QRegularExpression btcTest("^(tb1)[a-zA-HJ-NP-Z0-9]{39}$");
|
||||
QString xmrReceive = ui->xmr_address->text();
|
||||
if(xmrReceive.isEmpty()) {
|
||||
QMessageBox::warning(this, "Warning", "XMR receive address is required to start swap");
|
||||
return;
|
||||
}
|
||||
QRegularExpression xmrMain("^[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}");
|
||||
QRegularExpression xmrStage("^[57][0-9AB][1-9A-HJ-NP-Za-km-z]{93}");
|
||||
if (constants::networkType==NetworkType::STAGENET){
|
||||
if(!btcChange.isEmpty() && !btcTest.match(btcChange).hasMatch()){
|
||||
QMessageBox::warning(this, "Warning","BTC change address is wrong, not a bech32 segwit address, or on wrong network");
|
||||
return;
|
||||
}
|
||||
if(!xmrStage.match(xmrReceive).hasMatch()){
|
||||
QMessageBox::warning(this, "Warning","XMR receive address is improperly formated or on wrong network");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(!btcChange.isEmpty() && !btcMain.match(btcChange).hasMatch()){
|
||||
QMessageBox::warning(this, "Warning","BTC change address is wrong, not a bech32 segwit address,or on wrong network");
|
||||
return;
|
||||
}
|
||||
if(!xmrMain.match(xmrReceive).hasMatch()){
|
||||
QMessageBox::warning(this, "Warning","XMR receive address is improperly formated or on wrong network");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
runSwap(seller,btcChange, xmrReceive);
|
||||
//}
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btn_addRendezvous, &QPushButton::clicked, this, [this]{
|
||||
|
@ -89,11 +115,6 @@ AtomicWidget::AtomicWidget(QWidget *parent)
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
//Remove after testing
|
||||
QVariant var;
|
||||
var.setValue(HistoryEntry {QDateTime::currentDateTime(),"test-id"});
|
||||
conf()->set(Config::pendingSwap, QVariantList{var});
|
||||
auto recd = new AtomicRecoverDialog(this);
|
||||
if (!recd->historyEmpty()){
|
||||
recd->show();
|
||||
|
@ -124,18 +145,10 @@ void AtomicWidget::runSwap(const QString& seller, const QString& btcChange, cons
|
|||
arguments << "-j";
|
||||
arguments << "buy-xmr";
|
||||
arguments << "--change-address";
|
||||
arguments << "tb1qzndh6u8qgl2ee4k4gl9erg947g67hyx03vvgen";
|
||||
//arguments << btcChange;
|
||||
arguments << btcChange;
|
||||
arguments << "--receive-address";
|
||||
arguments << "78YnzFTp3UUMgtKuAJCP2STcbxRZPDPveJ5YGgfg5doiPahS9suWF1r3JhKqjM1McYBJvu8nhkXExGfXVkU6n5S6AXrg4KP";
|
||||
//arguments << xmrReceive;
|
||||
arguments << "--seller";
|
||||
arguments << "/ip4/127.0.0.1/tcp/9939/p2p/12D3KooW9yDFYojXnZRdqS9UXcfP2amgwoYdSjujwWdRw4LTSdWw";
|
||||
// Remove after testing
|
||||
arguments << "--electrum-rpc";
|
||||
arguments << "tcp://127.0.0.1:50001";
|
||||
arguments << "--bitcoin-target-block";
|
||||
arguments << "1";
|
||||
arguments << xmrReceive;
|
||||
|
||||
auto nodes = conf()->get(Config::nodes).toJsonObject();
|
||||
if (nodes.isEmpty()) {
|
||||
auto jsonData = conf()->get(Config::nodes).toByteArray();
|
||||
|
@ -144,12 +157,10 @@ void AtomicWidget::runSwap(const QString& seller, const QString& btcChange, cons
|
|||
nodes = doc.object();
|
||||
}
|
||||
}
|
||||
qDebug() << nodes.value("0").toObject()["ws"].toArray()[0];
|
||||
arguments << "--monero-daemon-address";
|
||||
//arguments << "node.monerodevs.org:38089";
|
||||
arguments << nodes.value("0").toObject()["ws"].toArray()[0].toString();
|
||||
// Uncomment after testing
|
||||
//arguments << seller;
|
||||
arguments << "--seller";
|
||||
arguments << seller;
|
||||
if(conf()->get(Config::proxy).toInt() != Config::Proxy::None) {
|
||||
arguments << "--tor-socks5-port";
|
||||
arguments << conf()->get(Config::socks5Port).toString();
|
||||
|
@ -176,23 +187,16 @@ void AtomicWidget::list(const QString& rendezvous) {
|
|||
auto *swap = new QProcess();
|
||||
procList->append(QSharedPointer<QProcess>(swap));
|
||||
swap->setReadChannel(QProcess::StandardError);
|
||||
//swap->start(conf()->get(Config::swapPath).toString(), arguments);
|
||||
connect(swap, &QProcess::finished, this, [this, swap]{
|
||||
QJsonDocument parsedLine;
|
||||
QJsonParseError parseError;
|
||||
QList<QSharedPointer<OfferEntry>> list;
|
||||
qDebug() << "Subprocess has finished";
|
||||
auto output = QString::fromLocal8Bit(swap->readAllStandardError());
|
||||
qDebug() << "Crashes before splitting";
|
||||
auto lines = output.split(QRegularExpression("[\r\n]"),Qt::SkipEmptyParts);
|
||||
qDebug() << lines.size();
|
||||
qDebug() << "parsing Output";
|
||||
|
||||
|
||||
for(const auto& line : lines){
|
||||
qDebug() << line;
|
||||
if(line.contains("status")){
|
||||
qDebug() << "status contained";
|
||||
parsedLine = QJsonDocument::fromJson(line.toLocal8Bit(), &parseError );
|
||||
if (parsedLine["fields"]["status"].toString().contains("Online")){
|
||||
bool skip = false;
|
||||
|
@ -205,17 +209,14 @@ void AtomicWidget::list(const QString& rendezvous) {
|
|||
ui->meta_label->setText("Updated offer book");
|
||||
offerList->append(QSharedPointer<OfferEntry>(entry));
|
||||
}
|
||||
qDebug() << entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
qDebug() << "exits fine";
|
||||
swap->close();
|
||||
o_model->updateOffers(*offerList);
|
||||
return list;
|
||||
});
|
||||
swap->start(conf()->get(Config::swapPath).toString(), arguments);
|
||||
//swap->waitForFinished(120000);
|
||||
|
||||
|
||||
|
||||
|
@ -234,13 +235,6 @@ void AtomicWidget::clean() {
|
|||
for (const auto& proc : *procList){
|
||||
proc->kill();
|
||||
}
|
||||
if(QString::compare("WINDOWS",conf()->get(Config::operatingSystem).toString()) != 0) {
|
||||
qDebug() << "Closing monero-wallet-rpc";
|
||||
(new QProcess)->start("kill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +
|
||||
"/mainnet/monero/monero-wallet-rpc"});
|
||||
(new QProcess)->start("kill", QStringList{"-f", Config::defaultConfigDir().absolutePath() +
|
||||
"/testnet/monero/monero-wallet-rpc"});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ void OfferModel::clear() {
|
|||
|
||||
void OfferModel::updateOffers(const QList<QSharedPointer<OfferEntry>> &posts) {
|
||||
beginResetModel();
|
||||
qDebug() << "updating Offers";
|
||||
m_offers.clear();
|
||||
for (const auto& post : posts) {
|
||||
m_offers.push_back(post);
|
||||
|
|
|
@ -150,6 +150,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
|||
{Config::swapPath, {QS("swapPath"), ""}},
|
||||
{Config::operatingSystem, {QS("operatingSystem"), OS}},
|
||||
{Config::pendingSwap, {QS("pendingSwap"), QVariantList{}}},
|
||||
{Config::swapVersion, {QS("swapVersion"), "0.13.4"}},
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -156,6 +156,7 @@ public:
|
|||
swapPath,
|
||||
operatingSystem,
|
||||
pendingSwap,
|
||||
swapVersion,
|
||||
};
|
||||
|
||||
enum PrivacyLevel {
|
||||
|
|
Loading…
Reference in a new issue