refactor provider view to not depend on libstatus
This commit is contained in:
parent
1b7799944e
commit
ca990796a0
|
@ -96,6 +96,10 @@ Typically this means the method has no return type and so `result =` isn't neces
|
|||
|
||||
This usually means a method that has no return type is being discarded
|
||||
|
||||
### required type for <variable>: <Type> but expression '<variable>' is of type: <Type>
|
||||
|
||||
This tpyically means there is an import missing
|
||||
|
||||
## Warnings
|
||||
|
||||
### QML anchor warnings
|
||||
|
|
|
@ -1,19 +1,12 @@
|
|||
import NimQml
|
||||
import ../../status/[status, ens, chat/stickers, wallet, settings]
|
||||
import ../../status/[status, ens, chat/stickers, wallet, settings, provider]
|
||||
import ../../status/types
|
||||
import ../../status/libstatus/accounts
|
||||
import ../../status/libstatus/core
|
||||
import ../../status/libstatus/settings as status_settings
|
||||
import json, json_serialization, sets, strutils
|
||||
import chronicles
|
||||
import nbaser
|
||||
import stew/byteutils
|
||||
from base32 import nil
|
||||
|
||||
const AUTH_METHODS = toHashSet(["eth_accounts", "eth_coinbase", "eth_sendTransaction", "eth_sign", "keycard_signTypedData", "eth_signTypedData", "eth_signTypedData_v3", "personal_sign", "personal_ecRecover"])
|
||||
const SIGN_METHODS = toHashSet(["eth_sign", "personal_sign", "eth_signTypedData", "eth_signTypedData_v3"])
|
||||
const ACC_METHODS = toHashSet(["eth_accounts", "eth_coinbase"])
|
||||
|
||||
const HTTPS_SCHEME = "https"
|
||||
const IPFS_GATEWAY = ".infura.status.im"
|
||||
const SWARM_GATEWAY = "swarm-gateways.net"
|
||||
|
@ -23,65 +16,6 @@ const base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|||
logScope:
|
||||
topics = "provider-view"
|
||||
|
||||
type
|
||||
RequestTypes {.pure.} = enum
|
||||
Web3SendAsyncReadOnly = "web3-send-async-read-only",
|
||||
HistoryStateChanged = "history-state-changed",
|
||||
APIRequest = "api-request"
|
||||
Unknown = "unknown"
|
||||
|
||||
ResponseTypes {.pure.} = enum
|
||||
Web3SendAsyncCallback = "web3-send-async-callback",
|
||||
APIResponse = "api-response",
|
||||
Web3ResponseError = "web3-response-error"
|
||||
|
||||
type
|
||||
Payload = ref object
|
||||
id: JsonNode
|
||||
rpcMethod: string
|
||||
|
||||
Web3SendAsyncReadOnly = ref object
|
||||
messageId: JsonNode
|
||||
payload: Payload
|
||||
request: string
|
||||
hostname: string
|
||||
|
||||
APIRequest = ref object
|
||||
isAllowed: bool
|
||||
messageId: JsonNode
|
||||
permission: Permission
|
||||
hostname: string
|
||||
|
||||
proc requestType(message: string): RequestTypes =
|
||||
let data = message.parseJson
|
||||
result = RequestTypes.Unknown
|
||||
try:
|
||||
result = parseEnum[RequestTypes](data["type"].getStr())
|
||||
except:
|
||||
warn "Unknown request type received", value=data["permission"].getStr()
|
||||
|
||||
proc toWeb3SendAsyncReadOnly(message: string): Web3SendAsyncReadOnly =
|
||||
let data = message.parseJson
|
||||
result = Web3SendAsyncReadOnly(
|
||||
messageId: data["messageId"],
|
||||
request: $data["payload"],
|
||||
hostname: data{"hostname"}.getStr(),
|
||||
payload: Payload(
|
||||
id: data["payload"]{"id"},
|
||||
rpcMethod: data["payload"]["method"].getStr()
|
||||
)
|
||||
)
|
||||
|
||||
proc toAPIRequest(message: string): APIRequest =
|
||||
let data = message.parseJson
|
||||
|
||||
result = APIRequest(
|
||||
messageId: data["messageId"],
|
||||
isAllowed: data{"isAllowed"}.getBool(),
|
||||
permission: data["permission"].getStr().toPermission(),
|
||||
hostname: data{"hostname"}.getStr()
|
||||
)
|
||||
|
||||
QtObject:
|
||||
type Web3ProviderView* = ref object of QObject
|
||||
status*: Status
|
||||
|
@ -100,153 +34,6 @@ QtObject:
|
|||
result.dappsAddress = ""
|
||||
result.setup
|
||||
|
||||
proc process(data: Web3SendAsyncReadOnly, status: Status): string =
|
||||
if AUTH_METHODS.contains(data.payload.rpcMethod) and not status.permissions.hasPermission(data.hostname, Permission.Web3):
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": {
|
||||
"code": 4100
|
||||
}
|
||||
}
|
||||
|
||||
if data.payload.rpcMethod == "eth_sendTransaction":
|
||||
try:
|
||||
let request = data.request.parseJson
|
||||
let fromAddress = request["params"][0]["from"].getStr()
|
||||
let to = request["params"][0]{"to"}.getStr()
|
||||
let value = if (request["params"][0]["value"] != nil):
|
||||
request["params"][0]["value"].getStr()
|
||||
else:
|
||||
"0"
|
||||
let password = request["password"].getStr()
|
||||
let selectedGasLimit = request["selectedGasLimit"].getStr()
|
||||
let selectedGasPrice = request["selectedGasPrice"].getStr()
|
||||
let txData = if (request["params"][0].hasKey("data") and request["params"][0]["data"].kind != JNull):
|
||||
request["params"][0]["data"].getStr()
|
||||
else:
|
||||
""
|
||||
|
||||
var success: bool
|
||||
# TODO make this async
|
||||
let response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success, txData)
|
||||
let errorMessage = if not success:
|
||||
if response == "":
|
||||
"web3-response-error"
|
||||
else:
|
||||
response
|
||||
else:
|
||||
""
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": errorMessage,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": data.payload.id,
|
||||
"result": if (success): response else: ""
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
error "Error sending the transaction", msg = e.msg
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": {
|
||||
"code": 4100,
|
||||
"message": e.msg
|
||||
}
|
||||
}
|
||||
|
||||
if SIGN_METHODS.contains(data.payload.rpcMethod):
|
||||
try:
|
||||
let request = data.request.parseJson
|
||||
var params = request["params"]
|
||||
let password = hashPassword(request["password"].getStr())
|
||||
let dappAddress = status_settings.getSetting[string](Setting.DappsAddress)
|
||||
var rpcResult = "{}"
|
||||
|
||||
case data.payload.rpcMethod:
|
||||
of "eth_signTypedData", "eth_signTypedData_v3":
|
||||
rpcResult = signTypedData(params[1].getStr(), dappAddress, password)
|
||||
else:
|
||||
rpcResult = signMessage($ %* {
|
||||
"data": params[0].getStr(),
|
||||
"password": password,
|
||||
"account": dappAddress
|
||||
})
|
||||
|
||||
let jsonRpcResult = rpcResult.parseJson
|
||||
let success: bool = not jsonRpcResult.hasKey("error")
|
||||
let errorMessage = if success: "" else: jsonRpcResult["error"]{"message"}.getStr()
|
||||
let response = if success: jsonRpcResult["result"].getStr() else: ""
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": errorMessage,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": if data.payload.id == nil: newJNull() else: data.payload.id,
|
||||
"result": if (success): response else: ""
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
error "Error signing message", msg = e.msg
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": {
|
||||
"code": 4100,
|
||||
"message": e.msg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ACC_METHODS.contains(data.payload.rpcMethod):
|
||||
let dappAddress = status_settings.getSetting[string](Setting.DappsAddress)
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": data.payload.id,
|
||||
"result": if data.payload.rpcMethod == "eth_coinbase": newJString(dappAddress) else: %*[dappAddress]
|
||||
}
|
||||
}
|
||||
|
||||
let rpcResult = callRPC(data.request)
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": (if rpcResult == "": newJString("web3-response-error") else: newJNull()),
|
||||
"result": rpcResult.parseJson
|
||||
}
|
||||
|
||||
proc process*(data: APIRequest, status: Status): string =
|
||||
var value:JsonNode = case data.permission
|
||||
of Permission.Web3: %* [status_settings.getSetting[string](Setting.DappsAddress, "0x0000000000000000000000000000000000000000")]
|
||||
of Permission.ContactCode: %* status_settings.getSetting[string](Setting.PublicKey, "0x0")
|
||||
of Permission.Unknown: newJNull()
|
||||
|
||||
let isAllowed = data.isAllowed and data.permission != Permission.Unknown
|
||||
|
||||
info "API request received", host=data.hostname, value=data.permission, isAllowed
|
||||
|
||||
if isAllowed: status.permissions.addPermission(data.hostname, data.permission)
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.APIResponse,
|
||||
"isAllowed": isAllowed,
|
||||
"permission": data.permission,
|
||||
"messageId": data.messageId,
|
||||
"data": value
|
||||
}
|
||||
|
||||
proc hasPermission*(self: Web3ProviderView, hostname: string, permission: string): bool {.slot.} =
|
||||
result = self.status.permissions.hasPermission(hostname, permission.toPermission())
|
||||
|
||||
|
@ -254,13 +41,10 @@ QtObject:
|
|||
self.status.permissions.revoke("web3".toPermission())
|
||||
|
||||
proc postMessage*(self: Web3ProviderView, message: string): string {.slot.} =
|
||||
case message.requestType():
|
||||
of RequestTypes.Web3SendAsyncReadOnly: message.toWeb3SendAsyncReadOnly().process(self.status)
|
||||
of RequestTypes.HistoryStateChanged: """{"type":"TODO-IMPLEMENT-THIS"}""" ############# TODO:
|
||||
of RequestTypes.APIRequest: message.toAPIRequest().process(self.status)
|
||||
else: """{"type":"TODO-IMPLEMENT-THIS"}""" ##################### TODO:
|
||||
result = self.status.provider.postMessage(message)
|
||||
|
||||
proc getNetworkId*(self: Web3ProviderView): int {.slot.} = getCurrentNetworkDetails().config.networkId
|
||||
proc getNetworkId*(self: Web3ProviderView): int {.slot.} =
|
||||
self.status.settings.getCurrentNetworkDetails().config.networkId
|
||||
|
||||
QtProperty[int] networkId:
|
||||
read = getNetworkId
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
import ens, chat/stickers, wallet, settings, permissions
|
||||
import ../eventemitter
|
||||
import types
|
||||
import libstatus/accounts
|
||||
import libstatus/core
|
||||
import libstatus/settings as status_settings
|
||||
import json, json_serialization, sets, strutils
|
||||
import chronicles
|
||||
import nbaser
|
||||
import stew/byteutils
|
||||
from base32 import nil
|
||||
|
||||
logScope:
|
||||
topics = "provider-model"
|
||||
|
||||
type
|
||||
RequestTypes {.pure.} = enum
|
||||
Web3SendAsyncReadOnly = "web3-send-async-read-only",
|
||||
HistoryStateChanged = "history-state-changed",
|
||||
APIRequest = "api-request"
|
||||
Unknown = "unknown"
|
||||
|
||||
ResponseTypes {.pure.} = enum
|
||||
Web3SendAsyncCallback = "web3-send-async-callback",
|
||||
APIResponse = "api-response",
|
||||
Web3ResponseError = "web3-response-error"
|
||||
|
||||
type
|
||||
Payload = ref object
|
||||
id: JsonNode
|
||||
rpcMethod: string
|
||||
|
||||
Web3SendAsyncReadOnly = ref object
|
||||
messageId: JsonNode
|
||||
payload: Payload
|
||||
request: string
|
||||
hostname: string
|
||||
|
||||
APIRequest = ref object
|
||||
isAllowed: bool
|
||||
messageId: JsonNode
|
||||
permission: Permission
|
||||
hostname: string
|
||||
|
||||
const AUTH_METHODS = toHashSet(["eth_accounts", "eth_coinbase", "eth_sendTransaction", "eth_sign", "keycard_signTypedData", "eth_signTypedData", "eth_signTypedData_v3", "personal_sign", "personal_ecRecover"])
|
||||
const SIGN_METHODS = toHashSet(["eth_sign", "personal_sign", "eth_signTypedData", "eth_signTypedData_v3"])
|
||||
const ACC_METHODS = toHashSet(["eth_accounts", "eth_coinbase"])
|
||||
|
||||
type ProviderModel* = ref object
|
||||
events*: EventEmitter
|
||||
permissions*: PermissionsModel
|
||||
|
||||
proc newProviderModel*(events: EventEmitter, permissions: PermissionsModel): ProviderModel =
|
||||
result = ProviderModel()
|
||||
result.events = events
|
||||
result.permissions = permissions
|
||||
|
||||
proc requestType(message: string): RequestTypes =
|
||||
let data = message.parseJson
|
||||
result = RequestTypes.Unknown
|
||||
try:
|
||||
result = parseEnum[RequestTypes](data["type"].getStr())
|
||||
except:
|
||||
warn "Unknown request type received", value=data["permission"].getStr()
|
||||
|
||||
proc toWeb3SendAsyncReadOnly(message: string): Web3SendAsyncReadOnly =
|
||||
let data = message.parseJson
|
||||
result = Web3SendAsyncReadOnly(
|
||||
messageId: data["messageId"],
|
||||
request: $data["payload"],
|
||||
hostname: data{"hostname"}.getStr(),
|
||||
payload: Payload(
|
||||
id: data["payload"]{"id"},
|
||||
rpcMethod: data["payload"]["method"].getStr()
|
||||
)
|
||||
)
|
||||
|
||||
proc toAPIRequest(message: string): APIRequest =
|
||||
let data = message.parseJson
|
||||
|
||||
result = APIRequest(
|
||||
messageId: data["messageId"],
|
||||
isAllowed: data{"isAllowed"}.getBool(),
|
||||
permission: data["permission"].getStr().toPermission(),
|
||||
hostname: data{"hostname"}.getStr()
|
||||
)
|
||||
|
||||
proc process(self: ProviderModel, data: Web3SendAsyncReadOnly): string =
|
||||
if AUTH_METHODS.contains(data.payload.rpcMethod) and not self.permissions.hasPermission(data.hostname, Permission.Web3):
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": {
|
||||
"code": 4100
|
||||
}
|
||||
}
|
||||
|
||||
if data.payload.rpcMethod == "eth_sendTransaction":
|
||||
try:
|
||||
let request = data.request.parseJson
|
||||
let fromAddress = request["params"][0]["from"].getStr()
|
||||
let to = request["params"][0]{"to"}.getStr()
|
||||
let value = if (request["params"][0]["value"] != nil):
|
||||
request["params"][0]["value"].getStr()
|
||||
else:
|
||||
"0"
|
||||
let password = request["password"].getStr()
|
||||
let selectedGasLimit = request["selectedGasLimit"].getStr()
|
||||
let selectedGasPrice = request["selectedGasPrice"].getStr()
|
||||
let txData = if (request["params"][0].hasKey("data") and request["params"][0]["data"].kind != JNull):
|
||||
request["params"][0]["data"].getStr()
|
||||
else:
|
||||
""
|
||||
|
||||
var success: bool
|
||||
# TODO make this async
|
||||
let response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success, txData)
|
||||
let errorMessage = if not success:
|
||||
if response == "":
|
||||
"web3-response-error"
|
||||
else:
|
||||
response
|
||||
else:
|
||||
""
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": errorMessage,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": data.payload.id,
|
||||
"result": if (success): response else: ""
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
error "Error sending the transaction", msg = e.msg
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": {
|
||||
"code": 4100,
|
||||
"message": e.msg
|
||||
}
|
||||
}
|
||||
|
||||
if SIGN_METHODS.contains(data.payload.rpcMethod):
|
||||
try:
|
||||
let request = data.request.parseJson
|
||||
var params = request["params"]
|
||||
let password = hashPassword(request["password"].getStr())
|
||||
let dappAddress = status_settings.getSetting[string](Setting.DappsAddress)
|
||||
var rpcResult = "{}"
|
||||
|
||||
case data.payload.rpcMethod:
|
||||
of "eth_signTypedData", "eth_signTypedData_v3":
|
||||
rpcResult = signTypedData(params[1].getStr(), dappAddress, password)
|
||||
else:
|
||||
rpcResult = signMessage($ %* {
|
||||
"data": params[0].getStr(),
|
||||
"password": password,
|
||||
"account": dappAddress
|
||||
})
|
||||
|
||||
let jsonRpcResult = rpcResult.parseJson
|
||||
let success: bool = not jsonRpcResult.hasKey("error")
|
||||
let errorMessage = if success: "" else: jsonRpcResult["error"]{"message"}.getStr()
|
||||
let response = if success: jsonRpcResult["result"].getStr() else: ""
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": errorMessage,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": if data.payload.id == nil: newJNull() else: data.payload.id,
|
||||
"result": if (success): response else: ""
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
error "Error signing message", msg = e.msg
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": {
|
||||
"code": 4100,
|
||||
"message": e.msg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ACC_METHODS.contains(data.payload.rpcMethod):
|
||||
let dappAddress = status_settings.getSetting[string](Setting.DappsAddress)
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": data.payload.id,
|
||||
"result": if data.payload.rpcMethod == "eth_coinbase": newJString(dappAddress) else: %*[dappAddress]
|
||||
}
|
||||
}
|
||||
|
||||
let rpcResult = callRPC(data.request)
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": (if rpcResult == "": newJString("web3-response-error") else: newJNull()),
|
||||
"result": rpcResult.parseJson
|
||||
}
|
||||
|
||||
proc process*(self: ProviderModel, data: APIRequest): string =
|
||||
var value:JsonNode = case data.permission
|
||||
of Permission.Web3: %* [status_settings.getSetting[string](Setting.DappsAddress, "0x0000000000000000000000000000000000000000")]
|
||||
of Permission.ContactCode: %* status_settings.getSetting[string](Setting.PublicKey, "0x0")
|
||||
of Permission.Unknown: newJNull()
|
||||
|
||||
let isAllowed = data.isAllowed and data.permission != Permission.Unknown
|
||||
|
||||
info "API request received", host=data.hostname, value=data.permission, isAllowed
|
||||
|
||||
if isAllowed: self.permissions.addPermission(data.hostname, data.permission)
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.APIResponse,
|
||||
"isAllowed": isAllowed,
|
||||
"permission": data.permission,
|
||||
"messageId": data.messageId,
|
||||
"data": value
|
||||
}
|
||||
|
||||
proc postMessage*(self: ProviderModel, message: string): string =
|
||||
case message.requestType():
|
||||
of RequestTypes.Web3SendAsyncReadOnly: self.process(message.toWeb3SendAsyncReadOnly())
|
||||
of RequestTypes.HistoryStateChanged: """{"type":"TODO-IMPLEMENT-THIS"}""" ############# TODO:
|
||||
of RequestTypes.APIRequest: self.process(message.toAPIRequest())
|
||||
else: """{"type":"TODO-IMPLEMENT-THIS"}""" ##################### TODO:
|
|
@ -2,7 +2,7 @@ import libstatus/accounts as libstatus_accounts
|
|||
import libstatus/core as libstatus_core
|
||||
import libstatus/settings as libstatus_settings
|
||||
import types as libstatus_types
|
||||
import chat, accounts, wallet, node, network, messages, contacts, profile, stickers, permissions, fleet, settings, mailservers, browser, tokens
|
||||
import chat, accounts, wallet, node, network, messages, contacts, profile, stickers, permissions, fleet, settings, mailservers, browser, tokens, provider
|
||||
import ../eventemitter
|
||||
import ./tasks/task_runner_impl
|
||||
|
||||
|
@ -26,6 +26,7 @@ type Status* = ref object
|
|||
mailservers*: MailserversModel
|
||||
browser*: BrowserModel
|
||||
tokens*: TokensModel
|
||||
provider*: ProviderModel
|
||||
|
||||
proc newStatusInstance*(fleetConfig: string): Status =
|
||||
result = Status()
|
||||
|
@ -47,6 +48,7 @@ proc newStatusInstance*(fleetConfig: string): Status =
|
|||
result.mailservers = mailservers.newMailserversModel(result.events)
|
||||
result.browser = browser.newBrowserModel(result.events)
|
||||
result.tokens = tokens.newTokensModel(result.events)
|
||||
result.provider = provider.newProviderModel(result.events, result.permissions)
|
||||
|
||||
proc initNode*(self: Status) =
|
||||
self.tasks.init()
|
||||
|
|
Loading…
Reference in New Issue