feat(dapps): show estimated time for dApps requests
Implemented using the fees from the transaction data sent by the dApp. Also fixed the nim status go wrapper to send proper formatted string as expected on the other side. Updates: #15192
This commit is contained in:
parent
be1c6ba2ad
commit
4deea3461f
|
@ -168,7 +168,7 @@ proc newModule*(
|
|||
result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events)
|
||||
result.filter = initFilter(result.controller)
|
||||
|
||||
result.walletConnectService = wc_service.newService(result.events, result.threadpool, settingsService)
|
||||
result.walletConnectService = wc_service.newService(result.events, result.threadpool, settingsService, transactionService)
|
||||
result.walletConnectController = wc_controller.newController(result.walletConnectService, walletAccountService)
|
||||
|
||||
result.view = newView(result, result.activityController, result.tmpActivityControllers, result.activityDetailsController, result.collectibleDetailsController, result.walletConnectController)
|
||||
|
|
|
@ -70,3 +70,6 @@ QtObject:
|
|||
|
||||
proc sendTransaction*(self: Controller, address: string, chainId: int, password: string, txJson: string): string {.slot.} =
|
||||
return self.service.sendTransaction(address, chainId, password, txJson)
|
||||
|
||||
proc getEstimatedTimeMinutesInterval(self: Controller, chainId: int, maxFeePerGas: string): int {.slot.} =
|
||||
return self.service.getEstimatedTimeMinutesInterval(chainId, maxFeePerGas).int
|
|
@ -632,7 +632,7 @@ QtObject:
|
|||
|
||||
proc getEstimatedTime*(self: Service, chainId: int, maxFeePerGas: string): EstimatedTime =
|
||||
try:
|
||||
let response = backend.getTransactionEstimatedTime(chainId, maxFeePerGas.parseFloat).result.getInt
|
||||
let response = backend.getTransactionEstimatedTime(chainId, maxFeePerGas).result.getInt
|
||||
return EstimatedTime(response)
|
||||
except Exception as e:
|
||||
error "Error estimating transaction time", message = e.msg
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import NimQml, chronicles, times, json
|
||||
import strutils
|
||||
|
||||
import backend/wallet_connect as status_go
|
||||
import backend/wallet
|
||||
|
@ -6,6 +7,7 @@ import backend/wallet
|
|||
import app_service/service/settings/service as settings_service
|
||||
import app_service/common/wallet_constants
|
||||
from app_service/service/transaction/dto import PendingTransactionTypeDto
|
||||
import app_service/service/transaction/service as tr
|
||||
|
||||
import app/global/global_singleton
|
||||
|
||||
|
@ -30,6 +32,7 @@ QtObject:
|
|||
events: EventEmitter
|
||||
threadpool: ThreadPool
|
||||
settingsService: settings_service.Service
|
||||
transactions: tr.Service
|
||||
|
||||
authenticationCallback: AuthenticationResponseFn
|
||||
|
||||
|
@ -40,6 +43,7 @@ QtObject:
|
|||
events: EventEmitter,
|
||||
threadpool: ThreadPool,
|
||||
settingsService: settings_service.Service,
|
||||
transactions: tr.Service,
|
||||
): Service =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
|
@ -47,6 +51,7 @@ QtObject:
|
|||
result.events = events
|
||||
result.threadpool = threadpool
|
||||
result.settingsService = settings_service
|
||||
result.transactions = transactions
|
||||
|
||||
proc init*(self: Service) =
|
||||
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
|
||||
|
@ -202,3 +207,7 @@ QtObject:
|
|||
return ""
|
||||
|
||||
return txResponse.getStr
|
||||
|
||||
proc getEstimatedTimeMinutesInterval*(self: Service, chainId: int, maxFeePerGas: string): EstimatedTime =
|
||||
let maxFeePerGasInt = parseHexInt(maxFeePerGas)
|
||||
return self.transactions.getEstimatedTime(chainId, $(maxFeePerGasInt.float))
|
||||
|
|
|
@ -156,7 +156,7 @@ rpc(startWallet, "wallet"):
|
|||
|
||||
rpc(getTransactionEstimatedTime, "wallet"):
|
||||
chainId: int
|
||||
maxFeePerGas: float
|
||||
maxFeePerGas: string
|
||||
|
||||
rpc(fetchPrices, "wallet"):
|
||||
symbols: seq[string]
|
||||
|
|
|
@ -20,6 +20,7 @@ import Storybook 1.0
|
|||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
import AppLayouts.Wallet.services.dapps 1.0
|
||||
import AppLayouts.Wallet.services.dapps.types 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
|
@ -331,7 +332,6 @@ Item {
|
|||
return true
|
||||
}
|
||||
|
||||
|
||||
function getDapps() {
|
||||
let dappsJson = JSON.stringify(d.persistedDapps)
|
||||
this.dappsListReceived(dappsJson)
|
||||
|
@ -373,6 +373,10 @@ Item {
|
|||
console.info(`calling mocked DAppsStore.sendTransaction(${topic}, ${id}, ${address}, ${chainId}, ${password}, ${tx})`)
|
||||
return "0xf8672a8402fb7acf82520894e2d622c817878da5143bbe068"
|
||||
}
|
||||
|
||||
function getEstimatedTime(chainId, maxFeePerGas) {
|
||||
return Constants.TransactionEstimatedTime.LessThanThreeMins
|
||||
}
|
||||
}
|
||||
|
||||
walletRootStore: QObject {
|
||||
|
|
|
@ -5,12 +5,13 @@ import QtQuick.Layouts 1.15
|
|||
import StatusQ 0.1
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Wallet 1.0
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
|
||||
import shared.popups.walletconnect 1.0
|
||||
import AppLayouts.Wallet.services.dapps 1.0
|
||||
import AppLayouts.Wallet.services.dapps.types 1.0
|
||||
|
||||
import shared.popups.walletconnect 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
DappsComboBox {
|
||||
|
@ -119,6 +120,7 @@ DappsComboBox {
|
|||
property SessionRequestResolved request: null
|
||||
|
||||
sourceComponent: DAppSignRequestModal {
|
||||
id: dappRequestModal
|
||||
objectName: "dappsRequestModal"
|
||||
loginType: request.account.migragedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||
visible: true
|
||||
|
@ -138,7 +140,7 @@ DappsComboBox {
|
|||
currentCurrency: ""
|
||||
fiatFees: request.maxFeesText
|
||||
cryptoFees: request.maxFeesEthText
|
||||
estimatedTime: request.estimatedTimeText
|
||||
estimatedTime: ""
|
||||
feesLoading: !request.maxFeesText || !request.maxFeesEthText
|
||||
hasFees: signingTransaction
|
||||
enoughFundsForTransaction: request.enoughFunds
|
||||
|
@ -199,14 +201,16 @@ DappsComboBox {
|
|||
} catch (e) {
|
||||
// ignore error in case of tests and storybook where we don't have access to globalUtils
|
||||
}
|
||||
|
||||
cryptoFees = ethStr
|
||||
enoughFundsForTransaction = haveEnoughFunds
|
||||
enoughFundsForFees = haveEnoughFunds
|
||||
feesLoading = false
|
||||
hasFees = !!maxFees
|
||||
}
|
||||
function onEstimatedTimeUpdated(minMinutes, maxMinutes) {
|
||||
estimatedTime = qsTr("%1-%2mins").arg(minMinutes).arg(maxMinutes)
|
||||
|
||||
function onEstimatedTimeUpdated(estimatedTimeEnum) {
|
||||
dappRequestModal.estimatedTime = WalletUtils.getLabelForEstimatedTxTime(estimatedTimeEnum)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ QObject {
|
|||
signal displayToastMessage(string message, bool error)
|
||||
signal sessionRequestResult(/*model entry of SessionRequestResolved*/ var request, bool isSuccess)
|
||||
signal maxFeesUpdated(real maxFees, int maxFeesWei, bool haveEnoughFunds, string symbol)
|
||||
signal estimatedTimeUpdated(int minMinutes, int maxMinutes)
|
||||
// Reports Constants.TransactionEstimatedTime values
|
||||
signal estimatedTimeUpdated(int estimatedTimeEnum)
|
||||
|
||||
Connections {
|
||||
target: sdk
|
||||
|
@ -138,7 +139,6 @@ QObject {
|
|||
maxFeesText: "?",
|
||||
maxFeesEthText: "?",
|
||||
enoughFunds: false,
|
||||
estimatedTimeText: "?"
|
||||
})
|
||||
if (obj === null) {
|
||||
console.error("Error creating SessionRequestResolved for event")
|
||||
|
@ -158,20 +158,21 @@ QObject {
|
|||
}
|
||||
obj.resolveDappInfoFromSession(session)
|
||||
root.sessionRequest(obj)
|
||||
|
||||
let estimatedTimeEnum = getEstimatedTimeInterval(data, method, obj.network.chainId)
|
||||
root.estimatedTimeUpdated(estimatedTimeEnum)
|
||||
|
||||
// TODO #15192: update maxFees
|
||||
if (!event.params.request.params[0].gasLimit || !event.params.request.params[0].gasPrice) {
|
||||
root.maxFeesUpdated(0, 0, true, "")
|
||||
root.estimatedTimeUpdated(0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
let gasLimit = parseFloat(parseInt(event.params.request.params[0].gasLimit, 16));
|
||||
let gasPrice = parseFloat(parseInt(event.params.request.params[0].gasPrice, 16));
|
||||
let maxFees = gasLimit * gasPrice
|
||||
root.maxFeesUpdated(maxFees/1000000000, maxFees, true, "Gwei")
|
||||
// TODO #15192: update estimatedTime
|
||||
root.estimatedTimeUpdated(1, 12)
|
||||
|
||||
})
|
||||
|
||||
return obj
|
||||
|
@ -320,6 +321,34 @@ QObject {
|
|||
console.error("No password or pin provided to sign message")
|
||||
}
|
||||
}
|
||||
|
||||
// Returns Constants.TransactionEstimatedTime
|
||||
function getEstimatedTimeInterval(data, method, chainId) {
|
||||
if (method != SessionRequest.methods.signTransaction.name
|
||||
&& method != SessionRequest.methods.sendTransaction.name)
|
||||
{
|
||||
return ""
|
||||
}
|
||||
|
||||
var tx = {}
|
||||
if (method === SessionRequest.methods.signTransaction.name) {
|
||||
tx = SessionRequest.methods.signTransaction.getTxObjFromData(data)
|
||||
} else if (method === SessionRequest.methods.sendTransaction.name) {
|
||||
tx = SessionRequest.methods.sendTransaction.getTxObjFromData(data)
|
||||
}
|
||||
|
||||
var maxFeePerGas = ""
|
||||
if (!!tx.maxFeePerGas) {
|
||||
maxFeePerGas = tx.maxFeePerGas
|
||||
} else if (!!tx.gasPrice) {
|
||||
maxFeePerGas = tx.gasPrice
|
||||
}
|
||||
if (!maxFeePerGas) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return root.store.getEstimatedTime(chainId, maxFeePerGas)
|
||||
}
|
||||
}
|
||||
|
||||
/// The queue is used to ensure that the events are processed in the order they are received but they could be
|
||||
|
|
|
@ -5,6 +5,7 @@ import QtQml 2.15
|
|||
import utils 1.0
|
||||
|
||||
QtObject {
|
||||
|
||||
/// Supported methods
|
||||
/// userString is used in the context `dapp.url #{userString} <accepted/rejected>`
|
||||
/// requestDisplay is used in the context `dApp wants you to ${requestDisplay} with <Account Name Here>`
|
||||
|
|
|
@ -31,7 +31,6 @@ QObject {
|
|||
readonly property string maxFeesText: ""
|
||||
readonly property string maxFeesEthText: ""
|
||||
readonly property bool enoughFunds: false
|
||||
readonly property string estimatedTimeText: ""
|
||||
|
||||
function resolveDappInfoFromSession(session) {
|
||||
let meta = session.peer.metadata
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property alias estimatedTimeText: contentText.text
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Est. time:")
|
||||
font.pixelSize: 12
|
||||
color: Theme.palette.directColor1
|
||||
}
|
||||
StatusBaseText {
|
||||
id: contentText
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
MaxFeesDisplay 1.0 MaxFeesDisplay.qml
|
||||
EstimatedTimeDisplay 1.0 EstimatedTimeDisplay.qml
|
||||
IntentionPanel 1.0 IntentionPanel.qml
|
||||
ContentPanel 1.0 ContentPanel.qml
|
||||
|
|
|
@ -63,6 +63,12 @@ QObject {
|
|||
if (txObj.value) { tx.value = stripLeadingZeros(txObj.value) }
|
||||
return tx
|
||||
}
|
||||
|
||||
// Returns ui/imports/utils -> Constants.TransactionEstimatedTime values
|
||||
function getEstimatedTime(chainId, maxFeePerGas) {
|
||||
return controller.getEstimatedTime(chainId, maxFeePerGas)
|
||||
}
|
||||
|
||||
// Returns the hex encoded signature of the transaction or empty string if error
|
||||
function signTransaction(topic, id, address, chainId, password, txObj) {
|
||||
let tx = prepareTxForStatusGo(txObj)
|
||||
|
|
|
@ -1333,6 +1333,7 @@ QtObject {
|
|||
readonly property string paraswapUrl: "app.paraswap.io"
|
||||
}
|
||||
|
||||
// Mirrors src/app_service/service/transaction/service.nim -> EstimatedTime
|
||||
enum TransactionEstimatedTime {
|
||||
Unknown = 0,
|
||||
LessThanOneMin,
|
||||
|
|
Loading…
Reference in New Issue