import json, json_serialization, chronicles import ./core, ./utils import ./response_type import status_go export response_type logScope: topics = "rpc-accounts" 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, "mnemonicPhraseLength": MNEMONIC_PHRASE_LENGTH, "bip39Passphrase": "", "paths": paths } try: let response = status_go.multiAccountGenerateAndDeriveAddresses($payload) result.result = Json.decode(response, JsonNode) except RpcException as e: error "error doing rpc request", methodName = "generateAddresses", exception=e.msg raise newException(RpcException, e.msg) proc generateAlias*(publicKey: string): RpcResponse[JsonNode] {.raises: [Exception].} = try: let response = status_go.generateAlias(publicKey) result.result = %* response except RpcException as e: error "error doing rpc request", methodName = "generateAlias", exception=e.msg raise newException(RpcException, e.msg) proc generateIdenticon*(publicKey: string): RpcResponse[JsonNode] {.raises: [Exception].} = try: let response = status_go.identicon(publicKey) result.result = %* response except RpcException as e: error "error doing rpc request", methodName = "generateIdenticon", exception=e.msg raise newException(RpcException, e.msg) proc multiAccountImportMnemonic*(mnemonic: string): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* { "mnemonicPhrase": mnemonic, "Bip39Passphrase": "" } try: let response = status_go.multiAccountImportMnemonic($payload) result.result = Json.decode(response, JsonNode) except RpcException as e: error "error doing rpc request", methodName = "multiAccountImportMnemonic", exception=e.msg raise newException(RpcException, e.msg) proc deriveAccounts*(accountId: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* { "accountID": accountId, "paths": paths } try: let response = status_go.multiAccountDeriveAddresses($payload) result.result = Json.decode(response, JsonNode) except RpcException as e: error "error doing rpc request", methodName = "deriveAccounts", exception=e.msg raise newException(RpcException, e.msg) proc openedAccounts*(path: string): RpcResponse[JsonNode] {.raises: [Exception].} = try: let response = status_go.openAccounts(path) result.result = Json.decode(response, JsonNode) except RpcException as e: error "error doing rpc request", methodName = "openedAccounts", exception=e.msg raise newException(RpcException, e.msg) proc storeDerivedAccounts*(id, hashedPassword: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* { "accountID": id, "paths": paths, "password": hashedPassword } try: let response = status_go.multiAccountStoreDerivedAccounts($payload) result.result = Json.decode(response, JsonNode) except RpcException as e: 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 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) result.result = %* response except RpcException as e: error "error doing rpc request", methodName = "addPeer", exception=e.msg raise newException(RpcException, e.msg) proc saveAccountAndLogin*(hashedPassword: string, account, subaccounts, settings, config: JsonNode): RpcResponse[JsonNode] {.raises: [Exception].} = try: let response = status_go.saveAccountAndLogin($account, hashedPassword, $settings, $config, $subaccounts) result.result = Json.decode(response, JsonNode) except RpcException as e: error "error doing rpc request", methodName = "saveAccountAndLogin", exception=e.msg raise newException(RpcException, e.msg) proc login*(name, keyUid, hashedPassword, identicon, thumbnail, large: string): RpcResponse[JsonNode] {.raises: [Exception].} = try: var payload = %* { "name": name, "key-uid": keyUid, "identityImage": newJNull(), "identicon": identicon } if(thumbnail.len>0 and large.len > 0): payload["identityImage"] = %* {"thumbnail": thumbnail, "large": large} # TODO: # If you added a new value in the nodeconfig in status-go, old accounts will not have this value, since the node config # is stored in the database, and it's not easy to migrate using .sql # While this is fixed, you can add here any missing attribute on the node config, and it will be merged with whatever # the account has in the db var nodeCfg = %* { "ShhextConfig": %* { "EnableMailserverCycle": true }, "Web3ProviderConfig": %* { "Enabled": true }, "EnsConfig": %* { "Enabled": true }, } let response = status_go.loginWithConfig($payload, hashedPassword, $nodeCfg) result.result = Json.decode(response, JsonNode) 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 proc generateAccount*(password, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* [hashPassword(password), name, color] return core.callPrivateRPC("accounts_generateAccount", payload) proc addAccountWithMnemonic*(mnemonic, password, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* [mnemonic, hashPassword(password), name, color] return core.callPrivateRPC("accounts_addAccountWithMnemonic", payload) proc addAccountWithPrivateKey*(privateKey, password, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* [privateKey, hashPassword(password), name, color] return core.callPrivateRPC("accounts_addAccountWithPrivateKey", payload) proc addAccountWatch*(address, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* [address, name, color] return core.callPrivateRPC("accounts_addAccountWatch", payload)