parent
c08767c74b
commit
832518a0e1
|
@ -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/[status, wallet, threads]
|
||||||
import ../../status/wallet/collectibles as status_collectibles
|
import ../../status/wallet/collectibles as status_collectibles
|
||||||
import ../../status/libstatus/wallet as status_wallet
|
import ../../status/libstatus/wallet as status_wallet
|
||||||
|
import ../../status/libstatus/utils
|
||||||
import views/[asset_list, account_list, account_item, transaction_list, collectibles_list]
|
import views/[asset_list, account_list, account_item, transaction_list, collectibles_list]
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
|
@ -15,6 +16,11 @@ QtObject:
|
||||||
status: Status
|
status: Status
|
||||||
totalFiatBalance: string
|
totalFiatBalance: string
|
||||||
etherscanLink: string
|
etherscanLink: string
|
||||||
|
safeLowGasPrice: string
|
||||||
|
standardGasPrice: string
|
||||||
|
fastGasPrice: string
|
||||||
|
fastestGasPrice: string
|
||||||
|
defaultGasLimit: string
|
||||||
|
|
||||||
proc delete(self: WalletView) =
|
proc delete(self: WalletView) =
|
||||||
self.accounts.delete
|
self.accounts.delete
|
||||||
|
@ -36,6 +42,11 @@ QtObject:
|
||||||
result.currentCollectiblesList = newCollectiblesList()
|
result.currentCollectiblesList = newCollectiblesList()
|
||||||
result.totalFiatBalance = ""
|
result.totalFiatBalance = ""
|
||||||
result.etherscanLink = ""
|
result.etherscanLink = ""
|
||||||
|
result.safeLowGasPrice = "0"
|
||||||
|
result.standardGasPrice = "0"
|
||||||
|
result.fastGasPrice = "0"
|
||||||
|
result.fastestGasPrice = "0"
|
||||||
|
result.defaultGasLimit = "22000"
|
||||||
result.setup
|
result.setup
|
||||||
|
|
||||||
proc etherscanLinkChanged*(self: WalletView) {.signal.}
|
proc etherscanLinkChanged*(self: WalletView) {.signal.}
|
||||||
|
@ -156,6 +167,17 @@ QtObject:
|
||||||
proc getCryptoValue*(self: WalletView, fiatBalance: string, fiatSymbol: string, cryptoSymbol: string): string {.slot.} =
|
proc getCryptoValue*(self: WalletView, fiatBalance: string, fiatSymbol: string, cryptoSymbol: string): string {.slot.} =
|
||||||
result = fmt"{self.status.wallet.convertValue(fiatBalance, fiatSymbol, cryptoSymbol)}"
|
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.} =
|
proc generateNewAccount*(self: WalletView, password: string, accountName: string, color: string): string {.slot.} =
|
||||||
result = self.status.wallet.generateNewAccount(password, accountName, color)
|
result = self.status.wallet.generateNewAccount(password, accountName, color)
|
||||||
|
|
||||||
|
@ -271,3 +293,38 @@ QtObject:
|
||||||
if address == self.currentAccount.address:
|
if address == self.currentAccount.address:
|
||||||
self.setCurrentTransactions(transactions)
|
self.setCurrentTransactions(transactions)
|
||||||
self.loadingTrxHistory(false)
|
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
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,12 @@ type SignalType* {.pure.} = enum
|
||||||
WhisperFilterAdded = "whisper.filter.added"
|
WhisperFilterAdded = "whisper.filter.added"
|
||||||
Unknown
|
Unknown
|
||||||
|
|
||||||
|
type GasPricePrediction* = object
|
||||||
|
safeLow*: string
|
||||||
|
standard*: string
|
||||||
|
fast*: string
|
||||||
|
fastest*: string
|
||||||
|
|
||||||
type DerivedAccount* = object
|
type DerivedAccount* = object
|
||||||
publicKey*: string
|
publicKey*: string
|
||||||
address*: string
|
address*: string
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import eventemitter, json, strformat, strutils, chronicles, sequtils
|
import eventemitter, json, strformat, strutils, chronicles, sequtils, httpclient
|
||||||
import json_serialization
|
import json_serialization
|
||||||
from eth/common/utils import parseAddress
|
from eth/common/utils import parseAddress
|
||||||
import libstatus/accounts as status_accounts
|
import libstatus/accounts as status_accounts
|
||||||
|
@ -6,7 +6,7 @@ import libstatus/tokens as status_tokens
|
||||||
import libstatus/settings as status_settings
|
import libstatus/settings as status_settings
|
||||||
import libstatus/wallet as status_wallet
|
import libstatus/wallet as status_wallet
|
||||||
import libstatus/accounts/constants as constants
|
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/balance_manager
|
||||||
import wallet/account
|
import wallet/account
|
||||||
import wallet/collectibles
|
import wallet/collectibles
|
||||||
|
@ -187,3 +187,15 @@ proc validateMnemonic*(self: WalletModel, mnemonic: string): string =
|
||||||
result = status_wallet.validateMnemonic(mnemonic).parseJSON()["error"].getStr
|
result = status_wallet.validateMnemonic(mnemonic).parseJSON()["error"].getStr
|
||||||
|
|
||||||
proc getAllCollectibles*(self: WalletModel, address: string): seq[Collectible] = getAllCollectibles(address)
|
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
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,9 @@ Item {
|
||||||
|
|
||||||
SendModal{
|
SendModal{
|
||||||
id: sendModal
|
id: sendModal
|
||||||
|
onOpened: {
|
||||||
|
walletModel.getGasPricePredictions()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReceiveModal{
|
ReceiveModal{
|
||||||
|
|
|
@ -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 {
|
RecipientSelector {
|
||||||
id: selectRecipient
|
id: selectRecipient
|
||||||
accounts: walletModel.accounts
|
accounts: walletModel.accounts
|
||||||
contacts: profileModel.addedContacts
|
contacts: profileModel.addedContacts
|
||||||
label: qsTr("Recipient")
|
label: qsTr("Recipient")
|
||||||
anchors.top: selectFromAccount.bottom
|
anchors.top: gasSelector.bottom
|
||||||
anchors.topMargin: Style.current.padding
|
anchors.topMargin: Style.current.padding
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,6 @@ QQC1.Slider {
|
||||||
id: slider
|
id: slider
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
stepSize: ((slider.maximumValue - slider.minimumValue) / 10).toFixed(1)
|
|
||||||
style: SliderStyle {
|
style: SliderStyle {
|
||||||
groove: Rectangle {
|
groove: Rectangle {
|
||||||
implicitHeight: 4
|
implicitHeight: 4
|
||||||
|
|
Loading…
Reference in New Issue