diff --git a/src/app/global/utils.nim b/src/app/global/utils.nim
index 5d97129883..f28b2c8689 100644
--- a/src/app/global/utils.nim
+++ b/src/app/global/utils.nim
@@ -61,6 +61,9 @@ QtObject:
proc hex2Eth*(self: Utils, value: string): string {.slot.} =
return stripTrailingZeroes(conversion.wei2Eth(stint.fromHex(StUint[256], value)))
+ proc hex2Gwei*(self: Utils, value: string): string {.slot.} =
+ return stripTrailingZeroes(conversion.wei2Eth(stint.fromHex(StUint[256], value)*1000000000))
+
proc gwei2Hex*(self: Utils, gwei: float): string {.slot.} =
return "0x" & conversion.gwei2Wei(gwei).toHex()
diff --git a/src/app/modules/main/wallet_section/transactions/controller.nim b/src/app/modules/main/wallet_section/transactions/controller.nim
index 1d361af382..d7eb37e930 100644
--- a/src/app/modules/main/wallet_section/transactions/controller.nim
+++ b/src/app/modules/main/wallet_section/transactions/controller.nim
@@ -113,3 +113,6 @@ proc getChainIdForBrowser*(self: Controller): int =
proc getEstimatedTime*(self: Controller, chainId: int, maxFeePerGas: string): EstimatedTime =
return self.transactionService.getEstimatedTime(chainId, maxFeePerGas)
+
+proc getLastTxBlockNumber*(self: Controller): string =
+ return self.transactionService.getLastTxBlockNumber(self.networkService.getNetworkForBrowser().chainId)
diff --git a/src/app/modules/main/wallet_section/transactions/io_interface.nim b/src/app/modules/main/wallet_section/transactions/io_interface.nim
index 420a16bcdb..a7150884db 100644
--- a/src/app/modules/main/wallet_section/transactions/io_interface.nim
+++ b/src/app/modules/main/wallet_section/transactions/io_interface.nim
@@ -72,3 +72,6 @@ method getEstimatedTime*(self: AccessInterface, chainId: int, maxFeePerGas: stri
# inheritance, which is not well supported in Nim.
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
+
+method getLastTxBlockNumber*(self: AccessInterface): string {.base.} =
+ raise newException(ValueError, "No implementation available")
diff --git a/src/app/modules/main/wallet_section/transactions/item.nim b/src/app/modules/main/wallet_section/transactions/item.nim
index 0305b3a1f1..f1b6413841 100644
--- a/src/app/modules/main/wallet_section/transactions/item.nim
+++ b/src/app/modules/main/wallet_section/transactions/item.nim
@@ -24,6 +24,9 @@ type
txHash: string
multiTransactionID: int
isTimeStamp: bool
+ baseGasFees: string
+ totalFees: string
+ maxTotalFees: string
proc initItem*(
id: string,
@@ -47,7 +50,10 @@ proc initItem*(
input: string,
txHash: string,
multiTransactionID: int,
- isTimeStamp: bool
+ isTimeStamp: bool,
+ baseGasFees: string,
+ totalFees: string,
+ maxTotalFees: string
): Item =
result.id = id
result.typ = typ
@@ -71,6 +77,9 @@ proc initItem*(
result.txHash = txHash
result.multiTransactionID = multiTransactionID
result.isTimeStamp = isTimeStamp
+ result.baseGasFees = baseGasFees
+ result.totalFees = totalFees
+ result.maxTotalFees = maxTotalFees
proc `$`*(self: Item): string =
result = fmt"""AllTokensItem(
@@ -96,6 +105,9 @@ proc `$`*(self: Item): string =
txHash: {self.txHash},
multiTransactionID: {self.multiTransactionID},
isTimeStamp: {self.isTimeStamp},
+ baseGasFees: {self.baseGasFees},
+ totalFees: {self.totalFees},
+ maxTotalFees: {self.maxTotalFees},
]"""
proc getId*(self: Item): string =
@@ -163,3 +175,12 @@ proc getMultiTransactionID*(self: Item): int =
proc getIsTimeStamp*(self: Item): bool =
return self.isTimeStamp
+
+proc getBaseGasFees*(self: Item): string =
+ return self.baseGasFees
+
+proc getTotalFees*(self: Item): string =
+ return self.totalFees
+
+proc getMaxTotalFees*(self: Item): string =
+ return self.maxTotalFees
diff --git a/src/app/modules/main/wallet_section/transactions/model.nim b/src/app/modules/main/wallet_section/transactions/model.nim
index 3b7617d5c0..ad93303985 100644
--- a/src/app/modules/main/wallet_section/transactions/model.nim
+++ b/src/app/modules/main/wallet_section/transactions/model.nim
@@ -1,4 +1,4 @@
-import NimQml, Tables, strutils, strformat, sequtils, tables, sugar, algorithm, std/[times, os], stint
+import NimQml, Tables, strutils, strformat, sequtils, tables, sugar, algorithm, std/[times, os], stint, parseutils
import ./item
import ../../../../../app_service/service/eth/utils as eth_service_utils
@@ -28,6 +28,9 @@ type
TxHash
MultiTransactionID
IsTimeStamp
+ BaseGasFees
+ TotalFees
+ MaxTotalFees
QtObject:
type
@@ -88,7 +91,10 @@ QtObject:
ModelRole.Input.int:"input",
ModelRole.TxHash.int:"txHash",
ModelRole.MultiTransactionID.int:"multiTransactionID",
- ModelRole.IsTimeStamp.int: "isTimeStamp"
+ ModelRole.IsTimeStamp.int: "isTimeStamp",
+ ModelRole.BaseGasFees.int: "baseGasFees",
+ ModelRole.TotalFees.int: "totalFees",
+ ModelRole.MaxTotalFees.int: "maxTotalFees"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@@ -145,7 +151,13 @@ QtObject:
of ModelRole.MultiTransactionID:
result = newQVariant(item.getMultiTransactionID())
of ModelRole.IsTimeStamp:
- result = newQVariant(item.getIsTimeStamp())
+ result = newQVariant(item.getIsTimeStamp())
+ of ModelRole.BaseGasFees:
+ result = newQVariant(item.getBaseGasFees())
+ of ModelRole.TotalFees:
+ result = newQVariant(item.getTotalFees())
+ of ModelRole.MaxTotalFees:
+ result = newQVariant(item.getMaxTotalFees())
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()
@@ -206,7 +218,10 @@ QtObject:
t.input,
t.txHash,
t.multiTransactionID,
- false
+ false,
+ t.baseGasFees,
+ t.totalFees,
+ t.maxTotalFees,
))
var allTxs = self.items.concat(newTxItems)
@@ -219,7 +234,7 @@ QtObject:
for tx in allTxs:
let duration = fromUnix(tx.getTimestamp()) - tempTimeStamp
if(duration.inDays != 0):
- itemsWithDateHeaders.add(initItem("", "", "", "", "", tx.getTimestamp(), "", "", "", "", "", "", "", "", "", 0, "", "", "", "", 0, true))
+ itemsWithDateHeaders.add(initItem("", "", "", "", "", tx.getTimestamp(), "", "", "", "", "", "", "", "", "", 0, "", "", "", "", 0, true, "", "", ""))
itemsWithDateHeaders.add(tx)
tempTimeStamp = fromUnix(tx.getTimestamp())
diff --git a/src/app/modules/main/wallet_section/transactions/module.nim b/src/app/modules/main/wallet_section/transactions/module.nim
index 2038749e91..c68d1d27b4 100644
--- a/src/app/modules/main/wallet_section/transactions/module.nim
+++ b/src/app/modules/main/wallet_section/transactions/module.nim
@@ -113,3 +113,6 @@ method getChainIdForBrowser*(self: Module): int =
method getEstimatedTime*(self: Module, chainId: int, maxFeePerGas: string): int =
return self.controller.getEstimatedTime(chainId, maxFeePerGas).int
+
+method getLastTxBlockNumber*(self: Module): string =
+ return self.controller.getLastTxBlockNumber()
diff --git a/src/app/modules/main/wallet_section/transactions/view.nim b/src/app/modules/main/wallet_section/transactions/view.nim
index 3950f1aaa7..b96535ac81 100644
--- a/src/app/modules/main/wallet_section/transactions/view.nim
+++ b/src/app/modules/main/wallet_section/transactions/view.nim
@@ -150,3 +150,6 @@ QtObject:
proc getEstimatedTime*(self: View, chainId: int, maxFeePerGas: string): int {.slot.} =
return self.delegate.getEstimatedTime(chainId, maxFeePerGas)
+
+ proc getLastTxBlockNumber*(self: View): string {.slot.} =
+ return self.delegate.getLastTxBlockNumber()
diff --git a/src/app_service/service/transaction/dto.nim b/src/app_service/service/transaction/dto.nim
index 1b8d2ffcac..37570f151b 100644
--- a/src/app_service/service/transaction/dto.nim
+++ b/src/app_service/service/transaction/dto.nim
@@ -49,6 +49,21 @@ type
input*: string
txHash*: string
multiTransactionID*: int
+ baseGasFees*: string
+ totalFees*: string
+ maxTotalFees*: string
+
+
+proc getTotalFees(tip: string, baseFee: string, gasUsed: string, maxFee: string): string =
+ var maxFees = stint.fromHex(Uint256, maxFee)
+ var totalGasUsed = stint.fromHex(Uint256, tip) + stint.fromHex(Uint256, baseFee)
+ if totalGasUsed > maxFees:
+ totalGasUsed = maxFees
+ var totalGasUsedInHex = (totalGasUsed * stint.fromHex(Uint256, gasUsed)).toHex
+ return totalGasUsedInHex
+
+proc getMaxTotalFees(maxFee: string, gasLimit: string): string =
+ return (stint.fromHex(Uint256, maxFee) * stint.fromHex(Uint256, gasLimit)).toHex
proc toTransactionDto*(jsonObj: JsonNode): TransactionDto =
result = TransactionDto()
@@ -73,6 +88,9 @@ proc toTransactionDto*(jsonObj: JsonNode): TransactionDto =
discard jsonObj.getProp("input", result.input)
discard jsonObj.getProp("txHash", result.txHash)
discard jsonObj.getProp("multiTransactionID", result.multiTransactionID)
+ discard jsonObj.getProp("base_gas_fee", result.baseGasFees)
+ result.totalFees = getTotalFees(result.maxPriorityFeePerGas, result.baseGasFees, result.gasUsed, result.maxFeePerGas)
+ result.maxTotalFees = getMaxTotalFees(result.maxFeePerGas, result.gasLimit)
proc cmpTransactions*(x, y: TransactionDto): int =
# Sort proc to compare transactions from a single account.
diff --git a/src/app_service/service/transaction/service.nim b/src/app_service/service/transaction/service.nim
index d513de5286..2f85505266 100644
--- a/src/app_service/service/transaction/service.nim
+++ b/src/app_service/service/transaction/service.nim
@@ -422,3 +422,11 @@ QtObject:
except Exception as e:
error "Error estimating transaction time", message = e.msg
return EstimatedTime.Unknown
+
+ proc getLastTxBlockNumber*(self: Service, chainId: int): string =
+ try:
+ let response = eth.getBlockByNumber(chainId, "latest")
+ return response.result{"number"}.getStr
+ except Exception as e:
+ error "Error getting latest block number", message = e.msg
+ return ""
diff --git a/ui/StatusQ b/ui/StatusQ
index 7108ac87cf..c3bbb396ec 160000
--- a/ui/StatusQ
+++ b/ui/StatusQ
@@ -1 +1 @@
-Subproject commit 7108ac87cffe529d011ec1c14473630e52980282
+Subproject commit c3bbb396ecd5ad25df565d64429aaba869df4b49
diff --git a/ui/app/AppLayouts/Wallet/WalletLayout.qml b/ui/app/AppLayouts/Wallet/WalletLayout.qml
index 3bc7f189ba..237106a840 100644
--- a/ui/app/AppLayouts/Wallet/WalletLayout.qml
+++ b/ui/app/AppLayouts/Wallet/WalletLayout.qml
@@ -54,6 +54,7 @@ Item {
id: walletContainer
RightTabView {
store: root.store
+ contactsStore: root.contactsStore
sendModal: root.sendModal
}
}
diff --git a/ui/app/AppLayouts/Wallet/views/RightTabView.qml b/ui/app/AppLayouts/Wallet/views/RightTabView.qml
index 5a42aca4b5..5c8b5fe208 100644
--- a/ui/app/AppLayouts/Wallet/views/RightTabView.qml
+++ b/ui/app/AppLayouts/Wallet/views/RightTabView.qml
@@ -6,6 +6,7 @@ import StatusQ.Controls 0.1
import utils 1.0
import shared.views 1.0
+import "./"
import "../stores"
import "../panels"
import "../views/collectibles"
@@ -15,6 +16,7 @@ Item {
property alias currentTabIndex: walletTabBar.currentIndex
property var store
+ property var contactsStore
property var sendModal
ColumnLayout {
@@ -80,6 +82,10 @@ Item {
}
HistoryView {
account: RootStore.currentAccount
+ onLaunchTransactionDetail: {
+ transactionDetailView.transaction = transaction
+ stack.currentIndex = 3
+ }
}
}
}
@@ -94,6 +100,14 @@ Item {
Layout.fillHeight: true
onGoBack: stack.currentIndex = 0
}
+ TransactionDetailView {
+ id: transactionDetailView
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ sendModal: root.sendModal
+ contactsStore: root.contactsStore
+ onGoBack: stack.currentIndex = 0
+ }
}
WalletFooter {
diff --git a/ui/app/AppLayouts/Wallet/views/SavedAddressesView.qml b/ui/app/AppLayouts/Wallet/views/SavedAddressesView.qml
index 12c405bb55..18fb49d469 100644
--- a/ui/app/AppLayouts/Wallet/views/SavedAddressesView.qml
+++ b/ui/app/AppLayouts/Wallet/views/SavedAddressesView.qml
@@ -26,6 +26,16 @@ Item {
id: _internal
property bool loading: false
property string error: ""
+ function saveAddress(name, address) {
+ loading = true
+ error = RootStore.createOrUpdateSavedAddress(name, address)
+ loading = false
+ }
+ function deleteSavedAddress(address) {
+ loading = true
+ error = RootStore.deleteSavedAddress(address)
+ loading = false
+ }
}
Item {
@@ -65,155 +75,6 @@ Item {
}
}
- Component {
- id: delegateSavedAddress
- StatusListItem {
- id: savedAddress
- title: name
- objectName: name
- subTitle: name + " \u2022 " + Utils.getElidedCompressedPk(address)
- implicitWidth: parent.width
- color: "transparent"
- border.color: Theme.palette.baseColor5
- //TODO uncomment when #6456 is fixed
- //titleTextIcon: RootStore.favouriteAddress ? "star-icon" : ""
- statusListItemComponentsSlot.spacing: 0
- property bool showButtons: sensor.containsMouse
-
- components: [
- StatusRoundButton {
- icon.color: savedAddress.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
- type: StatusRoundButton.Type.Tertiary
- icon.name: "send"
- onClicked: {
- root.sendModal.open(address);
- }
- },
- CopyToClipBoardButton {
- type: StatusRoundButton.Type.Tertiary
- icon.color: savedAddress.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
- store: RootStore
- textToCopy: address
- },
- //TODO uncomment when #6456 is fixed
-// StatusRoundButton {
-// icon.color: savedAddress.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
-// type: StatusRoundButton.Type.Tertiary
-// icon.name: savedAddress.favouriteAddress ? "favourite" : "unfavourite"
-// onClicked: {
-// RootStore.setFavourite();
-// }
-// },
- StatusRoundButton {
- icon.color: savedAddress.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
- type: StatusRoundButton.Type.Tertiary
- icon.name: "more"
- onClicked: {
- editDeleteMenu.openMenu(name, address);
- }
- }
- ]
- }
- }
-
- StatusPopupMenu {
- id: editDeleteMenu
- property string contactName
- property string contactAddress
- function openMenu(name, address) {
- contactName = name;
- contactAddress = address;
- popup();
- }
- onClosed: {
- contactName = "";
- contactAddress = "";
- }
- StatusMenuItem {
- text: qsTr("Edit")
- objectName: "editSavedAddress"
- icon.name: "pencil-outline"
- onTriggered: {
- Global.openPopup(addEditSavedAddress,
- {
- edit: true,
- address: editDeleteMenu.contactAddress,
- name: editDeleteMenu.contactName
- })
- }
- }
- StatusMenuSeparator { }
- StatusMenuItem {
- text: qsTr("Delete")
- type: StatusMenuItem.Type.Danger
- icon.name: "delete"
- objectName: "deleteSavedAddress"
- onTriggered: {
- deleteAddressConfirm.name = editDeleteMenu.contactName;
- deleteAddressConfirm.address = editDeleteMenu.contactAddress;
- deleteAddressConfirm.open()
- }
- }
- }
-
- Component {
- id: addEditSavedAddress
- AddEditSavedAddressPopup {
- id: addEditModal
- anchors.centerIn: parent
- onClosed: destroy()
- contactsStore: root.contactsStore
- onSave: {
- _internal.loading = true
- _internal.error = RootStore.createOrUpdateSavedAddress(name, address)
- _internal.loading = false
- close()
- }
- }
- }
-
- StatusModal {
- id: deleteAddressConfirm
- property string address
- property string name
- // NOTE: the `text` property was created as a workaround because
- // setting StatusBaseText.text to `qsTr("...").arg("...")`
- // caused no text to render
- property string text: qsTr("Are you sure you want to remove '%1' from your saved addresses?").arg(name)
- anchors.centerIn: parent
- header.title: qsTr("Are you sure?")
- header.subTitle: name
- contentItem: StatusBaseText {
- anchors.centerIn: parent
- height: contentHeight + topPadding + bottomPadding
- text: deleteAddressConfirm.text
- font.pixelSize: 15
- color: Theme.palette.directColor1
- wrapMode: Text.Wrap
- topPadding: Style.current.padding
- rightPadding: Style.current.padding
- bottomPadding: Style.current.padding
- leftPadding: Style.current.padding
- }
- rightButtons: [
- StatusButton {
- text: qsTr("Cancel")
- onClicked: deleteAddressConfirm.close()
- },
- StatusButton {
- type: StatusBaseButton.Type.Danger
- objectName: "confirmDeleteSavedAddress"
- text: qsTr("Delete")
- onClicked: {
- _internal.loading = true
- _internal.error = RootStore.deleteSavedAddress(deleteAddressConfirm.address)
- deleteAddressConfirm.close()
- _internal.loading = false
- }
- }
- ]
- }
-
SavedAddressesError {
id: errorMessage
anchors.top: header.bottom
@@ -242,6 +103,32 @@ Item {
visible: listView.count > 0
spacing: 5
model: RootStore.savedAddresses
- delegate: delegateSavedAddress
+ delegate: SavedAddressesDelegate {
+ name: model.name
+ address: model.address
+ store: RootStore
+ contactsStore: root.contactsStore
+ onOpenSendModal: root.sendModal.open(address);
+ saveAddress: function(name, address) {
+ _internal.saveAddress(name, address)
+ }
+ deleteSavedAddress: function(address) {
+ _internal.deleteSavedAddress(address)
+ }
+ }
+ }
+
+ Component {
+ id: addEditSavedAddress
+ AddEditSavedAddressPopup {
+ id: addEditModal
+ anchors.centerIn: parent
+ onClosed: destroy()
+ contactsStore: root.contactsStore
+ onSave: {
+ _internal.saveAddress(name, address)
+ close()
+ }
+ }
}
}
diff --git a/ui/imports/shared/controls/SavedAddressesDelegate.qml b/ui/imports/shared/controls/SavedAddressesDelegate.qml
new file mode 100644
index 0000000000..ccd9575769
--- /dev/null
+++ b/ui/imports/shared/controls/SavedAddressesDelegate.qml
@@ -0,0 +1,176 @@
+import QtQuick 2.13
+import QtQuick.Controls 2.13
+
+import utils 1.0
+
+import StatusQ.Controls 0.1
+import StatusQ.Components 0.1
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Popups 0.1
+import shared.controls 1.0
+
+import "../popups"
+import "../controls"
+
+StatusListItem {
+ id: root
+
+ property var store
+ property var contactsStore
+ property string name
+ property string address
+ property var saveAddress: function (name, address) {}
+ property var deleteSavedAddress: function (address) {}
+
+ signal openSendModal()
+
+ implicitWidth: parent.width
+
+ title: name
+ objectName: name
+ subTitle: name + " \u2022 " + Utils.getElidedCompressedPk(address)
+ color: "transparent"
+ border.color: Theme.palette.baseColor5
+ //TODO uncomment when #6456 is fixed
+ //titleTextIcon: RootStore.favouriteAddress ? "star-icon" : ""
+ statusListItemComponentsSlot.spacing: 0
+ property bool showButtons: sensor.containsMouse
+
+ components: [
+ StatusRoundButton {
+ icon.color: root.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
+ type: StatusRoundButton.Type.Tertiary
+ icon.name: "send"
+ onClicked: openSendModal()
+ },
+ CopyToClipBoardButton {
+ id: copyButton
+ type: StatusRoundButton.Type.Tertiary
+ icon.color: root.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
+ store: root.store
+ textToCopy: root.address
+ },
+ //TODO uncomment when #6456 is fixed
+ // StatusRoundButton {
+ // icon.color: root.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
+ // type: StatusRoundButton.Type.Tertiary
+ // icon.name: root.favouriteAddress ? "favourite" : "unfavourite"
+ // onClicked: {
+ // RootStore.setFavourite();
+ // }
+ // },
+ StatusRoundButton {
+ visible: !!root.name
+ icon.color: root.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
+ type: StatusRoundButton.Type.Tertiary
+ icon.name: "more"
+ onClicked: {
+ editDeleteMenu.openMenu(root.name, root.address);
+ }
+ },
+ StatusRoundButton {
+ visible: !root.name
+ icon.color: root.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
+ type: StatusRoundButton.Type.Tertiary
+ icon.name: "add"
+ onClicked: {
+ Global.openPopup(addEditSavedAddress,
+ {
+ addAddress: true,
+ address: root.address
+ })
+ }
+ }
+ ]
+
+ StatusPopupMenu {
+ id: editDeleteMenu
+ property string contactName
+ property string contactAddress
+ function openMenu(name, address) {
+ contactName = name;
+ contactAddress = address;
+ popup();
+ }
+ onClosed: {
+ contactName = "";
+ contactAddress = "";
+ }
+ StatusMenuItem {
+ text: qsTr("Edit")
+ objectName: "editroot"
+ assetSettings.name: "pencil-outline"
+ onTriggered: {
+ Global.openPopup(addEditSavedAddress,
+ {
+ edit: true,
+ address: editDeleteMenu.contactAddress,
+ name: editDeleteMenu.contactName
+ })
+ }
+ }
+ StatusMenuSeparator { }
+ StatusMenuItem {
+ text: qsTr("Delete")
+ type: StatusMenuItem.Type.Danger
+ assetSettings.name: "delete"
+ objectName: "deleteSavedAddress"
+ onTriggered: {
+ deleteAddressConfirm.name = editDeleteMenu.contactName;
+ deleteAddressConfirm.address = editDeleteMenu.contactAddress;
+ deleteAddressConfirm.open()
+ }
+ }
+ }
+
+ Component {
+ id: addEditSavedAddress
+ AddEditSavedAddressPopup {
+ id: addEditModal
+ anchors.centerIn: parent
+ onClosed: destroy()
+ contactsStore: root.contactsStore
+ onSave: {
+ root.saveAddress(name, address)
+ close()
+ }
+ }
+ }
+
+ StatusModal {
+ id: deleteAddressConfirm
+ property string address
+ property string name
+ anchors.centerIn: parent
+ header.title: qsTr("Are you sure?")
+ header.subTitle: name
+ contentItem: StatusBaseText {
+ anchors.centerIn: parent
+ height: contentHeight + topPadding + bottomPadding
+ text: qsTr("Are you sure you want to remove '%1' from your saved addresses?").arg(name)
+ font.pixelSize: 15
+ color: Theme.palette.directColor1
+ wrapMode: Text.Wrap
+ topPadding: Style.current.padding
+ rightPadding: Style.current.padding
+ bottomPadding: Style.current.padding
+ leftPadding: Style.current.padding
+ }
+ rightButtons: [
+ StatusButton {
+ text: qsTr("Cancel")
+ onClicked: deleteAddressConfirm.close()
+ },
+ StatusButton {
+ type: StatusBaseButton.Type.Danger
+ objectName: "confirmDeleteSavedAddress"
+ text: qsTr("Delete")
+ onClicked: {
+ root.deleteSavedAddress(deleteAddressConfirm.address)
+ deleteAddressConfirm.close()
+ }
+ }
+ ]
+ }
+}
diff --git a/ui/imports/shared/controls/TransactionDelegate.qml b/ui/imports/shared/controls/TransactionDelegate.qml
index d1a4ab8bd0..84ce6289da 100644
--- a/ui/imports/shared/controls/TransactionDelegate.qml
+++ b/ui/imports/shared/controls/TransactionDelegate.qml
@@ -25,12 +25,13 @@ StatusListItem {
property string resolvedSymbol: root.symbol != "" ? root.symbol : "ETH"
property string savedAddressName
+ state: "normal"
asset.isImage: true
asset.name: Style.png("tokens/%1".arg(resolvedSymbol))
- statusListItemTitle.font.weight: Font.Medium
- title: isIncoming ? qsTr("Receive %1").arg(resolvedSymbol) : !!savedAddressName ?
+ title: modelData !== undefined && !!modelData ?
+ isIncoming ? qsTr("Receive %1").arg(resolvedSymbol) : !!savedAddressName ?
qsTr("Send %1 to %2").arg(resolvedSymbol).arg(savedAddressName) :
- qsTr("Send %1 to %2").arg(resolvedSymbol).arg(Utils.compactAddress(modelData.to, 4))
+ qsTr("Send %1 to %2").arg(resolvedSymbol).arg(Utils.compactAddress(modelData.to, 4)): ""
subTitle: shortTimeStamp
inlineTagModel: 1
inlineTagDelegate: InformationTag {
@@ -60,8 +61,8 @@ StatusListItem {
height: 18
}
StatusBaseText {
+ id: cryptoValueText
text: "%1 %2".arg(cryptoValue).arg(resolvedSymbol)
- font.pixelSize: 15
color: Theme.palette.directColor1
}
}
@@ -92,4 +93,41 @@ StatusListItem {
height: 10
}
}
+
+ states: [
+ State {
+ name: "normal"
+ PropertyChanges {
+ target: asset
+ width: 40
+ height: 40
+ }
+ PropertyChanges {
+ target: statusListItemTitle
+ font.weight: Font.Medium
+ font.pixelSize: 15
+ }
+ PropertyChanges {
+ target: cryptoValueText
+ font.pixelSize: 15
+ }
+ },
+ State {
+ name: "big"
+ PropertyChanges {
+ target: asset
+ width: 50
+ height: 50
+ }
+ PropertyChanges {
+ target: statusListItemTitle
+ font.weight: Font.Bold
+ font.pixelSize: 17
+ }
+ PropertyChanges {
+ target: cryptoValueText
+ font.pixelSize: 17
+ }
+ }
+ ]
}
diff --git a/ui/imports/shared/controls/qmldir b/ui/imports/shared/controls/qmldir
index e89bd65eb8..25d352f947 100644
--- a/ui/imports/shared/controls/qmldir
+++ b/ui/imports/shared/controls/qmldir
@@ -27,3 +27,5 @@ InformationTile 1.0 InformationTile.qml
SocialLinkPreview 1.0 SocialLinkPreview.qml
AssetsDetailsHeader 1.0 AssetsDetailsHeader.qml
InformationTag 1.0 InformationTag.qml
+TransactionDetailsHeader.qml 1.0 TransactionDetailsHeader.qml
+SavedAddressesDelegate 1.0 SavedAddressesDelegate.qml
diff --git a/ui/imports/shared/popups/AddEditSavedAddressPopup.qml b/ui/imports/shared/popups/AddEditSavedAddressPopup.qml
new file mode 100644
index 0000000000..c575d4b97d
--- /dev/null
+++ b/ui/imports/shared/popups/AddEditSavedAddressPopup.qml
@@ -0,0 +1,115 @@
+import QtQuick 2.13
+import QtQuick.Controls 2.13
+import QtQml.Models 2.14
+
+import utils 1.0
+import shared.controls 1.0
+import shared.panels 1.0
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Controls.Validators 0.1
+import StatusQ.Popups.Dialog 0.1
+
+import "../stores"
+
+StatusDialog {
+ id: root
+
+ property bool edit: false
+ property bool addAddress: false
+ property string address
+ property alias name: nameInput.text
+ property var contactsStore
+
+ signal save(string name, string address)
+
+ QtObject {
+ id: d
+ property int validationMode: root.edit ?
+ StatusInput.ValidationMode.Always
+ : StatusInput.ValidationMode.OnlyWhenDirty
+ property bool valid: addressInput.isValid && nameInput.valid // TODO: Add network preference and emoji
+ property bool dirty: nameInput.input.dirty
+ }
+
+ width: 574
+ height: 490
+
+ header: StatusDialogHeader {
+ headline.title: edit ? qsTr("Edit saved address") : qsTr("Add saved address")
+ headline.subtitle: edit ? name : ""
+ }
+
+ onOpened: {
+ if(edit || addAddress) {
+ addressInput.input.text = root.address
+ }
+ nameInput.input.edit.forceActiveFocus(Qt.MouseFocusReason)
+ }
+
+ Column {
+ width: parent.width
+ height: childrenRect.height
+ topPadding: Style.current.xlPadding
+
+ spacing: Style.current.bigPadding
+
+ StatusInput {
+ id: nameInput
+ implicitWidth: parent.width
+ input.edit.objectName: "savedAddressNameInput"
+ minimumHeight: 56
+ maximumHeight: 56
+ placeholderText: qsTr("Enter a name")
+ label: qsTr("Name")
+ validators: [
+ StatusMinLengthValidator {
+ minLength: 1
+ errorMessage: qsTr("Name must not be blank")
+ },
+ StatusRegularExpressionValidator {
+ regularExpression: /^[^<>]+$/
+ errorMessage: qsTr("This is not a valid account name")
+ }
+ ]
+ charLimit: 40
+ validationMode: d.validationMode
+ }
+
+ // To-Do use StatusInput within the below component
+ RecipientSelector {
+ id: addressInput
+ implicitWidth: parent.width
+ inputWidth: implicitWidth
+ accounts: RootStore.accounts
+ contactsStore: root.contactsStore
+ label: qsTr("Address")
+ input.textField.objectName: "savedAddressAddressInput"
+ input.placeholderText: qsTr("Enter ENS Name or Ethereum Address")
+ labelFont.pixelSize: 15
+ labelFont.weight: Font.Normal
+ input.implicitHeight: 56
+ input.textField.anchors.rightMargin: 0
+ isSelectorVisible: false
+ addContactEnabled: false
+ onSelectedRecipientChanged: {
+ root.address = selectedRecipient.address
+ }
+ readOnly: root.edit || root.addAddress
+ wrongInputValidationError: qsTr("Please enter a valid ENS name OR Ethereum Address")
+ }
+ }
+
+ footer: StatusDialogFooter {
+ rightButtons: ObjectModel {
+ StatusButton {
+ text: root.edit ? qsTr("Save") : qsTr("Add address")
+ enabled: d.valid && d.dirty
+ onClicked: root.save(name, address)
+ objectName: "addSavedAddress"
+ }
+ }
+ }
+}
diff --git a/ui/imports/shared/popups/qmldir b/ui/imports/shared/popups/qmldir
index 42b0b00814..470ea5bd27 100644
--- a/ui/imports/shared/popups/qmldir
+++ b/ui/imports/shared/popups/qmldir
@@ -21,3 +21,4 @@ ProfilePopup 1.0 ProfilePopup.qml
ImageCropWorkflow 1.0 ImageCropWorkflow.qml
ImportCommunityPopup 1.0 ImportCommunityPopup.qml
DisplayNamePopup 1.0 DisplayNamePopup.qml
+AddEditSavedAddressPopup 1.0 AddEditSavedAddressPopup.qml
diff --git a/ui/imports/shared/stores/RootStore.qml b/ui/imports/shared/stores/RootStore.qml
index 9cc58afba1..c967e5919b 100644
--- a/ui/imports/shared/stores/RootStore.qml
+++ b/ui/imports/shared/stores/RootStore.qml
@@ -38,6 +38,7 @@ QtObject {
property var historyTransactions: walletSectionTransactions.model
property bool isNonArchivalNode: history.isNonArchivalNode
+ property var currentAccount: walletSectionCurrent
property var walletTokensModule: walletSectionAllTokens
property var tokens: walletSectionAllTokens.all
property var accounts: walletSectionAccounts.model
@@ -170,6 +171,10 @@ QtObject {
return globalUtils.hex2Eth(value)
}
+ function hex2Gwei(value) {
+ return globalUtils.hex2Gwei(value)
+ }
+
function findTokenSymbolByAddress(address) {
return walletSectionAllTokens.findTokenSymbolByAddress(address)
@@ -178,4 +183,20 @@ QtObject {
function getNameForSavedWalletAddress(address) {
return walletSectionSavedAddresses.getNameByAddress(address)
}
+
+ function createOrUpdateSavedAddress(name, address) {
+ return walletSectionSavedAddresses.createOrUpdateSavedAddress(name, address)
+ }
+
+ function deleteSavedAddress(address) {
+ return walletSectionSavedAddresses.deleteSavedAddress(address)
+ }
+
+ function getLatestBlockNumber() {
+ return walletSectionTransactions.getLastTxBlockNumber()
+ }
+
+ function getGasEthValue(gweiValue, gasLimit) {
+ return profileSectionModule.ensUsernamesModule.getGasEthValue(gweiValue, gasLimit)
+ }
}
diff --git a/ui/imports/shared/views/HistoryView.qml b/ui/imports/shared/views/HistoryView.qml
index e4721a1d95..d618c6fb76 100644
--- a/ui/imports/shared/views/HistoryView.qml
+++ b/ui/imports/shared/views/HistoryView.qml
@@ -21,6 +21,8 @@ ColumnLayout {
property int pageSize: 20 // number of transactions per page
property bool isLoading: false
+ signal launchTransactionDetail(var transaction)
+
function fetchHistory() {
if (RootStore.isFetchingHistory(historyView.account.address)) {
isLoading = true
@@ -78,7 +80,7 @@ ColumnLayout {
onLoaded: {
item.modelData = model
}
- }
+ }
ScrollBar.vertical: StatusScrollBar {}
@@ -99,7 +101,7 @@ ColumnLayout {
StatusListItem {
property var modelData
height: 40
- title: Utils.formatShortDate(modelData.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat)
+ title: modelData !== undefined && !!modelData ? Utils.formatShortDate(modelData.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat) : ""
statusListItemTitle.color: Theme.palette.baseColor1
color: Theme.palette.statusListItem.backgroundColor
sensor.enabled: false
@@ -109,21 +111,18 @@ ColumnLayout {
Component {
id: transactionDelegate
TransactionDelegate {
- isIncoming: modelData !== undefined ? modelData.to === account.address: false
+ isIncoming: modelData !== undefined && !!modelData ? modelData.to === account.address: false
currentCurrency: RootStore.currentCurrency
- cryptoValue: modelData !== undefined ? RootStore.hex2Eth(modelData.value) : ""
+ cryptoValue: modelData !== undefined && !!modelData ? RootStore.hex2Eth(modelData.value) : ""
fiatValue: RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency)
- networkIcon: modelData !== undefined ? RootStore.getNetworkIcon(modelData.chainId) : ""
- networkColor: modelData !== undefined ? RootStore.getNetworkColor(modelData.chainId) : ""
- networkName: modelData !== undefined ? RootStore.getNetworkShortName(modelData.chainId) : ""
- symbol: modelData !== undefined ? RootStore.findTokenSymbolByAddress(modelData.contract) : ""
- transferStatus: modelData !== undefined ? RootStore.hex2Dec(modelData.txStatus) : ""
- shortTimeStamp: modelData !== undefined ? Utils.formatShortTime(modelData.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat) : ""
- savedAddressName: modelData !== undefined ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
- onClicked: {
- transactionModal.transaction = modelData
- transactionModal.open()
- }
+ networkIcon: modelData !== undefined && !!modelData ? RootStore.getNetworkIcon(modelData.chainId) : ""
+ networkColor: modelData !== undefined && !!modelData ? RootStore.getNetworkColor(modelData.chainId) : ""
+ networkName: modelData !== undefined && !!modelData ? RootStore.getNetworkShortName(modelData.chainId) : ""
+ symbol: modelData !== undefined && !!modelData ? RootStore.findTokenSymbolByAddress(modelData.contract) : ""
+ transferStatus: modelData !== undefined && !!modelData ? RootStore.hex2Dec(modelData.txStatus) : ""
+ shortTimeStamp: modelData !== undefined && !!modelData ? Utils.formatShortTime(modelData.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat) : ""
+ savedAddressName: modelData !== undefined && !!modelData ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
+ onClicked: launchTransactionDetail(modelData)
}
}
@@ -131,8 +130,4 @@ ColumnLayout {
id: loadingImageComponent
StatusLoadingIndicator {}
}
-
- TransactionModal {
- id: transactionModal
- }
}
diff --git a/ui/imports/shared/views/TransactionDetailView.qml b/ui/imports/shared/views/TransactionDetailView.qml
new file mode 100644
index 0000000000..b35cf79df6
--- /dev/null
+++ b/ui/imports/shared/views/TransactionDetailView.qml
@@ -0,0 +1,250 @@
+import QtQuick 2.13
+import QtQuick.Layouts 1.13
+import QtQuick.Controls 2.14
+import QtQuick.Window 2.12
+
+import StatusQ.Components 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Core 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Popups 0.1
+
+import shared.controls 1.0
+import utils 1.0
+
+import "../stores"
+import "../controls"
+
+Item {
+ id: root
+
+ property var currentAccount: RootStore.currentAccount
+ property var contactsStore
+ property var transaction
+ property var sendModal
+
+ signal goBack()
+
+ QtObject {
+ id: d
+ readonly property bool isIncoming: root.transaction !== undefined && !!root.transaction ? root.transaction.to === currentAccount.address : false
+ readonly property string savedAddressNameTo: root.transaction !== undefined && !!root.transaction ? d.getNameForSavedWalletAddress(transaction.to) : ""
+ readonly property string savedAddressNameFrom: root.transaction !== undefined && !!root.transaction ? d.getNameForSavedWalletAddress(transaction.from): ""
+ readonly property string from: root.transaction !== undefined && !!root.transaction ? !!savedAddressNameFrom ? savedAddressNameFrom : Utils.compactAddress(transaction.from, 4): ""
+ readonly property string to: root.transaction !== undefined && !!root.transaction ? !!savedAddressNameTo ? savedAddressNameTo : Utils.compactAddress(transaction.to, 4): ""
+
+ function getNameForSavedWalletAddress(address) {
+ return RootStore.getNameForSavedWalletAddress(address)
+ }
+ }
+
+ StatusFlatButton {
+ id: backButton
+ anchors.top: parent.top
+ anchors.left: parent.left
+ Layout.alignment: Qt.AlignTop
+ anchors.topMargin: -Style.current.xlPadding
+ anchors.leftMargin: -Style.current.xlPadding
+ icon.name: "arrow-left"
+ icon.width: 20
+ icon.height: 20
+ text: qsTr("Activity")
+ size: StatusBaseButton.Size.Large
+ onClicked: root.goBack()
+ }
+
+ StatusScrollView {
+ anchors.top: backButton.bottom
+ anchors.left: parent.left
+
+ width: parent.width
+ height: parent.height
+ contentHeight: column.height
+ contentWidth: parent.width
+
+ Column {
+ id: column
+ width: parent.width - Style.current.xlPadding
+
+ spacing: Style.current.bigPadding
+
+ TransactionDelegate {
+ width: parent.width
+
+ modelData: transaction
+ isIncoming: d.isIncoming
+ currentCurrency: RootStore.currentCurrency
+ cryptoValue: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Eth(transaction.value): ""
+ fiatValue: root.transaction !== undefined && !!root.transaction ? RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency): ""
+ networkIcon: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkIcon(transaction.chainId): ""
+ networkColor: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkColor(transaction.chainId): ""
+ networkName: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkShortName(transaction.chainId): ""
+ symbol: root.transaction !== undefined && !!root.transaction ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
+ transferStatus: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Dec(transaction.txStatus): ""
+ shortTimeStamp: root.transaction !== undefined && !!root.transaction ? Utils.formatShortTime(transaction.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat): ""
+ savedAddressName: root.transaction !== undefined && !!root.transaction ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
+ title: d.isIncoming ? qsTr("Received %1 %2 from %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.from) :
+ qsTr("Sent %1 %2 to %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.to)
+ sensor.enabled: false
+ color: Theme.palette.statusListItem.backgroundColor
+ state: "big"
+ }
+
+ SavedAddressesDelegate {
+ width: parent.width
+
+ name: d.isIncoming ? d.savedAddressNameFrom : d.savedAddressNameTo
+ address: root.transaction !== undefined && !!root.transaction ? d.isIncoming ? transaction.from : transaction.to : ""
+ title: d.isIncoming ? d.from : d.to
+ subTitle: root.transaction !== undefined && !!root.transaction ? d.isIncoming ? !!d.savedAddressNameFrom ? Utils.compactAddress(transaction.from, 4) : "" : !!d.savedAddressNameTo ? Utils.compactAddress(transaction.to, 4) : "": ""
+ store: RootStore
+ contactsStore: root.contactsStore
+ onOpenSendModal: root.sendModal.open(address);
+ saveAddress: function(name, address) {
+ RootStore.createOrUpdateSavedAddress(name, address)
+ }
+ deleteSavedAddress: function(address) {
+ RootStore.deleteSavedAddress(address)
+ }
+ }
+
+ StatusExpandableItem {
+ width: parent.width
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ type: StatusExpandableItem.Type.Tertiary
+ expandable: true
+ primaryText: qsTr("Transaction summary")
+ expandableComponent: transactionSummary
+ separatorVisible: false
+ expanded: true
+ }
+
+ StatusExpandableItem {
+ width: parent.width
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ type: StatusExpandableItem.Type.Tertiary
+ expandable: true
+ primaryText: qsTr("Fees")
+ expandableComponent: fees
+ expanded: true
+ }
+
+ StatusListItem {
+ id: data
+ width: parent.width
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ color: "transparent"
+ border.width: 1
+ border.color: Theme.palette.directColor8
+
+ statusListItemTitle.color: Theme.palette.baseColor1
+
+ title: qsTr("Data" )
+ subTitle: root.transaction !== undefined && !!root.transaction ? root.transaction.input : ""
+ components: [
+ CopyToClipBoardButton {
+ icon.width: 15
+ icon.height: 15
+ type: StatusRoundButton.Type.Tertiary
+ color: "transparent"
+ icon.color: data.showButtons ? Theme.palette.directColor1 : Theme.palette.baseColor1
+ store: RootStore
+ textToCopy: data.subTitle
+ }
+ ]
+ }
+ }
+ }
+
+
+ Component {
+ id: transactionSummary
+ Column {
+ id: column
+ width: parent.width
+ spacing: 8
+ TransactionDelegate {
+ width: parent.width
+ modelData: transaction
+ isIncoming: d.isIncoming
+ currentCurrency: RootStore.currentCurrency
+ cryptoValue: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Eth(transaction.value): ""
+ fiatValue: RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency)
+ networkIcon: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkIcon(transaction.chainId) : ""
+ networkColor: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkColor(transaction.chainId): ""
+ networkName: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkShortName(transaction.chainId): ""
+ symbol: root.transaction !== undefined && !!root.transaction ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
+ transferStatus: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Dec(transaction.txStatus): ""
+ shortTimeStamp: root.transaction !== undefined && !!root.transaction ? Utils.formatShortTime(transaction.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat): ""
+ savedAddressName: root.transaction !== undefined && !!root.transaction ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
+ title: d.isIncoming ? qsTr("Received %1 %2 from %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.from) :
+ qsTr("Sent %1 %2 to %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.to)
+ sensor.enabled: false
+ color: Theme.palette.statusListItem.backgroundColor
+ border.width: 1
+ border.color: Theme.palette.directColor8
+ }
+ Row {
+ spacing: 8
+ InformationTile {
+ maxWidth: parent.width
+ primaryText: qsTr("Time")
+ secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 on %2").
+ arg(Utils.formatShortTime(transaction.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat)).
+ arg(Utils.formatShortDate(transaction.timestamp * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat)): ""
+ }
+ InformationTile {
+ maxWidth: parent.width
+ primaryText: qsTr("Confirmations")
+ secondaryText: {
+ if(root.transaction !== undefined && !!root.transaction )
+ return Math.abs(RootStore.getLatestBlockNumber() - RootStore.hex2Dec(root.transaction.blockNumber))
+ else
+ return ""
+ }
+ }
+ InformationTile {
+ maxWidth: parent.width
+ primaryText: qsTr("Nonce")
+ secondaryText: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Dec(root.transaction.nonce) : ""
+ }
+ }
+ }
+ }
+
+ Component {
+ id: fees
+ Column {
+ width: parent.width
+ spacing: 8
+ Row {
+ spacing: 8
+ InformationTile {
+ id: baseFee
+ maxWidth: parent.width
+ primaryText: qsTr("Base fee")
+ secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 Gwei").arg(RootStore.hex2Gwei(root.transaction.baseGasFees)) : ""
+ }
+ InformationTile {
+ maxWidth: parent.width
+ primaryText: qsTr("Tip")
+ secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 Gwei • Max: %2 Gwei").
+ arg(RootStore.hex2Gwei(root.transaction.maxPriorityFeePerGas)).
+ arg(RootStore.hex2Gwei(root.transaction.maxFeePerGas)) : ""
+ secondaryLabel.textFormat: Text.RichText
+ }
+ }
+ InformationTile {
+ maxWidth: parent.width
+ primaryText: qsTr("Total fee")
+ secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 Gwei • Max: %2 Gwei").
+ arg(Utils.stripTrailingZeros(RootStore.hex2Gwei(root.transaction.totalFees))).
+ arg(Utils.stripTrailingZeros(RootStore.hex2Gwei(root.transaction.maxTotalFees))) : ""
+ secondaryLabel.textFormat: Text.RichText
+ }
+ }
+ }
+}
diff --git a/ui/imports/shared/views/qmldir b/ui/imports/shared/views/qmldir
index 7b478465c6..b6cc69e0ac 100644
--- a/ui/imports/shared/views/qmldir
+++ b/ui/imports/shared/views/qmldir
@@ -11,3 +11,4 @@ ProfileView 1.0 ProfileView.qml
AssetsView 1.0 AssetsView.qml
HistoryView 1.0 HistoryView.qml
AssetsDetailView 1.0 AssetsDetailView.qml
+TransactionDetailView 1.0 TransactionDetailView.qml
diff --git a/vendor/status-go b/vendor/status-go
index 65be6f2b96..1485b3b4c8 160000
--- a/vendor/status-go
+++ b/vendor/status-go
@@ -1 +1 @@
-Subproject commit 65be6f2b96d72161bfa23a384e9d0f2ccfc85c6a
+Subproject commit 1485b3b4c808dd875d30f17e4be842fcc44c8d35