feat(walletconnect): support for auth request

This commit is contained in:
Sale Djenic 2023-12-06 15:01:25 +01:00 committed by saledjenic
parent b819bdb574
commit 3854920f54
11 changed files with 468 additions and 1950 deletions

View File

@ -141,7 +141,7 @@ proc newModule*(
result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events) result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events)
result.filter = initFilter(result.controller) result.filter = initFilter(result.controller)
result.wcController = wcc.newController(events) result.wcController = wcc.newController(events, walletAccountService)
result.view = newView(result, result.activityController, result.tmpActivityController, result.collectiblesController, result.collectibleDetailsController, result.wcController) result.view = newView(result, result.activityController, result.tmpActivityController, result.collectiblesController, result.collectibleDetailsController, result.wcController)
@ -260,7 +260,7 @@ method load*(self: Module) =
self.onUpdatedKeypairsOperability(args.keypairs) self.onUpdatedKeypairsOperability(args.keypairs)
self.events.on(SIGNAL_LOCAL_PAIRING_STATUS_UPDATE) do(e:Args): self.events.on(SIGNAL_LOCAL_PAIRING_STATUS_UPDATE) do(e:Args):
let data = LocalPairingStatus(e) let data = LocalPairingStatus(e)
self.onLocalPairingStatusUpdate(data) self.onLocalPairingStatusUpdate(data)
self.events.on(SIGNAL_WALLET_ACCOUNT_HIDDEN_UPDATED) do(e: Args): self.events.on(SIGNAL_WALLET_ACCOUNT_HIDDEN_UPDATED) do(e: Args):
self.filter.setFillterAllAddresses() self.filter.setFillterAllAddresses()
self.notifyFilterChanged() self.notifyFilterChanged()

View File

@ -1,4 +1,4 @@
import NimQml, strutils, logging, json, options import NimQml, strutils, logging, json, options, chronicles
import backend/wallet as backend_wallet import backend/wallet as backend_wallet
import backend/wallet_connect as backend_wallet_connect import backend/wallet_connect as backend_wallet_connect
@ -9,25 +9,33 @@ import app/core/signals/types
import app_service/common/utils as common_utils import app_service/common/utils as common_utils
from app_service/service/transaction/dto import PendingTransactionTypeDto 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 app/modules/shared_modules/keycard_popup/io_interface as keycard_shared_module
import constants import constants
import tx_response_dto, helper import tx_response_dto, helper
const UNIQUE_WALLET_CONNECT_MODULE_SIGNING_IDENTIFIER* = "WalletConnect-Signing" const UNIQUE_WC_SESSION_REQUEST_SIGNING_IDENTIFIER* = "WalletConnect-SessionRequestSigning"
const UNIQUE_WC_AUTH_REQUEST_SIGNING_IDENTIFIER* = "WalletConnect-AuthRequestSigning"
logScope:
topics = "wallet-connect"
QtObject: QtObject:
type type
Controller* = ref object of QObject Controller* = ref object of QObject
events: EventEmitter events: EventEmitter
walletAccountService: wallet_account_service.Service
sessionRequestJson: JsonNode sessionRequestJson: JsonNode
txResponseDto: TxResponseDto txResponseDto: TxResponseDto
hasActivePairings: Option[bool] hasActivePairings: Option[bool]
## Forward declarations ## Forward declarations
proc onDataSigned(self: Controller, keyUid: string, path: string, r: string, s: string, v: string, pin: string) proc invalidateData(self: Controller)
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 finishSessionRequest(self: Controller, signature: string)
proc finishAuthRequest(self: Controller, signature: string)
proc setup(self: Controller) = proc setup(self: Controller) =
self.QObject.setup self.QObject.setup
@ -40,24 +48,36 @@ QtObject:
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_DATA_SIGNED) do(e: Args): self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_DATA_SIGNED) do(e: Args):
let args = SharedKeycarModuleArgs(e) let args = SharedKeycarModuleArgs(e)
if args.uniqueIdentifier != UNIQUE_WALLET_CONNECT_MODULE_SIGNING_IDENTIFIER: if args.uniqueIdentifier != UNIQUE_WC_SESSION_REQUEST_SIGNING_IDENTIFIER and
args.uniqueIdentifier != UNIQUE_WC_AUTH_REQUEST_SIGNING_IDENTIFIER:
return return
self.onDataSigned(args.keyUid, args.path, args.r, args.s, args.v, args.pin) self.onDataSigned(args.keyUid, args.path, args.r, args.s, args.v, args.pin, args.uniqueIdentifier)
proc delete*(self: Controller) = proc delete*(self: Controller) =
self.invalidateData()
self.QObject.delete self.QObject.delete
proc newController*(events: EventEmitter): Controller = proc newController*(events: EventEmitter, walletAccountService: wallet_account_service.Service): Controller =
new(result, delete) new(result, delete)
result.events = events result.events = events
result.walletAccountService = walletAccountService
result.setup() result.setup()
proc onDataSigned(self: Controller, keyUid: string, path: string, r: string, s: string, v: string, pin: string) = 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: 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" error "invalid data signed"
return return
let signature = "0x" & r & s & v let signature = "0x" & r & s & v
self.finishSessionRequest(signature) 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"
# supportedNamespaces is a Namespace as defined in status-go: services/wallet/walletconnect/walletconnect.go # supportedNamespaces is a Namespace as defined in status-go: services/wallet/walletconnect/walletconnect.go
proc proposeUserPair*(self: Controller, sessionProposalJson: string, supportedNamespacesJson: string) {.signal.} proc proposeUserPair*(self: Controller, sessionProposalJson: string, supportedNamespacesJson: string) {.signal.}
@ -117,6 +137,9 @@ QtObject:
self.respondSessionRequest($self.sessionRequestJson, txResponseDto.rawTx, false) self.respondSessionRequest($self.sessionRequestJson, txResponseDto.rawTx, false)
proc finishSessionRequest(self: Controller, signature: string) = proc finishSessionRequest(self: Controller, signature: string) =
if signature.len == 0:
self.respondSessionRequest($self.sessionRequestJson, "", true)
return
let requestMethod = getRequestMethod(self.sessionRequestJson) let requestMethod = getRequestMethod(self.sessionRequestJson)
if requestMethod == RequestMethod.SendTransaction: if requestMethod == RequestMethod.SendTransaction:
self.sendTransactionAndRespond(signature) self.sendTransactionAndRespond(signature)
@ -130,24 +153,26 @@ QtObject:
self.respondSessionRequest($self.sessionRequestJson, signature, false) self.respondSessionRequest($self.sessionRequestJson, signature, false)
else: else:
error "Unknown request method" error "Unknown request method"
self.respondSessionRequest($self.sessionRequestJson, "", true)
proc sessionRequest*(self: Controller, sessionRequestJson: string, password: string) {.slot.} = proc sessionRequest*(self: Controller, sessionRequestJson: string, password: string) {.slot.} =
var signature: string
try: try:
self.invalidateData()
self.sessionRequestJson = parseJson(sessionRequestJson) self.sessionRequestJson = parseJson(sessionRequestJson)
var sessionRes: JsonNode var sessionRes: JsonNode
let err = backend_wallet_connect.sessionRequest(sessionRes, sessionRequestJson) let err = backend_wallet_connect.sessionRequest(sessionRes, sessionRequestJson)
if err.len > 0: if err.len > 0:
error "Failed to request a session" raise newException(CatchableError, err)
self.respondSessionRequest(sessionRequestJson, "", true)
return
self.txResponseDto = sessionRes.toTxResponseDto() self.txResponseDto = sessionRes.toTxResponseDto()
if self.txResponseDto.signOnKeycard: if self.txResponseDto.signOnKeycard:
let data = SharedKeycarModuleSigningArgs(uniqueIdentifier: UNIQUE_WALLET_CONNECT_MODULE_SIGNING_IDENTIFIER, let data = SharedKeycarModuleSigningArgs(uniqueIdentifier: UNIQUE_WC_SESSION_REQUEST_SIGNING_IDENTIFIER,
keyUid: self.txResponseDto.keyUid, keyUid: self.txResponseDto.keyUid,
path: self.txResponseDto.addressPath, path: self.txResponseDto.addressPath,
dataToSign: singletonInstance.utils.removeHexPrefix(self.txResponseDto.messageToSign)) dataToSign: singletonInstance.utils.removeHexPrefix(self.txResponseDto.messageToSign))
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA, data) self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_SIGN_DATA, data)
return
else: else:
let hashedPasssword = common_utils.hashPassword(password) let hashedPasssword = common_utils.hashPassword(password)
var signMsgRes: JsonNode var signMsgRes: JsonNode
@ -156,14 +181,56 @@ QtObject:
self.txResponseDto.address, self.txResponseDto.address,
hashedPasssword) hashedPasssword)
if err.len > 0: if err.len > 0:
error "Failed to sign message on statusgo side" raise newException(CatchableError, err)
return signature = signMsgRes.getStr
let signature = signMsgRes.getStr except Exception as e:
self.finishSessionRequest(signature) error "session request", msg=e.msg
except: self.finishSessionRequest(signature)
error "session request action failed"
proc getProjectId*(self: Controller): string {.slot.} = proc getProjectId*(self: Controller): string {.slot.} =
return constants.WALLET_CONNECT_PROJECT_ID return constants.WALLET_CONNECT_PROJECT_ID
QtProperty[string] projectId: QtProperty[string] projectId:
read = getProjectId read = getProjectId
proc getWalletAccounts*(self: Controller): string {.slot.} =
let jsonObj = % self.walletAccountService.getWalletAccounts()
return $jsonObj
proc respondAuthRequest*(self: Controller, signature: string, error: bool) {.signal.}
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

@ -174,7 +174,6 @@ QtObject:
proc cancelCurrentFlow*(self: Service) = proc cancelCurrentFlow*(self: Service) =
if self.busy: if self.busy:
return return
writeStackTrace()
let response = keycard_go.keycardCancelFlow() let response = keycard_go.keycardCancelFlow()
self.currentFlow = KCSFlowType.NoFlow self.currentFlow = KCSFlowType.NoFlow
if self.doLogging: if self.doLogging:

View File

@ -82,3 +82,27 @@ proc `$`*(self: WalletAccountDto): string =
testPreferredChainIds: {self.testPreferredChainIds}, testPreferredChainIds: {self.testPreferredChainIds},
hideFromTotalBalance: {self.hideFromTotalBalance} hideFromTotalBalance: {self.hideFromTotalBalance}
]""" ]"""
proc `%`*(x: WalletAccountDto): JsonNode =
result = newJobject()
result["name"] = % x.name
result["address"] = % x.address
result["mixedcaseAddress"] = % x.mixedcaseAddress
result["keyUid"] = % x.keyUid
result["path"] = % x.path
result["colorId"] = % x.colorId
result["publicKey"] = % x.publicKey
result["isWallet"] = % x.isWallet
result["isChat"] = % x.isChat
result["emoji"] = % x.emoji
result["ens"] = % x.ens
result["assetsLoading"] = % x.assetsLoading
result["hasBalanceCache"] = % x.hasBalanceCache
result["hasMarketValuesCache"] = % x.hasMarketValuesCache
result["removed"] = % x.removed
result["operable"] = % x.operable
result["createdAt"] = % x.createdAt
result["position"] = % x.position
result["prodPreferredChainIds"] = % x.prodPreferredChainIds
result["testPreferredChainIds"] = % x.testPreferredChainIds
result["hideFromTotalBalance"] = % x.hideFromTotalBalance

View File

@ -39,6 +39,10 @@ rpc(wCHasActivePairings, "wallet"):
rpc(wCSessionRequest, "wallet"): rpc(wCSessionRequest, "wallet"):
sessionRequestJson: string sessionRequestJson: string
rpc(wCAuthRequest, "wallet"):
address: string
message: string
proc isErrorResponse(rpcResponse: RpcResponse[JsonNode]): bool = proc isErrorResponse(rpcResponse: RpcResponse[JsonNode]): bool =
return not rpcResponse.error.isNil return not rpcResponse.error.isNil
@ -92,3 +96,11 @@ proc sessionRequest*(res: var JsonNode, sessionRequestJson: string): string =
except Exception as e: except Exception as e:
warn e.msg warn e.msg
return 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

@ -0,0 +1,32 @@
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

@ -49,6 +49,12 @@ Popup {
text: qsTr("Debugging UX until design is ready") text: qsTr("Debugging UX until design is ready")
} }
StatusSwitch {
id: testAuthentication
checkable: true
text: qsTr("Test Authentication")
}
StatusInput { StatusInput {
id: pairLinkInput id: pairLinkInput
@ -61,36 +67,37 @@ Popup {
Layout.fillWidth: true Layout.fillWidth: true
StatusButton { StatusButton {
text: "Pair" text: testAuthentication.checked? "Authentication" : "Pair"
onClicked: { onClicked: {
if (testAuthentication.checked) {
d.setStatusText("")
d.setDetailsText("")
d.state = ""
accountsModel.clear()
statusText.text = "Authenticating..."
root.sdk.auth(pairLinkInput.text)
return
}
statusText.text = "Pairing..." statusText.text = "Pairing..."
sdk.pair(pairLinkInput.text) root.sdk.pair(pairLinkInput.text)
} }
enabled: pairLinkInput.text.length > 0 && sdk.sdkReady enabled: pairLinkInput.text.length > 0 && root.sdk.sdkReady
}
StatusButton {
text: "Auth"
onClicked: {
statusText.text = "Authenticating..."
sdk.auth()
}
enabled: false && pairLinkInput.text.length > 0 && sdk.sdkReady
} }
StatusButton { StatusButton {
text: "Accept" text: "Accept"
onClicked: { onClicked: {
sdk.approvePairSession(d.sessionProposal, d.supportedNamespaces) root.sdk.approvePairSession(d.observedData, d.supportedNamespaces)
// Will trigger an onPairAcceptedResult if successful
} }
visible: d.state === d.waitingPairState visible: d.state === d.waitingPairState
} }
StatusButton { StatusButton {
text: "Reject" text: "Reject"
onClicked: { onClicked: {
sdk.rejectPairSession(d.sessionProposal.id) root.sdk.rejectPairSession(d.observedData.id)
} }
visible: d.state === d.waitingPairState visible: d.state === d.waitingPairState
} }
@ -103,7 +110,7 @@ Popup {
} }
StatusBaseText { StatusBaseText {
text: "Pairings" text: "Pairings"
visible: sdk.pairingsModel.count > 0 visible: root.sdk.pairingsModel.count > 0
} }
Pairings { Pairings {
@ -112,10 +119,29 @@ Popup {
Layout.preferredHeight: contentHeight Layout.preferredHeight: contentHeight
Layout.maximumHeight: 300 Layout.maximumHeight: 300
model: sdk.pairingsModel model: root.sdk.pairingsModel
onDisconnect: function (topic) { onDisconnect: function (topic) {
sdk.disconnectPairing(topic) root.sdk.disconnectPairing(topic)
}
}
ButtonGroup {
id: selAccBtnGroup
}
SelectAccount {
Layout.fillWidth: true
Layout.minimumWidth: count > 0 ? 400 : 0
Layout.preferredHeight: contentHeight
Layout.maximumHeight: 300
model: accountsModel
buttonGroup: selAccBtnGroup
onAccountSelected: {
root.sdk.formatAuthMessage(d.observedData.params.cacaoPayload, address)
} }
} }
@ -131,23 +157,36 @@ Popup {
StatusButton { StatusButton {
text: "Accept" text: "Accept"
onClicked: { onClicked: {
if (testAuthentication.checked) {
root.controller.authRequest(d.selectedAddress, d.authMessage, passwordInput.text)
return
}
root.controller.sessionRequest(JSON.stringify(d.sessionRequest), passwordInput.text) root.controller.sessionRequest(JSON.stringify(d.sessionRequest), passwordInput.text)
} }
visible: d.state === d.waitingUserResponseToSessionRequest visible: d.state === d.waitingUserResponseToSessionRequest ||
d.state === d.waitingUserResponseToAuthRequest
} }
StatusButton { StatusButton {
text: "Reject" text: "Reject"
onClicked: { onClicked: {
sdk.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, false) 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 visible: d.state === d.waitingUserResponseToSessionRequest ||
d.state === d.waitingUserResponseToAuthRequest
} }
StatusInput { StatusInput {
id: passwordInput id: passwordInput
text: "1234567890" text: "1234567890"
placeholderText: "Insert account password" placeholderText: "Insert account password"
visible: d.state === d.waitingUserResponseToSessionRequest visible: d.state === d.waitingUserResponseToSessionRequest ||
d.state === d.waitingUserResponseToAuthRequest
} }
} }
@ -177,15 +216,10 @@ Popup {
} }
} }
function onPairSessionProposal(success, sessionProposal) { function onPairSessionProposal(sessionProposal) {
d.setDetailsText(sessionProposal) d.setDetailsText(sessionProposal)
if (success) { d.setStatusText("Pair ID: " + sessionProposal.id + "; Topic: " + sessionProposal.params.pairingTopic)
d.setStatusText("Pair ID: " + sessionProposal.id + "; Topic: " + sessionProposal.params.pairingTopic) root.controller.pairSessionProposal(JSON.stringify(sessionProposal))
root.controller.pairSessionProposal(JSON.stringify(sessionProposal))
// Expecting signal onProposeUserPair(..., true, ...) from controller
} else {
d.setStatusText("Pairing error", "red")
}
} }
function onPairAcceptedResult(sessionProposal, success, result) { function onPairAcceptedResult(sessionProposal, success, result) {
@ -230,12 +264,75 @@ Popup {
function onStatusChanged(message) { function onStatusChanged(message) {
statusText.text = message statusText.text = 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 onAuthSignMessage(message, 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 = message
d.setDetailsText(`${details}\n\n${message}`)
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 { QtObject {
id: d id: d
property var sessionProposal: null property string selectedAddress: ""
property var observedData: null
property var authMessage: null
property var supportedNamespaces: null property var supportedNamespaces: null
property var sessionRequest: null property var sessionRequest: null
@ -245,6 +342,7 @@ Popup {
readonly property string sdkReadyState: "sdk_ready" readonly property string sdkReadyState: "sdk_ready"
readonly property string waitingPairState: "waiting_pairing" readonly property string waitingPairState: "waiting_pairing"
readonly property string waitingUserResponseToSessionRequest: "waiting_user_response_to_session_request" 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" readonly property string pairedState: "paired"
function setStatusText(message, textColor) { function setStatusText(message, textColor) {
@ -264,13 +362,17 @@ Popup {
} }
} }
ListModel {
id: accountsModel
}
Connections { Connections {
target: root.controller target: root.controller
function onProposeUserPair(sessionProposalJson, supportedNamespacesJson) { function onProposeUserPair(sessionProposalJson, supportedNamespacesJson) {
d.setStatusText("Waiting user accept") d.setStatusText("Waiting user accept")
d.sessionProposal = JSON.parse(sessionProposalJson) d.observedData = JSON.parse(sessionProposalJson)
d.supportedNamespaces = JSON.parse(supportedNamespacesJson) d.supportedNamespaces = JSON.parse(supportedNamespacesJson)
d.setDetailsText(JSON.stringify(d.supportedNamespaces, null, 2)) d.setDetailsText(JSON.stringify(d.supportedNamespaces, null, 2))
@ -282,19 +384,30 @@ Popup {
console.log("WC respondSessionRequest", sessionRequestJson, " signedData", signedData, " error: ", error) console.log("WC respondSessionRequest", sessionRequestJson, " signedData", signedData, " error: ", error)
if (error) { if (error) {
d.setStatusText("Session Request error", "red") d.setStatusText("Session Request error", "red")
sdk.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, true) root.sdk.rejectSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, true)
return return
} }
d.sessionRequest = JSON.parse(sessionRequestJson) d.sessionRequest = JSON.parse(sessionRequestJson)
d.signedData = signedData d.signedData = signedData
sdk.acceptSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, d.signedData) root.sdk.acceptSessionRequest(d.sessionRequest.topic, d.sessionRequest.id, d.signedData)
d.state = d.pairedState d.state = d.pairedState
d.setStatusText("Session Request accepted") d.setStatusText("Session Request accepted")
d.setDetailsText(d.signedData) 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)
}
} }
} }

View File

@ -24,32 +24,32 @@ Item {
signal statusChanged(string message) signal statusChanged(string message)
signal sdkInit(bool success, var result) signal sdkInit(bool success, var result)
signal pairSessionProposal(bool success, var sessionProposal) signal pairSessionProposal(var sessionProposal)
signal pairSessionProposalExpired() signal pairSessionProposalExpired()
signal pairAcceptedResult(var sessionProposal, bool success, var sessionType) signal pairAcceptedResult(var sessionProposal, bool success, var sessionType)
signal pairRejectedResult(bool success, var result) signal pairRejectedResult(bool success, var result)
signal sessionRequestEvent(var sessionRequest) signal sessionRequestEvent(var sessionRequest)
signal sessionRequestUserAnswerResult(bool accept, string error) signal sessionRequestUserAnswerResult(bool accept, string error)
signal authRequest(var request)
signal authSignMessage(string message, string address)
signal authRequestUserAnswerResult(bool accept, string error)
signal sessionDelete(var deletePayload) signal sessionDelete(var deletePayload)
function pair(pairLink) function pair(pairLink) {
{
wcCalls.pair(pairLink) wcCalls.pair(pairLink)
} }
function disconnectPairing(topic) function disconnectPairing(topic) {
{
wcCalls.disconnectPairing(topic) wcCalls.disconnectPairing(topic)
} }
function approvePairSession(sessionProposal, supportedNamespaces) function approvePairSession(sessionProposal, supportedNamespaces) {
{
wcCalls.approvePairSession(sessionProposal, supportedNamespaces) wcCalls.approvePairSession(sessionProposal, supportedNamespaces)
} }
function rejectPairSession(id) function rejectPairSession(id) {
{
wcCalls.rejectPairSession(id) wcCalls.rejectPairSession(id)
} }
@ -61,6 +61,22 @@ Item {
wcCalls.rejectSessionRequest(topic, id, error) wcCalls.rejectSessionRequest(topic, id, error)
} }
function auth(authLink) {
wcCalls.auth(authLink)
}
function formatAuthMessage(cacaoPayload, address) {
wcCalls.formatAuthMessage(cacaoPayload, address)
}
function authApprove(authRequest, address, signature) {
wcCalls.authApprove(authRequest, address, signature)
}
function authReject(id, address) {
wcCalls.authReject(id, address)
}
QtObject { QtObject {
id: d id: d
@ -275,6 +291,74 @@ Item {
d.resetPairingsModel() d.resetPairingsModel()
}) })
} }
function auth(authLink) {
console.debug(`WC WalletConnectSDK.wcCall.auth; authLink: ${authLink}`)
d.engine.runJavaScript(`wc.auth("${authLink}")`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.auth; response: ${JSON.stringify(result, null, 2)}`)
if (result) {
if (!!result.error) {
console.error("auth: ", result.error)
return
}
}
})
}
function formatAuthMessage(cacaoPayload, address) {
console.debug(`WC WalletConnectSDK.wcCall.auth; cacaoPayload: ${JSON.stringify(cacaoPayload)}, address: ${address}`)
d.engine.runJavaScript(`wc.formatAuthMessage(${JSON.stringify(cacaoPayload)}, "${address}")`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.formatAuthMessage; response: ${JSON.stringify(result, null, 2)}`)
if (result) {
if (!!result.error) {
console.error("formatAuthMessage: ", result.error)
return
}
}
root.authSignMessage(result.result, address)
})
}
function authApprove(authRequest, address, signature) {
console.debug(`WC WalletConnectSDK.wcCall.authApprove; authRequest: ${JSON.stringify(authRequest)}, address: ${address}, signature: ${signature}`)
d.engine.runJavaScript(`wc.approveAuth(${JSON.stringify(authRequest)}, "${address}", "${signature}")`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.approveAuth; response: ${JSON.stringify(result, null, 2)}`)
if (result) {
if (!!result.error)
{
console.error("approveAuth: ", result.error)
root.authRequestUserAnswerResult(true, result.error)
return
}
root.authRequestUserAnswerResult(true, result.error)
}
})
}
function authReject(id, address) {
console.debug(`WC WalletConnectSDK.wcCall.authReject; id: ${id}, address: ${address}`)
d.engine.runJavaScript(`wc.rejectAuth(${id}, "${address}")`, function(result) {
console.debug(`WC WalletConnectSDK.wcCall.rejectAuth; response: ${JSON.stringify(result, null, 2)}`)
if (result) {
if (!!result.error)
{
console.error("rejectAuth: ", result.error)
root.authRequestUserAnswerResult(false, result.error)
return
}
root.authRequestUserAnswerResult(false, result.error)
}
})
}
} }
QtObject { QtObject {
@ -303,7 +387,7 @@ Item {
function onSessionProposal(details) function onSessionProposal(details)
{ {
console.debug(`WC WalletConnectSDK.onSessionProposal; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC WalletConnectSDK.onSessionProposal; details: ${JSON.stringify(details, null, 2)}`)
root.pairSessionProposal(true, details) root.pairSessionProposal(details)
} }
function onSessionUpdate(details) function onSessionUpdate(details)
@ -353,6 +437,12 @@ Item {
console.debug(`WC WalletConnectSDK.onProposalExpire; details: ${JSON.stringify(details, null, 2)}`) console.debug(`WC WalletConnectSDK.onProposalExpire; details: ${JSON.stringify(details, null, 2)}`)
root.pairSessionProposalExpired() root.pairSessionProposalExpired()
} }
function onAuthRequest(details)
{
console.debug(`WC WalletConnectSDK.onAuthRequest; details: ${JSON.stringify(details, null, 2)}`)
root.authRequest(details)
}
} }
ListModel { ListModel {

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,7 @@
import { Core } from "@walletconnect/core"; import { Core } from "@walletconnect/core";
import { Web3Wallet } from "@walletconnect/web3wallet"; import { Web3Wallet } from "@walletconnect/web3wallet";
// Disabled for now to debug the issue with wrong pairing topic import AuthClient from '@walletconnect/auth-client'
//import AuthClient from '@walletconnect/auth-client'
// import the builder util // import the builder util
import { buildApprovedNamespaces, getSdkError } from "@walletconnect/utils"; import { buildApprovedNamespaces, getSdkError } from "@walletconnect/utils";
@ -49,10 +48,10 @@ window.wc = {
}, },
}); });
//window.wc.authClient = await AuthClient.init({ window.wc.authClient = await AuthClient.init({
// projectId: projectId, projectId: projectId,
// metadata: window.wc.web3wallet.metadata, metadata: window.wc.web3wallet.metadata,
//}); });
// connect session responses https://specs.walletconnect.com/2.0/specs/clients/sign/session-events#events // connect session responses https://specs.walletconnect.com/2.0/specs/clients/sign/session-events#events
window.wc.web3wallet.on("session_proposal", async (details) => { window.wc.web3wallet.on("session_proposal", async (details) => {
@ -95,6 +94,10 @@ window.wc = {
wc.statusObject.onProposalExpire(details) wc.statusObject.onProposalExpire(details)
}); });
window.wc.authClient.on("auth_request", async (details) => {
wc.statusObject.onAuthRequest(details)
});
wc.statusObject.sdkInitialized(""); wc.statusObject.sdkInitialized("");
resolve(""); resolve("");
}); });
@ -130,7 +133,6 @@ window.wc = {
supportedNamespaces: supportedNamespaces, supportedNamespaces: supportedNamespaces,
}); });
wc.statusObject.bubbleConsoleMessage("debug", `web3wallet.approveSession id: ${id} ${JSON.stringify(approvedNamespaces, null, 2)}`)
return { return {
result: window.wc.web3wallet.approveSession({ result: window.wc.web3wallet.approveSession({
id, id,
@ -149,45 +151,66 @@ window.wc = {
}; };
}, },
// auth: function (uri) { auth: function (uri) {
// return { try {
// result: window.wc.authClient.core.pairing.pair({ uri }), return {
// error: "" result: window.wc.authClient.core.pairing.pair({ uri }),
// }; error: ""
// }, };
} catch (e) {
return {
result: "",
error: e
};
}
},
// approveAuth: function (authProposal) { formatAuthMessage: function (cacaoPayload, address) {
// const { id, params } = authProposal; const iss = `did:pkh:eip155:1:${address}`;
// // TODO: source users address return {
// const iss = `did:pkh:eip155:1:${"0x0123456789"}`; result: window.wc.authClient.formatMessage(cacaoPayload, iss),
error: ""
};
},
// // format the cacao payload with the users address approveAuth: function (authRequest, address, signature) {
// const message = window.wc.authClient.formatMessage(params.cacaoPayload, iss); const { id, params } = authRequest;
// // TODO: signature const iss = `did:pkh:eip155:1:${address}`;
// const signature = "0x123456789"
// return { const message = window.wc.authClient.formatMessage(params.cacaoPayload, iss);
// result: window.wc.authClient.respond(
// {
// id: id,
// signature: {
// s: signature,
// t: "eip191",
// },
// },
// iss),
// error: ""
// };
// },
// rejectAuth: function (id) { return {
// return { result: window.wc.authClient.respond(
// result: window.wc.authClient.reject(id), {
// error: "" id: id,
// }; signature: {
// }, s: signature,
t: "eip191",
},
},
iss),
error: ""
};
},
rejectAuth: function (id, address) {
const iss = `did:pkh:eip155:1:${address}`;
return {
result: window.wc.authClient.respond(
{
id: id,
error: {
code: 4001,
message: 'Auth request has been rejected'
},
},
iss),
error: ""
};
},
respondSessionRequest: function (topic, id, signature) { respondSessionRequest: function (topic, id, signature) {
const response = formatJsonRpcResult(id, signature) const response = formatJsonRpcResult(id, signature)
@ -200,7 +223,6 @@ window.wc = {
}; };
} catch (e) { } catch (e) {
wc.statusObject.bubbleConsoleMessage("error", `respondSessionRequest error: ${JSON.stringify(e, null, 2)}`)
return { return {
result: "", result: "",
error: e error: e

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 04c533b8d5f1e0249b9edd38ef1304b9e9ef81de Subproject commit 12ba1bdf6987d767cd56bbeb011607659f39d30d