feat(dapp) disconnect wallet connect dapps

Closes: #15189
This commit is contained in:
Stefan 2024-06-25 00:26:53 +03:00 committed by Stefan Dunca
parent fecbd4005e
commit 94dc7b04a5
10 changed files with 248 additions and 153 deletions

View File

@ -27,6 +27,9 @@ QtObject:
proc addWalletConnectSession*(self: Controller, session_json: string): bool {.slot.} = proc addWalletConnectSession*(self: Controller, session_json: string): bool {.slot.} =
return self.service.addSession(session_json) return self.service.addSession(session_json)
proc deactivateWalletConnectSession*(self: Controller, topic: string): bool {.slot.} =
return self.service.deactivateSession(topic)
proc dappsListReceived*(self: Controller, dappsJson: string) {.signal.} proc dappsListReceived*(self: Controller, dappsJson: string) {.signal.}
# Emits signal dappsListReceived with the list of dApps # Emits signal dappsListReceived with the list of dApps

View File

@ -71,6 +71,10 @@ QtObject:
# TODO #14588: call it async # TODO #14588: call it async
return status_go.addSession(session_json) return status_go.addSession(session_json)
proc addSession*(self: Service, topic: string): bool =
# TODO #14588: call it async
return status_go.deactivateSession(topic)
proc getDapps*(self: Service): string = proc getDapps*(self: Service): string =
let validAtEpoch = now().toTime().toUnix() let validAtEpoch = now().toTime().toUnix()
let testChains = self.settingsService.areTestNetworksEnabled() let testChains = self.settingsService.areTestNetworksEnabled()

View File

@ -108,8 +108,11 @@ Item {
color: "grey" color: "grey"
} }
StatusBaseText { text: "Requests Queue" }
ListView { ListView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: Math.min(50, contentHeight)
model: walletConnectService.requestHandler.requestsModel model: walletConnectService.requestHandler.requestsModel
delegate: RowLayout { delegate: RowLayout {
StatusBaseText { StatusBaseText {
@ -119,6 +122,35 @@ Item {
} }
} }
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "grey"
}
StatusBaseText { text: "Persisted Sessions" }
ListView {
Layout.fillWidth: true
Layout.preferredHeight: Math.min(100, contentHeight)
model: sessionsModel
delegate: RowLayout {
StatusBaseText {
text: SQUtils.Utils.elideAndFormatWalletAddress(model.topic, 6, 4)
Layout.fillWidth: true
}
}
}
StatusButton {
text: qsTr("Clear Persistance")
visible: sessionsModel.count > 0
onClicked: {
settings.persistedSessions = "[]"
d.updateSessionsModelAndAddNewIfNotNull(null)
}
}
// spacer // spacer
ColumnLayout {} ColumnLayout {}
@ -268,19 +300,26 @@ Item {
console.info("Persist Session", sessionJson) console.info("Persist Session", sessionJson)
let session = JSON.parse(sessionJson) let session = JSON.parse(sessionJson)
d.updateSessionsModelAndAddNewIfNotNull(session)
let firstIconUrl = session.peer.metadata.icons.length > 0 ? session.peer.metadata.icons[0] : "" return true
let persistedDapp = { }
"name": session.peer.metadata.name,
"url": session.peer.metadata.url, function deactivateWalletConnectSession(topic) {
"iconUrl": firstIconUrl console.info("Deactivate Persisted Session", topic)
}
d.persistedDapps.push(persistedDapp) let sessions = JSON.parse(settings.persistedSessions)
let newSessions = sessions.filter(function(session) {
return session.topic !== topic
})
settings.persistedSessions = JSON.stringify(newSessions)
d.updateSessionsModelAndAddNewIfNotNull(null)
return true return true
} }
function getDapps() { function getDapps() {
this.dappsListReceived(JSON.stringify(d.persistedDapps)) let dappsJson = JSON.stringify(d.persistedDapps)
this.dappsListReceived(dappsJson)
return true return true
} }
@ -323,7 +362,7 @@ Item {
} }
property var accounts: customAccountsModel.count > 0 ? customAccountsModel : defaultAccountsModel property var accounts: customAccountsModel.count > 0 ? customAccountsModel : defaultAccountsModel
readonly property ListModel nonWatchAccounts: accounts readonly property ListModel nonWatchAccounts: accounts
function getNetworkShortNames(chainIds) { function getNetworkShortNames(chainIds) {
return "eth:oeth:arb" return "eth:oeth:arb"
} }
@ -355,15 +394,43 @@ Item {
readonly property int openDappsTestCase: 1 readonly property int openDappsTestCase: 1
readonly property int openPairTestCase: 2 readonly property int openPairTestCase: 2
property var persistedDapps: [ ListModel {
{"name":"Test dApp 1", "url":"https://dapp.test/1","iconUrl":"https://se-sdk-dapp.vercel.app/assets/eip155:1.png"}, id: sessionsModel
{"name":"Test dApp 2", "url":"https://dapp.test/2","iconUrl":"https://react-app.walletconnect.com/assets/eip155-1.png"}, }
{"name":"Test dApp 3", "url":"https://dapp.test/3","iconUrl":"https://react-app.walletconnect.com/assets/eip155-1.png"},
{"name":"Test dApp 4 - very long name !!!!!!!!!!!!!!!!", "url":"https://dapp.test/4","iconUrl":"https://react-app.walletconnect.com/assets/eip155-1.png"},
{"name":"Test dApp 5 - very long url", "url":"https://dapp.test/very_long/url/unusual","iconUrl":"https://react-app.walletconnect.com/assets/eip155-1.png"},
{"name":"Test dApp 6", "url":"https://dapp.test/6","iconUrl":"https://react-app.walletconnect.com/assets/eip155-1.png"}
]
function updateSessionsModelAndAddNewIfNotNull(newSession) {
var sessions = JSON.parse(settings.persistedSessions)
if (!!newSession) {
sessions.push(newSession)
settings.persistedSessions = JSON.stringify(sessions)
}
sessionsModel.clear()
d.persistedDapps = []
sessions.forEach(function(session) {
sessionsModel.append(session)
let firstIconUrl = session.peer.metadata.icons.length > 0 ? session.peer.metadata.icons[0] : ""
let persistedDapp = {
"name": session.peer.metadata.name,
"url": session.peer.metadata.url,
"iconUrl": firstIconUrl,
"topic": session.topic
}
var found = false
for (var i = 0; i < d.persistedDapps.length; i++) {
if (d.persistedDapps[i].url == persistedDapp.url) {
found = true
break
}
}
if (!found) {
d.persistedDapps.push(persistedDapp)
}
})
}
property var persistedDapps: []
ListModel { ListModel {
id: customAccountsModel id: customAccountsModel
} }
@ -387,6 +454,11 @@ Item {
property bool enableSDK: true property bool enableSDK: true
property bool pending : false property bool pending : false
property string customAccounts: "" property string customAccounts: ""
property string persistedSessions: "[]"
}
Component.onCompleted: {
d.updateSessionsModelAndAddNewIfNotNull(null)
} }
} }

View File

