mirror of
				https://git.wownero.com/wowlet/wowlet.git
				synced 2024-08-15 01:03:14 +00:00 
			
		
		
		
	Merge pull request 'Exchanges: Remove XMR.to' (#316) from tobtoht/feather:rip_to into master
Reviewed-on: https://git.wownero.com/feather/feather/pulls/316
This commit is contained in:
		
						commit
						e3f6b73ab2
					
				
					 24 changed files with 2 additions and 1863 deletions
				
			
		| 
						 | 
				
			
			@ -10,7 +10,6 @@ set(VERSION_REVISION "0")
 | 
			
		|||
set(VERSION "beta-3")
 | 
			
		||||
 | 
			
		||||
option(FETCH_DEPS "Download dependencies if they are not found" ON)
 | 
			
		||||
option(XMRTO "Include Xmr.To module" ON)
 | 
			
		||||
option(XMRIG "Include XMRig module" ON)
 | 
			
		||||
option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,7 +41,6 @@ via the `CMAKE_PREFIX_PATH` definition. For me this is:
 | 
			
		|||
 | 
			
		||||
There are some Monero/Feather related options/definitions that you may pass:
 | 
			
		||||
 | 
			
		||||
- `-DXMRTO=OFF` - disable Xmr.To feature
 | 
			
		||||
- `-DXMRIG=OFF` - disable XMRig feature
 | 
			
		||||
- `-DTOR_BIN=/path/to/tor` - Embed a Tor executable inside Feather
 | 
			
		||||
- `-DDONATE_BEG=OFF` - disable the dreaded donate requests
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -30,7 +30,6 @@ CMAKEFLAGS = \
 | 
			
		|||
	-DARCH=x86_64 \
 | 
			
		||||
	-DBUILD_64=On \
 | 
			
		||||
	-DBUILD_TESTS=Off \
 | 
			
		||||
	-DXMRTO=On \
 | 
			
		||||
	-DXMRIG=On \
 | 
			
		||||
	-DTOR_BIN=Off \
 | 
			
		||||
	-DCMAKE_CXX_STANDARD=11 \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -122,10 +122,6 @@ if(DONATE_BEG)
 | 
			
		|||
    target_compile_definitions(feather PRIVATE DONATE_BEG=1)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(XMRTO)
 | 
			
		||||
    target_compile_definitions(feather PRIVATE HAS_XMRTO=1)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(TOR_BIN)
 | 
			
		||||
    target_compile_definitions(feather PRIVATE HAS_TOR_BIN=1)
 | 
			
		||||
endif()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -132,11 +132,6 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
 | 
			
		|||
    // fiat/crypto lookup
 | 
			
		||||
    AppContext::prices = new Prices();
 | 
			
		||||
 | 
			
		||||
    // xmr.to
 | 
			
		||||
#ifdef HAS_XMRTO
 | 
			
		||||
    this->XMRTo = new XmrTo(this);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // XMRig
 | 
			
		||||
#ifdef HAS_XMRIG
 | 
			
		||||
    this->XMRig = new XmRig(this->configDirectory, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +166,6 @@ void AppContext::initTor() {
 | 
			
		|||
        if (m_wsUrl.host().endsWith(".onion"))
 | 
			
		||||
            this->ws->webSocket.setProxy(*networkProxy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AppContext::initWS() {
 | 
			
		||||
| 
						 | 
				
			
			@ -199,13 +193,6 @@ void AppContext::onSweepOutput(const QString &keyImage, QString address, bool ch
 | 
			
		|||
    this->currentWallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AppContext::onCreateTransaction(XmrToOrder *order) {
 | 
			
		||||
    // tx creation via xmr.to
 | 
			
		||||
    const QString description = QString("XmrTo order %1").arg(order->uuid);
 | 
			
		||||
    quint64 amount = WalletManager::amountFromDouble(order->incoming_amount_total);
 | 
			
		||||
    this->onCreateTransaction(order->receiving_subaddress, amount, description, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AppContext::onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all) {
 | 
			
		||||
    // tx creation
 | 
			
		||||
    this->tmpTxDescription = description;
 | 
			
		||||
| 
						 | 
				
			
			@ -434,12 +421,6 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
 | 
			
		|||
        QJsonObject fiat_rates = msg.value("data").toObject();
 | 
			
		||||
        AppContext::prices->fiatPricesReceived(fiat_rates);
 | 
			
		||||
    }
 | 
			
		||||
#if defined(HAS_XMRTO)
 | 
			
		||||
    else if(cmd == "xmrto_rates") {
 | 
			
		||||
        auto xmr_rates = msg.value("data").toObject();
 | 
			
		||||
        this->XMRTo->onRatesReceived(xmr_rates);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    else if(cmd == "reddit") {
 | 
			
		||||
        QJsonArray reddit_data = msg.value("data").toArray();
 | 
			
		||||
        this->onWSReddit(reddit_data);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,6 @@
 | 
			
		|||
#include "utils/prices.h"
 | 
			
		||||
#include "utils/networking.h"
 | 
			
		||||
#include "utils/tor.h"
 | 
			
		||||
#include "utils/xmrto.h"
 | 
			
		||||
#include "utils/xmrig.h"
 | 
			
		||||
#include "utils/wsclient.h"
 | 
			
		||||
#include "utils/txfiathistory.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -81,7 +80,6 @@ public:
 | 
			
		|||
 | 
			
		||||
    Tor *tor{};
 | 
			
		||||
    WSClient *ws;
 | 
			
		||||
    XmrTo *XMRTo;
 | 
			
		||||
    XmRig *XMRig;
 | 
			
		||||
    Nodes *nodes;
 | 
			
		||||
    static Prices *prices;
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +112,6 @@ public:
 | 
			
		|||
public slots:
 | 
			
		||||
    void onOpenWallet(const QString& path, const QString &password);
 | 
			
		||||
    void onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all);
 | 
			
		||||
    void onCreateTransaction(XmrToOrder *order);
 | 
			
		||||
    void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
 | 
			
		||||
    void onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address);
 | 
			
		||||
    void onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@
 | 
			
		|||
    <file>assets/images/cutexmrfox.png</file>
 | 
			
		||||
    <file>assets/images/edit.png</file>
 | 
			
		||||
    <file>assets/images/exchange.png</file>
 | 
			
		||||
    <file>assets/images/exchange_white.png</file>
 | 
			
		||||
    <file>assets/images/expired.png</file>
 | 
			
		||||
    <file>assets/images/expired_icon.png</file>
 | 
			
		||||
    <file>assets/images/eye1.png</file>
 | 
			
		||||
| 
						 | 
				
			
			@ -97,8 +98,6 @@
 | 
			
		|||
    <file>assets/images/unpaid.png</file>
 | 
			
		||||
    <file>assets/images/update.png</file>
 | 
			
		||||
    <file>assets/images/warning.png</file>
 | 
			
		||||
    <file>assets/images/xmrto_big.png</file>
 | 
			
		||||
    <file>assets/images/xmrto.png</file>
 | 
			
		||||
    <file>assets/images/xmrig.ico</file>
 | 
			
		||||
    <file>assets/images/xmrig.svg</file>
 | 
			
		||||
    <file>assets/images/zoom.png</file>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/exchange_white.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/images/exchange_white.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1,000 B  | 
| 
						 | 
				
			
			@ -1,35 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#include "xmrtoinfodialog.h"
 | 
			
		||||
#include "ui_xmrtoinfodialog.h"
 | 
			
		||||
 | 
			
		||||
XmrToInfoDialog::XmrToInfoDialog(XmrToOrder *oInfo, QWidget *parent)
 | 
			
		||||
        : QDialog(parent)
 | 
			
		||||
        , ui(new Ui::XmrToInfoDialog)
 | 
			
		||||
        , m_oInfo(oInfo)
 | 
			
		||||
{
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    ui->status->setText(XmrTo::stateMap[(OrderState) oInfo->state]);
 | 
			
		||||
    ui->xmrto_id->setText(!oInfo->uuid.isEmpty() ? oInfo->uuid : "");
 | 
			
		||||
 | 
			
		||||
    ui->error_code->setText(!oInfo->errorCode.isEmpty() ? oInfo->errorCode : "");
 | 
			
		||||
    ui->error_msg->setText(!oInfo->errorMsg.isEmpty() ? oInfo->errorMsg : "");
 | 
			
		||||
 | 
			
		||||
    ui->xmr_amount->setText(QString::number(oInfo->incoming_amount_total));
 | 
			
		||||
    ui->btc_amount->setText(QString::number(oInfo->btc_amount));
 | 
			
		||||
    ui->rate->setText(oInfo->incoming_price_btc > 0 ? QString::number(oInfo->incoming_price_btc) : "");
 | 
			
		||||
 | 
			
		||||
    ui->xmr_txid->setText(oInfo->xmr_txid);
 | 
			
		||||
    ui->xmr_address->setText(oInfo->receiving_subaddress);
 | 
			
		||||
 | 
			
		||||
    ui->btc_txid->setText(oInfo->btc_txid);
 | 
			
		||||
    ui->btc_address->setText(oInfo->btc_dest_address);
 | 
			
		||||
 | 
			
		||||
    this->adjustSize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
XmrToInfoDialog::~XmrToInfoDialog() {
 | 
			
		||||
    delete ui;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,28 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#ifndef FEATHER_XMRTOINFODIALOG_H
 | 
			
		||||
#define FEATHER_XMRTOINFODIALOG_H
 | 
			
		||||
 | 
			
		||||
#include <QDialog>
 | 
			
		||||
#include "utils/xmrto.h"
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
    class XmrToInfoDialog;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class XmrToInfoDialog : public QDialog
 | 
			
		||||
{
 | 
			
		||||
Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit XmrToInfoDialog(XmrToOrder *oInfo, QWidget *parent = nullptr);
 | 
			
		||||
    ~XmrToInfoDialog() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Ui::XmrToInfoDialog *ui;
 | 
			
		||||
 | 
			
		||||
    XmrToOrder *m_oInfo;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif //FEATHER_XMRTOINFODIALOG_H
 | 
			
		||||
| 
						 | 
				
			
			@ -1,256 +0,0 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<ui version="4.0">
 | 
			
		||||
 <class>XmrToInfoDialog</class>
 | 
			
		||||
 <widget class="QWidget" name="XmrToInfoDialog">
 | 
			
		||||
  <property name="geometry">
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>689</width>
 | 
			
		||||
    <height>581</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="windowTitle">
 | 
			
		||||
   <string>Xmr.to Order</string>
 | 
			
		||||
  </property>
 | 
			
		||||
  <layout class="QVBoxLayout" name="verticalLayout">
 | 
			
		||||
   <item>
 | 
			
		||||
    <layout class="QHBoxLayout" name="horizontalLayout">
 | 
			
		||||
     <item>
 | 
			
		||||
      <layout class="QFormLayout" name="formLayout_2">
 | 
			
		||||
       <item row="0" column="0">
 | 
			
		||||
        <widget class="QLabel" name="label_10">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>Status:</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="1" column="0">
 | 
			
		||||
        <widget class="QLabel" name="label_16">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>XMR.to ID:</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="2" column="0">
 | 
			
		||||
        <widget class="QLabel" name="label_17">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>Error code:</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="0" column="1">
 | 
			
		||||
        <widget class="QLineEdit" name="status">
 | 
			
		||||
         <property name="readOnly">
 | 
			
		||||
          <bool>true</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="1" column="1">
 | 
			
		||||
        <widget class="QLineEdit" name="xmrto_id">
 | 
			
		||||
         <property name="readOnly">
 | 
			
		||||
          <bool>true</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="2" column="1">
 | 
			
		||||
        <widget class="QLineEdit" name="error_code">
 | 
			
		||||
         <property name="readOnly">
 | 
			
		||||
          <bool>true</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
      </layout>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="Line" name="line_5">
 | 
			
		||||
       <property name="orientation">
 | 
			
		||||
        <enum>Qt::Vertical</enum>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <layout class="QFormLayout" name="formLayout_3">
 | 
			
		||||
       <item row="0" column="0">
 | 
			
		||||
        <widget class="QLabel" name="label_14">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>XMR amount:</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="1" column="0">
 | 
			
		||||
        <widget class="QLabel" name="label_20">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>BTC amount:</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="2" column="0">
 | 
			
		||||
        <widget class="QLabel" name="label_22">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>Rate:</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="0" column="1">
 | 
			
		||||
        <widget class="QLineEdit" name="xmr_amount">
 | 
			
		||||
         <property name="readOnly">
 | 
			
		||||
          <bool>true</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="1" column="1">
 | 
			
		||||
        <widget class="QLineEdit" name="btc_amount">
 | 
			
		||||
         <property name="readOnly">
 | 
			
		||||
          <bool>true</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item row="2" column="1">
 | 
			
		||||
        <widget class="QLineEdit" name="rate">
 | 
			
		||||
         <property name="readOnly">
 | 
			
		||||
          <bool>true</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
      </layout>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLabel" name="label">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Message:</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLineEdit" name="error_msg">
 | 
			
		||||
       <property name="readOnly">
 | 
			
		||||
        <bool>true</bool>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="Line" name="line">
 | 
			
		||||
       <property name="orientation">
 | 
			
		||||
        <enum>Qt::Horizontal</enum>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLabel" name="label_3">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>XMR.to address:</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLineEdit" name="xmr_address">
 | 
			
		||||
       <property name="readOnly">
 | 
			
		||||
        <bool>true</bool>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLabel" name="label_2">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>XMR txid:</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLineEdit" name="xmr_txid">
 | 
			
		||||
       <property name="readOnly">
 | 
			
		||||
        <bool>true</bool>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="Line" name="line_3">
 | 
			
		||||
       <property name="orientation">
 | 
			
		||||
        <enum>Qt::Horizontal</enum>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLabel" name="label_12">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>BTC address:</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLineEdit" name="btc_address">
 | 
			
		||||
       <property name="readOnly">
 | 
			
		||||
        <bool>true</bool>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLabel" name="label_5">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>BTC txid:</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QLineEdit" name="btc_txid">
 | 
			
		||||
       <property name="readOnly">
 | 
			
		||||
        <bool>true</bool>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <widget class="Line" name="line_2">
 | 
			
		||||
     <property name="orientation">
 | 
			
		||||
      <enum>Qt::Horizontal</enum>
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <layout class="QHBoxLayout" name="horizontalLayout_10">
 | 
			
		||||
     <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="pushButton">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Copy support template</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </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>
 | 
			
		||||
 <resources/>
 | 
			
		||||
 <connections/>
 | 
			
		||||
</ui>
 | 
			
		||||
| 
						 | 
				
			
			@ -97,22 +97,6 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
 | 
			
		|||
    connect(ui->actionShow_debug_info, &QAction::triggered, this, &MainWindow::showDebugInfo);
 | 
			
		||||
    connect(ui->actionOfficialWebsite, &QAction::triggered, [=] { Utils::externalLinkWarning(this, "https://featherwallet.org"); });
 | 
			
		||||
 | 
			
		||||
#if defined(HAS_XMRTO)
 | 
			
		||||
    // xmr.to connects/widget
 | 
			
		||||
    connect(ui->xmrToWidget, &XMRToWidget::viewOrder, m_ctx->XMRTo, &XmrTo::onViewOrder);
 | 
			
		||||
    connect(ui->xmrToWidget, &XMRToWidget::getRates, m_ctx->XMRTo, &XmrTo::onGetRates);
 | 
			
		||||
    connect(ui->xmrToWidget, &XMRToWidget::createOrder, m_ctx->XMRTo, &XmrTo::createOrder);
 | 
			
		||||
    connect(m_ctx->XMRTo, &XmrTo::ratesUpdated, ui->xmrToWidget, &XMRToWidget::onRatesUpdated);
 | 
			
		||||
    connect(m_ctx->XMRTo, &XmrTo::connectionError, ui->xmrToWidget, &XMRToWidget::onConnectionError);
 | 
			
		||||
    connect(m_ctx->XMRTo, &XmrTo::connectionSuccess, ui->xmrToWidget, &XMRToWidget::onConnectionSuccess);
 | 
			
		||||
    connect(m_ctx, &AppContext::balanceUpdated, ui->xmrToWidget, &XMRToWidget::onBalanceUpdated);
 | 
			
		||||
    connect(m_ctx->XMRTo, &XmrTo::openURL, this, [=](const QString &url){ Utils::externalLinkWarning(this, url); });
 | 
			
		||||
    connect(m_ctx, &AppContext::walletClosed, ui->xmrToWidget, &XMRToWidget::onWalletClosed);
 | 
			
		||||
    ui->xmrToWidget->setHistoryModel(m_ctx->XMRTo->tableModel);
 | 
			
		||||
#else
 | 
			
		||||
    ui->tabExchanges->setTabVisible(0, false);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(Q_OS_LINUX)
 | 
			
		||||
    // system tray
 | 
			
		||||
    m_trayIcon = new QSystemTrayIcon(QIcon(":/assets/images/appicons/64x64.png"));
 | 
			
		||||
| 
						 | 
				
			
			@ -225,10 +209,6 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
 | 
			
		|||
    connect(m_ctx, &AppContext::initiateTransaction, ui->sendWidget, &SendWidget::onInitiateTransaction);
 | 
			
		||||
    connect(m_ctx, &AppContext::endTransaction, ui->sendWidget, &SendWidget::onEndTransaction);
 | 
			
		||||
 | 
			
		||||
    // XMR.to
 | 
			
		||||
    connect(m_ctx, &AppContext::initiateTransaction, ui->xmrToWidget, &XMRToWidget::onInitiateTransaction);
 | 
			
		||||
    connect(m_ctx, &AppContext::endTransaction, ui->xmrToWidget, &XMRToWidget::onEndTransaction);
 | 
			
		||||
 | 
			
		||||
    connect(m_ctx, &AppContext::initiateTransaction, [this]{
 | 
			
		||||
        m_statusDots = 0;
 | 
			
		||||
        m_constructingTransaction = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -421,13 +401,8 @@ void MainWindow::initMenu() {
 | 
			
		|||
    m_tabShowHideMapper["Calc"] = new ToggleTab(ui->tabCalc, "Calc", "Calc", ui->actionShow_calc, Config::showTabCalc);
 | 
			
		||||
    m_tabShowHideSignalMapper->setMapping(ui->actionShow_calc, "Calc");
 | 
			
		||||
 | 
			
		||||
#if defined(HAS_XMRTO)
 | 
			
		||||
    connect(ui->actionShow_Exchange, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
 | 
			
		||||
    m_tabShowHideMapper["Exchange"] = new ToggleTab(ui->tabExchange, "Exchange", "Exchange", ui->actionShow_Exchange, Config::showTabExchange);
 | 
			
		||||
    m_tabShowHideSignalMapper->setMapping(ui->actionShow_Exchange, "Exchange");
 | 
			
		||||
#else
 | 
			
		||||
    ui->actionShow_Exchange->setVisible(false);
 | 
			
		||||
#endif
 | 
			
		||||
    ui->tabWidget->setTabVisible(Tabs::EXCHANGES, false);
 | 
			
		||||
 | 
			
		||||
#if defined(HAS_XMRIG)
 | 
			
		||||
    connect(ui->actionShow_XMRig, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -293,39 +293,6 @@
 | 
			
		|||
        <property name="bottomMargin">
 | 
			
		||||
         <number>0</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QTabWidget" name="tabExchanges">
 | 
			
		||||
          <property name="currentIndex">
 | 
			
		||||
           <number>0</number>
 | 
			
		||||
          </property>
 | 
			
		||||
          <widget class="QWidget" name="tabXMRto">
 | 
			
		||||
           <attribute name="icon">
 | 
			
		||||
            <iconset resource="assets.qrc">
 | 
			
		||||
             <normaloff>:/assets/images/xmrto.png</normaloff>:/assets/images/xmrto.png</iconset>
 | 
			
		||||
           </attribute>
 | 
			
		||||
           <attribute name="title">
 | 
			
		||||
            <string>XMR.to</string>
 | 
			
		||||
           </attribute>
 | 
			
		||||
           <layout class="QVBoxLayout" name="verticalLayout_10">
 | 
			
		||||
            <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="XMRToWidget" name="xmrToWidget" native="true"/>
 | 
			
		||||
            </item>
 | 
			
		||||
           </layout>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </widget>
 | 
			
		||||
      <widget class="QWidget" name="tabXmrRig">
 | 
			
		||||
| 
						 | 
				
			
			@ -764,12 +731,6 @@
 | 
			
		|||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>historywidget.h</header>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>XMRToWidget</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>xmrtowidget.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>CalcWidget</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,107 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#include "XmrToModel.h"
 | 
			
		||||
#include "model/ModelUtils.h"
 | 
			
		||||
#include "utils/xmrto.h"
 | 
			
		||||
#include "utils/ColorScheme.h"
 | 
			
		||||
 | 
			
		||||
XmrToModel::XmrToModel(QList<XmrToOrder*> *orders, QObject *parent)
 | 
			
		||||
        : QAbstractTableModel(parent),
 | 
			
		||||
          orders(orders)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToModel::update() {
 | 
			
		||||
    beginResetModel();
 | 
			
		||||
    endResetModel();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int XmrToModel::rowCount(const QModelIndex &) const {
 | 
			
		||||
    return this->orders->count();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int XmrToModel::columnCount(const QModelIndex &) const {
 | 
			
		||||
    return COUNT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QVariant XmrToModel::data(const QModelIndex &index, int role) const {
 | 
			
		||||
    const int _row = index.row();
 | 
			
		||||
    const int _col = index.column();
 | 
			
		||||
    const auto order = this->orders->at(_row);
 | 
			
		||||
 | 
			
		||||
    if (role == Qt::DisplayRole){
 | 
			
		||||
        switch(index.column()){
 | 
			
		||||
            case Status:
 | 
			
		||||
            {
 | 
			
		||||
                QString status = XmrTo::stateMap[(OrderState) order->state];
 | 
			
		||||
 | 
			
		||||
                if (order->state == OrderState::Status_OrderUnpaid)
 | 
			
		||||
                    return QString("%1 (%2)").arg(status, QString::number(order->countdown));
 | 
			
		||||
 | 
			
		||||
                return status;
 | 
			
		||||
            }
 | 
			
		||||
            case ID:
 | 
			
		||||
                return !order->uuid.isEmpty() ? order->uuid.split("-")[1] : "-";
 | 
			
		||||
            case Destination:
 | 
			
		||||
                return ModelUtils::displayAddress(order->btc_dest_address, 1);
 | 
			
		||||
            case Conversion:
 | 
			
		||||
                if(order->state <= OrderState::Status_OrderToBeCreated)
 | 
			
		||||
                    return "";
 | 
			
		||||
 | 
			
		||||
                return QString("%1 XMR ⟶ %2 BTC").arg(QString::number(order->incoming_amount_total), QString::number(order->btc_amount));
 | 
			
		||||
            case Rate:
 | 
			
		||||
                return order->incoming_price_btc ? QString::number(order->incoming_price_btc, 'f', 6) : "";
 | 
			
		||||
            case ErrorMsg:
 | 
			
		||||
                if(order->errorMsg.isEmpty()) return "";
 | 
			
		||||
                return order->errorMsg;
 | 
			
		||||
            default: return {};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    else if(role == Qt::BackgroundRole) {
 | 
			
		||||
        if (_col == 0) {
 | 
			
		||||
            if (order->state == OrderState::Status_OrderPaid || order->state == OrderState::Status_OrderPaidUnconfirmed)
 | 
			
		||||
                return QBrush(ColorScheme::GREEN.asColor(true));
 | 
			
		||||
            else if (order->state == OrderState::Status_OrderCreating || order->state == OrderState::Status_OrderToBeCreated)
 | 
			
		||||
                return QBrush(ColorScheme::YELLOW.asColor(true));
 | 
			
		||||
            else if (order->state == OrderState::Status_OrderUnpaid)
 | 
			
		||||
                return QBrush(ColorScheme::YELLOW.asColor(true));
 | 
			
		||||
            else if (order->state == OrderState::Status_OrderBTCSent)
 | 
			
		||||
                return QBrush(ColorScheme::GREEN.asColor(true));
 | 
			
		||||
            else if (order->state == OrderState::Status_OrderFailed || order->state == OrderState::Status_OrderTimedOut)
 | 
			
		||||
                return QBrush(ColorScheme::RED.asColor(true));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (role == Qt::FontRole) {
 | 
			
		||||
        switch(index.column()) {
 | 
			
		||||
            case ID:
 | 
			
		||||
            case Destination:
 | 
			
		||||
                return ModelUtils::getMonospaceFont();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return QVariant();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QVariant XmrToModel::headerData(int section, Qt::Orientation orientation, int role) const {
 | 
			
		||||
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
 | 
			
		||||
        switch (section) {
 | 
			
		||||
            case Status:
 | 
			
		||||
                return QString("Status");
 | 
			
		||||
            case ID:
 | 
			
		||||
                return QString("ID");
 | 
			
		||||
            case Destination:
 | 
			
		||||
                return QString("Address");
 | 
			
		||||
            case Conversion:
 | 
			
		||||
                return QString("Conversion");
 | 
			
		||||
            case Rate:
 | 
			
		||||
                return QString("Rate");
 | 
			
		||||
            case ErrorMsg:
 | 
			
		||||
                return QString("Message");
 | 
			
		||||
            default:
 | 
			
		||||
                return QVariant();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return QVariant();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,38 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#ifndef FEATHER_XMRTOMODEL_H
 | 
			
		||||
#define FEATHER_XMRTOMODEL_H
 | 
			
		||||
 | 
			
		||||
#include <QAbstractTableModel>
 | 
			
		||||
 | 
			
		||||
class XmrToOrder;
 | 
			
		||||
class XmrToModel : public QAbstractTableModel
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    enum ModelColumn
 | 
			
		||||
    {
 | 
			
		||||
        Status = 0,
 | 
			
		||||
        ID,
 | 
			
		||||
        Conversion,
 | 
			
		||||
        Rate,
 | 
			
		||||
        Destination,
 | 
			
		||||
        ErrorMsg,
 | 
			
		||||
        COUNT
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    XmrToModel(QList<XmrToOrder*> *orders, QObject *parent = nullptr);
 | 
			
		||||
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
 | 
			
		||||
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
 | 
			
		||||
    QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
 | 
			
		||||
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
 | 
			
		||||
    QList<XmrToOrder*> *orders;
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    void update();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //FEATHER_XMRTOMODEL_H
 | 
			
		||||
| 
						 | 
				
			
			@ -1,110 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#include "xmrto.h"
 | 
			
		||||
 | 
			
		||||
#include "appcontext.h"
 | 
			
		||||
 | 
			
		||||
QMap<OrderState, QString> XmrTo::stateMap;
 | 
			
		||||
 | 
			
		||||
XmrTo::XmrTo(AppContext *ctx, QObject *parent) :
 | 
			
		||||
        QObject(parent),
 | 
			
		||||
        m_ctx(ctx) {
 | 
			
		||||
 | 
			
		||||
    m_baseUrl = m_ctx->networkType == NetworkType::Type::MAINNET ? "https://xmr.to" : "https://test.xmr.to";
 | 
			
		||||
 | 
			
		||||
    m_netTor = new UtilsNetworking(this->m_ctx->network);
 | 
			
		||||
    m_netClear = new UtilsNetworking(this->m_ctx->networkClearnet);
 | 
			
		||||
 | 
			
		||||
    m_apiTor = new XmrToApi(this, m_netTor, m_baseUrl);
 | 
			
		||||
    m_apiClear = new XmrToApi(this, m_netClear, m_baseUrl);
 | 
			
		||||
 | 
			
		||||
    connect(m_apiTor, &XmrToApi::ApiResponse, this, &XmrTo::onApiResponse);
 | 
			
		||||
    connect(m_apiClear, &XmrToApi::ApiResponse, this, &XmrTo::onApiResponse);
 | 
			
		||||
 | 
			
		||||
    connect(this, &XmrTo::orderPaymentRequired, this->m_ctx, QOverload<XmrToOrder*>::of(&AppContext::onCreateTransaction));
 | 
			
		||||
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_Idle] = "IDLE";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderCreating] = "CREATING";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderUnpaid] = "UNPAID";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderToBeCreated] = "TO_BE_CREATED";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderUnderPaid] = "UNDERPAID";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderPaidUnconfirmed] = "PAID_UNCONFIRMED";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderPaid] = "PAID";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderBTCSent] = "BTC_SENT";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderTimedOut] = "TIMED_OUT";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderFailed] = "FAILED";
 | 
			
		||||
    XmrTo::stateMap[OrderState::Status_OrderXMRSent] = "XMR_SENT";
 | 
			
		||||
 | 
			
		||||
    this->tableModel = new XmrToModel(&this->orders, this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::createOrder(double amount, const QString ¤cy, const QString &btcAddress) {
 | 
			
		||||
    // ^[13][a-km-zA-HJ-NP-Z0-9]{26,33}$
 | 
			
		||||
 | 
			
		||||
    XmrToOrder *order;
 | 
			
		||||
    order = new XmrToOrder(this->m_ctx, m_netTor, m_baseUrl, false, &this->rates, this);
 | 
			
		||||
 | 
			
		||||
    connect(order, &XmrToOrder::orderFailed, this, &XmrTo::orderFailed);
 | 
			
		||||
    connect(order, &XmrToOrder::orderPaid, this, &XmrTo::orderPaid);
 | 
			
		||||
    connect(order, &XmrToOrder::orderPaidUnconfirmed, this, &XmrTo::orderPaidUnconfirmed);
 | 
			
		||||
    connect(order, &XmrToOrder::orderPaymentRequired, this, &XmrTo::orderPaymentRequired);
 | 
			
		||||
    connect(order, &XmrToOrder::orderChanged, this->tableModel, &XmrToModel::update);
 | 
			
		||||
 | 
			
		||||
    order->create(amount, currency, btcAddress);
 | 
			
		||||
    this->orders.append(order);
 | 
			
		||||
    tableModel->update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void XmrTo::onApiResponse(const XmrToResponse &resp) {
 | 
			
		||||
    if (!resp.ok) {
 | 
			
		||||
        this->onApiFailure(resp);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emit connectionSuccess();
 | 
			
		||||
    if (resp.endpoint == Endpoint::RATES) {
 | 
			
		||||
        onRatesReceived(resp.obj);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::onApiFailure(const XmrToResponse &resp) {
 | 
			
		||||
    emit connectionError(resp.message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::onGetRates() {
 | 
			
		||||
    m_apiTor->getRates();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::onRatesReceived(const QJsonObject &doc) {
 | 
			
		||||
    this->rates.price = doc.value("price").toString().toDouble();
 | 
			
		||||
    this->rates.ln_lower_limit = doc.value("ln_lower_limit").toString().toDouble();
 | 
			
		||||
    this->rates.ln_upper_limit = doc.value("ln_upper_limit").toString().toDouble();
 | 
			
		||||
    this->rates.lower_limit = doc.value("lower_limit").toString().toDouble();
 | 
			
		||||
    this->rates.upper_limit = doc.value("upper_limit").toString().toDouble();
 | 
			
		||||
    this->rates.zero_conf_enabled = doc.value("zero_conf_enabled").toBool();
 | 
			
		||||
    this->rates.zero_conf_max_amount = doc.value("zero_conf_enabled").toString().toDouble();
 | 
			
		||||
    emit ratesUpdated(rates);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::onNetworkChanged(bool clearnet) {
 | 
			
		||||
    m_api = clearnet ? m_apiClear : m_apiTor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::onWalletClosed() {
 | 
			
		||||
    // @TODO: cleanup
 | 
			
		||||
    for(const auto &order: this->orders)
 | 
			
		||||
        order->deleteLater();
 | 
			
		||||
 | 
			
		||||
    this->tableModel->update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::onWalletOpened() {
 | 
			
		||||
    // @TODO: read past XMR.To orders, start pending ones
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrTo::onViewOrder(const QString &orderId) {
 | 
			
		||||
    QString url = QString("%1/nojs/status/%2").arg(this->m_baseUrl).arg(orderId);
 | 
			
		||||
    emit openURL(url);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,63 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#ifndef FEATHER_XMRTOCONVERT_H
 | 
			
		||||
#define FEATHER_XMRTOCONVERT_H
 | 
			
		||||
 | 
			
		||||
#include <QObject>
 | 
			
		||||
 | 
			
		||||
#include "model/XmrToModel.h"
 | 
			
		||||
#include "utils/xmrtoorder.h"
 | 
			
		||||
#include "utils/xmrtoapi.h"
 | 
			
		||||
 | 
			
		||||
class AppContext;
 | 
			
		||||
class XmrTo: public QObject {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit XmrTo(AppContext *ctx, QObject *parent = nullptr);
 | 
			
		||||
    Q_ENUM(OrderState);
 | 
			
		||||
 | 
			
		||||
    XmrToModel *tableModel;
 | 
			
		||||
    static QMap<OrderState, QString> stateMap;
 | 
			
		||||
    XmrToRates rates;
 | 
			
		||||
    QList<XmrToOrder*> orders;
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    void createOrder(double amount, const QString ¤cy, const QString &btcAddress);
 | 
			
		||||
    void onGetRates();
 | 
			
		||||
    void onRatesReceived(const QJsonObject &doc);
 | 
			
		||||
    void onViewOrder(const QString &orderId);
 | 
			
		||||
    void onNetworkChanged(bool clearnet);
 | 
			
		||||
    void onWalletOpened();
 | 
			
		||||
    void onWalletClosed();
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void onApiResponse(const XmrToResponse &doc);
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void orderPaymentRequired(XmrToOrder *order);
 | 
			
		||||
    void orderPaidUnconfirmed(XmrToOrder *order);
 | 
			
		||||
    void orderPaid(XmrToOrder *order);
 | 
			
		||||
    void orderFailed(XmrToOrder *order);
 | 
			
		||||
    void ratesUpdated(XmrToRates rates);
 | 
			
		||||
    void openURL(const QString &url);
 | 
			
		||||
    void connectionError(const QString &err);
 | 
			
		||||
    void connectionSuccess();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void onApiFailure(const XmrToResponse &doc);
 | 
			
		||||
 | 
			
		||||
    QString m_baseUrl;
 | 
			
		||||
    AppContext *m_ctx;
 | 
			
		||||
    int m_orderTimeout = 900;  // https://xmrto-api.readthedocs.io/en/latest/introduction.html#various-parameters
 | 
			
		||||
 | 
			
		||||
    UtilsNetworking *m_netTor;
 | 
			
		||||
    UtilsNetworking *m_netClear;
 | 
			
		||||
 | 
			
		||||
    XmrToApi *m_api;
 | 
			
		||||
    XmrToApi *m_apiTor;
 | 
			
		||||
    XmrToApi *m_apiClear;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif //FEATHER_XMRTOCONVERT_H
 | 
			
		||||
| 
						 | 
				
			
			@ -1,76 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#include "xmrtoapi.h"
 | 
			
		||||
 | 
			
		||||
XmrToApi::XmrToApi(QObject *parent, UtilsNetworking *network, QString baseUrl)
 | 
			
		||||
    : QObject(parent)
 | 
			
		||||
    , m_network(network)
 | 
			
		||||
    , m_baseUrl(std::move(baseUrl))
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToApi::getRates() {
 | 
			
		||||
    QString url = QString("%1/api/v3/xmr2btc/order_parameter_query/").arg(this->m_baseUrl);
 | 
			
		||||
    QNetworkReply *reply = m_network->getJson(url);
 | 
			
		||||
    connect(reply, &QNetworkReply::finished, std::bind(&XmrToApi::onResponse, this, reply, Endpoint::RATES));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToApi::createOrder(double amount, const QString &amount_currency, const QString &dest_address) {
 | 
			
		||||
    QJsonObject order;
 | 
			
		||||
    order["amount"] = amount;
 | 
			
		||||
    order["amount_currency"] = amount_currency;
 | 
			
		||||
    order["btc_dest_address"] = dest_address;
 | 
			
		||||
 | 
			
		||||
    QString url = QString("%1/api/v3/xmr2btc/order_create/").arg(m_baseUrl);
 | 
			
		||||
    QNetworkReply *reply = m_network->postJson(url, order);
 | 
			
		||||
    connect(reply, &QNetworkReply::finished, std::bind(&XmrToApi::onResponse, this, reply, Endpoint::ORDER_CREATE));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToApi::getOrderStatus(const QString &uuid) {
 | 
			
		||||
    QJsonObject order;
 | 
			
		||||
    order["uuid"] = uuid;
 | 
			
		||||
 | 
			
		||||
    QString url = QString("%1/api/v3/xmr2btc/order_status_query/").arg(m_baseUrl);
 | 
			
		||||
    QNetworkReply *reply = m_network->postJson(url, order);
 | 
			
		||||
    connect(reply, &QNetworkReply::finished, std::bind(&XmrToApi::onResponse, this, reply, Endpoint::ORDER_STATUS));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToApi::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(XmrToResponse(false, endpoint, err));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        emit ApiResponse(XmrToResponse(false, endpoint, "Invalid response from XMR.to"));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    XmrToError xmrto_err = XmrToApi::getApiError(obj);
 | 
			
		||||
    if (!xmrto_err.code.isEmpty()) {
 | 
			
		||||
        emit ApiResponse(XmrToResponse(false, endpoint, m_errorMap.contains(xmrto_err.code) ? m_errorMap[xmrto_err.code] : "", xmrto_err));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    reply->deleteLater();
 | 
			
		||||
    emit ApiResponse(XmrToResponse(true, endpoint, "", obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
XmrToError XmrToApi::getApiError(const QJsonObject &obj) {
 | 
			
		||||
    if (!obj.contains("error"))
 | 
			
		||||
        return XmrToError();
 | 
			
		||||
 | 
			
		||||
    QString code = obj.value("error").toString();
 | 
			
		||||
    QString msg = obj.value("error_msg").toString();
 | 
			
		||||
 | 
			
		||||
    return XmrToError(code, msg);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,87 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#ifndef FEATHER_XMRTOAPI_H
 | 
			
		||||
#define FEATHER_XMRTOAPI_H
 | 
			
		||||
 | 
			
		||||
#include <QObject>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "utils/networking.h"
 | 
			
		||||
 | 
			
		||||
enum Endpoint {
 | 
			
		||||
    RATES = 0,
 | 
			
		||||
    ORDER_CREATE,
 | 
			
		||||
    ORDER_STATUS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct XmrToError {
 | 
			
		||||
    explicit XmrToError(QString code = "", QString msg = "")
 | 
			
		||||
        : code(std::move(code)), msg(std::move(msg)) {};
 | 
			
		||||
 | 
			
		||||
    QString code;
 | 
			
		||||
    QString msg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct XmrToResponse {
 | 
			
		||||
    explicit XmrToResponse(bool ok, Endpoint endpoint, QString message, XmrToError error = XmrToError(), QJsonObject obj = {})
 | 
			
		||||
        : ok(ok), endpoint(endpoint), message(std::move(message)), error(std::move(error)), obj(std::move(obj)) {};
 | 
			
		||||
 | 
			
		||||
    explicit XmrToResponse(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;
 | 
			
		||||
    XmrToError error = XmrToError();
 | 
			
		||||
    QJsonObject obj;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class XmrToApi : public QObject {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit XmrToApi(QObject *parent, UtilsNetworking *network, QString baseUrl = "https://xmr.to");
 | 
			
		||||
 | 
			
		||||
    void getRates();
 | 
			
		||||
    void createOrder(double amount, const QString &amount_currency, const QString &dest_address);
 | 
			
		||||
    void getOrderStatus(const QString &uuid);
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void ApiResponse(XmrToResponse resp);
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void onResponse(QNetworkReply *reply, Endpoint endpoint);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static XmrToError getApiError(const QJsonObject &obj);
 | 
			
		||||
 | 
			
		||||
    QString m_baseUrl;
 | 
			
		||||
    UtilsNetworking *m_network;
 | 
			
		||||
 | 
			
		||||
    // https://xmrto-api.readthedocs.io/en/latest/introduction.html#list-of-all-error-codes
 | 
			
		||||
    const QMap<QString, QString> m_errorMap = {
 | 
			
		||||
            {"XMRTO-ERROR-001", "internal services not available, try again later."},
 | 
			
		||||
            {"XMRTO-ERROR-002", "malformed bitcoin address, check address validity."},
 | 
			
		||||
            {"XMRTO-ERROR-003", "invalid bitcoin amount, check amount data type."},
 | 
			
		||||
            {"XMRTO-ERROR-004", "bitcoin amount out of bounds, check min and max amount."},
 | 
			
		||||
            {"XMRTO-ERROR-005", "unexpected validation error, contact support."},
 | 
			
		||||
            {"XMRTO-ERROR-006", "requested order not found, check order UUID."},
 | 
			
		||||
            {"XMRTO-ERROR-007", "third party service not available, try again later."},
 | 
			
		||||
            {"XMRTO-ERROR-008", "insufficient funds available, try again later."},
 | 
			
		||||
            {"XMRTO-ERROR-009", "invalid request, check request parameters."},
 | 
			
		||||
            {"XMRTO-ERROR-010", "payment protocol failed, invalid or outdated data served by URL."},
 | 
			
		||||
            {"XMRTO-ERROR-011", "malformed payment protocol url, URL is malformed or cannot be contacted."},
 | 
			
		||||
            {"XMRTO-ERROR-012", "too many requests, try less often."},
 | 
			
		||||
            {"XMRTO-ERROR-013", "access forbidden."},
 | 
			
		||||
            {"XMRTO-ERROR-014", "service is not available in your region."},
 | 
			
		||||
            {"XMRTO-ERROR-015", "invalid monero amount, check amount data type."},
 | 
			
		||||
            {"XMRTO-ERROR-016", "invalid currency, check available currency options."},
 | 
			
		||||
            {"XMRTO-ERROR-017", "malformed lightning network invoice, provide a correct invoice for the main network."},
 | 
			
		||||
            {"XMRTO-ERROR-018", "lightning payment unlikely to succeed, check first if xmr.to has routes available."},
 | 
			
		||||
            {"XMRTO-ERROR-019", "lightning invoice preimage already known, don’t use the same invoice more than once."}
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //FEATHER_XMRTOAPI_H
 | 
			
		||||
| 
						 | 
				
			
			@ -1,274 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#include "xmrtoorder.h"
 | 
			
		||||
 | 
			
		||||
#include "libwalletqt/Wallet.h"
 | 
			
		||||
#include "appcontext.h"
 | 
			
		||||
#include "globals.h"
 | 
			
		||||
 | 
			
		||||
XmrToOrder::XmrToOrder(AppContext *ctx, UtilsNetworking *network, QString baseUrl, bool clearnet, XmrToRates *rates, QObject *parent) :
 | 
			
		||||
        QObject(parent),
 | 
			
		||||
        m_ctx(ctx),
 | 
			
		||||
        m_network(network),
 | 
			
		||||
        m_baseUrl(std::move(baseUrl)),
 | 
			
		||||
        m_rates(rates),
 | 
			
		||||
        m_clearnet(clearnet) {
 | 
			
		||||
    this->state = OrderState::Status_Idle;
 | 
			
		||||
 | 
			
		||||
    m_baseUrl = m_ctx->networkType == NetworkType::Type::MAINNET ? "https://xmr.to" : "https://test.xmr.to";
 | 
			
		||||
    m_api = new XmrToApi(this, network, m_baseUrl);
 | 
			
		||||
 | 
			
		||||
    connect(m_api, &XmrToApi::ApiResponse, this, &XmrToOrder::onApiResponse);
 | 
			
		||||
    connect(m_ctx, &AppContext::transactionCommitted, this, &XmrToOrder::onTransactionCommitted);
 | 
			
		||||
    connect(m_ctx, &AppContext::createTransactionCancelled, this, &XmrToOrder::onTransactionCancelled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onTransactionCancelled(const QVector<QString> &address, double amount) {
 | 
			
		||||
    // listener for all cancelled transactions - will try to match the exact amount to this order.
 | 
			
		||||
    if(this->incoming_amount_total != amount || this->receiving_subaddress != address[0]) return;
 | 
			
		||||
 | 
			
		||||
    this->errorMsg = "TX cancelled by user";
 | 
			
		||||
    this->changeState(OrderState::Status_OrderFailed);
 | 
			
		||||
    this->stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid) {
 | 
			
		||||
    // listener for all outgoing transactions - will try to match the exact amount to this order.
 | 
			
		||||
    if(this->state == OrderState::Status_OrderUnpaid){
 | 
			
		||||
        if(tx->amount() / globals::cdiv == this->incoming_amount_total) {
 | 
			
		||||
            if(!status) {
 | 
			
		||||
                this->errorMsg = "TX failed to commit";
 | 
			
		||||
                this->changeState(OrderState::Status_OrderFailed);
 | 
			
		||||
                this->stop();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this->xmr_txid = txid.at(0);
 | 
			
		||||
            this->m_paymentSent = true;
 | 
			
		||||
            this->changeState(OrderState::Status_OrderXMRSent);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onApiFailure(const XmrToResponse &resp) {
 | 
			
		||||
    this->errorCode = resp.error.code;
 | 
			
		||||
    this->errorMsg = resp.message;
 | 
			
		||||
 | 
			
		||||
    switch (resp.endpoint) {
 | 
			
		||||
        case ORDER_CREATE:
 | 
			
		||||
            this->onCreatedError();
 | 
			
		||||
            break;
 | 
			
		||||
        case ORDER_STATUS:
 | 
			
		||||
            this->onCheckedError(resp.error);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onApiResponse(const XmrToResponse& resp) {
 | 
			
		||||
    if (!resp.ok) {
 | 
			
		||||
        this->onApiFailure(resp);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (resp.endpoint) {
 | 
			
		||||
        case ORDER_CREATE:
 | 
			
		||||
            this->onCreated(resp.obj);
 | 
			
		||||
            break;
 | 
			
		||||
        case ORDER_STATUS:
 | 
			
		||||
            this->onChecked(resp.obj);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::create(double amount, const QString ¤cy, const QString &btcAddress) {
 | 
			
		||||
    if(this->m_ctx->currentWallet == nullptr) {
 | 
			
		||||
        this->errorMsg = "No wallet opened";
 | 
			
		||||
        this->changeState(OrderState::Status_OrderFailed);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_api->createOrder(amount, currency, btcAddress);
 | 
			
		||||
    this->changeState(OrderState::Status_OrderCreating);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onCreatedError() {
 | 
			
		||||
    this->changeState(OrderState::Status_OrderFailed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onCreated(const QJsonObject &object) {
 | 
			
		||||
    if(!object.contains("state"))
 | 
			
		||||
        this->errorMsg = "Could not parse 'state' from JSON response";
 | 
			
		||||
    if(object.value("state").toString() != "TO_BE_CREATED")
 | 
			
		||||
        this->errorMsg = "unknown state from response, should be \"TO_BE_CREATED\"";
 | 
			
		||||
 | 
			
		||||
    if(!this->errorMsg.isEmpty()) {
 | 
			
		||||
        this->changeState(OrderState::Status_OrderFailed);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(m_created) return;
 | 
			
		||||
    m_created = true;
 | 
			
		||||
    this->btc_amount = object.value("btc_amount").toDouble();
 | 
			
		||||
    this->btc_dest_address = object.value("btc_dest_address").toString();
 | 
			
		||||
    this->uses_lightning = object.value("uses_lightning").toBool();
 | 
			
		||||
    this->uuid = object.value("uuid").toString();
 | 
			
		||||
    m_checkTimer.start(1000*5);
 | 
			
		||||
    m_countdownTimer.start(1000);
 | 
			
		||||
    connect(&m_checkTimer, &QTimer::timeout, this, &XmrToOrder::check);
 | 
			
		||||
    connect(&m_countdownTimer, &QTimer::timeout, this, &XmrToOrder::onCountdown);
 | 
			
		||||
 | 
			
		||||
    this->changeState(OrderState::Status_OrderToBeCreated);
 | 
			
		||||
    this->check();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::check() {
 | 
			
		||||
    if(this->m_ctx->currentWallet == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    m_api->getOrderStatus(this->uuid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onCheckedError(const XmrToError& err) {
 | 
			
		||||
    if (!err.code.isEmpty())
 | 
			
		||||
        this->changeState(OrderState::Status_OrderFailed);
 | 
			
		||||
 | 
			
		||||
    m_checkFailures += 1;
 | 
			
		||||
    if(m_checkFailures > 15){
 | 
			
		||||
        this->errorMsg = "Too many failed attempts";
 | 
			
		||||
        this->changeState(OrderState::Status_OrderFailed);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onChecked(const QJsonObject &object) {
 | 
			
		||||
    if(object.contains("btc_amount"))
 | 
			
		||||
        this->btc_amount = object.value("btc_amount").toString().toDouble();
 | 
			
		||||
    if(object.contains("btc_dest_address"))
 | 
			
		||||
        this->btc_dest_address = object.value("btc_dest_address").toString();
 | 
			
		||||
    if(object.contains("seconds_till_timeout")) {
 | 
			
		||||
        this->seconds_till_timeout = object.value("seconds_till_timeout").toInt();
 | 
			
		||||
        this->countdown = this->seconds_till_timeout;
 | 
			
		||||
    }
 | 
			
		||||
    if(object.contains("created_at"))
 | 
			
		||||
        this->created_at = object.value("created_at").toString();
 | 
			
		||||
    if(object.contains("expires_at"))
 | 
			
		||||
        this->expires_at = object.value("expires_at").toString();
 | 
			
		||||
    if(object.contains("incoming_amount_total"))
 | 
			
		||||
        this->incoming_amount_total = object.value("incoming_amount_total").toString().toDouble();
 | 
			
		||||
    if(object.contains("remaining_amount_incoming"))
 | 
			
		||||
        this->remaining_amount_incoming = object.value("remaining_amount_incoming").toString().toDouble();
 | 
			
		||||
    if(object.contains("incoming_price_btc"))
 | 
			
		||||
    {
 | 
			
		||||
        qDebug() << object.value("incoming_price_btc").toString();
 | 
			
		||||
        this->incoming_price_btc = object.value("incoming_price_btc").toString().toDouble();
 | 
			
		||||
    }
 | 
			
		||||
    if(object.contains("receiving_subaddress"))
 | 
			
		||||
        this->receiving_subaddress = object.value("receiving_subaddress").toString();
 | 
			
		||||
 | 
			
		||||
    if(object.contains("payments")) {
 | 
			
		||||
        // detect btc txid, xmr.to api can output several - we'll just grab the first #yolo
 | 
			
		||||
        auto payments = object.value("payments").toArray();
 | 
			
		||||
        for(const auto &payment: payments){
 | 
			
		||||
            auto obj = payment.toObject();
 | 
			
		||||
            if(obj.contains("tx_id")) {
 | 
			
		||||
                this->btc_txid = obj.value("tx_id").toString();
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->changeState(object.value("state").toString());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::changeState(const QString &_state) {
 | 
			
		||||
    for(const auto &key: XmrTo::stateMap.keys()) {
 | 
			
		||||
        const auto &val = XmrTo::stateMap[key];
 | 
			
		||||
        if(_state == val){
 | 
			
		||||
            this->changeState(key);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::changeState(OrderState _state) {
 | 
			
		||||
    if(this->m_ctx->currentWallet == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if(_state == OrderState::Status_OrderUnderPaid && m_paymentSent) {
 | 
			
		||||
        this->state = OrderState::Status_OrderXMRSent;
 | 
			
		||||
        emit orderChanged();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(_state == this->state) return;
 | 
			
		||||
    switch(_state){
 | 
			
		||||
        case OrderState::Status_Idle:
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderCreating:
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderToBeCreated:
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderUnderPaid:
 | 
			
		||||
            emit orderFailed(this);
 | 
			
		||||
            this->stop();
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderUnpaid:
 | 
			
		||||
            // need to send Monero
 | 
			
		||||
            if(!m_paymentRequested) {
 | 
			
		||||
                auto unlocked_balance = m_ctx->currentWallet->unlockedBalance() / globals::cdiv;
 | 
			
		||||
                if (this->incoming_amount_total >= unlocked_balance) {
 | 
			
		||||
                    this->state = OrderState::Status_OrderFailed;
 | 
			
		||||
                    emit orderFailed(this);
 | 
			
		||||
                    this->stop();
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                m_paymentRequested = true;
 | 
			
		||||
                emit orderPaymentRequired(this);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderFailed:
 | 
			
		||||
            emit orderFailed(this);
 | 
			
		||||
            this->stop();
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderPaidUnconfirmed:
 | 
			
		||||
            emit orderPaidUnconfirmed(this);
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderPaid:
 | 
			
		||||
            emit orderPaid(this);
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderTimedOut:
 | 
			
		||||
            emit orderFailed(this);
 | 
			
		||||
            this->stop();
 | 
			
		||||
            break;
 | 
			
		||||
        case OrderState::Status_OrderBTCSent:
 | 
			
		||||
            emit orderPaid(this);
 | 
			
		||||
            this->stop();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->state = _state;
 | 
			
		||||
    emit orderChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::onCountdown() {
 | 
			
		||||
    if(this->countdown <= 0) return;
 | 
			
		||||
    this->countdown -= 1;
 | 
			
		||||
    emit orderChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XmrToOrder::stop(){
 | 
			
		||||
    this->m_checkTimer.stop();
 | 
			
		||||
    this->m_countdownTimer.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
XmrToOrder::~XmrToOrder(){
 | 
			
		||||
    this->stop();
 | 
			
		||||
    this->disconnect();
 | 
			
		||||
    this->m_network->deleteLater();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,106 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#ifndef FEATHER_XMRTOORDER_H
 | 
			
		||||
#define FEATHER_XMRTOORDER_H
 | 
			
		||||
 | 
			
		||||
#include <QObject>
 | 
			
		||||
 | 
			
		||||
#include "utils/networking.h"
 | 
			
		||||
#include "PendingTransaction.h"
 | 
			
		||||
#include "utils/xmrtoapi.h"
 | 
			
		||||
 | 
			
		||||
enum OrderState {
 | 
			
		||||
    Status_Idle,
 | 
			
		||||
    Status_OrderCreating,
 | 
			
		||||
    Status_OrderToBeCreated,
 | 
			
		||||
    Status_OrderUnpaid,
 | 
			
		||||
    Status_OrderXMRSent,
 | 
			
		||||
    Status_OrderUnderPaid,
 | 
			
		||||
    Status_OrderPaidUnconfirmed,
 | 
			
		||||
    Status_OrderPaid,
 | 
			
		||||
    Status_OrderBTCSent,
 | 
			
		||||
    Status_OrderTimedOut,
 | 
			
		||||
    Status_OrderFailed
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct XmrToRates {
 | 
			
		||||
    double price;
 | 
			
		||||
    double upper_limit;
 | 
			
		||||
    double lower_limit;
 | 
			
		||||
    double ln_upper_limit;
 | 
			
		||||
    double ln_lower_limit;
 | 
			
		||||
    double zero_conf_max_amount;
 | 
			
		||||
    bool zero_conf_enabled;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class XmrToOrder : public QObject {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit XmrToOrder(AppContext *ctx, UtilsNetworking *network, QString baseUrl, bool clearnet, XmrToRates *rates, QObject *parent = nullptr);
 | 
			
		||||
    void create(double btcAmount, const QString ¤cy, const QString &btcAddress);
 | 
			
		||||
    void changeState(OrderState state);
 | 
			
		||||
    void changeState(const QString &state);
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    int state;
 | 
			
		||||
    int countdown = -1; // seconds remaining calculated from `seconds_till_timeout`
 | 
			
		||||
    QString uuid;
 | 
			
		||||
    QString errorMsg;
 | 
			
		||||
    QString errorCode;
 | 
			
		||||
 | 
			
		||||
    double btc_amount = 0;
 | 
			
		||||
    QString btc_dest_address;
 | 
			
		||||
    QString btc_txid;
 | 
			
		||||
    QString xmr_txid;
 | 
			
		||||
    bool uses_lightning = false;
 | 
			
		||||
 | 
			
		||||
    QString receiving_subaddress;
 | 
			
		||||
    QString created_at;
 | 
			
		||||
    QString expires_at;
 | 
			
		||||
    int seconds_till_timeout = -1;
 | 
			
		||||
    double incoming_amount_total = 0;       // amount_in_incoming_currency_for_this_order_as_string
 | 
			
		||||
    double remaining_amount_incoming;   // amount_in_incoming_currency_that_the_user_must_still_send_as_string
 | 
			
		||||
    double incoming_price_btc = 0;          // price_of_1_incoming_in_btc_currency_as_offered_by_service
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    void onCountdown();
 | 
			
		||||
    void onTransactionCancelled(const QVector<QString> &address, double amount);
 | 
			
		||||
    void onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid);
 | 
			
		||||
 | 
			
		||||
    void onCreatedError();
 | 
			
		||||
    void onChecked(const QJsonObject &object);
 | 
			
		||||
    void onCheckedError(const XmrToError& err);
 | 
			
		||||
    void check();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool m_created = false;
 | 
			
		||||
    QString m_baseUrl;
 | 
			
		||||
    QTimer m_checkTimer;
 | 
			
		||||
    QTimer m_countdownTimer;
 | 
			
		||||
    int m_checkFailures = 0;
 | 
			
		||||
    bool m_clearnet;
 | 
			
		||||
    bool m_paymentSent = false;
 | 
			
		||||
    bool m_paymentRequested = false;
 | 
			
		||||
    UtilsNetworking *m_network;
 | 
			
		||||
    AppContext *m_ctx;
 | 
			
		||||
    XmrToRates *m_rates;
 | 
			
		||||
    XmrToApi *m_api;
 | 
			
		||||
 | 
			
		||||
    ~XmrToOrder();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void orderChanged();
 | 
			
		||||
    void orderPaymentRequired(XmrToOrder *order);
 | 
			
		||||
    void orderPaid(XmrToOrder *order);
 | 
			
		||||
    void orderPaidUnconfirmed(XmrToOrder *order);
 | 
			
		||||
    void orderFailed(XmrToOrder *order);
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void onCreated(const QJsonObject &object);
 | 
			
		||||
    void onApiFailure(const XmrToResponse &resp);
 | 
			
		||||
    void onApiResponse(const XmrToResponse &resp);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif //FEATHER_XMRTOORDER_H
 | 
			
		||||
| 
						 | 
				
			
			@ -1,193 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#include "xmrtowidget.h"
 | 
			
		||||
#include "ui_xmrtowidget.h"
 | 
			
		||||
#include "dialog/xmrtoinfodialog.h"
 | 
			
		||||
#include "mainwindow.h"
 | 
			
		||||
#include "globals.h"
 | 
			
		||||
 | 
			
		||||
#include <QMessageBox>
 | 
			
		||||
 | 
			
		||||
XMRToWidget::XMRToWidget(QWidget *parent) :
 | 
			
		||||
        QWidget(parent),
 | 
			
		||||
        ui(new Ui::XMRToWidget)
 | 
			
		||||
{
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
    m_ctx = MainWindow::getContext();
 | 
			
		||||
 | 
			
		||||
    QString amount_rx = R"(^\d*\.\d*$)";
 | 
			
		||||
    QRegExp rx;
 | 
			
		||||
    rx.setPattern(amount_rx);
 | 
			
		||||
    QValidator *validator =  new QRegExpValidator(rx, this);
 | 
			
		||||
    ui->lineAmount->setValidator(validator);
 | 
			
		||||
 | 
			
		||||
    // xmrto logo (c) binaryFate et. al. :-D
 | 
			
		||||
    QPixmap p(":assets/images/xmrto_big.png");
 | 
			
		||||
    ui->logo->setPixmap(p.scaled(112, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation));
 | 
			
		||||
 | 
			
		||||
    ui->ratesLayout->hide();
 | 
			
		||||
 | 
			
		||||
    // context menu
 | 
			
		||||
    m_contextMenu = new QMenu();
 | 
			
		||||
    m_showDetailsAction = m_contextMenu->addAction("Details");
 | 
			
		||||
    m_viewOnXmrToAction = m_contextMenu->addAction("View order on XMR.to");
 | 
			
		||||
    m_viewOnXmrToAction->setIcon(QIcon(":/assets/images/xmrto.png"));
 | 
			
		||||
    connect(m_showDetailsAction, &QAction::triggered, this, &XMRToWidget::showInfoDialog);
 | 
			
		||||
    connect(m_viewOnXmrToAction, &QAction::triggered, [&](){
 | 
			
		||||
        QModelIndex index = ui->historyTable->currentIndex();
 | 
			
		||||
        XmrToOrder *order = this->tableModel->orders->at(index.row());
 | 
			
		||||
        emit viewOrder(order->uuid);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // connects
 | 
			
		||||
    connect(ui->btnGetRates, &QPushButton::pressed, this, &XMRToWidget::onGetRates);
 | 
			
		||||
    connect(ui->lineAmount, &QLineEdit::textChanged, this, &XMRToWidget::updateConversionLabel);
 | 
			
		||||
    connect(ui->comboBox_currency, &QComboBox::currentTextChanged, this, &XMRToWidget::updateConversionLabel);
 | 
			
		||||
    connect(ui->torCheckBox, &QCheckBox::stateChanged, this, &XMRToWidget::onTorCheckBoxToggled);
 | 
			
		||||
    connect(ui->btnCreate, &QPushButton::clicked, this, &XMRToWidget::onCreateOrder);
 | 
			
		||||
 | 
			
		||||
    ui->historyTable->header()->setStretchLastSection(true);
 | 
			
		||||
    ui->historyTable->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
 | 
			
		||||
    ui->historyTable->setSelectionBehavior(QAbstractItemView::SelectRows);
 | 
			
		||||
    ui->historyTable->setContextMenuPolicy(Qt::CustomContextMenu);
 | 
			
		||||
    connect(ui->historyTable, &QTreeView::customContextMenuRequested, [&](const QPoint & point){
 | 
			
		||||
        QModelIndex index = ui->historyTable->indexAt(point);
 | 
			
		||||
        if (index.isValid()) {
 | 
			
		||||
            m_contextMenu->popup(ui->historyTable->viewport()->mapToGlobal(point));
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (m_ctx->isTails || m_ctx->isWhonix) {
 | 
			
		||||
        ui->torCheckBox->setDisabled(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connect(ui->historyTable, &QTreeView::doubleClicked, this, &XMRToWidget::showInfoDialog);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::setHistoryModel(XmrToModel *model) {
 | 
			
		||||
    this->tableModel = model;
 | 
			
		||||
    this->ui->historyTable->setModel(model);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onBalanceUpdated(quint64 balance, quint64 spendable) {
 | 
			
		||||
    this->m_unlockedBalance = spendable / globals::cdiv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onWalletClosed() {
 | 
			
		||||
    ui->lineAddress->clear();
 | 
			
		||||
    ui->lineAmount->clear();
 | 
			
		||||
    ui->xmrLabelEstimate->setText("0.00 XMR");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onCreateOrder() {
 | 
			
		||||
    // @TODO: regex verify
 | 
			
		||||
 | 
			
		||||
    auto amount = ui->lineAmount->text();
 | 
			
		||||
    if(amount.isEmpty()) {
 | 
			
		||||
        QMessageBox::warning(this, "Cannot create XMR.To order", "Invalid amount");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    double amount_num = amount.toDouble();
 | 
			
		||||
    QString amount_cur = (ui->comboBox_currency->currentIndex() == curr::BTC) ? "BTC" : "XMR";
 | 
			
		||||
    double amount_xmr = amount_num;
 | 
			
		||||
    if (ui->comboBox_currency->currentIndex() == curr::BTC) {
 | 
			
		||||
        amount_xmr = AppContext::prices->convert("BTC", "XMR", amount_num);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto available = m_unlockedBalance;
 | 
			
		||||
    if(amount_xmr > available){
 | 
			
		||||
        QMessageBox::warning(this, "Cannot create XMR.To order", "Not enough Monero to create order.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ui->btnGetRates->setEnabled(false);
 | 
			
		||||
    ui->btnCreate->setEnabled(false);
 | 
			
		||||
 | 
			
		||||
    auto btc_address = ui->lineAddress->text();
 | 
			
		||||
    emit createOrder(amount_num, amount_cur, btc_address);
 | 
			
		||||
 | 
			
		||||
    QTimer::singleShot(2000, [=] {
 | 
			
		||||
        ui->lineAmount->clear();
 | 
			
		||||
        ui->lineAddress->clear();
 | 
			
		||||
        ui->btnGetRates->setEnabled(true);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onTorCheckBoxToggled(int state) {
 | 
			
		||||
    ui->btnGetRates->setEnabled(true);
 | 
			
		||||
    ui->btnCreate->setEnabled(false);
 | 
			
		||||
    emit networkChanged(!state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::updateConversionLabel() {
 | 
			
		||||
    QString amount = ui->lineAmount->text();
 | 
			
		||||
 | 
			
		||||
    int curIndex = ui->comboBox_currency->currentIndex();
 | 
			
		||||
    QString symbolFrom = (curIndex == curr::XMR) ? "XMR" : "BTC";
 | 
			
		||||
    QString symbolTo = (curIndex == curr::XMR) ? "BTC" : "XMR";
 | 
			
		||||
 | 
			
		||||
    if(amount.isEmpty()) {
 | 
			
		||||
        ui->xmrLabelEstimate->setText(QString("0.00 %1").arg(symbolTo));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    auto amount_num = amount.toDouble();
 | 
			
		||||
    auto amount_converted = AppContext::prices->convert(symbolFrom, symbolTo, amount_num);
 | 
			
		||||
    auto amount_converted_str = QString::number(amount_converted, 'f', 2);
 | 
			
		||||
 | 
			
		||||
    auto fiat_cur = config()->get(Config::preferredFiatCurrency).toString();
 | 
			
		||||
    auto amount_fiat = AppContext::prices->convert(symbolFrom, fiat_cur, amount_num);
 | 
			
		||||
    auto amount_fiat_str = QString::number(amount_fiat, 'f', 2);
 | 
			
		||||
 | 
			
		||||
    ui->xmrLabelEstimate->setText(QString("%1 %2, %3 %4").arg(amount_converted_str, symbolTo, amount_fiat_str, fiat_cur));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onGetRates() {
 | 
			
		||||
    ui->btnGetRates->setEnabled(false);
 | 
			
		||||
    ui->btnCreate->setEnabled(false);
 | 
			
		||||
    emit getRates();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onConnectionError(QString msg) {
 | 
			
		||||
    ui->btnGetRates->setEnabled(true);
 | 
			
		||||
    ui->btnCreate->setEnabled(false);
 | 
			
		||||
    msg = QString("%1\n\n%2").arg(msg).arg(m_regionBlockMessage);
 | 
			
		||||
    QMessageBox::warning(this, "XMR.To Connection Error", msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onConnectionSuccess() {
 | 
			
		||||
    ui->btnGetRates->setEnabled(true);
 | 
			
		||||
    ui->btnCreate->setEnabled(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onRatesUpdated(XmrToRates rates) {
 | 
			
		||||
    ui->label_rate->setText(QString("%1 BTC").arg(QString::number(rates.price)));
 | 
			
		||||
    ui->label_minimum->setText(QString("%1 BTC").arg(QString::number(rates.lower_limit)));
 | 
			
		||||
    ui->label_maximum->setText(QString("%1 BTC").arg(QString::number(rates.upper_limit)));
 | 
			
		||||
 | 
			
		||||
    if(!m_ratesDisplayed) {
 | 
			
		||||
        ui->ratesLayout->setVisible(true);
 | 
			
		||||
        m_ratesDisplayed = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onInitiateTransaction() {
 | 
			
		||||
    ui->btnCreate->setEnabled(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::onEndTransaction() {
 | 
			
		||||
    ui->btnCreate->setEnabled(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XMRToWidget::showInfoDialog() {
 | 
			
		||||
    QModelIndex index = ui->historyTable->currentIndex();
 | 
			
		||||
    XmrToOrder *order = this->tableModel->orders->at(index.row());
 | 
			
		||||
    auto *dialog = new XmrToInfoDialog(order, this);
 | 
			
		||||
    dialog->exec();
 | 
			
		||||
    dialog->deleteLater();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
XMRToWidget::~XMRToWidget() {
 | 
			
		||||
    delete ui;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,67 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
// Copyright (c) 2020-2021, The Monero Project.
 | 
			
		||||
 | 
			
		||||
#ifndef XMRTOWIDGET_H
 | 
			
		||||
#define XMRTOWIDGET_H
 | 
			
		||||
 | 
			
		||||
#include <QWidget>
 | 
			
		||||
#include "widgets/tickerwidget.h"
 | 
			
		||||
#include "utils/xmrto.h"
 | 
			
		||||
#include "appcontext.h"
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
    class XMRToWidget;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class XMRToWidget : public QWidget
 | 
			
		||||
{
 | 
			
		||||
Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit XMRToWidget(QWidget *parent = nullptr);
 | 
			
		||||
    void setHistoryModel(XmrToModel *model);
 | 
			
		||||
    ~XMRToWidget() override;
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    void onWalletClosed();
 | 
			
		||||
    void onGetRates();
 | 
			
		||||
    void onConnectionError(QString msg);
 | 
			
		||||
    void onConnectionSuccess();
 | 
			
		||||
    void onRatesUpdated(XmrToRates rates);
 | 
			
		||||
    void onTorCheckBoxToggled(int state);
 | 
			
		||||
    void onCreateOrder();
 | 
			
		||||
    void onBalanceUpdated(quint64 balance, quint64 spendable);
 | 
			
		||||
    void updateConversionLabel();
 | 
			
		||||
 | 
			
		||||
    void onInitiateTransaction();
 | 
			
		||||
    void onEndTransaction();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void getRates();
 | 
			
		||||
    void networkChanged(bool clearnet);
 | 
			
		||||
    void createOrder(double btnAmount, QString currency, QString btnAddress);
 | 
			
		||||
    void viewOrder(const QString &orderId);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void showInfoDialog();
 | 
			
		||||
 | 
			
		||||
    QMap<QString, TickerWidget*> m_tickerWidgets;
 | 
			
		||||
    QMenu *m_contextMenu;
 | 
			
		||||
    QAction *m_viewOnXmrToAction;
 | 
			
		||||
    QAction *m_showDetailsAction;
 | 
			
		||||
 | 
			
		||||
    Ui::XMRToWidget *ui;
 | 
			
		||||
    AppContext *m_ctx;
 | 
			
		||||
    bool m_ratesDisplayed = false;
 | 
			
		||||
    const QString m_regionBlockMessage = "Beware that XMR.To region blocks certain IPs, which can be problematic in combination with Tor. "
 | 
			
		||||
                                         "Wait a few minutes for the circuit to switch, or disable the option to relay over Tor if the problem persists.";
 | 
			
		||||
    double m_unlockedBalance = 0;
 | 
			
		||||
    XmrToModel *tableModel;
 | 
			
		||||
 | 
			
		||||
    enum curr {
 | 
			
		||||
        BTC = 0,
 | 
			
		||||
        XMR
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,327 +0,0 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<ui version="4.0">
 | 
			
		||||
 <class>XMRToWidget</class>
 | 
			
		||||
 <widget class="QWidget" name="XMRToWidget">
 | 
			
		||||
  <property name="geometry">
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>896</width>
 | 
			
		||||
    <height>472</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="windowTitle">
 | 
			
		||||
   <string>Form</string>
 | 
			
		||||
  </property>
 | 
			
		||||
  <layout class="QVBoxLayout" name="verticalLayout">
 | 
			
		||||
   <item>
 | 
			
		||||
    <layout class="QGridLayout" name="gridLayout_2">
 | 
			
		||||
     <item row="3" column="1">
 | 
			
		||||
      <layout class="QHBoxLayout" name="horizontalLayout_6">
 | 
			
		||||
       <item>
 | 
			
		||||
        <widget class="QCheckBox" name="torCheckBox">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>Relay over Tor</string>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="checked">
 | 
			
		||||
          <bool>true</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item>
 | 
			
		||||
        <spacer name="horizontalSpacer_4">
 | 
			
		||||
         <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="btnGetRates">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>Get Rates</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item>
 | 
			
		||||
        <widget class="QPushButton" name="btnCreate">
 | 
			
		||||
         <property name="enabled">
 | 
			
		||||
          <bool>false</bool>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>Create Order</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
      </layout>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item row="2" column="0">
 | 
			
		||||
      <widget class="QLabel" name="label_2">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Amount</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item row="2" column="1">
 | 
			
		||||
      <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
			
		||||
       <item>
 | 
			
		||||
        <layout class="QHBoxLayout" name="horizontalLayout_8">
 | 
			
		||||
         <property name="spacing">
 | 
			
		||||
          <number>0</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <item>
 | 
			
		||||
          <widget class="QLineEdit" name="lineAmount">
 | 
			
		||||
           <property name="sizePolicy">
 | 
			
		||||
            <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
 | 
			
		||||
             <horstretch>0</horstretch>
 | 
			
		||||
             <verstretch>0</verstretch>
 | 
			
		||||
            </sizepolicy>
 | 
			
		||||
           </property>
 | 
			
		||||
           <property name="text">
 | 
			
		||||
            <string/>
 | 
			
		||||
           </property>
 | 
			
		||||
           <property name="placeholderText">
 | 
			
		||||
            <string/>
 | 
			
		||||
           </property>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </item>
 | 
			
		||||
         <item>
 | 
			
		||||
          <widget class="QComboBox" name="comboBox_currency">
 | 
			
		||||
           <item>
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>BTC</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </item>
 | 
			
		||||
           <item>
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>XMR</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </item>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </item>
 | 
			
		||||
        </layout>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item>
 | 
			
		||||
        <widget class="QLabel" name="xmrLabelEstimate">
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>0.00 XMR</string>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="wordWrap">
 | 
			
		||||
          <bool>false</bool>
 | 
			
		||||
         </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>
 | 
			
		||||
      </layout>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item row="1" column="1">
 | 
			
		||||
      <layout class="QHBoxLayout" name="horizontalLayout">
 | 
			
		||||
       <item>
 | 
			
		||||
        <widget class="QLineEdit" name="lineAddress">
 | 
			
		||||
         <property name="sizePolicy">
 | 
			
		||||
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
 | 
			
		||||
           <horstretch>0</horstretch>
 | 
			
		||||
           <verstretch>0</verstretch>
 | 
			
		||||
          </sizepolicy>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string/>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="placeholderText">
 | 
			
		||||
          <string>BTC address</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item>
 | 
			
		||||
        <spacer name="horizontalSpacer_2">
 | 
			
		||||
         <property name="orientation">
 | 
			
		||||
          <enum>Qt::Horizontal</enum>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="sizeType">
 | 
			
		||||
          <enum>QSizePolicy::Minimum</enum>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="sizeHint" stdset="0">
 | 
			
		||||
          <size>
 | 
			
		||||
           <width>40</width>
 | 
			
		||||
           <height>20</height>
 | 
			
		||||
          </size>
 | 
			
		||||
         </property>
 | 
			
		||||
        </spacer>
 | 
			
		||||
       </item>
 | 
			
		||||
       <item>
 | 
			
		||||
        <widget class="QLabel" name="logo">
 | 
			
		||||
         <property name="sizePolicy">
 | 
			
		||||
          <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
 | 
			
		||||
           <horstretch>0</horstretch>
 | 
			
		||||
           <verstretch>0</verstretch>
 | 
			
		||||
          </sizepolicy>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="maximumSize">
 | 
			
		||||
          <size>
 | 
			
		||||
           <width>169</width>
 | 
			
		||||
           <height>48</height>
 | 
			
		||||
          </size>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="text">
 | 
			
		||||
          <string>-</string>
 | 
			
		||||
         </property>
 | 
			
		||||
        </widget>
 | 
			
		||||
       </item>
 | 
			
		||||
      </layout>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item row="1" column="0">
 | 
			
		||||
      <widget class="QLabel" name="label">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Pay to</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <widget class="Line" name="line">
 | 
			
		||||
     <property name="frameShadow">
 | 
			
		||||
      <enum>QFrame::Sunken</enum>
 | 
			
		||||
     </property>
 | 
			
		||||
     <property name="orientation">
 | 
			
		||||
      <enum>Qt::Horizontal</enum>
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <widget class="QWidget" name="ratesLayout" native="true">
 | 
			
		||||
     <property name="sizePolicy">
 | 
			
		||||
      <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
 | 
			
		||||
       <horstretch>0</horstretch>
 | 
			
		||||
       <verstretch>0</verstretch>
 | 
			
		||||
      </sizepolicy>
 | 
			
		||||
     </property>
 | 
			
		||||
     <layout class="QHBoxLayout" name="tickerLayout">
 | 
			
		||||
      <property name="leftMargin">
 | 
			
		||||
       <number>0</number>
 | 
			
		||||
      </property>
 | 
			
		||||
      <property name="topMargin">
 | 
			
		||||
       <number>1</number>
 | 
			
		||||
      </property>
 | 
			
		||||
      <property name="rightMargin">
 | 
			
		||||
       <number>0</number>
 | 
			
		||||
      </property>
 | 
			
		||||
      <property name="bottomMargin">
 | 
			
		||||
       <number>6</number>
 | 
			
		||||
      </property>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QGroupBox" name="groupBox_3">
 | 
			
		||||
        <property name="title">
 | 
			
		||||
         <string>Rate (1 XMR)</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <layout class="QHBoxLayout" name="horizontalLayout_3">
 | 
			
		||||
         <property name="leftMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="topMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="rightMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="bottomMargin">
 | 
			
		||||
          <number>4</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <item>
 | 
			
		||||
          <widget class="QLabel" name="label_rate">
 | 
			
		||||
           <property name="text">
 | 
			
		||||
            <string>Rate</string>
 | 
			
		||||
           </property>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </item>
 | 
			
		||||
        </layout>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QGroupBox" name="groupBox_2">
 | 
			
		||||
        <property name="title">
 | 
			
		||||
         <string>Minimum</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <layout class="QHBoxLayout" name="horizontalLayout_5">
 | 
			
		||||
         <property name="leftMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="topMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="rightMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="bottomMargin">
 | 
			
		||||
          <number>4</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <item>
 | 
			
		||||
          <widget class="QLabel" name="label_minimum">
 | 
			
		||||
           <property name="text">
 | 
			
		||||
            <string>Minimum</string>
 | 
			
		||||
           </property>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </item>
 | 
			
		||||
        </layout>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QGroupBox" name="groupBox">
 | 
			
		||||
        <property name="title">
 | 
			
		||||
         <string>Maximum</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <layout class="QHBoxLayout" name="horizontalLayout_7">
 | 
			
		||||
         <property name="leftMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="topMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="rightMargin">
 | 
			
		||||
          <number>6</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <property name="bottomMargin">
 | 
			
		||||
          <number>4</number>
 | 
			
		||||
         </property>
 | 
			
		||||
         <item>
 | 
			
		||||
          <widget class="QLabel" name="label_maximum">
 | 
			
		||||
           <property name="text">
 | 
			
		||||
            <string>Maximum</string>
 | 
			
		||||
           </property>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </item>
 | 
			
		||||
        </layout>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
     </layout>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <widget class="QTreeView" name="historyTable">
 | 
			
		||||
     <property name="rootIsDecorated">
 | 
			
		||||
      <bool>false</bool>
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
  </layout>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <resources/>
 | 
			
		||||
 <connections/>
 | 
			
		||||
</ui>
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue