feat(dapps) implement wallet connect URI input

Other changes

- start Wallet Connect SDK using web engine after wallet is ready
- source WC project ID from the constants in nim
- close list when opening the `ConnectDappModal`
- remove the old POC modal instantiation
- rename ConnectDappPopup to Modal for consistency
- move specific dapps related user settings to their place in the component
- add DAppsStore to be used for dapps abstraction

Updates #14556
This commit is contained in:
Stefan 2024-05-01 18:15:42 +02:00 committed by Stefan Dunca
parent 0de54bb584
commit 1f60410db8
14 changed files with 247 additions and 134 deletions

View File

@ -1,6 +1,6 @@
import NimQml, strutils, os import NimQml, strutils, os
import ../../constants import constants
# Local App Settings keys: # Local App Settings keys:
const LAS_KEY_LANGUAGE* = "global/language" const LAS_KEY_LANGUAGE* = "global/language"
@ -207,3 +207,9 @@ QtObject:
of LAS_KEY_FAKE_LOADING_SCREEN_ENABLED: self.fakeLoadingScreenEnabledChanged() of LAS_KEY_FAKE_LOADING_SCREEN_ENABLED: self.fakeLoadingScreenEnabledChanged()
of LAS_KEY_SHARDED_COMMUNITIES_ENABLED: self.wakuV2ShardedCommunitiesEnabledChanged() of LAS_KEY_SHARDED_COMMUNITIES_ENABLED: self.wakuV2ShardedCommunitiesEnabledChanged()
of LAS_KEY_TRANSLATIONS_ENABLED: self.translationsEnabledChanged() of LAS_KEY_TRANSLATIONS_ENABLED: self.translationsEnabledChanged()
proc getWalletConnectProjectID*(self: LocalAppSettings): string {.slot.} =
return constants.WALLET_CONNECT_PROJECT_ID
QtProperty[string] walletConnectProjectID:
read = getWalletConnectProjectID

View File

@ -46,6 +46,7 @@ Button {
property color textHoverColor: textColor property color textHoverColor: textColor
property color disabledTextColor property color disabledTextColor
property color borderColor: "transparent" property color borderColor: "transparent"
property int borderWidth: 0
property bool textFillWidth: false property bool textFillWidth: false
property int radius: size === StatusBaseButton.Size.Tiny ? 6 : 8 property int radius: size === StatusBaseButton.Size.Tiny ? 6 : 8
@ -126,6 +127,7 @@ Button {
background: Rectangle { background: Rectangle {
radius: root.radius radius: root.radius
border.color: root.borderColor border.color: root.borderColor
border.width: root.borderWidth
color: { color: {
if (!root.enabled || !root.interactive) if (!root.enabled || !root.interactive)
return disabledColor return disabledColor

View File

@ -104,6 +104,8 @@ QtObject {
property color white: getColor('white') property color white: getColor('white')
property color transparent: "#00000000" property color transparent: "#00000000"
property color green: getColor('green')
property color blue: getColor('blue') property color blue: getColor('blue')
property color darkBlue: getColor('blue2') property color darkBlue: getColor('blue2')

View File

@ -90,6 +90,7 @@ StatusButton {
text: qsTr("Connect a dApp via WalletConnect") text: qsTr("Connect a dApp via WalletConnect")
onClicked: { onClicked: {
root.connectDapp() root.connectDapp()
popup.close()
} }
} }
} }

View File

@ -11,6 +11,8 @@ import StatusQ.Popups 0.1
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import shared.popups.walletconnect 1.0
import utils 1.0 import utils 1.0
import "../controls" import "../controls"
@ -81,7 +83,26 @@ Item {
visible: !root.walletStore.showSavedAddresses && Global.featureFlags.dappsEnabled visible: !root.walletStore.showSavedAddresses && Global.featureFlags.dappsEnabled
onConnectDapp: { onConnectDapp: {
console.warn("TODO: run ConnectDappPopup...") connectDappLoader.active = true
}
Loader {
id: connectDappLoader
active: false
onLoaded: item.open()
sourceComponent: ConnectDappModal {
visible: true
onClosed: connectDappLoader.active = false
onPair: (uri) => {
this.close()
console.debug(`TODO(#14556): ConnectionRequestDappModal with ${uri}`)
}
}
} }
} }

View File

@ -1,45 +0,0 @@
/////////////////////////////////////////////////////
// WalletConnect POC - to remove this file
/////////////////////////////////////////////////////
import QtQuick 2.15
import AppLayouts.Wallet.stores 1.0 as WalletStores
import shared.popups.walletconnect 1.0
Item {
id: root
required property var controller
property alias modal: modal
property alias sdk: sdk
property alias url: sdk.url
POCWalletConnectModal {
id: modal
controller: root.controller
sdk: sdk
}
WalletConnectSDK {
id: sdk
projectId: controller.projectId
active: WalletStores.RootStore.walletSectionInst.walletReady && (controller.hasActivePairings || modal.opened)
onSessionRequestEvent: (details) => {
modal.openWithSessionRequestEvent(details)
}
}
Connections {
target: root.controller
function onRequestOpenWalletConnectPopup(uri) {
modal.openWithUri(uri)
}
}
}

View File

@ -27,6 +27,7 @@ import shared.stores 1.0
import shared.popups.send 1.0 import shared.popups.send 1.0
import shared.popups.send.views 1.0 import shared.popups.send.views 1.0
import shared.stores.send 1.0 import shared.stores.send 1.0
import shared.popups.walletconnect 1.0
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
@ -43,11 +44,6 @@ import AppLayouts.Communities.stores 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStore import AppLayouts.Wallet.stores 1.0 as WalletStore
import AppLayouts.Wallet.popups 1.0 as WalletPopups import AppLayouts.Wallet.popups 1.0 as WalletPopups
/////////////////////////////////////////////////////
// WalletConnect POC - to remove
import AppLayouts.Wallet.views.pocwalletconnect 1.0
/////////////////////////////////////////////////////
import mainui.activitycenter.stores 1.0 import mainui.activitycenter.stores 1.0
import mainui.activitycenter.popups 1.0 import mainui.activitycenter.popups 1.0
@ -82,6 +78,18 @@ Item {
walletAssetStore: appMain.walletAssetsStore walletAssetStore: appMain.walletAssetsStore
tokensStore: appMain.tokensStore tokensStore: appMain.tokensStore
} }
readonly property DAppsStore dappsStore: DAppsStore {
wCSDK: WalletConnectSDK {
active: WalletStore.RootStore.walletSectionInst.walletReady
projectId: WalletStore.RootStore.appSettings.walletConnectProjectID
onSessionRequestEvent: (details) => {
// TODO #14556
console.debug(`@dd onSessionRequestEvent: ${JSON.stringify(details)}`)
}
}
}
// set from main.qml // set from main.qml
property var sysPalette property var sysPalette
@ -2032,23 +2040,4 @@ Item {
onClosed: userAgreementLoader.active = false onClosed: userAgreementLoader.active = false
} }
} }
/////////////////////////////////////////////////////
// WalletConnect POC - to remove
POCWalletConnect {
id: walletConnect
anchors.top: parent.bottom
width: 100
height: 100
controller: WalletStore.RootStore.walletSectionInst.walletConnectController
Connections {
target: Global
function onPopupWalletConnect() {
walletConnect.modal.open()
}
}
}
/////////////////////////////////////////////////////
} }

View File

@ -0,0 +1,67 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.14
import StatusQ.Core 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Controls 0.1
import utils 1.0
import "ConnectDappModal"
StatusDialog {
id: root
signal pair(string uri)
width: 480
implicitHeight: 633
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
title: qsTr("Connect a dApp via WalletConnect")
padding: 20
contentItem: ColumnLayout {
StatusBaseText {
text: "WalletConnect URI"
}
WCUriInput {
id: uriInput
}
// Spacer
ColumnLayout {}
StatusLinkText {
text: qsTr("How to copy the dApp URI")
Layout.alignment: Qt.AlignHCenter
Layout.margins: 18
normalColor: linkColor
onClicked: {
console.warn("TODO: open help...")
}
}
}
footer: StatusDialogFooter {
id: footer
rightButtons: ObjectModel {
StatusButton {
height: 44
text: qsTr("Done")
enabled: uriInput.valid && uriInput.text.length > 0
onClicked: root.pair(uriInput.text)
}
}
}
}

View File

@ -0,0 +1,120 @@
import QtQuick 2.15
import QtQml 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
ColumnLayout {
id: root
readonly property bool valid: input.valid && input.text.length > 0
readonly property alias text: input.text
StatusBaseInput {
id: input
Layout.fillWidth: true
Layout.preferredHeight: 132
placeholderText: qsTr("Paste URI")
verticalAlignment: TextInput.AlignTop
valid: {
let uri = input.text
if(uri.length === 0) {
errorText.text = ""
return true
}
if(containsOnlyEmoji(uri)) {
errorText.text = qsTr("WalletConnect URI too cool")
return false
} else if(!validURI(uri)) {
errorText.text = qsTr("WalletConnect URI invalid")
return false
} else if(wcUriAlreadyUsed(uri)) {
errorText.text = qsTr("WalletConnect URI already used")
return false
} else if(wcUriExpired(uri)) {
errorText.text = qsTr("WalletConnect URI has expired")
return false
}
errorText.text = ""
return true
}
function validURI(uri) {
var regex = /^wc:[0-9a-fA-F-]*@([1-9][0-9]*)(\?([a-zA-Z-]+=[^&]+)(&[a-zA-Z-]+=[^&]+)*)?$/
return regex.test(uri)
}
function containsOnlyEmoji(uri) {
var emojiRegex = new RegExp("[\\u203C-\\u3299\\u1F000-\\u1F644]");
return !emojiRegex.test(uri);
}
function wcUriAlreadyUsed(uri) {
// TODO: Check if URI is already used
return false
}
function wcUriExpired(uri) {
// TODO: Check if URI is expired
return false
}
rightComponent: Item {
width: pasteButton.implicitWidth
height: pasteButton.implicitHeight
readonly property bool showIcon: input.valid && input.text.length > 0
StatusIcon {
anchors.centerIn: parent
icon: "tiny/tiny-checkmark"
color: Theme.palette.green
visible: showIcon
}
StatusButton {
id: pasteButton
text: qsTr("Paste")
size: StatusBaseButton.Size.Small
visible: !showIcon
borderWidth: enabled ? 1 : 0
borderColor: textColor
enabled: input.edit.canPaste
onClicked: {
input.edit.paste()
input.edit.focus = true
}
}
}
multiline: true
}
StatusBaseText {
id: errorText
visible: !input.valid && input.text.length !== 0
Layout.alignment: Qt.AlignRight
color: Theme.palette.dangerColor1
}
}

View File

@ -1,57 +0,0 @@
import QtQuick 2.15
import StatusQ.Core 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls 0.1
import utils 1.0
StatusModal {
id: root
width: Constants.dapps.connectDappPopupWidth
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
headerSettings.title: qsTr("Connect a Dapp via WalletConnect")
StatusScrollView {
id: scrollView
anchors.fill: parent
padding: 0
contentWidth: availableWidth
Item {
id: content
implicitWidth: loader.implicitWidth
implicitHeight: loader.implicitHeight
width: scrollView.availableWidth
Loader {
id: loader
width: parent.width
sourceComponent: {
// TODO
return undefined
}
}
}
}
rightButtons: [
StatusButton {
id: primaryButton
height: Constants.dapps.footerButtonsHeight
text: qsTr("Done")
visible: text !== ""
enabled: root.store.primaryPopupButtonEnabled
onClicked: {
console.warn("TODO: done...")
}
}
]
}

View File

@ -1,2 +1,2 @@
WalletConnectSDK 1.0 WalletConnectSDK.qml WalletConnectSDK 1.0 WalletConnectSDK.qml
ConnectDappPopup 1.0 ConnectDappPopup.qml ConnectDappModal 1.0 ConnectDappModal.qml

View File

@ -0,0 +1,11 @@
import QtQuick 2.15
import shared.popups.walletconnect 1.0
QtObject {
id: root
required property WalletConnectSDK wCSDK
// Here we will have business logic calls and expose connections history models
}

View File

@ -7,3 +7,4 @@ PermissionsStore 1.0 PermissionsStore.qml
TokenBalanceHistoryStore 1.0 TokenBalanceHistoryStore.qml TokenBalanceHistoryStore 1.0 TokenBalanceHistoryStore.qml
TokenMarketValuesStore 1.0 TokenMarketValuesStore.qml TokenMarketValuesStore 1.0 TokenMarketValuesStore.qml
NetworkConnectionStore 1.0 NetworkConnectionStore.qml NetworkConnectionStore 1.0 NetworkConnectionStore.qml
DAppsStore 1.0 DAppsStore.qml

View File

@ -788,11 +788,6 @@ QtObject {
} }
} }
readonly property QtObject dapps: QtObject {
readonly property int connectDappPopupWidth: 480
readonly property int footerButtonsHeight: 44
}
readonly property QtObject localPairingAction: QtObject { readonly property QtObject localPairingAction: QtObject {
readonly property int actionUnknown: 0 readonly property int actionUnknown: 0
readonly property int actionConnect: 1 readonly property int actionConnect: 1