@ -19,6 +19,7 @@ ComboBox {
signal dappsListReady signal dappsListReady
signal pairDapp signal pairDapp
signal disconnectDapp(string dappUrl)
implicitHeight: 38 implicitHeight: 38
implicitWidth: 38 implicitWidth: 38
@ -54,11 +55,15 @@ ComboBox {
delegate: DAppDelegate { delegate: DAppDelegate {
width: ListView.view.width width: ListView.view.width
onDisconnectDapp: (dappUrl) => {
root.disconnectDapp(dappUrl)
}
} }
popup: DAppsListPopup { popup: DAppsListPopup {
objectName: "dappsListPopup" objectName: "dappsListPopup"
x: root.width - width x: root.width - width
y: root.height + 4 y: root.height + 4

View File

@ -27,6 +27,10 @@ DappsComboBox {
pairWCLoader.active = true pairWCLoader.active = true
} }
onDisconnectDapp: (dappUrl) => {
root.wcService.disconnectDapp(dappUrl)
}
Loader { Loader {
id: pairWCLoader id: pairWCLoader
@ -94,7 +98,7 @@ DappsComboBox {
onDisconnect: { onDisconnect: {
connectDappLoader.active = false connectDappLoader.active = false
root.wcService.disconnectDapp(sessionTopic) root.wcService.disconnectSession(sessionTopic)
} }
} }
} }

View File

@ -45,11 +45,6 @@ QObject {
root.store.dappsListReceived.disconnect(dappsListReceivedFn); root.store.dappsListReceived.disconnect(dappsListReceivedFn);
} }
// TODO DEV: check if still holds true
// Reasons to postpone `getDapps` call:
// - the first recent made session will always have `active` prop set to false
// - expiration date won't be the correct one, but one used in session proposal
// - the list of dapps will display successfully made pairing as inactive
getActiveSessionsFn = () => { getActiveSessionsFn = () => {
sdk.getActiveSessions((sessions) => { sdk.getActiveSessions((sessions) => {
root.store.dappsListReceived.disconnect(dappsListReceivedFn); root.store.dappsListReceived.disconnect(dappsListReceivedFn);

View File

@ -99,7 +99,7 @@ WalletConnectSDKBase {
d.engine.runJavaScript(`wc.init("${root.projectId}").catch((error) => {wc.statusObject.sdkInitialized("SDK init error: "+error);})`, function(result) { d.engine.runJavaScript(`wc.init("${root.projectId}").catch((error) => {wc.statusObject.sdkInitialized("SDK init error: "+error);})`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.init; response: ${JSON.stringify(result, null, 2)}`) console.debug(`WC WalletConnectSDK.wcCall.init; response: ${JSON.stringify(result)}`)
if (result && !!result.error) if (result && !!result.error)
{ {
@ -113,7 +113,7 @@ WalletConnectSDKBase {
if (d.engine) { if (d.engine) {
d.engine.runJavaScript(`wc.getPairings()`, function(result) { d.engine.runJavaScript(`wc.getPairings()`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.getPairings; result: ${JSON.stringify(result, null, 2)}`) console.debug(`WC WalletConnectSDK.wcCall.getPairings; result: ${JSON.stringify(result)}`)
if (callback && result) { if (callback && result) {
callback(result) callback(result)
@ -127,12 +127,6 @@ WalletConnectSDKBase {
if (d.engine) { if (d.engine) {
d.engine.runJavaScript(`wc.getActiveSessions()`, function(result) { d.engine.runJavaScript(`wc.getActiveSessions()`, function(result) {
var allSessions = ""
for (var key of Object.keys(result)) {
allSessions += `\nsessionTopic: ${key} relatedPairingTopic: ${result[key].pairingTopic}`;
}
console.debug(`WC WalletConnectSDK.wcCall.getActiveSessions; result: ${allSessions}`)
if (callback && result) { if (callback && result) {
callback(result) callback(result)
} }
@ -294,7 +288,7 @@ WalletConnectSDKBase {
console.debug(`WC WalletConnectSDK.wcCall.auth; cacaoPayload: ${JSON.stringify(cacaoPayload)}, address: ${address}`) console.debug(`WC WalletConnectSDK.wcCall.auth; cacaoPayload: ${JSON.stringify(cacaoPayload)}, address: ${address}`)
d.engine.runJavaScript(`wc.formatAuthMessage(${JSON.stringify(cacaoPayload)}, "${address}")`, function(result) { d.engine.runJavaScript(`wc.formatAuthMessage(${JSON.stringify(cacaoPayload)}, "${address}")`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.formatAuthMessage; response: ${JSON.stringify(result, null, 2)}`) console.debug(`WC WalletConnectSDK.wcCall.formatAuthMessage; response: ${JSON.stringify(result)}`)
root.authMessageFormated(result, address) root.authMessageFormated(result, address)
}) })
@ -373,12 +367,12 @@ WalletConnectSDKBase {
} }
function onBuildApprovedNamespacesResponse(approvedNamespaces, error) { function onBuildApprovedNamespacesResponse(approvedNamespaces, error) {
console.debug(`WC WalletConnectSDK.onBuildApprovedNamespacesResponse; approvedNamespaces: ${approvedNamespaces ? JSON.stringify(approvedNamespaces, null, 2) : "-"}, error: ${error}`) console.debug(`WC WalletConnectSDK.onBuildApprovedNamespacesResponse; approvedNamespaces: ${approvedNamespaces ? JSON.stringify(approvedNamespaces) : "-"}, error: ${error}`)
root.buildApprovedNamespacesResult(approvedNamespaces, error) root.buildApprovedNamespacesResult(approvedNamespaces, error)
} }
function onApproveSessionResponse(session, error) { function onApproveSessionResponse(session, error) {
console.debug(`WC WalletConnectSDK.onApproveSessionResponse; sessionTopic: ${JSON.stringify(session, null, 2)}, error: ${error}`) console.debug(`WC WalletConnectSDK.onApproveSessionResponse; sessionTopic: ${JSON.stringify(session)}, error: ${error}`)
root.approveSessionResult(session, error) root.approveSessionResult(session, error)
} }
@ -400,51 +394,51 @@ WalletConnectSDKBase {
} }
function onSessionProposal(details) { function onSessionProposal(details) {
console.debug(`WC WalletConnectSDK.onSessionProposal; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC WalletConnectSDK.onSessionProposal; details: ${JSON.stringify(details)}`)
root.sessionProposal(details) root.sessionProposal(details)
} }
function onSessionUpdate(details) { function onSessionUpdate(details) {
console.debug(`WC TODO WalletConnectSDK.onSessionUpdate; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC TODO WalletConnectSDK.onSessionUpdate; details: ${JSON.stringify(details)}`)
} }
function onSessionExtend(details) { function onSessionExtend(details) {
console.debug(`WC TODO WalletConnectSDK.onSessionExtend; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC TODO WalletConnectSDK.onSessionExtend; details: ${JSON.stringify(details)}`)
} }
function onSessionPing(details) { function onSessionPing(details) {
console.debug(`WC TODO WalletConnectSDK.onSessionPing; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC TODO WalletConnectSDK.onSessionPing; details: ${JSON.stringify(details)}`)
} }
function onSessionDelete(details) { function onSessionDelete(details) {
console.debug(`WC WalletConnectSDK.onSessionDelete; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC WalletConnectSDK.onSessionDelete; details: ${JSON.stringify(details)}`)
root.sessionDelete(details.topic, "") root.sessionDelete(details.topic, "")
} }
function onSessionExpire(details) { function onSessionExpire(details) {
console.debug(`WC TODO WalletConnectSDK.onSessionExpire; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC TODO WalletConnectSDK.onSessionExpire; details: ${JSON.stringify(details)}`)
} }
function onSessionRequest(details) { function onSessionRequest(details) {
console.debug(`WC WalletConnectSDK.onSessionRequest; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC WalletConnectSDK.onSessionRequest; details: ${JSON.stringify(details)}`)
root.sessionRequestEvent(details) root.sessionRequestEvent(details)
} }
function onSessionRequestSent(details) { function onSessionRequestSent(details) {
console.debug(`WC TODO WalletConnectSDK.onSessionRequestSent; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC TODO WalletConnectSDK.onSessionRequestSent; details: ${JSON.stringify(details)}`)
} }
function onSessionEvent(details) { function onSessionEvent(details) {
console.debug(`WC TODO WalletConnectSDK.onSessionEvent; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC TODO WalletConnectSDK.onSessionEvent; details: ${JSON.stringify(details)}`)
} }
function onProposalExpire(details) { function onProposalExpire(details) {
console.debug(`WC WalletConnectSDK.onProposalExpire; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC WalletConnectSDK.onProposalExpire; details: ${JSON.stringify(details)}`)
root.sessionProposalExpired() root.sessionProposalExpired()
} }
function onAuthRequest(details) { function onAuthRequest(details) {
console.debug(`WC WalletConnectSDK.onAuthRequest; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC WalletConnectSDK.onAuthRequest; details: ${JSON.stringify(details)}`)
root.authRequest(details) root.authRequest(details)
} }

View File

@ -64,10 +64,22 @@ QObject {
wcSDK.rejectSession(id) wcSDK.rejectSession(id)
} }
function disconnectDapp(sessionTopic) { function disconnectSession(sessionTopic) {
wcSDK.disconnectSession(sessionTopic) wcSDK.disconnectSession(sessionTopic)
} }
function disconnectDapp(url) {
wcSDK.getActiveSessions((sessions) => {
for (let key in sessions) {
let dapp = sessions[key].peer.metadata
let topic = sessions[key].topic
if (dapp.url == url) {
wcSDK.disconnectSession(topic)
}
}
});
}
signal connectDApp(var dappChains, var sessionProposal, var approvedNamespaces) signal connectDApp(var dappChains, var sessionProposal, var approvedNamespaces)
signal approveSessionResult(var session, var error) signal approveSessionResult(var session, var error)
signal sessionRequest(SessionRequestResolved request) signal sessionRequest(SessionRequestResolved request)
@ -133,6 +145,9 @@ QObject {
} }
function onSessionDelete(topic, err) { function onSessionDelete(topic, err) {
store.deactivateWalletConnectSession(topic)
dappsProvider.updateDapps()
const app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-" const app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
const app_domain = StringUtils.extractDomainFromLink(app_url) const app_domain = StringUtils.extractDomainFromLink(app_url)
if(err) { if(err) {

View File

@ -1,106 +1,105 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.15 import QtGraphicalEffects 1.15
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
MouseArea { MouseArea {
id: root id: root
implicitHeight: 50 implicitHeight: 50
hoverEnabled: true hoverEnabled: true
required property string name required property string name
required property string url required property string url
required property string iconUrl required property string iconUrl
signal disconnectDapp() signal disconnectDapp(string dappUrl)
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 8 anchors.margins: 8
Item { Item {
Layout.preferredWidth: 32 Layout.preferredWidth: 32
Layout.preferredHeight: 32 Layout.preferredHeight: 32
StatusImage { StatusImage {
id: iconImage id: iconImage
anchors.fill: parent anchors.fill: parent
source: root.iconUrl source: root.iconUrl
visible: !fallbackImage.visible visible: !fallbackImage.visible
} }
StatusIcon { StatusIcon {
id: fallbackImage id: fallbackImage
anchors.fill: parent anchors.fill: parent
icon: "dapp" icon: "dapp"
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
visible: iconImage.isLoading || iconImage.isError || !root.iconUrl visible: iconImage.isLoading || iconImage.isError || !root.iconUrl
} }
layer.enabled: true layer.enabled: true
layer.effect: OpacityMask { layer.effect: OpacityMask {
maskSource: Rectangle { maskSource: Rectangle {
width: iconImage.width width: iconImage.width
height: iconImage.height height: iconImage.height
radius: width / 2 radius: width / 2
visible: false visible: false
} }
} }
} }
ColumnLayout { ColumnLayout {
Layout.leftMargin: 12 Layout.leftMargin: 12
Layout.rightMargin: 12 Layout.rightMargin: 12
StatusBaseText { StatusBaseText {
text: root.name text: root.name
Layout.fillWidth: true Layout.fillWidth: true
font.pixelSize: 13 font.pixelSize: 13
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
clip: true clip: true
} }
StatusBaseText { StatusBaseText {
text: root.url text: root.url
Layout.fillWidth: true Layout.fillWidth: true
font.pixelSize: 12 font.pixelSize: 12
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
elide: Text.ElideRight elide: Text.ElideRight
clip: true clip: true
} }
} }
StatusFlatButton { StatusFlatButton {
size: StatusBaseButton.Size.Large size: StatusBaseButton.Size.Large
asset.color: root.containsMouse ? Theme.palette.directColor1 asset.color: root.containsMouse ? Theme.palette.directColor1
: Theme.palette.baseColor1 : Theme.palette.baseColor1
icon.name: "disconnect" icon.name: "disconnect"
tooltip.text: qsTr("Disconnect dApp") tooltip.text: qsTr("Disconnect dApp")
onClicked: { onClicked: {
console.debug(`TODO #14755 - Disconnect ${root.name}`) root.disconnectDapp(root.url)
// root.disconnectDapp() }
} }
} }
} }
}

View File

@ -16,6 +16,10 @@ QObject {
return controller.addWalletConnectSession(sessionJson) return controller.addWalletConnectSession(sessionJson)
} }
function deactivateWalletConnectSession(topic) {
return controller.deactivateWalletConnectSession(topic)
}
function authenticateUser(topic, id, address) { function authenticateUser(topic, id, address) {
let ok = controller.authenticateUser(topic, id, address) let ok = controller.authenticateUser(topic, id, address)
if(!ok) { if(!ok) {