feat(dapps): Add support for max fees in WalletConnect requests
Compute max fees for transaction related requests and display the results to user. Also: - Add helper to convert from hex (backend) to decimal (frontend) values. - Add helper to convert from float gwei to hex wei - Update tests to accommodate for the new dependencies. Sourcing of account balances is not included therefore the transaction is allowed to go through even if the account balance is insufficient. An error will be generated by the backend in this case. Updates: #15192
This commit is contained in:
parent
e1611cbc83
commit
248ba1c1c8
|
@ -4,9 +4,12 @@ import chronicles
|
|||
import app_service/service/wallet_connect/service as wallet_connect_service
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
|
||||
import helpers
|
||||
|
||||
logScope:
|
||||
topics = "wallet-connect-controller"
|
||||
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Controller* = ref object of QObject
|
||||
|
@ -44,16 +47,16 @@ QtObject:
|
|||
self.dappsListReceived(res)
|
||||
return true
|
||||
|
||||
proc userAuthenticationResult*(self: Controller, topic: string, id: string, error: bool, password: string, pin: string) {.signal.}
|
||||
proc userAuthenticationResult*(self: Controller, topic: string, id: string, error: bool, password: string, pin: string, payload: string) {.signal.}
|
||||
|
||||
# Beware, it will fail if an authentication is already in progress
|
||||
proc authenticateUser*(self: Controller, topic: string, id: string, address: string): bool {.slot.} =
|
||||
proc authenticateUser*(self: Controller, topic: string, id: string, address: string, payload: string): bool {.slot.} =
|
||||
let acc = self.walletAccountService.getAccountByAddress(address)
|
||||
if acc.keyUid == "":
|
||||
return false
|
||||
|
||||
return self.service.authenticateUser(acc.keyUid, proc(password: string, pin: string, success: bool) =
|
||||
self.userAuthenticationResult(topic, id, success, password, pin)
|
||||
self.userAuthenticationResult(topic, id, success, password, pin, payload)
|
||||
)
|
||||
|
||||
proc signMessageUnsafe*(self: Controller, address: string, password: string, message: string): string {.slot.} =
|
||||
|
@ -73,3 +76,22 @@ QtObject:
|
|||
|
||||
proc getEstimatedTime(self: Controller, chainId: int, maxFeePerGasHex: string): int {.slot.} =
|
||||
return self.service.getEstimatedTime(chainId, maxFeePerGasHex).int
|
||||
|
||||
proc getSuggestedFeesJson(self: Controller, chainId: int): string {.slot.} =
|
||||
let dto = self.service.getSuggestedFees(chainId)
|
||||
return dto.toJson()
|
||||
|
||||
proc hexToDecBigString*(self: Controller, hex: string): string {.slot.} =
|
||||
try:
|
||||
return hexToDec(hex)
|
||||
except Exception as e:
|
||||
error "Failed to convert hex big int: ", hex=hex, ex=e.msg
|
||||
return ""
|
||||
|
||||
# Convert from float gwei to hex wei
|
||||
proc convertFeesInfoToHex*(self: Controller, feesInfoJson: string): string {.slot.} =
|
||||
try:
|
||||
return convertFeesInfoToHex(feesInfoJson)
|
||||
except Exception as e:
|
||||
error "Failed to convert fees info to hex: ", feesInfoJson=feesInfoJson, ex=e.msg
|
||||
return ""
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import stint, json, strutils
|
||||
|
||||
proc hexToDec*(hex: string): string =
|
||||
return stint.parse(hex, UInt256, 16).toString()
|
||||
|
||||
proc convertFeesInfoToHex*(feesInfoJson: string): string =
|
||||
let parsedJson = parseJson(feesInfoJson)
|
||||
|
||||
let maxFeeFloat = parsedJson["maxFeePerGas"].getFloat()
|
||||
let maxFeeWei = int64(maxFeeFloat * 1e9)
|
||||
|
||||
let maxPriorityFeeFloat = parsedJson["maxPriorityFeePerGas"].getFloat()
|
||||
let maxPriorityFeeWei = int64(maxPriorityFeeFloat * 1e9)
|
||||
|
||||
# Assemble the JSON and return it
|
||||
var resultJson = %* {
|
||||
"maxFeePerGas": "0x" & toHex(maxFeeWei).strip(chars = {'0'}, trailing = false),
|
||||
"maxPriorityFeePerGas": "0x" & toHex(maxPriorityFeeWei).strip(chars = {'0'}, trailing = false)
|
||||
}
|
||||
return $resultJson
|
||||
|
|
@ -225,3 +225,6 @@ QtObject:
|
|||
let maxFeePerGasInt = parseHexInt(maxFeePerGasHex)
|
||||
maxFeePerGas = maxFeePerGasInt.float
|
||||
return self.transactions.getEstimatedTime(chainId, $(maxFeePerGas))
|
||||
|
||||
proc getSuggestedFees*(self: Service, chainId: int): SuggestedFeesDto =
|
||||
return self.transactions.suggestedFees(chainId)
|
|
@ -377,6 +377,13 @@ Item {
|
|||
function getEstimatedTime(chainId, maxFeePerGas) {
|
||||
return Constants.TransactionEstimatedTime.LessThanThreeMins
|
||||
}
|
||||
|
||||
function hexToDec(hex) {
|
||||
if (hex.length > "0xfffffffffffff".length) {
|
||||
console.warn(`Beware of possible loss of precision converting ${hex}`)
|
||||
}
|
||||
return parseInt(hex, 16).toString()
|
||||
}
|
||||
}
|
||||
|
||||
walletRootStore: QObject {
|
||||
|
@ -390,6 +397,7 @@ Item {
|
|||
function getNetworkShortNames(chainIds) {
|
||||
return "eth:oeth:arb"
|
||||
}
|
||||
readonly property CurrenciesStore currencyStore: CurrenciesStore {}
|
||||
}
|
||||
|
||||
onDisplayToastMessage: (message, isErr) => {
|
||||
|
|
|
@ -155,6 +155,7 @@ Item {
|
|||
id: dappsRequestHandlerComponent
|
||||
|
||||
DAppsRequestHandler {
|
||||
currenciesStore: CurrenciesStore {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,19 @@ import unittest
|
|||
|
||||
import app/modules/main/wallet_section/poc_wallet_connect/helpers
|
||||
|
||||
import app/modules/shared_modules/wallet_connect/helpers
|
||||
|
||||
suite "wallet connect":
|
||||
|
||||
test "hexToDec":
|
||||
check(hexToDec("0x3") == "3")
|
||||
check(hexToDec("f") == "15")
|
||||
|
||||
test "convertFeesInfoToHex":
|
||||
const feesInfoJson = "{\"maxFees\":\"24528.282681\",\"maxFeePerGas\":1.168013461,\"maxPriorityFeePerGas\":0.036572351,\"gasPrice\":\"1.168013461\"}"
|
||||
|
||||
check(convertFeesInfoToHex(feesInfoJson) == """{"maxFeePerGas":"0x459E7895","maxPriorityFeePerGas":"0x22E0CBF"}""")
|
||||
|
||||
test "parse deep link url":
|
||||
const testUrl = "https://status.app/wc?uri=wc%3Aa4f32854428af0f5b6635fb7a3cb2cfe174eaad63b9d10d52ef1c686f8eab862%402%3Frelay-protocol%3Dirn%26symKey%3D4ccbae2b4c81c26fbf4a6acee9de2771705d467de9a1d24c80240e8be59de6be"
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
|
|||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Wallet 1.0
|
||||
|
@ -159,6 +160,8 @@ DappsComboBox {
|
|||
loginType: request.account.migragedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||
visible: true
|
||||
|
||||
property var feesInfo: null
|
||||
|
||||
dappUrl: request.dappUrl
|
||||
dappIcon: request.dappIcon
|
||||
dappName: request.dappName
|
||||
|
@ -180,7 +183,7 @@ DappsComboBox {
|
|||
enoughFundsForTransaction: request.enoughFunds
|
||||
enoughFundsForFees: request.enoughFunds
|
||||
|
||||
signingTransaction: request.method === SessionRequest.methods.signTransaction.name || request.method === SessionRequest.methods.sendTransaction.name
|
||||
signingTransaction: !!request.method && (request.method === SessionRequest.methods.signTransaction.name || request.method === SessionRequest.methods.sendTransaction.name)
|
||||
requestPayload: {
|
||||
switch(request.method) {
|
||||
case SessionRequest.methods.personalSign.name:
|
||||
|
@ -219,8 +222,9 @@ DappsComboBox {
|
|||
console.error("Error signing: request is null")
|
||||
return
|
||||
}
|
||||
|
||||
requestHandled = true
|
||||
root.wcService.requestHandler.authenticate(request)
|
||||
root.wcService.requestHandler.authenticate(request, JSON.stringify(feesInfo))
|
||||
}
|
||||
|
||||
onRejected: {
|
||||
|
@ -240,22 +244,18 @@ DappsComboBox {
|
|||
Connections {
|
||||
target: root.wcService.requestHandler
|
||||
|
||||
function onMaxFeesUpdated(maxFees, maxFeesWei, haveEnoughFunds, symbol) {
|
||||
fiatFees = maxFees
|
||||
currentCurrency = symbol
|
||||
|
||||
var ethStr = "?"
|
||||
try {
|
||||
ethStr = globalUtils.wei2Eth(maxFeesWei, 9)
|
||||
} catch (e) {
|
||||
// ignore error in case of tests and storybook where we don't have access to globalUtils
|
||||
function onMaxFeesUpdated(fiatMaxFees, ethMaxFees, haveEnoughFunds, haveEnoughFees, symbol, feesInfo) {
|
||||
dappRequestModal.hasFees = !!ethMaxFees
|
||||
dappRequestModal.feesLoading = !dappRequestModal.hasFees
|
||||
if (!hasFees) {
|
||||
return
|
||||
}
|
||||
|
||||
cryptoFees = ethStr
|
||||
enoughFundsForTransaction = haveEnoughFunds
|
||||
enoughFundsForFees = haveEnoughFunds
|
||||
feesLoading = false
|
||||
hasFees = !!maxFees
|
||||
dappRequestModal.fiatFees = fiatMaxFees.toString()
|
||||
dappRequestModal.cryptoFees = ethMaxFees.toString()
|
||||
dappRequestModal.currentCurrency = symbol
|
||||
dappRequestModal.enoughFundsForTransaction = haveEnoughFunds
|
||||
dappRequestModal.enoughFundsForFees = haveEnoughFees
|
||||
dappRequestModal.feesInfo = feesInfo
|
||||
}
|
||||
|
||||
function onEstimatedTimeUpdated(estimatedTimeEnum) {
|
||||
|
@ -273,6 +273,8 @@ DappsComboBox {
|
|||
sessionRequestLoader.active = false
|
||||
} else {
|
||||
// TODO #14762 handle the error case
|
||||
let userRejected = false
|
||||
root.wcService.requestHandler.rejectSessionRequest(request, userRejected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,20 +3,21 @@ import QtQuick 2.15
|
|||
import AppLayouts.Wallet.services.dapps 1.0
|
||||
import AppLayouts.Wallet.services.dapps.types 1.0
|
||||
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||
|
||||
import shared.stores 1.0
|
||||
import utils 1.0
|
||||
|
||||
import "types"
|
||||
|
||||
QObject {
|
||||
SQUtils.QObject {
|
||||
id: root
|
||||
|
||||
required property WalletConnectSDKBase sdk
|
||||
required property DAppsStore store
|
||||
required property var accountsModel
|
||||
required property var networksModel
|
||||
required property CurrenciesStore currenciesStore
|
||||
|
||||
property alias requestsModel: requests
|
||||
|
||||
|
@ -26,14 +27,14 @@ QObject {
|
|||
}
|
||||
|
||||
/// Beware, it will fail if called multiple times before getting an answer
|
||||
function authenticate(request) {
|
||||
return store.authenticateUser(request.topic, request.id, request.account.address)
|
||||
function authenticate(request, payload) {
|
||||
return store.authenticateUser(request.topic, request.id, request.account.address, payload)
|
||||
}
|
||||
|
||||
signal sessionRequest(SessionRequestResolved request)
|
||||
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 maxFeesUpdated(real fiatMaxFees, var /* Big */ ethMaxFees, bool haveEnoughFunds, bool haveEnoughFees, string symbol, var feesInfo)
|
||||
// Reports Constants.TransactionEstimatedTime values
|
||||
signal estimatedTimeUpdated(int estimatedTimeEnum)
|
||||
|
||||
|
@ -51,7 +52,7 @@ QObject {
|
|||
}
|
||||
|
||||
function onSessionRequestUserAnswerResult(topic, id, accept, error) {
|
||||
var request = requests.findRequest(topic, id)
|
||||
let request = requests.findRequest(topic, id)
|
||||
if (request === null) {
|
||||
console.error("Error finding event for topic", topic, "id", id)
|
||||
return
|
||||
|
@ -85,17 +86,17 @@ QObject {
|
|||
Connections {
|
||||
target: root.store
|
||||
|
||||
function onUserAuthenticated(topic, id, password, pin) {
|
||||
function onUserAuthenticated(topic, id, password, pin, payload) {
|
||||
var request = requests.findRequest(topic, id)
|
||||
if (request === null) {
|
||||
console.error("Error finding event for topic", topic, "id", id)
|
||||
return
|
||||
}
|
||||
d.executeSessionRequest(request, password, pin)
|
||||
d.executeSessionRequest(request, password, pin, payload)
|
||||
}
|
||||
|
||||
function onUserAuthenticationFailed(topic, id) {
|
||||
var request = requests.findRequest(topic, id)
|
||||
let request = requests.findRequest(topic, id)
|
||||
let methodStr = SessionRequest.methodToUserString(request.method)
|
||||
if (request === null || !methodStr) {
|
||||
return
|
||||
|
@ -108,7 +109,7 @@ QObject {
|
|||
}
|
||||
}
|
||||
|
||||
QObject {
|
||||
SQUtils.QObject {
|
||||
id: d
|
||||
|
||||
function resolveAsync(event) {
|
||||
|
@ -128,6 +129,7 @@ QObject {
|
|||
console.error("Error in event data lookup", JSON.stringify(event))
|
||||
return null
|
||||
}
|
||||
let enoughFunds = !d.isTransactionMethod(method)
|
||||
let obj = sessionRequestComponent.createObject(null, {
|
||||
event,
|
||||
topic: event.topic,
|
||||
|
@ -138,7 +140,7 @@ QObject {
|
|||
data,
|
||||
maxFeesText: "?",
|
||||
maxFeesEthText: "?",
|
||||
enoughFunds: false,
|
||||
enoughFunds: enoughFunds,
|
||||
})
|
||||
if (obj === null) {
|
||||
console.error("Error creating SessionRequestResolved for event")
|
||||
|
@ -159,20 +161,16 @@ 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, "")
|
||||
if (!d.isTransactionMethod(method)) {
|
||||
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")
|
||||
let estimatedTimeEnum = getEstimatedTimeInterval(data, method, obj.network.chainId)
|
||||
root.estimatedTimeUpdated(estimatedTimeEnum)
|
||||
|
||||
let st = getEstimatedFeesStatus(data, method, obj.network.chainId)
|
||||
|
||||
root.maxFeesUpdated(st.fiatMaxFees, st.maxFeesEth, st.haveEnoughFunds, st.haveEnoughFees, st.symbol, st.feesInfo)
|
||||
})
|
||||
|
||||
return obj
|
||||
|
@ -180,7 +178,7 @@ QObject {
|
|||
|
||||
/// Returns null if the account is not found
|
||||
function lookupAccountFromEvent(event, method) {
|
||||
var address = ""
|
||||
let address = ""
|
||||
if (method === SessionRequest.methods.personalSign.name) {
|
||||
if (event.params.request.params.length < 2) {
|
||||
return null
|
||||
|
@ -198,14 +196,13 @@ QObject {
|
|||
return null
|
||||
}
|
||||
address = event.params.request.params[0]
|
||||
} else if (method === SessionRequest.methods.signTransaction.name
|
||||
|| method === SessionRequest.methods.sendTransaction.name) {
|
||||
} else if (d.isTransactionMethod(method)) {
|
||||
if (event.params.request.params.length == 0) {
|
||||
return null
|
||||
}
|
||||
address = event.params.request.params[0].from
|
||||
}
|
||||
return ModelUtils.getFirstModelEntryIf(root.accountsModel, (account) => {
|
||||
return SQUtils.ModelUtils.getFirstModelEntryIf(root.accountsModel, (account) => {
|
||||
return account.address.toLowerCase() === address.toLowerCase();
|
||||
})
|
||||
}
|
||||
|
@ -216,7 +213,7 @@ QObject {
|
|||
return null
|
||||
}
|
||||
let chainId = Helpers.chainIdFromEip155(event.params.chainId)
|
||||
return ModelUtils.getByKey(root.networksModel, "chainId", chainId)
|
||||
return SQUtils.ModelUtils.getByKey(root.networksModel, "chainId", chainId)
|
||||
}
|
||||
|
||||
function extractMethodData(event, method) {
|
||||
|
@ -226,7 +223,7 @@ QObject {
|
|||
if (event.params.request.params.length < 1) {
|
||||
return null
|
||||
}
|
||||
var message = ""
|
||||
let message = ""
|
||||
let messageIndex = (method === SessionRequest.methods.personalSign.name ? 0 : 1)
|
||||
let messageParam = event.params.request.params[messageIndex]
|
||||
// There is no standard on how data is encoded. Therefore we support hex or utf8
|
||||
|
@ -275,14 +272,14 @@ QObject {
|
|||
})
|
||||
}
|
||||
|
||||
function executeSessionRequest(request, password, pin) {
|
||||
function executeSessionRequest(request, password, pin, payload) {
|
||||
if (!SessionRequest.getSupportedMethods().includes(request.method)) {
|
||||
console.error("Unsupported method to execute: ", request.method)
|
||||
return
|
||||
}
|
||||
|
||||
if (password !== "") {
|
||||
var actionResult = ""
|
||||
let actionResult = ""
|
||||
if (request.method === SessionRequest.methods.sign.name) {
|
||||
actionResult = store.signMessageUnsafe(request.topic, request.id,
|
||||
request.account.address, password,
|
||||
|
@ -299,15 +296,36 @@ QObject {
|
|||
request.account.address, password,
|
||||
SessionRequest.methods.signTypedData.getMessageFromData(request.data),
|
||||
request.network.chainId, legacy)
|
||||
} else if (request.method === SessionRequest.methods.signTransaction.name) {
|
||||
let txObj = SessionRequest.methods.signTransaction.getTxObjFromData(request.data)
|
||||
actionResult = store.signTransaction(request.topic, request.id,
|
||||
request.account.address, request.network.chainId, password, txObj)
|
||||
} else if (request.method === SessionRequest.methods.sendTransaction.name) {
|
||||
let txObj = SessionRequest.methods.sendTransaction.getTxObjFromData(request.data)
|
||||
actionResult = store.sendTransaction(request.topic, request.id,
|
||||
request.account.address, request.network.chainId, password, txObj)
|
||||
} else if (d.isTransactionMethod(request.method)) {
|
||||
let txObj = d.getTxObject(request.method, request.data)
|
||||
if (!!payload) {
|
||||
let feesInfoJson = payload
|
||||
let hexFeesJson = root.store.convertFeesInfoToHex(feesInfoJson)
|
||||
if (!!hexFeesJson) {
|
||||
let feesInfo = JSON.parse(hexFeesJson)
|
||||
if (feesInfo.maxFeePerGas) {
|
||||
txObj.maxFeePerGas = feesInfo.maxFeePerGas
|
||||
}
|
||||
if (feesInfo.maxPriorityFeePerGas) {
|
||||
txObj.maxPriorityFeePerGas = feesInfo.maxPriorityFeePerGas
|
||||
}
|
||||
}
|
||||
delete txObj.gasLimit
|
||||
delete txObj.gasPrice
|
||||
}
|
||||
// Remove nonce from txObj to be auto-filled by the wallet
|
||||
delete txObj.nonce
|
||||
|
||||
if (request.method === SessionRequest.methods.signTransaction.name) {
|
||||
actionResult = store.signTransaction(request.topic, request.id,
|
||||
request.account.address, request.network.chainId, password, txObj)
|
||||
} else if (request.method === SessionRequest.methods.sendTransaction.name) {
|
||||
let txObj = SessionRequest.methods.sendTransaction.getTxObjFromData(request.data)
|
||||
actionResult = store.sendTransaction(request.topic, request.id,
|
||||
request.account.address, request.network.chainId, password, txObj)
|
||||
}
|
||||
}
|
||||
|
||||
let isSuccessful = (actionResult != "")
|
||||
if (isSuccessful) {
|
||||
// acceptSessionRequest will trigger an sdk.sessionRequestUserAnswerResult signal
|
||||
|
@ -324,28 +342,110 @@ QObject {
|
|||
|
||||
// Returns Constants.TransactionEstimatedTime
|
||||
function getEstimatedTimeInterval(data, method, chainId) {
|
||||
if (method != SessionRequest.methods.signTransaction.name
|
||||
&& method != SessionRequest.methods.sendTransaction.name)
|
||||
{
|
||||
return ""
|
||||
let tx = {}
|
||||
let maxFeePerGas = ""
|
||||
if (d.isTransactionMethod(method)) {
|
||||
tx = d.getTxObject(method, data)
|
||||
// Empty string instructs getEstimatedTime to fetch the blockchain value
|
||||
if (!!tx.maxFeePerGas) {
|
||||
maxFeePerGas = tx.maxFeePerGas
|
||||
} else if (!!tx.gasPrice) {
|
||||
maxFeePerGas = tx.gasPrice
|
||||
}
|
||||
}
|
||||
|
||||
var tx = {}
|
||||
return root.store.getEstimatedTime(chainId, maxFeePerGas)
|
||||
}
|
||||
|
||||
// Returns {
|
||||
// maxFees -> Big number in Gwei
|
||||
// maxFeePerGas
|
||||
// maxPriorityFeePerGas
|
||||
// gasPrice
|
||||
// }
|
||||
function getEstimatedMaxFees(data, method, chainId) {
|
||||
let tx = {}
|
||||
if (d.isTransactionMethod(method)) {
|
||||
tx = d.getTxObject(method, data)
|
||||
}
|
||||
|
||||
let Math = SQUtils.AmountsArithmetic
|
||||
let gasLimit = Math.fromString("21000")
|
||||
let gasPrice, maxFeePerGas, maxPriorityFeePerGas
|
||||
// Beware, the tx values are standard blockchain hex big number values; the fees values are nim's float64 values, hence the complex conversions
|
||||
if (!!tx.maxFeePerGas && !!tx.maxPriorityFeePerGas) {
|
||||
let maxFeePerGasDec = root.store.hexToDec(tx.maxFeePerGas)
|
||||
gasPrice = Math.fromString(maxFeePerGasDec)
|
||||
// Source fees info from the incoming transaction for when we process it
|
||||
maxFeePerGas = maxFeePerGasDec
|
||||
let maxPriorityFeePerGasDec = root.store.hexToDec(tx.maxPriorityFeePerGas)
|
||||
maxPriorityFeePerGas = maxPriorityFeePerGasDec
|
||||
} else {
|
||||
let fees = root.store.getSuggestedFees(chainId)
|
||||
maxPriorityFeePerGas = fees.maxPriorityFeePerGas
|
||||
if (fees.eip1559Enabled) {
|
||||
if (!!fees.maxFeePerGasM) {
|
||||
gasPrice = Math.fromString(fees.maxFeePerGasM)
|
||||
maxFeePerGas = fees.maxFeePerGasM
|
||||
} else if(!!tx.maxFeePerGas) {
|
||||
let maxFeePerGasDec = root.store.hexToDec(tx.maxFeePerGas)
|
||||
gasPrice = Math.fromString(maxFeePerGasDec)
|
||||
maxFeePerGas = maxFeePerGasDec
|
||||
} else {
|
||||
console.error("Error fetching maxFeePerGas from fees or tx objects")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (!!fees.gasPrice) {
|
||||
gasPrice = Math.fromString(fees.gasPrice)
|
||||
} else {
|
||||
console.error("Error fetching suggested fees")
|
||||
return
|
||||
}
|
||||
}
|
||||
gasPrice = Math.sum(gasPrice, Math.fromString(fees.l1GasFee))
|
||||
}
|
||||
|
||||
let maxFees = Math.times(gasLimit, gasPrice)
|
||||
return {maxFees, maxFeePerGas, maxPriorityFeePerGas, gasPrice}
|
||||
}
|
||||
|
||||
function getEstimatedFeesStatus(data, method, chainId) {
|
||||
let Math = SQUtils.AmountsArithmetic
|
||||
|
||||
let feesInfo = getEstimatedMaxFees(data, method, chainId)
|
||||
|
||||
let maxFeesEth = Math.div(feesInfo.maxFees, Math.fromString("1000000000"))
|
||||
|
||||
// TODO #15192: extract account.balance
|
||||
//let accountFundsEth = account.balance
|
||||
//let haveEnoughFees = Math.cmp(accountFundsEth, maxFeesEth) >= 0
|
||||
let haveEnoughFees = true
|
||||
|
||||
let maxFeesEthStr = maxFeesEth.toString()
|
||||
let fiatMaxFees = root.currenciesStore.getFiatValue(maxFeesEthStr, Constants.ethToken)
|
||||
let symbol = root.currenciesStore.currentCurrency
|
||||
|
||||
// We don't process the transaction so we don't have this information yet
|
||||
let haveEnoughFunds = true
|
||||
return {fiatMaxFees, maxFeesEth, haveEnoughFunds, haveEnoughFees, symbol, feesInfo}
|
||||
}
|
||||
|
||||
function isTransactionMethod(method) {
|
||||
return method === SessionRequest.methods.signTransaction.name
|
||||
|| method === SessionRequest.methods.sendTransaction.name
|
||||
}
|
||||
|
||||
function getTxObject(method, data) {
|
||||
let 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)
|
||||
} else {
|
||||
console.error("Not a transaction method")
|
||||
}
|
||||
|
||||
// Empty string instructs getEstimatedTime to fetch the blockchain value
|
||||
var maxFeePerGas = ""
|
||||
if (!!tx.maxFeePerGas) {
|
||||
maxFeePerGas = tx.maxFeePerGas
|
||||
} else if (!!tx.gasPrice) {
|
||||
maxFeePerGas = tx.gasPrice
|
||||
}
|
||||
|
||||
return root.store.getEstimatedTime(chainId, maxFeePerGas)
|
||||
return tx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -238,6 +238,7 @@ QObject {
|
|||
store: root.store
|
||||
accountsModel: root.validAccounts
|
||||
networksModel: root.flatNetworks
|
||||
currenciesStore: root.walletRootStore.currencyStore
|
||||
|
||||
onSessionRequest: (request) => {
|
||||
timeoutTimer.stop()
|
||||
|
|
|
@ -99,4 +99,4 @@ function extractInfoFromPairUri(uri) {
|
|||
}
|
||||
}
|
||||
return { topic, expiry }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ QObject {
|
|||
readonly property alias dappUrl: d.dappUrl
|
||||
readonly property alias dappIcon: d.dappIcon
|
||||
|
||||
readonly property string maxFeesText: ""
|
||||
readonly property string maxFeesEthText: ""
|
||||
readonly property bool enoughFunds: false
|
||||
property string maxFeesText: ""
|
||||
property string maxFeesEthText: ""
|
||||
property bool enoughFunds: false
|
||||
|
||||
function resolveDappInfoFromSession(session) {
|
||||
let meta = session.peer.metadata
|
||||
|
|
|
@ -8,7 +8,7 @@ QObject {
|
|||
required property var controller
|
||||
/// \c dappsJson serialized from status-go.wallet.GetDapps
|
||||
signal dappsListReceived(string dappsJson)
|
||||
signal userAuthenticated(string topic, string id, string password, string pin)
|
||||
signal userAuthenticated(string topic, string id, string password, string pin, string payload)
|
||||
signal userAuthenticationFailed(string topic, string id)
|
||||
|
||||
function addWalletConnectSession(sessionJson) {
|
||||
|
@ -23,8 +23,8 @@ QObject {
|
|||
return controller.updateSessionsMarkedAsActive(activeTopicsJson)
|
||||
}
|
||||
|
||||
function authenticateUser(topic, id, address) {
|
||||
let ok = controller.authenticateUser(topic, id, address)
|
||||
function authenticateUser(topic, id, address, payload) {
|
||||
let ok = controller.authenticateUser(topic, id, address, payload)
|
||||
if(!ok) {
|
||||
root.userAuthenticationFailed()
|
||||
}
|
||||
|
@ -70,6 +70,12 @@ QObject {
|
|||
return controller.getEstimatedTime(chainId, maxFeePerGasHex)
|
||||
}
|
||||
|
||||
// Returns nim's SuggestedFeesDto; see src/app_service/service/transaction/dto.nim
|
||||
// Returns all value initialized to 0 if error
|
||||
function getSuggestedFees(chainId) {
|
||||
return JSON.parse(controller.getSuggestedFeesJson(chainId))
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -87,6 +93,15 @@ QObject {
|
|||
return controller.getDapps()
|
||||
}
|
||||
|
||||
function hexToDec(hex) {
|
||||
return controller.hexToDecBigString(hex)
|
||||
}
|
||||
|
||||
// Return just the modified fields { "maxFeePerGas": "0x<...>", "maxPriorityFeePerGas": "0x<...>" }
|
||||
function convertFeesInfoToHex(feesInfoJson) {
|
||||
return controller.convertFeesInfoToHex(feesInfoJson)
|
||||
}
|
||||
|
||||
// Handle async response from controller
|
||||
Connections {
|
||||
target: controller
|
||||
|
@ -95,9 +110,9 @@ QObject {
|
|||
root.dappsListReceived(dappsJson)
|
||||
}
|
||||
|
||||
function onUserAuthenticationResult(topic, id, success, password, pin) {
|
||||
function onUserAuthenticationResult(topic, id, success, password, pin, payload) {
|
||||
if (success) {
|
||||
root.userAuthenticated(topic, id, password, pin)
|
||||
root.userAuthenticated(topic, id, password, pin, payload)
|
||||
} else {
|
||||
root.userAuthenticationFailed(topic, id)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue