DEMO on how would connector quickly integrate by simulating a
wallet-connect session
This commit is contained in:
parent
78e605d928
commit
1526afae6f
|
@ -19,6 +19,7 @@ import ./activity/details_controller as activity_detailsc
|
|||
|
||||
import app/modules/shared_modules/collectible_details/controller as collectible_detailsc
|
||||
import app/modules/shared_modules/wallet_connect/controller as wc_controller
|
||||
import app/modules/shared_modules/connector/controller as connector_controller
|
||||
|
||||
import app/global/global_singleton
|
||||
import app/core/eventemitter
|
||||
|
@ -39,6 +40,7 @@ import app_service/service/network_connection/service as network_connection_serv
|
|||
import app_service/service/devices/service as devices_service
|
||||
import app_service/service/community_tokens/service as community_tokens_service
|
||||
import app_service/service/wallet_connect/service as wc_service
|
||||
import app_service/service/connector/service as connector_service
|
||||
|
||||
import backend/collectibles as backend_collectibles
|
||||
|
||||
|
@ -80,7 +82,9 @@ type
|
|||
savedAddressService: saved_address_service.Service
|
||||
devicesService: devices_service.Service
|
||||
walletConnectService: wc_service.Service
|
||||
dappsConnectorService: connector_service.Service
|
||||
walletConnectController: wc_controller.Controller
|
||||
dappsConnectorController: connector_controller.Controller
|
||||
|
||||
activityController: activityc.Controller
|
||||
collectibleDetailsController: collectible_detailsc.Controller
|
||||
|
@ -171,7 +175,10 @@ proc newModule*(
|
|||
result.walletConnectService = wc_service.newService(result.events, result.threadpool, settingsService)
|
||||
result.walletConnectController = wc_controller.newController(result.walletConnectService, walletAccountService)
|
||||
|
||||
result.view = newView(result, result.activityController, result.tmpActivityControllers, result.activityDetailsController, result.collectibleDetailsController, result.walletConnectController)
|
||||
result.dappsConnectorService = connector_service.newService(result.events)
|
||||
result.dappsConnectorController = connector_controller.newController(result.dappsConnectorService)
|
||||
|
||||
result.view = newView(result, result.activityController, result.tmpActivityControllers, result.activityDetailsController, result.collectibleDetailsController, result.walletConnectController, result.dappsConnectorController)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
|
||||
method delete*(self: Module) =
|
||||
|
@ -348,6 +355,7 @@ method load*(self: Module) =
|
|||
self.sendModule.load()
|
||||
self.networksModule.load()
|
||||
self.walletConnectService.init()
|
||||
self.dappsConnectorService.init()
|
||||
|
||||
method isLoaded*(self: Module): bool =
|
||||
return self.moduleLoaded
|
||||
|
|
|
@ -6,6 +6,7 @@ import app/modules/shared_modules/collectible_details/controller as collectible_
|
|||
import ./io_interface
|
||||
import app/modules/shared_models/currency_amount
|
||||
import app/modules/shared_modules/wallet_connect/controller as wc_controller
|
||||
import app/modules/shared_modules/connector/controller as connector_controller
|
||||
|
||||
type
|
||||
ActivityControllerArray* = array[2, activityc.Controller]
|
||||
|
@ -26,6 +27,7 @@ QtObject:
|
|||
isNonArchivalNode: bool
|
||||
keypairOperabilityForObservedAccount: string
|
||||
wcController: QVariant
|
||||
dappsConnectorController: QVariant
|
||||
walletReady: bool
|
||||
addressFilters: string
|
||||
currentCurrency: string
|
||||
|
@ -37,6 +39,7 @@ QtObject:
|
|||
|
||||
proc delete*(self: View) =
|
||||
self.wcController.delete
|
||||
self.dappsConnectorController.delete
|
||||
|
||||
self.QObject.delete
|
||||
|
||||
|
@ -45,7 +48,8 @@ QtObject:
|
|||
tmpActivityControllers: ActivityControllerArray,
|
||||
activityDetailsController: activity_detailsc.Controller,
|
||||
collectibleDetailsController: collectible_detailsc.Controller,
|
||||
wcController: wc_controller.Controller): View =
|
||||
wcController: wc_controller.Controller,
|
||||
dappsConnectorController: connector_controller.Controller): View =
|
||||
new(result, delete)
|
||||
result.delegate = delegate
|
||||
result.activityController = activityController
|
||||
|
@ -53,6 +57,7 @@ QtObject:
|
|||
result.activityDetailsController = activityDetailsController
|
||||
result.collectibleDetailsController = collectibleDetailsController
|
||||
result.wcController = newQVariant(wcController)
|
||||
result.dappsConnectorController = newQVariant(dappsConnectorController)
|
||||
|
||||
result.setup()
|
||||
|
||||
|
@ -248,6 +253,14 @@ QtObject:
|
|||
QtProperty[QVariant] walletConnectController:
|
||||
read = getWalletConnectController
|
||||
|
||||
proc getDappsConnectorController(self: View): QVariant {.slot.} =
|
||||
if self.dappsConnectorController == nil:
|
||||
return newQVariant()
|
||||
return self.dappsConnectorController
|
||||
|
||||
QtProperty[QVariant] dappsConnectorController:
|
||||
read = getDappsConnectorController
|
||||
|
||||
proc walletReadyChanged*(self: View) {.signal.}
|
||||
|
||||
proc getWalletReady*(self: View): bool {.slot.} =
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import NimQml
|
||||
import chronicles
|
||||
|
||||
import app_service/service/connector/service as connector_service
|
||||
|
||||
logScope:
|
||||
topics = "connector-controller"
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Controller* = ref object of QObject
|
||||
service: connector_service.Service
|
||||
|
||||
proc delete*(self: Controller) =
|
||||
self.QObject.delete
|
||||
|
||||
proc dappRequestsToConnect*(self: Controller, payload: string) {.signal.}
|
||||
|
||||
proc newController*(service: connector_service.Service): Controller =
|
||||
new(result, delete)
|
||||
|
||||
result.service = service
|
||||
service.registerEventsHandler(proc (event: connector_service.Event, payload: string) =
|
||||
# TODO: there is some compilation error here. Need to propagate event to signal
|
||||
# case event
|
||||
# of connector_service.Event.DappConnect:
|
||||
# result.dappRequestsToConnect(payload)
|
||||
# TODO of SendTransaction:
|
||||
discard
|
||||
)
|
||||
|
||||
result.QObject.setup
|
||||
|
||||
proc approveDappConnectRequest*(self: Controller, accountsJson: string): bool {.slot.} =
|
||||
return self.service.approveDappConnect(accountsJson)
|
||||
|
||||
proc rejectDappConnectRequest*(self: Controller, id: string): bool {.slot.} =
|
||||
return self.service.rejectDappConnect(id)
|
||||
|
||||
proc errorProcessingDappConnectRequest*(self: Controller): bool {.slot.} =
|
||||
return self.service.errorProcessingDappConnect()
|
||||
|
||||
proc getDappsJson*(self: Controller): string {.slot.} =
|
||||
# TODO: return a json string with the list of dApps to be parsed in ConnectorSDK.getActiveSessions
|
||||
#return @[{url, name, icon}].toJson
|
||||
return ""
|
||||
|
||||
proc disconnectDapp*(self: Controller, url: string): bool {.slot.} =
|
||||
# TODO: call service ...
|
||||
return true
|
|
@ -0,0 +1,68 @@
|
|||
import NimQml, chronicles, json
|
||||
|
||||
import backend/connector as status_go
|
||||
|
||||
import app/global/global_singleton
|
||||
|
||||
import app/core/eventemitter
|
||||
import app/core/signals/types
|
||||
|
||||
logScope:
|
||||
topics = "connector-service"
|
||||
|
||||
# Enum with events
|
||||
type Event* = enum
|
||||
DappConnect
|
||||
# TODO SendTransaction
|
||||
|
||||
# Event handler function
|
||||
type EventHandlerFn* = proc(event: Event, payload: string)
|
||||
|
||||
# This can be ditched for now and process everything in the controller;
|
||||
# However, it would be good to have the DB based calls async and this might be needed
|
||||
QtObject:
|
||||
type Service* = ref object of QObject
|
||||
events: EventEmitter
|
||||
eventHandler: EventHandlerFn
|
||||
|
||||
proc delete*(self: Service) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newService*(
|
||||
events: EventEmitter
|
||||
): Service =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
|
||||
result.events = events
|
||||
|
||||
proc init*(self: Service) =
|
||||
self.events.on(SignalType.Wallet.event, proc(e: Args) =
|
||||
if self.eventHandler == nil:
|
||||
return
|
||||
|
||||
var data = WalletSignal(e)
|
||||
|
||||
# TODO Uncomment if still considering to use the request ID for request identification
|
||||
#if not data.requestId.isSome():
|
||||
# return
|
||||
|
||||
case data.eventType:
|
||||
of status_go.EventConnectorSendRequestAccounts:
|
||||
# TODO: propagate up to the presentation layer via controller
|
||||
discard
|
||||
# TODO of status_go.EventConnectorSendTransaction:
|
||||
)
|
||||
|
||||
proc registerEventsHandler*(self: Service, handler: EventHandlerFn) =
|
||||
self.eventHandler = handler
|
||||
|
||||
proc approveDappConnect*(self: Service, accountsJson: string): bool =
|
||||
return status_go.requestAccountsFinishedRpc(accountsJson, status_go.RequestAccountNoError)
|
||||
|
||||
proc rejectDappConnect*(self: Service, id: string): bool =
|
||||
# Pass the id to status-go
|
||||
return status_go.requestAccountsFinishedRpc("{?}", status_go.RequestAccountRejectError)
|
||||
|
||||
proc errorProcessingDappConnect*(self: Service): bool =
|
||||
return status_go.requestAccountsFinishedRpc("[]", status_go.RequestAccountGenericError)
|
|
@ -0,0 +1,52 @@
|
|||
import options, logging
|
||||
import json, json_serialization
|
||||
import core, response_type
|
||||
|
||||
from gen import rpc
|
||||
|
||||
const
|
||||
EventConnectorSendRequestAccounts* = "connector.sendRequestAccounts"
|
||||
EventConnectorSendTransaction* = "connector.sendTransaction"
|
||||
|
||||
# TODO: improve on the way to handle the same errors in status-go
|
||||
RequestAccountNoError* = ""
|
||||
RequestAccountRejectError* = "connector.RequestAccountRejectError"
|
||||
RequestAccountGenericError* = "connector.RequestAccountGenericError"
|
||||
|
||||
# type RequestAccountsFinishedArgs struct {
|
||||
# Accounts []types.Address
|
||||
# Error *error
|
||||
# }
|
||||
# implement above in nim
|
||||
type RequestAccountsFinishedArgs* = ref object of RootObj
|
||||
accounts* {.serializedFieldName("accounts").}: seq[string]
|
||||
error* {.serializedFieldName("error").}: string
|
||||
|
||||
|
||||
# TODO This file is the bridge between nim and RPC calls. We should define all the connector-related RPCs here.
|
||||
|
||||
# TODO Adjust the namespace as you see fit.
|
||||
rpc(requestAccountsFinished, "connector"):
|
||||
args: RequestAccountsFinishedArgs
|
||||
|
||||
proc isSuccessResponse(rpcResponse: RpcResponse[JsonNode]): bool =
|
||||
return rpcResponse.error.isNil
|
||||
|
||||
# accountsJson is a stringified JS array
|
||||
proc requestAccountsFinishedRpc*(accountsJson: string, error: string): bool =
|
||||
try:
|
||||
let args = RequestAccountsFinishedArgs()
|
||||
if error.len > 0:
|
||||
args.error = error
|
||||
else:
|
||||
let accountsJN = parseJson(accountsJson)
|
||||
# TODO fill in args.accounts with the parsed accountsJN
|
||||
|
||||
let rpcRes = requestAccountsFinished(args)
|
||||
return isSuccessResponse(rpcRes):
|
||||
except Exception as e:
|
||||
error "TODO failed: ", "msg", e.msg
|
||||
return false
|
||||
|
||||
# TODO rendTransactionFinishedRpc
|
||||
# TODO recallDAppPermissionRpc
|
|
@ -0,0 +1,113 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import QtWebEngine 1.10
|
||||
import QtWebChannel 1.15
|
||||
|
||||
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
import "types"
|
||||
|
||||
// Act as another layer of abstraction to the WalletConnectSDKBase
|
||||
// Quick hack until the WalletConnectSDKBase could be refactored to a more generic DappProviderBase with API to match
|
||||
// the UX requirements
|
||||
WalletConnectSDKBase {
|
||||
id: root
|
||||
|
||||
// Nim connector.controller instance
|
||||
required property controller
|
||||
|
||||
readonly property alias sdkReady: true
|
||||
readonly property bool active: true
|
||||
|
||||
implicitWidth: 1
|
||||
implicitHeight: 1
|
||||
|
||||
Connections {
|
||||
target: controller
|
||||
function dappRequestsToConnect(dappInfo): {
|
||||
root.sessionProposal(JSON.parse(`{
|
||||
"id": ${dappInfo.id},
|
||||
"params": {
|
||||
"id": ${dappInfo.id},
|
||||
"optionalNamespaces": {},
|
||||
"proposer": {
|
||||
"metadata": {
|
||||
"description": "-",
|
||||
"icons": [
|
||||
"${dappInfo.icon}"
|
||||
],
|
||||
"name": "${dappInfo.name}",
|
||||
"url": "${dappInfo.url}"
|
||||
},
|
||||
},
|
||||
"requiredNamespaces": {
|
||||
"eip155": {
|
||||
"chains": [
|
||||
"eip155:${dappInfo.chainId}"
|
||||
],
|
||||
"events": [],
|
||||
"methods": ["eth_sendTransaction"],
|
||||
}
|
||||
}
|
||||
}
|
||||
}`))
|
||||
}
|
||||
}
|
||||
|
||||
getActiveSessions: function(callback) {
|
||||
let sessionTemplate = (dappUrl, dappName, dappIcon) => {
|
||||
return JSON.parse(`{
|
||||
"peer": {
|
||||
"metadata": {
|
||||
"description": "-",
|
||||
"icons": [
|
||||
"${dappIcon}"
|
||||
],
|
||||
"name": "${dappName}",
|
||||
"url": "${dappUrl}"
|
||||
}
|
||||
},
|
||||
"topic": "dappUrl"
|
||||
}`)
|
||||
}
|
||||
let dapps = JSON.parse(controller.getDappsJson())
|
||||
var sessions = []
|
||||
for (let i = 0; i < dapps.length; i++) {
|
||||
let dapp = dapps[i]
|
||||
let session = sessionTemplate(dapp.url, dapp.name, dapp.icon)
|
||||
sessions.push(session)
|
||||
}
|
||||
callback(sessions.push(session))
|
||||
}
|
||||
|
||||
disconnectSession: function(topic) {
|
||||
controller.disconnectDapp(topic)
|
||||
}
|
||||
|
||||
approveSession: function(sessionProposal, supportedNamespaces) {
|
||||
// TODO extract the account from the sessionProposal
|
||||
controller.approveDappConnectRequest()
|
||||
}
|
||||
|
||||
rejectSession: function(id) {
|
||||
// TODO: ensure id is propagated
|
||||
controller.rejectDappConnectRequest(id)
|
||||
}
|
||||
|
||||
acceptSessionRequest: function(topic, id, signature) {
|
||||
// TODO propagate to controller
|
||||
}
|
||||
|
||||
rejectSessionRequest: function(topic, id, error) {
|
||||
// TODO propagate to controller
|
||||
}
|
||||
|
||||
// We don't expect requests for these. They are here only to spot errors
|
||||
pair: function(pairLink) { console.error("ConnectorSDK.pair: not implemented") }
|
||||
getPairings: function(callback) { console.error("ConnectorSDK.getPairings: not implemented") }
|
||||
disconnectPairing: function(topic) { console.error("ConnectorSDK.disconnectPairing: not implemented") }
|
||||
buildApprovedNamespaces: function(params, supportedNamespaces) { console.error("ConnectorSDK.buildApprovedNamespaces: not implemented") }
|
||||
}
|
|
@ -105,6 +105,7 @@ QtObject {
|
|||
readonly property var tmpActivityController1: walletSectionInst.tmpActivityController1
|
||||
readonly property var activityDetailsController: walletSectionInst.activityDetailsController
|
||||
readonly property var walletConnectController: walletSectionInst.walletConnectController
|
||||
readonly property var dappsConnectorController: walletSectionInst.dappsConnectorController
|
||||
|
||||
readonly property bool isAccountTokensReloading: walletSectionInst.isAccountTokensReloading
|
||||
readonly property double lastReloadTimestamp: walletSectionInst.lastReloadTimestamp
|
||||
|
|
|
@ -2042,6 +2042,31 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: walletConnectSDK
|
||||
WalletConnectSDK {
|
||||
active: WalletStore.RootStore.walletSectionInst.walletReady
|
||||
|
||||
projectId: WalletStore.RootStore.appSettings.walletConnectProjectID
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: dappsConnector
|
||||
|
||||
DappsConnectorSDK {
|
||||
controller: WalletStore.RootStore.dappsConnectorController
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary solution to use the dapps connector until a proper abstraction is in place
|
||||
Loader {
|
||||
id: sdkLoader
|
||||
sourceComponent: Global.featureFlags.dappsConnectorEnabled
|
||||
? dappsConnector
|
||||
: walletConnectSDK
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: walletConnectServiceLoader
|
||||
|
||||
|
@ -2050,11 +2075,7 @@ Item {
|
|||
sourceComponent: WalletConnectService {
|
||||
id: walletConnectService
|
||||
|
||||
wcSDK: WalletConnectSDK {
|
||||
active: WalletStore.RootStore.walletSectionInst.walletReady
|
||||
|
||||
projectId: WalletStore.RootStore.appSettings.walletConnectProjectID
|
||||
}
|
||||
wcSDK: sdkLoader.item
|
||||
store: DAppsStore {
|
||||
controller: WalletStore.RootStore.walletConnectController
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue