chore(dapps) remove the POC wallet connect

Updates: #15598
This commit is contained in:
Stefan 2024-07-25 13:37:32 +03:00 committed by Stefan Dunca
parent 20620e04cf
commit da622348f6
14 changed files with 0 additions and 1264 deletions

View File

@ -391,9 +391,6 @@ proc checkForStoringPasswordToKeychain(self: AppController) =
else:
self.keychainService.storeData(account.keyUid, self.startupModule.getPin())
proc chekForWalletConnectPairings(self: AppController) =
self.statusFoundation.events.emit(WALLET_CONNECT_CHECK_PAIRINGS, Args())
proc startupDidLoad*(self: AppController) =
singletonInstance.engine.setRootContextProperty("localAppSettings", self.localAppSettingsVariant)
singletonInstance.engine.setRootContextProperty("localAccountSettings", self.localAccountSettingsVariant)
@ -410,7 +407,6 @@ proc mainDidLoad*(self: AppController) =
self.applyNecessaryActionsAfterLoggingIn()
self.startupModule.moveToAppState()
self.checkForStoringPasswordToKeychain()
self.chekForWalletConnectPairings()
proc start*(self: AppController) =
self.keycardService.init()

View File

@ -48,6 +48,3 @@ type
addresses*: seq[string]
const MARK_WALLET_ADDRESSES_AS_SHOWN* = "markWalletAddressesAsShown"
const WALLET_CONNECT_CHECK_PAIRINGS* = "walletConnectCheckPairings"

View File

