feature(connector)_: Add model join to handle connected dApps (#15954)
* feature(connector)_: Add model join to handle connected dApps * Fix review comments * chore: bump status-go
This commit is contained in:
parent
4ba3cea925
commit
bef66612c5
|
@ -17,6 +17,16 @@ type ConnectorSendTransactionSignal* = ref object of Signal
|
|||
chainId*: int
|
||||
txArgs*: string
|
||||
|
||||
type ConnectorGrantDAppPermissionSignal* = ref object of Signal
|
||||
url*: string
|
||||
name*: string
|
||||
iconUrl*: string
|
||||
|
||||
type ConnectorRevokeDAppPermissionSignal* = ref object of Signal
|
||||
url*: string
|
||||
name*: string
|
||||
iconUrl*: string
|
||||
|
||||
proc fromEvent*(T: type ConnectorSendRequestAccountsSignal, event: JsonNode): ConnectorSendRequestAccountsSignal =
|
||||
result = ConnectorSendRequestAccountsSignal()
|
||||
result.url = event["event"]{"url"}.getStr()
|
||||
|
@ -32,3 +42,15 @@ proc fromEvent*(T: type ConnectorSendTransactionSignal, event: JsonNode): Connec
|
|||
result.requestId = event["event"]{"requestId"}.getStr()
|
||||
result.chainId = event["event"]{"chainId"}.getInt()
|
||||
result.txArgs = event["event"]{"txArgs"}.getStr()
|
||||
|
||||
proc fromEvent*(T: type ConnectorGrantDAppPermissionSignal, event: JsonNode): ConnectorGrantDAppPermissionSignal =
|
||||
result = ConnectorGrantDAppPermissionSignal()
|
||||
result.url = event["event"]{"url"}.getStr()
|
||||
result.name = event["event"]{"name"}.getStr()
|
||||
result.iconUrl = event["event"]{"iconUrl"}.getStr()
|
||||
|
||||
proc fromEvent*(T: type ConnectorRevokeDAppPermissionSignal, event: JsonNode): ConnectorRevokeDAppPermissionSignal =
|
||||
result = ConnectorRevokeDAppPermissionSignal()
|
||||
result.url = event["event"]{"url"}.getStr()
|
||||
result.name = event["event"]{"name"}.getStr()
|
||||
result.iconUrl = event["event"]{"iconUrl"}.getStr()
|
||||
|
|
|
@ -68,6 +68,8 @@ type SignalType* {.pure.} = enum
|
|||
CommunityTokenAction = "communityToken.communityTokenAction"
|
||||
ConnectorSendRequestAccounts = "connector.sendRequestAccounts"
|
||||
ConnectorSendTransaction = "connector.sendTransaction"
|
||||
ConnectorGrantDAppPermission = "connector.dAppPermissionGranted"
|
||||
ConnectorRevokeDAppPermission = "connector.dAppPermissionRevoked"
|
||||
Unknown
|
||||
|
||||
proc event*(self:SignalType):string =
|
||||
|
|
|
@ -137,6 +137,8 @@ QtObject:
|
|||
of SignalType.CommunityTokenAction: CommunityTokenActionSignal.fromEvent(jsonSignal)
|
||||
of SignalType.ConnectorSendRequestAccounts: ConnectorSendRequestAccountsSignal.fromEvent(jsonSignal)
|
||||
of SignalType.ConnectorSendTransaction: ConnectorSendTransactionSignal.fromEvent(jsonSignal)
|
||||
of SignalType.ConnectorGrantDAppPermission: ConnectorGrantDAppPermissionSignal.fromEvent(jsonSignal)
|
||||
of SignalType.ConnectorRevokeDAppPermission: ConnectorRevokeDAppPermissionSignal.fromEvent(jsonSignal)
|
||||
else: Signal()
|
||||
|
||||
result.signalType = signalType
|
||||
|
|
|
@ -11,6 +11,8 @@ import app_service/common/utils
|
|||
|
||||
const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts"
|
||||
const SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION* = "ConnectorSendTransaction"
|
||||
const SIGNAL_CONNECTOR_GRANT_DAPP_PERMISSION* = "ConnectorGrantDAppPermission"
|
||||
const SIGNAL_CONNECTOR_REVOKE_DAPP_PERMISSION* = "ConnectorRevokeDAppPermission"
|
||||
|
||||
logScope:
|
||||
topics = "connector-controller"
|
||||
|
@ -26,6 +28,8 @@ QtObject:
|
|||
|
||||
proc dappRequestsToConnect*(self: Controller, requestId: string, payload: string) {.signal.}
|
||||
proc dappValidatesTransaction*(self: Controller, requestId: string, payload: string) {.signal.}
|
||||
proc dappGrantDAppPermission*(self: Controller, payload: string) {.signal.}
|
||||
proc dappRevokeDAppPermission*(self: Controller, payload: string) {.signal.}
|
||||
|
||||
proc newController*(service: connector_service.Service, events: EventEmitter): Controller =
|
||||
new(result, delete)
|
||||
|
@ -61,6 +65,26 @@ QtObject:
|
|||
|
||||
controller.dappValidatesTransaction(params.requestId, dappInfo.toJson())
|
||||
|
||||
result.events.on(SIGNAL_CONNECTOR_GRANT_DAPP_PERMISSION) do(e: Args):
|
||||
let params = ConnectorGrantDAppPermissionSignal(e)
|
||||
let dappInfo = %*{
|
||||
"icon": params.iconUrl,
|
||||
"name": params.name,
|
||||
"url": params.url,
|
||||
}
|
||||
|
||||
controller.dappGrantDAppPermission(dappInfo.toJson())
|
||||
|
||||
result.events.on(SIGNAL_CONNECTOR_REVOKE_DAPP_PERMISSION) do(e: Args):
|
||||
let params = ConnectorRevokeDAppPermissionSignal(e)
|
||||
let dappInfo = %*{
|
||||
"icon": params.iconUrl,
|
||||
"name": params.name,
|
||||
"url": params.url,
|
||||
}
|
||||
|
||||
controller.dappRevokeDAppPermission(dappInfo.toJson())
|
||||
|
||||
result.QObject.setup
|
||||
|
||||
proc parseSingleUInt(chainIDsString: string): uint =
|
||||
|
@ -87,3 +111,6 @@ QtObject:
|
|||
|
||||
proc rejectTransactionSigning*(self: Controller, requestId: string): bool {.slot.} =
|
||||
return self.service.rejectTransactionSigning(requestId)
|
||||
|
||||
proc recallDAppPermission*(self: Controller, dAppUrl: string): bool {.slot.} =
|
||||
return self.service.recallDAppPermission(dAppUrl)
|
||||
|
|
|
@ -14,6 +14,8 @@ logScope:
|
|||
|
||||
const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts"
|
||||
const SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION* = "ConnectorSendTransaction"
|
||||
const SIGNAL_CONNECTOR_GRANT_DAPP_PERMISSION* = "ConnectorGrantDAppPermission"
|
||||
const SIGNAL_CONNECTOR_REVOKE_DAPP_PERMISSION* = "ConnectorRevokeDAppPermission"
|
||||
|
||||
# Enum with events
|
||||
type Event* = enum
|
||||
|
@ -65,6 +67,22 @@ QtObject:
|
|||
|
||||
self.events.emit(SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION, data)
|
||||
)
|
||||
self.events.on(SignalType.ConnectorGrantDAppPermission.event, proc(e: Args) =
|
||||
if self.eventHandler == nil:
|
||||
return
|
||||
|
||||
var data = ConnectorGrantDAppPermissionSignal(e)
|
||||
|
||||
self.events.emit(SIGNAL_CONNECTOR_GRANT_DAPP_PERMISSION, data)
|
||||
)
|
||||
self.events.on(SignalType.ConnectorRevokeDAppPermission.event, proc(e: Args) =
|
||||
if self.eventHandler == nil:
|
||||
return
|
||||
|
||||
var data = ConnectorRevokeDAppPermissionSignal(e)
|
||||
|
||||
self.events.emit(SIGNAL_CONNECTOR_REVOKE_DAPP_PERMISSION, data)
|
||||
)
|
||||
|
||||
proc registerEventsHandler*(self: Service, handler: EventHandlerFn) =
|
||||
self.eventHandler = handler
|
||||
|
@ -112,3 +130,11 @@ QtObject:
|
|||
|
||||
proc rejectDappConnect*(self: Service, requestId: string): bool =
|
||||
rejectRequest(self, requestId, status_go.requestAccountsRejectedFinishedRpc, "requestAccountsRejectedFinishedRpc failed: ")
|
||||
|
||||
proc recallDAppPermission*(self: Service, dAppUrl: string): bool =
|
||||
try:
|
||||
return status_go.recallDAppPermissionFinishedRpc(dAppUrl)
|
||||
|
||||
except Exception as e:
|
||||
error "recallDAppPermissionFinishedRpc failed: ", err=e.msg
|
||||
return false
|
|
@ -20,6 +20,9 @@ type SendTransactionAcceptedArgs* = ref object of RootObj
|
|||
type RejectedArgs* = ref object of RootObj
|
||||
requestId* {.serializedFieldName("requestId").}: string
|
||||
|
||||
type RecallDAppPermissionArgs* = ref object of RootObj
|
||||
dAppUrl* {.serializedFieldName("dAppUrl").}: string
|
||||
|
||||
rpc(requestAccountsAccepted, "connector"):
|
||||
args: RequestAccountsAcceptedArgs
|
||||
|
||||
|
@ -32,6 +35,9 @@ rpc(sendTransactionRejected, "connector"):
|
|||
rpc(requestAccountsRejected, "connector"):
|
||||
args: RejectedArgs
|
||||
|
||||
rpc(recallDAppPermission, "connector"):
|
||||
dAppUrl: string
|
||||
|
||||
proc isSuccessResponse(rpcResponse: RpcResponse[JsonNode]): bool =
|
||||
return rpcResponse.error.isNil
|
||||
|
||||
|
@ -45,4 +51,7 @@ proc sendTransactionAcceptedFinishedRpc*(args: SendTransactionAcceptedArgs): boo
|
|||
return isSuccessResponse(sendTransactionAccepted(args))
|
||||
|
||||
proc sendTransactionRejectedFinishedRpc*(args: RejectedArgs): bool =
|
||||
return isSuccessResponse(sendTransactionRejected(args))
|
||||
return isSuccessResponse(sendTransactionRejected(args))
|
||||
|
||||
proc recallDAppPermissionFinishedRpc*(dAppUrl: string): bool =
|
||||
return isSuccessResponse(recallDAppPermission(dAppUrl))
|
|
@ -0,0 +1,69 @@
|
|||
import QtQuick 2.15
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import AppLayouts.Wallet.services.dapps 1.0
|
||||
import shared.stores 1.0
|
||||
import utils 1.0
|
||||
|
||||
QObject {
|
||||
id: root
|
||||
|
||||
readonly property alias dappsModel: d.dappsModel
|
||||
|
||||
function addSession(session) {
|
||||
d.addSession(session)
|
||||
}
|
||||
|
||||
function revokeSession(session) {
|
||||
d.revokeSession(session)
|
||||
}
|
||||
|
||||
function getActiveSession(dAppUrl) {
|
||||
return d.getActionSession(dAppUrl)
|
||||
}
|
||||
|
||||
QObject {
|
||||
id: d
|
||||
|
||||
property ListModel dappsModel: ListModel {
|
||||
id: dapps
|
||||
}
|
||||
|
||||
function addSession(dappInfo) {
|
||||
let dappItem = JSON.parse(dappInfo)
|
||||
dapps.append(dappItem)
|
||||
}
|
||||
|
||||
function revokeSession(dappInfo) {
|
||||
let dappItem = JSON.parse(dappInfo)
|
||||
for (let i = 0; i < dapps.count; i++) {
|
||||
let existingDapp = dapps.get(i)
|
||||
if (existingDapp.url === dappItem.url) {
|
||||
dapps.remove(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function revokeAllSessions() {
|
||||
for (let i = 0; i < dapps.count; i++) {
|
||||
dapps.remove(i)
|
||||
}
|
||||
}
|
||||
|
||||
function getActionSession(dAppUrl) {
|
||||
for (let i = 0; i < dapps.count; i++) {
|
||||
let existingDapp = dapps.get(i)
|
||||
|
||||
if (existingDapp.url === dAppUrl) {
|
||||
return JSON.stringify({
|
||||
name: existingDapp.name,
|
||||
url: existingDapp.url,
|
||||
icon: existingDapp.iconUrl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,6 +39,8 @@ WalletConnectSDKBase {
|
|||
property string requestId: ""
|
||||
property alias requestsModel: requests
|
||||
|
||||
readonly property string invalidDAppUrlError: "Invalid dappInfo: URL is missing"
|
||||
|
||||
projectId: ""
|
||||
|
||||
implicitWidth: 1
|
||||
|
@ -103,10 +105,10 @@ WalletConnectSDKBase {
|
|||
return null
|
||||
}
|
||||
|
||||
let session = getActiveSessions(root.dappInfo)
|
||||
let session = getActiveSession(root.dappInfo)
|
||||
|
||||
if (session === null) {
|
||||
console.error("DAppsRequestHandler.lookupSession: error finding session for topic", obj.topic)
|
||||
console.error("Connector.lookupSession: error finding session for requestId ", obj.requestId)
|
||||
return
|
||||
}
|
||||
obj.resolveDappInfoFromSession(session)
|
||||
|
@ -254,7 +256,7 @@ WalletConnectSDKBase {
|
|||
}
|
||||
|
||||
function acceptSessionRequest(topic, method, id, signature) {
|
||||
console.debug(`WC DappsConnectorSDK.acceptSessionRequest; topic: "${topic}", id: ${root.requestId}, signature: "${signature}"`)
|
||||
console.debug(`Connector DappsConnectorSDK.acceptSessionRequest; requestId: ${root.requestId}, signature: "${signature}"`)
|
||||
|
||||
sessionRequestLoader.active = false
|
||||
controller.approveTransactionRequest(requestId, signature)
|
||||
|
@ -262,7 +264,7 @@ WalletConnectSDKBase {
|
|||
root.wcService.displayToastMessage(qsTr("Successfully signed transaction from %1").arg(root.dappInfo.url), false)
|
||||
}
|
||||
|
||||
function getActiveSessions(dappInfos) {
|
||||
function getActiveSession(dappInfos) {
|
||||
let sessionTemplate = (dappUrl, dappName, dappIcon) => {
|
||||
return {
|
||||
"peer": {
|
||||
|
@ -279,7 +281,16 @@ WalletConnectSDKBase {
|
|||
};
|
||||
}
|
||||
|
||||
return sessionTemplate(dappInfos.url, dappInfos.name, dappInfos.icon)
|
||||
let sessionString = root.wcService.connectorDAppsProvider.getActiveSession(dappInfos.url)
|
||||
if (sessionString === null) {
|
||||
console.error("Connector.lookupSession: error finding session for requestId ", root.requestId)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let session = JSON.parse(sessionString);
|
||||
|
||||
return sessionTemplate(session.url, session.name, session.icon)
|
||||
}
|
||||
|
||||
function authenticate(request) {
|
||||
|
@ -350,6 +361,11 @@ WalletConnectSDKBase {
|
|||
connectDappLoader.active = false
|
||||
rejectSession(root.requestId)
|
||||
}
|
||||
|
||||
onDisconnect: {
|
||||
connectDappLoader.active = false;
|
||||
controller.recallDAppPermission(root.dappInfo.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,6 +470,22 @@ WalletConnectSDKBase {
|
|||
id: requests
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.wcService
|
||||
|
||||
function onRevokeSession(dAppUrl) {
|
||||
if (!dAppUrl) {
|
||||
console.warn(invalidDAppUrlError)
|
||||
return
|
||||
}
|
||||
|
||||
controller.recallDAppPermission(dAppUrl)
|
||||
const session = { url: dAppUrl, name: "", icon: "" }
|
||||
root.wcService.connectorDAppsProvider.revokeSession(JSON.stringify(session))
|
||||
root.wcService.displayToastMessage(qsTr("Disconnected from %1").arg(dAppUrl), false)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: controller
|
||||
|
||||
|
@ -518,11 +550,40 @@ WalletConnectSDKBase {
|
|||
connectDappLoader.active = true
|
||||
root.requestId = requestId
|
||||
}
|
||||
|
||||
onDappGrantDAppPermission: function(dappInfoString) {
|
||||
let dappItem = JSON.parse(dappInfoString)
|
||||
const { url, name, icon: iconUrl } = dappItem
|
||||
|
||||
if (!url) {
|
||||
console.warn(invalidDAppUrlError)
|
||||
return
|
||||
}
|
||||
const session = { url, name, iconUrl }
|
||||
root.wcService.connectorDAppsProvider.addSession(JSON.stringify(session))
|
||||
}
|
||||
|
||||
onDappRevokeDAppPermission: function(dappInfoString) {
|
||||
let dappItem = JSON.parse(dappInfoString)
|
||||
let session = {
|
||||
"url": dappItem.url,
|
||||
"name": dappItem.name,
|
||||
"iconUrl": dappItem.icon
|
||||
}
|
||||
|
||||
if (!session.url) {
|
||||
console.warn(invalidDAppUrlError)
|
||||
return
|
||||
}
|
||||
root.wcService.connectorDAppsProvider.revokeSession(JSON.stringify(session))
|
||||
root.wcService.displayToastMessage(qsTr("Disconnected from %1").arg(dappItem.url), false)
|
||||
}
|
||||
}
|
||||
|
||||
approveSession: function(requestId, account, selectedChains) {
|
||||
controller.approveDappConnectRequest(requestId, account, JSON.stringify(selectedChains))
|
||||
root.wcService.displayToastMessage(qsTr("Successfully authenticated %1").arg(root.dappInfo.url), false)
|
||||
const { url, name, icon: iconUrl } = root.dappInfo;
|
||||
root.wcService.displayToastMessage(qsTr("Successfully authenticated %1").arg(url), false);
|
||||
}
|
||||
|
||||
rejectSession: function(requestId) {
|
||||
|
|
|
@ -32,11 +32,26 @@ QObject {
|
|||
required property DAppsStore store
|
||||
required property var walletRootStore
|
||||
|
||||
readonly property alias dappsModel: dappsProvider.dappsModel
|
||||
readonly property var dappsModel: ConcatModel {
|
||||
markerRoleName: "source"
|
||||
|
||||
sources: [
|
||||
SourceModel {
|
||||
model: dappsProvider.dappsModel
|
||||
markerRoleValue: "walletConnect"
|
||||
},
|
||||
SourceModel {
|
||||
model: connectorDAppsProvider.dappsModel
|
||||
markerRoleValue: "connector"
|
||||
}
|
||||
]
|
||||
}
|
||||
readonly property alias requestHandler: requestHandler
|
||||
|
||||
readonly property bool isServiceAvailableForAddressSelection: dappsProvider.supportedAccountsModel.ModelCount.count
|
||||
|
||||
readonly property alias connectorDAppsProvider: connectorDAppsProvider
|
||||
|
||||
readonly property var validAccounts: SortFilterProxyModel {
|
||||
sourceModel: d.supportedAccountsModel
|
||||
proxyRoles: [
|
||||
|
@ -127,6 +142,8 @@ QObject {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
root.revokeSession(url)
|
||||
}
|
||||
|
||||
function getDApp(dAppUrl) {
|
||||
|
@ -141,6 +158,8 @@ QObject {
|
|||
// and WalletConnectService.approvePair errors
|
||||
signal pairingValidated(int validationState)
|
||||
|
||||
signal revokeSession(string dAppUrl)
|
||||
|
||||
readonly property Connections sdkConnections: Connections {
|
||||
target: wcSDK
|
||||
|
||||
|
@ -293,6 +312,10 @@ QObject {
|
|||
selectedAddress: root.walletRootStore.selectedAddress
|
||||
}
|
||||
|
||||
ConnectorDAppsListProvider {
|
||||
id: connectorDAppsProvider
|
||||
}
|
||||
|
||||
// Timeout for the corner case where the URL was already dismissed and the SDK doesn't respond with an error nor advances with the proposal
|
||||
Timer {
|
||||
id: timeoutTimer
|
||||
|
|
|
@ -5,5 +5,6 @@ DappsConnectorSDK 1.0 DappsConnectorSDK.qml
|
|||
|
||||
DAppsListProvider 1.0 DAppsListProvider.qml
|
||||
DAppsRequestHandler 1.0 DAppsRequestHandler.qml
|
||||
ConnectorDAppsListProvider 1.0 ConnectorDAppsListProvider.qml
|
||||
|
||||
DAppsHelpers 1.0 helpers.js
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit cf1a6631f879726b57247c73ebc4309b601ace7b
|
||||
Subproject commit d5a78e784aa1b8852efc3a82de1cf9a0a1c10eda
|
Loading…
Reference in New Issue