2021-09-07 12:30:12 +00:00
|
|
|
# Nimbus
|
2024-01-29 13:20:04 +00:00
|
|
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
2021-09-07 12:30:12 +00:00
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
|
|
# at your option.
|
|
|
|
# This file may not be copied, modified, or distributed except according to
|
|
|
|
# those terms.
|
|
|
|
|
2024-01-29 13:20:04 +00:00
|
|
|
{.push gcsafe, raises: [].}
|
2023-02-14 20:27:17 +00:00
|
|
|
|
2021-09-07 12:30:12 +00:00
|
|
|
import
|
2021-10-05 23:31:35 +00:00
|
|
|
std/[os, json, tables, strutils],
|
2024-05-30 12:54:03 +00:00
|
|
|
results,
|
2024-10-16 01:34:12 +00:00
|
|
|
eth/keyfile,
|
|
|
|
eth/common/[keys, addresses],
|
2024-01-29 13:20:04 +00:00
|
|
|
json_serialization
|
2021-09-07 12:30:12 +00:00
|
|
|
|
|
|
|
from nimcrypto/utils import burnMem
|
|
|
|
|
|
|
|
type
|
|
|
|
NimbusAccount* = object
|
|
|
|
privateKey*: PrivateKey
|
|
|
|
keystore*: JsonNode
|
|
|
|
unlocked*: bool
|
|
|
|
|
|
|
|
AccountsManager* = object
|
2024-10-16 01:34:12 +00:00
|
|
|
accounts: Table[Address, NimbusAccount]
|
2021-09-07 12:30:12 +00:00
|
|
|
|
|
|
|
proc init*(_: type AccountsManager): AccountsManager =
|
|
|
|
discard
|
|
|
|
|
2024-05-30 12:54:03 +00:00
|
|
|
proc loadKeystores*(am: var AccountsManager, path: string):
|
2024-01-29 13:20:04 +00:00
|
|
|
Result[void, string] =
|
2021-09-07 12:30:12 +00:00
|
|
|
try:
|
|
|
|
createDir(path)
|
2024-01-29 13:20:04 +00:00
|
|
|
for filename in walkDirRec(path):
|
|
|
|
var data = Json.loadFile(filename, JsonNode)
|
2024-10-24 04:07:06 +00:00
|
|
|
if data.kind != JObject:
|
|
|
|
return err("expect json object of keystore data: " & filename)
|
|
|
|
if not data.hasKey("address"):
|
|
|
|
return err("no 'address' field in keystore data: " & filename)
|
2024-10-16 01:34:12 +00:00
|
|
|
let address = Address.fromHex(data["address"].getStr())
|
2021-09-07 12:30:12 +00:00
|
|
|
am.accounts[address] = NimbusAccount(keystore: data, unlocked: false)
|
2024-01-29 13:20:04 +00:00
|
|
|
except CatchableError as exc:
|
2024-10-24 04:07:06 +00:00
|
|
|
return err("loadKeystores: " & exc.msg)
|
2024-05-30 12:54:03 +00:00
|
|
|
|
2021-09-07 12:30:12 +00:00
|
|
|
ok()
|
|
|
|
|
2024-10-16 01:34:12 +00:00
|
|
|
proc getAccount*(am: var AccountsManager, address: Address): Result[NimbusAccount, string] =
|
2021-09-07 12:30:12 +00:00
|
|
|
am.accounts.withValue(address, value) do:
|
|
|
|
return ok(value[])
|
|
|
|
do:
|
|
|
|
return err("getAccount: not available " & address.toHex)
|
|
|
|
|
2024-10-16 01:34:12 +00:00
|
|
|
proc unlockAccount*(am: var AccountsManager, address: Address, password: string): Result[void, string] =
|
2021-09-07 12:30:12 +00:00
|
|
|
let accRes = am.getAccount(address)
|
|
|
|
if accRes.isErr:
|
|
|
|
return err(accRes.error)
|
|
|
|
|
|
|
|
var acc = accRes.get()
|
|
|
|
let res = decodeKeyFileJson(acc.keystore, password)
|
|
|
|
if res.isOk:
|
|
|
|
acc.privateKey = res.get()
|
|
|
|
acc.unlocked = true
|
|
|
|
am.accounts[address] = acc
|
|
|
|
return ok()
|
|
|
|
|
|
|
|
err($res.error)
|
|
|
|
|
2024-10-16 01:34:12 +00:00
|
|
|
proc lockAccount*(am: var AccountsManager, address: Address): Result[void, string] =
|
2021-09-07 12:30:12 +00:00
|
|
|
am.accounts.withValue(address, acc) do:
|
|
|
|
acc.unlocked = false
|
|
|
|
burnMem(acc.privateKey)
|
|
|
|
am.accounts[address] = acc[]
|
|
|
|
return ok()
|
|
|
|
do:
|
|
|
|
return err("getAccount: not available " & address.toHex)
|
|
|
|
|
|
|
|
proc numAccounts*(am: AccountsManager): int =
|
|
|
|
am.accounts.len
|
|
|
|
|
2024-10-16 01:34:12 +00:00
|
|
|
iterator addresses*(am: AccountsManager): Address =
|
2021-09-07 12:30:12 +00:00
|
|
|
for a in am.accounts.keys:
|
|
|
|
yield a
|
|
|
|
|
|
|
|
proc importPrivateKey*(am: var AccountsManager, fileName: string): Result[void, string] =
|
|
|
|
try:
|
|
|
|
let pkhex = readFile(fileName)
|
2021-10-05 23:31:35 +00:00
|
|
|
let res = PrivateKey.fromHex(pkhex.strip)
|
2021-09-07 12:30:12 +00:00
|
|
|
if res.isErr:
|
|
|
|
return err("not a valid private key, expect 32 bytes hex")
|
|
|
|
|
|
|
|
let seckey = res.get()
|
|
|
|
let acc = seckey.toPublicKey().toCanonicalAddress()
|
|
|
|
|
|
|
|
am.accounts[acc] = NimbusAccount(
|
|
|
|
privateKey: seckey,
|
|
|
|
unlocked: true
|
|
|
|
)
|
|
|
|
|
|
|
|
return ok()
|
|
|
|
except CatchableError as ex:
|
|
|
|
return err(ex.msg)
|
2024-01-29 13:20:04 +00:00
|
|
|
|
|
|
|
{.pop.}
|