parent
20620e04cf
commit
da622348f6
|
@ -391,9 +391,6 @@ proc checkForStoringPasswordToKeychain(self: AppController) =
|
||||||
else:
|
else:
|
||||||
self.keychainService.storeData(account.keyUid, self.startupModule.getPin())
|
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) =
|
proc startupDidLoad*(self: AppController) =
|
||||||
singletonInstance.engine.setRootContextProperty("localAppSettings", self.localAppSettingsVariant)
|
singletonInstance.engine.setRootContextProperty("localAppSettings", self.localAppSettingsVariant)
|
||||||
singletonInstance.engine.setRootContextProperty("localAccountSettings", self.localAccountSettingsVariant)
|
singletonInstance.engine.setRootContextProperty("localAccountSettings", self.localAccountSettingsVariant)
|
||||||
|
@ -410,7 +407,6 @@ proc mainDidLoad*(self: AppController) =
|
||||||
self.applyNecessaryActionsAfterLoggingIn()
|
self.applyNecessaryActionsAfterLoggingIn()
|
||||||
self.startupModule.moveToAppState()
|
self.startupModule.moveToAppState()
|
||||||
self.checkForStoringPasswordToKeychain()
|
self.checkForStoringPasswordToKeychain()
|
||||||
self.chekForWalletConnectPairings()
|
|
||||||
|
|
||||||
proc start*(self: AppController) =
|
proc start*(self: AppController) =
|
||||||
self.keycardService.init()
|
self.keycardService.init()
|
||||||
|
|
|
@ -48,6 +48,3 @@ type
|
||||||
addresses*: seq[string]
|
addresses*: seq[string]
|
||||||
|
|
||||||
const MARK_WALLET_ADDRESSES_AS_SHOWN* = "markWalletAddressesAsShown"
|
const MARK_WALLET_ADDRESSES_AS_SHOWN* = "markWalletAddressesAsShown"
|
||||||
|
|
||||||
|
|
||||||
const WALLET_CONNECT_CHECK_PAIRINGS* = "walletConnectCheckPairings"
|
|
|
@ -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)
|
|
|
@ -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, "")
|
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -1,7 +1,5 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import app/modules/main/wallet_section/poc_wallet_connect/helpers
|
|
||||||
|
|
||||||
import app/modules/shared_modules/wallet_connect/helpers
|
import app/modules/shared_modules/wallet_connect/helpers
|
||||||
|
|
||||||
suite "wallet connect":
|
suite "wallet connect":
|
||||||
|
@ -14,27 +12,3 @@ suite "wallet connect":
|
||||||
const feesInfoJson = "{\"maxFees\":\"24528.282681\",\"maxFeePerGas\":1.168013461,\"maxPriorityFeePerGas\":0.036572351,\"gasPrice\":\"1.168013461\"}"
|
const feesInfoJson = "{\"maxFees\":\"24528.282681\",\"maxFeePerGas\":1.168013461,\"maxPriorityFeePerGas\":0.036572351,\"gasPrice\":\"1.168013461\"}"
|
||||||
|
|
||||||
check(convertFeesInfoToHex(feesInfoJson) == """{"maxFeePerGas":"0x459E7895","maxPriorityFeePerGas":"0x22E0CBF"}""")
|
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 == "")
|
|
||||||
|
|
|
@ -24,11 +24,6 @@ import "../controls"
|
||||||
import "../popups"
|
import "../popups"
|
||||||
import "../panels"
|
import "../panels"
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
// WalletConnect POC - to remove
|
|
||||||
import AppLayouts.Wallet.views.pocwalletconnect 1.0
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
SettingsContentBase {
|
SettingsContentBase {
|
||||||
id: root
|
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 {
|
Separator {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
POCWalletConnect 1.0 POCWalletConnect.qml
|
|
||||||
POCWalletConnectModal 1.0 POCWalletConnectModal.qml
|
|
||||||
POCPairings 1.0 POCPairings.qml
|
|
|
@ -112,11 +112,6 @@ QtObject {
|
||||||
// Metrics
|
// Metrics
|
||||||
signal openMetricsEnablePopupRequested(bool isOnboarding, var cb)
|
signal openMetricsEnablePopupRequested(bool isOnboarding, var cb)
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
// WalletConnect POC - to remove
|
|
||||||
signal popupWalletConnect()
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
signal openAddEditSavedAddressesPopup(var params)
|
signal openAddEditSavedAddressesPopup(var params)
|
||||||
signal openDeleteSavedAddressesPopup(var params)
|
signal openDeleteSavedAddressesPopup(var params)
|
||||||
signal openShowQRPopup(var params)
|
signal openShowQRPopup(var params)
|
||||||
|
|
Loading…
Reference in New Issue