refactor: move provider logic to status-go

This commit is contained in:
Richard Ramos 2021-12-16 13:22:16 -04:00
parent f0c1ad5087
commit caa44cf5b9
5 changed files with 18 additions and 237 deletions

View File

@ -18,39 +18,6 @@ const SWARM_GATEWAY* = "swarm-gateways.net"
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
@ -62,206 +29,6 @@ proc newProviderModel*(events: EventEmitter, permissions: PermissionsModel, wall
result.permissions = permissions
result.wallet = wallet
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 selectedTipLimit = request{"selectedTipLimit"}.getStr()
let selectedOverallLimit = request{"selectedOverallLimit"}.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
var errorMessage = ""
var response = ""
var validInput: bool = true
let eip1559Enabled = self.wallet.isEIP1559Enabled()
try:
validateTransactionInput(fromAddress, to, "", value, selectedGasLimit, selectedGasPrice, txData, eip1559Enabled, selectedTipLimit, selectedOverallLimit, "dummy")
except Exception as e:
validInput = false
success = false
errorMessage = e.msg
if validInput:
# TODO make this async
response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, eip1559Enabled, selectedTipLimit, selectedOverallLimit, password, success, txData)
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:
proc ensResourceURL*(self: ProviderModel, ens: string, url: string):
(string, string, string, string, bool) =

View File

@ -1,7 +1,7 @@
import statusgo_backend/accounts as statusgo_backend_accounts
import statusgo_backend/core as statusgo_backend_core
import statusgo_backend/settings as statusgo_backend_settings
import chat, accounts, wallet, wallet2, node, network, messages, contacts, profile, stickers, permissions, fleet, settings, mailservers, tokens, provider
import chat, accounts, wallet, wallet2, node, network, messages, contacts, profile, stickers, permissions, fleet, settings, mailservers, tokens
import notifications/os_notifications
import ../eventemitter
import bitops, stew/byteutils, chronicles
@ -30,7 +30,6 @@ type Status* = ref object
settings*: SettingsModel
mailservers*: MailserversModel
tokens*: TokensModel
provider*: ProviderModel
osnotifications*: OsNotifications
keycard*: KeycardModel
@ -54,7 +53,6 @@ proc newStatusInstance*(fleetConfig: string, backendName: string = "statusgo"):
result.settings = settings.newSettingsModel(result.events)
result.mailservers = mailservers.newMailserversModel(result.events)
result.tokens = tokens.newTokensModel(result.events)
result.provider = provider.newProviderModel(result.events, result.permissions, result.wallet)
result.osnotifications = newOsNotifications(result.events)
result.keycard = newKeycardModel(result.backend)

View File

@ -114,6 +114,9 @@ var NODE_CONFIG* = %* {
"ClusterConfig": {
"Enabled": true
},
"Web3ProviderConfig": {
"Enabled": true
},
"DataDir": "./ethereum/mainnet",
"EnableNTPSync": true,
"KeyStoreDir": "./keystore",

View File

@ -0,0 +1,13 @@
import json, json_serialization, strformat, chronicles
import status_go
import accounts
import core
logScope:
topics = "provider"
proc providerRequest*(requestType: string, message:string): RpcResponse[JsonNode] =
let jsonMessage = message.parseJson
if requestType == "web3-send-async-read-only" and jsonMessage.hasKey("payload") and jsonMessage["payload"].hasKey("password"):
jsonMessage["payload"]["password"] = newJString(hashPassword(jsonMessage["payload"]["password"].getStr()))
callPrivateRPC("provider_processRequest", %*[requestType, jsonMessage])

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 31f2a0810d07399dfc23037db00ef315d43f93e8
Subproject commit abbd796e0c56402e0723c407119cabbb9fbd5d73