|
|
|
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: []
|
|
|
|
property alias gasPrice: gasPriceInput
|
|
|
|
color: "#E3E3E3E3"
|
|
|
|
signal deployed
|
|
|
|
anchors.fill: parent
|
|
|
|
id: root
|
|
|
|
|
|
|
|
property int labelWidth: 150
|
|
|
|
property bool verifyDeploy: true
|
|
|
|
|
|
|
|
function show()
|
|
|
|
{
|
|
|
|
visible = true
|
|
|
|
contractList.currentIndex = 0
|
|
|
|
contractList.change()
|
|
|
|
accountsModel.clear()
|
|
|
|
for (var k in worker.accounts)
|
|
|
|
accountsModel.append(worker.accounts[k])
|
|
|
|
|
|
|
|
if (worker.currentAccount === "" && worker.accounts.length > 0)
|
|
|
|
{
|
|
|
|
worker.currentAccount = worker.accounts[0].id
|
|
|
|
accountsList.currentIndex = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
verifyDeployedContract()
|
|
|
|
deployedAddresses.refresh()
|
|
|
|
|
|
|
|
worker.renewCtx()
|
|
|
|
verifyDeploy = true
|
|
|
|
worker.pooler.onTriggered.connect(function() {
|
|
|
|
if (root.visible && verifyDeploy)
|
|
|
|
verifyDeployedContract();
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function verifyDeployedContract()
|
|
|
|
{
|
|
|
|
if (projectModel.deployBlockNumber !== -1)
|
|
|
|
{
|
|
|
|
worker.verifyHashes(projectModel.deploymentTrHashes, function (bn, trLost)
|
|
|
|
{
|
|
|
|
root.updateVerification(bn, trLost)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateVerification(blockNumber, trLost)
|
|
|
|
{
|
|
|
|
var nb = parseInt(blockNumber - projectModel.deployBlockNumber)
|
|
|
|
verificationTextArea.visible = false
|
|
|
|
verificationLabel.visible = true
|
|
|
|
if (nb >= 10)
|
|
|
|
{
|
|
|
|
verificationLabel.text = qsTr("contracts deployment verified")
|
|
|
|
verificationLabel.color = "green"
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
verificationLabel.text = nb
|
|
|
|
if (trLost.length > 0)
|
|
|
|
{
|
|
|
|
verifyDeploy = false
|
|
|
|
verificationTextArea.visible = true
|
|
|
|
verificationLabel.visible = false
|
|
|
|
verificationTextArea.text = ""
|
|
|
|
deploymentStepChanged("following transactions are invalidated:")
|
|
|
|
verificationTextArea.text += "\n" + qsTr("Transactions lost") + "\n"
|
|
|
|
verificationTextArea.textColor = "red"
|
|
|
|
for (var k in trLost)
|
|
|
|
{
|
|
|
|
deploymentStepChanged(trLost[k])
|
|
|
|
verificationTextArea.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
|
|
|
|
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle
|
|
|
|
{
|
|
|
|
Layout.preferredWidth: scenarioList.width
|
|
|
|
Layout.preferredHeight: 1
|
|
|
|
color: "#cccccc"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
function toHexWei()
|
|
|
|
{
|
|
|
|
return "0x" + gasPriceInput.value.toWei().hexValue()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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("Deployment Cost")
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ether
|
|
|
|
{
|
|
|
|
id: gasToUseInput
|
|
|
|
displayUnitSelection: false
|
|
|
|
displayFormattedValue: true
|
|
|
|
edit: false
|
|
|
|
Layout.preferredWidth: 350
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle
|
|
|
|
{
|
|
|
|
border.color: "#cccccc"
|
|
|
|
border.width: 2
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.preferredHeight: parent.height + 25
|
|
|
|
color: "transparent"
|
|
|
|
id: rectDeploymentVariable
|
|
|
|
ScrollView
|
|
|
|
{
|
|
|
|
anchors.fill: parent
|
|
|
|
anchors.topMargin: 4
|
|
|
|
anchors.bottomMargin: 4
|
|
|
|
ColumnLayout
|
|
|
|
{
|
|
|
|
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
|
|
|
|
width: parent.width
|
|
|
|
id: deployedAddresses
|
|
|
|
function refresh()
|
|
|
|
{
|
|
|
|
textAddresses.text = ""
|
|
|
|
deployedRow.visible = Object.keys(projectModel.deploymentAddresses).length > 0
|
|
|
|
textAddresses.text = JSON.stringify(projectModel.deploymentAddresses, null, ' ')
|
|
|
|
}
|
|
|
|
TextArea
|
|
|
|
{
|
|
|
|
anchors.fill: parent
|
|
|
|
id: textAddresses
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TextArea
|
|
|
|
{
|
|
|
|
id: verificationTextArea
|
|
|
|
visible: false
|
|
|
|
}
|
|
|
|
|
|
|
|
Label
|
|
|
|
{
|
|
|
|
id: verificationLabel
|
|
|
|
visible: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle
|
|
|
|
{
|
|
|
|
Layout.preferredWidth: parent.width
|
|
|
|
Layout.alignment: Qt.BottomEdge
|
|
|
|
Button
|
|
|
|
{
|
|
|
|
Layout.preferredHeight: 22
|
|
|
|
anchors.right: deployBtn.left
|
|
|
|
text: qsTr("Reset")
|
|
|
|
action: clearDeployAction
|
|
|
|
}
|
|
|
|
|
|
|
|
Action {
|
|
|
|
id: clearDeployAction
|
|
|
|
onTriggered: {
|
|
|
|
worker.forceStopPooling()
|
|
|
|
if (projectModel.deploymentDir && projectModel.deploymentDir !== "")
|
|
|
|
fileIo.deleteDir(projectModel.deploymentDir)
|
|
|
|
projectModel.cleanDeploymentStatus()
|
|
|
|
deploymentDialog.steps.reset()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Button
|
|
|
|
{
|
|
|
|
id: deployBtn
|
|
|
|
anchors.right: parent.right
|
|
|
|
text: qsTr("Deploy Contracts")
|
|
|
|
onClicked:
|
|
|
|
{
|
|
|
|
projectModel.deployedScenarioIndex = contractList.currentIndex
|
|
|
|
NetworkDeploymentCode.deployContracts(root.gas, gasPriceInput.toHexWei(), function(addresses, trHashes)
|
|
|
|
{
|
|
|
|
projectModel.deploymentTrHashes = trHashes
|
|
|
|
worker.verifyHashes(trHashes, function (nb, trLost)
|
|
|
|
{
|
|
|
|
projectModel.deployBlockNumber = nb
|
|
|
|
projectModel.saveProject()
|
|
|
|
root.updateVerification(nb, trLost)
|
|
|
|
root.deployed()
|
|
|
|
})
|
|
|
|
projectModel.deploymentAddresses = addresses
|
|
|
|
projectModel.saveProject()
|
|
|
|
deployedAddresses.refresh()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|