Arkadiy Paronyan
10 years ago
30 changed files with 2139 additions and 825 deletions
@ -0,0 +1,488 @@ |
|||
import QtQuick 2.0 |
|||
import QtQuick.Layouts 1.0 |
|||
import QtQuick.Controls 1.1 |
|||
import QtQuick.Controls.Styles 1.3 |
|||
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 org.ethereum.qml.QEther 1.0 |
|||
|
|||
Rectangle { |
|||
property variant paramsModel: [] |
|||
property variant worker |
|||
property variant gas: [] |
|||
color: "#E3E3E3E3" |
|||
anchors.fill: parent |
|||
id: root |
|||
|
|||
property int labelWidth: 150 |
|||
|
|||
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 |
|||
|
|||
if (projectModel.deployBlockNumber !== -1) |
|||
{ |
|||
worker.verifyHashes(projectModel.deploymentTrHashes, function (bn, trLost) |
|||
{ |
|||
root.updateVerification(bn, trLost) |
|||
}); |
|||
} |
|||
deployedAddresses.refresh() |
|||
worker.renewCtx() |
|||
} |
|||
|
|||
function updateVerification(blockNumber, trLost) |
|||
{ |
|||
verificationLabel.text = blockNumber - projectModel.deployBlockNumber |
|||
if (trLost.length > 0) |
|||
{ |
|||
verificationLabel.text += "\n" + qsTr("Transactions lost") + "\n" |
|||
for (var k in trLost) |
|||
{ |
|||
verificationLabel.text += trLost[k] + "\n" |
|||
} |
|||
} |
|||
} |
|||
|
|||
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: |
|||
{ |
|||
if (root.visible) |
|||
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 |
|||
spacing: 8 |
|||
|
|||
Label |
|||
{ |
|||
anchors.left: parent.left |
|||
anchors.leftMargin: 105 |
|||
text: qsTr("Deployment options") |
|||
} |
|||
|
|||
ListModel |
|||
{ |
|||
id: accountsModel |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
Layout.fillWidth: true |
|||
Rectangle |
|||
{ |
|||
width: labelWidth |
|||
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 |
|||
accountBalance.text = worker.balance(currentText).format() |
|||
console.log(worker.balance(currentText).format()) |
|||
} |
|||
} |
|||
|
|||
Label |
|||
{ |
|||
id: accountBalance |
|||
} |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
Layout.fillWidth: true |
|||
Rectangle |
|||
{ |
|||
width: labelWidth |
|||
Label |
|||
{ |
|||
text: qsTr("Gas Price") |
|||
anchors.right: parent.right |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
} |
|||
} |
|||
|
|||
Ether |
|||
{ |
|||
id: gasPriceInput |
|||
displayUnitSelection: true |
|||
displayFormattedValue: true |
|||
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) |
|||
{ |
|||
root.gas = gas |
|||
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: labelWidth |
|||
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 |
|||
} |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
id: deployedRow |
|||
Layout.fillWidth: true |
|||
Rectangle |
|||
{ |
|||
width: labelWidth |
|||
Label |
|||
{ |
|||
id: labelAddresses |
|||
text: qsTr("Deployed Contracts") |
|||
anchors.right: parent.right |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
} |
|||
} |
|||
|
|||
ColumnLayout |
|||
{ |
|||
anchors.top: parent.top |
|||
anchors.topMargin: 1 |
|||
ListModel |
|||
{ |
|||
id: deployedAddrModel |
|||
} |
|||
|
|||
Repeater |
|||
{ |
|||
id: deployedAddresses |
|||
model: deployedAddrModel |
|||
function refresh() |
|||
{ |
|||
deployedAddrModel.clear() |
|||
deployedRow.visible = Object.keys(projectModel.deploymentAddresses).length > 0 |
|||
for (var k in projectModel.deploymentAddresses) |
|||
{ |
|||
if (k.indexOf("-") !== -1) // this is an contract instance. ctr without - are the last deployed (to support old project) |
|||
deployedAddrModel.append({ id: k, value: projectModel.deploymentAddresses[k]}) |
|||
} |
|||
} |
|||
|
|||
Rectangle |
|||
{ |
|||
Layout.preferredHeight: 20 |
|||
Layout.preferredWidth: 235 |
|||
color: "transparent" |
|||
Label |
|||
{ |
|||
id: labelContract |
|||
width: 112 |
|||
elide: Text.ElideRight |
|||
text: index > -1 ? deployedAddrModel.get(index).id : "" |
|||
} |
|||
|
|||
TextField |
|||
{ |
|||
width: 123 |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
anchors.left: labelContract.right |
|||
text: index > - 1 ? deployedAddrModel.get(index).value : "" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
id: verificationRow |
|||
Layout.fillWidth: true |
|||
visible: Object.keys(projectModel.deploymentAddresses).length > 0 |
|||
Rectangle |
|||
{ |
|||
width: labelWidth |
|||
Label |
|||
{ |
|||
text: qsTr("Verifications") |
|||
anchors.right: parent.right |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
} |
|||
} |
|||
|
|||
Label |
|||
{ |
|||
id: verificationLabel |
|||
maximumLineCount: 20 |
|||
} |
|||
} |
|||
} |
|||
|
|||
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(root.gas, function(addresses, trHashes) |
|||
{ |
|||
projectModel.deploymentTrHashes = trHashes |
|||
worker.verifyHashes(trHashes, function (nb, trLost) |
|||
{ |
|||
projectModel.deployBlockNumber = nb |
|||
projectModel.saveProject() |
|||
root.updateVerification(nb, trLost) |
|||
}) |
|||
projectModel.deploymentAddresses = addresses |
|||
projectModel.saveProject() |
|||
deployedAddresses.refresh() |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
@ -0,0 +1,210 @@ |
|||
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 var worker |
|||
property variant sel |
|||
signal selected(string step) |
|||
id: root |
|||
|
|||
function refreshCurrent() |
|||
{ |
|||
menu.itemAt(sel).select() |
|||
} |
|||
|
|||
function init() |
|||
{ |
|||
menu.itemAt(0).select() |
|||
} |
|||
|
|||
function itemClicked(step) |
|||
{ |
|||
selected(step) |
|||
} |
|||
|
|||
border.color: "#cccccc" |
|||
border.width: 1 |
|||
|
|||
ColumnLayout |
|||
{ |
|||
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 |
|||
{ |
|||
Layout.preferredHeight: 50 |
|||
Layout.fillWidth: true |
|||
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() |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Connections { |
|||
target: projectModel |
|||
onDeploymentStarted: log.text = log.text + qsTr("Running deployment...") + "\n" |
|||
onDeploymentError: log.text = log.text + error + "\n" |
|||
onDeploymentComplete: log.text = log.text + qsTr("Deployment complete") + "\n" |
|||
onDeploymentStepChanged: log.text = log.text + message + "\n" |
|||
} |
|||
|
|||
Rectangle |
|||
{ |
|||
Layout.fillWidth: true |
|||
Layout.preferredHeight: 1 |
|||
color: "#cccccc" |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
anchors.horizontalCenter: parent.horizontalCenter |
|||
Layout.preferredHeight: 20 |
|||
anchors.left: parent.left |
|||
anchors.leftMargin: 2 |
|||
Button |
|||
{ |
|||
Layout.preferredHeight: 22 |
|||
Layout.preferredWidth: 22 |
|||
action: clearAction |
|||
iconSource: "qrc:/qml/img/cleariconactive.png" |
|||
} |
|||
|
|||
Action { |
|||
id: clearAction |
|||
enabled: log.text !== "" |
|||
tooltip: qsTr("Clear") |
|||
onTriggered: { |
|||
log.text = "" |
|||
} |
|||
} |
|||
|
|||
Button |
|||
{ |
|||
Layout.preferredHeight: 22 |
|||
text: qsTr("Clear Deployment") |
|||
action: clearDeployAction |
|||
} |
|||
|
|||
Action { |
|||
id: clearDeployAction |
|||
onTriggered: { |
|||
worker.forceStopPooling() |
|||
fileIo.deleteDir(projectModel.deploymentDir) |
|||
projectModel.cleanDeploymentStatus() |
|||
root.refreshCurrent() |
|||
log.text = "" |
|||
} |
|||
} |
|||
} |
|||
|
|||
ScrollView |
|||
{ |
|||
Layout.fillHeight: true |
|||
Layout.fillWidth: true |
|||
Text |
|||
{ |
|||
anchors.left: parent.left |
|||
anchors.leftMargin: 2 |
|||
font.pointSize: 9 |
|||
font.italic: true |
|||
id: log |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,239 @@ |
|||
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() |
|||
{ |
|||
accounts = [] |
|||
balances = {} |
|||
var requests = [{ |
|||
//accounts |
|||
jsonrpc: "2.0", |
|||
method: "eth_accounts", |
|||
params: null, |
|||
id: 0 |
|||
}]; |
|||
|
|||
TransactionHelper.rpcCall(requests, function(arg1, arg2) |
|||
{ |
|||
|
|||
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].id] = ether |
|||
} |
|||
}, function(){}); |
|||
}, function(){}); |
|||
|
|||
NetworkDeploymentCode.gasPrice(function(price) { |
|||
gasPrice = price; |
|||
gasPriceInt.setValue(price); |
|||
gasPriceLoaded() |
|||
}, function(){}); |
|||
} |
|||
|
|||
function balance(account) |
|||
{ |
|||
for (var k in accounts) |
|||
{ |
|||
if (accounts[k].id === account) |
|||
return balances[account] |
|||
} |
|||
return null |
|||
} |
|||
|
|||
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 forceStopPooling() |
|||
{ |
|||
poolLog.stop() |
|||
} |
|||
|
|||
function waitForTrReceipt(hash, callback) |
|||
{ |
|||
poolLog.callBack = callback; |
|||
poolLog.hash = hash |
|||
poolLog.elapsed = 0; |
|||
poolLog.start(); |
|||
} |
|||
|
|||
function verifyHash(tr, hash, callBack) |
|||
{ |
|||
var h = {} |
|||
h[tr] = hash |
|||
verifyHashes(h, function (bn, trLost) |
|||
{ |
|||
callBack(bn, trLost) |
|||
}); |
|||
} |
|||
|
|||
function verifyHashes(trHashes, callback) |
|||
{ |
|||
//trHashes : { "trLabel": 'hash' } |
|||
var requests = []; |
|||
var req = 0 |
|||
requests.push({ |
|||
jsonrpc: "2.0", |
|||
method: "eth_blockNumber", |
|||
params: [], |
|||
id: req |
|||
}); |
|||
var label = {} |
|||
for (var k in trHashes) |
|||
{ |
|||
req++ |
|||
label[req] = k |
|||
requests.push({ |
|||
jsonrpc: "2.0", |
|||
method: "eth_getTransactionReceipt", |
|||
params: [trHashes[k]], |
|||
id: req |
|||
}); |
|||
} |
|||
|
|||
TransactionHelper.rpcCall(requests, function (httpRequest, response){ |
|||
console.log(response) |
|||
|
|||
var ret = JSON.parse(response) |
|||
var b = ret[0].result; |
|||
var trLost = [] |
|||
for (var k in ret) |
|||
{ |
|||
if (ret[k].result === null) |
|||
trLost.push(label[ret[k]]) |
|||
} |
|||
callback(parseInt(b, 16), trLost) |
|||
}); |
|||
} |
|||
|
|||
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 elapsed |
|||
property string hash |
|||
interval: 500 |
|||
running: false |
|||
repeat: true |
|||
onTriggered: { |
|||
elapsed += interval; |
|||
var requests = []; |
|||
var jsonRpcRequestId = 0; |
|||
requests.push({ |
|||
jsonrpc: "2.0", |
|||
method: "eth_getTransactionReceipt", |
|||
params: [ hash ], |
|||
id: jsonRpcRequestId++ |
|||
}); |
|||
TransactionHelper.rpcCall(requests, function (httpRequest, response){ |
|||
console.log(response) |
|||
var receipt = JSON.parse(response)[0].result |
|||
if (receipt) |
|||
{ |
|||
stop(); |
|||
callBack(1, receipt); |
|||
} |
|||
else if (elapsed > 250000) |
|||
{ |
|||
stop(); |
|||
callBack(-1, null); |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,207 @@ |
|||
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 |
|||
id: root |
|||
property string packageHash |
|||
property string packageBase64 |
|||
property alias localPackageUrl: localPackageUrl.text |
|||
property alias lastDeployDate: lastDeployLabel.text |
|||
property string deploymentId |
|||
property string packageDir |
|||
|
|||
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: 40 |
|||
color: "transparent" |
|||
Button |
|||
{ |
|||
id: generatePackageBtn |
|||
anchors.horizontalCenter: parent.horizontalCenter |
|||
text: qsTr("Generate Package") |
|||
onClicked: |
|||
{ |
|||
NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses); |
|||
projectModel.saveProject() |
|||
} |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
anchors.top: generatePackageBtn.bottom |
|||
anchors.topMargin: 10 |
|||
visible: root.lastDeployDate !== "" |
|||
anchors.horizontalCenter: parent.horizontalCenter |
|||
Label |
|||
{ |
|||
id: lastPackage |
|||
text: qsTr("Last Package") |
|||
} |
|||
|
|||
Label |
|||
{ |
|||
id: lastDeployLabel |
|||
} |
|||
} |
|||
} |
|||
|
|||
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/"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,310 @@ |
|||
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 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 |
|||
id: root |
|||
color: "#E3E3E3E3" |
|||
anchors.fill: parent |
|||
|
|||
function show() |
|||
{ |
|||
ctrRegisterLabel.calculateRegisterGas() |
|||
applicationUrlEthCtrl.text = projectModel.applicationUrlEth |
|||
applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp |
|||
visible = true |
|||
|
|||
verificationEthUrl.text = "" |
|||
if (projectModel.registerContentHashTrHash !== "") |
|||
{ |
|||
worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) |
|||
{ |
|||
updateVerification(projectModel.registerContentHashBlockNumber, bn, trLost, verificationEthUrl) |
|||
}); |
|||
} |
|||
|
|||
verificationUrl.text = "" |
|||
if (projectModel.registerUrlTrHash !== "") |
|||
{ |
|||
worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) |
|||
{ |
|||
updateVerification(projectModel.registerUrlBlockNumber, bn, trLost, verificationUrl) |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function updateVerification(originbn, bn, trLost, ctrl) |
|||
{ |
|||
if (trLost.length === 0) |
|||
{ |
|||
ctrl.text = bn - originbn |
|||
ctrl.text += qsTr(" verifications") |
|||
} |
|||
else |
|||
{ |
|||
ctrl.text = qsTr("invalidated") |
|||
} |
|||
} |
|||
|
|||
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: "c6d9d2cd449a754c494264e1809c50e34d64562b" |
|||
visible: true |
|||
Layout.preferredWidth: 235 |
|||
} |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
Layout.fillWidth: true |
|||
Layout.preferredHeight: 20 |
|||
Rectangle |
|||
{ |
|||
Layout.preferredWidth: col.width / 2 |
|||
Label |
|||
{ |
|||
text: qsTr("Http URL") |
|||
anchors.right: parent.right |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
} |
|||
} |
|||
|
|||
DefaultTextField |
|||
{ |
|||
id: applicationUrlHttpCtrl |
|||
Layout.preferredWidth: 235 |
|||
} |
|||
|
|||
Label |
|||
{ |
|||
id: verificationUrl |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
} |
|||
} |
|||
|
|||
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(applicationUrlEthCtrl.text).join('/'); |
|||
NetworkDeploymentCode.checkPathCreationCost(applicationUrlEthCtrl.text, 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 URL") |
|||
anchors.right: parent.right |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
} |
|||
} |
|||
|
|||
Rectangle |
|||
{ |
|||
height: 25 |
|||
color: "transparent" |
|||
Layout.preferredWidth: 235 |
|||
DefaultTextField |
|||
{ |
|||
width: 235 |
|||
id: applicationUrlEthCtrl |
|||
onTextChanged: { |
|||
ctrRegisterLabel.calculateRegisterGas(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
Layout.fillWidth: true |
|||
Layout.preferredHeight: 20 |
|||
Rectangle |
|||
{ |
|||
Layout.preferredWidth: col.width / 2 |
|||
Label |
|||
{ |
|||
text: qsTr("Formatted Ethereum URL") |
|||
anchors.right: parent.right |
|||
anchors.verticalCenter: parent.verticalCenter |
|||
} |
|||
} |
|||
|
|||
DefaultLabel |
|||
{ |
|||
id: appUrlFormatted |
|||
anchors.verticalCenter: parent.verticalCenter; |
|||
anchors.topMargin: 10 |
|||
font.italic: true |
|||
font.pointSize: appStyle.absoluteSize(-1) |
|||
} |
|||
|
|||
Label |
|||
{ |
|||
id: verificationEthUrl |
|||
} |
|||
} |
|||
} |
|||
|
|||
RowLayout |
|||
{ |
|||
anchors.bottom: parent.bottom |
|||
anchors.bottomMargin: 10 |
|||
width: parent.width |
|||
|
|||
function registerHash(callback) |
|||
{ |
|||
var inError = []; |
|||
var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.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(ethUrl, function(){ |
|||
projectModel.applicationUrlEth = applicationUrlEthCtrl.text |
|||
projectModel.saveProject() |
|||
worker.waitForTrReceipt(projectModel.registerContentHashTrHash, function(status, receipt) |
|||
{ |
|||
worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) |
|||
{ |
|||
projectModel.registerContentHashBlockNumber = bn |
|||
projectModel.saveProject() |
|||
root.updateVerification(bn, bn, trLost, verificationEthUrl) |
|||
callback() |
|||
}); |
|||
}); |
|||
}) |
|||
} |
|||
} |
|||
|
|||
function registerUrl() |
|||
{ |
|||
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 (applicationUrlHttpCtrl.text.length > 32) |
|||
inError.push(qsTr(applicationUrlHttpCtrl.text)); |
|||
if (!worker.stopForInputError(inError)) |
|||
{ |
|||
registerToUrlHint(applicationUrlHttpCtrl.text, function(){ |
|||
projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text |
|||
projectModel.saveProject() |
|||
worker.waitForTrReceipt(projectModel.registerUrlTrHash, function(status, receipt) |
|||
{ |
|||
worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) |
|||
{ |
|||
projectModel.registerUrlBlockNumber = bn |
|||
projectModel.saveProject() |
|||
root.updateVerification(bn, bn, trLost, verificationUrl) |
|||
}); |
|||
}) |
|||
}) |
|||
} |
|||
} |
|||
|
|||
Button |
|||
{ |
|||
anchors.right: parent.right |
|||
anchors.rightMargin: 10 |
|||
text: qsTr("Register Dapp") |
|||
width: 30 |
|||
onClicked: |
|||
{ |
|||
parent.registerHash(function(){ |
|||
parent.registerUrl() |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue