feat(wallet): WalletConnect web engine view runs SDK in background

Validated that WebEngineView runs SDK in background and can be hidden
from view.

Closes: #12639
This commit is contained in:
Stefan 2023-11-18 18:06:04 +02:00 committed by Stefan Dunca
parent a87a11f92f
commit 0d10d30b30
4 changed files with 52 additions and 89 deletions

View File

@ -1,5 +1,4 @@
import QtQuick 2.15 import QtQuick 2.15
import QtWebView 1.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
@ -44,31 +43,31 @@ Item {
text: "Pair" text: "Pair"
onClicked: { onClicked: {
statusText.text = "Pairing..." statusText.text = "Pairing..."
d.sdkView.pair(pairLinkInput.text) sdkView.pair(pairLinkInput.text)
} }
enabled: pairLinkInput.text.length > 0 && d.sdkView.sdkReady enabled: pairLinkInput.text.length > 0 && sdkView.sdkReady
} }
StatusButton { StatusButton {
text: "Auth" text: "Auth"
onClicked: { onClicked: {
statusText.text = "Authenticating..." statusText.text = "Authenticating..."
d.sdkView.auth() sdkView.auth()
} }
enabled: false && pairLinkInput.text.length > 0 && d.sdkView.sdkReady enabled: false && pairLinkInput.text.length > 0 && sdkView.sdkReady
} }
StatusButton { StatusButton {
text: "Accept" text: "Accept"
onClicked: { onClicked: {
d.sdkView.approvePairSession(d.sessionProposal, d.supportedNamespaces) sdkView.approvePairSession(d.sessionProposal, d.supportedNamespaces)
} }
visible: root.state === d.waitingPairState visible: root.state === d.waitingPairState
} }
StatusButton { StatusButton {
text: "Reject" text: "Reject"
onClicked: { onClicked: {
d.sdkView.rejectPairSession(d.sessionProposal.id) sdkView.rejectPairSession(d.sessionProposal.id)
} }
visible: root.state === d.waitingPairState visible: root.state === d.waitingPairState
} }
@ -81,14 +80,14 @@ Item {
} }
StatusBaseText { StatusBaseText {
text: "Pairings" text: "Pairings"
visible: d.sdkView.pairingsModel.count > 0 visible: sdkView.pairingsModel.count > 0
} }
StatusListView { StatusListView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: contentHeight Layout.preferredHeight: contentHeight
Layout.maximumHeight: 200 Layout.maximumHeight: 200
model: d.sdkView.pairingsModel model: sdkView.pairingsModel
delegate: StatusBaseText { delegate: StatusBaseText {
text: `${SQUtils.Utils.elideText(topic, 6, 6)} - ${new Date(expiry * 1000).toLocaleString()}` text: `${SQUtils.Utils.elideText(topic, 6, 6)} - ${new Date(expiry * 1000).toLocaleString()}`
@ -127,7 +126,7 @@ Item {
StatusButton { StatusButton {
text: "Reject" text: "Reject"
onClicked: { onClicked: {
d.sdkView.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, false) sdkView.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, false)
} }
visible: root.state === d.waitingUserResponseToSessionRequest visible: root.state === d.waitingUserResponseToSessionRequest
} }
@ -143,62 +142,20 @@ Item {
ColumnLayout { /* spacer */ } ColumnLayout { /* spacer */ }
} }
// TODO: DEBUG JS Loading in DMG
// RowLayout {
// TextField {
// id: urlInput
// Layout.fillWidth: true
// placeholderText: "Insert URL here"
// }
// Button {
// text: "Set URL"
// onClicked: {
// d.sdkView.url = urlInput.text
// }
// }
// }
// Button {
// text: "Set HTML"
// onClicked: {
// d.sdkView.loadHtml(htmlContent.text, "http://status.im")
// }
// }
// StatusInput {
// id: htmlContent
// Layout.fillWidth: true
// Layout.minimumHeight: 200
// Layout.maximumHeight: 300
// text: `<!DOCTYPE html><html><head><title>TODO: Test</title>\n<!--<script src="http://127.0.0.1:8080/bundle.js" defer></script>-->\n<script type='text/javascript'>\n console.log("@dd loaded dummy script!")\n</script>\n</head><body style='background-color: ${root.backgroundColor.toString()};'></body></html>`
// multiline: true
// minimumHeight: Layout.minimumHeight
// maximumHeight: Layout.maximumHeight
// }
// END DEBUGGING
// Separator // Separator
ColumnLayout {} ColumnLayout {}
// TODO: use it in tests to load a dummy SDK
Loader {
id: sdkViewLoader
Layout.fillWidth: true
// Note that a too smaller height might cause the webview to generate rendering errors
Layout.preferredHeight: 10
sourceComponent: SdkViewComponent {}
}
} }
component SdkViewComponent: WalletConnectSDK { WalletConnectSDK {
id: sdkView
// SDK runs fine if WebEngineView is not visible
visible: false
anchors.top: parent.bottom
anchors.left: parent.left
width: 100
height: 100
projectId: controller.projectId projectId: controller.projectId
onSdkInit: function(success, info) { onSdkInit: function(success, info) {
@ -287,8 +244,6 @@ Item {
readonly property string waitingUserResponseToSessionRequest: "waiting_user_response_to_session_request" readonly property string waitingUserResponseToSessionRequest: "waiting_user_response_to_session_request"
readonly property string pairedState: "paired" readonly property string pairedState: "paired"
property var sdkView: sdkViewLoader.item
function setStatusText(message, textColor) { function setStatusText(message, textColor) {
statusText.text = message statusText.text = message
if (textColor === undefined) { if (textColor === undefined) {
@ -324,14 +279,14 @@ Item {
console.log("@dd respondSessionRequest", sessionRequestJson, signedJson, error) console.log("@dd respondSessionRequest", sessionRequestJson, signedJson, error)
if (error) { if (error) {
d.setStatusText("Session Request error", "red") d.setStatusText("Session Request error", "red")
d.sdkView.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, true) sdkView.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, true)
return return
} }
d.sessionRequest = JSON.parse(sessionRequestJson) d.sessionRequest = JSON.parse(sessionRequestJson)
d.signedData = JSON.parse(signedJson) d.signedData = JSON.parse(signedJson)
d.sdkView.acceptSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, d.signedData) sdkView.acceptSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, d.signedData)
d.setStatusText("Session Request accepted") d.setStatusText("Session Request accepted")
d.setDetailsText(d.signedData) d.setDetailsText(d.signedData)

View File

@ -317,6 +317,10 @@ Item {
anchors.fill: parent anchors.fill: parent
Component.onCompleted: {
console.debug(`@dd WalletConnectSDK.WebEngineView.onCompleted; url: ${url}; debug? ${SQUtils.isDebug()};`)
}
url: "qrc:/app/AppLayouts/Wallet/views/walletconnect/sdk/src/index.html" url: "qrc:/app/AppLayouts/Wallet/views/walletconnect/sdk/src/index.html"
webChannel: statusChannel webChannel: statusChannel

View File

@ -6,16 +6,7 @@
### Design questions ### Design questions
- [ ] Do we report all chains and all accounts combination or let user select?
- Wallet Connect require to report all chainIDs that were requested
- Show error to user workflow.
- [ ] Can't respond to sign messages if the wallet-connect dialog/view is closed (app is minimized)
- Only apps that use deep links are expected to work seamlessly
- [ ] Do we report **disabled chains**? **Update session** in case of enabled/disabled chains? - [ ] Do we report **disabled chains**? **Update session** in case of enabled/disabled chains?
- [ ] Allow user to **disconnect session**? Manage sessions?
- [ ] Support update session if one account is added/removed?
- [ ] User awareness of session expiration?
- Support extend session?
- [ ] User error workflow: retry? - [ ] User error workflow: retry?
- [ ] Check the `Auth` request for verifyContext <https://docs.walletconnect.com/web3wallet/verify> - [ ] Check the `Auth` request for verifyContext <https://docs.walletconnect.com/web3wallet/verify>
- [ ] What `description` and `icons` to use for the app? See `metadata` parameter in `Web3Wallet.init` call - [ ] What `description` and `icons` to use for the app? See `metadata` parameter in `Web3Wallet.init` call
@ -37,18 +28,6 @@ Install dependencies steps by executing commands in this directory:
Use the web demo test client https://react-app.walletconnect.com/ for wallet pairing and https://react-auth-dapp.walletconnect.com/ for authentication Use the web demo test client https://react-app.walletconnect.com/ for wallet pairing and https://react-auth-dapp.walletconnect.com/ for authentication
## Log
Initial setup
```sh
npm init -y
npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save @walletconnect/web3wallet
npm run build
# npm run build:dev # for development
```
## Dev - to be removed ## Dev - to be removed
To test SDK loading add the following to `ui/app/mainui/AppMain.qml` To test SDK loading add the following to `ui/app/mainui/AppMain.qml`
@ -75,3 +54,29 @@ StatusDialog {
clip: true clip: true
} }
``` ```
## Log
Initial setup
```sh
npm init -y
npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save @walletconnect/web3wallet
npm run build
# npm run build:dev # for development
```
- [x] Do we report all chains and all accounts combination or let user select?
- Wallet Connect require to report all chainIDs that were requested
- Answer: We only report the available chains for the current account. We will look into adding others to he same session instead of requiring a new link
- [x] Can't respond to sign messages if the wallet-connect dialog/view is closed (app is minimized)
- Only apps that use deep links are expected to work seamlessly
- Also the main workflow will be driven by user
- [x] Allow user to **disconnect session**? Manage sessions?
- Yes, in settings
- [x] Support update session if one account is added/removed?
- Not at first
- [X] User awareness of session expiration?
- Support extend session?
- Yes

View File

@ -22,8 +22,7 @@ continueUserActivity:(NSUserActivity *)userActivity
if (!url) if (!url)
return FALSE; return FALSE;
QUrl deeplink = QUrl::fromNSURL(url); QUrl deeplink = QUrl::fromNSURL(url);
// TODO #12434: Check if WalletConnect link and redirect the workflow // TODO #12434: Check if WalletConnect link and redirect the workflow to Pair or Authenticate
qDebug() << "@dd deeplink " << deeplink;
// TODO #12245: set it to nim // TODO #12245: set it to nim
return TRUE; return TRUE;