diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 9b4eeab14..7cc080d99 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -81,13 +81,7 @@ ClientModel::ClientModel(): qRegisterMetaType("QInstruction"); qRegisterMetaType("QCode"); qRegisterMetaType("QCallData"); - qRegisterMetaType("RecordLogEntry*"); - - m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); - - m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); - m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector(), m_client.get())); - connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); + qRegisterMetaType("RecordLogEntry*"); } ClientModel::~ClientModel() @@ -95,6 +89,19 @@ ClientModel::~ClientModel() m_runFuture.waitForFinished(); } +void ClientModel::init(QString _dbpath) +{ + m_dbpath = _dbpath; + if (m_dbpath.isEmpty()) + m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); + else + m_client.reset(new MixClient(m_dbpath.toStdString())); + + m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); + m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector(), m_client.get())); + connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); +} + QString ClientModel::apiCall(QString const& _message) { try @@ -295,36 +302,40 @@ void ClientModel::finalizeBlock() } } +TransactionSettings ClientModel::transaction(QVariant _tr) +{ + QVariantMap transaction = _tr.toMap(); + QString contractId = transaction.value("contractId").toString(); + QString functionId = transaction.value("functionId").toString(); + bool gasAuto = transaction.value("gasAuto").toBool(); + u256 gas = 0; + if (transaction.value("gas").data()) + gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); + else + gasAuto = true; + + u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); + u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); + QString sender = transaction.value("sender").toString(); + bool isContractCreation = transaction.value("isContractCreation").toBool(); + bool isFunctionCall = transaction.value("isFunctionCall").toBool(); + if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later + contractId = m_codeModel->contracts().keys()[0]; + Secret f = Secret(sender.toStdString()); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, f, isContractCreation, isFunctionCall); + transactionSettings.parameterValues = transaction.value("parameters").toMap(); + if (contractId == functionId || functionId == "Constructor") + transactionSettings.functionId.clear(); + return transactionSettings; +} + void ClientModel::processNextTransactions() { WriteGuard(x_queueTransactions); vector transactionSequence; for (auto const& t: m_queueTransactions.front()) { - QVariantMap transaction = t.toMap(); - QString contractId = transaction.value("contractId").toString(); - QString functionId = transaction.value("functionId").toString(); - bool gasAuto = transaction.value("gasAuto").toBool(); - u256 gas = 0; - if (transaction.value("gas").data()) - gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); - else - gasAuto = true; - - u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); - u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); - QString sender = transaction.value("sender").toString(); - bool isContractCreation = transaction.value("isContractCreation").toBool(); - bool isFunctionCall = transaction.value("isFunctionCall").toBool(); - if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later - contractId = m_codeModel->contracts().keys()[0]; - Secret f = Secret(sender.toStdString()); - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, f, isContractCreation, isFunctionCall); - transactionSettings.parameterValues = transaction.value("parameters").toMap(); - - if (contractId == functionId || functionId == "Constructor") - transactionSettings.functionId.clear(); - + TransactionSettings transactionSettings = transaction(t); transactionSequence.push_back(transactionSettings); } executeSequence(transactionSequence); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index ca8c36b79..4a367f9ba 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -171,7 +171,7 @@ public: Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) /// @returns deployed contracts gas costs Q_PROPERTY(QVariantList gasCosts READ gasCosts NOTIFY gasCostsChanged) - // @returns the last block + /// @returns the last block Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT) /// ethereum.js RPC request entry point /// @param _message RPC request in Json format @@ -191,6 +191,10 @@ public: Q_INVOKABLE void addAccount(QString const& _secret); /// Return the address associated with the current secret Q_INVOKABLE QString resolveAddress(QString const& _secret); + /// Compute required gas for a list of transactions @arg _tr + QBigInt computeRequiredGas(QVariantList _tr); + /// init eth client + Q_INVOKABLE void init(QString _dbpath); public slots: /// Setup scenario, run transaction sequence, show debugger for the last transaction @@ -266,6 +270,7 @@ private: void finalizeBlock(); void stopExecution(); void setupExecutionChain(); + TransactionSettings transaction(QVariant _tr); std::atomic m_running; std::atomic m_mining; @@ -284,6 +289,7 @@ private: CodeModel* m_codeModel = nullptr; QList m_queueTransactions; mutable boost::shared_mutex x_queueTransactions; + QString m_dbpath; }; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index c73763076..8e3b24cd9 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -79,7 +79,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -124,22 +123,16 @@ Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secre return ret; } -void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) +ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, LastHashes _lastHashes, bool _call) { - Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; - // do debugging run first - LastHashes lastHashes(256); - lastHashes[0] = bc().numberHash(bc().number()); - for (unsigned i = 1; i < 256; ++i) - lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); - State execState = _state; - execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation + execState.addBalance(_t.sender(), _t.gas() * _t.gasPrice()); //give it enough balance for gas estimation eth::ExecutionResult er; - Executive execution(execState, lastHashes, 0); + Executive execution(execState, _lastHashes, 0); execution.setResultRecipient(er); - execution.initialize(t); + execution.initialize(_t); execution.execute(); + std::vector machineStates; std::vector levels; std::vector codes; @@ -235,7 +228,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c } ExecutionResult d; - d.inputParameters = t.data(); + d.inputParameters = _t.data(); d.result = er; d.machineStates = machineStates; d.executionCode = std::move(codes); @@ -249,12 +242,26 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c if (!_call) d.transactionIndex = m_state.pending().size(); d.executonIndex = m_executions.size(); + return d; +} + + +void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) +{ + Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; + // do debugging run first + LastHashes lastHashes(256); + lastHashes[0] = bc().numberHash(bc().number()); + for (unsigned i = 1; i < 256; ++i) + lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); + + ExecutionResult d = debugTransaction(t, _state, lastHashes, _call); // execute on a state if (!_call) { t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; - er = _state.execute(lastHashes, t); + eth::ExecutionResult er = _state.execute(lastHashes, _t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..75f45efbf 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -61,7 +61,7 @@ public: virtual std::pair submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret) override { return submitTransaction(_ts, _secret, false); } std::pair submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto); dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); - + ExecutionResult debugTransaction(dev::eth::Transaction const& _t, eth:: State const& _state, eth::LastHashes _lastHashes, bool _call); void setAddress(Address _us) override; void startMining() override; void stopMining() override; diff --git a/mix/qml.qrc b/mix/qml.qrc index 34295b022..c1901c220 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -71,5 +71,10 @@ qml/ScenarioButton.qml qml/Watchers.qml qml/KeyValuePanel.qml + qml/DeployContractStep.qml + qml/RegisteringStep.qml + qml/DeploymentDialogSteps.qml + qml/PackagingStep.qml + qml/DeploymentWorker.qml diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index bdb0896e5..8ee70942d 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -42,6 +42,11 @@ ApplicationWindow { ClientModel { id: clientModel codeModel: codeModel + Component.onCompleted: + { + console.log("tmp") + init("/tmp") + } } ProjectModel { diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 51950fec7..774a3b11f 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -24,6 +24,19 @@ Item { return ""; } + function getContracts() + { + var ctr = [] + for (var i = 0; i < openDocCount; i++) + { + if (editorListModel.get(i).isContract) + { + ctr.push(editors.itemAt(i).item) + } + } + return ctr; + } + function isDocumentOpen(documentId) { for (var i = 0; i < openDocCount; i++) if (editorListModel.get(i).documentId === documentId && diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml new file mode 100644 index 000000000..4d675a639 --- /dev/null +++ b/mix/qml/DeployContractStep.qml @@ -0,0 +1,352 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper +import org.ethereum.qml.QEther 1.0 + +Rectangle { + property variant paramsModel: [] + property variant worker + color: "#E3E3E3E3" + anchors.fill: parent + id: root + + function show() + { + visible = true + contractList.currentIndex = 0 + contractList.change() + accountsModel.clear() + for (var k in worker.accounts) + { + accountsModel.append(worker.accounts[k]) + } + if (worker.accounts.length > 0) + worker.currentAccount = worker.accounts[0].id + } + + RowLayout + { + anchors.fill: parent + anchors.margins: 10 + ColumnLayout + { + anchors.top: parent.top + Layout.preferredWidth: parent.width * 0.40 - 20 + Layout.fillHeight: true + id: scenarioList + + Label + { + Layout.fillWidth: true + text: qsTr("Pick Scenario to deploy") + } + + ComboBox + { + id: contractList + Layout.preferredWidth: parent.width - 20 + model: projectModel.stateListModel + textRole: "title" + onCurrentIndexChanged: + { + change() + } + + function change() + { + trListModel.clear() + if (currentIndex > -1) + { + for (var k = 0; k < projectModel.stateListModel.get(currentIndex).blocks.count; k++) + { + for (var j = 0; j < projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.count; j++) + { + trListModel.append(projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.get(j)); + } + } + for (var k = 0; k < trListModel.count; k++) + { + trList.itemAt(k).init() + } + ctrDeployCtrLabel.calculateContractDeployGas(); + } + } + } + + Rectangle + { + Layout.fillHeight: true + Layout.preferredWidth: parent.width - 20 + id: trContainer + color: "white" + border.color: "#cccccc" + border.width: 1 + ScrollView + { + anchors.fill: parent + ColumnLayout + { + spacing: 0 + ListModel + { + id: trListModel + } + + Repeater + { + id: trList + model: trListModel + ColumnLayout + { + Layout.fillWidth: true + spacing: 5 + Layout.preferredHeight: + { + if (index > -1) + return 20 + trListModel.get(index)["parameters"].count * 20 + else + return 20 + } + + function init() + { + paramList.clear() + if (trListModel.get(index).parameters) + { + for (var k in trListModel.get(index).parameters) + { + paramList.append({ "name": k, "value": trListModel.get(index).parameters[k] }) + } + } + } + + Label + { + id: trLabel + Layout.preferredHeight: 20 + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: 5 + anchors.leftMargin: 10 + text: + { + if (index > -1) + return trListModel.get(index).label + else + return "" + } + } + + ListModel + { + id: paramList + } + + Repeater + { + Layout.preferredHeight: + { + if (index > -1) + return trListModel.get(index)["parameters"].count * 20 + else + return 0 + } + model: paramList + Label + { + Layout.preferredHeight: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + text: name + "=" + value + font.italic: true + } + } + } + } + } + } + } + } + + + ColumnLayout + { + anchors.top: parent.top + Layout.preferredHeight: parent.height - 25 + ColumnLayout + { + anchors.top: parent.top + Layout.preferredWidth: parent.width * 0.60 + Layout.fillHeight: true + id: deploymentOption + + Label + { + anchors.left: parent.left + anchors.leftMargin: 105 + text: qsTr("Deployment options") + } + + ListModel + { + id: accountsModel + } + + RowLayout + { + Layout.fillWidth: true + Rectangle + { + width: 100 + Label + { + text: qsTr("Account") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + ComboBox + { + id: accountsList + textRole: "id" + model: accountsModel + Layout.preferredWidth: 235 + onCurrentTextChanged: + { + worker.currentAccount = currentText + } + } + } + + RowLayout + { + Layout.fillWidth: true + Rectangle + { + width: 100 + Label + { + text: qsTr("Gas Price") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Ether + { + id: gasPriceInput + displayUnitSelection: true + displayFormattedValue: false + edit: true + } + + Connections + { + target: gasPriceInput + onValueChanged: + { + ctrDeployCtrLabel.calculateContractDeployGas() + } + onAmountChanged: + { + ctrDeployCtrLabel.setCost() + } + onUnitChanged: + { + ctrDeployCtrLabel.setCost() + } + } + + Connections + { + target: worker + id: gasPriceLoad + property bool loaded: false + onGasPriceLoaded: + { + gasPriceInput.value = QEtherHelper.createEther(worker.gasPriceInt.value(), QEther.Wei) + gasPriceLoad.loaded = true + ctrDeployCtrLabel.calculateContractDeployGas() + } + } + } + + RowLayout + { + id: ctrDeployCtrLabel + Layout.fillWidth: true + property int cost + function calculateContractDeployGas() + { + if (!root.visible) + return; + var sce = projectModel.stateListModel.getState(contractList.currentIndex) + worker.estimateGas(sce, function(gas) { + if (gasPriceLoad.loaded) + { + cost = 0 + for (var k in gas) + { + cost += gas[k] + } + setCost() + } + }); + } + + function setCost() + { + var ether = QEtherHelper.createBigInt(cost); + var gasTotal = ether.multiply(gasPriceInput.value); + gasToUseInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); + } + + Rectangle + { + width: 100 + Label + { + text: qsTr("Cost Estimate") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Ether + { + id: gasToUseInput + displayUnitSelection: false + displayFormattedValue: true + edit: false + Layout.preferredWidth: 350 + } + } + + + } + + Rectangle + { + Layout.preferredWidth: parent.width + Layout.alignment: Qt.BottomEdge + Button + { + anchors.right: parent.right + text: qsTr("Deploy Contracts") + onClicked: + { + projectModel.deployedScenarioIndex = contractList.currentIndex + NetworkDeploymentCode.deployContracts(); + } + } + } + } + } + +} + diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 81092ec76..ad946cd3e 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -14,22 +14,14 @@ import "." Dialog { id: modalDeploymentDialog modality: Qt.ApplicationModal - width: 735 + width: 800 height: 450 visible: false - property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr. - property int ownedRegistrarSetSubRegistrarGas: 50000 - property int ownedRegistrarSetContentHashGas: 50000 - property int urlHintSuggestUrlGas: 70000 - property alias applicationUrlEth: applicationUrlEth.text - property alias applicationUrlHttp: applicationUrlHttp.text - property alias localPackageUrl: localPackageUrl.text - property string packageHash - property string packageBase64 - property string eth: registrarAddr.text - property string currentAccount - property string gasPrice - property variant paramsModel: [] + + property alias deployStep: deployStep + property alias packageStep: packageStep + property alias registerStep: registerStep + property alias worker: worker function close() { @@ -38,552 +30,126 @@ Dialog { function open() { + deployStep.visible = false + packageStep.visible = false + registerStep.visible = false + steps.init() + worker.renewCtx() visible = true; - var requests = [{ - //accounts - jsonrpc: "2.0", - method: "eth_accounts", - params: null, - id: 0 - }]; - - TransactionHelper.rpcCall(requests, function(arg1, arg2) - { - modelAccounts.clear(); - var ids = JSON.parse(arg2)[0].result; - requests = []; - for (var k in ids) - { - modelAccounts.append({ "id": ids[k] }) - requests.push({ - //accounts - jsonrpc: "2.0", - method: "eth_getBalance", - params: [ids[k], 'latest'], - id: k - }); - } - - if (ids.length > 0) - currentAccount = modelAccounts.get(0).id; - - TransactionHelper.rpcCall(requests, function (request, response){ - var balanceRet = JSON.parse(response); - for (var k in balanceRet) - { - var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei); - comboAccounts.balances.push(ether.format()); - comboAccounts.weiBalances.push(balanceRet[k].result); - } - balance.text = comboAccounts.balances[0]; - }); - }); - - if (clientModel.gasCosts.length === 0) - { - errorDialog.text = qsTr("Please run the state one time before deploying in order to calculate gas requirement."); - errorDialog.open(); - } - else - { - NetworkDeploymentCode.gasPrice(function(price) { - gasPrice = price; - gasPriceInt.setValue(gasPrice); - ctrDeployCtrLabel.calculateContractDeployGas(); - ctrRegisterLabel.calculateRegisterGas(); - }); - } } - function stopForInputError(inError) + DeploymentWorker { - errorDialog.text = ""; - if (inError.length > 0) - { - errorDialog.text = qsTr("The length of a string cannot exceed 32 characters.\nPlease verify the following value(s):\n\n") - for (var k in inError) - errorDialog.text += inError[k] + "\n"; - errorDialog.open(); - return true; - } - return false; - } - - function pad(h) - { - // TODO move this to QHashType class - while (h.length < 64) - { - h = '0' + h; - } - return h; - } - - function waitForTrCountToIncrement(callBack) - { - poolLog.callBack = callBack; - poolLog.k = -1; - poolLog.elapsed = 0; - poolLog.start(); - } - - BigIntValue - { - id: gasPriceInt - } - - Timer - { - id: poolLog - property var callBack - property int k: -1 - property int elapsed - interval: 500 - running: false - repeat: true - onTriggered: { - elapsed += interval; - var requests = []; - var jsonRpcRequestId = 0; - requests.push({ - jsonrpc: "2.0", - method: "eth_getTransactionCount", - params: [ currentAccount, "pending" ], - id: jsonRpcRequestId++ - }); - TransactionHelper.rpcCall(requests, function (httpRequest, response){ - response = response.replace(/,0+/, ''); // ==> result:27,00000000 - var count = JSON.parse(response)[0].result - console.log("count " + count); - if (k < parseInt(count) && k > 0) - { - stop(); - callBack(1); - } - else if (elapsed > 25000) - { - stop(); - callBack(-1); - } - else - k = parseInt(JSON.parse(response)[0].result); - }) - } - } - - SourceSansProRegular - { - id: lightFont + id: worker } contentItem: Rectangle { color: appStyle.generic.layout.backgroundColor anchors.fill: parent - Column + ColumnLayout { spacing: 5 anchors.fill: parent anchors.margins: 10 - ColumnLayout + + RowLayout { - id: containerDeploy - Layout.fillWidth: true - Layout.preferredHeight: 500 - RowLayout + id: explanation + Layout.preferredWidth: parent.width - 50 + Layout.preferredHeight: 50 + Label { - Rectangle - { - Layout.preferredWidth: 357 - DefaultLabel - { - text: qsTr("Deployment") - font.family: lightFont.name - font.underline: true - anchors.centerIn: parent - } - } - - Button - { - action: displayHelpAction - iconSource: "qrc:/qml/img/help.png" - } - - Action { - id: displayHelpAction - tooltip: qsTr("Help") - onTriggered: { - Qt.openUrlExternally("https://github.com/ethereum/wiki/wiki/Mix:-The-DApp-IDE#deployment-to-network") - } - } - - Button - { - action: openFolderAction - iconSource: "qrc:/qml/img/openedfolder.png" - } - - Action { - id: openFolderAction - enabled: deploymentDialog.packageBase64 !== "" - tooltip: qsTr("Open Package Folder") - onTriggered: { - fileIo.openFileBrowser(projectModel.deploymentDir); - } - } - - Button - { - action: b64Action - iconSource: "qrc:/qml/img/b64.png" - } - - Action { - id: b64Action - enabled: deploymentDialog.packageBase64 !== "" - tooltip: qsTr("Copy Base64 conversion to ClipBoard") - onTriggered: { - clipboard.text = deploymentDialog.packageBase64; - } - } - - Button - { - action: exitAction - iconSource: "qrc:/qml/img/exit.png" - } - - Action { - id: exitAction - tooltip: qsTr("Exit") - onTriggered: { - close() - } - } + anchors.centerIn: parent + text: qsTr("Putting your dapp live is a multi step process. You can read more about it on the 'guide to uploading'.") } + } - GridLayout + RowLayout + { + ColumnLayout { - columns: 2 - width: parent.width - - DefaultLabel + Layout.preferredHeight: parent.height - 50 + Layout.preferredWidth: 200 + DeploymentDialogSteps { - text: qsTr("State:") + id: steps } + } - Rectangle + Connections + { + target: steps + property variant selected + onSelected: { - width: 300 - color: "transparent" - height: 25 - id: paramsRect - ComboBox + if (selected) + selected.visible = false + switch (step) { - id: statesList - textRole: "title" - model: projectModel.stateListModel - onCurrentIndexChanged : { - ctrDeployCtrLabel.calculateContractDeployGas(); - ctrRegisterLabel.calculateRegisterGas(); - } - } - } - - DefaultLabel - { - text: qsTr("Root Registrar address:") - visible: true //still use it for now in dev env. - } - - DefaultTextField - { - Layout.preferredWidth: 350 - id: registrarAddr - text: "c6d9d2cd449a754c494264e1809c50e34d64562b" - visible: true - } - - DefaultLabel - { - text: qsTr("Account used to deploy:") - } - - Rectangle - { - width: 300 - height: 25 - color: "transparent" - ComboBox { - id: comboAccounts - property var balances: [] - property var weiBalances: [] - onCurrentIndexChanged : { - if (modelAccounts.count > 0) - { - currentAccount = modelAccounts.get(currentIndex).id; - balance.text = balances[currentIndex]; - balanceInt.setValue(weiBalances[currentIndex]); - ctrDeployCtrLabel.calculateContractDeployGas(); - ctrRegisterLabel.calculateRegisterGas(); - } - } - model: ListModel { - id: modelAccounts - } + case "deploy": + { + selected = deployStep + break; } - - DefaultLabel + case "package": { - anchors.verticalCenter: parent.verticalCenter - anchors.left: comboAccounts.right - anchors.leftMargin: 20 - id: balance; + selected = packageStep + break; } - - BigIntValue + case "register": { - id: balanceInt + selected = registerStep + break; } + } + selected.show() } } - DefaultLabel + ColumnLayout { - text: qsTr("Amount of gas to use for contract deployment: ") - id: ctrDeployCtrLabel - function calculateContractDeployGas() + Layout.preferredHeight: parent.height - 50 + Layout.preferredWidth: parent.width - 200 + DeployContractStep { - var ether = QEtherHelper.createBigInt(NetworkDeploymentCode.gasUsed()); - var gasTotal = ether.multiply(gasPriceInt); - gasToUseInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); - gasToUseDeployInput.update(); + id: deployStep + visible: false + worker: worker } - } - Ether { - id: gasToUseInput - displayUnitSelection: false - displayFormattedValue: true - Layout.preferredWidth: 350 - } - - DefaultLabel - { - text: qsTr("Amount of gas to use for dapp registration: ") - id: ctrRegisterLabel - function calculateRegisterGas() + PackagingStep { - if (!modalDeploymentDialog.visible) - return; - appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text).join('/'); - NetworkDeploymentCode.checkPathCreationCost(function(pathCreationCost) - { - var ether = QEtherHelper.createBigInt(pathCreationCost); - var gasTotal = ether.multiply(gasPriceInt); - gasToUseDeployInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); - gasToUseDeployInput.update(); - }); + id: packageStep + visible: false + worker: worker } - } - - Ether { - id: gasToUseDeployInput - displayUnitSelection: false - displayFormattedValue: true - Layout.preferredWidth: 350 - } - DefaultLabel - { - text: qsTr("Ethereum Application URL: ") - } - - Rectangle - { - Layout.fillWidth: true - height: 25 - color: "transparent" - DefaultTextField + RegisteringStep { - width: 200 - id: applicationUrlEth - onTextChanged: { - ctrRegisterLabel.calculateRegisterGas(); - } - } - - DefaultLabel - { - id: appUrlFormatted - anchors.verticalCenter: parent.verticalCenter; - anchors.left: applicationUrlEth.right - font.italic: true - font.pointSize: appStyle.absoluteSize(-1) + id: registerStep + visible: false + worker: worker } } } - RowLayout - { - Layout.fillWidth: true - Rectangle - { - Layout.preferredWidth: 357 - color: "transparent" - } - - Button - { - id: deployButton - action: runAction - iconSource: "qrc:/qml/img/run.png" - } - - Action { - id: runAction - tooltip: qsTr("Deploy contract(s) and Package resources files.") - onTriggered: { - var inError = []; - var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); - for (var k in ethUrl) - { - if (ethUrl[k].length > 32) - inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); - } - if (!stopForInputError(inError)) - { - projectModel.deployedState = statesList.currentText; - if (contractRedeploy.checked) - deployWarningDialog.open(); - else - NetworkDeploymentCode.startDeployProject(false); - } - } - } - - CheckBox - { - anchors.left: deployButton.right - id: contractRedeploy - enabled: Object.keys(projectModel.deploymentAddresses).length > 0 - checked: Object.keys(projectModel.deploymentAddresses).length == 0 - text: qsTr("Deploy Contract(s)") - anchors.verticalCenter: parent.verticalCenter - } - } - Rectangle { - width: parent.width - height: 1 - color: "#5891d3" - } - - ColumnLayout - { - id: containerRegister Layout.fillWidth: true - Layout.preferredHeight: 500 - RowLayout - { - Layout.preferredHeight: 25 - Rectangle - { - Layout.preferredWidth: 356 - DefaultLabel - { - text: qsTr("Registration") - font.family: lightFont.name - font.underline: true - anchors.centerIn: parent - } - } - } - - GridLayout - { - columns: 2 - Layout.fillWidth: true - - DefaultLabel - { - Layout.preferredWidth: 355 - text: qsTr("Local package URL") - } - - DefaultTextField - { - Layout.preferredWidth: 350 - id: localPackageUrl - readOnly: true - } - - DefaultLabel - { - Layout.preferredWidth: 355 - text: qsTr("Web Application Resources URL: ") - } - - DefaultTextField - { - Layout.preferredWidth: 350 - id: applicationUrlHttp - enabled: rowRegister.isOkToRegister() - } - } - - RowLayout + Layout.preferredHeight: 30 + color: "transparent" + Button { - id: rowRegister - Layout.fillWidth: true - - Rectangle + text: qsTr("Cancel") + anchors.right: parent.right + anchors.rightMargin: 10 + onClicked: { - Layout.preferredWidth: 357 - color: "transparent" - } - - function isOkToRegister() - { - return Object.keys(projectModel.deploymentAddresses).length > 0 && deploymentDialog.packageHash !== ""; - } - - Button { - action: registerAction - iconSource: "qrc:/qml/img/note.png" - } - - BigIntValue - { - id: registerUrlHintGas - Component.onCompleted: - { - setValue(modalDeploymentDialog.urlHintSuggestUrlGas); - } - } - - Action { - id: registerAction - enabled: rowRegister.isOkToRegister() - tooltip: qsTr("Register hosted Web Application.") - onTriggered: { - if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") - { - deployDialog.title = text; - deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") - deployDialog.open(); - return; - } - var inError = []; - if (applicationUrlHttp.text.length > 32) - inError.push(qsTr(applicationUrlHttp.text)); - if (!stopForInputError(inError)) - NetworkDeploymentCode.registerToUrlHint(); - } + modalDeploymentDialog.close() } } } + } } diff --git a/mix/qml/DeploymentDialogSteps.qml b/mix/qml/DeploymentDialogSteps.qml new file mode 100644 index 000000000..4ba4d0382 --- /dev/null +++ b/mix/qml/DeploymentDialogSteps.qml @@ -0,0 +1,133 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 + +Rectangle { + anchors.fill: parent + color: "white" + property variant sel + signal selected(string step) + + function init() + { + menu.itemAt(0).select() + } + + function itemClicked(step) + { + selected(step) + } + + border.color: "#cccccc" + border.width: 1 + + Column + { + anchors.fill: parent + anchors.margins: 1 + Repeater + { + id: menu + model: [ + { + step: 1, + type:"deploy", + label: qsTr("Deploy contracts") + }, + { + step: 2, + type:"package", + label: qsTr("Package files") + }, + { + step: 3, + type:"register", + label: qsTr("Register Dapp") + } + ] + + Rectangle + { + height: 50 + width: parent.width + color: "white" + id: itemContainer + + function select() + { + if (sel !== undefined) + { + menu.itemAt(sel).unselect() + } + labelContainer.state = "selected" + sel = index + itemClicked(menu.model[index].type) + } + + function unselect() + { + labelContainer.state = "" + } + + Rectangle { + width: 40 + height: 40 + color: "transparent" + border.color: "#cccccc" + border.width: 2 + radius: width*0.5 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + id: labelContainer + Label + { + color: "#cccccc" + id: label + anchors.centerIn: parent + text: menu.model[index].step + } + states: [ + State { + name: "selected" + PropertyChanges { target: label; color: "white" } + PropertyChanges { target: labelContainer.border; color: "white" } + PropertyChanges { target: detail; color: "white" } + PropertyChanges { target: itemContainer; color: "#3395FE" } + } + ] + } + + Rectangle + { + anchors.verticalCenter: parent.verticalCenter + anchors.left: label.parent.right + width: parent.width - 40 + height: 40 + color: "transparent" + Label + { + id: detail + color: "black" + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + text: menu.model[index].label + } + } + + MouseArea + { + anchors.fill: parent + onClicked: + { + itemContainer.select() + } + } + } + } + + } +} + diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml new file mode 100644 index 000000000..054d5a90c --- /dev/null +++ b/mix/qml/DeploymentWorker.qml @@ -0,0 +1,176 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 +import org.ethereum.qml.QEther 1.0 +import org.ethereum.qml.CodeModel 1.0 +import org.ethereum.qml.ClientModel 1.0 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper +import "." + +Item +{ + property string currentAccount + property string gasPrice + property alias gasPriceInt: gasPriceInt + property variant balances: ({}) + property variant accounts: [] + signal gasPriceLoaded() + + function renewCtx() + { + var requests = [{ + //accounts + jsonrpc: "2.0", + method: "eth_accounts", + params: null, + id: 0 + }]; + + TransactionHelper.rpcCall(requests, function(arg1, arg2) + { + accounts = [] + var ids = JSON.parse(arg2)[0].result; + requests = []; + for (var k in ids) + { + requests.push({ + //accounts + jsonrpc: "2.0", + method: "eth_getBalance", + params: [ids[k], 'latest'], + id: k + }); + accounts.push({ "id": ids[k] }) + } + + TransactionHelper.rpcCall(requests, function (request, response){ + var balanceRet = JSON.parse(response); + for (var k in balanceRet) + { + var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei); + balances[accounts[k]] = ether + } + }, function(){}); + }, function(){}); + + NetworkDeploymentCode.gasPrice(function(price) { + gasPrice = price; + gasPriceInt.setValue(price); + console.log("fjdsfkjds hfkdsf " + price) + gasPriceLoaded() + }, function(){}); + } + + function stopForInputError(inError) + { + errorDialog.text = ""; + if (inError.length > 0) + { + errorDialog.text = qsTr("The length of a string cannot exceed 32 characters.\nPlease verify the following value(s):\n\n") + for (var k in inError) + errorDialog.text += inError[k] + "\n"; + errorDialog.open(); + return true; + } + return false; + } + + function waitForTrCountToIncrement(callBack) + { + poolLog.callBack = callBack; + poolLog.k = -1; + poolLog.elapsed = 0; + poolLog.start(); + } + + Component.onCompleted: + { + renewCtx() + } + + BigIntValue + { + id: gasPriceInt + } + + function estimateGas(scenario, callback) + { + if (!clientModelGasEstimation.running) + { + var ctr = projectModel.codeEditor.getContracts() + for (var k in ctr) + { + codeModelGasEstimation.registerCodeChange(ctr[k].document.documentId, ctr[k].getText()); + } + gasEstimationConnect.callback = callback + clientModelGasEstimation.setupScenario(scenario) + } + } + + Connections + { + id: gasEstimationConnect + target: clientModelGasEstimation + property var callback + onRunComplete: { + callback(clientModelGasEstimation.gasCosts) + } + } + + CodeModel { + id: codeModelGasEstimation + } + + ClientModel { + id: clientModelGasEstimation + codeModel: codeModelGasEstimation + Component.onCompleted: + { + init("/tmp/bcgas/") + } + } + + Timer + { + id: poolLog + property var callBack + property int k: -1 + property int elapsed + interval: 500 + running: false + repeat: true + onTriggered: { + elapsed += interval; + var requests = []; + var jsonRpcRequestId = 0; + requests.push({ + jsonrpc: "2.0", + method: "eth_getTransactionCount", + params: [ currentAccount, "pending" ], + id: jsonRpcRequestId++ + }); + TransactionHelper.rpcCall(requests, function (httpRequest, response){ + response = response.replace(/,0+/, ''); // ==> result:27,00000000 + var count = JSON.parse(response)[0].result + if (k < parseInt(count) && k > 0) + { + stop(); + callBack(1); + } + else if (elapsed > 25000) + { + stop(); + callBack(-1); + } + else + k = parseInt(JSON.parse(response)[0].result); + }) + } + } +} + diff --git a/mix/qml/Ether.qml b/mix/qml/Ether.qml index 29323642a..593a54a3a 100644 --- a/mix/qml/Ether.qml +++ b/mix/qml/Ether.qml @@ -18,6 +18,8 @@ RowLayout { property bool displayUnitSelection onValueChanged: update() Component.onCompleted: update() + signal amountChanged + signal unitChanged function update() @@ -37,16 +39,17 @@ RowLayout { DefaultTextField { - implicitWidth: 200 onTextChanged: { if (value !== undefined) { value.setValue(text) formattedValue.text = value.format(); + amountChanged() } } readOnly: !edit + visible: edit id: etherValueEdit; } @@ -54,13 +57,13 @@ RowLayout { { id: units visible: displayUnitSelection; - implicitWidth: 145 onCurrentTextChanged: { if (value) { value.setUnit(currentText); formattedValue.text = value.format(); + unitChanged() } } diff --git a/mix/qml/PackagingStep.qml b/mix/qml/PackagingStep.qml new file mode 100644 index 000000000..24453a24b --- /dev/null +++ b/mix/qml/PackagingStep.qml @@ -0,0 +1,192 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Dialogs 1.1 +import Qt.labs.settings 1.0 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper + +Rectangle { + property variant paramsModel: [] + property variant worker + color: "#E3E3E3E3" + anchors.fill: parent + + property string packageHash + property string packageBase64 + property alias localPackageUrl: localPackageUrl.text + property string deploymentId + property string packageDir + + Settings { + property alias localUrl: localPackageUrl.text + } + + + function show() + { + visible = true + } + + FileDialog { + id: ressourcesFolder + visible: false + title: qsTr("Please choose a path") + selectFolder: true + property variant target + onAccepted: { + var u = ressourcesFolder.fileUrl.toString(); + if (u.indexOf("file://") == 0) + u = u.substring(7, u.length) + if (Qt.platform.os == "windows" && u.indexOf("/") == 0) + u = u.substring(1, u.length); + target.text = u; + } + } + + ColumnLayout + { + anchors.top: parent.top + anchors.topMargin: 10 + width: parent.width + + id: col + spacing: 20 + + Label + { + anchors.top: parent.top + Layout.fillWidth: true + anchors.left: parent.left + anchors.leftMargin: 10 + text: qsTr("Upload and update your Dapp assets") + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Save Package to") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: packageFolder + visible: true + Layout.preferredWidth: 150 + text: projectPath + "package/" + } + + Button + { + text: qsTr("select") + onClicked: { + ressourcesFolder.target = packageFolder + ressourcesFolder.open() + } + } + } + + Rectangle + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + color: "transparent" + Button + { + Layout.preferredWidth: 200 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Generate Package") + onClicked: + { + NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses) + } + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Local package URL") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: localPackageUrl + Layout.preferredWidth: 235 + readOnly: true + } + } + + Label + { + Layout.preferredWidth: 300 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("You have to upload the package to a remote folder, or use a service like pastebin") + wrapMode: Text.WordWrap + clip: true + } + + Rectangle + { + color: "transparent" + Layout.fillWidth: true + Layout.preferredHeight: 20 + Button + { + Layout.preferredWidth: 200 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Copy Base64") + onClicked: + { + clipboard.text = deploymentDialog.packageStep.packageBase64; + } + } + } + + Rectangle + { + color: "transparent" + Layout.fillWidth: true + Layout.preferredHeight: 20 + Button + { + Layout.preferredWidth: 200 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Open pastebin") + onClicked: + { + Qt.openUrlExternally("http://pastebin.com/"); + } + } + } + } +} + + + + + + + + + diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 0bf7c0fb2..9c9734289 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -40,7 +40,7 @@ Item { property string projectPath: "" property string projectTitle: "" property string currentDocumentId: "" - property var deploymentAddresses: [] + property var deploymentAddresses: ({}) property string deploymentDir property var listModel: projectListModel property var stateListModel: projectStateListModel.model @@ -48,7 +48,7 @@ Item { property CodeEditorView codeEditor: null property var unsavedFiles: [] property alias newProjectDialog: newProjectDialog - property string deployedState + property int deployedScenarioIndex //interface function saveAll() { ProjectModelCode.saveAll(); } diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml new file mode 100644 index 000000000..79ea17d0d --- /dev/null +++ b/mix/qml/RegisteringStep.qml @@ -0,0 +1,230 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import org.ethereum.qml.QEther 1.0 +import Qt.labs.settings 1.0 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper +import "." + +Rectangle { + property variant worker + property alias applicationUrlEth: applicationUrlEth.text + property alias applicationUrlHttp: applicationUrlHttp.text + property string eth: registrarAddr.text + property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr. + property int ownedRegistrarSetSubRegistrarGas: 50000 + property int ownedRegistrarSetContentHashGas: 50000 + property int urlHintSuggestUrlGas: 70000 + + color: "#E3E3E3E3" + anchors.fill: parent + + function show() + { + ctrRegisterLabel.calculateRegisterGas() + visible = true + } + + Settings + { + id: settings + property alias ethUrl: applicationUrlEth.text + property string httpUrl: applicationUrlHttp.text + } + + ColumnLayout + { + anchors.top: parent.top + width: parent.width + anchors.topMargin: 10 + id: col + spacing: 20 + Label + { + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: 10 + Layout.fillWidth: true + text: qsTr("Register your Dapp on the Name registrar Contract") + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Root Registrar address") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: registrarAddr + text: "bb9af5b8f19fb2bc1765ca36e697fa30e3386b71" //"c6d9d2cd449a754c494264e1809c50e34d64562b" + visible: true + Layout.preferredWidth: 235 + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Web Application Resources URL") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: applicationUrlHttp + enabled: rowRegister.isOkToRegister() + Layout.preferredWidth: 235 + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Gas to use for dapp registration") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + id: ctrRegisterLabel + function calculateRegisterGas() + { + if (!modalDeploymentDialog.visible) + return; + appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text).join('/'); + NetworkDeploymentCode.checkPathCreationCost(function(pathCreationCost) + { + var ether = QEtherHelper.createBigInt(pathCreationCost); + var gasTotal = ether.multiply(worker.gasPriceInt); + gasToUseDeployInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); + gasToUseDeployInput.update(); + }); + } + } + } + + Ether + { + id: gasToUseDeployInput + displayUnitSelection: true + displayFormattedValue: true + edit: true + Layout.preferredWidth: 235 + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Ethereum Application URL") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Rectangle + { + height: 25 + color: "transparent" + Layout.preferredWidth: 235 + DefaultTextField + { + width: 235 + id: applicationUrlEth + onTextChanged: { + ctrRegisterLabel.calculateRegisterGas(); + } + } + + DefaultLabel + { + id: appUrlFormatted + anchors.verticalCenter: parent.verticalCenter; + anchors.top: applicationUrlEth.bottom + anchors.topMargin: 10 + font.italic: true + font.pointSize: appStyle.absoluteSize(-1) + } + } + } + + + } + + RowLayout + { + anchors.bottom: parent.bottom + width: parent.width + anchors.bottomMargin: 8 + Button + { + anchors.right: parent.right + anchors.rightMargin: 10 + text: qsTr("Register Dapp") + width: 30 + onClicked: + { + var inError = []; + var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); + for (var k in ethUrl) + { + if (ethUrl[k].length > 32) + inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); + } + if (!worker.stopForInputError(inError)) + { + NetworkDeploymentCode.registerDapp(function(){ + applicationUrlEth.text = ethUrl + if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") + { + deployDialog.title = text; + deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") + deployDialog.open(); + return; + } + var inError = []; + if (applicationUrlHttp.text.length > 32) + inError.push(qsTr(applicationUrlHttp.text)); + if (!worker.stopForInputError(inError)) + { + /*registerToUrlHint(function(){ + settings.httpUrl = applicationUrlHttp.text + })*/ + } + }) + } + } + } + } +} + diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 4edc601de..9960afca7 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -125,9 +125,9 @@ Dialog { function loadParameters() { paramsModel = [] if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var contract = codeModel.contracts[contractFromToken(contractCreationComboBox.currentValue())]; + var contract = codeModel.contracts[TransactionHelper.contractFromToken(contractCreationComboBox.currentValue())]; if (contract) { - var func = contract.contract.functions[functionComboBox.currentIndex + 1]; + var func = contract.contract.functions[functionComboBox.currentIndex /*+ 1*/]; if (func) { var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) @@ -188,7 +188,7 @@ Dialog { if (!item.isContractCreation) { item.contractId = recipientsAccount.currentValue(); - item.label = contractFromToken(item.contractId) + "." + item.functionId + "()"; + item.label = TransactionHelper.contractFromToken(item.contractId) + "." + item.functionId + "()"; if (recipientsAccount.current().type === "address") { item.functionId = ""; @@ -205,14 +205,7 @@ Dialog { item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.parameters = paramValues; return item; - } - - function contractFromToken(token) - { - if (token.indexOf('<') === 0) - return token.replace("<", "").replace(">", "").split(" - ")[0]; - return token; - } + } function load(isContractCreation, isFunctionCall, functionId, contractId) { @@ -236,7 +229,7 @@ Dialog { { labelRecipient.text = qsTr("Recipient Contract") functionRect.show() - loadFunctions(contractFromToken(recipientsAccount.currentValue())) + loadFunctions(TransactionHelper.contractFromToken(recipientsAccount.currentValue())) loadParameters(); paramScroll.updateView() } @@ -416,7 +409,7 @@ Dialog { onIndexChanged: { if (rbbuttonList.current.objectName === "trTypeExecute") - loadFunctions(contractFromToken(currentValue())) + loadFunctions(TransactionHelper.contractFromToken(currentValue())) } } @@ -587,7 +580,7 @@ Dialog { target: functionComboBox onCurrentIndexChanged: { - estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + estimatedGas.displayGas(TransactionHelper.contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) } } @@ -604,7 +597,7 @@ Dialog { function updateView() { if (rbbuttonList.current.objectName === "trTypeExecute") - estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + estimatedGas.displayGas(TransactionHelper.contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) else if (rbbuttonList.current.objectName === "trTypeCreate") { var contractName = contractCreationComboBox.currentValue() diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index 94d83460f..24be9eb3e 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -32,38 +32,30 @@ function deployProject(force) { deploymentDialog.open(); } -function startDeployProject(erasePrevious) -{ - var date = new Date(); - var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); - if (!erasePrevious) - { - finalizeDeployment(deploymentId, projectModel.deploymentAddresses); - return; - } - +function deployContracts() +{ var jsonRpcUrl = "http://127.0.0.1:8080"; - console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); + console.log("Deploying to " + jsonRpcUrl); deploymentStarted(); var ctrAddresses = {}; - var state = retrieveState(projectModel.deployedState); - console.log(JSON.stringify(state)); + var state = retrieveState(projectModel.deployedScenarioIndex); if (!state) { - var txt = qsTr("Unable to find state " + projectModel.deployedState); + var txt = qsTr("Unable to find this scenario"); deploymentError(txt); console.log(txt); return; } - executeTr(0, state, ctrAddresses, function (){ - finalizeDeployment(deploymentId, ctrAddresses); + executeTr(0, 0, state, ctrAddresses, function(){ + projectModel.deploymentAddresses = ctrAddresses; + deploymentStepChanged(qsTr("Scenario deployed. Please wait for verifications")) }); } function checkPathCreationCost(callBack) { - var dappUrl = formatAppUrl(deploymentDialog.applicationUrlEth); + var dappUrl = formatAppUrl(deploymentDialog.registerStep.applicationUrlEth); checkEthPath(dappUrl, true, function(success, cause) { if (!success) { @@ -85,7 +77,7 @@ function checkPathCreationCost(callBack) else { deploymentStepChanged(qsTr("Your Dapp can be registered here.")); - callBack((dappUrl.length - 1) * (deploymentDialog.ownedRegistrarDeployGas + deploymentDialog.ownedRegistrarSetSubRegistrarGas) + deploymentDialog.ownedRegistrarSetContentHashGas); + callBack((dappUrl.length - 1) * (deploymentDialog.registerStep.ownedRegistrarDeployGas + deploymentDialog.registerStep.ownedRegistrarSetSubRegistrarGas) + deploymentDialog.registerStep.ownedRegistrarSetContentHashGas); } }); } @@ -97,19 +89,13 @@ function gasUsed() for (var g in gasCosts) { gas += gasCosts[g]; - console.log(" gasCost " + gasCosts[g]); } return gas; } -function retrieveState(state) +function retrieveState(stateIndex) { - for (var k = 0; k < projectModel.stateListModel.count; k++) - { - if (projectModel.stateListModel.get(k).title === state) - return projectModel.stateListModel.get(k); - } - return null; + return projectModel.stateListModel.get(stateIndex); } function replaceParamToken(paramsDef, params, ctrAddresses) @@ -134,6 +120,7 @@ function replaceParamToken(paramsDef, params, ctrAddresses) function getFunction(ctrName, functionId) { + ctrName = contractFromToken(ctrName) if (codeModel.contracts[ctrName] === undefined) return null; if (ctrName === functionId) @@ -148,20 +135,21 @@ function getFunction(ctrName, functionId) } } -function executeTr(trIndex, state, ctrAddresses, callBack) +function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) { - var tr = state.transactions.get(trIndex); + var tr = state.blocks.get(blockIndex).transactions.get(trIndex); var func = getFunction(tr.contractId, tr.functionId); + console.log(func + " " + tr.contractId + " " + tr.functionId + " ") if (!func) - executeTrNextStep(trIndex, state, ctrAddresses, callBack); + executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack); else { var gasCost = clientModel.toHex(clientModel.gasCosts[trIndex]); - var rpcParams = { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost }; + var rpcParams = { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost }; var params = replaceParamToken(func.parameters, tr.parameters, ctrAddresses); - var encodedParams = clientModel.encodeParams(params, tr.contractId, tr.functionId); + var encodedParams = clientModel.encodeParams(params, contractFromToken(tr.contractId), tr.functionId); - if (state.contractId === state.functionId) + if (tr.contractId === tr.functionId) rpcParams.code = codeModel.contracts[tr.contractId].codeHex + encodedParams.join(""); else rpcParams.data = func.hash + encodedParams.join(""); @@ -182,23 +170,34 @@ function executeTr(trIndex, state, ctrAddresses, callBack) ctrAddresses[tr.contractId] = JSON.parse(response)[0].result ctrAddresses[tr.contractId + " - " + trIndex] = JSON.parse(response)[0].result //get right ctr address if deploy more than one contract of same type. } - deploymentDialog.waitForTrCountToIncrement(function(status) { + deploymentDialog.worker.waitForTrCountToIncrement(function(status) { + console.log("deploy contract?" + status) if (status === -1) trCountIncrementTimeOut(); else - executeTrNextStep(trIndex, state, ctrAddresses, callBack) + executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) }); }); } } -function executeTrNextStep(trIndex, state, ctrAddresses, callBack) +function executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) { trIndex++; - if (trIndex < state.transactions.count) - executeTr(trIndex, state, ctrAddresses, callBack); + if (trIndex < state.blocks.get(blockIndex).transactions.count) + executeTr(blockIndex, trIndex, state, ctrAddresses, callBack); else - callBack(); + { + blockIndex++ + if (blockIndex < state.blocks.count) + { + executeTr(blockIndex, 0, state, ctrAddresses, callBack); + } + else + { + callBack(); + } + } } function gasPrice(callBack, error) @@ -216,7 +215,12 @@ function gasPrice(callBack, error) }); } -function finalizeDeployment(deploymentId, addresses) { +function packageDapp(addresses) +{ + var date = new Date(); + var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); + deploymentDialog.packageStep.deploymentId = deploymentId + deploymentStepChanged(qsTr("Packaging application ...")); var deploymentDir = projectPath + deploymentId + "/"; projectModel.deploymentDir = deploymentDir; @@ -259,21 +263,32 @@ function finalizeDeployment(deploymentId, addresses) { deploymentAddresses = addresses; saveProject(); - var packageRet = fileIo.makePackage(deploymentDir); - deploymentDialog.packageHash = packageRet[0]; - deploymentDialog.packageBase64 = packageRet[1]; - deploymentDialog.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; + if (deploymentDialog.packageStep.packageDir !== "") + deploymentDir = deploymentDialog.packageStep.packageDir + else + { + deploymentDir = projectPath + "package/" + fileIo.makeDir(deploymentDir); + } - var applicationUrlEth = deploymentDialog.applicationUrlEth; + var packageRet = fileIo.makePackage(deploymentDir); + deploymentDialog.packageStep.packageHash = packageRet[0]; + deploymentDialog.packageStep.packageBase64 = packageRet[1]; + deploymentDialog.packageStep.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; + deploymentComplete() +} +function registerDapp(callback) +{ + var applicationUrlEth = deploymentDialog.registerStep.applicationUrlEth; applicationUrlEth = formatAppUrl(applicationUrlEth); deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); checkEthPath(applicationUrlEth, false, function (success) { if (!success) return; deploymentComplete(); - deployResourcesDialog.text = qsTr("Register Web Application to finalize deployment."); - deployResourcesDialog.open(); + if (callback) + callback() }); } @@ -283,8 +298,8 @@ function checkEthPath(dappUrl, checkOnly, callBack) { // convenient for dev purpose, should not be possible in normal env. if (!checkOnly) - reserve(deploymentDialog.eth, function() { - registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar. + reserve(deploymentDialog.registerStep.eth, function() { + registerContentHash(deploymentDialog.registerStep.eth, callBack); // we directly create a dapp under the root registrar. }); else callBack(true); @@ -298,7 +313,7 @@ function checkEthPath(dappUrl, checkOnly, callBack) //subRegistrar() jsonrpc: "2.0", method: "eth_call", - params: [ { "gas": "0xffff", "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0xe1fa8e84" + str }, "pending" ], + params: [ { "gas": "0xffff", "from": deploymentDialog.worker.currentAccount, "to": '0x' + deploymentDialog.registerStep.eth, "data": "0xe1fa8e84" + str }, "pending" ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { @@ -327,12 +342,12 @@ function isOwner(addr, callBack) //getOwner() jsonrpc: "2.0", method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0xb387ef92" }, "pending" ], + params: [ { "from": deploymentDialog.worker.currentAccount, "to": '0x' + addr, "data": "0xb387ef92" }, "pending" ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { var res = JSON.parse(response); - callBack(normalizeAddress(deploymentDialog.currentAccount) === normalizeAddress(res[0].result)); + callBack(normalizeAddress(deploymentDialog.worker.currentAccount) === normalizeAddress(res[0].result)); }); } @@ -374,7 +389,7 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly) //register() jsonrpc: "2.0", method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x5a3a05bd" + str }, "pending" ], + params: [ { "from": deploymentDialog.worker.currentAccount, "to": '0x' + addr, "data": "0x5a3a05bd" + str }, "pending" ], id: jsonRpcRequestId++ }); @@ -406,11 +421,11 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly) deploymentStepChanged(txt); //current registrar is owned => ownedregistrar creation and continue. requests = []; - var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarDeployGas); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarDeployGas); requests.push({ jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "code": "0x600080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331781556105cd90819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100b257806321f8a721146100e45780632dff6941146100ee5780633b3b57de1461010e5780635a3a05bd1461013e5780635fd4b08a146101715780637dd564111461017d57806389a69c0e14610187578063b387ef92146101bb578063b5c645bd146101f4578063be99a98014610270578063c3d014d6146102a8578063d93e7573146102dc57005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000808052602081f35b60005461030c9060043590602435903373ffffffffffffffffffffffffffffffffffffffff908116911614610569576105c9565b60005473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b600054610312906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff90811691161461045457610523565b6000546103189060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052857610565565b60005461031e90600435903373ffffffffffffffffffffffffffffffffffffffff90811691161461032457610451565b60006000f35b60006000f35b60006000f35b60006000f35b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610361576103e1565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b600083815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001683179055806104bb57827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a2610522565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "code": "0x600080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331781556105cd90819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100b257806321f8a721146100e45780632dff6941146100ee5780633b3b57de1461010e5780635a3a05bd1461013e5780635fd4b08a146101715780637dd564111461017d57806389a69c0e14610187578063b387ef92146101bb578063b5c645bd146101f4578063be99a98014610270578063c3d014d6146102a8578063d93e7573146102dc57005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000808052602081f35b60005461030c9060043590602435903373ffffffffffffffffffffffffffffffffffffffff908116911614610569576105c9565b60005473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b600054610312906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff90811691161461045457610523565b6000546103189060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052857610565565b60005461031e90600435903373ffffffffffffffffffffffffffffffffffffffff90811691161461032457610451565b60006000f35b60006000f35b60006000f35b60006000f35b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610361576103e1565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b600083815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001683179055806104bb57827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a2610522565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ], id: jsonRpcRequestId++ }); @@ -420,19 +435,19 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly) var txt = qsTr("Please wait " + dappUrl[0] + " is registering ..."); deploymentStepChanged(txt); console.log(txt); - deploymentDialog.waitForTrCountToIncrement(function(status) { + deploymentDialog.worker.waitForTrCountToIncrement(function(status) { if (status === -1) { trCountIncrementTimeOut(); return; } var crLevel = clientModel.encodeStringParam(dappUrl[0]); - var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarSetSubRegistrarGas); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarSetSubRegistrarGas); requests.push({ //setRegister() jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + deploymentDialog.pad(newCtrAddress) } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + newCtrAddress } ], id: jsonRpcRequestId++ }); @@ -465,7 +480,7 @@ function reserve(registrar, callBack) //reserve() jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0xfffff", "to": '0x' + registrar, "data": "0x432ced04" + paramTitle } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0xfffff", "to": '0x' + registrar, "data": "0x432ced04" + paramTitle } ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { @@ -481,12 +496,12 @@ function registerContentHash(registrar, callBack) console.log(txt); var requests = []; var paramTitle = clientModel.encodeStringParam(projectModel.projectTitle); - var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarSetContentHashGas); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarSetContentHashGas); requests.push({ //setContent() jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageHash } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageStep.packageHash } ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { @@ -494,24 +509,26 @@ function registerContentHash(registrar, callBack) }); } -function registerToUrlHint() +function registerToUrlHint(callback) { - deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ..."); + deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.registerStep.applicationUrlHttp) + ") ..."); urlHintAddress(function(urlHint){ var requests = []; - var paramUrlHttp = clientModel.encodeStringParam(deploymentDialog.applicationUrlHttp); - var gasCost = clientModel.toHex(deploymentDialog.urlHintSuggestUrlGas); + var paramUrlHttp = clientModel.encodeStringParam(deploymentDialog.registerStep.applicationUrlHttp); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.urlHintSuggestUrlGas); requests.push({ //urlHint => suggestUrl jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "to": '0x' + urlHint, "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "data": "0x584e86ad" + deploymentDialog.packageHash + paramUrlHttp } ], + params: [ { "to": '0x' + urlHint, "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "data": "0x584e86ad" + deploymentDialog.packageStep.packageHash + paramUrlHttp } ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { deploymentComplete(); + if (callback) + callback() }); }); } @@ -524,7 +541,7 @@ function urlHintAddress(callBack) //registrar: get UrlHint addr jsonrpc: "2.0", method: "eth_call", - params: [ { "to": '0x' + deploymentDialog.eth, "from": deploymentDialog.currentAccount, "data": "0x3b3b57de" + urlHint }, "pending" ], + params: [ { "to": '0x' + deploymentDialog.registerStep.eth, "from": deploymentDialog.worker.currentAccount, "data": "0x3b3b57de" + urlHint }, "pending" ], id: jsonRpcRequestId++ }); diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index b3afabd3d..a3f6372e0 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -107,13 +107,13 @@ function loadProject(path) { if (projectData.deploymentDir) projectModel.deploymentDir = projectData.deploymentDir if (projectData.packageHash) - deploymentDialog.packageHash = projectData.packageHash + deploymentDialog.packageStep.packageHash = projectData.packageHash if (projectData.packageBase64) - deploymentDialog.packageBase64 = projectData.packageBase64 + deploymentDialog.packageStep.packageBase64 = projectData.packageBase64 if (projectData.applicationUrlEth) - deploymentDialog.applicationUrlEth = projectData.applicationUrlEth + deploymentDialog.registerStep.applicationUrlEth = projectData.applicationUrlEth if (projectData.applicationUrlHttp) - deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp + deploymentDialog.registerStep.applicationUrlHttp = projectData.applicationUrlHttp if (!projectData.title) { var parts = path.split("/"); projectData.title = parts[parts.length - 2]; diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index ea91a40d7..33dadab9d 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -45,3 +45,10 @@ function rpcCall(requests, callBack, error) httpRequest.send(rpcRequest); } +function contractFromToken(token) +{ + if (token.indexOf('<') === 0) + return token.replace("<", "").replace(">", "").split(" - ")[0]; + return token; +} +