@ -1,262 +0,0 @@
################################################################################
# WalletConnect POC - to remove this file
################################################################################
import NimQml, strutils, json, chronicles
import backend/wallet as backend_wallet
import backend/poc_wallet_connect as backend_wallet_connect
import app/global/global_singleton
import app/global/app_signals
import app/core/eventemitter
import app/core/signals/types
import app/global/app_signals
import app_service/common/utils as common_utils
from app_service/service/transaction/dto import PendingTransactionTypeDto
import app_service/service/wallet_account/service as wallet_account_service
import app/modules/shared_modules/keycard_popup/io_interface as keycard_shared_module
import constants
import tx_response_dto, helpers
const UNIQUE_WC_SESSION_REQUEST_SIGNING_IDENTIFIER* = "WalletConnect-SessionRequestSigning"
const UNIQUE_WC_AUTH_REQUEST_SIGNING_IDENTIFIER* = "WalletConnect-AuthRequestSigning"
logScope:
topics = "wallet-connect"
QtObject:
type
Controller* = ref object of QObject
events: EventEmitter
walletAccountService: wallet_account_service.Service
sessionRequestJson: JsonNode
txResponseDto: TxResponseDto
hasActivePairings: bool
## Forward declarations
proc invalidateData(self: Controller)
proc setHasActivePairings*(self: Controller, value: bool)
proc onDataSigned(self: Controller, keyUid: string, path: string, r: string, s: string, v: string, pin: string, identifier: string)
proc finishSessionRequest(self: Controller, signature: string)
proc finishAuthRequest(self: Controller, signature: string)
## signals
proc checkPairings*(self: Controller) {.signal.}
proc requestOpenWalletConnectPopup*(self: Controller, uri: string) {.signal.}
proc hasActivePairingsChanged*(self: Controller) {.signal.}
proc respondSessionProposal*(self: Controller, sessionProposalJson: string, supportedNamespacesJson: string, error: string) {.signal.}
proc respondSessionRequest*(self: Controller, sessionRequestJson: string, signedJson: string, error: bool) {.signal.}
proc respondAuthRequest*(self: Controller, signature: string, error: bool) {.signal.}
proc setup(self: Controller) =
self.QObject.setup
# Register for wallet events
self.events.on(SignalType.Wallet.event, proc(e: Args) =
# TODO #12434: async processing
discard
)
self.events.on(SIGNAL_STATUS_URL_ACTIVATED) do(e: Args):
var args = StatusUrlArgs(e)
let (found, wcUri) = extractAndCheckUriParameter(args.url)
if found:
self.requestOpenWalletConnectPopup(wcUri)
self.events.on(WALLET_CONNECT_CHECK_PAIRINGS) do(e: Args):
self.setHasActivePairings(true)
self.checkPairings()
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_DATA_SIGNED) do(e: Args):
let args = SharedKeycarModuleArgs(e)
if args.uniqueIdentifier != UNIQUE_WC_SESSION_REQUEST_SIGNING_IDENTIFIER and
args.uniqueIdentifier != UNIQUE_WC_AUTH_REQUEST_SIGNING_IDENTIFIER:
return
self.onDataSigned(args.keyUid, args.path, args.r, args.s, args.v, args.pin, args.uniqueIdentifier)
proc delete*(self: Controller) =
self.invalidateData()
self.QObject.delete
proc newController*(events: EventEmitter, walletAccountService: wallet_account_service.Service): Controller =
new(result, delete)
result.events = events
result.walletAccountService = walletAccountService
result.setup()
proc invalidateData(self: Controller) =
self.sessionRequestJson = nil
self.txResponseDto = nil
proc onDataSigned(self: Controller, keyUid: string, path: string, r: string, s: string, v: string, pin: string, identifier: string) =
if keyUid.len == 0 or path.len == 0 or r.len == 0 or s.len == 0 or v.len == 0 or pin.len == 0:
error "invalid data signed"
return
let signature = "0x" & r & s & v
if identifier == UNIQUE_WC_SESSION_REQUEST_SIGNING_IDENTIFIER:
self.finishSessionRequest(signature)
elif identifier == UNIQUE_WC_AUTH_REQUEST_SIGNING_IDENTIFIER:
self.finishAuthRequest(signature)
else:
error "Unknown identifier"
proc sessionProposal(self: Controller, sessionProposalJson: string) {.slot.} =
var
supportedNamespacesJson: string
error: string
try:
var res: JsonNode
let err = backend_wallet_connect.pair(res, sessionProposalJson)
if err.len > 0:
raise newException(CatchableError, err)
supportedNamespacesJson = if res.hasKey("supportedNamespaces"): $res["supportedNamespaces"] else: ""
except Exception as e:
error = e.msg
error "pairing", msg=error
self.respondSessionProposal(sessionProposalJson, supportedNamespacesJson, error)
proc saveOrUpdateSession(self: Controller, sessionJson: string) {.slot.} =
if not backend_wallet_connect.saveOrUpdateSession(sessionJson):
error "Failed to save/update session"
proc deleteSession(self: Controller, topic: string) {.slot.} =
if not backend_wallet_connect.deleteSession(topic):
error "Failed to delete session"
proc getHasActivePairings*(self: Controller): bool {.slot.} =
return self.hasActivePairings
proc setHasActivePairings*(self: Controller, value: bool) {.slot.} =
self.hasActivePairings = value
self.hasActivePairingsChanged()
QtProperty[bool] hasActivePairings:
read = getHasActivePairings
write = setHasActivePairings
notify = hasActivePairingsChanged
proc sendTransactionAndRespond(self: Controller, signature: string) =
let finalSignature = singletonInstance.utils.removeHexPrefix(signature)
var txResponse: JsonNode
let err = backend_wallet.sendTransactionWithSignature(txResponse, self.txResponseDto.chainId,
$PendingTransactionTypeDto.WalletConnectTransfer, $self.txResponseDto.txArgsJson, finalSignature)
if err.len > 0 or txResponse.isNil:
error "Failed to send tx"
return
let txHash = txResponse.getStr
self.respondSessionRequest($self.sessionRequestJson, txHash, false)
proc buildRawTransactionAndRespond(self: Controller, signature: string) =
let finalSignature = singletonInstance.utils.removeHexPrefix(signature)
var txResponse: JsonNode
let err = backend_wallet.buildRawTransaction(txResponse, self.txResponseDto.chainId, $self.txResponseDto.txArgsJson,
finalSignature)
if err.len > 0:
error "Failed to build raw tx"
return
let txResponseDto = txResponse.toTxResponseDto()
self.respondSessionRequest($self.sessionRequestJson, txResponseDto.rawTx, false)
proc finishSessionRequest(self: Controller, signature: string) =
if signature.len == 0:
self.respondSessionRequest($self.sessionRequestJson, "", true)
return
let requestMethod = getRequestMethod(self.sessionRequestJson)
if requestMethod == RequestMethod.SendTransaction:
self.sendTransactionAndRespond(signature)
elif requestMethod == RequestMethod.SignTransaction:
self.buildRawTransactionAndRespond(signature)
elif requestMethod == RequestMethod.PersonalSign:
self.respondSessionRequest($self.sessionRequestJson, signature, false)
elif requestMethod == RequestMethod.EthSign:
self.respondSessionRequest($self.sessionRequestJson, signature, false)
elif requestMethod == RequestMethod.SignTypedData or
requestMethod == RequestMethod.SignTypedDataV3 or
requestMethod == RequestMethod.SignTypedDataV4:
self.respondSessionRequest($self.sessionRequestJson, signature, false)
else:
error "Unknown request method"
self.respondSessionRequest($self.sessionRequestJson, "", true)
proc sessionRequest*(self: Controller, sessionRequestJson: string, password: string) {.slot.} =
var signature: string
try:
self.invalidateData()
self.sessionRequestJson = parseJson(sessionRequestJson)
var sessionRes: JsonNode
let err = backend_wallet_connect.sessionRequest(sessionRes, sessionRequestJson)
if err.len > 0:
raise newException(CatchableError, err)
self.txResponseDto = sessionRes.toTxResponseDto()
if self.txResponseDto.signOnKeycard:
let data = SharedKeycarModuleSigningArgs(uniqueIdentifier: UNIQUE_WC_SESSION_REQUEST_SIGNING_IDENTIFIER,
keyUid: self.txResponseDto.keyUid,
path: self.txResponseDto.addressPath,
dataToSign: singletonInstance.utils.removeHexPrefix(self.txResponseDto.messageToSign))
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA, data)
return
else:
let hashedPasssword = common_utils.hashPassword(password)
var signMsgRes: JsonNode
let err = backend_wallet.signMessage(signMsgRes,
self.txResponseDto.messageToSign,
self.txResponseDto.address,
hashedPasssword)
if err.len > 0:
raise newException(CatchableError, err)
signature = signMsgRes.getStr
except Exception as e:
error "session request", msg=e.msg
self.finishSessionRequest(signature)
proc getProjectId*(self: Controller): string {.slot.} =
return constants.WALLET_CONNECT_PROJECT_ID
QtProperty[string] projectId:
read = getProjectId
proc getWalletAccounts*(self: Controller): string {.slot.} =
let jsonObj = % self.walletAccountService.getWalletAccounts()
return $jsonObj
proc finishAuthRequest(self: Controller, signature: string) =
if signature.len == 0:
self.respondAuthRequest("", true)
return
self.respondAuthRequest(signature, false)
proc authRequest*(self: Controller, selectedAddress: string, authMessage: string, password: string) {.slot.} =
var signature: string
try:
self.invalidateData()
var sessionRes: JsonNode
let err = backend_wallet_connect.authRequest(sessionRes, selectedAddress, authMessage)
if err.len > 0:
raise newException(CatchableError, err)
self.txResponseDto = sessionRes.toTxResponseDto()
if self.txResponseDto.signOnKeycard:
let data = SharedKeycarModuleSigningArgs(uniqueIdentifier: UNIQUE_WC_AUTH_REQUEST_SIGNING_IDENTIFIER,
keyUid: self.txResponseDto.keyUid,
path: self.txResponseDto.addressPath,
dataToSign: singletonInstance.utils.removeHexPrefix(self.txResponseDto.messageToSign))
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA, data)
return
else:
let hashedPasssword = common_utils.hashPassword(password)
var signMsgRes: JsonNode
let err = backend_wallet.signMessage(signMsgRes,
self.txResponseDto.messageToSign,
self.txResponseDto.address,
hashedPasssword)
if err.len > 0:
raise newException(CatchableError, err)
signature = signMsgRes.getStr
except Exception as e:
error "auth request", msg=e.msg
self.finishAuthRequest(signature)

View File

@ -1,47 +0,0 @@
################################################################################
# WalletConnect POC - to remove this file
################################################################################
import json, strutils
import uri
include app_service/common/json_utils
type
RequestMethod* {.pure.} = enum
Unknown = "unknown"
SendTransaction = "eth_sendTransaction"
SignTransaction = "eth_signTransaction"
PersonalSign = "personal_sign"
EthSign = "eth_sign"
SignTypedData = "eth_signTypedData"
SignTypedDataV3 = "eth_signTypedData_v3"
SignTypedDataV4 = "eth_signTypedData_v4"
## provided json represents a `SessionRequest`
proc getRequestMethod*(jsonObj: JsonNode): RequestMethod =
var paramsJsonObj: JsonNode
if jsonObj.getProp("params", paramsJsonObj):
var requestJsonObj: JsonNode
if paramsJsonObj.getProp("request", requestJsonObj):
var requestMethod: string
discard requestJsonObj.getProp("method", requestMethod)
try:
return parseEnum[RequestMethod](requestMethod)
except:
discard
return RequestMethod.Unknown
# check and extract Wallet Connect URI parameter from a deep link updated URL
proc extractAndCheckUriParameter*(url: string): (bool, string) =
let parsedUrl = parseUri(url)
if parsedUrl.path != "/wc":
return (false, "")
for (key, value) in decodeQuery(parsedUrl.query):
if key.toLower == "uri":
if value.startsWith("wc:"):
return (true, value)
return (false, "")

View File

@ -1,31 +0,0 @@
################################################################################
# WalletConnect POC - to remove this file
################################################################################
import json
include app_service/common/json_utils
type
TxResponseDto* = ref object
keyUid*: string
address*: string
addressPath*: string
signOnKeycard*: bool
chainId*: int
messageToSign*: string
txArgsJson*: JsonNode
rawTx*: string
txHash*: string
proc toTxResponseDto*(jsonObj: JsonNode): TxResponseDto =
result = TxResponseDto()
discard jsonObj.getProp("keyUid", result.keyUid)
discard jsonObj.getProp("address", result.address)
discard jsonObj.getProp("addressPath", result.addressPath)
discard jsonObj.getProp("signOnKeycard", result.signOnKeycard)
discard jsonObj.getProp("chainId", result.chainId)
discard jsonObj.getProp("messageToSign", result.messageToSign)
discard jsonObj.getProp("txArgs", result.txArgsJson)
discard jsonObj.getProp("rawTx", result.rawTx)
discard jsonObj.getProp("txHash", result.txHash)

View File

@ -1,97 +0,0 @@
################################################################################
# WalletConnect POC - to remove this file
################################################################################
import options, logging
import json
import core, response_type
from gen import rpc
import backend
# Declared in services/wallet/walletconnect/walletconnect.go
const eventWCProposeUserPair*: string = "WalletConnectProposeUserPair"
# Declared in services/wallet/walletconnect/walletconnect.go
const ErrorChainsNotSupported*: string = "chains not supported"
rpc(wCSignMessage, "wallet"):
message: string
address: string
password: string
rpc(wCBuildRawTransaction, "wallet"):
signature: string
rpc(wCSendTransactionWithSignature, "wallet"):
signature: string
rpc(wCPairSessionProposal, "wallet"):
sessionProposalJson: string
rpc(wCSaveOrUpdateSession, "wallet"):
sessionJson: string
rpc(wCChangeSessionState, "wallet"):
topic: string
active: bool
rpc(wCSessionRequest, "wallet"):
sessionRequestJson: string
rpc(wCAuthRequest, "wallet"):
address: string
message: string
proc isErrorResponse(rpcResponse: RpcResponse[JsonNode]): bool =
return not rpcResponse.error.isNil
proc prepareResponse(res: var JsonNode, rpcResponse: RpcResponse[JsonNode]): string =
if isErrorResponse(rpcResponse):
return rpcResponse.error.message
if rpcResponse.result.isNil:
return "no result"
res = rpcResponse.result
# TODO #12434: async answer
proc pair*(res: var JsonNode, sessionProposalJson: string): string =
try:
let response = wCPairSessionProposal(sessionProposalJson)
return prepareResponse(res, response)
except Exception as e:
warn e.msg
return e.msg
proc saveOrUpdateSession*(sessionJson: string): bool =
try:
let response = wCSaveOrUpdateSession(sessionJson)
return not isErrorResponse(response)
except Exception as e:
warn e.msg
return false
proc deleteSession*(topic: string): bool =
try:
let response = wCChangeSessionState(topic, false)
return not isErrorResponse(response)
except Exception as e:
warn e.msg
return false
proc sessionRequest*(res: var JsonNode, sessionRequestJson: string): string =
try:
let response = wCSessionRequest(sessionRequestJson)
return prepareResponse(res, response)
except Exception as e:
warn e.msg
return e.msg
proc authRequest*(res: var JsonNode, address: string, authMessage: string): string =
try:
let response = wCAuthRequest(address, authMessage)
return prepareResponse(res, response)
except Exception as e:
warn e.msg
return e.msg

View File

@ -1,7 +1,5 @@
import unittest
import app/modules/main/wallet_section/poc_wallet_connect/helpers
import app/modules/shared_modules/wallet_connect/helpers
suite "wallet connect":
@ -14,27 +12,3 @@ suite "wallet connect":
const feesInfoJson = "{\"maxFees\":\"24528.282681\",\"maxFeePerGas\":1.168013461,\"maxPriorityFeePerGas\":0.036572351,\"gasPrice\":\"1.168013461\"}"
check(convertFeesInfoToHex(feesInfoJson) == """{"maxFeePerGas":"0x459E7895","maxPriorityFeePerGas":"0x22E0CBF"}""")
test "parse deep link url":
const testUrl = "https://status.app/wc?uri=wc%3Aa4f32854428af0f5b6635fb7a3cb2cfe174eaad63b9d10d52ef1c686f8eab862%402%3Frelay-protocol%3Dirn%26symKey%3D4ccbae2b4c81c26fbf4a6acee9de2771705d467de9a1d24c80240e8be59de6be"
let (resOk, wcUri) = extractAndCheckUriParameter(testUrl)
check(resOk)
check(wcUri == "wc:a4f32854428af0f5b6635fb7a3cb2cfe174eaad63b9d10d52ef1c686f8eab862@2?relay-protocol=irn&symKey=4ccbae2b4c81c26fbf4a6acee9de2771705d467de9a1d24c80240e8be59de6be")
test "parse another valid deep link url":
const testUrl = "https://status.app/notwc?uri=lt%3Asomevalue"
let (resOk, wcUri) = extractAndCheckUriParameter(testUrl)
check(not resOk)
check(wcUri == "")
test "parse a WC no-prefix deeplink":
const testUrl = "https://status.app/wc?uri=w4%3Atest"
let (resOk, wcUri) = extractAndCheckUriParameter(testUrl)
check(not resOk)
check(wcUri == "")

