chore(walletconnect): improvements identifying pairings and sessions

This commit is contained in:
Sale Djenic 2023-12-08 19:18:58 +01:00 committed by saledjenic
parent f1c090a765
commit d587552c40
7 changed files with 571 additions and 298 deletions

View File

@ -80,17 +80,23 @@ QtObject:
error "Unknown identifier" error "Unknown identifier"
# supportedNamespaces is a Namespace as defined in status-go: services/wallet/walletconnect/walletconnect.go # supportedNamespaces is a Namespace as defined in status-go: services/wallet/walletconnect/walletconnect.go
proc proposeUserPair*(self: Controller, sessionProposalJson: string, supportedNamespacesJson: string) {.signal.} proc respondSessionProposal*(self: Controller, sessionProposalJson: string, supportedNamespacesJson: string, error: string) {.signal.}
proc pairSessionProposal(self: Controller, sessionProposalJson: string) {.slot.} = proc sessionProposal(self: Controller, sessionProposalJson: string) {.slot.} =
var
supportedNamespacesJson: string
error: string
try:
var res: JsonNode var res: JsonNode
let err = backend_wallet_connect.pair(res, sessionProposalJson) let err = backend_wallet_connect.pair(res, sessionProposalJson)
if err.len > 0: if err.len > 0:
error "Failed to pair session" raise newException(CatchableError, err)
return
let sessionProposalJson = if res.hasKey("sessionProposal"): $res["sessionProposal"] else: "" supportedNamespacesJson = if res.hasKey("supportedNamespaces"): $res["supportedNamespaces"] else: ""
let supportedNamespacesJson = if res.hasKey("supportedNamespaces"): $res["supportedNamespaces"] else: "" except Exception as e:
self.proposeUserPair(sessionProposalJson, supportedNamespacesJson) error = e.msg
error "pairing", msg=error
self.respondSessionProposal(sessionProposalJson, supportedNamespacesJson, error)
proc recordSuccessfulPairing(self: Controller, sessionProposalJson: string) {.slot.} = proc recordSuccessfulPairing(self: Controller, sessionProposalJson: string) {.slot.} =
if backend_wallet_connect.recordSuccessfulPairing(sessionProposalJson): if backend_wallet_connect.recordSuccessfulPairing(sessionProposalJson):

View File

