2020-08-13 07:27:53 +00:00
import QtQuick 2.13
import QtQuick . Controls 2.13
import QtQuick . Layouts 1.13
2021-09-28 15:04:06 +00:00
import utils 1.0
2020-09-17 15:04:38 +00:00
import "./status"
2020-08-13 07:27:53 +00:00
import "./"
Item {
id: root
2021-05-21 20:19:03 +00:00
width: parent . width
height: Style . current . smallPadding + prioritytext . height +
( advancedMode ? advancedModeItemGroup.height : selectorButtons . height )
2021-07-05 12:34:56 +00:00
property double gasPrice: 0
property bool eip1599Enabled: walletModel . transactionsView . isEIP1559Enabled
property var suggestedFees: JSON . parse ( walletModel . gasView . suggestedFees )
property var latestBaseFee: JSON . parse ( walletModel . transactionsView . latestBaseFee )
property double latestBaseFeeGwei: {
if ( ! eip1599Enabled ) return 0 ;
return parseFloat ( latestBaseFee . gwei )
}
property var getGasGweiValue: function ( ) { }
2020-08-13 07:27:53 +00:00
property var getGasEthValue: function ( ) { }
property var getFiatValue: function ( ) { }
property string defaultCurrency: "USD"
property alias selectedGasPrice: inputGasPrice . text
property alias selectedGasLimit: inputGasLimit . text
2021-07-05 12:34:56 +00:00
property string defaultGasLimit: "0"
property alias selectedTipLimit: inputPerGasTipLimit . text
property alias selectedOverallLimit: inputGasPrice . text
2020-09-01 03:49:05 +00:00
property double selectedGasEthValue
property double selectedGasFiatValue
2020-09-14 12:12:47 +00:00
//% "Must be greater than 0"
property string greaterThan0ErrorMessage: qsTrId ( "must-be-greater-than-0" )
2020-08-20 04:45:29 +00:00
//% "This needs to be a number"
property string invalidInputErrorMessage: qsTrId ( "this-needs-to-be-a-number" )
2020-09-14 12:12:47 +00:00
//% "Please enter an amount"
property string noInputErrorMessage: qsTrId ( "please-enter-an-amount" )
2020-08-20 04:45:29 +00:00
property bool isValid: true
2020-12-14 05:50:47 +00:00
readonly property string uuid: Utils . uuid ( )
2020-08-13 07:27:53 +00:00
2021-07-05 12:34:56 +00:00
property bool advancedMode: true // TODO: change to false once EIP1559 suggestions are revised
// TODO: change these values false once EIP1559 suggestions are revised
property double perGasTipLimitFloor: 1 // Matches status-react minimum-priority-fee
property double perGasTipLimitAverage: formatDec ( suggestedFees . maxPriorityFeePerGas , 2 ) // 1.5 // Matches status-react average-priority-fee
property bool showPriceLimitWarning : false
property bool showTipLimitWarning : false
function formatDec ( num , dec ) {
return Math . round ( ( num + Number . EPSILON ) * Math . pow ( 10 , dec ) ) / Math . pow ( 10 , dec )
}
2021-05-21 20:19:03 +00:00
2020-08-13 07:27:53 +00:00
function updateGasEthValue ( ) {
2020-08-13 08:24:51 +00:00
// causes error on application load without this null check
if ( ! inputGasPrice || ! inputGasLimit ) {
return
}
2021-07-05 12:34:56 +00:00
2020-08-13 07:27:53 +00:00
let ethValue = root . getGasEthValue ( inputGasPrice . text , inputGasLimit . text )
let fiatValue = root . getFiatValue ( ethValue , "ETH" , root . defaultCurrency )
2021-05-21 20:19:03 +00:00
2020-09-01 03:49:05 +00:00
selectedGasEthValue = ethValue
selectedGasFiatValue = fiatValue
2020-08-13 07:27:53 +00:00
}
2021-07-05 12:34:56 +00:00
function appendError ( accum , error , nonBlocking = false ) {
return accum + ` < span class = "${nonBlocking ? " non - blocking " : " "}" > $ { error } . < / s p a n > `
}
function checkLimits ( ) {
if ( ! eip1599Enabled ) return ;
let inputTipLimit = parseFloat ( inputPerGasTipLimit . text || "0.00" )
let inputOverallLimit = parseFloat ( inputGasPrice . text || "0.00" )
let gasLimit = parseInt ( inputGasLimit . text , 10 )
errorsText . text = "" ;
showPriceLimitWarning = false
showTipLimitWarning = false
let errorMsg = "" ;
if ( gasLimit < 21000 ) {
errorMsg = appendError ( errorMsg , qsTr ( "Min 21000 units" ) )
} else if ( gasLimit < parseInt ( defaultGasLimit ) ) {
errorMsg = appendError ( errorMsg , qsTr ( "Not enough gas" ) . arg ( perGasTipLimitAverage ) , true )
}
// Per-gas tip limit rules
if ( inputTipLimit < perGasTipLimitFloor ) {
errorMsg = appendError ( errorMsg , qsTr ( "Miners will currently not process transactions with a tip below %1 Gwei, the average is %2 Gwei" ) . arg ( perGasTipLimitFloor ) . arg ( perGasTipLimitAverage ) )
showTipLimitWarning = true
} else if ( inputTipLimit < perGasTipLimitAverage ) {
errorMsg = appendError ( errorMsg , qsTr ( "The average miner tip is %1 Gwei" ) . arg ( perGasTipLimitAverage ) , true )
}
// Per-gas overall limit rules
if ( inputOverallLimit < latestBaseFeeGwei ) {
errorMsg = appendError ( errorMsg , qsTr ( "The limit is below the current base fee of %1 %2" ) . arg ( latestBaseFeeGwei ) . arg ( "Gwei" ) )
showPriceLimitWarning = true
}
/ * T O D O : c h a n g e t h e s e v a l u e s f a l s e o n c e E I P 1 5 5 9 s u g g e s t i o n s a r e r e v i s e d
else if ( ( inputOverallLimit - inputTipLimit ) < latestBaseFeeGwei ) {
errorMsg = appendError ( errorMsg , qsTr ( "The limit should be at least %1 Gwei above the base fee" ) . arg ( perGasTipLimitFloor ) )
} else if ( ( inputOverallLimit - perGasTipLimitAverage ) < latestBaseFeeGwei ) {
errorMsg = appendError ( errorMsg , qsTr ( "The maximum miner tip after the current base fee will be %1 Gwei, the minimum miner tip is currently %2 Gwei" ) . arg ( inputOverallLimit ) . arg ( perGasTipLimitFloor ) , true )
showTipLimitWarning = true
} * /
errorsText . text = ` < style type = "text/css" > span { color: "#ff0000" } span . non - blocking { color: "#FE8F59" } < / s t y l e > $ { e r r o r M s g } `
}
Component.onCompleted: {
updateGasEthValue ( )
checkLimits ( )
}
2021-05-25 14:58:53 +00:00
2021-05-21 20:19:03 +00:00
function validate ( ) {
// causes error on application load without a null check
2021-07-05 12:34:56 +00:00
if ( ! inputGasLimit || ! inputGasPrice || ! inputPerGasTipLimit ) {
2021-05-21 20:19:03 +00:00
return
}
2021-07-05 12:34:56 +00:00
2021-05-21 20:19:03 +00:00
inputGasLimit . validationError = ""
inputGasPrice . validationError = ""
2021-07-05 12:34:56 +00:00
inputPerGasTipLimit . validationError = ""
2021-05-21 20:19:03 +00:00
const noInputLimit = inputGasLimit . text === ""
const noInputPrice = inputGasPrice . text === ""
2021-07-05 12:34:56 +00:00
const noPerGasTip = inputPerGasTipLimit . text === ""
2021-05-21 20:19:03 +00:00
if ( noInputLimit ) {
inputGasLimit . validationError = root . noInputErrorMessage
}
2021-07-05 12:34:56 +00:00
2021-05-21 20:19:03 +00:00
if ( noInputPrice ) {
inputGasPrice . validationError = root . noInputErrorMessage
}
2021-07-05 12:34:56 +00:00
if ( noPerGasTip ) {
inputPerGasTipLimit . validationError = root . noInputErrorMessage
}
2021-05-21 20:19:03 +00:00
if ( isNaN ( inputGasLimit . text ) ) {
inputGasLimit . validationError = invalidInputErrorMessage
}
if ( isNaN ( inputGasPrice . text ) ) {
inputGasPrice . validationError = invalidInputErrorMessage
}
2021-07-05 12:34:56 +00:00
if ( isNaN ( inputPerGasTipLimit . text ) ) {
inputPerGasTipLimit . validationError = invalidInputErrorMessage
}
2021-05-21 20:19:03 +00:00
let inputLimit = parseFloat ( inputGasLimit . text || "0.00" )
let inputPrice = parseFloat ( inputGasPrice . text || "0.00" )
2021-07-05 12:34:56 +00:00
let inputTipLimit = parseFloat ( inputPerGasTipLimit . text || "0.00" )
if ( inputLimit <= 0.00 ) {
2021-05-21 20:19:03 +00:00
inputGasLimit . validationError = root . greaterThan0ErrorMessage
}
2021-07-05 12:34:56 +00:00
if ( inputPrice <= 0.00 ) {
2021-05-21 20:19:03 +00:00
inputGasPrice . validationError = root . greaterThan0ErrorMessage
}
2021-07-05 12:34:56 +00:00
if ( inputTipLimit <= 0.00 ) {
inputPerGasTipLimit . validationError = root . greaterThan0ErrorMessage
}
const isInputValid = inputGasLimit . validationError === "" && inputGasPrice . validationError === "" && inputPerGasTipLimit . validationError === ""
return isInputValid
2021-05-21 20:19:03 +00:00
}
2020-08-13 07:27:53 +00:00
StyledText {
2021-05-21 20:19:03 +00:00
id: prioritytext
2020-08-13 07:27:53 +00:00
anchors.top: parent . top
anchors.left: parent . left
2021-07-16 20:22:50 +00:00
//% "Priority"
text: qsTrId ( "priority" )
2020-08-13 07:27:53 +00:00
font.weight: Font . Medium
font.pixelSize: 13
color: Style . current . textColor
}
2021-07-05 12:34:56 +00:00
StyledText {
id: baseFeeText
visible: eip1599Enabled && advancedMode
anchors.top: parent . top
anchors.left: prioritytext . right
anchors.leftMargin: Style . current . smallPadding
text: qsTr ( "Current base fee: %1 %2" ) . arg ( latestBaseFeeGwei ) . arg ( "Gwei" )
font.weight: Font . Medium
font.pixelSize: 13
color: Style . current . secondaryText
}
2021-05-21 20:19:03 +00:00
StatusButton {
2021-07-05 12:34:56 +00:00
visible: false // Change to TRUE once EIP1559 suggestions are revised
2021-05-21 20:19:03 +00:00
id: buttonAdvanced
anchors.verticalCenter: prioritytext . verticalCenter
2020-08-13 07:27:53 +00:00
anchors.right: parent . right
2021-07-22 15:03:59 +00:00
text: advancedMode ?
2021-07-19 21:57:57 +00:00
//% "Use suggestions"
2021-07-22 15:03:59 +00:00
qsTrId ( "use-suggestions" ) :
2021-07-19 21:57:57 +00:00
//% "Use custom"
qsTrId ( "use-custom" )
2021-05-21 20:19:03 +00:00
flat: true
2020-08-13 07:27:53 +00:00
font.pixelSize: 13
2021-05-21 20:19:03 +00:00
onClicked: advancedMode = ! advancedMode
2020-08-13 07:27:53 +00:00
}
2021-05-21 20:19:03 +00:00
Row {
id: selectorButtons
visible: ! advancedMode
anchors.top: prioritytext . bottom
anchors.topMargin: Style . current . halfPadding
spacing: 11
2020-08-13 07:27:53 +00:00
2021-05-21 20:19:03 +00:00
ButtonGroup {
id: gasGroup
onClicked: updateGasEthValue ( )
2020-08-13 07:27:53 +00:00
}
2021-05-21 20:19:03 +00:00
GasSelectorButton {
buttonGroup: gasGroup
2021-07-05 12:34:56 +00:00
text: qsTr ( "Low" )
price: {
if ( ! eip1599Enabled ) return gasPrice ;
return formatDec ( suggestedFees . maxFeePerGasL , 6 )
}
2021-05-21 20:19:03 +00:00
gasLimit: inputGasLimit ? inputGasLimit.text : ""
getGasEthValue: root . getGasEthValue
getFiatValue: root . getFiatValue
defaultCurrency: root . defaultCurrency
2021-07-05 12:34:56 +00:00
onChecked: {
if ( eip1599Enabled ) {
inputPerGasTipLimit . text = formatDec ( suggestedFees . maxPriorityFeePerGas , 2 ) ;
inputGasPrice . text = formatDec ( suggestedFees . maxFeePerGasL , 2 ) ;
} else {
inputGasPrice . text = price
}
root . updateGasEthValue ( )
root . checkLimits ( )
}
2020-08-13 07:27:53 +00:00
}
2021-05-21 20:19:03 +00:00
GasSelectorButton {
2021-05-25 14:58:53 +00:00
id: optimalGasButton
2021-05-21 20:19:03 +00:00
buttonGroup: gasGroup
checkedByDefault: true
2021-07-16 20:22:50 +00:00
//% "Optimal"
text: qsTrId ( "optimal" )
2021-06-22 17:17:37 +00:00
price: {
2021-07-05 12:34:56 +00:00
if ( ! eip1599Enabled ) {
const price = gasPrice
// Setting the gas price field here because the binding didn't work
inputGasPrice . text = price
return price
}
return formatDec ( suggestedFees . maxFeePerGasM , 6 )
2021-06-22 17:17:37 +00:00
}
2021-05-21 20:19:03 +00:00
gasLimit: inputGasLimit ? inputGasLimit.text : ""
getGasEthValue: root . getGasEthValue
getFiatValue: root . getFiatValue
defaultCurrency: root . defaultCurrency
2021-07-05 12:34:56 +00:00
onChecked: {
if ( eip1599Enabled ) {
inputPerGasTipLimit . text = formatDec ( suggestedFees . maxPriorityFeePerGas , 2 ) ;
inputGasPrice . text = formatDec ( suggestedFees . maxFeePerGasM , 2 ) ;
} else {
inputGasPrice . text = price
}
root . updateGasEthValue ( )
root . checkLimits ( )
}
2020-08-13 07:27:53 +00:00
}
2021-05-21 20:19:03 +00:00
GasSelectorButton {
buttonGroup: gasGroup
2021-07-05 12:34:56 +00:00
text: qsTr ( "High" )
price: {
if ( ! eip1599Enabled ) return gasPrice ;
return formatDec ( suggestedFees . maxFeePerGasH , 6 ) ;
}
2021-05-21 20:19:03 +00:00
gasLimit: inputGasLimit ? inputGasLimit.text : ""
getGasEthValue: root . getGasEthValue
getFiatValue: root . getFiatValue
defaultCurrency: root . defaultCurrency
2021-07-05 12:34:56 +00:00
onChecked: {
if ( eip1599Enabled ) {
inputPerGasTipLimit . text = formatDec ( suggestedFees . maxPriorityFeePerGas , 2 ) ;
inputGasPrice . text = formatDec ( suggestedFees . maxFeePerGasH , 2 ) ;
} else {
inputGasPrice . text = price
}
root . updateGasEthValue ( )
root . checkLimits ( )
}
2020-08-13 07:27:53 +00:00
}
}
2021-05-21 20:19:03 +00:00
Item {
id: advancedModeItemGroup
anchors.top: prioritytext . bottom
anchors.topMargin: 14
visible: root . advancedMode
width: parent . width
height: childrenRect . height
2020-08-20 04:45:29 +00:00
2021-05-21 20:19:03 +00:00
Input {
id: inputGasLimit
2021-07-16 20:22:50 +00:00
//% "Gas amount limit"
label: qsTrId ( "gas-amount-limit" )
2021-05-21 20:19:03 +00:00
text: "21000"
2021-07-05 12:34:56 +00:00
inputLabel.color: Style . current . secondaryText
2021-05-21 20:19:03 +00:00
customHeight: 56
anchors.top: parent . top
anchors.left: parent . left
2021-07-05 12:34:56 +00:00
anchors.right: eip1599Enabled ? inputPerGasTipLimit.left : inputGasPrice . left
2021-05-21 20:19:03 +00:00
anchors.rightMargin: Style . current . padding
placeholderText: "21000"
2021-07-27 08:59:28 +00:00
validator: IntValidator {
bottom: 1
}
2021-05-21 20:19:03 +00:00
validationErrorAlignment: TextEdit . AlignRight
validationErrorTopMargin: 8
onTextChanged: {
if ( root . validate ( ) ) {
root . updateGasEthValue ( )
2021-07-05 12:34:56 +00:00
root . checkLimits ( )
}
}
}
Input {
id: inputPerGasTipLimit
label: qsTr ( "Per-gas tip limit" )
inputLabel.color: Style . current . secondaryText
anchors.top: parent . top
anchors.right: inputGasPrice . left
anchors.rightMargin: Style . current . padding
anchors.left: undefined
visible: eip1599Enabled
width: 125
customHeight: 56
text: formatDec ( suggestedFees . maxPriorityFeePerGas , 2 ) ;
placeholderText: "20"
onTextChanged: {
if ( root . validate ( ) ) {
root . updateGasEthValue ( )
root . checkLimits ( )
2021-05-21 20:19:03 +00:00
}
2020-08-20 04:45:29 +00:00
}
}
2020-08-13 07:27:53 +00:00
2021-07-05 12:34:56 +00:00
StyledText {
color: Style . current . secondaryText
//% "Gwei"
text: qsTrId ( "gwei" )
visible: eip1599Enabled
anchors.top: parent . top
anchors.topMargin: 42
anchors.right: inputPerGasTipLimit . right
anchors.rightMargin: Style . current . padding
font.pixelSize: 15
}
2020-08-13 07:27:53 +00:00
Input {
2021-05-21 20:19:03 +00:00
id: inputGasPrice
2021-07-16 20:22:50 +00:00
//% "Per-gas overall limit"
label: qsTrId ( "per-gas-overall-limit" )
2021-07-05 12:34:56 +00:00
inputLabel.color: Style . current . secondaryText
2021-05-21 20:19:03 +00:00
anchors.top: parent . top
anchors.left: undefined
anchors.right: parent . right
2021-07-05 12:34:56 +00:00
width: 125
2021-05-21 20:19:03 +00:00
customHeight: 56
placeholderText: "20"
onTextChanged: {
if ( root . validate ( ) ) {
root . updateGasEthValue ( )
2021-07-05 12:34:56 +00:00
root . checkLimits ( )
2021-05-21 20:19:03 +00:00
}
}
2020-08-13 07:27:53 +00:00
}
2021-05-21 20:19:03 +00:00
StyledText {
color: Style . current . secondaryText
2020-08-26 15:52:26 +00:00
//% "Gwei"
text: qsTrId ( "gwei" )
2020-08-13 07:27:53 +00:00
anchors.top: parent . top
anchors.topMargin: 42
2021-05-21 20:19:03 +00:00
anchors.right: inputGasPrice . right
2020-08-13 07:27:53 +00:00
anchors.rightMargin: Style . current . padding
font.pixelSize: 15
}
2021-07-05 12:34:56 +00:00
StyledText {
id: errorsText
text: ""
width: parent . width - Style . current . padding
visible: text != ""
height: visible ? undefined : 0
anchors.top: inputGasLimit . bottom
anchors.topMargin: Style . current . smallPadding + 5
font.pixelSize: 13
textFormat: Text . RichText
color: Style . current . secondaryText
wrapMode: Text . WordWrap
}
2020-08-13 07:27:53 +00:00
StyledText {
2021-05-21 20:19:03 +00:00
id: maxPriorityFeeText
2021-07-05 12:34:56 +00:00
anchors.left: parent . left
2021-07-16 20:22:50 +00:00
//% "Maximum priority fee: %1 ETH"
2021-07-05 12:34:56 +00:00
text: {
let v = selectedGasEthValue > 0.00009 ? selectedGasEthValue :
( selectedGasEthValue < 0.000001 ? "0.000000..." : selectedGasEthValue . toFixed ( 6 ) )
return qsTrId ( "maximum-priority-fee---1-eth" ) . arg ( v )
}
anchors.top: errorsText . bottom
anchors.topMargin: Style . current . smallPadding + 5
2020-08-13 07:27:53 +00:00
font.pixelSize: 13
2021-07-05 12:34:56 +00:00
color: Style . current . textColor
2021-05-21 20:19:03 +00:00
}
StyledText {
id: maxPriorityFeeFiatText
2021-07-05 12:34:56 +00:00
text: ` $ { selectedGasFiatValue } $ { root . defaultCurrency . toUpperCase ( ) } `
2021-05-21 20:19:03 +00:00
anchors.verticalCenter: maxPriorityFeeText . verticalCenter
anchors.left: maxPriorityFeeText . right
anchors.leftMargin: 6
2020-08-13 07:27:53 +00:00
color: Style . current . secondaryText
2021-05-21 20:19:03 +00:00
anchors.topMargin: 19
font.pixelSize: 13
2020-08-13 07:27:53 +00:00
}
2021-05-21 20:19:03 +00:00
StyledText {
id: maxPriorityFeeDetailsText
2021-07-16 20:22:50 +00:00
//% "Maximum overall price for the transaction. If the block base fee exceeds this, it will be included in a following block with a lower base fee."
text: qsTrId ( "maximum-overall-price-for-the-transaction--if-the-block-base-fee-exceeds-this--it-will-be-included-in-a-following-block-with-a-lower-base-fee-" )
2021-05-21 20:19:03 +00:00
width: parent . width
anchors.top: maxPriorityFeeText . bottom
anchors.topMargin: Style . current . smallPadding
font.pixelSize: 13
color: Style . current . secondaryText
wrapMode: Text . WordWrap
2020-08-13 07:27:53 +00:00
}
}
}