Browse Source

deploy dialog

cl-refactor
yann300 9 years ago
parent
commit
ae07c6a11a
  1. 73
      mix/ClientModel.cpp
  2. 8
      mix/ClientModel.h
  3. 35
      mix/MixClient.cpp
  4. 2
      mix/MixClient.h
  5. 5
      mix/qml.qrc
  6. 5
      mix/qml/Application.qml
  7. 13
      mix/qml/CodeEditorView.qml
  8. 352
      mix/qml/DeployContractStep.qml
  9. 584
      mix/qml/DeploymentDialog.qml
  10. 133
      mix/qml/DeploymentDialogSteps.qml
  11. 176
      mix/qml/DeploymentWorker.qml
  12. 7
      mix/qml/Ether.qml
  13. 192
      mix/qml/PackagingStep.qml
  14. 4
      mix/qml/ProjectModel.qml
  15. 230
      mix/qml/RegisteringStep.qml
  16. 23
      mix/qml/TransactionDialog.qml
  17. 149
      mix/qml/js/NetworkDeployment.js
  18. 8
      mix/qml/js/ProjectModel.js
  19. 7
      mix/qml/js/TransactionHelper.js

73
mix/ClientModel.cpp

@ -81,13 +81,7 @@ ClientModel::ClientModel():
qRegisterMetaType<QInstruction*>("QInstruction");
qRegisterMetaType<QCode*>("QCode");
qRegisterMetaType<QCallData*>("QCallData");
qRegisterMetaType<RecordLogEntry*>("RecordLogEntry*");
m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString()));
m_ethAccounts = make_shared<FixedAccountHolder>([=](){return m_client.get();}, std::vector<KeyPair>());
m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector<KeyPair>(), m_client.get()));
connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection);
qRegisterMetaType<RecordLogEntry*>("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<FixedAccountHolder>([=](){return m_client.get();}, std::vector<KeyPair>());
m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector<KeyPair>(), 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<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue());
else
gasAuto = true;
u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
u256 gasPrice = (qvariant_cast<QEther*>(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<TransactionSettings> 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<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue());
else
gasAuto = true;
u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
u256 gasPrice = (qvariant_cast<QEther*>(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);

8
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<bool> m_running;
std::atomic<bool> m_mining;
@ -284,6 +289,7 @@ private:
CodeModel* m_codeModel = nullptr;
QList<QVariantList> m_queueTransactions;
mutable boost::shared_mutex x_queueTransactions;
QString m_dbpath;
};
}

35
mix/MixClient.cpp

@ -79,7 +79,6 @@ MixClient::~MixClient()
void MixClient::resetState(std::unordered_map<Address, Account> 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<MachineState> machineStates;
std::vector<unsigned> levels;
std::vector<MachineCode> 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;

2
mix/MixClient.h

@ -61,7 +61,7 @@ public:
virtual std::pair<h256, Address> submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret) override { return submitTransaction(_ts, _secret, false); }
std::pair<h256, Address> 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;

5
mix/qml.qrc

@ -71,5 +71,10 @@
<file>qml/ScenarioButton.qml</file>
<file>qml/Watchers.qml</file>
<file>qml/KeyValuePanel.qml</file>
<file>qml/DeployContractStep.qml</file>
<file>qml/RegisteringStep.qml</file>
<file>qml/DeploymentDialogSteps.qml</file>
<file>qml/PackagingStep.qml</file>
<file>qml/DeploymentWorker.qml</file>
</qresource>
</RCC>

5
mix/qml/Application.qml

@ -42,6 +42,11 @@ ApplicationWindow {
ClientModel {
id: clientModel
codeModel: codeModel
Component.onCompleted:
{
console.log("tmp")
init("/tmp")
}
}
ProjectModel {

13
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 &&

352
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();
}
}
}
}
}
}

584
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()
}
}
}
}
}

133
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()
}
}
}
}
}
}

176
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);
})
}
}
}

7
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()
}
}

192
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/");
}
}
}
}
}

4
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(); }

230
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
})*/
}
})
}
}
}
}
}

23
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()

149
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++
});

8
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];

7
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;
}

Loading…
Cancel
Save