View File

@ -24,11 +24,6 @@ import "../controls"
import "../popups"
import "../panels"
/////////////////////////////////////////////////////
// WalletConnect POC - to remove
import AppLayouts.Wallet.views.pocwalletconnect 1.0
/////////////////////////////////////////////////////
SettingsContentBase {
id: root
@ -205,20 +200,6 @@ SettingsContentBase {
}
}
/////////////////////////////////////////////////////
// WalletConnect POC - to remove
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
text: qsTr("POC Wallet Connect")
visible: root.advancedStore.isDebugEnabled
onClicked: {
Global.popupWalletConnect()
}
}
/////////////////////////////////////////////////////
Separator {
width: parent.width
}

View File

@ -1,49 +0,0 @@
/////////////////////////////////////////////////////
// WalletConnect POC - to remove this file
/////////////////////////////////////////////////////
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
ListView {
id: root
signal disconnect(string topic)
spacing: 32
delegate: Item {
implicitWidth: delegateLayout.implicitWidth
implicitHeight: delegateLayout.implicitHeight
RowLayout {
id: delegateLayout
width: root.width
StatusIcon {
icon: model.peerMetadata.icons.length > 0 ? model.peerMetadata.icons[0] : ""
visible: !!icon
}
StatusBaseText {
text: `${model.peerMetadata.name}\n${model.peerMetadata.url}\nTopic: ${SQUtils.Utils.elideText(model.topic, 6, 6)}\nExpire: ${new Date(model.expiry * 1000).toLocaleString()}`
color: model.active ? "green" : "orange"
}
StatusButton {
text: "Disconnect"
visible: model.active
onClicked: {
root.disconnect(model.topic)
}
}
}
}
}

View File

@ -1,36 +0,0 @@
/////////////////////////////////////////////////////
// WalletConnect POC - to remove this file
/////////////////////////////////////////////////////
import QtQuick 2.15
import QtQuick.Controls 2.15
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import utils 1.0
import "../../../Profile/controls"
ListView {
id: root
property ButtonGroup buttonGroup
signal accountSelected(string address)
delegate: WalletAccountDelegate {
implicitWidth: root.width
nextIconVisible: false
account: model
totalCount: ListView.view.count
components: StatusRadioButton {
ButtonGroup.group: root.buttonGroup
onClicked: {
root.accountSelected(model.address)
}
}
}
}

View File

