Fabcoin Core  0.16.2
P2P Digital Currency
sendtocontract.cpp
Go to the documentation of this file.
1 #include <sendtocontract.h>
2 #include <ui_sendtocontract.h>
3 #include <platformstyle.h>
4 #include <walletmodel.h>
5 #include <clientmodel.h>
6 #include <guiconstants.h>
7 #include <rpcconsole.h>
8 #include <execrpccommand.h>
9 #include <fabcoinunits.h>
10 #include <optionsmodel.h>
11 #include <validation.h>
12 #include <utilmoneystr.h>
13 #include <abifunctionfield.h>
14 #include <contractabi.h>
15 #include <tabbarinfo.h>
16 #include <contractresult.h>
17 #include <contractbookpage.h>
18 #include <editcontractinfodialog.h>
19 #include <contracttablemodel.h>
20 #include <styleSheet.h>
21 #include <guiutil.h>
22 #include <sendcoinsdialog.h>
23 #include <QClipboard>
24 
26 {
27 // Contract data names
28 static const QString PRC_COMMAND = "sendtocontract";
29 static const QString PARAM_ADDRESS = "address";
30 static const QString PARAM_DATAHEX = "datahex";
31 static const QString PARAM_AMOUNT = "amount";
32 static const QString PARAM_GASLIMIT = "gaslimit";
33 static const QString PARAM_GASPRICE = "gasprice";
34 static const QString PARAM_SENDER = "sender";
35 
36 static const CAmount SINGLE_STEP = 0.00000001*COIN;
37 static const CAmount HIGH_GASPRICE = 0.001*COIN;
38 }
39 using namespace SendToContract_NS;
40 
41 SendToContract::SendToContract(const PlatformStyle *platformStyle, QWidget *parent) :
42  QWidget(parent),
43  ui(new Ui::SendToContract),
44  m_model(0),
45  m_clientModel(0),
46  m_contractModel(0),
47  m_execRPCCommand(0),
48  m_ABIFunctionField(0),
49  m_contractABI(0),
50  m_tabInfo(0),
51  m_results(1)
52 {
53  m_platformStyle = platformStyle;
54 
55  // Setup ui components
56  Q_UNUSED(platformStyle);
57  ui->setupUi(this);
58  ui->saveInfoButton->setIcon(platformStyle->MultiStatesIcon(":/icons/filesave", PlatformStyle::PushButton));
59  ui->loadInfoButton->setIcon(platformStyle->MultiStatesIcon(":/icons/address-book", PlatformStyle::PushButton));
60  ui->pasteAddressButton->setIcon(platformStyle->MultiStatesIcon(":/icons/editpaste", PlatformStyle::PushButton));
61  // Format tool buttons
63 
64  // Set stylesheet
65  SetObjectStyleSheet(ui->pushButtonClearAll, StyleSheetNames::ButtonBlack);
66 
70  ui->labelContractAddress->setToolTip(tr("The contract address that will receive the funds and data."));
71  ui->labelAmount->setToolTip(tr("The amount in FABCOIN to send. Default = 0."));
72  ui->labelSenderAddress->setToolTip(tr("The quantum address that will be used as sender."));
73 
75  m_tabInfo->addTab(0, tr("Send To Contract"));
76 
77  // Set defaults
78  ui->lineEditGasPrice->setValue(DEFAULT_GAS_PRICE);
79  ui->lineEditGasPrice->setSingleStep(SINGLE_STEP);
80  ui->lineEditGasLimit->setMinimum(MINIMUM_GAS_LIMIT);
81  ui->lineEditGasLimit->setMaximum(DEFAULT_GAS_LIMIT_OP_SEND);
82  ui->lineEditGasLimit->setValue(DEFAULT_GAS_LIMIT_OP_SEND);
84  ui->pushButtonSendToContract->setEnabled(false);
85 
86  // Create new PRC command line interface
87  QStringList lstMandatory;
88  lstMandatory.append(PARAM_ADDRESS);
89  lstMandatory.append(PARAM_DATAHEX);
90  QStringList lstOptional;
91  lstOptional.append(PARAM_AMOUNT);
92  lstOptional.append(PARAM_GASLIMIT);
93  lstOptional.append(PARAM_GASPRICE);
94  lstOptional.append(PARAM_SENDER);
95  QMap<QString, QString> lstTranslations;
96  lstTranslations[PARAM_ADDRESS] = ui->labelContractAddress->text();
97  lstTranslations[PARAM_AMOUNT] = ui->labelAmount->text();
98  lstTranslations[PARAM_GASLIMIT] = ui->labelGasLimit->text();
99  lstTranslations[PARAM_GASPRICE] = ui->labelGasPrice->text();
100  lstTranslations[PARAM_SENDER] = ui->labelSenderAddress->text();
101  m_execRPCCommand = new ExecRPCCommand(PRC_COMMAND, lstMandatory, lstOptional, lstTranslations, this);
102  m_contractABI = new ContractABI();
103 
104  // Connect signals with slots
105  connect(ui->pushButtonClearAll, SIGNAL(clicked()), SLOT(on_clearAllClicked()));
106  connect(ui->pushButtonSendToContract, SIGNAL(clicked()), SLOT(on_sendToContractClicked()));
107  connect(ui->lineEditContractAddress, SIGNAL(textChanged(QString)), SLOT(on_updateSendToContractButton()));
108  connect(ui->textEditInterface, SIGNAL(textChanged()), SLOT(on_newContractABI()));
109  connect(ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(on_updateSendToContractButton()));
110  connect(m_ABIFunctionField, SIGNAL(functionChanged()), SLOT(on_functionChanged()));
111  connect(ui->saveInfoButton, SIGNAL(clicked()), SLOT(on_saveInfoClicked()));
112  connect(ui->loadInfoButton, SIGNAL(clicked()), SLOT(on_loadInfoClicked()));
113  connect(ui->pasteAddressButton, SIGNAL(clicked()), SLOT(on_pasteAddressClicked()));
114  connect(ui->lineEditContractAddress, SIGNAL(textChanged(QString)), SLOT(on_contractAddressChanged()));
115 
116  // Set contract address validator
117  QRegularExpression regEx;
118  regEx.setPattern(paternAddress);
119  QRegularExpressionValidator *addressValidatr = new QRegularExpressionValidator(ui->lineEditContractAddress);
120  addressValidatr->setRegularExpression(regEx);
121  ui->lineEditContractAddress->setCheckValidator(addressValidatr);
122 }
123 
125 {
126  delete m_contractABI;
127  delete ui;
128 }
129 
131 {
132  m_model = _model;
134 }
135 
137 {
140 }
141 
143 {
145  return ui->textEditInterface->isValid();
146 }
147 
149 {
150  bool dataValid = true;
151 
153  dataValid = false;
154  if(!isValidInterfaceABI())
155  dataValid = false;
157  dataValid = false;
158  return dataValid;
159 }
160 
162 {
163  ui->lineEditContractAddress->setText(address);
164  ui->lineEditContractAddress->setFocus();
165 }
166 
168 {
169  m_clientModel = _clientModel;
170 
171  if (m_clientModel)
172  {
173  connect(m_clientModel, SIGNAL(tipChanged()), this, SLOT(on_numBlocksChanged()));
175  }
176 }
177 
179 {
181  ui->lineEditAmount->clear();
182  ui->lineEditAmount->setEnabled(true);
183  ui->lineEditGasLimit->setValue(DEFAULT_GAS_LIMIT_OP_SEND);
184  ui->lineEditGasPrice->setValue(DEFAULT_GAS_PRICE);
185  ui->lineEditSenderAddress->setCurrentIndex(-1);
188  m_tabInfo->clear();
189 }
190 
192 {
193  if(isDataValid())
194  {
196  if(!ctx.isValid())
197  {
198  return;
199  }
200 
201  // Initialize variables
202  QMap<QString, QString> lstParams;
203  QVariant result;
204  QString errorMessage;
205  QString resultJson;
206  int unit = m_model->getOptionsModel()->getDisplayUnit();
207  uint64_t gasLimit = ui->lineEditGasLimit->value();
208  CAmount gasPrice = ui->lineEditGasPrice->value();
210 
211  // Check for high gas price
212  if(gasPrice > HIGH_GASPRICE)
213  {
214  QString message = tr("The Gas Price is too high, are you sure you want to possibly spend a max of %1 for this transaction?");
215  if(QMessageBox::question(this, tr("High Gas price"), message.arg(FabcoinUnits::formatWithUnit(unit, gasLimit * gasPrice))) == QMessageBox::No)
216  return;
217  }
218 
219  // Append params to the list
220  ExecRPCCommand::appendParam(lstParams, PARAM_ADDRESS, ui->lineEditContractAddress->text());
221  ExecRPCCommand::appendParam(lstParams, PARAM_DATAHEX, toDataHex(func, errorMessage));
222  QString amount = isFunctionPayable() ? FabcoinUnits::format(unit, ui->lineEditAmount->value(), false, FabcoinUnits::separatorNever) : "0";
223  ExecRPCCommand::appendParam(lstParams, PARAM_AMOUNT, amount);
224  ExecRPCCommand::appendParam(lstParams, PARAM_GASLIMIT, QString::number(gasLimit));
225  ExecRPCCommand::appendParam(lstParams, PARAM_GASPRICE, FabcoinUnits::format(unit, gasPrice, false, FabcoinUnits::separatorNever));
226  ExecRPCCommand::appendParam(lstParams, PARAM_SENDER, ui->lineEditSenderAddress->currentText());
227 
228  QString questionString = tr("Are you sure you want to send to the contract: <br /><br />");
229  questionString.append(tr("<b>%1</b>?")
230  .arg(ui->lineEditContractAddress->text()));
231 
232  SendConfirmationDialog confirmationDialog(tr("Confirm sending to contract."), questionString, 3, this);
233  confirmationDialog.exec();
234  QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
235  if(retval == QMessageBox::Yes)
236  {
237  // Execute RPC command line
238  if(errorMessage.isEmpty() && m_execRPCCommand->exec(lstParams, result, resultJson, errorMessage))
239  {
240  ContractResult *widgetResult = new ContractResult(ui->stackedWidget);
242  ui->stackedWidget->addWidget(widgetResult);
243  int position = ui->stackedWidget->count() - 1;
244  m_results = position == 1 ? 1 : m_results + 1;
245 
246  m_tabInfo->addTab(position, tr("Result %1").arg(m_results));
247  m_tabInfo->setCurrent(position);
248  }
249  else
250  {
251  QMessageBox::warning(this, tr("Send to contract"), errorMessage);
252  }
253  }
254  }
255 }
256 
258 {
259  if(m_clientModel)
260  {
261  uint64_t blockGasLimit = 0;
262  uint64_t minGasPrice = 0;
263  uint64_t nGasPrice = 0;
264  m_clientModel->getGasInfo(blockGasLimit, minGasPrice, nGasPrice);
265 
266  ui->labelGasLimit->setToolTip(tr("Gas limit: Default = %1, Max = %2.").arg(DEFAULT_GAS_LIMIT_OP_SEND).arg(blockGasLimit));
267  ui->labelGasPrice->setToolTip(tr("Gas price: FABCOIN price per gas unit. Default = %1, Min = %2.").arg(QString::fromStdString(FormatMoney(DEFAULT_GAS_PRICE))).arg(QString::fromStdString(FormatMoney(minGasPrice))));
268  ui->lineEditGasPrice->setMinimum(minGasPrice);
269  ui->lineEditGasLimit->setMaximum(blockGasLimit);
270 
272  }
273 }
274 
276 {
278  bool enabled = func >= -1;
279  if(ui->lineEditContractAddress->text().isEmpty())
280  {
281  enabled = false;
282  }
283  enabled &= ui->stackedWidget->currentIndex() == 0;
284 
285  ui->pushButtonSendToContract->setEnabled(enabled);
286 }
287 
289 {
290  std::string json_data = ui->textEditInterface->toPlainText().toStdString();
291  if(!m_contractABI->loads(json_data))
292  {
293  m_contractABI->clean();
295  }
296  else
297  {
299  }
301 
303 }
304 
306 {
307  bool payable = isFunctionPayable();
308  ui->lineEditAmount->setEnabled(payable);
309  if(!payable)
310  {
311  ui->lineEditAmount->clear();
312  }
313 }
314 
316 {
317  if(!m_contractModel)
318  return;
319 
320  bool valid = true;
321 
323  valid = false;
324 
325  if(!isValidInterfaceABI())
326  valid = false;
327 
328  if(!valid)
329  return;
330 
331  QString contractAddress = ui->lineEditContractAddress->text();
332  int row = m_contractModel->lookupAddress(contractAddress);
334  EditContractInfoDialog dlg(dlgMode, this);
337  {
338  dlg.loadRow(row);
339  }
340  dlg.setAddress(ui->lineEditContractAddress->text());
341  dlg.setABI(ui->textEditInterface->toPlainText());
342  if(dlg.exec())
343  {
344  ui->lineEditContractAddress->setText(dlg.getAddress());
345  ui->textEditInterface->setText(dlg.getABI());
347  }
348 }
349 
351 {
354  if(dlg.exec())
355  {
356  ui->lineEditContractAddress->setText(dlg.getAddressValue());
358  }
359 }
360 
362 {
363  setContractAddress(QApplication::clipboard()->text());
364 }
365 
367 {
369  {
370  QString contractAddress = ui->lineEditContractAddress->text();
371  if(m_contractModel->lookupAddress(contractAddress) > -1)
372  {
373  QString contractAbi = m_contractModel->abiForAddress(contractAddress);
374  if(ui->textEditInterface->toPlainText() != contractAbi)
375  {
376  ui->textEditInterface->setText(m_contractModel->abiForAddress(contractAddress));
377  }
378  }
379  }
380 }
381 
382 QString SendToContract::toDataHex(int func, QString& errorMessage)
383 {
384  if(func == -1 || m_ABIFunctionField == NULL || m_contractABI == NULL)
385  {
386  std::string defSelector = FunctionABI::defaultSelector();
387  return QString::fromStdString(defSelector);
388  }
389 
390  std::string strData;
391  std::vector<std::vector<std::string>> values = m_ABIFunctionField->getValuesVector();
392  FunctionABI function = m_contractABI->functions[func];
393  std::vector<ParameterABI::ErrorType> errors;
394  if(function.abiIn(values, strData, errors))
395  {
396  return QString::fromStdString(strData);
397  }
398  else
399  {
400  errorMessage = function.errorMessage(errors, true);
401  }
402  return "";
403 }
404 
406 {
408  if(func < 0) return true;
409  FunctionABI function = m_contractABI->functions[func];
410  return function.payable;
411 }
QPushButton * pushButtonSendToContract
#define SetObjectStyleSheet(object, name)
Definition: styleSheet.h:10
const QString & getAddressValue() const
QLabel * labelContractAddress
int lookupAddress(const QString &address) const
void setModel(WalletModel *model)
Dialog for editing a contract information.
void setABI(const QString &ABI)
ContractABI * m_contractABI
UnlockContext requestUnlock()
void on_contractAddressChanged()
void on_updateSendToContractButton()
void setupUi(QWidget *SendToContract)
void setSingleStep(const CAmount &step)
Set single step in satoshis.
void setResultData(QVariant result, FunctionABI function, QList< QStringList > paramValues, ContractTxType type)
WalletModel * m_model
void on_numBlocksChanged()
ContractTableModel * getContractTableModel()
#define paternAddress
Definition: contractabi.h:11
bool isValidContractAddress()
void setIsValidManually(bool value)
std::vector< FunctionABI > functions
Definition: contractabi.h:205
QToolButton * pasteAddressButton
void on_refresh()
on_refresh Refresh the list of addresses
ExecRPCCommand * m_execRPCCommand
std::vector< std::vector< std::string > > getValuesVector()
getValuesVector Get params values vector List of all parameters that can be sent to a function...
bool exec(const QMap< QString, QString > &params, QVariant &result, QString &resultJson, QString &errorMessage)
exec Execute the RPC command
bool addTab(int index, const QString &name)
addTab Add new tab
Definition: tabbarinfo.cpp:14
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
QString abiForAddress(const QString &address) const
bytes abiIn(std::string _id, T const &..._t)
Definition: ABI.h:64
void setContractABI(ContractABI *contractABI)
setContractABI Set the contract ABI (list of functions from the contract)
int64_t CAmount
Amount in lius (Can be negative)
Definition: amount.h:15
void setCurrent(int index)
setCurrent Set current index
Definition: tabbarinfo.cpp:95
void setContractAddress(const QString &address)
void on_sendToContractClicked()
FabcoinAmountField * lineEditAmount
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string.
int getSelectedFunction() const
getSelectedFunction Get the ABI for the selected function from the contract
void setModel(ContractTableModel *model)
AddressField * lineEditSenderAddress
int getDisplayUnit()
Definition: optionsmodel.h:70
void clear()
clear Remove all tabs except the first one which is not closable
Definition: tabbarinfo.cpp:101
Model for Fabcoin network client.
Definition: clientmodel.h:38
std::string FormatMoney(const CAmount &n)
Money parsing/formatting utilities.
void setModel(ContractTableModel *model)
The ABIFunctionField class ABI functions widget.
FabcoinAmountField * lineEditGasPrice
QPushButton * pushButtonClearAll
void setEnabled(bool fEnabled)
Enable/Disable.
void on_pasteAddressClicked()
Ui::SendToContract * ui
void setValue(const CAmount &value)
const PlatformStyle * m_platformStyle
bool isValidInterfaceABI()
QString toDataHex(int func, QString &errorMessage)
QValidatedLineEdit * lineEditContractAddress
The ExecRPCCommand class Execution of RPC command line.
QList< QStringList > getParamsValues()
getParamsValues Get the values of the whole list of input parameters for the selected function ...
QIcon MultiStatesIcon(const QString &resourcename, StateType type=NavBar, QColor color=Qt::white, QColor colorAlt=0x2d2d2d) const
Get multi-states icon.
Interface to Fabcoin wallet from Qt view code.
Definition: walletmodel.h:103
virtual QString currentText() const
currentText Get the current text
QStackedWidget * stackedWidget
TabBarInfo * m_tabInfo
void setCheckValidator(const QValidator *v)
The TabBarInfo class Class for informations about tabs.
Definition: tabbarinfo.h:13
static void appendParam(QMap< QString, QString > &params, const QString &paramName, const QString &paramValue)
appendParam Append paramether to the list
QToolButton * loadInfoButton
bool loads(const std::string &json_data)
Definition: contractabi.cpp:54
struct evm_uint160be address(struct evm_env *env)
Definition: capi.c:13
static std::string defaultSelector()
void formatToolButtons(QToolButton *btn1, QToolButton *btn2, QToolButton *btn3)
Definition: guiutil.cpp:989
ContractTableModel * m_contractModel
QSpinBox * lineEditGasLimit
SendToContract(const PlatformStyle *platformStyle, QWidget *parent=0)
void setMinimum(const CAmount &min)
QToolButton * saveInfoButton
ABIFunctionField * m_ABIFunctionField
QValidatedTextEdit * textEditInterface
ClientModel * m_clientModel
void clear()
Make field empty and ready for new input.
QScrollArea * scrollAreaFunction
void setAddress(const QString &address)
OptionsModel * getOptionsModel()
void setClientModel(ClientModel *clientModel)
void getGasInfo(uint64_t &blockGasLimit, uint64_t &minGasPrice, uint64_t &nGasPrice) const
Get the information about the needed gas.