feat(GasSelector): introduce GasSelector component

Closes #674
This commit is contained in:
Pascal Precht 2020-08-13 09:27:53 +02:00 committed by Iuri Matias
parent c08767c74b
commit 832518a0e1
7 changed files with 299 additions and 6 deletions

View File

@ -1,7 +1,8 @@
import NimQml, Tables, strformat, strutils, chronicles, json
import NimQml, Tables, strformat, strutils, chronicles, json, std/wrapnils, parseUtils, stint
import ../../status/[status, wallet, threads]
import ../../status/wallet/collectibles as status_collectibles
import ../../status/libstatus/wallet as status_wallet
import ../../status/libstatus/utils
import views/[asset_list, account_list, account_item, transaction_list, collectibles_list]
QtObject:
@ -15,6 +16,11 @@ QtObject:
status: Status
totalFiatBalance: string
etherscanLink: string
safeLowGasPrice: string
standardGasPrice: string
fastGasPrice: string
fastestGasPrice: string
defaultGasLimit: string
proc delete(self: WalletView) =
self.accounts.delete
@ -36,6 +42,11 @@ QtObject:
result.currentCollectiblesList = newCollectiblesList()
result.totalFiatBalance = ""
result.etherscanLink = ""
result.safeLowGasPrice = "0"
result.standardGasPrice = "0"
result.fastGasPrice = "0"
result.fastestGasPrice = "0"
result.defaultGasLimit = "22000"
result.setup
proc etherscanLinkChanged*(self: WalletView) {.signal.}
@ -156,6 +167,17 @@ QtObject:
proc getCryptoValue*(self: WalletView, fiatBalance: string, fiatSymbol: string, cryptoSymbol: string): string {.slot.} =
result = fmt"{self.status.wallet.convertValue(fiatBalance, fiatSymbol, cryptoSymbol)}"
proc getGasEthValue*(self: WalletView, gweiValue: string, gasLimit: string): string {.slot.} =
var gweiValueInt:int
var gasLimitInt:int
discard gweiValue.parseInt(gweiValueInt)
discard gasLimit.parseInt(gasLimitInt)
let weiValue = gweiValueInt.u256 * 1000000000.u256 * gasLimitInt.u256
let ethValue = wei2Eth(weiValue)
result = fmt"{ethValue}"
proc generateNewAccount*(self: WalletView, password: string, accountName: string, color: string): string {.slot.} =
result = self.status.wallet.generateNewAccount(password, accountName, color)
@ -271,3 +293,38 @@ QtObject:
if address == self.currentAccount.address:
self.setCurrentTransactions(transactions)
self.loadingTrxHistory(false)
proc gasPricePredictionsChanged*(self: WalletView) {.signal.}
proc getGasPricePredictions*(self: WalletView) {.slot.} =
let prediction = self.status.wallet.getGasPricePredictions()
self.safeLowGasPrice = prediction.safeLow
self.standardGasPrice = prediction.standard
self.fastGasPrice = prediction.fast
self.fastestGasPrice = prediction.fastest
self.gasPricePredictionsChanged()
proc safeLowGasPrice*(self: WalletView): string {.slot.} = result = ?.self.safeLowGasPrice
QtProperty[string] safeLowGasPrice:
read = safeLowGasPrice
notify = gasPricePredictionsChanged
proc standardGasPrice*(self: WalletView): string {.slot.} = result = ?.self.standardGasPrice
QtProperty[string] standardGasPrice:
read = standardGasPrice
notify = gasPricePredictionsChanged
proc fastGasPrice*(self: WalletView): string {.slot.} = result = ?.self.fastGasPrice
QtProperty[string] fastGasPrice:
read = fastGasPrice
notify = gasPricePredictionsChanged
proc fastestGasPrice*(self: WalletView): string {.slot.} = result = ?.self.fastestGasPrice
QtProperty[string] fastestGasPrice:
read = fastestGasPrice
notify = gasPricePredictionsChanged
proc defaultGasLimit*(self: WalletView): string {.slot.} = result = ?.self.defaultGasLimit
QtProperty[string] defaultGasLimit:
read = defaultGasLimit

View File