@ -1,159 +0,0 @@
/////////////////////////////////////////////////////
// WalletConnect POC - to remove this file
/////////////////////////////////////////////////////
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
ListView {
id: root
signal disconnect(string topic)
signal ping(string topic)
spacing: 48
delegate: Item {
implicitWidth: delegateLayout.implicitWidth
implicitHeight: delegateLayout.implicitHeight
ListModel {
id: namespacesListModel
}
Component.onCompleted: {
for (var key of Object.keys(model.namespaces)) {
let namespace = model.namespaces[key]
let obj = {
"eip": "",
"chain": "",
"methods": namespace.methods.join(", "),
"events": namespace.events.join(", ")
}
if (namespace.chains.length > 0) {
let data = namespace.chains[0].split(":")
if (data.length === 2) {
obj["eip"] = data[0]
obj["chain"] = data[1]
}
}
namespacesListModel.append(obj)
}
}
ColumnLayout {
id: delegateLayout
width: root.width
spacing: 8
StatusIcon {
icon: model.peer.metadata.icons.length > 0? model.peer.metadata.icons[0] : ""
visible: !!icon
}
StatusBaseText {
text: `Pairing topic:${SQUtils.Utils.elideText(model.pairingTopic, 6, 6)}\n${model.peer.metadata.name}\n${model.peer.metadata.url}`
}
StatusBaseText {
text: `Session topic:${SQUtils.Utils.elideText(model.topic, 6, 6)}\nExpire:${new Date(model.expiry * 1000).toLocaleString()}`
}
Rectangle {
color: "transparent"
border.color: "grey"
border.width: 1
Layout.fillWidth: true
Layout.preferredHeight: allNamespaces.implicitHeight
ColumnLayout {
id: allNamespaces
Repeater {
model: namespacesListModel
delegate: Rectangle {
id: namespaceDelegateRoot
property bool expanded: false
color: "transparent"
border.color: "grey"
border.width: 1
Layout.fillWidth: true
Layout.preferredHeight: namespace.implicitHeight
ColumnLayout {
id: namespace
spacing: 8
RowLayout {
StatusBaseText {
text: `Review ${model.eip} permissions`
}
StatusIcon {
icon: namespaceDelegateRoot.expanded? "chevron-up" : "chevron-down"
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
namespaceDelegateRoot.expanded = !namespaceDelegateRoot.expanded
}
}
}
}
StatusBaseText {
Layout.fillWidth: true
visible: namespaceDelegateRoot.expanded
text: `Chain ${model.chain}`
}
StatusBaseText {
Layout.fillWidth: true
visible: namespaceDelegateRoot.expanded
text: `Methods: ${model.methods}\nEvents: ${model.events}`
}
}
}
}
}
}
RowLayout {
StatusButton {
text: "Disconnect"
onClicked: {
root.disconnect(model.topic)
}
}
StatusButton {
text: "Ping"
onClicked: {
root.ping(model.topic)
}
}
}
}
}
}

View File

