Skip to content

Commit

Permalink
feat(dapps) add DAppsService component and ConnectDAppModal
Browse files Browse the repository at this point in the history
Also rename pairing modal accordingly to make room for the proper
ConnectDAppModal.qml

Closes #14607
  • Loading branch information
stefandunca committed May 7, 2024
1 parent ad2aaa7 commit 8e79216
Show file tree
Hide file tree
Showing 19 changed files with 2,238 additions and 66 deletions.
82 changes: 82 additions & 0 deletions storybook/pages/ConnectDAppModalPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15
import Qt.labs.settings 1.0
import QtTest 1.15

import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups.Dialog 0.1

import Models 1.0
import Storybook 1.0

import shared.popups.walletconnect 1.0

import SortFilterProxyModel 0.2

import AppLayouts.Wallet.panels 1.0

import utils 1.0
import shared.stores 1.0

Item {
id: root

function openModal() {
modal.openWithFilter([], [], JSON.parse(`{
"metadata": {
"description": "React App for WalletConnect",
"icons": [
"https://avatars.githubusercontent.com/u/37784886"
],
"name": "React App",
"url": "https://react-app.walletconnect.com",
"verifyUrl": "https://verify.walletconnect.com"
},
"publicKey": "300a6a1df4cb0cd73eb652f11845f35a318541eb18ab369860be85c0c2ada54a"
}`))
}

// qml Splitter
SplitView {
anchors.fill: parent

ColumnLayout {
SplitView.fillWidth: true

Component.onCompleted: root.openModal()

StatusButton {
id: openButton

Layout.alignment: Qt.AlignHCenter
Layout.margins: 20

text: "Open ConnectDAppModal"

onClicked: root.openModal()
}

ConnectDAppModal {
id: modal

anchors.centerIn: parent

spacing: 8
}

ColumnLayout {}
}

ColumnLayout {
id: optionsSpace
}
}
}

// category: Wallet
13 changes: 10 additions & 3 deletions storybook/pages/DAppsWorkflowPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Item {
anchors.centerIn: parent

spacing: 8

wcService: walletConnectService
}
}
ColumnLayout {}
Expand Down Expand Up @@ -113,7 +115,7 @@ Item {
}
}

function onConnectDappReady() {
function onPairWCReady() {
if (!d.startPairingWorkflowActive)
return

Expand All @@ -130,8 +132,10 @@ Item {
}
}

DAppsStore {
wCSDK: WalletConnectSDK {
WalletConnectService {
id: walletConnectService

wcSDK: WalletConnectSDK {
active: true

projectId: projectIdText.projectId
Expand All @@ -141,6 +145,9 @@ Item {
console.debug(`@dd onSessionRequestEvent: ${JSON.stringify(details)}`)
}
}

dappsStore: DAppsStore {
}
}


Expand Down
4 changes: 0 additions & 4 deletions storybook/stubs/shared/stores/DAppsStore.qml
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import QtQuick 2.15

import AppLayouts.Wallet.services.dapps 1.0

QtObject {
id: root

required property WalletConnectSDK wCSDK
}
50 changes: 42 additions & 8 deletions ui/app/AppLayouts/Wallet/panels/DAppsWorkflow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ import QtQuick.Layouts 1.15
import AppLayouts.Wallet.controls 1.0

import shared.popups.walletconnect 1.0
import AppLayouts.Wallet.services.dapps 1.0

import shared.stores 1.0

ConnectedDappsButton {
id: root

required property WalletConnectService wcService

signal dAppsListReady()
signal connectDappReady()
signal pairWCReady()

onClicked: {
dappsListLoader.active = true
Expand All @@ -19,23 +24,23 @@ ConnectedDappsButton {
highlighted: dappsListLoader.active

Loader {
id: connectDappLoader
id: pairWCLoader

active: false

onLoaded: {
item.open()
root.connectDappReady()
root.pairWCReady()
}

sourceComponent: ConnectDappModal {
sourceComponent: PairWCModal {
visible: true

onClosed: connectDappLoader.active = false
onClosed: pairWCLoader.active = false

onPair: (uri) => {
this.close()
console.debug(`TODO(#14556): ConnectionRequestDappModal with ${uri}`)
root.wcService.pair(uri)
}
}
}
Expand All @@ -53,8 +58,8 @@ ConnectedDappsButton {
sourceComponent: DAppsListPopup {
visible: true

onConnectDapp: {
connectDappLoader.active = true
onPairWCDapp: {
pairWCLoader.active = true
this.close()
}
onOpened: {
Expand All @@ -64,4 +69,33 @@ ConnectedDappsButton {
onClosed: dappsListLoader.active = false
}
}

Loader {
id: connectDappLoader

active: false

onLoaded: item.openWithFilter(filterChains, filterAccounts, proposer)

property var filterChains: []
property var filterAccounts: []
property var proposer: null

sourceComponent: ConnectDAppModal {
visible: true

onClosed: connectDappLoader.active = false
}
}

Connections {
target: root.wcService

function onConnectDApp(chains, accounts, proposer) {
connectDappLoader.filterChains = chains
connectDappLoader.filterAccounts = accounts
connectDappLoader.proposer = proposer
connectDappLoader.active = true
}
}
}
2 changes: 2 additions & 0 deletions ui/app/AppLayouts/Wallet/panels/WalletHeader.qml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ Item {
spacing: 8

visible: !root.walletStore.showSavedAddresses && Global.featureFlags.dappsEnabled

wcService: Global.walletConnectService
}

StatusButton {
Expand Down
33 changes: 32 additions & 1 deletion ui/app/AppLayouts/Wallet/services/dapps/WalletConnectSDK.qml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ Item {

signal statusChanged(string message)
signal sdkInit(bool success, var result)
signal pairResponse(bool success)
signal sessionProposal(var sessionProposal)
signal sessionProposalExpired()
signal approveSessionResult(var session, string error)
signal buildApprovedNamespacesResult(var session, string error)
signal approveSessionResult(var approvedNamespaces, string error)
signal rejectSessionResult(string error)
signal sessionRequestEvent(var sessionRequest)
signal sessionRequestUserAnswerResult(bool accept, string error)
Expand All @@ -40,6 +42,8 @@ Item {

signal sessionDelete(var topic, string error)

/// Generates \c pairResponse signal and expects to receive
/// a \c sessionProposal signal with the sessionProposal object
function pair(pairLink) {
wcCalls.pair(pairLink)
}
Expand All @@ -64,6 +68,10 @@ Item {
wcCalls.ping(topic)
}

function buildApprovedNamespaces(params, supportedNamespaces) {
wcCalls.buildApprovedNamespaces(params, supportedNamespaces)
}

function approveSession(sessionProposal, supportedNamespaces) {
wcCalls.approveSession(sessionProposal, supportedNamespaces)
}
Expand Down Expand Up @@ -218,15 +226,32 @@ Item {
d.engine.runJavaScript(`
wc.pair("${pairLink}")
.then((value) => {
wc.statusObject.bubbleConsoleMessage("debug", "@dd SDK.onPairResponse: " + value)
wc.statusObject.onPairResponse("")
})
.catch((e) => {
wc.statusObject.bubbleConsoleMessage("debug", "@dd ERROR SDK.onPairResponse: " + e)
wc.statusObject.onPairResponse(e.message)
})
`
)
}

function buildApprovedNamespaces(params, supportedNamespaces) {
console.debug(`WC WalletConnectSDK.wcCall.buildApprovedNamespaces; params: ${JSON.stringify(params)}, supportedNamespaces: ${JSON.stringify(supportedNamespaces)}`)

d.engine.runJavaScript(`
wc.buildApprovedNamespaces(${JSON.stringify(params)}, ${JSON.stringify(supportedNamespaces)})
.then((approvedNamespaces) => {
wc.statusObject.onBuildApprovedNamespacesResponse(approvedNamespaces, "")
})
.catch((e) => {
wc.statusObject.onBuildApprovedNamespacesResponse("", e.message)
})
`
)
}

function approveSession(sessionProposal, supportedNamespaces) {
console.debug(`WC WalletConnectSDK.wcCall.approveSession; sessionProposal: ${JSON.stringify(sessionProposal)}, supportedNamespaces: ${JSON.stringify(supportedNamespaces)}`)

Expand Down Expand Up @@ -413,6 +438,7 @@ Item {

function onPairResponse(error) {
console.debug(`WC WalletConnectSDK.onPairResponse; error: ${error}`)
root.pairResponse(error == "")
}

function onPingResponse(error) {
Expand All @@ -430,6 +456,11 @@ Item {
d.resetPairingsModel()
}

function onBuildApprovedNamespacesResponse(approvedNamespaces, error) {
console.debug(`WC WalletConnectSDK.onBuildApprovedNamespacesResponse; approvedNamespaces: ${approvedNamespaces ? JSON.stringify(approvedNamespaces, null, 2) : "-"}, error: ${error}`)
root.buildApprovedNamespacesResult(approvedNamespaces, error)
}

function onApproveSessionResponse(session, error) {
console.debug(`WC WalletConnectSDK.onApproveSessionResponse; sessionTopic: ${JSON.stringify(session, null, 2)}, error: ${error}`)
d.resetPairingsModel()
Expand Down
75 changes: 75 additions & 0 deletions ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import QtQuick 2.15

import AppLayouts.Wallet.services.dapps 1.0
import AppLayouts.Profile.stores 1.0
import shared.stores 1.0
import shared.popups.walletconnect 1.0

QtObject {
id: root

required property WalletConnectSDK wcSDK
required property DAppsStore dappsStore
//required property WalletStore walletStore

function pair(uri) {
wcSDK.pair(uri)
}

/// proposer taken from the SessionProposal.params.proposer
signal connectDApp(var chains, var accounts, var proposer)

readonly property Connections sdkConnections: Connections {
target: wcSDK
function onPairResponse(success) {
// TODO #14607: propagate pairings if the session is expired and report as error to the PairWCModal
}

function onSessionProposal(sessionProposal) {
// TODO DEV: get the available chains and accounts from the source
_d.currentSessionProposal = sessionProposal
wcSDK.buildApprovedNamespaces(sessionProposal.params, JSON.parse(`{
"eip155": {
"chains": ["eip155:11155111", "eip155:421614", "eip155:11155420"],
"methods": ["eth_sendTransaction", "personal_sign"],
"events": ["accountsChanged", "chainChanged"],
"accounts": [
"eip155:11155111:0xE2D622C817878DA5143BBE06866CA8E35273BA8A",
"eip155:421614:0xE2D622C817878DA5143BBE06866CA8E35273BA8A",
"eip155:11155420:0xE2D622C817878DA5143BBE06866CA8E35273BA8A",
"eip155:11155111:0xBD54A96C0AE19A220C8E1234F54C940DFAB34639",
"eip155:421614:0xBD54A96C0AE19A220C8E1234F54C940DFAB34639",
"eip155:11155420:0xBD54A96C0AE19A220C8E1234F54C940DFAB34639",
"eip155:11155111:0x5D7905390B77A937AE8C444AA8BF7FA9A6A7DBA0",
"eip155:421614:0x5D7905390B77A937AE8C444AA8BF7FA9A6A7DBA0",
"eip155:11155420:0x5D7905390B77A937AE8C444AA8BF7FA9A6A7DBA0"
]
}
}`))
}

function onBuildApprovedNamespacesResult(approvedNamespaces, error) {
if(error) {
// TODO: error reporting
return
}

let res = _d.extractChainsAndAccountsFromApprovedNamespaces(approvedNamespaces)

root.connectDApp(res.chains, res.accounts, _d.currentSessionProposal.params.proposer)
}
}

readonly property QtObject _d: QtObject {
property var currentSessionProposal: null
function extractChainsAndAccountsFromApprovedNamespaces(approvedNamespaces) {
const eip155Data = approvedNamespaces.eip155;
const chains = eip155Data.chains.map(chain => parseInt(chain.split(':').pop().trim(), 10));
const accountSet = new Set(
eip155Data.accounts.map(account => account.split(':').pop().trim())
);
const uniqueAccounts = Array.from(accountSet);
return { chains, accounts: uniqueAccounts };
}
}
}
Loading

0 comments on commit 8e79216

Please sign in to comment.