fix(@desktop/wallet): estimated time for transaction is always Unknown

Fixes #5938
This commit is contained in:
Sale Djenic 2022-06-02 19:47:42 +02:00 committed by Iuri Matias
parent 2251f870a0
commit 60ed62231e
12 changed files with 134 additions and 8 deletions

View File

@ -105,4 +105,7 @@ proc getChainIdForChat*(self: Controller): int =
return self.networkService.getNetworkForChat().chainId
proc getChainIdForBrowser*(self: Controller): int =
return self.networkService.getNetworkForBrowser().chainId
return self.networkService.getNetworkForBrowser().chainId
proc getEstimatedTime*(self: Controller, priorityFeePerGas: string, maxFeePerGas: string): EstimatedTime =
return self.transactionService.getEstimatedTime(priorityFeePerGas, maxFeePerGas)

View File

@ -64,6 +64,9 @@ method getChainIdForChat*(self: AccessInterface): int =
method getChainIdForBrowser*(self: AccessInterface): int =
raise newException(ValueError, "No implementation available")
method getEstimatedTime*(self: AccessInterface, priorityFeePerGas: string, maxFeePerGas: string): int {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface
# Delegate for the view must be declared here due to use of QtObject and multi
# inheritance, which is not well supported in Nim.

View File

@ -109,4 +109,7 @@ method getChainIdForChat*(self: Module): int =
return self.controller.getChainIdForChat()
method getChainIdForBrowser*(self: Module): int =
return self.controller.getChainIdForBrowser()
return self.controller.getChainIdForBrowser()
method getEstimatedTime*(self: Module, priorityFeePerGas: string, maxFeePerGas: string): int =
return self.controller.getEstimatedTime(priorityFeePerGas, maxFeePerGas).int

View File

@ -139,4 +139,7 @@ QtObject:
return self.delegate.getChainIdForChat()
proc getChainIdForBrowser*(self: View): int {.slot.} =
return self.delegate.getChainIdForBrowser()
return self.delegate.getChainIdForBrowser()
proc getEstimatedTime*(self: View, priorityFeePerGas: string, maxFeePerGas: string): int {.slot.} =
return self.delegate.getEstimatedTime(priorityFeePerGas, maxFeePerGas)

View File

@ -33,6 +33,13 @@ include ../../common/json_utils
const SIGNAL_TRANSACTIONS_LOADED* = "transactionsLoaded"
const SIGNAL_TRANSACTION_SENT* = "transactionSent"
type
EstimatedTime* {.pure.} = enum
Unknown = -1
LessThanOneMin
LessThanThreeMins
LessThanFiveMins
type
TransactionMinedArgs* = ref object of Args
data*: string
@ -394,3 +401,69 @@ QtObject:
except Exception as e:
error "Error fetching crypto services", message = e.msg
return @[]
proc addToAllTransactionsAndSetNewMinMax(self: Service, myTip: float, numOfTransactionWithTipLessThanMine: var int,
transactions: JsonNode) =
if transactions.kind != JArray:
return
for t in transactions:
let gasPriceUnparsed = $fromHex(Stuint[256], t{"gasPrice"}.getStr)
let gasPrice = parseFloat(wei2gwei(gasPriceUnparsed))
if gasPrice < myTip:
numOfTransactionWithTipLessThanMine.inc
proc getEstimatedTime*(self: Service, priorityFeePerGas: string, maxFeePerGas: string): EstimatedTime =
let priorityFeePerGasF = priorityFeePerGas.parseFloat
let maxFeePerGasF = maxFeePerGas.parseFloat
var transactionsProcessed = 0
var numOfTransactionWithTipLessThanMine = 0
var latestBlockNumber: Option[Uint256]
var expectedBaseFeeForNextBlock: float
try:
let response = eth.getBlockByNumber("latest", true)
if response.error.isNil:
let transactionsJson = response.result{"transactions"}
self.addToAllTransactionsAndSetNewMinMax(priorityFeePerGasF, numOfTransactionWithTipLessThanMine, transactionsJson)
transactionsProcessed = transactionsJson.len
latestBlockNumber = some(stint.fromHex(Uint256, response.result{"number"}.getStr))
let latestBlockBaseFeePerGasUnparsed = $fromHex(Stuint[256], response.result{"baseFeePerGas"}.getStr)
let latestBlockBaseFeePerGas = parseFloat(wei2gwei(latestBlockBaseFeePerGasUnparsed))
let latestBlockGasUsedUnparsed = $fromHex(Stuint[256], response.result{"gasUsed"}.getStr)
let latestBlockGasUsed = parseFloat(wei2gwei(latestBlockGasUsedUnparsed))
let latestBlockGasLimitUnparsed = $fromHex(Stuint[256], response.result{"gasLimit"}.getStr)
let latestBlockGasLimit = parseFloat(wei2gwei(latestBlockGasLimitUnparsed))
let ratio = latestBlockGasUsed / latestBlockGasLimit * 0.01
let maxFeeChange = latestBlockBaseFeePerGas * 0.125
if(ratio > 50):
expectedBaseFeeForNextBlock = latestBlockBaseFeePerGas + maxFeeChange * (ratio - 50) * 0.01
else:
expectedBaseFeeForNextBlock = latestBlockBaseFeePerGas - maxFeeChange * (50 - ratio) * 0.01
except Exception as e:
error "error fetching latest block", msg=e.msg
if latestBlockNumber.isNone or
priorityFeePerGasF + expectedBaseFeeForNextBlock > maxFeePerGasF:
return EstimatedTime.Unknown
var blockNumber = latestBlockNumber.get
while (transactionsProcessed < 100 and latestBlockNumber.get < blockNumber + 10):
blockNumber = blockNumber - 1
try:
let hexPrevNum = "0x" & stint.toHex(blockNumber)
let response = getBlockByNumber(hexPrevNum, true)
let transactionsJson = response.result{"transactions"}
self.addToAllTransactionsAndSetNewMinMax(priorityFeePerGasF, numOfTransactionWithTipLessThanMine, transactionsJson)
transactionsProcessed += transactionsJson.len
except Exception as e:
error "error fetching block number", blockNumber=blockNumber, msg=e.msg
let p = numOfTransactionWithTipLessThanMine / transactionsProcessed
if p > 0.5:
return EstimatedTime.LessThanOneMin
elif p > 0.35:
return EstimatedTime.LessThanThreeMins
elif p > 0.15:
return EstimatedTime.LessThanFiveMins
else:
return EstimatedTime.Unknown

View File

@ -6,8 +6,8 @@ export response_type
proc getAccounts*(): RpcResponse[JsonNode] {.raises: [Exception].} =
return core.callPrivateRPC("eth_accounts")
proc getBlockByNumber*(blockNumber: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [blockNumber, false]
proc getBlockByNumber*(blockNumber: string, fullTransactionObject = false): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [blockNumber, fullTransactionObject]
return core.callPrivateRPC("eth_getBlockByNumber", payload)
proc getNativeChainBalance*(chainId: int, address: string): RpcResponse[JsonNode] {.raises: [Exception].} =

View File

@ -99,6 +99,10 @@ QtObject {
return JSON.parse(walletSectionTransactions.suggestedFees(chainId))
}
function getEstimatedTime(priorityFeePerGas, maxFeePerGas) {
return walletSectionTransactions.getEstimatedTime(priorityFeePerGas, maxFeePerGas)
}
function getChainIdForChat() {
return walletSectionTransactions.getChainIdForChat()
}

View File

@ -21,11 +21,13 @@ Item {
property var getGasGweiValue: function () {}
property var getGasEthValue: function () {}
property var getFiatValue: function () {}
property var getEstimatedTime: function () {}
property string defaultCurrency: "USD"
property alias selectedGasPrice: inputGasPrice.text
property alias selectedGasLimit: inputGasLimit.text
property string defaultGasLimit: "0"
property string maxFiatFees: selectedGasFiatValue + root.defaultCurrency.toUpperCase()
property int estimatedTxTimeFlag: Constants.transactionEstimatedTime.unknown
property alias selectedTipLimit: inputPerGasTipLimit.text
@ -62,11 +64,15 @@ Item {
return
}
Qt.callLater(function () {
let ethValue = root.getGasEthValue(inputGasPrice.text, inputGasLimit.text)
let fiatValue = root.getFiatValue(ethValue, "ETH", root.defaultCurrency)
selectedGasEthValue = ethValue
selectedGasFiatValue = fiatValue
root.estimatedTxTimeFlag = root.getEstimatedTime(inputPerGasTipLimit.text, inputGasPrice.text)
})
}
function appendError(accum, error, nonBlocking = false) {
@ -111,6 +117,11 @@ Item {
}
}
Component.onCompleted: {
updateGasEthValue()
checkLimits()
}
function validate() {
// causes error on application load without a null check
if (!inputGasLimit || !inputGasPrice || !inputPerGasTipLimit) {

View File

@ -176,6 +176,7 @@ StatusModal {
anchors.top: networkSelector.bottom
getGasEthValue: popup.store.getGasEthValue
getFiatValue: popup.store.getFiatValue
getEstimatedTime: popup.store.getEstimatedTime
defaultCurrency: popup.store.currentCurrency
width: stack.width
@ -239,6 +240,7 @@ StatusModal {
advancedFooterComponent: SendModalFooter {
maxFiatFees: gasSelector.maxFiatFees
estimatedTxTimeFlag: gasSelector.estimatedTxTimeFlag
currentGroupPending: popup.contentItem.currentGroup.isPending
currentGroupValid: popup.contentItem.currentGroup.isValid
isLastGroup: popup.contentItem.isLastGroup

View File

@ -12,15 +12,18 @@ import StatusQ.Core.Theme 0.1
Rectangle {
id: footer
//% "Unknown"
property string estimatedTime: qsTr("Unknown")
property string maxFiatFees: ""
property int estimatedTxTimeFlag: Constants.transactionEstimatedTime.unknown
property bool currentGroupPending: true
property bool currentGroupValid: false
property bool isLastGroup: false
signal nextButtonClicked()
onEstimatedTxTimeFlagChanged: {
estimatedTime.text = Utils.getLabelForEstimatedTxTime(estimatedTxTimeFlag)
}
width: parent.width
height: 82
radius: 8
@ -55,9 +58,9 @@ Rectangle {
}
// To-do not implemented yet
StatusBaseText {
id: estimatedTime
font.pixelSize: 15
color: Theme.palette.directColor1
text: estimatedTime
wrapMode: Text.WordWrap
}
}
@ -79,6 +82,7 @@ Rectangle {
wrapMode: Text.WordWrap
}
StatusBaseText {
id: fiatFees
font.pixelSize: 15
color: Theme.palette.directColor1
text: maxFiatFees

View File

@ -189,6 +189,13 @@ QtObject {
readonly property int success: 1
}
readonly property QtObject transactionEstimatedTime: QtObject {
readonly property int unknown: -1
readonly property int lessThanOneMin: 0
readonly property int lessThanThreeMins: 1
readonly property int lessThanFiveMins: 2
}
readonly property int communityImported: 0
readonly property int communityImportingInProgress: 1
readonly property int communityImportingError: 2

View File

@ -618,6 +618,19 @@ QtObject {
/* Validation section end */
function getLabelForEstimatedTxTime(estimatedFlag) {
if (estimatedFlag === Constants.transactionEstimatedTime.lessThanOneMin) {
return qsTr("< 1 min")
}
if (estimatedFlag === Constants.transactionEstimatedTime.lessThanThreeMins) {
return qsTr("< 3 mins")
}
if (estimatedFlag === Constants.transactionEstimatedTime.lessThanFiveMins) {
return qsTr("< 5 mins")
}
return qsTr("> 5 mins")
}
function getContactDetailsAsJson(publicKey) {
let jsonObj = mainModule.getContactDetailsAsJson(publicKey)