Refactor/wallet part 2 (#91)

* refactor: add save account

* refactor: add account generation

* refactor: save settings

* refactor: add update account in new be

* add getTransfersByAddress (#93)

Co-authored-by: Jonathan Rainville <rainville.jonathan@gmail.com>
This commit is contained in:
Anthony Laibe 2021-10-27 14:44:35 +02:00 committed by GitHub
parent ad9af00340
commit 76e867f1d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 162 additions and 5 deletions

View File

@ -1,4 +1,4 @@
import json, json_serialization, chronicles
import json, json_serialization, chronicles, nimcrypto
import ./core, ./utils
import ./response_type
@ -12,9 +12,29 @@ logScope:
const NUMBER_OF_ADDRESSES_TO_GENERATE = 5
const MNEMONIC_PHRASE_LENGTH = 12
const GENERATED* = "generated"
const SEED* = "seed"
const KEY* = "key"
const WATCH* = "watch"
proc getAccounts*(): RpcResponse[JsonNode] {.raises: [Exception].} =
return core.callPrivateRPC("accounts_getAccounts")
proc deleteAccount*(address: string): RpcResponse[JsonNode] {.raises: [Exception].} =
return core.callPrivateRPC("accounts_deleteAccount", %* [address])
proc updateAccount*(name, address, publicKey, walletType, color: string) {.raises: [Exception].} =
discard core.callPrivateRPC("accounts_saveAccounts", %* [
[{
"color": color,
"name": name,
"address": address,
"public-key": publicKey,
"type": walletType,
"path": "m/44'/60'/0'/0/1" # <--- TODO: fix this. Derivation path is not supposed to change
}]
])
proc generateAddresses*(paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* {
"n": NUMBER_OF_ADDRESSES_TO_GENERATE,
@ -102,6 +122,69 @@ proc storeDerivedAccounts*(id, hashedPassword: string, paths: seq[string]):
error "error doing rpc request", methodName = "storeDerivedAccounts", exception=e.msg
raise newException(RpcException, e.msg)
proc storeAccounts*(id, hashedPassword: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* {
"accountID": id,
"password": hashedPassword
}
try:
let response = status_go.multiAccountStoreAccount($payload)
result.result = Json.decode(response, JsonNode)
except RpcException as e:
error "error doing rpc request", methodName = "storeAccounts", exception=e.msg
raise newException(RpcException, e.msg)
proc hashPassword*(password: string): string =
result = "0x" & $keccak_256.digest(password)
proc saveAccount*(
address: string,
name: string,
password: string,
color: string,
accountType: string,
isADerivedAccount = true,
walletIndex: int = 0,
id: string = "",
publicKey: string = "",
) {.raises: [Exception].} =
var derivationPath = "m/44'/60'/0'/0/0"
let hashedPassword = hashPassword(password)
if (isADerivedAccount):
let derivationPath = (if accountType == GENERATED: "m/" else: "m/44'/60'/0'/0/") & $walletIndex
discard storeDerivedAccounts(id, hashedPassword, @[derivationPath])
elif accountType == KEY:
discard storeAccounts(id, hashedPassword)
discard callPrivateRPC("accounts_saveAccounts", %* [
[{
"color": color,
"name": name,
"address": address,
"public-key": publicKey,
"type": accountType,
"path": derivationPath
}]
])
proc loadAccount*(address: string, password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let hashedPassword = hashPassword(password)
let payload = %* {
"address": address,
"password": hashedPassword
}
try:
let response = status_go.multiAccountLoadAccount($payload)
result.result = Json.decode(response, JsonNode)
except RpcException as e:
error "error doing rpc request", methodName = "storeAccounts", exception=e.msg
raise newException(RpcException, e.msg)
proc addPeer*(peer: string): RpcResponse[JsonNode] {.raises: [Exception].} =
try:
let response = status_go.addPeer(peer)
@ -142,3 +225,26 @@ proc login*(name, keyUid, hashedPassword, identicon, thumbnail, large: string):
except RpcException as e:
error "error doing rpc request", methodName = "login", exception=e.msg
raise newException(RpcException, e.msg)
proc multiAccountImportPrivateKey*(privateKey: string): RpcResponse[JsonNode] =
let payload = %* {
"privateKey": privateKey
}
try:
let response = status_go.multiAccountImportPrivateKey($payload)
result.result = Json.decode(response, JsonNode)
except RpcException as e:
error "error doing rpc request", methodName = "multiAccountImportPrivateKey", exception=e.msg
raise newException(RpcException, e.msg)
proc verifyAccountPassword*(address: string, password: string, keystoreDir: string): bool =
let hashedPassword = hashPassword(password)
let verifyResult = status_go.verifyAccountPassword(keystoreDir, address, hashedPassword)
let error = parseJson(verifyResult)["error"].getStr
if error == "":
return true
return false

View File

@ -0,0 +1,35 @@
import
json, options, strutils
import
web3/[conversions, ethtypes], stint
import ../types/transaction
# TODO: make this public in nim-web3 lib
template stripLeadingZeros*(value: string): string =
var cidx = 0
# ignore the last character so we retain '0' on zero value
while cidx < value.len - 1 and value[cidx] == '0':
cidx.inc
value[cidx .. ^1]
proc `%`*(x: TransactionData): JsonNode =
result = newJobject()
result["from"] = %x.source
result["type"] = %x.txType
if x.to.isSome:
result["to"] = %x.to.unsafeGet
if x.gas.isSome:
result["gas"] = %x.gas.unsafeGet
if x.gasPrice.isSome:
result["gasPrice"] = %("0x" & x.gasPrice.unsafeGet.toHex.stripLeadingZeros)
if x.maxFeePerGas.isSome:
result["maxFeePerGas"] = %("0x" & x.maxFeePerGas.unsafeGet.toHex)
if x.maxPriorityFeePerGas.isSome:
result["maxPriorityFeePerGas"] = %("0x" & x.maxPriorityFeePerGas.unsafeGet.toHex)
if x.value.isSome:
result["value"] = %("0x" & x.value.unsafeGet.toHex)
result["data"] = %x.data
if x.nonce.isSome:
result["nonce"] = %x.nonce.unsafeGet

View File

@ -3,6 +3,9 @@ import ./core, ./response_type
export response_type
proc getAccounts*(): RpcResponse[JsonNode] {.raises: [Exception].} =
return core.callPrivateRPC("eth_accounts")
proc getBlockByNumber*(blockNumber: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [blockNumber, false]
return core.callPrivateRPC("eth_getBlockByNumber", payload)

View File

@ -4,4 +4,7 @@ import ./core, ./response_type
export response_type
proc getSettings*(): RpcResponse[JsonNode] {.raises: [Exception].} =
return core.callPrivateRPC("settings_getSettings")
return core.callPrivateRPC("settings_getSettings")
proc saveSettings*(key: string, value: string | JsonNode | bool | int) {.raises: [Exception].} =
discard core.callPrivateRPC("settings_saveSetting", %* [key, value])

View File

@ -1,7 +1,17 @@
import json
import json, stint, chronicles, strutils, conversions
import ./core
import ../types/transaction
import ./core as core
proc checkRecentHistory*(addresses: seq[string]) {.raises: [Exception].} =
let payload = %* [addresses]
discard callPrivateRPC("wallet_checkRecentHistory", payload)
discard callPrivateRPC("wallet_checkRecentHistory", payload)
proc getTransfersByAddress*(address: string, toBlock: Uint256, limit: int, loadMore: bool = false): RpcResponse[JsonNode] {.raises: [Exception].} =
let
toBlockParsed = if not loadMore: newJNull() else: %("0x" & stint.toHex(toBlock))
limitParsed = "0x" & limit.toHex.stripLeadingZeros
callPrivateRPC("wallet_getTransfersByAddress", %* [address, toBlockParsed, limitParsed, loadMore])