mirror of
https://github.com/feather-wallet/feather.git
synced 2024-11-17 09:47:36 +00:00
Merge pull request 'Initial MorphToken support' (#145) from tobtoht/feather:morphtoken into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/145
This commit is contained in:
commit
b66aceccc8
13 changed files with 744 additions and 3 deletions
174
src/MorphTokenWidget.cpp
Normal file
174
src/MorphTokenWidget.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include "MorphTokenWidget.h"
|
||||
#include "ui_MorphTokenWidget.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
MorphTokenWidget::MorphTokenWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::MorphTokenWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_ctx = MainWindow::getContext();
|
||||
|
||||
m_network = new UtilsNetworking(this->m_ctx->network);
|
||||
m_api = new MorphTokenApi(this, m_network);
|
||||
|
||||
connect(ui->btnCreateTrade, &QPushButton::clicked, this, &MorphTokenWidget::createTrade);
|
||||
connect(ui->btn_lookupTrade, &QPushButton::clicked, this, &MorphTokenWidget::lookupTrade);
|
||||
|
||||
connect(m_api, &MorphTokenApi::ApiResponse, this, &MorphTokenWidget::onApiResponse);
|
||||
|
||||
connect(ui->combo_From, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index){
|
||||
ui->label_refundAddress->setText(QString("Refund address (%1):").arg(ui->combo_From->currentText()));
|
||||
});
|
||||
connect(ui->combo_To, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index){
|
||||
ui->label_destinationAddress->setText(QString("Destination address (%1):").arg(ui->combo_To->currentText()));
|
||||
});
|
||||
|
||||
connect(ui->check_autorefresh, &QCheckBox::toggled, [this](bool toggled){
|
||||
m_countdown = 30;
|
||||
toggled ? m_countdownTimer.start(1000) : m_countdownTimer.stop();
|
||||
ui->check_autorefresh->setText("Autorefresh");
|
||||
});
|
||||
connect(&m_countdownTimer, &QTimer::timeout, this, &MorphTokenWidget::onCountdown);
|
||||
|
||||
connect(ui->line_Id, &QLineEdit::textChanged, [this](const QString &text){
|
||||
ui->btn_lookupTrade->setEnabled(!text.isEmpty());
|
||||
ui->check_autorefresh->setEnabled(!text.isEmpty());
|
||||
});
|
||||
|
||||
// Default to BTC -> XMR
|
||||
ui->combo_From->setCurrentIndex(1);
|
||||
ui->combo_To->setCurrentIndex(0);
|
||||
|
||||
ui->tabWidget->setTabVisible(2, false);
|
||||
}
|
||||
|
||||
void MorphTokenWidget::createTrade() {
|
||||
QString inputAsset = ui->combo_From->currentText();
|
||||
QString outputAsset = ui->combo_To->currentText();
|
||||
QString refundAddress = ui->line_refundAddress->text();
|
||||
QString destinationAddress = ui->line_destinationAddress->text();
|
||||
|
||||
m_api->createTrade(inputAsset, outputAsset, refundAddress, destinationAddress);
|
||||
}
|
||||
|
||||
void MorphTokenWidget::lookupTrade() {
|
||||
QString morphId = ui->line_Id->text();
|
||||
|
||||
if (!morphId.isEmpty())
|
||||
m_api->getTrade(morphId);
|
||||
}
|
||||
|
||||
void MorphTokenWidget::onApiResponse(const MorphTokenApi::MorphTokenResponse &resp) {
|
||||
if (!resp.ok) {
|
||||
ui->check_autorefresh->setChecked(false);
|
||||
QMessageBox::warning(this, "MorphToken error", QString("Request failed:\n\n%1").arg(resp.message));
|
||||
return;
|
||||
}
|
||||
|
||||
ui->debugInfo->setPlainText(QJsonDocument(resp.obj).toJson(QJsonDocument::Indented));
|
||||
|
||||
if (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE || resp.endpoint == MorphTokenApi::Endpoint::GET_TRADE) {
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
ui->line_Id->setText(resp.obj.value("id").toString());
|
||||
|
||||
auto obj = resp.obj;
|
||||
auto input = obj["input"].toObject();
|
||||
auto output = obj["output"].toArray()[0].toObject();
|
||||
QString state = obj.value("state").toString();
|
||||
QString statusText;
|
||||
|
||||
ui->trade->setTitle(QString("Trade (%1)").arg(state));
|
||||
|
||||
statusText += QString("Morph ID: %1\n\n").arg(obj["id"].toString());
|
||||
|
||||
if (state == "PENDING") {
|
||||
statusText += QString("Waiting for a deposit, send %1 to %2\n").arg(input["asset"].toString(),
|
||||
input["deposit_address"].toString());
|
||||
statusText += QString("Rate: 1 %1 -> %2 %3\n\n").arg(input["asset"].toString(),
|
||||
output["seen_rate"].toString(),
|
||||
output["asset"].toString());
|
||||
statusText += "Limits:\n";
|
||||
statusText += QString(" Minimum amount accepted: %1 %2\n").arg(formatAmount(input["asset"].toString(), input["limits"].toObject()["min"].toDouble()),
|
||||
input["asset"].toString());
|
||||
statusText += QString(" Maximum amount accepted: %1 %2\n").arg(formatAmount(input["asset"].toString(), input["limits"].toObject()["max"].toDouble()),
|
||||
input["asset"].toString());
|
||||
statusText += QString("\nSend a single deposit. If the amount is outside the limits, a refund will happen.");
|
||||
} else if (state == "PROCESSING" || state == "TRADING" || state == "CONFIRMING") {
|
||||
if (state == "CONFIRMING") {
|
||||
statusText += QString("Waiting for confirmations\n");
|
||||
} else if (state == "TRADING") {
|
||||
statusText += QString("Your transaction has been received and is confirmed. MorphToken is now executing your trade.\n"
|
||||
"Usually this step takes no longer than a minute, "
|
||||
"but in rare cases it can take a couple hours.\n"
|
||||
"Wait a bit before contacting support.\n");
|
||||
}
|
||||
statusText += QString("Converting %1 to %2\n").arg(input["asset"].toString(), output["asset"].toString());
|
||||
statusText += QString("Sending to %1\n").arg(output["address"].toString());
|
||||
statusText += QString("Stuck? Contact support at contact@morphtoken.com");
|
||||
} else if (state == "COMPLETE") {
|
||||
if (output["txid"].toString().isEmpty()) {
|
||||
statusText += QString("MorphToken is sending your transaction.\n");
|
||||
statusText += QString("MorphToken will send %1 %2 to %2").arg(this->formatAmount(output["asset"].toString(), output["converted_amount"].toDouble() - output["network_fee"].toObject()["fee"].toDouble()),
|
||||
output["asset"].toString(),
|
||||
output["address"].toString());
|
||||
} else {
|
||||
statusText += QString("Sent %1 %2 to %3\ntxid: {}").arg(this->formatAmount(output["asset"].toString(), output["converted_amount"].toDouble() - output["network_fee"].toObject()["fee"].toDouble()),
|
||||
output["asset"].toString(),
|
||||
output["address"].toString(),
|
||||
output["txid"].toString());
|
||||
}
|
||||
} else if (state == "PROCESSING_REFUND" || state == "COMPLETE_WITH_REFUND") {
|
||||
statusText += QString("MorphToken will refund %1 %2\nReason: %3\n").arg(obj["final_amount"].toString(),
|
||||
obj["asset"].toString(),
|
||||
obj["reason"].toString());
|
||||
|
||||
if (obj.contains("txid")) {
|
||||
statusText += QString("txid: %1").arg(obj["txid"].toString());
|
||||
}
|
||||
} else if (state == "COMPLETE_WITHOUT_REFUND") {
|
||||
statusText += "Deposit amount below network fee, too small to refund.";
|
||||
}
|
||||
|
||||
ui->label_status->setText(statusText);
|
||||
}
|
||||
|
||||
if (resp.endpoint == MorphTokenApi::Endpoint::CREATE_TRADE) {
|
||||
QMessageBox::information(this, "MorphToken", "Trade created!\n\nMake sure to save your Morph ID. You may need it in case something goes wrong.");
|
||||
}
|
||||
}
|
||||
|
||||
void MorphTokenWidget::onCountdown() {
|
||||
if (m_countdown > 0) {
|
||||
m_countdown -= 1;
|
||||
} else {
|
||||
this->lookupTrade();
|
||||
m_countdown = 30;
|
||||
}
|
||||
ui->check_autorefresh->setText(QString("Autorefresh (%1)").arg(m_countdown));
|
||||
}
|
||||
|
||||
QString MorphTokenWidget::formatAmount(const QString &asset, double amount) {
|
||||
double displayAmount;
|
||||
double div;
|
||||
|
||||
if (asset == "ETH")
|
||||
div = 1e18;
|
||||
else if (asset == "XMR")
|
||||
div = 1e12;
|
||||
else
|
||||
div = 1e8;
|
||||
|
||||
displayAmount = amount / div;
|
||||
|
||||
return QString::number(displayAmount, 'f', 8);
|
||||
}
|
||||
|
||||
MorphTokenWidget::~MorphTokenWidget() {
|
||||
delete ui;
|
||||
}
|
41
src/MorphTokenWidget.h
Normal file
41
src/MorphTokenWidget.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_MORPHTOKENWIDGET_H
|
||||
#define FEATHER_MORPHTOKENWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "appcontext.h"
|
||||
#include "utils/MorphTokenApi.h"
|
||||
|
||||
namespace Ui {
|
||||
class MorphTokenWidget;
|
||||
}
|
||||
|
||||
class MorphTokenWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MorphTokenWidget(QWidget *parent = nullptr);
|
||||
~MorphTokenWidget() override;
|
||||
|
||||
private:
|
||||
void createTrade();
|
||||
void lookupTrade();
|
||||
void onApiResponse(const MorphTokenApi::MorphTokenResponse &resp);
|
||||
|
||||
void onCountdown();
|
||||
|
||||
QString formatAmount(const QString &asset, double amount);
|
||||
|
||||
Ui::MorphTokenWidget *ui;
|
||||
|
||||
AppContext *m_ctx;
|
||||
MorphTokenApi *m_api;
|
||||
UtilsNetworking *m_network;
|
||||
QTimer m_countdownTimer;
|
||||
int m_countdown = 30;
|
||||
};
|
||||
|
||||
#endif //FEATHER_MORPHTOKENWIDGET_H
|
348
src/MorphTokenWidget.ui
Normal file
348
src/MorphTokenWidget.ui
Normal file
|
@ -0,0 +1,348 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MorphTokenWidget</class>
|
||||
<widget class="QWidget" name="MorphTokenWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1036</width>
|
||||
<height>614</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</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="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabCreateTrade">
|
||||
<attribute name="title">
|
||||
<string>Create trade</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>From:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_From">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>XMR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ETH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BCH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>LTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DASH</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>To:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_To">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>XMR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ETH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BCH</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>LTC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DASH</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_refundAddress">
|
||||
<property name="text">
|
||||
<string>Refund address (XMR):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="line_refundAddress"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_destinationAddress">
|
||||
<property name="text">
|
||||
<string>Destination address (XMR):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="line_destinationAddress"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Powered by MorphToken.com</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCreateTrade">
|
||||
<property name="text">
|
||||
<string>Create Trade</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<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>
|
||||
<widget class="QWidget" name="tabLookupTrade">
|
||||
<attribute name="title">
|
||||
<string>Lookup trade</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Morph ID or MorphToken deposit address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="line_Id"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="check_autorefresh">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Autorefresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_lookupTrade">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lookup trade</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="trade">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Trade</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_status">
|
||||
<property name="text">
|
||||
<string>No trade loaded.</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</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>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabDebug">
|
||||
<attribute name="title">
|
||||
<string>Debug</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="debugInfo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -181,7 +181,7 @@ void AppContext::initTor() {
|
|||
this->tor = new Tor(this, this);
|
||||
this->tor->start();
|
||||
|
||||
if (!(isTails || isWhonix)) {
|
||||
if (!(isWhonix)) {
|
||||
auto networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
|
||||
this->network->setProxy(*networkProxy);
|
||||
if (m_wsUrl.host().endsWith(".onion"))
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
<file>assets/images/lock_icon.png</file>
|
||||
<file>assets/images/lock.svg</file>
|
||||
<file>assets/images/microphone.png</file>
|
||||
<file>assets/images/morphtoken.png</file>
|
||||
<file>assets/images/network.png</file>
|
||||
<file>assets/images/offline_tx.png</file>
|
||||
<file>assets/images/person.svg</file>
|
||||
|
|
BIN
src/assets/images/morphtoken.png
Normal file
BIN
src/assets/images/morphtoken.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
|
@ -406,6 +406,10 @@ void MainWindow::initMenu() {
|
|||
m_tabShowHideMapper["Calc"] = new ToggleTab(ui->tabCalc, "Calc", "Calc", ui->actionShow_calc, Config::showTabCalc);
|
||||
m_tabShowHideSignalMapper->setMapping(ui->actionShow_calc, "Calc");
|
||||
|
||||
connect(ui->actionShow_MorphToken, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
m_tabShowHideMapper["MorphToken"] = new ToggleTab(ui->tabMorphToken, "MorphToken", "MorphToken", ui->actionShow_MorphToken, Config::showTabMorphToken);
|
||||
m_tabShowHideSignalMapper->setMapping(ui->actionShow_MorphToken, "MorphToken");
|
||||
|
||||
#if defined(XMRTO)
|
||||
connect(ui->actionShow_xmr_to, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
m_tabShowHideMapper["XMRto"] = new ToggleTab(ui->tabXmrTo, "XMRto", "XMR.to", ui->actionShow_xmr_to, Config::showTabXMRto);
|
||||
|
|
|
@ -76,6 +76,7 @@ public:
|
|||
RECEIVE,
|
||||
COINS,
|
||||
CALC,
|
||||
MORPHTOKEN,
|
||||
XMR_TO,
|
||||
XMRIG
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>894</width>
|
||||
<width>1156</width>
|
||||
<height>496</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -238,6 +238,20 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabMorphToken">
|
||||
<attribute name="icon">
|
||||
<iconset resource="assets.qrc">
|
||||
<normaloff>:/assets/images/morphtoken.png</normaloff>:/assets/images/morphtoken.png</iconset>
|
||||
</attribute>
|
||||
<attribute name="title">
|
||||
<string>MorphToken</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="MorphTokenWidget" name="morphtokenWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabXmrTo">
|
||||
<attribute name="icon">
|
||||
<iconset resource="assets.qrc">
|
||||
|
@ -304,7 +318,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>894</width>
|
||||
<width>1156</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -418,6 +432,7 @@
|
|||
</property>
|
||||
<addaction name="actionShow_Coins"/>
|
||||
<addaction name="actionShow_calc"/>
|
||||
<addaction name="actionShow_MorphToken"/>
|
||||
<addaction name="actionShow_xmr_to"/>
|
||||
<addaction name="actionShow_XMRig"/>
|
||||
</widget>
|
||||
|
@ -670,6 +685,11 @@
|
|||
<string>Import transaction</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShow_MorphToken">
|
||||
<property name="text">
|
||||
<string>Show MorphToken</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
@ -714,6 +734,12 @@
|
|||
<header>calcwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MorphTokenWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>MorphTokenWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="assets.qrc"/>
|
||||
|
|
93
src/utils/MorphTokenApi.cpp
Normal file
93
src/utils/MorphTokenApi.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#include "MorphTokenApi.h"
|
||||
|
||||
MorphTokenApi::MorphTokenApi(QObject *parent, UtilsNetworking *network, QString baseUrl)
|
||||
: QObject(parent)
|
||||
, m_network(network)
|
||||
, m_baseUrl(std::move(baseUrl))
|
||||
{
|
||||
}
|
||||
|
||||
void MorphTokenApi::createTrade(const QString &inputAsset, const QString &outputAsset, const QString &refundAddress, const QString &outputAddress) {
|
||||
QJsonObject trade;
|
||||
|
||||
QJsonObject input;
|
||||
input["asset"] = inputAsset;
|
||||
input["refund"] = refundAddress;
|
||||
|
||||
QJsonArray output;
|
||||
QJsonObject outputObj;
|
||||
outputObj["asset"] = outputAsset;
|
||||
outputObj["weight"] = 10000;
|
||||
outputObj["address"] = outputAddress;
|
||||
output.append(outputObj);
|
||||
|
||||
trade["input"] = input;
|
||||
trade["output"] = output;
|
||||
|
||||
QString url = QString("%1/morph").arg(m_baseUrl);
|
||||
QNetworkReply *reply = m_network->postJson(url, trade);
|
||||
connect(reply, &QNetworkReply::finished, std::bind(&MorphTokenApi::onResponse, this, reply, Endpoint::CREATE_TRADE));
|
||||
}
|
||||
|
||||
void MorphTokenApi::getTrade(const QString &morphId) {
|
||||
QString url = QString("%1/morph/%2").arg(m_baseUrl, morphId);
|
||||
QNetworkReply *reply = m_network->getJson(url);
|
||||
connect(reply, &QNetworkReply::finished, std::bind(&MorphTokenApi::onResponse, this, reply, Endpoint::GET_TRADE));
|
||||
}
|
||||
|
||||
void MorphTokenApi::getRates() {
|
||||
QString url = QString("%1/rates").arg(m_baseUrl);
|
||||
QNetworkReply *reply = m_network->getJson(url);
|
||||
connect(reply, &QNetworkReply::finished, std::bind(&MorphTokenApi::onResponse, this, reply, Endpoint::GET_RATES));
|
||||
}
|
||||
|
||||
void MorphTokenApi::getLimits(const QString &inputAsset, const QString &outputAsset) {
|
||||
QJsonObject limits;
|
||||
|
||||
QJsonObject input;
|
||||
input["asset"] = inputAsset;
|
||||
|
||||
QJsonArray output;
|
||||
QJsonObject outputObj;
|
||||
outputObj["asset"] = outputAsset;
|
||||
outputObj["weight"] = 10000;
|
||||
output.append(outputObj);
|
||||
|
||||
limits["input"] = input;
|
||||
limits["output"] = output;
|
||||
|
||||
QString url = QString("%1/limits").arg(m_baseUrl);
|
||||
QNetworkReply *reply = m_network->postJson(url, limits);
|
||||
connect(reply, &QNetworkReply::finished, std::bind(&MorphTokenApi::onResponse, this, reply, Endpoint::GET_LIMITS));
|
||||
}
|
||||
|
||||
void MorphTokenApi::onResponse(QNetworkReply *reply, Endpoint endpoint) {
|
||||
const auto ok = reply->error() == QNetworkReply::NoError;
|
||||
const auto err = reply->errorString();
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
QJsonObject obj;
|
||||
if (!data.isEmpty() && Utils::validateJSON(data)) {
|
||||
auto doc = QJsonDocument::fromJson(data);
|
||||
obj = doc.object();
|
||||
}
|
||||
else if (!ok) {
|
||||
emit ApiResponse(MorphTokenResponse(false, endpoint, err, {}));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
emit ApiResponse(MorphTokenResponse(false, endpoint, "Invalid response from MorphToken", {}));
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj.contains("success")) {
|
||||
emit ApiResponse(MorphTokenResponse(false, endpoint, obj.value("description").toString(), obj));
|
||||
return;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
emit ApiResponse(MorphTokenResponse(true, endpoint, "", obj));
|
||||
}
|
51
src/utils/MorphTokenApi.h
Normal file
51
src/utils/MorphTokenApi.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_MORPHTOKENAPI_H
|
||||
#define FEATHER_MORPHTOKENAPI_H
|
||||
|
||||
#include <QObject>
|
||||
#include <utility>
|
||||
#include "utils/networking.h"
|
||||
|
||||
class MorphTokenApi : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Endpoint {
|
||||
CREATE_TRADE = 0,
|
||||
GET_TRADE,
|
||||
GET_RATES,
|
||||
GET_LIMITS
|
||||
};
|
||||
|
||||
struct MorphTokenResponse {
|
||||
explicit MorphTokenResponse(bool ok, Endpoint endpoint, QString message, QJsonObject obj)
|
||||
: ok(ok), endpoint(endpoint), message(std::move(message)), obj(std::move(obj)) {};
|
||||
|
||||
bool ok;
|
||||
Endpoint endpoint;
|
||||
QString message;
|
||||
QJsonObject obj;
|
||||
};
|
||||
|
||||
explicit MorphTokenApi(QObject *parent, UtilsNetworking *network, QString baseUrl = "https://api.morphtoken.com");
|
||||
|
||||
void createTrade(const QString &inputAsset, const QString &outputAsset, const QString &refundAddress, const QString &outputAddress);
|
||||
void getTrade(const QString &morphId);
|
||||
void getRates();
|
||||
void getLimits(const QString &inputAsset, const QString &outputAsset);
|
||||
|
||||
signals:
|
||||
void ApiResponse(MorphTokenResponse resp);
|
||||
|
||||
private slots:
|
||||
void onResponse(QNetworkReply *reply, Endpoint endpoint);
|
||||
|
||||
private:
|
||||
QString m_baseUrl;
|
||||
UtilsNetworking *m_network;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_MORPHTOKENAPI_H
|
|
@ -41,6 +41,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
|||
{Config::nodeSource,{QS("nodeSource"), 0}},
|
||||
{Config::useOnionNodes,{QS("useOnionNodes"), false}},
|
||||
{Config::showTabCoins,{QS("showTabCoins"), false}},
|
||||
{Config::showTabMorphToken, {QS("showTabMorphToken"), false}},
|
||||
{Config::showTabXMRto,{QS("showTabXMRto"), true}},
|
||||
{Config::showTabXMRig,{QS("showTabXMRig"), false}},
|
||||
{Config::showTabCalc,{QS("showTabCalc"), true}},
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
nodeSource,
|
||||
useOnionNodes,
|
||||
showTabCoins,
|
||||
showTabMorphToken,
|
||||
showTabXMRto,
|
||||
showTabCalc,
|
||||
showTabXMRig,
|
||||
|
|
Loading…
Reference in a new issue