@ -21,6 +21,12 @@ type SignalType* {.pure.} = enum
WhisperFilterAdded = "whisper.filter.added"
Unknown
type GasPricePrediction* = object
safeLow*: string
standard*: string
fast*: string
fastest*: string
type DerivedAccount* = object
publicKey*: string
address*: string
@ -166,4 +172,4 @@ type
id*: string
name*: string
etherscanLink* {.serializedFieldName("etherscan-link").}: string
config*: NodeConfig
config*: NodeConfig

View File

@ -1,4 +1,4 @@
import eventemitter, json, strformat, strutils, chronicles, sequtils
import eventemitter, json, strformat, strutils, chronicles, sequtils, httpclient
import json_serialization
from eth/common/utils import parseAddress
import libstatus/accounts as status_accounts
@ -6,7 +6,7 @@ import libstatus/tokens as status_tokens
import libstatus/settings as status_settings
import libstatus/wallet as status_wallet
import libstatus/accounts/constants as constants
from libstatus/types import GeneratedAccount, DerivedAccount, Transaction, Setting
from libstatus/types import GeneratedAccount, DerivedAccount, Transaction, Setting, GasPricePrediction
import wallet/balance_manager
import wallet/account
import wallet/collectibles
@ -187,3 +187,15 @@ proc validateMnemonic*(self: WalletModel, mnemonic: string): string =
result = status_wallet.validateMnemonic(mnemonic).parseJSON()["error"].getStr
proc getAllCollectibles*(self: WalletModel, address: string): seq[Collectible] = getAllCollectibles(address)
proc getGasPricePredictions*(self: WalletModel): GasPricePrediction =
try:
let url: string = fmt"https://etherchain.org/api/gasPriceOracle"
let client = newHttpClient()
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
let response = client.request(url)
result = Json.decode(response.body, GasPricePrediction)
except Exception as e:
echo "error getting gas price predictions"
echo e.msg

View File

