Skip to content

Commit

Permalink
fix(WC): Refactor dapps service to work with multiple SDKs
Browse files Browse the repository at this point in the history
This PR is refactoring the dapps service to avoid code duplication between SDKs and also to avoid overlapping requests/responses.
It brings Browser Connect inline with Wallet Connect in terms of session management and sign transactions.

New architecture:

WalletConnectService becomes DAppsService. Its responsibility is to provide dapp access to the app. This is the component currently used by the UI
What does it do:
1. Provide dapp APIs line connect, disconnect, session requests etc
2. Spawn app notifications on dapp events
3. Timeout requests if the dapp does not respons

DAppsRequestHandler becomes DAppsModule. This component is consumed by the DAppService. Its responsibility is to aggregate all the building blocks for the dapps, but does not control any of the dapp features or consume the SDKs requests.
What does it do:
1. Aggregate all the building blocks for dapps (currently known as plugins)

DAppConnectionsPlugin - This component provides the session management features line connect, disconnect and provide a model with the connected dapps.
SignRequestPlugin - This component provides the sign request management. It receives the sign request from the dapp, translates it to what Status understands and manages the lifecycle of the request.
  • Loading branch information
alexjba committed Nov 20, 2024
1 parent bb483b3 commit 106988d
Show file tree
Hide file tree
Showing 38 changed files with 3,288 additions and 1,110 deletions.
12 changes: 6 additions & 6 deletions src/app/modules/shared_modules/connector/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ QtObject:
proc approveConnectResponse*(self: Controller, payload: string, error: bool) {.signal.}
proc rejectConnectResponse*(self: Controller, payload: string, error: bool) {.signal.}

proc approveTransactionResponse*(self: Controller, requestId: string, error: bool) {.signal.}
proc rejectTransactionResponse*(self: Controller, requestId: string, error: bool) {.signal.}
proc approveTransactionResponse*(self: Controller, topic: string, requestId: string, error: bool) {.signal.}
proc rejectTransactionResponse*(self: Controller, topic: string, requestId: string, error: bool) {.signal.}

proc newController*(service: connector_service.Service, events: EventEmitter): Controller =
new(result, delete)
Expand Down Expand Up @@ -114,15 +114,15 @@ QtObject:
result = self.service.rejectDappConnect(requestId)
self.rejectConnectResponse(requestId, not result)

proc approveTransaction*(self: Controller, requestId: string, signature: string): bool {.slot.} =
proc approveTransaction*(self: Controller, sessionTopic: string, requestId: string, signature: string): bool {.slot.} =
let hash = utils.createHash(signature)

result = self.service.approveTransactionRequest(requestId, hash)
self.approveTransactionResponse(requestId, not result)
self.approveTransactionResponse(sessionTopic, requestId, not result)

proc rejectTransaction*(self: Controller, requestId: string): bool {.slot.} =
proc rejectTransaction*(self: Controller, sessionTopic: string, requestId: string): bool {.slot.} =
result = self.service.rejectTransactionSigning(requestId)
self.rejectTransactionResponse(requestId, not result)
self.rejectTransactionResponse(sessionTopic, requestId, not result)

proc disconnect*(self: Controller, dAppUrl: string): bool {.slot.} =
result = self.service.recallDAppPermission(dAppUrl)
Expand Down
91 changes: 57 additions & 34 deletions storybook/pages/DAppsWorkflowPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Qt.labs.settings 1.0
import QtTest 1.15
import QtQml.Models 2.14

import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Backpressure 0.1
import StatusQ.Controls 0.1
Expand Down Expand Up @@ -64,13 +65,13 @@ Item {

spacing: 8

readonly property var wcService: walletConnectService
readonly property var wcService: dappsService
loginType: Constants.LoginType.Biometrics
selectedAccountAddress: ""

model: wcService.dappsModel
accountsModel: wcService.validAccounts
networksModel: wcService.flatNetworks
accountsModel: dappModule.accountsModel
networksModel: dappModule.networksModel
sessionRequestsModel: wcService.sessionRequestsModel
enabled: wcService.isServiceOnline

Expand Down Expand Up @@ -127,7 +128,7 @@ Item {
Layout.preferredWidth: 20
Layout.preferredHeight: Layout.preferredWidth
radius: Layout.preferredWidth / 2
color: walletConnectService.wcSDK.sdkReady ? "green" : "red"
color: dappModule.wcSdk.sdkReady ? "green" : "red"
}
}

Expand Down Expand Up @@ -166,7 +167,7 @@ Item {
ListView {
Layout.fillWidth: true
Layout.preferredHeight: Math.min(50, contentHeight)
model: walletConnectService.sessionRequestsModel
model: dappsService.sessionRequestsModel
delegate: RowLayout {
StatusBaseText {
text: SQUtils.Utils.elideAndFormatWalletAddress(model.topic, 6, 4)
Expand Down Expand Up @@ -208,7 +209,7 @@ Item {

NetworkFilter {
id: networkFilter
flatNetworks: walletConnectService.walletRootStore.filteredFlatModel
flatNetworks: dappModule.networksModel
}

// spacer
Expand All @@ -228,15 +229,15 @@ Item {
text: "WC feature flag"
checked: true
onCheckedChanged: {
walletConnectService.walletConnectFeatureEnabled = checked
dappsService.walletConnectFeatureEnabled = checked
}
}

CheckBox {
text: "Connector feature flag"
checked: true
onCheckedChanged: {
walletConnectService.connectorFeatureEnabled = checked
dappsService.connectorFeatureEnabled = checked
}
}
}
Expand Down Expand Up @@ -307,7 +308,7 @@ Item {
let modals = StoryBook.InspectionUtils.findVisualsByTypeName(dappsWorkflow, "PairWCModal")
if (modals.length === 1) {
let buttons = StoryBook.InspectionUtils.findVisualsByTypeName(modals[0].footer, "StatusButton")
if (buttons.length === 1 && buttons[0].enabled && walletConnectService.wcSDK.sdkReady) {
if (buttons.length === 1 && buttons[0].enabled && dappModule.wcSdk.sdkReady) {
d.activeTestCase = d.noTestCase
buttons[0].clicked()
return
Expand Down Expand Up @@ -342,32 +343,50 @@ Item {
StatusButton {
text: qsTr("Reject")
onClicked: {
walletConnectService.store.userAuthenticationFailed(authMockDialog.topic, authMockDialog.id)
dappModule.store.userAuthenticationFailed(authMockDialog.topic, authMockDialog.id)
authMockDialog.close()
}
}
StatusButton {
text: qsTr("Authenticate")
onClicked: {
walletConnectService.store.userAuthenticated(authMockDialog.topic, authMockDialog.id, "0x1234567890", "123")
dappModule.store.userAuthenticated(authMockDialog.topic, authMockDialog.id, "0x1234567890", "123")
authMockDialog.close()
}
}
}
}
}

WalletConnectService {
id: walletConnectService

wcSDK: WalletConnectSDK {
enableSdk: settings.enableSDK
DAppsModule {
id: dappModule
wcSdk: WalletConnectSDK {
enabled: settings.enableSDK && dappsService.walletConnectFeatureEnabled

projectId: projectIdText.projectId
}

blockchainNetworksDown: networkFilter.selection
bcSdk: DappsConnectorSDK {
enabled: false

projectId: projectIdText.projectId
networksModel: dappModule.networksModel
accountsModel: dappModule.accountsModel
store: SharedStores.BrowserConnectStore {
signal connectRequested(string requestId, string dappJson)
signal signRequested(string requestId, string requestJson)

signal connected(string dappJson)
signal disconnected(string dappJson)

// Responses to user actions
signal approveConnectResponse(string id, bool error)
signal rejectConnectResponse(string id, bool error)

signal approveTransactionResponse(string topic, string requestId, bool error)
signal rejectTransactionResponse(string topic, string requestId, bool error)
}
}
store: SharedStores.DAppsStore {
signal dappsListReceived(string dappsJson)
signal userAuthenticated(string topic, string id, string password, string pin)
Expand Down Expand Up @@ -485,25 +504,29 @@ Item {
}
}

walletRootStore: SQUtils.QObject {
property var filteredFlatModel: SortFilterProxyModel {
sourceModel: NetworksModel.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: settings.testNetworks; }
}
property var accounts: customAccountsModel.count > 0 ? customAccountsModel : defaultAccountsModel
readonly property ListModel nonWatchAccounts: accounts

readonly property SharedStores.CurrenciesStore currencyStore: SharedStores.CurrenciesStore {}
readonly property WalletStore.WalletAssetsStore walletAssetsStore: WalletStore.WalletAssetsStore {
// Silence warnings
assetsWithFilteredBalances: ListModel {}
// Name mismatch between storybook and production
readonly property var groupedAccountAssetsModel: groupedAccountsAssetsModel
}

readonly property string selectedAddress: ""
currenciesStore: SharedStores.CurrenciesStore {}
groupedAccountAssetsModel: GroupedAccountsAssetsModel {}
accountsModel: customAccountsModel.count > 0 ? customAccountsModel : defaultAccountsModel

networksModel: SortFilterProxyModel {
sourceModel: NetworksModel.flatNetworks
proxyRoles: [
FastExpressionRole {
name: "isOnline"
expression: !networkFilter.selection.map(Number).includes(model.chainId)
expectedRoles: "chainId"
}
]
filters: ValueFilter { roleName: "isTest"; value: settings.testNetworks; }
}
}

DAppsService {
id: dappsService

dappsModule: dappModule
accountsModel: customAccountsModel.count > 0 ? customAccountsModel : defaultAccountsModel
selectedAddress: ""
onDisplayToastMessage: (message, isErr) => {
if(isErr) {
console.log(`Storybook.displayToastMessage(${message}, "", "warning", false, Constants.ephemeralNotificationType.danger, "")`)
Expand Down
103 changes: 103 additions & 0 deletions storybook/pages/SessionRequestPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

import AppLayouts.Wallet.services.dapps.types 1.0

SplitView {
id: root
orientation: Qt.Horizontal

readonly property string sign: "{\n\
\"id\": 1730473461432473,\n\
\"params\": {\n\
\"chainId\": \"eip155:1\",\n\
\"request\": {\n\
\"expiryTimestamp\": 1730473761,\n\
\"method\": \"personal_sign\",\n\
\"params\": [\n\
\"0x4d7920656d61696c206973206a6f686e40646f652e636f6d202d2031373330343733343631343331\",\n\
\"0x8b6950bb8a74489a83e6a1281e3aa008f02bf368\"\n\
]\n\
},\n\
\"topic\": \"3a9a320f8fc8e7a814895b148911373ba7df58c176ddca989f0e72ea1f9b8148\",\n\
\"verifyContext\": {\n\
\"verified\": {\n\
\"isScam\": false,\n\
\"origin\": \"https://react-app.walletconnect.com\",\n\
\"validation\": \"VALID\",\n\
\"verifyUrl\": \"https://verify.walletconnect.org\"\n\
}\n\
}\n\
}\n\
}"
readonly property string transaction: "{\n\
\"id\": 1730473547658704,\n\
\"params\": {\n\
\"chainId\": \"eip155:10\",\n\
\"request\": {\n\
\"expiryTimestamp\": 1730473847,\n\
\"method\": \"eth_sendTransaction\",\n\
\"params\": [\n\
{\n\
\"data\": \"0x\",\n\
\"from\": \"0x8b6950bb8a74489a83e6a1281e3aa008f02bf368\",\n\
\"gasLimit\": \"0x5208\",\n\
\"gasPrice\": \"0x0f437c\",\n\
\"nonce\": \"0x4e\",\n\
\"to\": \"0x8b6950bb8a74489a83e6a1281e3aa008f02bf368\",\n\
\"value\": \"0x00\"\n\
}\n\
]\n\
}\n\
},\n\
\"topic\": \"3a9a320f8fc8e7a814895b148911373ba7df58c176ddca989f0e72ea1f9b8148\",\n\
\"verifyContext\": {\n\
\"verified\": {\n\
\"isScam\": false,\n\
\"origin\": \"https://react-app.walletconnect.com\",\n\
\"validation\": \"VALID\",\n\
\"verifyUrl\": \"https://verify.walletconnect.org\"\n\
}\n\
}\n\
}"
ScrollView {
SplitView.fillHeight: true
SplitView.fillWidth: true
TextArea {
id: result
text: "Result: " + JSON.stringify(SessionRequest.parse(JSON.parse(textEdit.text.replace(/\\n/g, "\n"))), undefined, 2)
readOnly: true
}
}

ColumnLayout {
SplitView.fillHeight: true
SplitView.fillWidth: true
SplitView.preferredWidth: root.width / 2
Label {
text: "Paste the event here to simulate the session request parsing"
font.bold: true
}
Rectangle {
Layout.fillWidth: true
height: 2
color: "black"
}
TextArea {
id: textEdit
Layout.fillHeight: true
Layout.fillWidth: true
text: root.transaction
onTextChanged: text = JSON.stringify(JSON.parse(text.replace(/\\/g, "")), undefined, 2)
}
ComboBox {
id: comboBox
Layout.fillWidth: true
Layout.fillHeight: true
model: ["sign", "transaction"]
currentIndex: 0
onCurrentIndexChanged: textEdit.text = root[comboBox.currentText]
}
}
}
Loading

0 comments on commit 106988d

Please sign in to comment.