fix: checksum validation (#15915)

* feat: checksum validation added to adding saved addresses

Fixes: #15772

* feat: checksum validation added to adding watch only address

Fixes: #15779
This commit is contained in:
saledjenic 2024-08-12 19:56:54 +02:00 committed by GitHub
parent 63076e6ecc
commit 7dc08731f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 131 additions and 14 deletions

View File

@ -71,3 +71,6 @@ proc hasPairedDevices*(self: Controller): bool =
proc reloadAccountTokens*(self: Controller) =
self.walletAccountService.reloadAccountTokens()
proc isChecksumValidForAddress*(self: Controller, address: string): bool =
return self.walletAccountService.isChecksumValidForAddress(address)

View File

@ -123,3 +123,6 @@ method canProfileProveOwnershipOfProvidedAddresses*(self: AccessInterface, addre
method reloadAccountTokens*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isChecksumValidForAddress*(self: AccessInterface, address: string): bool {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -539,3 +539,6 @@ method canProfileProveOwnershipOfProvidedAddresses*(self: Module, addresses: str
method reloadAccountTokens*(self: Module) =
self.view.setIsAccountTokensReloading(true)
self.controller.reloadAccountTokens()
method isChecksumValidForAddress*(self: Module, address: string): bool =
return self.controller.isChecksumValidForAddress(address)

View File

@ -300,7 +300,7 @@ QtObject:
QtProperty[QVariant] lastReloadTimestamp:
read = getLastReloadTimestamp
notify = lastReloadTimestampChanged
proc isAccountTokensReloadingChanged*(self: View) {.signal.}
proc setIsAccountTokensReloading*(self: View, isAccountTokensReloading: bool) =
@ -316,3 +316,5 @@ QtObject:
read = getIsAccountTokensReloading
notify = isAccountTokensReloadingChanged
proc isChecksumValidForAddress*(self: View, address: string): bool {.slot.} =
return self.delegate.isChecksumValidForAddress(address)

View File

@ -252,6 +252,9 @@ proc getNumOfAddressesToGenerateForKeypair*(self: Controller, keyUid: string): i
proc resolveSuggestedPathForKeypair*(self: Controller, keyUid: string): string =
return self.walletAccountService.resolveSuggestedPathForKeypair(keyUid)
proc isChecksumValidForAddress*(self: Controller, address: string): bool =
return self.walletAccountService.isChecksumValidForAddress(address)
proc remainingAccountCapacity*(self: Controller): int =
return self.walletAccountService.remainingAccountCapacity()
@ -259,4 +262,4 @@ proc remainingKeypairCapacity*(self: Controller): int =
return self.walletAccountService.remainingKeypairCapacity()
proc remainingWatchOnlyAccountCapacity*(self: Controller): int =
return self.walletAccountService.remainingWatchOnlyAccountCapacity()
return self.walletAccountService.remainingWatchOnlyAccountCapacity()

View File

@ -107,6 +107,9 @@ method removingSavedAddressConfirmed*(self: AccessInterface, address: string) {.
method savedAddressDeleted*(self: AccessInterface, address: string, errorMsg: string) {.base.} =
raise newException(ValueError, "No implementation available")
method isChecksumValidForAddress*(self: AccessInterface, address: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method remainingAccountCapacity*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -736,6 +736,9 @@ method buildNewSeedPhraseKeypairAndAddItToOrigin*[T](self: Module[T]) =
derivedFrom = genAcc.address)
self.setItemForSelectedOrigin(item)
method isChecksumValidForAddress*[T](self: Module[T], address: string): bool =
return self.controller.isChecksumValidForAddress(address)
method remainingAccountCapacity*[T](self: Module[T]): int =
return self.controller.remainingAccountCapacity()

View File

@ -364,6 +364,9 @@ QtObject:
proc removingSavedAddressRejected*(self: View) {.slot.} =
self.setDisablePopup(false)
proc isChecksumValidForAddress*(self: View, address: string): bool {.slot.} =
return self.delegate.isChecksumValidForAddress(address)
proc remainingAccountCapacity*(self: View): int {.slot.} =
return self.delegate.remainingAccountCapacity()

View File

@ -92,6 +92,17 @@ QtObject:
result.networkService = networkService
result.currencyService = currencyService
proc isChecksumValidForAddress*(self: Service, address: string): bool =
var updated = false
try:
let response = backend.isChecksumValidForAddress(address)
if not response.error.isNil:
error "status-go error", procName="isChecksumValidForAddress", errCode=response.error.code, errDesription=response.error.message
return response.result.getBool
except Exception as e:
error "error: ", procName="isChecksumValidForAddress", errName=e.name, errDesription=e.msg
include service_account
include service_token
include service_keycard

View File

@ -332,3 +332,6 @@ rpc(getBalancesByChain, "wallet"):
rpc(restartWalletReloadTimer, "wallet"):
discard
rpc(isChecksumValidForAddress, "wallet"):
address: string

View File

@ -0,0 +1,22 @@
import QtQuick 2.13
import QtQuick.Controls 2.15
import StatusQ.Controls 0.1
StatusIcon {
id: root
property string tooltipText
MouseArea {
id: tooltipSensor
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
}
StatusToolTip {
visible: tooltipSensor.containsMouse && !!text
text: root.tooltipText
}
}

View File

@ -7,6 +7,7 @@ StatusCenteredFlow 0.1 StatusCenteredFlow.qml
StatusFontSettings 0.1 StatusFontSettings.qml
StatusGridView 0.1 StatusGridView.qml
StatusIcon 0.1 StatusIcon.qml
StatusIconWithTooltip 0.1 StatusIconWithTooltip.qml
StatusIdenticonRingSettings 0.1 StatusIdenticonRingSettings.qml
StatusListView 0.1 StatusListView.qml
StatusModalHeaderSettings 0.1 StatusModalHeaderSettings.qml

View File

@ -176,6 +176,7 @@
<file>StatusQ/Core/StatusFontSettings.qml</file>
<file>StatusQ/Core/StatusGridView.qml</file>
<file>StatusQ/Core/StatusIcon.qml</file>
<file>StatusQ/Core/StatusIconWithTooltip.qml</file>
<file>StatusQ/Core/StatusIdenticonRingSettings.qml</file>
<file>StatusQ/Core/StatusListView.qml</file>
<file>StatusQ/Core/StatusModalHeaderSettings.qml</file>

View File

@ -102,7 +102,7 @@ StatusModal {
property bool chainShortNamesDirty: false
property var networkSelection: []
onNetworkSelectionChanged: {
onNetworkSelectionChanged: {
if (d.networkSelection !== networkSelectPopup.selection) {
networkSelectPopup.selection = d.networkSelection
}
@ -119,6 +119,8 @@ StatusModal {
|| chainShortNamesDirty && (!d.editMode || d.storedChainShortNames !== d.chainShortNames)
|| d.colorId.toUpperCase() !== d.storedColorId.toUpperCase()
property bool incorrectChecksum: false
readonly property var chainPrefixRegexPattern: /[^:]+\:?|:/g
readonly property bool addressInputIsENS: !!d.ens &&
@ -231,6 +233,13 @@ StatusModal {
addressInput.errorMessageCmp.visible = true
}
function checkIfAddressChecksumIsValid() {
d.incorrectChecksum = false
if (d.addressInputIsAddress) {
d.incorrectChecksum = !root.store.isChecksumValidForAddress(d.address)
}
}
function checkForAddressInputErrorsWarnings() {
addressInput.errorMessageCmp.visible = false
addressInput.errorMessageCmp.color = Theme.palette.dangerColor1
@ -261,6 +270,7 @@ StatusModal {
networkSelector.state = ""
if (d.addressInputIsAddress) {
d.checkForAddressInputOwningErrorsWarnings()
d.checkIfAddressChecksumIsValid()
return
}
@ -453,7 +463,7 @@ StatusModal {
enabled: !(d.editMode || d.addAddress)
input.edit.textFormat: TextEdit.RichText
input.rightComponent: (d.resolvingEnsNameInProgress || d.checkingContactsAddressInProgress) ?
loadingIndicator : null
loadingIndicator : d.incorrectChecksum? incorrectChecksumComponent : null
input.asset.name: d.addressInputValid && !d.editMode ? "checkbox" : ""
input.asset.color: enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
input.asset.width: 17
@ -472,6 +482,18 @@ StatusModal {
StatusLoadingIndicator {}
}
Component {
id: incorrectChecksumComponent
StatusIconWithTooltip {
icon: "warning"
width: 20
height: 20
color: Theme.palette.warningColor1
tooltipText: qsTr("Checksum of the entered address is incorrect")
}
}
onTextChanged: {
if (skipTextUpdate || !d.initialized)
return
@ -503,7 +525,7 @@ StatusModal {
d.ens = ""
d.address = prefixAndAddress.address
d.chainShortNames = prefixAndAddress.prefix
Qt.callLater(()=> {
// Sync chain short names with model. This could result in removing networks from this text
// Call it later to avoid binding loop warnings

View File

@ -304,6 +304,10 @@ QtObject {
}
}
function isChecksumValidForAddress(address) {
return root.walletSectionInst.isChecksumValidForAddress(address)
}
function getNameForAddress(address) {
var name = getNameForWalletAddress(address)
if (name.length === 0) {

View File

@ -20,6 +20,16 @@ Column {
addressInput.reset()
}
QtObject {
id: d
property bool incorrectChecksum: false
function checkIfAddressChecksumIsValid(address) {
d.incorrectChecksum = !root.store.isChecksumValidForAddress(address)
}
}
StatusInput {
id: addressInput
objectName: "AddAccountPopup-WatchOnlyAddress"
@ -29,14 +39,27 @@ Column {
label: qsTr("Ethereum address or ENS name")
placeholderText: qsTr("Type or paste ETH address")
input.multiline: true
input.rightComponent: StatusButton {
anchors.verticalCenter: parent.verticalCenter
borderColor: Theme.palette.primaryColor1
size: StatusBaseButton.Size.Tiny
text: qsTr("Paste")
onClicked: {
addressInput.text = ""
addressInput.input.edit.paste()
input.rightComponent: Row {
spacing: 8
StatusIconWithTooltip {
visible: d.incorrectChecksum
icon: "warning"
width: 20
height: 20
color: Theme.palette.warningColor1
tooltipText: qsTr("Checksum of the entered address is incorrect")
}
StatusButton {
anchors.verticalCenter: parent.verticalCenter
borderColor: Theme.palette.primaryColor1
size: StatusBaseButton.Size.Tiny
text: qsTr("Paste")
onClicked: {
addressInput.text = ""
addressInput.input.edit.paste()
}
}
}
validators: [
@ -46,8 +69,11 @@ Column {
]
onTextChanged: {
d.incorrectChecksum = false
if (addressInput.valid) {
root.store.changeWatchOnlyAccountAddressPostponed(text.trim())
const trimmedText = text.trim()
root.store.changeWatchOnlyAccountAddressPostponed(trimmedText)
d.checkIfAddressChecksumIsValid(trimmedText)
return
}
root.store.cleanWatchOnlyAccountAddress()

View File

@ -167,6 +167,10 @@ BasePopupStore {
root.addAccountModule.startScanningForActivity()
}
function isChecksumValidForAddress(address) {
return root.addAccountModule.isChecksumValidForAddress(address)
}
function remainingAccountCapacity() {
return root.addAccountModule.remainingAccountCapacity()
}