@ -1,523 +0,0 @@
/////////////////////////////////////////////////////
// WalletConnect POC - to remove this file
/////////////////////////////////////////////////////
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Popups 0.1
import shared.popups.walletconnect 1.0
Popup {
id: root
implicitWidth: 500
implicitHeight: Math.min(mainLayout.implicitHeight * 2, 700)
required property WalletConnectSDK sdk
parent: Overlay.overlay
anchors.centerIn: parent
clip: true
// wallet_connect.Controller \see wallet_section/wallet_connect/controller.nim
required property var controller
function openWithSessionRequestEvent(sessionRequest) {
d.setStatusText("Approve session request")
d.setDetailsText(JSON.stringify(sessionRequest, null, 2))
d.sessionRequest = sessionRequest
d.state = d.waitingUserResponseToSessionRequest
root.open()
}
function openWithUri(uri) {
pairLinkInput.text = uri
root.open()
if (root.sdk.sdkReady) {
d.setStatusText("Pairing from deeplink ...")
sdk.pair(uri)
} else {
d.pairModalUriWhenReady = uri
}
}
Flickable {
id: flickable
anchors.fill: parent
contentWidth: mainLayout.implicitWidth
contentHeight: mainLayout.implicitHeight
interactive: contentHeight > height || contentWidth > width
ColumnLayout {
id: mainLayout
spacing: 8
StatusBaseText {
text: qsTr("Debugging UX until design is ready")
font.bold: true
}
StatusTabBar {
id: tabBar
Layout.fillWidth: true
StatusTabButton {
width: implicitWidth
text: qsTr("WalletConnect")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Sessions")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Pairings")
}
}
StackLayout {
Layout.fillWidth: true
currentIndex: tabBar.currentIndex
ColumnLayout {
StatusSwitch {
id: testAuthentication
checkable: true
text: qsTr("Test Authentication")
}
StatusInput {
id: pairLinkInput
Layout.fillWidth: true
placeholderText: "Insert pair link"
}
RowLayout {
Layout.fillWidth: true
StatusButton {
text: testAuthentication.checked? "Authentication" : "Pair"
onClicked: {
d.setStatusText("")
d.setDetailsText("")
d.state = ""
accountsModel.clear()
if (testAuthentication.checked) {
d.setStatusText("Authenticating...")
root.sdk.auth(pairLinkInput.text)
return
}
d.setStatusText("Pairing...")
root.sdk.pair(pairLinkInput.text)
}
enabled: pairLinkInput.text.length > 0 && root.sdk.sdkReady
}
StatusButton {
text: "Accept"
onClicked: {
root.sdk.approveSession(d.observedData, d.supportedNamespaces)
}
visible: d.state === d.waitingPairState
}
StatusButton {
text: "Reject"
onClicked: {
root.sdk.rejectSession(d.observedData.id)
}
visible: d.state === d.waitingPairState
}
}
ButtonGroup {
id: selAccBtnGroup
}
POCSelectAccount {
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
model: accountsModel
buttonGroup: selAccBtnGroup
onAccountSelected: {
root.sdk.formatAuthMessage(d.observedData.params.cacaoPayload, address)
}
}
RowLayout {
StatusButton {
text: "Accept"
onClicked: {
if (testAuthentication.checked) {
root.controller.authRequest(d.selectedAddress, d.authMessage, passwordInput.text)
return
}
root.controller.sessionRequest(JSON.stringify(d.sessionRequest), passwordInput.text)
}
visible: d.state === d.waitingUserResponseToSessionRequest ||
d.state === d.waitingUserResponseToAuthRequest
}
StatusButton {
text: "Reject"
onClicked: {
if (testAuthentication.checked) {
root.sdk.authReject(d.observedData.id, d.selectedAddress)
return
}
root.sdk.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, false)
}
visible: d.state === d.waitingUserResponseToSessionRequest ||
d.state === d.waitingUserResponseToAuthRequest
}
StatusInput {
id: passwordInput
text: "1234567890"
placeholderText: "Insert account password"
visible: d.state === d.waitingUserResponseToSessionRequest ||
d.state === d.waitingUserResponseToAuthRequest
}
}
}
ColumnLayout {
Layout.fillWidth: true
POCPairings {
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
model: root.sdk.dappsModel
onDisconnect: function (topic) {
root.sdk.disconnectPairing(topic)
}
}
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 32
}
ColumnLayout {
StatusBaseText {
text: qsTr("Tracking details...")
font.bold: true
}
StatusBaseText {
id: statusText
text: "-"
font.bold: true
}
StatusBaseText {
id: detailsText
text: ""
visible: text.length > 0
color: "#FF00FF"
}
}
}
ScrollBar.vertical: ScrollBar {}
clip: true
}
Connections {
target: root.sdk
function onSdkReadyChanged() {
if (root.sdk.sdkReady && d.pairModalUriWhenReady) {
d.setStatusText("Lazy pairing from deeplink ...")
sdk.pair(d.pairModalUriWhenReady)
d.pairModalUriWhenReady = ""
}
d.checkForPairings()
}
function onSdkInit(success, info) {
d.setDetailsText(info)
if (success) {
d.setStatusText("Ready to pair or auth")
} else {
d.setStatusText("SDK Error", "red")
}
d.state = ""
}
function onSessionProposal(sessionProposal) {
d.setDetailsText(sessionProposal)
d.setStatusText("Pair ID: " + sessionProposal.id + "; Topic: " + sessionProposal.params.pairingTopic)
root.controller.sessionProposal(JSON.stringify(sessionProposal))
}
function onSessionDelete(topic, error) {
if (!!error) {
d.setStatusText(`Error deleting session: ${error}`, "red")
d.setDetailsText("")
return
}
root.controller.deleteSession(topic)
}
function onSessionRequestEvent(sessionRequest) {
d.setStatusText("Approve session request")
d.setDetailsText(JSON.stringify(sessionRequest, null, 2))
d.sessionRequest = sessionRequest
root.state = d.waitingUserResponseToSessionRequest
}
function onApproveSessionResult(session, error) {
d.setDetailsText("")
if (!error) {
d.setStatusText("Pairing OK")
d.state = d.pairedState
root.sdk.getActiveSessions((activeSession) => {
root.controller.saveOrUpdateSession(JSON.stringify(session))
})
} else {
d.setStatusText("Pairing error", "red")
d.state = ""
}
}
function onRejectSessionResult(error) {
d.setDetailsText("")
d.state = ""
if (!error) {
d.setStatusText("Pairing rejected")
} else {
d.setStatusText("Rejecting pairing error", "red")
}
}
function onSessionRequestUserAnswerResult(accept, error) {
if (error) {
d.setStatusText(`Session Request ${accept ? "Accept" : "Reject"} error`, "red")
return
}
d.state = d.pairedState
if (accept) {
d.setStatusText(`Session Request accepted`)
} else {
d.setStatusText(`Session Request rejected`)
}
}
function onSessionProposalExpired() {
d.setStatusText(`Timeout waiting for response. Reusing URI?`, "red")
}
function onStatusChanged(message) {
d.setStatusText(message)
}
function onAuthRequest(request) {
d.observedData = request
d.setStatusText("Select the address you want to sign in with:")
accountsModel.clear()
let walletAccounts = root.controller.getWalletAccounts()
try {
let walletAccountsJsonArr = JSON.parse(walletAccounts)
for (let i = 0; i < walletAccountsJsonArr.length; i++) {
let obj = {
preferredSharingChainIds: ""
}
for (var key in walletAccountsJsonArr[i]) {
obj[key] = walletAccountsJsonArr[i][key]
}
accountsModel.append(obj)
}
} catch (e) {
console.error("error parsing wallet accounts, error: ", e)
d.setStatusText("error parsing walelt accounts", "red")
return
}
}
function onAuthMessageFormated(formatedMessage, address) {
let details = ""
if (!!d.observedData.verifyContext.verified.isScam) {
details = "This website you`re trying to connect is flagged as malicious by multiple security providers.\nApproving may lead to loss of funds."
} else {
if (d.observedData.verifyContext.verified.validation === "UNKNOWN")
details = "Website is Unverified"
else if (d.observedData.verifyContext.verified.validation === "INVALID")
details = "Website is Mismatched"
else
details = "Website is Valid"
}
d.selectedAddress = address
d.authMessage = formatedMessage
d.setDetailsText(`${details}\n\n${formatedMessage}`)
d.state = d.waitingUserResponseToAuthRequest
}
function onAuthRequestUserAnswerResult(accept, error) {
if (error) {
d.setStatusText(`Auth Request ${accept ? "Accept" : "Reject"} error`, "red")
return
}
if (accept) {
d.setStatusText(`Auth Request completed`)
} else {
d.setStatusText(`Auth Request aborted`)
}
}
}
QtObject {
id: d
property bool checkPairings: false
property string selectedAddress: ""
property var observedData: null
property var authMessage: null
property var supportedNamespaces: null
property var sessionRequest: null
property var signedData: null
property string pairModalUriWhenReady: ""
property string state: ""
readonly property string waitingPairState: "waiting_pairing"
readonly property string waitingUserResponseToSessionRequest: "waiting_user_response_to_session_request"
readonly property string waitingUserResponseToAuthRequest: "waiting_user_response_to_auth_request"
readonly property string pairedState: "paired"
function checkForPairings() {
if (!d.checkPairings || !root.sdk.sdkReady) {
return
}
d.checkPairings = false;
root.sdk.getPairings((pairings) => {
for (let i = 0; i < pairings.length; i++) {
if (pairings[i].active) {
// if there is at least a single active pairing we leave wallet connect sdk loaded
return;
}
}
// if there are no active pairings, we unload loaded sdk
root.controller.hasActivePairings = false;
})
}
function setStatusText(message, textColor) {
statusText.text = message
if (textColor === undefined) {
textColor = "green"
}
statusText.color = textColor
}
function setDetailsText(message) {
if (message === undefined) {
message = "undefined"
} else if (typeof message !== "string") {
message = JSON.stringify(message, null, 2)
}
detailsText.text = message
}
}
ListModel {
id: accountsModel
}
Connections {
target: root.controller
function onRespondSessionProposal(sessionProposalJson, supportedNamespacesJson, error) {
if (error) {
d.setStatusText(`Error: ${error}`, "red")
d.setDetailsText("")
return
}
d.setStatusText("Waiting user accept")
d.observedData = JSON.parse(sessionProposalJson)
d.supportedNamespaces = JSON.parse(supportedNamespacesJson)
d.setDetailsText(JSON.stringify(d.supportedNamespaces, null, 2))
d.state = d.waitingPairState
}
function onRespondSessionRequest(sessionRequestJson, signedData, error) {
console.log("WC respondSessionRequest", sessionRequestJson, " signedData", signedData, " error: ", error)
if (error) {
d.setStatusText("Session Request error", "red")
root.sdk.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, true)
return
}
d.sessionRequest = JSON.parse(sessionRequestJson)
d.signedData = signedData
root.sdk.acceptSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, d.signedData)
d.state = d.pairedState
d.setStatusText("Session Request accepted")
d.setDetailsText(d.signedData)
}
function onRespondAuthRequest(signature, error) {
console.log("WC signature", signature, " error: ", error)
if (error) {
d.setStatusText("Session Request error", "red")
root.sdk.authReject(d.observedData.id, d.selectedAddress)
return
}
root.sdk.authApprove(d.observedData, d.selectedAddress, signature)
}
function onCheckPairings() {
d.checkPairings = true
d.checkForPairings()
}
}
}

View File

@ -1,3 +0,0 @@
POCWalletConnect 1.0 POCWalletConnect.qml
POCWalletConnectModal 1.0 POCWalletConnectModal.qml
POCPairings 1.0 POCPairings.qml

View File

@ -112,11 +112,6 @@ QtObject {
// Metrics
signal openMetricsEnablePopupRequested(bool isOnboarding, var cb)
/////////////////////////////////////////////////////
// WalletConnect POC - to remove
signal popupWalletConnect()
/////////////////////////////////////////////////////
signal openAddEditSavedAddressesPopup(var params)
signal openDeleteSavedAddressesPopup(var params)
signal openShowQRPopup(var params)