diff --git a/src/app/chat/views/stickers.nim b/src/app/chat/views/stickers.nim
index 45d7cbb478..eed424d59f 100644
--- a/src/app/chat/views/stickers.nim
+++ b/src/app/chat/views/stickers.nim
@@ -118,15 +118,17 @@ QtObject:
let estimateResult = Json.decode(estimateJson, tuple[estimate: int, uuid: string])
self.gasEstimateReturned(estimateResult.estimate, estimateResult.uuid)
- proc buy*(self: StickersView, packId: int, address: string, price: string, gas: string, gasPrice: string, password: string): string {.slot.} =
+ proc buy*(self: StickersView, packId: int, address: string, price: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string): string {.slot.} =
+ let eip1559Enabled = self.status.wallet.isEIP1559Enabled()
+
try:
- validateTransactionInput(address, address, "", price, gas, gasPrice, "", "ok")
+ validateTransactionInput(address, address, "", price, gas, gasPrice, "", eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, "ok")
except Exception as e:
error "Error buying sticker pack", msg = e.msg
return ""
-
+
var success: bool
- let response = self.status.stickers.buyPack(packId, address, price, gas, gasPrice, password, success)
+ let response = self.status.stickers.buyPack(packId, address, price, gas, gasPrice, eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, password, success)
# TODO:
# check if response["error"] is not null and handle the error
diff --git a/src/app/profile/views/ens_manager.nim b/src/app/profile/views/ens_manager.nim
index f61457fd8b..1eb8d78786 100644
--- a/src/app/profile/views/ens_manager.nim
+++ b/src/app/profile/views/ens_manager.nim
@@ -243,10 +243,11 @@ QtObject:
if not success:
result = 380000
- proc registerENS*(self: EnsManager, username: string, address: string, gas: string, gasPrice: string, password: string): string {.slot.} =
+ proc registerENS*(self: EnsManager, username: string, address: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string): string {.slot.} =
+ let eip1559Enabled = self.status.wallet.isEIP1559Enabled()
var success: bool
let pubKey = self.status.settings.getSetting[:string](Setting.PublicKey, "0x0")
- let response = registerUsername(username, pubKey, address, gas, gasPrice, password, success)
+ let response = registerUsername(username, pubKey, address, gas, gasPrice, eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, password, success)
result = $(%* { "result": %response, "success": %success })
if success:
@@ -282,10 +283,11 @@ QtObject:
if not success:
result = 80000
- proc setPubKey(self: EnsManager, username: string, address: string, gas: string, gasPrice: string, password: string): string {.slot.} =
+ proc setPubKey*(self: EnsManager, username: string, address: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string): string {.slot.} =
+ let eip1559Enabled = self.status.wallet.isEIP1559Enabled()
var success: bool
let pubKey = self.status.settings.getSetting[:string](Setting.PublicKey, "0x0")
- let response = setPubKey(username, pubKey, address, gas, gasPrice, password, success)
+ let response = setPubKey(username, pubKey, address, gas, gasPrice, eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, password, success)
result = $(%* { "result": %response, "success": %success })
if success:
self.transactionWasSent(response)
diff --git a/src/app/wallet/v1/core.nim b/src/app/wallet/v1/core.nim
index 51b8ca7478..39798fb2e4 100644
--- a/src/app/wallet/v1/core.nim
+++ b/src/app/wallet/v1/core.nim
@@ -60,6 +60,8 @@ proc init*(self: WalletController) =
for acc in data.accounts:
self.status.wallet.updateAccount(acc)
self.status.wallet.checkPendingTransactions(acc, data.blockNumber)
+ discard self.status.wallet.isEIP1559Enabled(data.blockNumber)
+ self.status.wallet.setLatestBaseFee(data.baseFeePerGas)
self.view.updateView()
# TODO: show notification
@@ -85,5 +87,9 @@ proc init*(self: WalletController) =
let tx = TransactionMinedArgs(e)
self.view.transactionCompleted(tx.success, tx.transactionHash, tx.revertReason)
-proc checkPendingTransactions*(self: WalletController) =
- self.status.wallet.checkPendingTransactions() # TODO: consider doing this in a threadpool task
+proc onLogin*(self: WalletController) =
+ let blockInfo = getLatestBlock()
+ self.status.wallet.checkPendingTransactions(blockInfo[0]) # TODO: consider doing this in a threadpool task
+ discard self.status.wallet.isEIP1559Enabled(blockInfo[0])
+ self.status.wallet.setLatestBaseFee(blockInfo[1])
+
\ No newline at end of file
diff --git a/src/app/wallet/v1/view.nim b/src/app/wallet/v1/view.nim
index b1fe6154f5..659adf2630 100644
--- a/src/app/wallet/v1/view.nim
+++ b/src/app/wallet/v1/view.nim
@@ -99,6 +99,8 @@ QtObject:
read = getDappBrowserView
proc updateView*(self: WalletView) =
+ self.transactionsView.triggerEIP1559Check()
+
self.balanceView.setTotalFiatBalance(self.status.wallet.getTotalFiatBalance())
self.balanceView.totalFiatBalanceChanged()
diff --git a/src/app/wallet/v1/views/gas.nim b/src/app/wallet/v1/views/gas.nim
index 05bfd0a43e..ea3456da3c 100644
--- a/src/app/wallet/v1/views/gas.nim
+++ b/src/app/wallet/v1/views/gas.nim
@@ -1,9 +1,10 @@
import atomics, strformat, strutils, sequtils, json, std/wrapnils, parseUtils, chronicles, web3/[ethtypes, conversions], stint
-import NimQml, json, sequtils, chronicles, strutils, strformat, json
+import NimQml, json, sequtils, chronicles, strutils, strformat, json, math
import
status/[status, wallet, utils],
- status/types/[gas_prediction]
+ status/types/[gas_prediction],
+ status/libstatus/wallet as status_wallet
import ../../../../app_service/[main]
import ../../../../app_service/tasks/[qt, threadpool]
@@ -17,7 +18,10 @@ type
const getGasPredictionsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let
arg = decode[GasPredictionsTaskArg](argEncoded)
- output = %getGasPricePredictions()
+ response = status_wallet.getGasPrice().parseJson
+ var output = "0"
+ if response.hasKey("result"):
+ output = $fromHex(Stuint[256], response["result"].getStr)
arg.finish(output)
proc getGasPredictions[T](self: T, slot: string) =
@@ -35,10 +39,7 @@ QtObject:
type GasView* = ref object of QObject
status: Status
appService: AppService
- safeLowGasPrice: string
- standardGasPrice: string
- fastGasPrice: string
- fastestGasPrice: string
+ gasPrice: string
defaultGasLimit: string
proc setup(self: GasView) = self.QObject.setup
@@ -48,10 +49,7 @@ QtObject:
new(result, delete)
result.status = status
result.appService = appService
- result.safeLowGasPrice = "0"
- result.standardGasPrice = "0"
- result.fastGasPrice = "0"
- result.fastestGasPrice = "0"
+ result.gasPrice = "0"
result.defaultGasLimit = "21000"
result.setup
@@ -89,39 +87,69 @@ QtObject:
else:
result = $(%* { "result": "-1", "success": %success, "error": { "message": %response } })
- proc gasPricePredictionsChanged*(self: GasView) {.signal.}
+ proc gasPriceChanged*(self: GasView) {.signal.}
- proc getGasPricePredictions*(self: GasView) {.slot.} =
- self.getGasPredictions("getGasPricePredictionsResult")
+ proc getGasPrice*(self: GasView) {.slot.} =
+ if not self.status.wallet.isEIP1559Enabled():
+ self.getGasPredictions("getGasPriceResult")
- proc getGasPricePredictionsResult(self: GasView, gasPricePredictionsJson: string) {.slot.} =
- let prediction = Json.decode(gasPricePredictionsJson, GasPricePrediction)
- self.safeLowGasPrice = fmt"{prediction.safeLow:.3f}"
- self.standardGasPrice = fmt"{prediction.standard:.3f}"
- self.fastGasPrice = fmt"{prediction.fast:.3f}"
- self.fastestGasPrice = fmt"{prediction.fastest:.3f}"
- self.gasPricePredictionsChanged()
+ proc getGasPriceResult(self: GasView, gasPrice: string) {.slot.} =
+ let p = parseFloat(wei2gwei(gasPrice))
+ self.gasPrice = fmt"{p:.3f}"
+ self.gasPriceChanged()
- proc safeLowGasPrice*(self: GasView): string {.slot.} = result = ?.self.safeLowGasPrice
- QtProperty[string] safeLowGasPrice:
- read = safeLowGasPrice
- notify = gasPricePredictionsChanged
-
- proc standardGasPrice*(self: GasView): string {.slot.} = result = ?.self.standardGasPrice
- QtProperty[string] standardGasPrice:
- read = standardGasPrice
- notify = gasPricePredictionsChanged
-
- proc fastGasPrice*(self: GasView): string {.slot.} = result = ?.self.fastGasPrice
- QtProperty[string] fastGasPrice:
- read = fastGasPrice
- notify = gasPricePredictionsChanged
-
- proc fastestGasPrice*(self: GasView): string {.slot.} = result = ?.self.fastestGasPrice
- QtProperty[string] fastestGasPrice:
- read = fastestGasPrice
- notify = gasPricePredictionsChanged
+ proc gasPrice*(self: GasView): string {.slot.} = result = ?.self.gasPrice
+ QtProperty[string] gasPrice:
+ read = gasPrice
+ notify = gasPriceChanged
proc defaultGasLimit*(self: GasView): string {.slot.} = result = ?.self.defaultGasLimit
QtProperty[string] defaultGasLimit:
read = defaultGasLimit
+
+ proc maxPriorityFeePerGas*(self: GasView): string {.slot.} =
+ result = self.status.wallet.maxPriorityFeePerGas()
+ debug "Max priority fee per gas", value=result
+
+ proc suggestedFees*(self: GasView): string {.slot.} =
+ #[
+ 0. priority tip always same, the value returned by eth_maxPriorityFeePerGas
+ 1. slow fee 10th percentile base fee (last 100 blocks) + eth_maxPriorityFeePerGas
+ 2. normal fee.
+ if 20th_percentile <= current_base_fee <= 80th_percentile then fee = current_base_fee + eth_maxPriorityFeePerGas.
+ if current_base_fee < 20th_percentile then fee = 20th_percentile + eth_maxPriorityFeePerGas
+ if current_base_fee > 80th_percentile then fee = 80th_percentile + eth_maxPriorityFeePerGas
+ The idea is to avoid setting too low base fee when price is in a dip and also to avoid overpaying on peak. Specific percentiles can be revisit later, it doesn't need to be symmetric because we are mostly interested in not getting stuck and overpaying might not be a huge issue here.
+ 3. fast fee: current_base_fee + eth_maxPriorityFeePerGas
+ ]#
+
+ let maxPriorityFeePerGas = self.status.wallet.maxPriorityFeePerGas().u256
+ let feeHistory = self.status.wallet.feeHistory(101)
+ let baseFee = self.status.wallet.getLatestBaseFee().u256
+ let gasPrice = self.status.wallet.getGasPrice().u256
+
+ let perc10 = feeHistory[ceil(10/100 * feeHistory.len.float).int - 1]
+ let perc20 = feeHistory[ceil(20/100 * feeHistory.len.float).int - 1]
+ let perc80 = feeHistory[ceil(80/100 * feeHistory.len.float).int - 1]
+
+ let maxFeePerGasM = if baseFee >= perc20 and baseFee <= perc80:
+ baseFee + maxPriorityFeePerGas
+ elif baseFee < perc20:
+ perc20 + maxPriorityFeePerGas
+ else:
+ perc80 + maxPriorityFeePerGas
+
+ result = $(%* {
+ "gasPrice": $gasPrice,
+ "baseFee": parseFloat(wei2gwei($baseFee)),
+ "maxPriorityFeePerGas": parseFloat(wei2gwei($maxPriorityFeePerGas)),
+ "maxFeePerGasL": parseFloat(wei2gwei($(perc10 + maxPriorityFeePerGas))),
+ "maxFeePerGasM": parseFloat(wei2gwei($(maxFeePerGasM))),
+ "maxFeePerGasH": parseFloat(wei2gwei($(baseFee + maxPriorityFeePerGas)))
+ })
+
+ QtProperty[string] maxPriorityFeePerGas:
+ read = maxPriorityFeePerGas
+
+ QtProperty[string] suggestedFees:
+ read = suggestedFees
\ No newline at end of file
diff --git a/src/app/wallet/v1/views/transactions.nim b/src/app/wallet/v1/views/transactions.nim
index 8053d0e984..e866710c0b 100644
--- a/src/app/wallet/v1/views/transactions.nim
+++ b/src/app/wallet/v1/views/transactions.nim
@@ -24,6 +24,9 @@ type
value: string
gas: string
gasPrice: string
+ isEIP1559Enabled: bool
+ maxPriorityFeePerGas: string
+ maxFeePerGas: string
password: string
uuid: string
WatchTransactionTaskArg = ref object of QObjectTaskArg
@@ -35,19 +38,20 @@ const sendTransactionTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
success: bool
response: string
if arg.assetAddress != ZERO_ADDRESS and not arg.assetAddress.isEmptyOrWhitespace:
- response = wallet.sendTokenTransaction(arg.from_addr, arg.to, arg.assetAddress, arg.value, arg.gas, arg.gasPrice, arg.password, success)
+ response = wallet.sendTokenTransaction(arg.from_addr, arg.to, arg.assetAddress, arg.value, arg.gas, arg.gasPrice, arg.isEIP1559Enabled, arg.maxPriorityFeePerGas, arg.maxFeePerGas, arg.password, success)
else:
- response = wallet.sendTransaction(arg.from_addr, arg.to, arg.value, arg.gas, arg.gasPrice, arg.password, success)
+ response = wallet.sendTransaction(arg.from_addr, arg.to, arg.value, arg.gas, arg.gasPrice, arg.isEIP1559Enabled, arg.maxPriorityFeePerGas, arg.maxFeePerGas, arg.password, success)
let output = %* { "result": %response, "success": %success, "uuid": %arg.uuid }
arg.finish(output)
-proc sendTransaction[T](self: T, slot: string, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string, uuid: string) =
+proc sendTransaction[T](self: T, slot: string, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, isEIP1559Enabled: bool, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, uuid: string) =
let arg = SendTransactionTaskArg(
tptr: cast[ByteAddress](sendTransactionTask),
vptr: cast[ByteAddress](self.vptr),
slot: slot, from_addr: from_addr, to: to,
assetAddress: assetAddress, value: value, gas: gas,
- gasPrice: gasPrice, password: password, uuid: uuid
+ gasPrice: gasPrice, password: password, uuid: uuid,
+ isEIP1559Enabled: isEIP1559Enabled, maxPriorityFeePerGas: maxPriorityFeePerGas, maxFeePerGas: maxFeePerGas
)
self.appService.threadpool.start(arg)
@@ -110,23 +114,24 @@ QtObject:
if txHash != "":
self.watchTransaction("transactionWatchResultReceived", txHash)
- proc sendTransaction*(self: TransactionsView, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string, uuid: string) {.slot.} =
- self.sendTransaction("transactionSent", from_addr, to, assetAddress, value, gas, gasPrice, password, uuid)
+ proc sendTransaction*(self: TransactionsView, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string,eip1559Enabled: bool, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, uuid: string) {.slot.} =
+ self.sendTransaction("transactionSent", from_addr, to, assetAddress, value, gas, gasPrice, eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, password, uuid)
-
- proc transferEth*(self: TransactionsView, from_addr: string, to_addr: string, value: string, gas: string, gasPrice: string, password: string, uuid: string): bool {.slot.} =
+ proc transferEth*(self: TransactionsView, from_addr: string, to_addr: string, value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, uuid: string): bool {.slot.} =
try:
- validateTransactionInput(from_addr, to_addr, "", value, gas, gasPrice, "", uuid)
- self.sendTransaction("transactionSent", from_addr, to_addr, ZERO_ADDRESS, value, gas, gasPrice, password, uuid)
+ let eip1559Enabled = self.status.wallet.isEIP1559Enabled()
+ validateTransactionInput(from_addr, to_addr, "", value, gas, gasPrice, "", eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, uuid)
+ self.sendTransaction("transactionSent", from_addr, to_addr, ZERO_ADDRESS, value, gas, gasPrice, eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, password, uuid)
except Exception as e:
error "Error sending eth transfer transaction", msg = e.msg
return false
return true
- proc transferTokens*(self: TransactionsView, from_addr: string, to_addr: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string, uuid: string): bool {.slot.} =
+ proc transferTokens*(self: TransactionsView, from_addr: string, to_addr: string, assetAddress: string, value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, uuid: string): bool {.slot.} =
try:
- validateTransactionInput(from_addr, to_addr, assetAddress, value, gas, gasPrice, "", uuid)
- self.sendTransaction("transactionSent", from_addr, to_addr, assetAddress, value, gas, gasPrice, password, uuid)
+ let eip1559Enabled = self.status.wallet.isEIP1559Enabled()
+ validateTransactionInput(from_addr, to_addr, assetAddress, value, gas, gasPrice, "", eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, uuid)
+ self.sendTransaction("transactionSent", from_addr, to_addr, assetAddress, value, gas, gasPrice, eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, password, uuid)
except Exception as e:
error "Error sending token transfer transaction", msg = e.msg
return false
@@ -146,3 +151,26 @@ QtObject:
discard #TODO: Ask Simon if should we show an error popup indicating the trx wasn't mined in 10m or something
proc transactionCompleted*(self: TransactionsView, success: bool, txHash: string, revertReason: string = "") {.signal.}
+
+ proc triggerEIP1559Check*(self: TransactionsView) {.signal.}
+
+ proc isEIP1559Enabled(self: TransactionsView): bool {.slot.} =
+ return self.status.wallet.isEIP1559Enabled()
+
+ proc getLatestBaseFee(self: TransactionsView): string {.slot.} =
+ var baseFeeWei:string = self.status.wallet.getLatestBaseFee()
+ var baseFeeGwei:string = wei2Gwei(baseFeeWei)
+ var unit:string = "wei"
+ var amount = baseFeeWei
+ if parseFloat(baseFeeGwei) > 1:
+ unit = "gwei"
+ amount = baseFeeGwei
+ return $(%*{"gwei": baseFeeGwei, "amount": amount, "unit": unit})
+
+ QtProperty[bool] isEIP1559Enabled:
+ read = isEIP1559Enabled
+ notify = triggerEIP1559Check
+
+ QtProperty[string] latestBaseFee:
+ read = getLatestBaseFee
+ notify = triggerEIP1559Check
\ No newline at end of file
diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim
index 9db91b2f53..61e9ebcd0a 100644
--- a/src/nim_status_client.nim
+++ b/src/nim_status_client.nim
@@ -198,7 +198,8 @@ proc mainProc() =
utilsController.init()
browserController.init()
node.init()
- wallet.checkPendingTransactions()
+
+ wallet.onLogin()
# this should be the last defer in the scope
defer:
diff --git a/ui/app/AppLayouts/Browser/BrowserLayout.qml b/ui/app/AppLayouts/Browser/BrowserLayout.qml
index 5ae78b2c39..fd7f5765c5 100644
--- a/ui/app/AppLayouts/Browser/BrowserLayout.qml
+++ b/ui/app/AppLayouts/Browser/BrowserLayout.qml
@@ -77,7 +77,7 @@ Rectangle {
}
// TODO we'll need a new dialog at one point because this one is not using the same call, but it's good for now
-property Component sendTransactionModalComponent: SignTransactionModal {}
+ property Component sendTransactionModalComponent: SignTransactionModal {}
property Component signMessageModalComponent: SignMessageModal {}
@@ -190,9 +190,11 @@ property Component sendTransactionModalComponent: SignTransactionModal {}
});
// TODO change sendTransaction function to the postMessage one
- sendDialog.sendTransaction = function (selectedGasLimit, selectedGasPrice, enteredPassword) {
+ sendDialog.sendTransaction = function (selectedGasLimit, selectedGasPrice, selectedTipLimit, selectedOverallLimit, enteredPassword) {
request.payload.selectedGasLimit = selectedGasLimit
request.payload.selectedGasPrice = selectedGasPrice
+ request.payload.selectedTipLimit = selectedTipLimit
+ request.payload.selectedOverallLimit = selectedOverallLimit
request.payload.password = enteredPassword
request.payload.params[0].value = value
@@ -229,7 +231,7 @@ property Component sendTransactionModalComponent: SignTransactionModal {}
}
sendDialog.open();
- walletModel.gasView.getGasPricePredictions()
+ walletModel.gasView.getGasPrice()
} else if (request.type === Constants.web3SendAsyncReadOnly && ["eth_sign", "personal_sign", "eth_signTypedData", "eth_signTypedData_v3"].indexOf(request.payload.method) > -1) {
const signDialog = signMessageModalComponent.createObject(browserWindow, {
request,
@@ -516,6 +518,7 @@ property Component sendTransactionModalComponent: SignTransactionModal {}
anchors.top: parent.top
anchors.topMargin: browserHeader.height
focus: true
+ url: "https://dap.ps"
webChannel: channel
onLinkHovered: function(hoveredUrl) {
if (hoveredUrl === "")
diff --git a/ui/app/AppLayouts/Chat/ChatColumn.qml b/ui/app/AppLayouts/Chat/ChatColumn.qml
index 05bef5ee5c..f2021ef49f 100644
--- a/ui/app/AppLayouts/Chat/ChatColumn.qml
+++ b/ui/app/AppLayouts/Chat/ChatColumn.qml
@@ -498,7 +498,7 @@ Item {
SendModal {
id: sendTransactionWithEns
onOpened: {
- walletModel.gasView.getGasPricePredictions()
+ walletModel.gasView.getGasPrice()
}
onClosed: {
txModalLoader.closed()
@@ -622,8 +622,8 @@ Item {
Connections {
target: chatsModel.stickers
onTransactionWasSent: {
- //% "Transaction pending"
- toastMessage.title = qsTrId("transaction-pending")
+ //% "Transaction pending..."
+ toastMessage.title = qsTr("Transaction pending...")
toastMessage.source = "../../../img/loading.svg"
toastMessage.iconColor = Style.current.primary
toastMessage.iconRotates = true
diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml
index 50bd8168b3..53c1fab790 100644
--- a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml
+++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml
@@ -5,6 +5,7 @@ import QtQuick.Dialogs 1.3
import "../../../../../imports"
import "../../../../../shared"
import "../../../../../shared/status"
+import "../../../Wallet/"
ModalPopup {
property var selectedAccount
@@ -18,7 +19,7 @@ ModalPopup {
property alias transactionSigner: transactionSigner
- property var sendTransaction: function(selectedGasLimit, selectedGasPrice, enteredPassword) {
+ property var sendTransaction: function(selectedGasLimit, selectedGasPrice, selectedTipLimit, selectedOveralLimit, enteredPassword) {
let success = false
if(root.selectedAsset.address == Constants.zeroAddress){
success = walletModel.transactionsView.transferEth(
@@ -26,7 +27,9 @@ ModalPopup {
selectRecipient.selectedRecipient.address,
root.selectedAmount,
selectedGasLimit,
- selectedGasPrice,
+ gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice,
+ gasSelector.selectedTipLimit,
+ gasSelector.selectedOverallLimit,
enteredPassword,
stack.uuid)
} else {
@@ -36,7 +39,9 @@ ModalPopup {
root.selectedAsset.address,
root.selectedAmount,
selectedGasLimit,
- selectedGasPrice,
+ gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice,
+ gasSelector.selectedTipLimit,
+ gasSelector.selectedOverallLimit,
enteredPassword,
stack.uuid)
}
@@ -52,7 +57,7 @@ ModalPopup {
//% "Send"
title: qsTrId("command-button-send")
- height: 504
+ height: 540
property MessageDialog sendingError: MessageDialog {
id: sendingError
@@ -60,7 +65,6 @@ ModalPopup {
title: qsTrId("error-sending-the-transaction")
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
- onAccepted: root.close()
}
onClosed: {
@@ -122,8 +126,7 @@ ModalPopup {
id: groupSelectGas
//% "Network fee"
headerText: qsTrId("network-fee")
- //% "Preview"
- footerText: qsTrId("preview")
+ footerText: qsTr("Continue")
showNextBtn: false
onBackClicked: function() {
stack.pop()
@@ -131,8 +134,7 @@ ModalPopup {
GasSelector {
id: gasSelector
anchors.topMargin: Style.current.bigPadding
- slowestGasPrice: parseFloat(walletModel.gasView.safeLowGasPrice)
- fastestGasPrice: parseFloat(walletModel.gasView.fastestGasPrice)
+ gasPrice: parseFloat(walletModel.gasView.gasPrice)
getGasEthValue: walletModel.gasView.getGasEthValue
getFiatValue: walletModel.balanceView.getFiatValue
defaultCurrency: walletModel.balanceView.defaultCurrency
@@ -144,6 +146,7 @@ ModalPopup {
root.selectedAsset && root.selectedAsset.address &&
root.selectedAmount)) {
selectedGasLimit = 250000
+ defaultGasLimit = selectedGasLimit
return
}
@@ -164,6 +167,7 @@ ModalPopup {
return
}
selectedGasLimit = gasEstimate.result
+ defaultGasLimit = selectedGasLimit
})
}
GasValidator {
@@ -267,6 +271,14 @@ ModalPopup {
stack.back()
}
}
+
+ Component {
+ id: transactionSettingsConfirmationPopupComponent
+ TransactionSettingsConfirmationPopup {
+
+ }
+ }
+
StatusButton {
id: btnNext
anchors.right: parent.right
@@ -279,9 +291,33 @@ ModalPopup {
if (validity.isValid && !validity.isPending) {
if (stack.isLastGroup) {
return root.sendTransaction(gasSelector.selectedGasLimit,
- gasSelector.selectedGasPrice,
+ gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice,
+ gasSelector.selectedTipLimit,
+ gasSelector.selectedOverallLimit,
transactionSigner.enteredPassword)
}
+
+ if(gasSelector.eip1599Enabled && stack.currentGroup === groupSelectGas && gasSelector.advancedMode){
+ if(gasSelector.showPriceLimitWarning || gasSelector.showTipLimitWarning){
+ openPopup(transactionSettingsConfirmationPopupComponent, {
+ currentBaseFee: gasSelector.latestBaseFeeGwei,
+ currentMinimumTip: gasSelector.perGasTipLimitFloor,
+ currentAverageTip: gasSelector.perGasTipLimitAverage,
+ tipLimit: gasSelector.selectedTipLimit,
+ suggestedTipLimit: gasSelector.perGasTipLimitFloor, // TODO:
+ priceLimit: gasSelector.selectedOverallLimit,
+ suggestedPriceLimit: gasSelector.latestBaseFeeGwei + gasSelector.perGasTipLimitFloor,
+ showPriceLimitWarning: gasSelector.showPriceLimitWarning,
+ showTipLimitWarning: gasSelector.showTipLimitWarning,
+ onConfirm: function(){
+ stack.next();
+ }
+ })
+ return
+ }
+ }
+
+
if (typeof stack.currentGroup.onNextClicked === "function") {
return stack.currentGroup.onNextClicked()
}
diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/AcceptTransaction.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/AcceptTransaction.qml
index 010d7bbca1..4a1929b3e1 100644
--- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/AcceptTransaction.qml
+++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/AcceptTransaction.qml
@@ -89,7 +89,7 @@ Item {
id: signTxComponent
SignTransactionModal {
onOpened: {
- walletModel.gasView.getGasPricePredictions()
+ walletModel.gasView.getGasPrice()
}
onClosed: {
destroy();
diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml
index 88b6c21e12..4fbd1b514e 100644
--- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml
+++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml
@@ -46,7 +46,7 @@ Item {
id: signTxComponent
SignTransactionModal {
onOpened: {
- walletModel.gasView.getGasPricePredictions()
+ walletModel.gasView.getGasPrice()
}
onClosed: {
destroy();
diff --git a/ui/app/AppLayouts/Profile/Sections/Ens/Search.qml b/ui/app/AppLayouts/Profile/Sections/Ens/Search.qml
index 8a3b8b0aee..3d8bb2841e 100644
--- a/ui/app/AppLayouts/Profile/Sections/Ens/Search.qml
+++ b/ui/app/AppLayouts/Profile/Sections/Ens/Search.qml
@@ -51,7 +51,7 @@ Item {
id: transactionDialogComponent
StatusETHTransactionModal {
onOpened: {
- walletModel.gasView.getGasPricePredictions()
+ walletModel.gasView.getGasPrice()
}
title: qsTr("Connect username with your pubkey")
onClosed: {
diff --git a/ui/app/AppLayouts/Profile/Sections/Ens/TermsAndConditions.qml b/ui/app/AppLayouts/Profile/Sections/Ens/TermsAndConditions.qml
index c58e894972..9d25dea54a 100644
--- a/ui/app/AppLayouts/Profile/Sections/Ens/TermsAndConditions.qml
+++ b/ui/app/AppLayouts/Profile/Sections/Ens/TermsAndConditions.qml
@@ -39,10 +39,12 @@ Item {
if (username === "" || !selectedAccount) return 380000;
return profileModel.ens.registerENSGasEstimate(username, selectedAccount.address)
}
- onSendTransaction: function(selectedAddress, gasLimit, gasPrice, password) {
+ onSendTransaction: function(selectedAddress, gasLimit, gasPrice, tipLimit, overallLimit, password) {
return profileModel.ens.registerENS(username,
selectedAddress,
gasLimit,
+ tipLimit,
+ overallLimit,
gasPrice,
password)
}
diff --git a/ui/app/AppLayouts/Wallet/SendModal.qml b/ui/app/AppLayouts/Wallet/SendModal.qml
index bfd2e12c19..c63ad319ab 100644
--- a/ui/app/AppLayouts/Wallet/SendModal.qml
+++ b/ui/app/AppLayouts/Wallet/SendModal.qml
@@ -34,7 +34,9 @@ ModalPopup {
selectRecipient.selectedRecipient.address,
txtAmount.selectedAmount,
gasSelector.selectedGasLimit,
- gasSelector.selectedGasPrice,
+ gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice,
+ gasSelector.selectedTipLimit,
+ gasSelector.selectedOverallLimit,
transactionSigner.enteredPassword,
stack.uuid)
} else {
@@ -44,7 +46,9 @@ ModalPopup {
txtAmount.selectedAsset.address,
txtAmount.selectedAmount,
gasSelector.selectedGasLimit,
- gasSelector.selectedGasPrice,
+ gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice,
+ gasSelector.selectedTipLimit,
+ gasSelector.selectedOverallLimit,
transactionSigner.enteredPassword,
stack.uuid)
}
@@ -53,7 +57,6 @@ ModalPopup {
//% "Invalid transaction parameters"
sendingError.text = qsTrId("invalid-transaction-parameters")
sendingError.open()
- root.close()
}
}
@@ -111,7 +114,7 @@ ModalPopup {
//% "Send"
headerText: qsTrId("command-button-send")
//% "Preview"
- footerText: qsTrId("preview")
+ footerText: qsTr("Continue")
AssetAndAmountInput {
id: txtAmount
@@ -127,11 +130,11 @@ ModalPopup {
id: gasSelector
anchors.top: txtAmount.bottom
anchors.topMargin: Style.current.bigPadding * 2
- slowestGasPrice: parseFloat(walletModel.gasView.safeLowGasPrice)
- fastestGasPrice: parseFloat(walletModel.gasView.fastestGasPrice)
+ gasPrice: parseFloat(walletModel.gasView.gasPrice)
getGasEthValue: walletModel.gasView.getGasEthValue
getFiatValue: walletModel.balanceView.getFiatValue
defaultCurrency: walletModel.balanceView.defaultCurrency
+
width: stack.width
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
if (!(selectFromAccount.selectedAccount && selectFromAccount.selectedAccount.address &&
@@ -151,7 +154,9 @@ ModalPopup {
console.warn(qsTrId("error-estimating-gas---1").arg(gasEstimate.error.message))
return
}
+
selectedGasLimit = gasEstimate.result
+ defaultGasLimit = selectedGasLimit
})
}
GasValidator {
@@ -222,6 +227,14 @@ ModalPopup {
stack.back()
}
}
+
+ Component {
+ id: transactionSettingsConfirmationPopupComponent
+ TransactionSettingsConfirmationPopup {
+
+ }
+ }
+
StatusButton {
id: btnNext
anchors.right: parent.right
@@ -235,6 +248,27 @@ ModalPopup {
if (stack.isLastGroup) {
return root.sendTransaction()
}
+
+ if(gasSelector.eip1599Enabled && stack.currentGroup === group2 && gasSelector.advancedMode){
+ if(gasSelector.showPriceLimitWarning || gasSelector.showTipLimitWarning){
+ openPopup(transactionSettingsConfirmationPopupComponent, {
+ currentBaseFee: gasSelector.latestBaseFeeGwei,
+ currentMinimumTip: gasSelector.perGasTipLimitFloor,
+ currentAverageTip: gasSelector.perGasTipLimitAverage,
+ tipLimit: gasSelector.selectedTipLimit,
+ suggestedTipLimit: gasSelector.perGasTipLimitFloor,
+ priceLimit: gasSelector.selectedOverallLimit,
+ suggestedPriceLimit: gasSelector.latestBaseFeeGwei + gasSelector.perGasTipLimitFloor,
+ showPriceLimitWarning: gasSelector.showPriceLimitWarning,
+ showTipLimitWarning: gasSelector.showTipLimitWarning,
+ onConfirm: function(){
+ stack.next();
+ }
+ })
+ return
+ }
+ }
+
stack.next()
}
}
diff --git a/ui/app/AppLayouts/Wallet/TransactionSettingsConfirmationPopup.qml b/ui/app/AppLayouts/Wallet/TransactionSettingsConfirmationPopup.qml
new file mode 100644
index 0000000000..e0f16f5d25
--- /dev/null
+++ b/ui/app/AppLayouts/Wallet/TransactionSettingsConfirmationPopup.qml
@@ -0,0 +1,258 @@
+import QtQuick 2.13
+import QtQuick.Controls 2.13
+import QtQuick.Layouts 1.13
+import "../../../imports"
+import "../../../shared/status"
+import "../../../shared"
+
+ModalPopup {
+ id: popup
+
+ height: 300 + (showPriceLimitWarning ? 65 : 0) + (showTipLimitWarning ? 65 : 0)
+ width: 400
+ title: qsTr("Are you sure?")
+
+ property var onConfirm: function(){}
+
+ property double currentBaseFee: 0
+ property double currentMinimumTip: 0
+ property double currentAverageTip: 0
+ property double tipLimit: 0
+ property double suggestedTipLimit: 0
+ property double priceLimit: 0
+ property double suggestedPriceLimit: 0
+
+ property bool showPriceLimitWarning: false
+ property bool showTipLimitWarning: false
+
+ Column {
+ id: content
+ width: 450
+ height: parent.height
+ spacing: 10
+
+ StyledText {
+ anchors.left: parent.left
+ anchors.leftMargin: Style.current.smallPadding
+ text: qsTr("Your priority fee is below our suggested parameters.")
+ font.pixelSize: 13
+ wrapMode: Text.WordWrap
+ color: Style.current.secondaryText
+ }
+
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: Style.current.smallPadding
+ height: 20
+
+ StyledText {
+ text: qsTr("Current base fee")
+ font.pixelSize: 13
+ width: 190
+ anchors.left: parent.left
+ }
+
+ StyledText {
+ text: qsTr("%1 Gwei").arg(currentBaseFee)
+ font.pixelSize: 13
+ width: 190
+ anchors.right: parent.right
+ }
+ }
+
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: Style.current.smallPadding
+ height: 20
+
+ StyledText {
+ text: qsTr("Current minimum tip")
+ font.pixelSize: 13
+ width: 190
+ anchors.left: parent.left
+ }
+
+ StyledText {
+ text: qsTr("%1 Gwei").arg(currentMinimumTip)
+ font.pixelSize: 13
+ width: 190
+ anchors.right: parent.right
+ }
+ }
+
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: Style.current.smallPadding
+ height: 20
+
+ StyledText {
+ text: qsTr("Current average tip")
+ font.pixelSize: 13
+ width: 190
+ anchors.left: parent.left
+ }
+
+ StyledText {
+ text: qsTr("%1 Gwei").arg(currentAverageTip)
+ font.pixelSize: 13
+ width: 190
+ anchors.right: parent.right
+ }
+ }
+
+ Rectangle {
+ id: tipLimitRect
+ width: 368
+ visible: showTipLimitWarning
+ height: visible ? 70 : 0
+ radius: 8
+ color: Style.current.backgroundHoverLight
+
+ Column {
+ anchors.top: parent.top
+ anchors.topMargin: Style.current.smallPadding
+ anchors.left: parent.left
+ anchors.leftMargin: Style.current.smallPadding
+ height: 100
+ width: 450 - Style.current.smallPadding
+ spacing: 10
+
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 20
+ StyledText {
+ text: qsTr("Your tip limit")
+ font.pixelSize: 13
+ width: 190
+ anchors.left: parent.left
+ color: Style.current.red
+ }
+
+ StyledText {
+ text: qsTr("%1 Gwei").arg(tipLimit)
+ font.pixelSize: 13
+ width: 190
+ anchors.right: parent.right
+ color: Style.current.red
+ }
+ }
+
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 20
+
+ StyledText {
+ text: qsTr("Suggested minimum tip")
+ font.pixelSize: 13
+ width: 190
+ anchors.left: parent.left
+ }
+
+ StyledText {
+ text: qsTr("%1 Gwei").arg(suggestedTipLimit)
+ font.pixelSize: 13
+ width: 190
+ anchors.right: parent.right
+ }
+ }
+ }
+
+ }
+
+ Rectangle {
+ id: minPriceLimitRect
+ width: 368
+ visible: showPriceLimitWarning
+ height: visible ? 70 : 0
+ radius: 8
+ color: Style.current.backgroundHoverLight
+
+ Column {
+ anchors.top: parent.top
+ anchors.topMargin: Style.current.smallPadding
+ anchors.left: parent.left
+ anchors.leftMargin: Style.current.smallPadding
+ height: 100
+ width: 450 - Style.current.smallPadding
+ spacing: 10
+
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 20
+ StyledText {
+ text: qsTr("Your price limit")
+ font.pixelSize: 13
+ width: 190
+ anchors.left: parent.left
+ color: Style.current.red
+ }
+
+ StyledText {
+ text: qsTr("%1 Gwei").arg(priceLimit)
+ font.pixelSize: 13
+ width: 190
+ anchors.right: parent.right
+ color: Style.current.red
+ }
+ }
+
+ Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 20
+
+ StyledText {
+ text: qsTr("Suggested minimum price limit")
+ font.pixelSize: 13
+ width: 190
+ anchors.left: parent.left
+ }
+
+ StyledText {
+ text: qsTr("%1 Gwei").arg(suggestedPriceLimit)
+ font.pixelSize: 13
+ width: 190
+ anchors.right: parent.right
+ }
+ }
+ }
+ }
+
+ }
+
+ footer: Item {
+ id: footerContainer
+ width: parent.width
+
+ StatusButton {
+ id: cancelButton
+ anchors.right: confirmButton.left
+ anchors.rightMargin: Style.current.smallPadding
+ text: qsTr("Change Limit")
+ anchors.bottom: parent.bottom
+ onClicked: popup.destroy()
+ }
+
+ StatusButton {
+ id: confirmButton
+ type: "warn"
+ anchors.right: parent.right
+ anchors.rightMargin: Style.current.smallPadding
+ text: qsTr("Continue anyway")
+ anchors.bottom: parent.bottom
+ onClicked: {
+ popup.onConfirm();
+ popup.destroy();
+ }
+ }
+ }
+}
+
+
+
diff --git a/ui/app/AppMain.qml b/ui/app/AppMain.qml
index 3553d05fcb..585e75ea1e 100644
--- a/ui/app/AppMain.qml
+++ b/ui/app/AppMain.qml
@@ -743,16 +743,15 @@ Item {
}
}
-
-
ToastMessage {
id: toastMessage
}
+
// Add SendModal here as it is used by the Wallet as well as the Browser
Loader {
id: sendModal
active: false
-
+
function open() {
this.active = true
this.item.open()
@@ -763,7 +762,7 @@ Item {
}
sourceComponent: SendModal {
onOpened: {
- walletModel.gasView.getGasPricePredictions()
+ walletModel.gasView.getGasPrice()
}
onClosed: {
sendModal.closed()
diff --git a/ui/shared/GasSelector.qml b/ui/shared/GasSelector.qml
index 2c80aa1969..de4d4b0a7c 100644
--- a/ui/shared/GasSelector.qml
+++ b/ui/shared/GasSelector.qml
@@ -11,14 +11,30 @@ Item {
height: Style.current.smallPadding + prioritytext.height +
(advancedMode ? advancedModeItemGroup.height : selectorButtons.height)
- property double slowestGasPrice: 0
- property double fastestGasPrice: 100
- property double stepSize: ((root.fastestGasPrice - root.slowestGasPrice) / 10).toFixed(1)
+ 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 () {}
property var getGasEthValue: function () {}
property var getFiatValue: function () {}
property string defaultCurrency: "USD"
property alias selectedGasPrice: inputGasPrice.text
property alias selectedGasLimit: inputGasLimit.text
+ property string defaultGasLimit: "0"
+
+
+ property alias selectedTipLimit: inputPerGasTipLimit.text
+ property alias selectedOverallLimit: inputGasPrice.text
+
property double selectedGasEthValue
property double selectedGasFiatValue
//% "Must be greater than 0"
@@ -30,13 +46,26 @@ Item {
property bool isValid: true
readonly property string uuid: Utils.uuid()
- property bool advancedMode: false
+ 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)
+ }
function updateGasEthValue() {
// causes error on application load without this null check
if (!inputGasPrice || !inputGasLimit) {
return
}
+
let ethValue = root.getGasEthValue(inputGasPrice.text, inputGasLimit.text)
let fiatValue = root.getFiatValue(ethValue, "ETH", root.defaultCurrency)
@@ -44,39 +73,114 @@ Item {
selectedGasFiatValue = fiatValue
}
- Component.onCompleted: updateGasEthValue()
+ function appendError(accum, error, nonBlocking = false) {
+ return accum + ` ${error}.`
+ }
+
+
+ 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
+ }
+
+ /* TODO: change these values false once EIP1559 suggestions are revised
+ 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 = `${errorMsg}`
+
+ }
+
+ Component.onCompleted: {
+ updateGasEthValue()
+ checkLimits()
+ }
function validate() {
// causes error on application load without a null check
- if (!inputGasLimit || !inputGasPrice) {
+ if (!inputGasLimit || !inputGasPrice || !inputPerGasTipLimit) {
return
}
+
inputGasLimit.validationError = ""
inputGasPrice.validationError = ""
+ inputPerGasTipLimit.validationError = ""
+
const noInputLimit = inputGasLimit.text === ""
const noInputPrice = inputGasPrice.text === ""
+ const noPerGasTip = inputPerGasTipLimit.text === ""
+
if (noInputLimit) {
inputGasLimit.validationError = root.noInputErrorMessage
}
+
if (noInputPrice) {
inputGasPrice.validationError = root.noInputErrorMessage
}
+
+ if (noPerGasTip) {
+ inputPerGasTipLimit.validationError = root.noInputErrorMessage
+ }
+
if (isNaN(inputGasLimit.text)) {
inputGasLimit.validationError = invalidInputErrorMessage
}
if (isNaN(inputGasPrice.text)) {
inputGasPrice.validationError = invalidInputErrorMessage
}
+
+ if (isNaN(inputPerGasTipLimit.text)) {
+ inputPerGasTipLimit.validationError = invalidInputErrorMessage
+ }
+
let inputLimit = parseFloat(inputGasLimit.text || "0.00")
let inputPrice = parseFloat(inputGasPrice.text || "0.00")
- if (inputLimit <= 0) {
+ let inputTipLimit = parseFloat(inputPerGasTipLimit.text || "0.00")
+
+ if (inputLimit <= 0.00) {
inputGasLimit.validationError = root.greaterThan0ErrorMessage
}
- if (inputPrice <= 0) {
+
+ if (inputPrice <= 0.00) {
inputGasPrice.validationError = root.greaterThan0ErrorMessage
}
- const isValid = inputGasLimit.validationError === "" && inputGasPrice.validationError === ""
- return isValid
+ if (inputTipLimit <= 0.00) {
+ inputPerGasTipLimit.validationError = root.greaterThan0ErrorMessage
+ }
+ const isInputValid = inputGasLimit.validationError === "" && inputGasPrice.validationError === "" && inputPerGasTipLimit.validationError === ""
+ return isInputValid
}
@@ -91,7 +195,20 @@ Item {
color: Style.current.textColor
}
+ 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
+ }
+
StatusButton {
+ visible: false // Change to TRUE once EIP1559 suggestions are revised
id: buttonAdvanced
anchors.verticalCenter: prioritytext.verticalCenter
anchors.right: parent.right
@@ -119,14 +236,25 @@ Item {
GasSelectorButton {
buttonGroup: gasGroup
- //% "Low"
- text: qsTrId("low")
- price: slowestGasPrice
+ text: qsTr("Low")
+ price: {
+ if (!eip1599Enabled) return gasPrice;
+ return formatDec(suggestedFees.maxFeePerGasL, 6)
+ }
gasLimit: inputGasLimit ? inputGasLimit.text : ""
getGasEthValue: root.getGasEthValue
getFiatValue: root.getFiatValue
defaultCurrency: root.defaultCurrency
- onChecked: inputGasPrice.text = price
+ onChecked: {
+ if (eip1599Enabled){
+ inputPerGasTipLimit.text = formatDec(suggestedFees.maxPriorityFeePerGas, 2);
+ inputGasPrice.text = formatDec(suggestedFees.maxFeePerGasL, 2);
+ } else {
+ inputGasPrice.text = price
+ }
+ root.updateGasEthValue()
+ root.checkLimits()
+ }
}
GasSelectorButton {
id: optimalGasButton
@@ -135,28 +263,52 @@ Item {
//% "Optimal"
text: qsTrId("optimal")
price: {
- const price = (fastestGasPrice + slowestGasPrice) / 2
- // Setting the gas price field here because the binding didn't work
- inputGasPrice.text = price
- return price
+ 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)
}
gasLimit: inputGasLimit ? inputGasLimit.text : ""
getGasEthValue: root.getGasEthValue
getFiatValue: root.getFiatValue
defaultCurrency: root.defaultCurrency
- onChecked: inputGasPrice.text = price
+ onChecked: {
+ if (eip1599Enabled){
+ inputPerGasTipLimit.text = formatDec(suggestedFees.maxPriorityFeePerGas, 2);
+ inputGasPrice.text = formatDec(suggestedFees.maxFeePerGasM, 2);
+ } else {
+ inputGasPrice.text = price
+ }
+ root.updateGasEthValue()
+ root.checkLimits()
+ }
}
GasSelectorButton {
buttonGroup: gasGroup
- //% "High"
- text: qsTrId("high")
- price: fastestGasPrice
+ text: qsTr("High")
+ price: {
+ if (!eip1599Enabled) return gasPrice;
+ return formatDec(suggestedFees.maxFeePerGasH,6);
+ }
gasLimit: inputGasLimit ? inputGasLimit.text : ""
getGasEthValue: root.getGasEthValue
getFiatValue: root.getFiatValue
defaultCurrency: root.defaultCurrency
- onChecked: inputGasPrice.text = price
+ onChecked: {
+ if (eip1599Enabled){
+ inputPerGasTipLimit.text = formatDec(suggestedFees.maxPriorityFeePerGas, 2);
+ inputGasPrice.text = formatDec(suggestedFees.maxFeePerGasH, 2);
+ } else {
+ inputGasPrice.text = price
+ }
+ root.updateGasEthValue()
+ root.checkLimits()
+ }
}
}
@@ -173,10 +325,11 @@ Item {
//% "Gas amount limit"
label: qsTrId("gas-amount-limit")
text: "21000"
+ inputLabel.color: Style.current.secondaryText
customHeight: 56
anchors.top: parent.top
anchors.left: parent.left
- anchors.right: inputGasPrice.left
+ anchors.right: eip1599Enabled ? inputPerGasTipLimit.left : inputGasPrice.left
anchors.rightMargin: Style.current.padding
placeholderText: "21000"
validator: IntValidator{
@@ -187,23 +340,59 @@ Item {
onTextChanged: {
if (root.validate()) {
root.updateGasEthValue()
+ 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()
+ }
+ }
+ }
+
+ 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
+ }
+
Input {
id: inputGasPrice
//% "Per-gas overall limit"
label: qsTrId("per-gas-overall-limit")
+ inputLabel.color: Style.current.secondaryText
anchors.top: parent.top
anchors.left: undefined
anchors.right: parent.right
- width: 130
+ width: 125
customHeight: 56
placeholderText: "20"
onTextChanged: {
if (root.validate()) {
root.updateGasEthValue()
+ root.checkLimits()
}
}
}
@@ -220,17 +409,37 @@ Item {
}
StyledText {
- id: maxPriorityFeeText
- //% "Maximum priority fee: %1 ETH"
- text: qsTrId("maximum-priority-fee---1-eth").arg(selectedGasEthValue)
+ id: errorsText
+ text: ""
+ width: parent.width - Style.current.padding
+ visible: text != ""
+ height: visible ? undefined : 0
anchors.top: inputGasLimit.bottom
- anchors.topMargin: 19
+ anchors.topMargin: Style.current.smallPadding + 5
font.pixelSize: 13
+ textFormat: Text.RichText
+ color: Style.current.secondaryText
+ wrapMode: Text.WordWrap
+ }
+
+ StyledText {
+ id: maxPriorityFeeText
+ anchors.left: parent.left
+ //% "Maximum priority fee: %1 ETH"
+ 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
+ font.pixelSize: 13
+ color: Style.current.textColor
}
StyledText {
id: maxPriorityFeeFiatText
- text: `${selectedGasFiatValue} ${root.defaultCurrency}`
+ text: `${selectedGasFiatValue} ${root.defaultCurrency.toUpperCase()}`
anchors.verticalCenter: maxPriorityFeeText.verticalCenter
anchors.left: maxPriorityFeeText.right
anchors.leftMargin: 6
diff --git a/ui/shared/GasSelectorButton.qml b/ui/shared/GasSelectorButton.qml
index 2d8ecf946a..99618f070b 100644
--- a/ui/shared/GasSelectorButton.qml
+++ b/ui/shared/GasSelectorButton.qml
@@ -17,11 +17,17 @@ Rectangle {
property bool checkedByDefault: false
property var getGasEthValue: function () {}
property var getFiatValue: function () {}
+
+
+ function formatDec(num, dec){
+ return Math.round((num + Number.EPSILON) * Math.pow(10, dec)) / Math.pow(10, dec)
+ }
+
property double ethValue: {
if (!gasLimit) {
return 0
}
- return getGasEthValue(price, gasLimit)
+ return formatDec(parseFloat(getGasEthValue(price, gasLimit)), 6)
}
property double fiatValue: getFiatValue(ethValue, "ETH", defaultCurrency)
signal checked()
diff --git a/ui/shared/Input.qml b/ui/shared/Input.qml
index 8833d08755..bad3f154e3 100644
--- a/ui/shared/Input.qml
+++ b/ui/shared/Input.qml
@@ -9,6 +9,8 @@ import "."
Item {
property alias textField: inputValue
+ property alias inputLabel: inputLabel
+
property string placeholderText: "My placeholder"
property string placeholderTextColor: Style.current.secondaryText
property alias text: inputValue.text
diff --git a/ui/shared/status/StatusETHTransactionModal.qml b/ui/shared/status/StatusETHTransactionModal.qml
index 45b17b5b31..e32bfb1ee9 100644
--- a/ui/shared/status/StatusETHTransactionModal.qml
+++ b/ui/shared/status/StatusETHTransactionModal.qml
@@ -5,6 +5,7 @@ import QtQuick.Dialogs 1.3
import "../../imports"
import "../../shared"
import "../../shared/status"
+import "../../app/AppLayouts/Wallet/"
ModalPopup {
id: root
@@ -20,14 +21,17 @@ ModalPopup {
walletModel.gasView.getGasPricePredictions()
}
+ height: 540
function sendTransaction() {
try {
- let responseStr = onSendTransaction(selectFromAccount.selectedAccount.address,
- gasSelector.selectedGasLimit,
- gasSelector.selectedGasPrice,
- transactionSigner.enteredPassword);
-
+ let responseStr = profileModel.ens.setPubKey(root.ensUsername,
+ selectFromAccount.selectedAccount.address,
+ gasSelector.selectedGasLimit,
+ gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice,
+ gasSelector.selectedTipLimit,
+ gasSelector.selectedOverallLimit,
+ transactionSigner.enteredPassword)
let response = JSON.parse(responseStr)
if (!response.success) {
@@ -105,11 +109,11 @@ ModalPopup {
visible: true
anchors.top: selectFromAccount.bottom
anchors.topMargin: Style.current.bigPadding * 2
- slowestGasPrice: parseFloat(walletModel.gasView.safeLowGasPrice)
- fastestGasPrice: parseFloat(walletModel.gasView.fastestGasPrice)
+ gasPrice: parseFloat(walletModel.gasView.gasPrice)
getGasEthValue: walletModel.gasView.getGasEthValue
getFiatValue: walletModel.balanceView.getFiatValue
defaultCurrency: walletModel.balanceView.defaultCurrency
+
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
let estimatedGas = root.estimateGasFunction(selectFromAccount.selectedAccount);
gasSelector.selectedGasLimit = estimatedGas
@@ -168,7 +172,7 @@ ModalPopup {
width: parent.width
height: btnNext.height
- StatusRoundButton {
+ StatusRoundButton {
id: btnBack
anchors.left: parent.left
icon.name: "arrow-right"
@@ -185,6 +189,13 @@ ModalPopup {
}
}
+ Component {
+ id: transactionSettingsConfirmationPopupComponent
+ TransactionSettingsConfirmationPopup {
+
+ }
+ }
+
StatusButton {
id: btnNext
anchors.right: parent.right
@@ -197,6 +208,27 @@ ModalPopup {
if (stack.isLastGroup) {
return root.sendTransaction()
}
+
+ if(gasSelector.eip1599Enabled && stack.currentGroup === group2 && gasSelector.advancedMode){
+ if(gasSelector.showPriceLimitWarning || gasSelector.showTipLimitWarning){
+ openPopup(transactionSettingsConfirmationPopupComponent, {
+ currentBaseFee: gasSelector.latestBaseFeeGwei,
+ currentMinimumTip: gasSelector.perGasTipLimitFloor,
+ currentAverageTip: gasSelector.perGasTipLimitAverage,
+ tipLimit: gasSelector.selectedTipLimit,
+ suggestedTipLimit: gasSelector.perGasTipLimitFloor,
+ priceLimit: gasSelector.selectedOverallLimit,
+ suggestedPriceLimit: gasSelector.latestBaseFeeGwei + gasSelector.perGasTipLimitFloor,
+ showPriceLimitWarning: gasSelector.showPriceLimitWarning,
+ showTipLimitWarning: gasSelector.showTipLimitWarning,
+ onConfirm: function(){
+ stack.next();
+ }
+ })
+ return
+ }
+ }
+
stack.next()
}
}
diff --git a/ui/shared/status/StatusSNTTransactionModal.qml b/ui/shared/status/StatusSNTTransactionModal.qml
index ee270eed24..3ac3f68ebd 100644
--- a/ui/shared/status/StatusSNTTransactionModal.qml
+++ b/ui/shared/status/StatusSNTTransactionModal.qml
@@ -5,6 +5,7 @@ import QtQuick.Dialogs 1.3
import "../../imports"
import "../../shared"
import "../../shared/status"
+import "../../app/AppLayouts/Wallet/"
ModalPopup {
id: root
@@ -12,13 +13,15 @@ ModalPopup {
property string assetPrice
property string contractAddress
property var estimateGasFunction: (function(userAddress, uuid) { return 0; })
- property var onSendTransaction: (function(userAddress, gasLimit, gasPrice, password){ return ""; })
+ property var onSendTransaction: (function(userAddress, gasLimit, gasPrice, tipLimit, overallLimit, password){ return ""; })
property var onSuccess: (function(){})
Component.onCompleted: {
- walletModel.gasView.getGasPricePredictions()
+ walletModel.gasView.getGasPrice()
}
+ height: 540
+
//% "Authorize %1 %2"
title: qsTrId("authorize--1--2").arg(Utils.stripTrailingZeros(assetPrice)).arg(asset.symbol)
@@ -33,13 +36,16 @@ ModalPopup {
function setAsyncGasLimitResult(uuid, value) {
if (uuid === gasSelector.uuid) {
gasSelector.selectedGasLimit = value
+ gasSelector.defaultGasLimit = value
}
}
function sendTransaction() {
let responseStr = onSendTransaction(selectFromAccount.selectedAccount.address,
gasSelector.selectedGasLimit,
- gasSelector.selectedGasPrice,
+ gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice,
+ gasSelector.selectedTipLimit,
+ gasSelector.selectedOverallLimit,
transactionSigner.enteredPassword);
let response = JSON.parse(responseStr)
@@ -108,12 +114,12 @@ ModalPopup {
id: gasSelector
anchors.top: selectFromAccount.bottom
anchors.topMargin: Style.current.bigPadding * 2
- slowestGasPrice: parseFloat(walletModel.gasView.safeLowGasPrice)
- fastestGasPrice: parseFloat(walletModel.gasView.fastestGasPrice)
+ gasPrice: parseFloat(walletModel.gasView.gasPrice)
getGasEthValue: walletModel.gasView.getGasEthValue
getFiatValue: walletModel.balanceView.getFiatValue
defaultCurrency: walletModel.balanceView.defaultCurrency
width: stack.width
+
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
let estimatedGas = root.estimateGasFunction(selectFromAccount.selectedAccount, uuid);
gasSelector.selectedGasLimit = estimatedGas
@@ -190,6 +196,14 @@ ModalPopup {
stack.back()
}
}
+
+ Component {
+ id: transactionSettingsConfirmationPopupComponent
+ TransactionSettingsConfirmationPopup {
+
+ }
+ }
+
StatusButton {
id: btnNext
anchors.right: parent.right
@@ -203,6 +217,27 @@ ModalPopup {
if (stack.isLastGroup) {
return root.sendTransaction()
}
+
+ if(gasSelector.eip1599Enabled && stack.currentGroup === group2 && gasSelector.advancedMode){
+ if(gasSelector.showPriceLimitWarning || gasSelector.showTipLimitWarning){
+ openPopup(transactionSettingsConfirmationPopupComponent, {
+ currentBaseFee: gasSelector.latestBaseFeeGwei,
+ currentMinimumTip: gasSelector.perGasTipLimitFloor,
+ currentAverageTip: gasSelector.perGasTipLimitAverage,
+ tipLimit: gasSelector.selectedTipLimit,
+ suggestedTipLimit: gasSelector.perGasTipLimitFloor, // TODO:
+ priceLimit: gasSelector.selectedOverallLimit,
+ suggestedPriceLimit: gasSelector.latestBaseFeeGwei + gasSelector.perGasTipLimitFloor,
+ showPriceLimitWarning: gasSelector.showPriceLimitWarning,
+ showTipLimitWarning: gasSelector.showTipLimitWarning,
+ onConfirm: function(){
+ stack.next();
+ }
+ })
+ return
+ }
+ }
+
stack.next()
}
}
diff --git a/ui/shared/status/StatusStickerMarket.qml b/ui/shared/status/StatusStickerMarket.qml
index 87162e496f..5adab84031 100644
--- a/ui/shared/status/StatusStickerMarket.qml
+++ b/ui/shared/status/StatusStickerMarket.qml
@@ -98,12 +98,14 @@ Item {
if (packId < 0 || !selectedAccount || !price) return 325000
return chatsModel.stickers.estimate(packId, selectedAccount.address, price, uuid)
}
- onSendTransaction: function(selectedAddress, gasLimit, gasPrice, password) {
+ onSendTransaction: function(selectedAddress, gasLimit, gasPrice, tipLimit, overallLimit, password) {
return chatsModel.stickers.buy(packId,
selectedAddress,
price,
gasLimit,
gasPrice,
+ tipLimit,
+ overallLimit,
password)
}
onClosed: {
diff --git a/ui/shared/status/StatusStickerPackClickPopup.qml b/ui/shared/status/StatusStickerPackClickPopup.qml
index 4f9350f930..248c5dcf00 100644
--- a/ui/shared/status/StatusStickerPackClickPopup.qml
+++ b/ui/shared/status/StatusStickerPackClickPopup.qml
@@ -60,12 +60,14 @@ ModalPopup {
if (packId < 0 || !selectedAccount || !price) return 325000
return chatsModel.stickers.estimate(packId, selectedAccount.address, price, uuid)
}
- onSendTransaction: function(selectedAddress, gasLimit, gasPrice, password) {
+ onSendTransaction: function(selectedAddress, gasLimit, gasPrice, tipLimit, overallLimit, password) {
return chatsModel.stickers.buy(packId,
selectedAddress,
price,
gasLimit,
gasPrice,
+ tipLimit,
+ overallLimit,
password)
}
onClosed: {
diff --git a/vendor/status-lib b/vendor/status-lib
index efe2790db6..c1d61a13c0 160000
--- a/vendor/status-lib
+++ b/vendor/status-lib
@@ -1 +1 @@
-Subproject commit efe2790db6cf5e3f01d4b3265d2a671fed70e2d1
+Subproject commit c1d61a13c0592e83083161e4b6d5b2e126a8a424