@ -11,6 +11,8 @@ ListView {
signal disconnect(string topic) signal disconnect(string topic)
spacing: 32
delegate: Item { delegate: Item {
implicitWidth: delegateLayout.implicitWidth implicitWidth: delegateLayout.implicitWidth
implicitHeight: delegateLayout.implicitHeight implicitHeight: delegateLayout.implicitHeight
@ -19,10 +21,16 @@ ListView {
id: delegateLayout id: delegateLayout
width: root.width width: root.width
StatusIcon {
icon: model.peerMetadata.icons.length > 0? model.peerMetadata.icons[0] : ""
visible: !!icon
}
StatusBaseText { StatusBaseText {
text: `${SQUtils.Utils.elideText(model.topic, 6, 6)}\n${new Date(model.expiry * 1000).toLocaleString()}` text: `${model.peerMetadata.name}\n${model.peerMetadata.url}\nTopic: ${SQUtils.Utils.elideText(model.topic, 6, 6)}\nExpire: ${new Date(model.expiry * 1000).toLocaleString()}`
color: model.active ? "green" : "orange" color: model.active ? "green" : "orange"
} }
StatusButton { StatusButton {
text: "Disconnect" text: "Disconnect"

View File

@ -0,0 +1,155 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
ListView {
id: root
signal disconnect(string topic)
signal ping(string topic)
spacing: 48
delegate: Item {
implicitWidth: delegateLayout.implicitWidth
implicitHeight: delegateLayout.implicitHeight
ListModel {
id: namespacesListModel
}
Component.onCompleted: {
for (var key of Object.keys(model.namespaces)) {
let namespace = model.namespaces[key]
let obj = {
"eip": "",
"chain": "",
"methods": namespace.methods.join(", "),
"events": namespace.events.join(", ")
}
if (namespace.chains.length > 0) {
let data = namespace.chains[0].split(":")
if (data.length === 2) {
obj["eip"] = data[0]
obj["chain"] = data[1]
}
}
namespacesListModel.append(obj)
}
}
ColumnLayout {
id: delegateLayout
width: root.width
spacing: 8
StatusIcon {
icon: model.peer.metadata.icons.length > 0? model.peer.metadata.icons[0] : ""
visible: !!icon
}
StatusBaseText {
text: `Pairing topic:${SQUtils.Utils.elideText(model.pairingTopic, 6, 6)}\n${model.peer.metadata.name}\n${model.peer.metadata.url}`
}
StatusBaseText {
text: `Session topic:${SQUtils.Utils.elideText(model.topic, 6, 6)}\nExpire:${new Date(model.expiry * 1000).toLocaleString()}`
}
Rectangle {
color: "transparent"
border.color: "grey"
border.width: 1
Layout.fillWidth: true
Layout.preferredHeight: allNamespaces.implicitHeight
ColumnLayout {
id: allNamespaces
Repeater {
model: namespacesListModel
delegate: Rectangle {
id: namespaceDelegateRoot
property bool expanded: false
color: "transparent"
border.color: "grey"
border.width: 1
Layout.fillWidth: true
Layout.preferredHeight: namespace.implicitHeight
ColumnLayout {
id: namespace
spacing: 8
RowLayout {
StatusBaseText {
text: `Review ${model.eip} permissions`
}
StatusIcon {
icon: namespaceDelegateRoot.expanded? "chevron-up" : "chevron-down"
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
namespaceDelegateRoot.expanded = !namespaceDelegateRoot.expanded
}
}
}
}
StatusBaseText {
Layout.fillWidth: true
visible: namespaceDelegateRoot.expanded
text: `Chain ${model.chain}`
}
StatusBaseText {
Layout.fillWidth: true
visible: namespaceDelegateRoot.expanded
text: `Methods: ${model.methods}\nEvents: ${model.events}`
}
}
}
}
}
}
RowLayout {
StatusButton {
text: "Disconnect"
onClicked: {
root.disconnect(model.topic)
}
}
StatusButton {
text: "Ping"
onClicked: {
root.ping(model.topic)
}
}
}
}
}
}

View File

@ -45,10 +45,39 @@ Popup {
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
spacing: 8
StatusBaseText { StatusBaseText {
text: qsTr("Debugging UX until design is ready") text: qsTr("Debugging UX until design is ready")
font.bold: true
} }
StatusTabBar {
id: tabBar
Layout.fillWidth: true
StatusTabButton {
width: implicitWidth
text: qsTr("WalletConnect")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Sessions")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Pairings")
}
}
StackLayout {
Layout.fillWidth: true
currentIndex: tabBar.currentIndex
ColumnLayout {
StatusSwitch { StatusSwitch {
id: testAuthentication id: testAuthentication
checkable: true checkable: true
@ -70,18 +99,18 @@ Popup {
text: testAuthentication.checked? "Authentication" : "Pair" text: testAuthentication.checked? "Authentication" : "Pair"
onClicked: { onClicked: {
if (testAuthentication.checked) {
d.setStatusText("") d.setStatusText("")
d.setDetailsText("") d.setDetailsText("")
d.state = "" d.state = ""
accountsModel.clear() accountsModel.clear()
statusText.text = "Authenticating..." if (testAuthentication.checked) {
d.setStatusText("Authenticating...")
root.sdk.auth(pairLinkInput.text) root.sdk.auth(pairLinkInput.text)
return return
} }
statusText.text = "Pairing..." d.setStatusText("Pairing...")
root.sdk.pair(pairLinkInput.text) root.sdk.pair(pairLinkInput.text)
} }
enabled: pairLinkInput.text.length > 0 && root.sdk.sdkReady enabled: pairLinkInput.text.length > 0 && root.sdk.sdkReady
@ -90,51 +119,26 @@ Popup {
StatusButton { StatusButton {
text: "Accept" text: "Accept"
onClicked: { onClicked: {
root.sdk.approvePairSession(d.observedData, d.supportedNamespaces) root.sdk.approveSession(d.observedData, d.supportedNamespaces)
} }
visible: d.state === d.waitingPairState visible: d.state === d.waitingPairState
} }
StatusButton { StatusButton {
text: "Reject" text: "Reject"
onClicked: { onClicked: {
root.sdk.rejectPairSession(d.observedData.id) root.sdk.rejectSession(d.observedData.id)
} }
visible: d.state === d.waitingPairState visible: d.state === d.waitingPairState
} }
} }
ColumnLayout {
StatusBaseText {
id: statusText
text: "-"
}
StatusBaseText {
text: "Pairings"
visible: root.sdk.pairingsModel.count > 0
}
Pairings {
Layout.fillWidth: true
Layout.minimumWidth: count > 0 ? 400 : 0
Layout.preferredHeight: contentHeight
Layout.maximumHeight: 300
model: root.sdk.pairingsModel
onDisconnect: function (topic) {
root.sdk.disconnectPairing(topic)
}
}
ButtonGroup { ButtonGroup {
id: selAccBtnGroup id: selAccBtnGroup
} }
SelectAccount { SelectAccount {
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumWidth: count > 0 ? 400 : 0
Layout.preferredHeight: contentHeight Layout.preferredHeight: contentHeight
Layout.maximumHeight: 300
model: accountsModel model: accountsModel
@ -145,14 +149,6 @@ Popup {
} }
} }
StatusBaseText {
id: detailsText
text: ""
visible: text.length > 0
color: "#FF00FF"
}
RowLayout { RowLayout {
StatusButton { StatusButton {
text: "Accept" text: "Accept"
@ -189,12 +185,68 @@ Popup {
d.state === d.waitingUserResponseToAuthRequest d.state === d.waitingUserResponseToAuthRequest
} }
} }
ColumnLayout { /* spacer */ }
} }
// Separator ColumnLayout {
ColumnLayout {} Layout.fillWidth: true
Sessions {
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
model: root.sdk.sessionsModel
onDisconnect: function (topic) {
root.sdk.disconnectTopic(topic)
}
onPing: function (topic) {
root.sdk.ping(topic)
}
}
}
ColumnLayout {
Layout.fillWidth: true
Pairings {
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
model: root.sdk.pairingsModel
onDisconnect: function (topic) {
root.sdk.disconnectTopic(topic)
}
}
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 32
}
ColumnLayout {
StatusBaseText {
text: qsTr("Tracking details...")
font.bold: true
}
StatusBaseText {
id: statusText
text: "-"
font.bold: true
}
StatusBaseText {
id: detailsText
text: ""
visible: text.length > 0
color: "#FF00FF"
}
}
} }
ScrollBar.vertical: ScrollBar {} ScrollBar.vertical: ScrollBar {}
@ -216,15 +268,15 @@ Popup {
} }
} }
function onPairSessionProposal(sessionProposal) { function onSessionProposal(sessionProposal) {
d.setDetailsText(sessionProposal) d.setDetailsText(sessionProposal)
d.setStatusText("Pair ID: " + sessionProposal.id + "; Topic: " + sessionProposal.params.pairingTopic) d.setStatusText("Pair ID: " + sessionProposal.id + "; Topic: " + sessionProposal.params.pairingTopic)
root.controller.pairSessionProposal(JSON.stringify(sessionProposal)) root.controller.sessionProposal(JSON.stringify(sessionProposal))
} }
function onPairAcceptedResult(sessionProposal, success, result) { function onApproveSessionResult(sessionProposal, error) {
d.setDetailsText(result) d.setDetailsText("")
if (success) { if (!error) {
d.setStatusText("Pairing OK") d.setStatusText("Pairing OK")
d.state = d.pairedState d.state = d.pairedState
root.controller.recordSuccessfulPairing(JSON.stringify(sessionProposal)) root.controller.recordSuccessfulPairing(JSON.stringify(sessionProposal))
@ -234,10 +286,10 @@ Popup {
} }
} }
function onPairRejectedResult(success, result) { function onRejectSessionResult(error) {
d.setDetailsText(result) d.setDetailsText("")
d.state = d.sdkReadyState d.state = d.sdkReadyState
if (success) { if (!error) {
d.setStatusText("Pairing rejected") d.setStatusText("Pairing rejected")
} else { } else {
d.setStatusText("Rejecting pairing error", "red") d.setStatusText("Rejecting pairing error", "red")
@ -257,12 +309,12 @@ Popup {
} }
} }
function onPairSessionProposalExpired() { function onSessionProposalExpired() {
d.setStatusText(`Timeout waiting for response. Reusing URI?`, "red") d.setStatusText(`Timeout waiting for response. Reusing URI?`, "red")
} }
function onStatusChanged(message) { function onStatusChanged(message) {
statusText.text = message d.setStatusText(message)
} }
function onAuthRequest(request) { function onAuthRequest(request) {
@ -352,6 +404,7 @@ Popup {
} }
statusText.color = textColor statusText.color = textColor
} }
function setDetailsText(message) { function setDetailsText(message) {
if (message === undefined) { if (message === undefined) {
message = "undefined" message = "undefined"
@ -369,7 +422,12 @@ Popup {
Connections { Connections {
target: root.controller target: root.controller
function onProposeUserPair(sessionProposalJson, supportedNamespacesJson) { function onRespondSessionProposal(sessionProposalJson, supportedNamespacesJson, error) {
if (error) {
d.setStatusText(`Error: ${error}`, "red")
d.setDetailsText("")
return
}
d.setStatusText("Waiting user accept") d.setStatusText("Waiting user accept")
d.observedData = JSON.parse(sessionProposalJson) d.observedData = JSON.parse(sessionProposalJson)

View File

@ -8,12 +8,15 @@ import QtWebChannel 1.15
import StatusQ.Core.Utils 0.1 as SQUtils import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import utils 1.0
Item { Item {
id: root id: root
required property string projectId required property string projectId
readonly property alias sdkReady: d.sdkReady readonly property alias sdkReady: d.sdkReady
readonly property alias pairingsModel: d.pairingsModel readonly property alias pairingsModel: d.pairingsModel
readonly property alias sessionsModel: d.sessionsModel
readonly property alias webEngineLoader: loader readonly property alias webEngineLoader: loader
property alias active: loader.active property alias active: loader.active
@ -24,10 +27,10 @@ Item {
signal statusChanged(string message) signal statusChanged(string message)
signal sdkInit(bool success, var result) signal sdkInit(bool success, var result)
signal pairSessionProposal(var sessionProposal) signal sessionProposal(var sessionProposal)
signal pairSessionProposalExpired() signal sessionProposalExpired()
signal pairAcceptedResult(var sessionProposal, bool success, var sessionType) signal approveSessionResult(var sessionProposal, string error)
signal pairRejectedResult(bool success, var result) signal rejectSessionResult(string error)
signal sessionRequestEvent(var sessionRequest) signal sessionRequestEvent(var sessionRequest)
signal sessionRequestUserAnswerResult(bool accept, string error) signal sessionRequestUserAnswerResult(bool accept, string error)
@ -41,16 +44,20 @@ Item {
wcCalls.pair(pairLink) wcCalls.pair(pairLink)
} }
function disconnectPairing(topic) { function disconnectTopic(topic) {
wcCalls.disconnectPairing(topic) wcCalls.disconnectTopic(topic)
} }
function approvePairSession(sessionProposal, supportedNamespaces) { function ping(topic) {
wcCalls.approvePairSession(sessionProposal, supportedNamespaces) wcCalls.ping(topic)
} }
function rejectPairSession(id) { function approveSession(sessionProposal, supportedNamespaces) {
wcCalls.rejectPairSession(id) wcCalls.approveSession(sessionProposal, supportedNamespaces)
}
function rejectSession(id) {
wcCalls.rejectSession(id)
} }
function acceptSessionRequest(topic, id, signature) { function acceptSessionRequest(topic, id, signature) {
@ -82,6 +89,7 @@ Item {
property bool sdkReady: false property bool sdkReady: false
property ListModel pairingsModel: pairings property ListModel pairingsModel: pairings
property ListModel sessionsModel: sessions
property WebEngineView engine: loader.instance property WebEngineView engine: loader.instance
@ -89,6 +97,7 @@ Item {
if (sdkReady) if (sdkReady)
{ {
d.resetPairingsModel() d.resetPairingsModel()
d.resetSessionsModel()
} }
} }
@ -96,18 +105,33 @@ Item {
{ {
pairings.clear(); pairings.clear();
// We have to postpone `getPairings` call, cause otherwise:
// - the last made pairing 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 pairings will display succesfully made pairing as inactive
Backpressure.debounce(this, 250, () => {
wcCalls.getPairings((pairList) => { wcCalls.getPairings((pairList) => {
for (let i = 0; i < pairList.length; i++) { for (let i = 0; i < pairList.length; i++) {
pairings.append({ pairings.append(pairList[i]);
active: pairList[i].active,
topic: pairList[i].topic,
expiry: pairList[i].expiry
});
if (entryCallback) { if (entryCallback) {
entryCallback(pairList[i]) entryCallback(pairList[i])
} }
} }
}) });
})();
}
function resetSessionsModel() {
sessions.clear();
Backpressure.debounce(this, 250, () => {
wcCalls.getActiveSessions((sessionList) => {
for (var topic of Object.keys(sessionList)) {
sessions.append(sessionList[topic]);
}
});
})();
} }
function getPairingTopicFromPairingUrl(url) function getPairingTopicFromPairingUrl(url)
@ -116,11 +140,13 @@ Item {
{ {
return null; return null;
} }
const atIndex = url.indexOf("@"); const atIndex = url.indexOf("@");
if (atIndex < 0) if (atIndex < 0)
{ {
return null; return null;
} }
return url.slice(3, atIndex); return url.slice(3, atIndex);
} }
} }
@ -147,17 +173,19 @@ Item {
d.engine.runJavaScript(`wc.getPairings()`, function(result) { d.engine.runJavaScript(`wc.getPairings()`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.getPairings; response: ${JSON.stringify(result, null, 2)}`) if (callback && result) {
callback(result)
if (result) }
{ })
if (!!result.error) {
console.error("getPairings: ", result.error)
return
} }
callback(result.result) function getActiveSessions(callback) {
return console.debug(`WC WalletConnectSDK.wcCall.getActiveSessions;`)
d.engine.runJavaScript(`wc.getActiveSessions()`, function(result) {
if (callback && result) {
callback(result)
} }
}) })
} }
@ -165,75 +193,46 @@ Item {
function pair(pairLink) { function pair(pairLink) {
console.debug(`WC WalletConnectSDK.wcCall.pair; pairLink: ${pairLink}`) console.debug(`WC WalletConnectSDK.wcCall.pair; pairLink: ${pairLink}`)
wcCalls.getPairings((allPairings) => { d.engine.runJavaScript(`
wc.pair("${pairLink}")
console.debug(`WC WalletConnectSDK.wcCall.pair; response: ${JSON.stringify(allPairings, null, 2)}`) .then((value) => {
wc.statusObject.onPairResponse("")
let pairingTopic = d.getPairingTopicFromPairingUrl(pairLink);
// Find pairing by topic
const pairing = allPairings.find((p) => p.topic === pairingTopic);
if (pairing)
{
if (pairing.active) {
console.warn("pair: already paired")
return
}
}
d.engine.runJavaScript(`wc.pair("${pairLink}")`, function(result) {
if (result && !!result.error)
{
console.error("pair: ", result.error)
}
}) })
} .catch((e) => {
wc.statusObject.onPairResponse(e.message)
})
`
) )
} }
function approvePairSession(sessionProposal, supportedNamespaces) { function approveSession(sessionProposal, supportedNamespaces) {
console.debug(`WC WalletConnectSDK.wcCall.approvePairSession; sessionProposal: ${JSON.stringify(sessionProposal)}, supportedNamespaces: ${JSON.stringify(supportedNamespaces)}`) console.debug(`WC WalletConnectSDK.wcCall.approveSession; sessionProposal: ${JSON.stringify(sessionProposal)}, supportedNamespaces: ${JSON.stringify(supportedNamespaces)}`)
d.engine.runJavaScript(`wc.approvePairSession(${JSON.stringify(sessionProposal)}, ${JSON.stringify(supportedNamespaces)})`, function(result) { d.engine.runJavaScript(`
wc.approveSession(${JSON.stringify(sessionProposal)}, ${JSON.stringify(supportedNamespaces)})
console.debug(`WC WalletConnectSDK.wcCall.approvePairSession; response: ${JSON.stringify(result, null, 2)}`) .then((value) => {
wc.statusObject.onApproveSessionResponse(${JSON.stringify(sessionProposal)}, "")
if (result) {
if (!!result.error)
{
console.error("approvePairSession: ", result.error)
root.pairAcceptedResult(sessionProposal, false, result.error)
return
}
// Update the temporary expiry with the one from the pairing
d.resetPairingsModel((pairing) => {
if (pairing.topic === sessionProposal.params.pairingTopic) {
sessionProposal.params.expiry = pairing.expiry
root.pairAcceptedResult(sessionProposal, true, result.error)
}
}) })
} .catch((e) => {
wc.statusObject.onApproveSessionResponse(${JSON.stringify(sessionProposal)}, e.message)
}) })
`
)
} }
function rejectPairSession(id) { function rejectSession(id) {
console.debug(`WC WalletConnectSDK.wcCall.rejectPairSession; id: ${id}`) console.debug(`WC WalletConnectSDK.wcCall.rejectSession; id: ${id}`)
d.engine.runJavaScript(`wc.rejectPairSession(${id})`, function(result) { d.engine.runJavaScript(`
wc.rejectSession(${id})
console.debug(`WC WalletConnectSDK.wcCall.rejectPairSession; response: ${JSON.stringify(result, null, 2)}`) .then((value) => {
wc.statusObject.onRejectSessionResponse("")
d.resetPairingsModel()
if (result) {
if (!!result.error)
{
console.error("rejectPairSession: ", result.error)
root.pairRejectedResult(false, result.error)
return
}
root.pairRejectedResult(true, result.error)
}
}) })
.catch((e) => {
wc.statusObject.onRejectSessionResponse(e.message)
})
`
)
} }
function acceptSessionRequest(topic, id, signature) { function acceptSessionRequest(topic, id, signature) {
@ -241,7 +240,7 @@ Item {
d.engine.runJavaScript(`wc.respondSessionRequest("${topic}", ${id}, "${signature}")`, function(result) { d.engine.runJavaScript(`wc.respondSessionRequest("${topic}", ${id}, "${signature}")`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.acceptSessionRequest; response: ${JSON.stringify(allPairings, null, 2)}`) console.debug(`WC WalletConnectSDK.wcCall.acceptSessionRequest; response: ${JSON.stringify(result, null, 2)}`)
if (result) { if (result) {
if (!!result.error) if (!!result.error)
@ -252,7 +251,9 @@ Item {
} }
root.sessionRequestUserAnswerResult(true, result.error) root.sessionRequestUserAnswerResult(true, result.error)
} }
d.resetPairingsModel() d.resetPairingsModel()
d.resetSessionsModel()
}) })
} }
@ -263,6 +264,9 @@ Item {
console.debug(`WC WalletConnectSDK.wcCall.rejectSessionRequest; response: ${JSON.stringify(result, null, 2)}`) console.debug(`WC WalletConnectSDK.wcCall.rejectSessionRequest; response: ${JSON.stringify(result, null, 2)}`)
d.resetPairingsModel()
d.resetSessionsModel()
if (result) { if (result) {
if (!!result.error) if (!!result.error)
{ {
@ -272,24 +276,37 @@ Item {
} }
root.sessionRequestUserAnswerResult(false, result.error) root.sessionRequestUserAnswerResult(false, result.error)
} }
d.resetPairingsModel()
}) })
} }
function disconnectPairing(topic) { function disconnectTopic(topic) {
console.debug(`WC WalletConnectSDK.wcCall.disconnectPairing; topic: "${topic}"`) console.debug(`WC WalletConnectSDK.wcCall.disconnectTopic; topic: "${topic}"`)
d.engine.runJavaScript(`wc.disconnect("${topic}")`, function(result) { d.engine.runJavaScript(`
console.debug(`WC WalletConnectSDK.wcCall.disconnect; response: ${JSON.stringify(result, null, 2)}`) wc.disconnect("${topic}")
.then((value) => {
if (result) { wc.statusObject.onDisconnectResponse("")
if (!!result.error) {
console.error("disconnect: ", result.error)
return
}
}
d.resetPairingsModel()
}) })
.catch((e) => {
wc.statusObject.onDisconnectResponse(e.message)
})
`
)
}
function ping(topic) {
console.debug(`WC WalletConnectSDK.wcCall.ping; topic: "${topic}"`)
d.engine.runJavaScript(`
wc.ping("${topic}")
.then((value) => {
wc.statusObject.onPingResponse("")
})
.catch((e) => {
wc.statusObject.onPingResponse(e.message)
})
`
)
} }
function auth(authLink) { function auth(authLink) {
@ -378,68 +395,93 @@ Item {
} }
} }
function sdkInitialized(error) function sdkInitialized(error) {
{ console.debug(`WC WalletConnectSDK.sdkInitialized; error: ${error}`)
d.sdkReady = !error d.sdkReady = !error
root.sdkInit(d.sdkReady, error) root.sdkInit(d.sdkReady, error)
} }
function onSessionProposal(details) function onPairResponse(error) {
{ console.debug(`WC WalletConnectSDK.onPairResponse; error: ${error}`)
console.debug(`WC WalletConnectSDK.onSessionProposal; details: ${JSON.stringify(details, null, 2)}`)
root.pairSessionProposal(details)
} }
function onSessionUpdate(details) function onPingResponse(error) {
{ console.debug(`WC WalletConnectSDK.onPingResponse; error: ${error}`)
}
function onDisconnectResponse(error) {
console.debug(`WC WalletConnectSDK.onDisconnectResponse; error: ${error}`)
d.resetPairingsModel()
d.resetSessionsModel()
}
function onApproveSessionResponse(sessionProposal, error) {
console.debug(`WC WalletConnectSDK.onApproveSessionResponse; sessionProposal: ${JSON.stringify(sessionProposal, null, 2)}, error: ${error}`)
// Update the temporary expiry with the one from the pairing
d.resetPairingsModel((pairing) => {
if (pairing.topic === sessionProposal.params.pairingTopic) {
sessionProposal.params.expiry = pairing.expiry
root.approveSessionResult(sessionProposal, error)
}
})
d.resetSessionsModel()
}
function onRejectSessionResponse(error) {
console.debug(`WC WalletConnectSDK.onRejectSessionResponse; error: ${error}`)
root.rejectSessionResult(error)
d.resetPairingsModel()
d.resetSessionsModel()
}
function onSessionProposal(details) {
console.debug(`WC WalletConnectSDK.onSessionProposal; details: ${JSON.stringify(details, null, 2)}`)
root.sessionProposal(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, null, 2)}`)
} }
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, null, 2)}`)
} }
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, null, 2)}`)
} }
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, null, 2)}`)
root.sessionDelete(details) root.sessionDelete(details)
d.resetPairingsModel()
d.resetSessionsModel()
} }
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, null, 2)}`)
} }
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, null, 2)}`)
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, null, 2)}`)
} }
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, null, 2)}`)
} }
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, null, 2)}`)
root.pairSessionProposalExpired() 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, null, 2)}`)
root.authRequest(details) root.authRequest(details)
} }
@ -449,6 +491,10 @@ Item {
id: pairings id: pairings
} }
ListModel {
id: sessions
}
WebEngineLoader { WebEngineLoader {
id: loader id: loader

File diff suppressed because one or more lines are too long

View File

@ -104,51 +104,51 @@ window.wc = {
}, },
// TODO: there is a corner case when attempting to pair with a link that is already paired or was rejected won't trigger any event back // TODO: there is a corner case when attempting to pair with a link that is already paired or was rejected won't trigger any event back
pair: function (uri) { pair: async function (uri) {
return { await window.wc.web3wallet.pair({ uri });
result: window.wc.web3wallet.pair({ uri }),
error: ""
};
}, },
getPairings: function () { getPairings: function () {
return { return window.wc.web3wallet.core.pairing.getPairings();
result: window.wc.core.pairing.getPairings(),
error: ""
};
}, },
disconnect: function (topic) { getActiveSessions: function () {
return { return window.wc.web3wallet.getActiveSessions();
result: window.wc.core.pairing.disconnect({ topic: topic }),
error: ""
};
}, },
approvePairSession: function (sessionProposal, supportedNamespaces) { disconnect: async function (topic) {
await window.wc.web3wallet.disconnectSession({
topic,
reason: getSdkError('USER_DISCONNECTED')
});
},
ping: async function (topic) {
await window.wc.web3wallet.engine.signClient.ping({ topic });
},
approveSession: async function (sessionProposal, supportedNamespaces) {
const { id, params } = sessionProposal; const { id, params } = sessionProposal;
const { relays } = params
const approvedNamespaces = buildApprovedNamespaces({ const approvedNamespaces = buildApprovedNamespaces({
proposal: params, proposal: params,
supportedNamespaces: supportedNamespaces, supportedNamespaces: supportedNamespaces,
}); });
return { await window.wc.web3wallet.approveSession({
result: window.wc.web3wallet.approveSession({
id, id,
relayProtocol: relays[0].protocol,
namespaces: approvedNamespaces, namespaces: approvedNamespaces,
}), });
error: ""
};
}, },
rejectPairSession: function (id) {
return { rejectSession: async function (id) {
result: window.wc.web3wallet.rejectSession({ await window.wc.web3wallet.rejectSession({
id: id, id,
reason: getSdkError("USER_REJECTED"), // TODO USER_REJECTED_METHODS, USER_REJECTED_CHAINS, USER_REJECTED_EVENTS reason: getSdkError("USER_REJECTED"), // TODO USER_REJECTED_METHODS, USER_REJECTED_CHAINS, USER_REJECTED_EVENTS
}), });
error: ""
};
}, },
auth: function (uri) { auth: function (uri) {