status-desktop/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml
Alex Jbanca 8b4cbc59a8 refactor: Refactoring of AccountSelector dropdown
The new account selector expects a generic account model. It will display all the account data if provided, including preferred chains, balance or asset balance. Otherwise it will display only the available data.
The account selector can receive an initial selection based on account address and will provide the current selected address and the current selected model item.

- Unify the account selector between communities and wallet
- Update the account selector to work with addresses instead of model indexes
- Adapt all components using the account selector or the account selection
- Move/reuse qml components involved in the account selector UI
- Remove nim logic used to handle index based account selection.
- Adding storybook page
2024-06-20 11:24:35 +03:00

193 lines
6.2 KiB
QML

import QtQuick 2.15
import StatusQ 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import AppLayouts.Wallet 1.0
import AppLayouts.Wallet.services.dapps 1.0
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
import "types"
QObject {
id: root
required property WalletConnectSDKBase wcSDK
required property DAppsStore store
required property WalletStore walletStore
readonly property alias dappsModel: dappsProvider.dappsModel
readonly property alias requestHandler: requestHandler
readonly property var validAccounts: SortFilterProxyModel {
sourceModel: root.walletStore ? root.walletStore.accounts : null
filters: ValueFilter {
roleName: "walletType"
value: Constants.watchWalletType
inverted: true
}
proxyRoles: [
FastExpressionRole {
name: "colorizedChainPrefixes"
function getChainShortNames(chainIds) {
const chainShortNames = root.walletStore.getNetworkShortNames(chainIds)
return WalletUtils.colorizedChainPrefix(chainShortNames)
}
expression: getChainShortNames(model.preferredSharingChainIds)
expectedRoles: ["preferredSharingChainIds"]
}
]
}
readonly property var flatNetworks: root.walletStore ? root.walletStore.flatNetworks : null
function pair(uri) {
d.acceptedSessionProposal = null
wcSDK.pair(uri)
}
function approvePairSession(sessionProposal, approvedChainIds, approvedAccount) {
d.acceptedSessionProposal = sessionProposal
let approvedNamespaces = JSON.parse(
Helpers.buildSupportedNamespaces(approvedChainIds,
[approvedAccount.address],
requestHandler.getSupportedMethods())
)
wcSDK.buildApprovedNamespaces(sessionProposal.params, approvedNamespaces)
}
function rejectPairSession(id) {
wcSDK.rejectSession(id)
}
function disconnectDapp(sessionTopic) {
wcSDK.disconnectSession(sessionTopic)
}
signal connectDApp(var dappChains, var sessionProposal, var approvedNamespaces)
signal approveSessionResult(var session, var error)
signal sessionRequest(SessionRequestResolved request)
signal displayToastMessage(string message, bool error)
readonly property Connections sdkConnections: Connections {
target: wcSDK
function onSessionProposal(sessionProposal) {
d.currentSessionProposal = sessionProposal
let supportedNamespacesStr = Helpers.buildSupportedNamespacesFromModels(
root.flatNetworks, root.validAccounts, requestHandler.getSupportedMethods())
wcSDK.buildApprovedNamespaces(sessionProposal.params, JSON.parse(supportedNamespacesStr))
}
function onBuildApprovedNamespacesResult(approvedNamespaces, error) {
if(error) {
// TODO: error reporting
return
}
if (d.acceptedSessionProposal) {
wcSDK.approveSession(d.acceptedSessionProposal, approvedNamespaces)
} else {
let res = Helpers.extractChainsAndAccountsFromApprovedNamespaces(approvedNamespaces)
root.connectDApp(res.chains, d.currentSessionProposal, approvedNamespaces)
}
}
function onApproveSessionResult(session, err) {
if (err) {
// TODO #14676: handle the error
console.error("Failed to approve session", err)
return
}
// TODO #14754: implement custom dApp notification
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
root.displayToastMessage(qsTr("Connected to %1 via WalletConnect").arg(app_url), false)
// Persist session
if(!store.addWalletConnectSession(JSON.stringify(session))) {
console.error("Failed to persist session")
}
// Notify client
root.approveSessionResult(session, err)
dappsProvider.updateDapps()
}
function onRejectSessionResult(err) {
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
if(err) {
root.displayToastMessage(qsTr("Failed to reject connection request for %1").arg(app_url), true)
} else {
root.displayToastMessage(qsTr("Connection request for %1 was rejected").arg(app_url), false)
}
}
function onSessionDelete(topic, err) {
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
if(err) {
root.displayToastMessage(qsTr("Failed to disconnect from %1").arg(app_url), true)
} else {
root.displayToastMessage(qsTr("Disconnected from %1").arg(app_url), false)
}
}
}
QObject {
id: d
property var currentSessionProposal: null
property var acceptedSessionProposal: null
// 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: {
dappsProvider.updateDapps()
}
DAppsRequestHandler {
id: requestHandler
sdk: root.wcSDK
store: root.store
walletStore: root.walletStore
onSessionRequest: (request) => {
root.sessionRequest(request)
}
onDisplayToastMessage: (message, error) => {
root.displayToastMessage(message, error)
}
}
DAppsListProvider {
id: dappsProvider
sdk: root.wcSDK
store: root.store
}
}