diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..304222d9af --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +libstatus.a +nim_libstatus +data/ +noBackup/ diff --git a/README.md b/README.md index 0d4df21360..de1d54258b 100644 --- a/README.md +++ b/README.md @@ -1 +1,33 @@ -# nim-status \ No newline at end of file +# nim-status + +Experiments calling status-go from nim + +![Image](screenRec.gif) + +``` +# 1. Install nim 1.2.0 + +# 2. Install QT, and add it to the PATH +export PATH=$PATH:/path/to/Qt/5.14.2/gcc_64/bin + + +# 3. Clone and build DOtherside +git clone https://github.com/filcuc/DOtherSide +cd DOtherSide +mkdir build && cd build +cmake .. +make + + +# 4. Setup Library Path +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/dotherside/build/lib + + +# 5. Copy libstatus.a to repo. Can be obtained from `status-react/result` +# by executing `make status-go-desktop` + + +# 6. +nimble build +./nim_libstatus +``` diff --git a/libstatus.h b/libstatus.h new file mode 100644 index 0000000000..886f2376be --- /dev/null +++ b/libstatus.h @@ -0,0 +1,293 @@ +/* Code generated by cmd/cgo; DO NOT EDIT. */ + +/* package github.com/status-im/status-go/lib */ + + +#line 1 "cgo-builtin-export-prolog" + +#include /* for ptrdiff_t below */ + +#ifndef GO_CGO_EXPORT_PROLOGUE_H +#define GO_CGO_EXPORT_PROLOGUE_H + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef struct { const char *p; ptrdiff_t n; } _GoString_; +#endif + +#endif + +/* Start of preamble from import "C" comments. */ + + +#line 3 "library.go" + #include + +#line 1 "cgo-generated-wrapper" + +#line 3 "multiaccount.go" + #include + +#line 1 "cgo-generated-wrapper" + + +/* End of preamble from import "C" comments. */ + + +/* Start of boilerplate cgo prologue. */ +#line 1 "cgo-gcc-export-header-prolog" + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoInt64 GoInt; +typedef GoUint64 GoUint; +typedef __SIZE_TYPE__ GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +typedef float _Complex GoComplex64; +typedef double _Complex GoComplex128; + +/* + static assertion to make sure the file is being used on architecture + at least with matching size of GoInt. +*/ +typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef _GoString_ GoString; +#endif +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif + + +// OpenAccounts opens database and returns accounts list. + +extern char* OpenAccounts(char* p0); + +// ExtractGroupMembershipSignatures extract public keys from tuples of content/signature + +extern char* ExtractGroupMembershipSignatures(char* p0); + +// Sign signs a string containing group membership information + +extern char* SignGroupMembership(char* p0); + +//ValidateNodeConfig validates config for status node + +extern char* ValidateNodeConfig(char* p0); + +//ResetChainData remove chain data from data directory + +extern char* ResetChainData(); + +//CallRPC calls public APIs via RPC + +extern char* CallRPC(char* p0); + +//CallPrivateRPC calls both public and private APIs via RPC + +extern char* CallPrivateRPC(char* p0); + +//CreateAccount is equivalent to creating an account from the command line, +// just modified to handle the function arg passing + +extern char* CreateAccount(char* p0); + +//RecoverAccount re-creates master key using given details + +extern char* RecoverAccount(char* p0, char* p1); + +// StartOnboarding initialize the onboarding with n random accounts + +extern char* StartOnboarding(int p0, int p1); + +// ImportOnboardingAccount re-creates and imports an account created during onboarding. + +extern char* ImportOnboardingAccount(char* p0, char* p1); + +// RemoveOnboarding resets the current onboarding removing from memory all the generated keys. + +extern void RemoveOnboarding(); + +//VerifyAccountPassword verifies account password + +extern char* VerifyAccountPassword(char* p0, char* p1, char* p2); + +//StartNode - start Status node + +extern char* StartNode(char* p0); + +//StopNode - stop status node + +extern char* StopNode(); + +//Login loads a key file (for a given address), tries to decrypt it using the password, to verify ownership +// if verified, purges all the previous identities from Whisper, and injects verified key as shh identity + +extern char* Login(char* p0, char* p1); + +// SaveAccountAndLogin saves account in status-go database.. + +extern char* SaveAccountAndLogin(char* p0, char* p1, char* p2, char* p3, char* p4); + +// InitKeystore initialize keystore before doing any operations with keys. + +extern char* InitKeystore(char* p0); + +// LoginWithKeycard initializes an account with a chat key and encryption key used for PFS. +// It purges all the previous identities from Whisper, and injects the key as shh identity. + +extern char* LoginWithKeycard(char* p0, char* p1); + +//Logout is equivalent to clearing whisper identities + +extern char* Logout(); + +// SignMessage unmarshals rpc params {data, address, password} and passes +// them onto backend.SignMessage + +extern char* SignMessage(char* p0); + +// Recover unmarshals rpc params {signDataString, signedData} and passes +// them onto backend. + +extern char* Recover(char* p0); + +// SendTransaction converts RPC args and calls backend.SendTransaction + +extern char* SendTransaction(char* p0, char* p1); + +// SendTransactionWithSignature converts RPC args and calls backend.SendTransactionWithSignature + +extern char* SendTransactionWithSignature(char* p0, char* p1); + +// HashTransaction validate the transaction and returns new txArgs and the transaction hash. + +extern char* HashTransaction(char* p0); + +// HashMessage calculates the hash of a message to be safely signed by the keycard +// The hash is calulcated as +// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). +// This gives context to the signed message and prevents signing of transactions. + +extern char* HashMessage(char* p0); + +// SignTypedData unmarshall data into TypedData, validate it and signs with selected account, +// if password matches selected account. + +extern char* SignTypedData(char* p0, char* p1, char* p2); + +// HashTypedData unmarshalls data into TypedData, validates it and hashes it. + +extern char* HashTypedData(char* p0); + +//StartCPUProfile runs pprof for cpu + +extern char* StartCPUProfile(char* p0); + +//StopCPUProfiling stops pprof for cpu + +extern char* StopCPUProfiling(); + +//WriteHeapProfile starts pprof for heap + +extern char* WriteHeapProfile(char* p0); + +// AddPeer adds an enode as a peer. + +extern char* AddPeer(char* p0); + +// ConnectionChange handles network state changes as reported +// by ReactNative (see https://facebook.github.io/react-native/docs/netinfo.html) + +extern void ConnectionChange(char* p0, int p1); + +// AppStateChange handles app state changes (background/foreground). + +extern void AppStateChange(char* p0); + +// SetSignalEventCallback setup geth callback to notify about new signal + +extern void SetSignalEventCallback(void* p0); + +// ExportNodeLogs reads current node log and returns content to a caller. + +extern char* ExportNodeLogs(); + +// ChaosModeUpdate changes the URL of the upstream RPC client. + +extern char* ChaosModeUpdate(int p0); + +// GetNodesFromContract returns a list of nodes from a contract + +extern char* GetNodesFromContract(char* p0, char* p1); + +// SignHash exposes vanilla ECDSA signing required for Swarm messages + +extern char* SignHash(char* p0); + +// GenerateAlias returns a 3 random name words given the pk string 0x prefixed + +extern char* GenerateAlias(GoString p0); + +// Identicon returns the base64 identicon + +extern char* Identicon(GoString p0); + +// MultiAccountGenerate generates account in memory without storing them. + +extern char* MultiAccountGenerate(char* p0); + +// MultiAccountGenerateAndDeriveAddresses combines Generate and DeriveAddresses in one call. + +extern char* MultiAccountGenerateAndDeriveAddresses(char* p0); + +// MultiAccountDeriveAddresses derive addresses from an account selected by ID, without storing them. + +extern char* MultiAccountDeriveAddresses(char* p0); + +// MultiAccountStoreDerivedAccounts derive accounts from the specified key and store them encrypted with the specified password. + +extern char* MultiAccountStoreDerivedAccounts(char* p0); + +// MultiAccountImportPrivateKey imports a raw private key without storing it. + +extern char* MultiAccountImportPrivateKey(char* p0); + +// MultiAccountImportMnemonic imports an account derived from the mnemonic phrase and the Bip39Passphrase storing it. + +extern char* MultiAccountImportMnemonic(char* p0); + +// MultiAccountStoreAccount stores the select account. + +extern char* MultiAccountStoreAccount(char* p0); + +// MultiAccountLoadAccount loads in memory the account specified by address unlocking it with password. + +extern char* MultiAccountLoadAccount(char* p0); + +// MultiAccountReset remove all the multi-account keys from memory. + +extern char* MultiAccountReset(); + +#ifdef __cplusplus +} +#endif diff --git a/main.qml b/main.qml new file mode 100644 index 0000000000..25406c8488 --- /dev/null +++ b/main.qml @@ -0,0 +1,36 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 + +ApplicationWindow { + width: 800 + height: 300 + title: "JSON RPC Caller" + visible: true + + menuBar: MenuBar { + Menu { + title: "&File" + MenuItem { text: "&Exit"; onTriggered: logic.onExitTriggered() } + } + } + + ColumnLayout { + anchors.fill: parent + + RowLayout { + TextArea { id: callResult; Layout.fillWidth: true; text: logic.callResult; readOnly: true } + } + + RowLayout { + Label { text: "data" } + TextField { id: txtData; Layout.fillWidth: true; text: "" } + Button { + text: "Send" + onClicked: logic.onSend(txtData.text) + enabled: txtData.text !== "" + } + } + } +} diff --git a/nim_libstatus.nimble b/nim_libstatus.nimble new file mode 100644 index 0000000000..b7b7b6a788 --- /dev/null +++ b/nim_libstatus.nimble @@ -0,0 +1,10 @@ +[Package] +version = "0.1.0" +author = "Richard Ramos" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" +bin = "nim_libstatus" + +[Deps] +Requires: "nim >= 1.0.0, nimqml >= 0.7.0" \ No newline at end of file diff --git a/screenRec.gif b/screenRec.gif new file mode 100644 index 0000000000..234512801f Binary files /dev/null and b/screenRec.gif differ diff --git a/src/applicationLogic.nim b/src/applicationLogic.nim new file mode 100644 index 0000000000..564734b4bc --- /dev/null +++ b/src/applicationLogic.nim @@ -0,0 +1,51 @@ +import NimQml +import status + +QtObject: + type ApplicationLogic* = ref object of QObject + app: QApplication + callResult: string + + # Constructor + proc newApplicationLogic*(app: QApplication): ApplicationLogic = + new(result) + result.app = app + result.callResult = "Use this tool to call JSONRPC methods" + result.setup() + + status.setupNewAccount() + + # ¯\_(ツ)_/¯ dunno what is this + proc setup(self: ApplicationLogic) = + self.QObject.setup + + # ¯\_(ツ)_/¯ seems to be a method for garbage collection + proc delete*(self: ApplicationLogic) = + self.QObject.delete + + # Read more about slots and signals here: https://doc.qt.io/qt-5/signalsandslots.html + + # This is an EventHandler + proc onExitTriggered(self: ApplicationLogic) {.slot.} = + self.app.quit + + proc callResult*(self: ApplicationLogic): string {.slot.} = + result = self.callResult + + proc callResultChanged*(self: ApplicationLogic, callResult: string) {.signal.} + + proc setCallResult(self: ApplicationLogic, callResult: string) {.slot.} = + if self.callResult == callResult: return + self.callResult = callResult + self.callResultChanged(callResult) + + proc `callResult=`*(self: ApplicationLogic, callResult: string) = self.setCallResult(callResult) + + QtProperty[string] callResult: + read = callResult + write = setCallResult + notify = callResultChanged + + proc onSend*(self: ApplicationLogic, inputJSON: string) {.slot.} = + self.setCallResult(status.callRPC(inputJSON)) + echo "Done!: ", self.callResult diff --git a/src/libstatus.nim b/src/libstatus.nim new file mode 100644 index 0000000000..6854416de5 --- /dev/null +++ b/src/libstatus.nim @@ -0,0 +1,16 @@ +{.passL: "libstatus.a -lm".} + + +proc hashMessage*(p0: cstring): cstring {.importc: "HashMessage".} + +proc initKeystore*(keydir: cstring): cstring {.importc: "InitKeystore".} + +proc openAccounts*(datadir: cstring): cstring {.importc: "OpenAccounts".} + +proc multiAccountGenerateAndDeriveAddresses*(paramsJSON: cstring): cstring {.importc: "MultiAccountGenerateAndDeriveAddresses".} + +proc multiAccountStoreDerivedAccounts*(paramsJSON: cstring): cstring {.importc: "MultiAccountStoreDerivedAccounts".} + +proc saveAccountAndLogin*(accountData: cstring, password: cstring, settingsJSON: cstring, configJSON: cstring, subaccountData: cstring): cstring {.importc: "SaveAccountAndLogin".} + +proc callRPC*(inputJSON: cstring): cstring {.importc: "CallRPC".} diff --git a/src/nim_libstatus.nim b/src/nim_libstatus.nim new file mode 100644 index 0000000000..649bb5017b --- /dev/null +++ b/src/nim_libstatus.nim @@ -0,0 +1,23 @@ +import NimQml +import applicationLogic + +proc mainProc() = + var app = newQApplication() + defer: app.delete() + + let logic = newApplicationLogic(app) + defer: logic.delete + + var engine = newQQmlApplicationEngine() + defer: engine.delete() + + let logicVariant = newQVariant(logic) + defer: logicVariant.delete + + engine.setRootContextProperty("logic", logicVariant) + engine.load("main.qml") + app.exec() + +when isMainModule: + mainProc() + GC_fullcollect() diff --git a/src/nim_libstatus.nim.cfg b/src/nim_libstatus.nim.cfg new file mode 100644 index 0000000000..aed303eef8 --- /dev/null +++ b/src/nim_libstatus.nim.cfg @@ -0,0 +1 @@ +--threads:on diff --git a/src/status.nim b/src/status.nim new file mode 100644 index 0000000000..9e42123d8c --- /dev/null +++ b/src/status.nim @@ -0,0 +1,271 @@ +import os +import libstatus +import json + +const datadir = "./data/" +const keystoredir = "./data/keystore/" +const nobackupdir = "./noBackup/" + +proc recreateDir(dirname: string) = + if existsDir(dirname): + removeDir(dirname) + createDir(dirname) + +proc setupNewAccount*() = + # Deleting directories + recreateDir(datadir) + recreateDir(keystoredir) + recreateDir(nobackupdir) + + var result: string + + # 1 + result = $libstatus.initKeystore(keystoredir); + + # 2 + result = $libstatus.openAccounts(datadir); + + # 3 + let multiAccountConfig = %* { + "n": 5, + "mnemonicPhraseLength": 12, + "bip39Passphrase": "", + "paths": ["m/43'/60'/1581'/0'/0", "m/44'/60'/0'/0/0"] + } + result = $libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig); + let generatedAddresses = result.parseJson + let account0 = generatedAddresses[0] + + # 4 + let password = "0x2cd9bf92c5e20b1b410f5ace94d963a96e89156fbe65b70365e8596b37f1f165" #qwerty + let multiAccount = %* { + "accountID": account0["id"].getStr, + "paths": ["m/44'/60'/0'/0", "m/43'/60'/1581'", "m/43'/60'/1581'/0'/0", "m/44'/60'/0'/0/0"], + "password": password + } + result = $libstatus.multiAccountStoreDerivedAccounts($multiAccount); + let multiAccounts = result.parseJson + + # 5 + let accountData = %* { + "name": "Delectable Overjoyed Nauplius", + "address": account0["address"].getStr, + "photo-path": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAmElEQVR4nOzX4QmAIBBA4Yp2aY52aox2ao6mqf+SoajwON73M0J4HBy6TEEYQmMIjSE0htCECVlbDziv+/n6fuzb3OP/UmEmYgiNITRNm+LPqO2UE2YihtAYQlN818ptoZzau1btOakwEzGExhCa5hdi7d2p1zZLhZmIITSG0PhCpDGExhANEmYihtAYQmMIjSE0bwAAAP//kHQdRIWYzToAAAAASUVORK5CYII=", + "key-uid": account0["keyUid"].getStr, + "keycard-pairing": nil + } + + let settingsJSON = %* { + "key-uid": account0["keyUid"].getStr, + "mnemonic": account0["mnemonic"].getStr, + "public-key": multiAccounts["m/43'/60'/1581'/0'/0"]["publicKey"].getStr, + "name": accountData["name"].getStr, + "address": account0["address"].getStr, + "eip1581-address": multiAccounts["m/43'/60'/1581'"]["address"].getStr, + "dapps-address": multiAccounts["m/44'/60'/0'/0/0"]["address"].getStr, + "wallet-root-address": multiAccounts["m/44'/60'/0'/0"]["address"].getStr, + "preview-privacy?": true, + "signing-phrase": "dust gear boss", + "log-level": "INFO", + "latest-derived-path": 0, + "networks/networks": [ + { + "id": "testnet_rpc", + "etherscan-link": "https://ropsten.etherscan.io/address/", + "name": "Ropsten with upstream RPC", + "config": { + "NetworkId": 3, + "DataDir": "/ethereum/testnet_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://ropsten.infura.io/v3/f315575765b14720b32382a61a89341a", + }, + }, + }, + { + "id": "rinkeby_rpc", + "etherscan-link": "https://rinkeby.etherscan.io/address/", + "name": "Rinkeby with upstream RPC", + "config": { + "NetworkId": 4, + "DataDir": "/ethereum/rinkeby_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://rinkeby.infura.io/v3/f315575765b14720b32382a61a89341a", + }, + }, + }, + { + "id": "goerli_rpc", + "etherscan-link": "https://goerli.etherscan.io/address/", + "name": "Goerli with upstream RPC", + "config": { + "NetworkId": 5, + "DataDir": "/ethereum/goerli_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://goerli.blockscout.com/", + }, + }, + }, + { + "id": "mainnet_rpc", + "etherscan-link": "https://etherscan.io/address/", + "name": "Mainnet with upstream RPC", + "config": { + "NetworkId": 1, + "DataDir": "/ethereum/mainnet_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a", + }, + }, + }, + { + "id": "xdai_rpc", + "name": "xDai Chain", + "config": { + "NetworkId": 100, + "DataDir": "/ethereum/xdai_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://dai.poa.network" + }, + }, + }, + { + "id": "poa_rpc", + "name": "POA Network", + "config": { + "NetworkId": 99, + "DataDir": "/ethereum/poa_rpc", + "UpstreamConfig": { + "Enabled": true, + "URL": "https://core.poa.network" + }, + }, + }, + ], + "currency": "usd", + "photo-path": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAmElEQVR4nOzX4QmAIBBA4Yp2aY52aox2ao6mqf+SoajwON73M0J4HBy6TEEYQmMIjSE0htCECVlbDziv+/n6fuzb3OP/UmEmYgiNITRNm+LPqO2UE2YihtAYQlN818ptoZzau1btOakwEzGExhCa5hdi7d2p1zZLhZmIITSG0PhCpDGExhANEmYihtAYQmMIjSE0bwAAAP//kHQdRIWYzToAAAAASUVORK5CYII=", + "waku-enabled": true, + "wallet/visible-tokens": { + "mainnet": ["SNT"] + }, + "appearance": 0, + "networks/current-network": "mainnet_rpc", + "installation-id": "5d6bc316-a97e-5b89-9541-ad01f8eb7397", + } + + let configJSON = %* { + "BrowsersConfig": { + "Enabled": true + }, + "ClusterConfig": { + "BootNodes": [ + "enode://23d0740b11919358625d79d4cac7d50a34d79e9c69e16831c5c70573757a1f5d7d884510bc595d7ee4da3c1508adf87bbc9e9260d804ef03f8c1e37f2fb2fc69@47.52.106.107:443", + "enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@178.128.140.188:443", + "enode://6e6554fb3034b211398fcd0f0082cbb6bd13619e1a7e76ba66e1809aaa0c5f1ac53c9ae79cf2fd4a7bacb10d12010899b370c75fed19b991d9c0cdd02891abad@47.75.99.169:443", + "enode://5405c509df683c962e7c9470b251bb679dd6978f82d5b469f1f6c64d11d50fbd5dd9f7801c6ad51f3b20a5f6c7ffe248cc9ab223f8bcbaeaf14bb1c0ef295fd0@35.223.215.156:443", + ], + "Enabled": true, + "Fleet": "eth.prod", + "RendezvousNodes": [ + "/ip4/34.70.75.208/tcp/30703/ethv4/16Uiu2HAm6ZsERLx2BwVD2UM9SVPnnMU6NBycG8XPtu8qKys5awsU", + "/ip4/178.128.140.188/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf", + "/ip4/47.52.106.107/tcp/30703/ethv4/16Uiu2HAmEHiptiDDd9gqNY8oQqo8hHUWMHJzfwt5aLRdD6W2zcXR", + ], + "StaticNodes": [ + "enode://887cbd92d95afc2c5f1e227356314a53d3d18855880ac0509e0c0870362aee03939d4074e6ad31365915af41d34320b5094bfcc12a67c381788cd7298d06c875@178.128.141.0:443", + "enode://fbeddac99d396b91d59f2c63a3cb5fc7e0f8a9f7ce6fe5f2eed5e787a0154161b7173a6a73124a4275ef338b8966dc70a611e9ae2192f0f2340395661fad81c0@34.67.230.193:443", + ], + "TrustedMailServers": [ + "enode://2c8de3cbb27a3d30cbb5b3e003bc722b126f5aef82e2052aaef032ca94e0c7ad219e533ba88c70585ebd802de206693255335b100307645ab5170e88620d2a81@47.244.221.14:443", + "enode://ee2b53b0ace9692167a410514bca3024695dbf0e1a68e1dff9716da620efb195f04a4b9e873fb9b74ac84de801106c465b8e2b6c4f0d93b8749d1578bfcaf03e@104.197.238.144:443", + "enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@178.128.142.94:443", + "enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@178.128.142.26:443", + "enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@178.128.142.54:443", + "enode://30211cbd81c25f07b03a0196d56e6ce4604bb13db773ff1c0ea2253547fafd6c06eae6ad3533e2ba39d59564cfbdbb5e2ce7c137a5ebb85e99dcfc7a75f99f55@23.236.58.92:443", + ], + }, + "DataDir": "./ethereum/mainnet", # TODO add network name + "EnableNTPSync": true, + "KeyStoreDir": "./keystore", + "ListenAddr": ":30304", + "LogEnabled": true, + "LogFile": "geth.log", + "LogLevel": "INFO", + "MailserversConfig": { + "Enabled": true + }, + "Name": "StatusIM", + "NetworkId": 1, + "NoDiscovery": false, + "PermissionsConfig": { + "Enabled": true + }, + "Rendezvous": true, + "RequireTopics": { + "whisper": { + "Max": 2, + "Min": 2 + } + }, + "ShhextConfig": { + "BackupDisabledDataDir": "./", + "DataSyncEnabled": true, + "InstallationID": "aef27732-8d86-5039-a32e-bdbe094d8791", + "MailServerConfirmations": true, + "MaxMessageDeliveryAttempts": 6, + "PFSEnabled": true, + "VerifyENSContractAddress": "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", + "VerifyENSURL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a", + "VerifyTransactionChainID": 1, + "VerifyTransactionURL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a", + }, + "StatusAccountsConfig": { + "Enabled": true + }, + "UpstreamConfig": { + "Enabled": true, + "URL": "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a", + }, + "WakuConfig": { + "BloomFilterMode": nil, + "Enabled": true, + "LightClient": true, + "MinimumPoW": 0.001 + }, + "WalletConfig": { + "Enabled": true + } + } + + let subaccountData = %* [ + { + "public-key": multiAccounts["m/44'/60'/0'/0/0"]["publicKey"], + "address": multiAccounts["m/44'/60'/0'/0/0"]["address"], + "color":"#4360df", + "wallet":true, + "path":"m/44'/60'/0'/0/0", + "name":"Status account" + }, + { + "public-key": multiAccounts["m/43'/60'/1581'/0'/0"]["publicKey"], + "address": multiAccounts["m/43'/60'/1581'/0'/0"]["address"], + "name":"Delectable Overjoyed Nauplius", + "photo-path":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAmElEQVR4nOzX4QmAIBBA4Yp2aY52aox2ao6mqf+SoajwON73M0J4HBy6TEEYQmMIjSE0htCECVlbDziv+/n6fuzb3OP/UmEmYgiNITRNm+LPqO2UE2YihtAYQlN818ptoZzau1btOakwEzGExhCa5hdi7d2p1zZLhZmIITSG0PhCpDGExhANEmYihtAYQmMIjSE0bwAAAP//kHQdRIWYzToAAAAASUVORK5CYII=", + "path":"m/43'/60'/1581'/0'/0", + "chat":true + } + ] + + result = $libstatus.saveAccountAndLogin($accountData, password, $settingsJSON, $configJSON, $subaccountData) + let saveResult = result.parseJson + + if saveResult["error"].getStr == "": + echo "Account saved succesfully" + + +proc callRPC*(inputJSON: string): string = + return $libstatus.callRPC(inputJSON)