@ -69,6 +69,9 @@ Item {
SendModal{
id: sendModal
onOpened: {
walletModel.getGasPricePredictions()
}
}
ReceiveModal{

View File

@ -92,12 +92,23 @@ Item {
}
}
GasSelector {
id: gasSelector
anchors.top: selectFromAccount.bottom
anchors.topMargin: Style.current.bigPadding
slowestGasPrice: parseFloat(walletModel.safeLowGasPrice)
fastestGasPrice: parseFloat(walletModel.fastestGasPrice)
getGasEthValue: walletModel.getGasEthValue
getFiatValue: walletModel.getFiatValue
defaultCurrency: walletModel.defaultCurrency
}
RecipientSelector {
id: selectRecipient
accounts: walletModel.accounts
contacts: profileModel.addedContacts
label: qsTr("Recipient")
anchors.top: selectFromAccount.bottom
anchors.top: gasSelector.bottom
anchors.topMargin: Style.current.padding
anchors.left: parent.left
anchors.right: parent.right

205
ui/shared/GasSelector.qml Normal file
View File

@ -0,0 +1,205 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import "../imports"
import "./"
Item {
id: root
anchors.left: parent.left
anchors.right: parent.right
height: sliderWrapper.height + Style.current.smallPadding + txtNetworkFee.height + buttonAdvanced.height
property double slowestGasPrice: 0
property double fastestGasPrice: 100
property double stepSize: ((root.fastestGasPrice - root.slowestGasPrice) / 10).toFixed(1)
property var getGasEthValue: function () {}
property var getFiatValue: function () {}
property string defaultCurrency: "USD"
property alias selectedGasPrice: inputGasPrice.text
property alias selectedGasLimit: inputGasLimit.text
function defaultGasPrice() {
return ((50 * (root.fastestGasPrice - root.slowestGasPrice) / 100) + root.slowestGasPrice)
}
function updateGasEthValue() {
let ethValue = root.getGasEthValue(inputGasPrice.text, inputGasLimit.text)
let fiatValue = root.getFiatValue(ethValue, "ETH", root.defaultCurrency)
let summary = ethValue + " ETH ~" + fiatValue + " " + root.defaultCurrency.toUpperCase()
labelGasPriceSummary.text = summary
labelGasPriceSummaryAdvanced.text = summary
}
StyledText {
id: txtNetworkFee
anchors.top: parent.top
anchors.left: parent.left
text: qsTr("Network fee")
font.weight: Font.Medium
font.pixelSize: 13
color: Style.current.textColor
}
StyledText {
id: labelGasPriceSummary
anchors.top: parent.top
anchors.right: parent.right
font.weight: Font.Medium
font.pixelSize: 13
color: Style.current.secondaryText
}
Item {
id: sliderWrapper
anchors.topMargin: Style.current.smallPadding
anchors.top: labelGasPriceSummary.bottom
height: sliderWrapper.visible ? gasSlider.height + labelSlow.height + Style.current.padding : 0
width: parent.width
visible: Number(root.selectedGasPrice) >= Number(root.slowestGasPrice) && Number(root.selectedGasPrice) <= Number(root.fastestGasPrice)
StatusSlider {
id: gasSlider
minimumValue: root.slowestGasPrice
maximumValue: root.fastestGasPrice
stepSize: root.stepSize
value: root.defaultGasPrice()
onValueChanged: {
if (!isNaN(gasSlider.value)) {
inputGasPrice.text = gasSlider.value + ""
root.updateGasEthValue()
}
}
visible: parent.visible
}
StyledText {
id: labelSlow
anchors.top: gasSlider.bottom
anchors.topMargin: Style.current.padding
anchors.left: parent.left
text: qsTr("Slow")
font.pixelSize: 15
color: Style.current.textColor
visible: parent.visible
}
StyledText {
id: labelOptimal
anchors.top: gasSlider.bottom
anchors.topMargin: Style.current.padding
anchors.horizontalCenter: gasSlider.horizontalCenter
text: qsTr("Optimal")
font.pixelSize: 15
color: Style.current.textColor
visible: parent.visible
}
StyledText {
id: labelFast
anchors.top: gasSlider.bottom
anchors.topMargin: Style.current.padding
anchors.right: parent.right
text: qsTr("Fast")
font.pixelSize: 15
color: Style.current.textColor
visible: parent.visible
}
}
StyledButton {
id: buttonReset
anchors.top: sliderWrapper.bottom
anchors.topMargin: sliderWrapper.visible ? Style.current.smallPadding : 0
anchors.right: buttonAdvanced.left
anchors.rightMargin: -Style.current.padding
label: qsTr("Reset")
btnColor: "transparent"
textSize: 13
visible: !sliderWrapper.visible
onClicked: {
gasSlider.value = root.defaultGasPrice()
inputGasPrice.text = root.defaultGasPrice()
}
}
StyledButton {
id: buttonAdvanced
anchors.top: sliderWrapper.bottom
anchors.topMargin: sliderWrapper.visible ? Style.current.smallPadding : 0
anchors.right: parent.right
anchors.rightMargin: -Style.current.padding
label: qsTr("Advanced")
btnColor: "transparent"
textSize: 13
onClicked: {
customNetworkFeeDialog.open()
}
}
ModalPopup {
id: customNetworkFeeDialog
title: qsTr("Custom Network Fee")
height: 386
Input {
id: inputGasLimit
label: qsTr("Gas limit")
text: "22000"
customHeight: 56
anchors.top: parent.top
onTextChanged: {
if (inputGasLimit.text.trim() === "") {
inputGasLimit.text = root.selectedGasLimit
}
root.updateGasEthValue()
}
}
Input {
id: inputGasPrice
label: qsTr("Gas price")
anchors.top: inputGasLimit.bottom
anchors.topMargin: Style.current.smallPadding
customHeight: 56
text: root.defaultGasPrice()
onTextChanged: {
if (inputGasPrice.text.trim() === "") {
inputGasPrice.text = root.defaultGasPrice()
}
root.updateGasEthValue()
}
StyledText {
color: Style.current.darkGrey
text: qsTr("Gwei")
anchors.top: parent.top
anchors.topMargin: 42
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
font.pixelSize: 15
}
}
StyledText {
id: labelGasPriceSummaryAdvanced
anchors.top: inputGasPrice.bottom
anchors.topMargin: Style.current.smallPadding
anchors.right: parent.right
font.weight: Font.Medium
font.pixelSize: 13
color: Style.current.secondaryText
}
footer: StyledButton {
id: applyButton
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
label: qsTr("Apply")
anchors.bottom: parent.bottom
onClicked: {
root.updateGasEthValue()
customNetworkFeeDialog.close()
}
}
}
}

View File

@ -8,7 +8,6 @@ QQC1.Slider {
id: slider
anchors.left: parent.left
anchors.right: parent.right
stepSize: ((slider.maximumValue - slider.minimumValue) / 10).toFixed(1)
style: SliderStyle {
groove: Rectangle {
implicitHeight: 4