2024-05-06 20:22:43 +00:00
|
|
|
import QtQuick 2.15
|
|
|
|
|
2024-06-07 12:27:56 +00:00
|
|
|
import StatusQ 0.1
|
2024-05-14 18:22:50 +00:00
|
|
|
import StatusQ.Core.Theme 0.1
|
2024-05-21 10:42:50 +00:00
|
|
|
import StatusQ.Core.Utils 0.1
|
2024-05-14 18:22:50 +00:00
|
|
|
|
2024-06-07 12:27:56 +00:00
|
|
|
import AppLayouts.Wallet 1.0
|
2024-06-29 20:24:05 +00:00
|
|
|
import AppLayouts.Wallet.stores 1.0 as WalletStores
|
2024-05-06 20:22:43 +00:00
|
|
|
import AppLayouts.Wallet.services.dapps 1.0
|
2024-06-12 13:48:44 +00:00
|
|
|
import AppLayouts.Wallet.services.dapps.types 1.0
|
2024-05-06 20:22:43 +00:00
|
|
|
import AppLayouts.Profile.stores 1.0
|
|
|
|
import shared.stores 1.0
|
|
|
|
import shared.popups.walletconnect 1.0
|
|
|
|
|
|
|
|
import SortFilterProxyModel 0.2
|
|
|
|
import utils 1.0
|
|
|
|
|
2024-05-31 09:58:47 +00:00
|
|
|
import "types"
|
|
|
|
|
2024-05-21 10:42:50 +00:00
|
|
|
QObject {
|
2024-05-06 20:22:43 +00:00
|
|
|
id: root
|
|
|
|
|
2024-05-31 09:34:59 +00:00
|
|
|
required property WalletConnectSDKBase wcSDK
|
2024-05-20 18:42:31 +00:00
|
|
|
required property DAppsStore store
|
2024-06-29 20:24:05 +00:00
|
|
|
required property WalletStores.RootStore walletRootStore
|
|
|
|
|
|
|
|
readonly property string selectedAccountAddress: walletRootStore.selectedAddress
|
2024-05-06 20:22:43 +00:00
|
|
|
|
2024-05-31 09:34:59 +00:00
|
|
|
readonly property alias dappsModel: dappsProvider.dappsModel
|
2024-05-31 09:58:47 +00:00
|
|
|
readonly property alias requestHandler: requestHandler
|
2024-05-21 10:42:50 +00:00
|
|
|
|
2024-05-06 20:22:43 +00:00
|
|
|
readonly property var validAccounts: SortFilterProxyModel {
|
2024-06-29 20:24:05 +00:00
|
|
|
sourceModel: root.walletRootStore.nonWatchAccounts
|
2024-06-07 12:27:56 +00:00
|
|
|
proxyRoles: [
|
|
|
|
FastExpressionRole {
|
|
|
|
name: "colorizedChainPrefixes"
|
|
|
|
function getChainShortNames(chainIds) {
|
2024-06-29 20:24:05 +00:00
|
|
|
const chainShortNames = root.walletRootStore.getNetworkShortNames(chainIds)
|
2024-06-07 12:27:56 +00:00
|
|
|
return WalletUtils.colorizedChainPrefix(chainShortNames)
|
|
|
|
}
|
|
|
|
expression: getChainShortNames(model.preferredSharingChainIds)
|
|
|
|
expectedRoles: ["preferredSharingChainIds"]
|
|
|
|
}
|
|
|
|
]
|
2024-05-06 20:22:43 +00:00
|
|
|
}
|
2024-06-29 20:24:05 +00:00
|
|
|
readonly property var flatNetworks: root.walletRootStore.filteredFlatModel
|
2024-05-06 20:22:43 +00:00
|
|
|
|
2024-07-05 09:32:31 +00:00
|
|
|
function validatePairingUri(uri) {
|
|
|
|
if(Helpers.containsOnlyEmoji(uri)) {
|
|
|
|
root.pairingUriValidated(Pairing.uriErrors.tooCool)
|
|
|
|
return
|
|
|
|
} else if(!Helpers.validURI(uri)) {
|
|
|
|
root.pairingUriValidated(Pairing.uriErrors.invalidUri)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let info = Helpers.extractInfoFromPairUri(uri)
|
|
|
|
wcSDK.getActiveSessions((sessions) => {
|
|
|
|
// Check if the URI is already paired
|
|
|
|
var validationState = Pairing.uriErrors.ok
|
|
|
|
for (let key in sessions) {
|
|
|
|
if (sessions[key].pairingTopic == info.topic) {
|
|
|
|
validationState = Pairing.uriErrors.alreadyUsed
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if expired
|
|
|
|
if (validationState == Pairing.uriErrors.ok) {
|
|
|
|
const now = (new Date().getTime())/1000
|
|
|
|
if (info.expiry < now) {
|
|
|
|
validationState = Pairing.uriErrors.expired
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
root.pairingUriValidated(validationState)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-05-06 20:22:43 +00:00
|
|
|
function pair(uri) {
|
2024-05-21 10:42:50 +00:00
|
|
|
d.acceptedSessionProposal = null
|
2024-05-06 20:22:43 +00:00
|
|
|
wcSDK.pair(uri)
|
|
|
|
}
|
|
|
|
|
|
|
|
function approvePairSession(sessionProposal, approvedChainIds, approvedAccount) {
|
2024-05-21 10:42:50 +00:00
|
|
|
d.acceptedSessionProposal = sessionProposal
|
2024-05-31 09:58:47 +00:00
|
|
|
let approvedNamespaces = JSON.parse(
|
|
|
|
Helpers.buildSupportedNamespaces(approvedChainIds,
|
|
|
|
[approvedAccount.address],
|
2024-06-12 13:48:44 +00:00
|
|
|
SessionRequest.getSupportedMethods())
|
2024-05-31 09:58:47 +00:00
|
|
|
)
|
2024-05-06 20:22:43 +00:00
|
|
|
wcSDK.buildApprovedNamespaces(sessionProposal.params, approvedNamespaces)
|
|
|
|
}
|
|
|
|
|
|
|
|
function rejectPairSession(id) {
|
|
|
|
wcSDK.rejectSession(id)
|
|
|
|
}
|
|
|
|
|
2024-06-24 21:26:53 +00:00
|
|
|
function disconnectSession(sessionTopic) {
|
2024-05-06 20:22:43 +00:00
|
|
|
wcSDK.disconnectSession(sessionTopic)
|
|
|
|
}
|
|
|
|
|
2024-06-24 21:26:53 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-05-06 20:22:43 +00:00
|
|
|
signal connectDApp(var dappChains, var sessionProposal, var approvedNamespaces)
|
|
|
|
signal approveSessionResult(var session, var error)
|
2024-05-31 09:58:47 +00:00
|
|
|
signal sessionRequest(SessionRequestResolved request)
|
2024-05-31 09:34:59 +00:00
|
|
|
signal displayToastMessage(string message, bool error)
|
2024-07-05 09:32:31 +00:00
|
|
|
signal pairingUriValidated(int validationState)
|
2024-05-06 20:22:43 +00:00
|
|
|
|
|
|
|
readonly property Connections sdkConnections: Connections {
|
|
|
|
target: wcSDK
|
|
|
|
|
|
|
|
function onSessionProposal(sessionProposal) {
|
2024-05-21 10:42:50 +00:00
|
|
|
d.currentSessionProposal = sessionProposal
|
2024-05-06 20:22:43 +00:00
|
|
|
|
2024-05-31 09:58:47 +00:00
|
|
|
let supportedNamespacesStr = Helpers.buildSupportedNamespacesFromModels(
|
2024-06-12 13:48:44 +00:00
|
|
|
root.flatNetworks, root.validAccounts, SessionRequest.getSupportedMethods())
|
2024-05-06 20:22:43 +00:00
|
|
|
wcSDK.buildApprovedNamespaces(sessionProposal.params, JSON.parse(supportedNamespacesStr))
|
|
|
|
}
|
|
|
|
|
|
|
|
function onBuildApprovedNamespacesResult(approvedNamespaces, error) {
|
|
|
|
if(error) {
|
2024-07-08 10:40:43 +00:00
|
|
|
// Check that it contains Non conforming namespaces"
|
|
|
|
if (error.includes("Non conforming namespaces")) {
|
|
|
|
root.pairingUriValidated(Pairing.uriErrors.unsupportedNetwork)
|
|
|
|
} else {
|
|
|
|
root.pairingUriValidated(Pairing.uriErrors.unknownError)
|
|
|
|
}
|
2024-05-06 20:22:43 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-05-21 10:42:50 +00:00
|
|
|
if (d.acceptedSessionProposal) {
|
|
|
|
wcSDK.approveSession(d.acceptedSessionProposal, approvedNamespaces)
|
2024-05-06 20:22:43 +00:00
|
|
|
} else {
|
|
|
|
let res = Helpers.extractChainsAndAccountsFromApprovedNamespaces(approvedNamespaces)
|
|
|
|
|
2024-05-21 10:42:50 +00:00
|
|
|
root.connectDApp(res.chains, d.currentSessionProposal, approvedNamespaces)
|
2024-05-06 20:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onApproveSessionResult(session, err) {
|
2024-05-20 18:42:31 +00:00
|
|
|
if (err) {
|
2024-05-21 10:42:50 +00:00
|
|
|
// TODO #14676: handle the error
|
|
|
|
console.error("Failed to approve session", err)
|
2024-05-20 18:42:31 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-05-14 18:22:50 +00:00
|
|
|
// TODO #14754: implement custom dApp notification
|
2024-06-29 20:24:05 +00:00
|
|
|
const app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
|
|
|
const app_domain = StringUtils.extractDomainFromLink(app_url)
|
|
|
|
root.displayToastMessage(qsTr("Connected to %1 via WalletConnect").arg(app_domain), false)
|
2024-05-20 18:42:31 +00:00
|
|
|
|
|
|
|
// Persist session
|
2024-06-07 16:54:19 +00:00
|
|
|
if(!store.addWalletConnectSession(JSON.stringify(session))) {
|
|
|
|
console.error("Failed to persist session")
|
|
|
|
}
|
2024-05-21 10:42:50 +00:00
|
|
|
|
2024-05-31 09:34:59 +00:00
|
|
|
// Notify client
|
|
|
|
root.approveSessionResult(session, err)
|
|
|
|
|
|
|
|
dappsProvider.updateDapps()
|
2024-05-06 20:22:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function onRejectSessionResult(err) {
|
2024-06-29 20:24:05 +00:00
|
|
|
const app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
|
|
|
const app_domain = StringUtils.extractDomainFromLink(app_url)
|
2024-05-06 20:22:43 +00:00
|
|
|
if(err) {
|
2024-06-29 20:24:05 +00:00
|
|
|
root.displayToastMessage(qsTr("Failed to reject connection request for %1").arg(app_domain), true)
|
2024-05-06 20:22:43 +00:00
|
|
|
} else {
|
2024-06-29 20:24:05 +00:00
|
|
|
root.displayToastMessage(qsTr("Connection request for %1 was rejected").arg(app_domain), false)
|
2024-05-06 20:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-14 18:22:50 +00:00
|
|
|
function onSessionDelete(topic, err) {
|
2024-06-24 21:26:53 +00:00
|
|
|
store.deactivateWalletConnectSession(topic)
|
|
|
|
dappsProvider.updateDapps()
|
|
|
|
|
2024-06-29 20:24:05 +00:00
|
|
|
const app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
|
|
|
const app_domain = StringUtils.extractDomainFromLink(app_url)
|
2024-05-14 18:22:50 +00:00
|
|
|
if(err) {
|
2024-06-29 20:24:05 +00:00
|
|
|
root.displayToastMessage(qsTr("Failed to disconnect from %1").arg(app_domain), true)
|
2024-05-06 20:22:43 +00:00
|
|
|
} else {
|
2024-06-29 20:24:05 +00:00
|
|
|
root.displayToastMessage(qsTr("Disconnected from %1").arg(app_domain), false)
|
2024-05-06 20:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-31 09:34:59 +00:00
|
|
|
QObject {
|
2024-05-21 10:42:50 +00:00
|
|
|
id: d
|
|
|
|
|
2024-05-06 20:22:43 +00:00
|
|
|
property var currentSessionProposal: null
|
|
|
|
property var acceptedSessionProposal: null
|
2024-05-16 17:57:37 +00:00
|
|
|
|
2024-05-21 10:42:50 +00:00
|
|
|
// TODO #14676: use it to check if already paired
|
|
|
|
function getPairingTopicFromPairingUrl(url)
|
|
|
|
{
|
|
|
|
if (!url.startsWith("wc:"))
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const atIndex = url.indexOf("@");
|
|
|
|
if (atIndex < 0)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return url.slice(3, atIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component.onCompleted: {
|
2024-05-31 09:34:59 +00:00
|
|
|
dappsProvider.updateDapps()
|
|
|
|
}
|
|
|
|
|
2024-05-31 09:58:47 +00:00
|
|
|
DAppsRequestHandler {
|
|
|
|
id: requestHandler
|
|
|
|
|
|
|
|
sdk: root.wcSDK
|
|
|
|
store: root.store
|
2024-06-29 20:24:05 +00:00
|
|
|
accountsModel: root.validAccounts
|
|
|
|
networksModel: root.flatNetworks
|
2024-05-31 09:58:47 +00:00
|
|
|
|
|
|
|
onSessionRequest: (request) => {
|
|
|
|
root.sessionRequest(request)
|
|
|
|
}
|
2024-06-04 20:45:03 +00:00
|
|
|
onDisplayToastMessage: (message, error) => {
|
|
|
|
root.displayToastMessage(message, error)
|
|
|
|
}
|
2024-05-31 09:58:47 +00:00
|
|
|
}
|
|
|
|
|
2024-05-31 09:34:59 +00:00
|
|
|
DAppsListProvider {
|
|
|
|
id: dappsProvider
|
|
|
|
|
|
|
|
sdk: root.wcSDK
|
|
|
|
store: root.store
|
2024-05-06 20:22:43 +00:00
|
|
|
}
|
|
|
|
}
|