From 73069255cd532ed6708f027d8ff0af066fd775a7 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Fri, 29 May 2020 15:54:35 -0400 Subject: [PATCH] move 'models' to status lib for clarity --- src/app/chat/core.nim | 4 +- src/app/chat/view.nim | 2 +- src/app/chat/views/channels_list.nim | 2 +- src/app/chat/views/message_list.nim | 2 +- src/app/login/core.nim | 4 +- src/app/login/view.nim | 6 +- src/app/node/core.nim | 3 +- src/app/node/view.nim | 2 +- src/app/onboarding/core.nim | 6 +- src/app/onboarding/view.nim | 4 +- src/app/profile/core.nim | 8 +- src/app/profile/view.nim | 2 +- src/app/profile/views/contact_list.nim | 2 +- src/app/profile/views/mailservers_list.nim | 2 +- src/app/profile/views/profile_info.nim | 2 +- src/app/wallet/core.nim | 4 +- src/app/wallet/view.nim | 2 +- src/app/wallet/views/asset_list.nim | 2 +- src/models/accounts.nim | 31 --- src/models/chat.nim | 103 ---------- src/models/wallet.nim | 40 ---- src/nim_status_client.nim | 10 +- src/signals/core.nim | 2 +- src/signals/types.nim | 2 +- src/status/accounts.nim | 182 +++-------------- src/status/chat.nim | 185 +++++++++--------- src/{models => status}/chat/chat_item.nim | 2 +- src/{models => status}/chat/chat_message.nim | 0 src/{models => status}/chat/stickers.nim | 0 src/status/libstatus/accounts.nim | 161 +++++++++++++++ .../{ => libstatus}/accounts/constants.nim | 0 .../accounts/signing_phrases.nim | 0 src/status/libstatus/chat.nim | 106 ++++++++++ src/status/{ => libstatus}/core.nim | 0 src/status/{ => libstatus}/libstatus.nim | 0 src/status/{ => libstatus}/mailservers.nim | 0 src/status/{ => libstatus}/types.nim | 0 src/status/{ => libstatus}/utils.nim | 0 src/status/libstatus/wallet.nim | 43 ++++ src/{models => status}/node.nim | 2 +- src/{models => status}/profile.nim | 2 +- src/status/wallet.nim | 61 +++--- 42 files changed, 495 insertions(+), 496 deletions(-) delete mode 100644 src/models/accounts.nim delete mode 100644 src/models/chat.nim delete mode 100644 src/models/wallet.nim rename src/{models => status}/chat/chat_item.nim (97%) rename src/{models => status}/chat/chat_message.nim (100%) rename src/{models => status}/chat/stickers.nim (100%) create mode 100644 src/status/libstatus/accounts.nim rename src/status/{ => libstatus}/accounts/constants.nim (100%) rename src/status/{ => libstatus}/accounts/signing_phrases.nim (100%) create mode 100644 src/status/libstatus/chat.nim rename src/status/{ => libstatus}/core.nim (100%) rename src/status/{ => libstatus}/libstatus.nim (100%) rename src/status/{ => libstatus}/mailservers.nim (100%) rename src/status/{ => libstatus}/types.nim (100%) rename src/status/{ => libstatus}/utils.nim (100%) create mode 100644 src/status/libstatus/wallet.nim rename src/{models => status}/node.nim (92%) rename src/{models => status}/profile.nim (93%) diff --git a/src/app/chat/core.nim b/src/app/chat/core.nim index f0b35b38ec..5ee72e16c5 100644 --- a/src/app/chat/core.nim +++ b/src/app/chat/core.nim @@ -1,8 +1,8 @@ import NimQml import json, eventemitter -import ../../models/chat as chat_model +import ../../status/chat as chat_model import ../../signals/types -import ../../status/types as status_types +import ../../status/libstatus/types as status_types import views/channels_list import view import chronicles diff --git a/src/app/chat/view.nim b/src/app/chat/view.nim index e134bfd25b..0f1f437298 100644 --- a/src/app/chat/view.nim +++ b/src/app/chat/view.nim @@ -3,7 +3,7 @@ import Tables import views/channels_list import views/message_list import ../../signals/types -import ../../models/chat +import ../../status/chat QtObject: type diff --git a/src/app/chat/views/channels_list.nim b/src/app/chat/views/channels_list.nim index d279592c90..41bbd09b3a 100644 --- a/src/app/chat/views/channels_list.nim +++ b/src/app/chat/views/channels_list.nim @@ -3,7 +3,7 @@ import Tables import strformat import random -import ../../../models/chat +import ../../../status/chat const accountColors* = [ "#9B832F", diff --git a/src/app/chat/views/message_list.nim b/src/app/chat/views/message_list.nim index f10470efe8..2a87281b75 100644 --- a/src/app/chat/views/message_list.nim +++ b/src/app/chat/views/message_list.nim @@ -1,5 +1,5 @@ import NimQml, Tables -import ../../../models/chat +import ../../../status/chat type ChatMessageRoles {.pure.} = enum diff --git a/src/app/login/core.nim b/src/app/login/core.nim index 5f740ec0a1..ce75f449e0 100644 --- a/src/app/login/core.nim +++ b/src/app/login/core.nim @@ -1,9 +1,9 @@ import NimQml -import ../../status/types as status_types +import ../../status/libstatus/types as status_types import ../../signals/types import eventemitter import view -import ../../models/accounts as AccountModel +import ../../status/accounts as AccountModel import chronicles import options import std/wrapnils diff --git a/src/app/login/view.nim b/src/app/login/view.nim index 27149e7cf6..4cd7e38040 100644 --- a/src/app/login/view.nim +++ b/src/app/login/view.nim @@ -3,12 +3,12 @@ import Tables import json import nimcrypto import ../../signals/types -import ../../status/types as status_types -import ../../status/accounts as status_accounts +import ../../status/libstatus/types as status_types +import ../../status/libstatus/accounts as status_accounts import strformat import json_serialization import core -import ../../models/accounts as AccountModel +import ../../status/accounts as AccountModel type AccountRoles {.pure.} = enum diff --git a/src/app/node/core.nim b/src/app/node/core.nim index 023b0d7afd..7d6611ff1d 100644 --- a/src/app/node/core.nim +++ b/src/app/node/core.nim @@ -1,9 +1,8 @@ import NimQml import chronicles import eventemitter -import "../../status/core" as status import ../../signals/types -import ../../models/node +import ../../status/node import view logScope: diff --git a/src/app/node/view.nim b/src/app/node/view.nim index 93b155aa8c..766d567b25 100644 --- a/src/app/node/view.nim +++ b/src/app/node/view.nim @@ -1,5 +1,5 @@ import NimQml -import ../../models/node +import ../../status/node QtObject: type NodeView* = ref object of QObject diff --git a/src/app/onboarding/core.nim b/src/app/onboarding/core.nim index 47b740450f..fc263eefd5 100644 --- a/src/app/onboarding/core.nim +++ b/src/app/onboarding/core.nim @@ -1,7 +1,7 @@ import NimQml -import ../../status/types as status_types -import ../../status/accounts as status_accounts -import ../../models/accounts as AccountModel +import ../../status/libstatus/types as status_types +import ../../status/libstatus/accounts as status_accounts +import ../../status/accounts as AccountModel import eventemitter import view import chronicles diff --git a/src/app/onboarding/view.nim b/src/app/onboarding/view.nim index db5dcd1ea0..9df620fadb 100644 --- a/src/app/onboarding/view.nim +++ b/src/app/onboarding/view.nim @@ -2,11 +2,11 @@ import NimQml import Tables import json import nimcrypto -import ../../status/types as status_types +import ../../status/libstatus/types as status_types import ../../signals/types import strformat import json_serialization -import ../../models/accounts as AccountModel +import ../../status/accounts as AccountModel type AccountRoles {.pure.} = enum diff --git a/src/app/profile/core.nim b/src/app/profile/core.nim index 1655d08096..66aab1974b 100644 --- a/src/app/profile/core.nim +++ b/src/app/profile/core.nim @@ -2,12 +2,12 @@ import NimQml import eventemitter import strformat import json -import "../../status/core" as status -import ../../status/mailservers as status_mailservers +import "../../status/libstatus/core" as status +import ../../status/libstatus/mailservers as status_mailservers import ../../signals/types import view -import "../../status/types" as status_types -import ../../models/profile +import "../../status/libstatus/types" as status_types +import ../../status/profile type ProfileController* = object view*: ProfileView diff --git a/src/app/profile/view.nim b/src/app/profile/view.nim index 3c218bc13e..e3a9be2096 100644 --- a/src/app/profile/view.nim +++ b/src/app/profile/view.nim @@ -2,7 +2,7 @@ import NimQml import views/mailservers_list import views/contact_list import views/profile_info -import ../../models/profile +import ../../status/profile QtObject: type ProfileView* = ref object of QObject diff --git a/src/app/profile/views/contact_list.nim b/src/app/profile/views/contact_list.nim index 7e69f88026..30caab7f07 100644 --- a/src/app/profile/views/contact_list.nim +++ b/src/app/profile/views/contact_list.nim @@ -1,7 +1,7 @@ import NimQml import Tables import strformat -import ../../../models/profile +import ../../../status/profile type ContactRoles {.pure.} = enum diff --git a/src/app/profile/views/mailservers_list.nim b/src/app/profile/views/mailservers_list.nim index ba77abbc8d..f0d4ffd014 100644 --- a/src/app/profile/views/mailservers_list.nim +++ b/src/app/profile/views/mailservers_list.nim @@ -1,6 +1,6 @@ import NimQml import Tables -import ../../../models/profile +import ../../../status/profile type MailServerRoles {.pure.} = enum diff --git a/src/app/profile/views/profile_info.nim b/src/app/profile/views/profile_info.nim index a33320b788..5cf4823334 100644 --- a/src/app/profile/views/profile_info.nim +++ b/src/app/profile/views/profile_info.nim @@ -1,5 +1,5 @@ import NimQml -import ../../../models/profile +import ../../../status/profile QtObject: type ProfileInfoView* = ref object of QObject diff --git a/src/app/wallet/core.nim b/src/app/wallet/core.nim index 36d2cab94b..249e135a0e 100644 --- a/src/app/wallet/core.nim +++ b/src/app/wallet/core.nim @@ -5,8 +5,8 @@ import strutils import chronicles import view -import ../../status/wallet as status_wallet -import ../../models/wallet +import ../../status/libstatus/wallet as status_wallet +import ../../status/wallet import ../../signals/types type WalletController* = ref object of SignalSubscriber diff --git a/src/app/wallet/view.nim b/src/app/wallet/view.nim index 06abdfb441..864b40019e 100644 --- a/src/app/wallet/view.nim +++ b/src/app/wallet/view.nim @@ -1,7 +1,7 @@ import NimQml import Tables import views/asset_list -import ../../models/wallet +import ../../status/wallet QtObject: type diff --git a/src/app/wallet/views/asset_list.nim b/src/app/wallet/views/asset_list.nim index 7e03a80387..3390dde8e9 100644 --- a/src/app/wallet/views/asset_list.nim +++ b/src/app/wallet/views/asset_list.nim @@ -1,7 +1,7 @@ import NimQml import Tables import strformat -import ../../../models/wallet +import ../../../status/wallet type AssetRoles {.pure.} = enum diff --git a/src/models/accounts.nim b/src/models/accounts.nim deleted file mode 100644 index eabdf8876f..0000000000 --- a/src/models/accounts.nim +++ /dev/null @@ -1,31 +0,0 @@ -import ../status/accounts as status_accounts -import ../status/types -import options - -type - AccountModel* = ref object - generatedAddresses*: seq[GeneratedAccount] - nodeAccounts*: seq[NodeAccount] - currentAccount*: Account - -proc newAccountModel*(): AccountModel = - result = AccountModel() - result.currentAccount = nil - -proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] = - var accounts = status_accounts.generateAddresses() - for account in accounts.mitems: - account.name = status_accounts.generateAlias(account.derived.whisper.publicKey) - account.photoPath = status_accounts.generateIdenticon(account.derived.whisper.publicKey) - self.generatedAddresses.add(account) - self.generatedAddresses - -proc login*(self: AccountModel, selectedAccountIndex: int, password: string): NodeAccount = - let currentNodeAccount = self.nodeAccounts[selectedAccountIndex] - self.currentAccount = currentNodeAccount.toAccount - result = status_accounts.login(currentNodeAccount, password) - -proc storeAccountAndLogin*(self: AccountModel, selectedAccountIndex: int, password: string): Account = - let generatedAccount: GeneratedAccount = self.generatedAddresses[selectedAccountIndex] - result = status_accounts.setupAccount(generatedAccount, password) - self.currentAccount = generatedAccount.toAccount \ No newline at end of file diff --git a/src/models/chat.nim b/src/models/chat.nim deleted file mode 100644 index f6ecf4af4a..0000000000 --- a/src/models/chat.nim +++ /dev/null @@ -1,103 +0,0 @@ -import eventemitter, sets, json, strutils -import sequtils -import ../status/utils -import ../status/chat as status_chat -import chronicles -import ../signals/types -import chat/chat_item -import chat/chat_message -import tables -export chat_item -export chat_message - -type MsgArgs* = ref object of Args - message*: string - chatId*: string - payload*: JsonNode - -type ChannelArgs* = ref object of Args - channel*: string - chatTypeInt*: ChatType - -type ChatArgs* = ref object of Args - chats*: seq[Chat] - -type - ChatModel* = ref object - events*: EventEmitter - channels*: HashSet[string] - filters*: Table[string, string] - -proc newChatModel*(): ChatModel = - result = ChatModel() - result.events = createEventEmitter() - result.channels = initHashSet[string]() - result.filters = initTable[string, string]() - -proc delete*(self: ChatModel) = - discard - -proc hasChannel*(self: ChatModel, chatId: string): bool = - result = self.channels.contains(chatId) - -proc getActiveChannel*(self: ChatModel): string = - if (self.channels.len == 0): "" else: self.channels.toSeq[self.channels.len - 1] - -proc join*(self: ChatModel, chatId: string, chatTypeInt: ChatType, isNewChat: bool = true) = - if self.hasChannel(chatId): return - - self.channels.incl chatId - - let generatedSymKey = status_chat.generateSymKeyFromPassword() - - # TODO get this from the connection or something - let peer = "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443" - - let oneToOne = isOneToOneChat(chatId) - - if isNewChat: status_chat.saveChat(chatId, oneToOne) - - let filterResult = status_chat.loadFilters(chatId = chatId, oneToOne = oneToOne) - - status_chat.chatMessages(chatId) - - let parsedResult = parseJson(filterResult)["result"] - - var topics = newSeq[string](0) - for topicObj in parsedResult: - if (($topicObj["chatId"]).strip(chars = {'"'}) == chatId): - topics.add(($topicObj["topic"]).strip(chars = {'"'})) - - if(not self.filters.hasKey(chatId)): self.filters[chatId] = topicObj["filterId"].getStr - - if (topics.len == 0): - warn "No topic found for the chat. Cannot load past messages" - else: - status_chat.requestMessages(topics, generatedSymKey, peer, 20) - - self.events.emit("channelJoined", ChannelArgs(channel: chatId, chatTypeInt: chatTypeInt)) - self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel())) - -proc load*(self: ChatModel) = - let chatList = status_chat.loadChats() - for chat in chatList: - # TODO: use correct type of chat instead of hardcoded 2 (assumes it's only public chats) - self.join(chat.id, ChatType.Public, false) - self.events.emit("chatsLoaded", ChatArgs(chats: chatList)) - -proc leave*(self: ChatModel, chatId: string) = - status_chat.removeFilters(chatId, self.filters[chatId]) - status_chat.deactivateChat(chatId) - # TODO: REMOVE MAILSERVER TOPIC - # TODO: REMOVE HISTORY - - self.filters.del(chatId) - self.channels.excl(chatId) - self.events.emit("channelLeft", ChannelArgs(channel: chatId)) - self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel())) - -proc sendMessage*(self: ChatModel, chatId: string, msg: string): string = - var sentMessage = status_chat.sendChatMessage(chatId, msg) - var parsedMessage = parseJson(sentMessage)["result"]["chats"][0]["lastMessage"] - self.events.emit("messageSent", MsgArgs(message: msg, chatId: chatId, payload: parsedMessage)) - sentMessage diff --git a/src/models/wallet.nim b/src/models/wallet.nim deleted file mode 100644 index 0abdba3ca5..0000000000 --- a/src/models/wallet.nim +++ /dev/null @@ -1,40 +0,0 @@ -import eventemitter -import json -import strformat -import strutils -import ../status/wallet as status_wallet - -type Asset* = ref object - name*, symbol*, value*, fiatValue*, image*: string - -type WalletModel* = ref object - events*: EventEmitter - -proc newWalletModel*(): WalletModel = - result = WalletModel() - result.events = createEventEmitter() - -proc delete*(self: WalletModel) = - discard - -proc sendTransaction*(self: WalletModel, from_value: string, to: string, value: string, password: string): string = - status_wallet.sendTransaction(from_value, to, value, password) - -proc getEthBalance*(self: WalletModel, address: string): string = - var balance = status_wallet.getBalance(address) - echo(fmt"balance in hex: {balance}") - - # 2. convert balance to eth - var eth_value = status_wallet.hex2Eth(balance) - echo(fmt"balance in eth: {eth_value}") - eth_value - -proc getFiatValue*(self: WalletModel, eth_balance: string, symbol: string, fiat_symbol: string): float = - # 3. get usd price of 1 eth - var usd_eth_price = status_wallet.getPrice("ETH", "USD") - echo(fmt"usd_price: {usd_eth_price}") - - # 4. convert balance to usd - var usd_balance = parseFloat(eth_balance) * parseFloat(usd_eth_price) - echo(fmt"balance in usd: {usd_balance}") - usd_balance diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index 678812b6a7..0bf1a4ec2b 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -8,12 +8,12 @@ import signals/core as signals import app/onboarding/core as onboarding import app/login/core as login import state -import status/accounts as status_accounts -import status/core as status_core -import status/types as types -import status/libstatus +import status/libstatus/accounts as status_accounts +import status/libstatus/core as status_core +import status/libstatus/types as types +import status/libstatus/libstatus +import status/libstatus/types import state -import status/types import eventemitter import json_serialization diff --git a/src/signals/core.nim b/src/signals/core.nim index d5e5f1f35f..e3b136dcb4 100644 --- a/src/signals/core.nim +++ b/src/signals/core.nim @@ -1,5 +1,5 @@ import NimQml -import ../status/types as status_types +import ../status/libstatus/types as status_types import tables import json import types diff --git a/src/signals/types.nim b/src/signals/types.nim index b0695fde05..f702b764f8 100644 --- a/src/signals/types.nim +++ b/src/signals/types.nim @@ -1,6 +1,6 @@ import json import chronicles -import ../status/types +import ../status/libstatus/types import json_serialization type SignalSubscriber* = ref object of RootObj diff --git a/src/status/accounts.nim b/src/status/accounts.nim index 77bdbea5a1..a620ebe3c5 100644 --- a/src/status/accounts.nim +++ b/src/status/accounts.nim @@ -1,161 +1,31 @@ -import libstatus -import core -import json -import utils -import accounts/constants -import nimcrypto -import os -import uuids -import types -import json_serialization -import chronicles +import libstatus/accounts as status_accounts +import libstatus/types +import options -proc queryAccounts*(): string = - var response = callPrivateRPC("eth_accounts") - result = parseJson(response)["result"][0].getStr() +type + AccountModel* = ref object + generatedAddresses*: seq[GeneratedAccount] + nodeAccounts*: seq[NodeAccount] + currentAccount*: Account -proc generateAddresses*(): seq[GeneratedAccount] = - let multiAccountConfig = %* { - "n": 5, - "mnemonicPhraseLength": 12, - "bip39Passphrase": "", - "paths": [PATH_WHISPER, PATH_WALLET_ROOT, PATH_DEFAULT_WALLET] - } - result = Json.decode($libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig), seq[GeneratedAccount]) +proc newAccountModel*(): AccountModel = + result = AccountModel() + result.currentAccount = nil -proc generateAlias*(publicKey: string): string = - result = $libstatus.generateAlias(publicKey.toGoString) +proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] = + var accounts = status_accounts.generateAddresses() + for account in accounts.mitems: + account.name = status_accounts.generateAlias(account.derived.whisper.publicKey) + account.photoPath = status_accounts.generateIdenticon(account.derived.whisper.publicKey) + self.generatedAddresses.add(account) + self.generatedAddresses -proc generateIdenticon*(publicKey: string): string = - result = $libstatus.identicon(publicKey.toGoString) +proc login*(self: AccountModel, selectedAccountIndex: int, password: string): NodeAccount = + let currentNodeAccount = self.nodeAccounts[selectedAccountIndex] + self.currentAccount = currentNodeAccount.toAccount + result = status_accounts.login(currentNodeAccount, password) -proc ensureDir(dirname: string) = - if not existsDir(dirname): - # removeDir(dirname) - createDir(dirname) - -proc initNodeAccounts*(): seq[NodeAccount] = - const datadir = "./data/" - const keystoredir = "./data/keystore/" - const nobackupdir = "./noBackup/" - - ensureDir(datadir) - ensureDir(keystoredir) - ensureDir(nobackupdir) - - discard $libstatus.initKeystore(keystoredir); - let strNodeAccounts = $libstatus.openAccounts(datadir); - result = Json.decode(strNodeAccounts, seq[NodeAccount]) - -proc saveAccountAndLogin*( - multiAccounts: MultiAccounts, - alias: string, - identicon: string, - accountData: string, - password: string, - configJSON: string, - settingsJSON: string): Account = - let hashedPassword = "0x" & $keccak_256.digest(password) - let subaccountData = %* [ - { - "public-key": multiAccounts.defaultWallet.publicKey, - "address": multiAccounts.defaultWallet.address, - "color": "#4360df", - "wallet": true, - "path": constants.PATH_DEFAULT_WALLET, - "name": "Status account" - }, - { - "public-key": multiAccounts.whisper.publicKey, - "address": multiAccounts.whisper.address, - "name": alias, - "photo-path": identicon, - "path": constants.PATH_WHISPER, - "chat": true - } - ] - - var savedResult = $libstatus.saveAccountAndLogin(accountData, hashedPassword, settingsJSON, configJSON, $subaccountData) - let parsedSavedResult = savedResult.parseJson - let error = parsedSavedResult["error"].getStr - - if error == "": - debug "Account saved succesfully" - result = Account(name: alias, photoPath: identicon) - return - - raise newException(LoginError, "Error saving account and logging in: " & error) - -proc generateMultiAccounts*(account: GeneratedAccount, password: string): MultiAccounts = - let hashedPassword = "0x" & $keccak_256.digest(password) - let multiAccount = %* { - "accountID": account.id, - "paths": [PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET], - "password": hashedPassword - } - var response = $libstatus.multiAccountStoreDerivedAccounts($multiAccount); - result = Json.decode($response, MultiAccounts) - -proc getAccountData*(account: GeneratedAccount, alias: string, identicon: string): JsonNode = - result = %* { - "name": alias, - "address": account.address, - "photo-path": identicon, - "key-uid": account.keyUid, - "keycard-pairing": nil - } - -proc getAccountSettings*(account: GeneratedAccount, alias: string, identicon: string, multiAccounts: MultiAccounts, defaultNetworks: JsonNode): JsonNode = - result = %* { - "key-uid": account.keyUid, - "mnemonic": account.mnemonic, - "public-key": multiAccounts.whisper.publicKey, - "name": alias, - "address": account.address, - "eip1581-address": multiAccounts.eip1581.address, - "dapps-address": multiAccounts.defaultWallet.address, - "wallet-root-address": multiAccounts.walletRoot.address, - "preview-privacy?": true, - "signing-phrase": generateSigningPhrase(3), - "log-level": "INFO", - "latest-derived-path": 0, - "networks/networks": defaultNetworks, - "currency": "usd", - "photo-path": identicon, - "waku-enabled": true, - "wallet/visible-tokens": { - "mainnet": ["SNT"] - }, - "appearance": 0, - "networks/current-network": "mainnet_rpc", - "installation-id": $genUUID() - } - -proc setupAccount*(account: GeneratedAccount, password: string): Account = - let multiAccounts = generateMultiAccounts(account, password) - - let whisperPubKey = account.derived.whisper.publicKey - let alias = generateAlias(whisperPubKey) - let identicon =generateIdenticon(whisperPubKey) - - let accountData = getAccountData(account, alias, identicon) - var settingsJSON = getAccountSettings(account, alias, identicon, multiAccounts, constants.DEFAULT_NETWORKS) - - result = saveAccountAndLogin(multiAccounts, alias, identicon, $accountData, password, $constants.NODE_CONFIG, $settingsJSON) - - # TODO this is needed for now for the retrieving of past messages. We'll either move or remove it later - let peer = "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443" - discard libstatus.addPeer(peer) - -proc login*(nodeAccount: NodeAccount, password: string): NodeAccount = - let hashedPassword = "0x" & $keccak_256.digest(password) - let account = nodeAccount.toAccount - let loginResult = $libstatus.login($toJson(account), hashedPassword) - let error = parseJson(loginResult)["error"].getStr - - if error == "": - debug "Login requested", user=nodeAccount.name - result = nodeAccount - return - - raise newException(LoginError, "Error logging in: " & error) +proc storeAccountAndLogin*(self: AccountModel, selectedAccountIndex: int, password: string): Account = + let generatedAccount: GeneratedAccount = self.generatedAddresses[selectedAccountIndex] + result = status_accounts.setupAccount(generatedAccount, password) + self.currentAccount = generatedAccount.toAccount \ No newline at end of file diff --git a/src/status/chat.nim b/src/status/chat.nim index 4803323224..15e8efab76 100644 --- a/src/status/chat.nim +++ b/src/status/chat.nim @@ -1,106 +1,103 @@ -import core -import json -import utils -import times -import strutils +import eventemitter, sets, json, strutils +import sequtils +import libstatus/utils +import libstatus/chat as status_chat import chronicles import ../signals/types -import ../signals/messages +import chat/chat_item +import chat/chat_message +import tables +export chat_item +export chat_message -proc loadFilters*(chatId: string, filterId: string = "", symKeyId: string = "", oneToOne: bool = false, identity: string = "", topic: string = "", discovery: bool = false, negotiated: bool = false, listen: bool = true): string = - result = callPrivateRPC("loadFilters".prefix, %* [ - [{ - "ChatID": chatId, # identifier of the chat - "FilterID": filterId, # whisper filter id generated - "SymKeyID": symKeyId, # symmetric key id used for symmetric filters - "OneToOne": oneToOne, # if asymmetric encryption is used for this chat - "Identity": identity, # public key of the other recipient for non-public filters. - # FIXME: passing empty string to the topic makes it error - # "Topic": topic, # whisper topic - "Discovery": discovery, - "Negotiated": negotiated, - "Listen": listen # whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic - }] - ]) +type MsgArgs* = ref object of Args + message*: string + chatId*: string + payload*: JsonNode -proc removeFilters*(chatId: string, filterId: string) = - discard callPrivateRPC("removeFilters".prefix, %* [ - [{ - "ChatID": chatId, - "FilterID": filterId - }] - ]) +type ChannelArgs* = ref object of Args + channel*: string + chatTypeInt*: ChatType -proc saveChat*(chatId: string, oneToOne: bool = false, active: bool = true) = - discard callPrivateRPC("saveChat".prefix, %* [ - { - "lastClockValue": 0, # TODO: - "color": "#51d0f0", # TODO: - "name": chatId, - "lastMessage": nil, # TODO: - "active": active, - "id": chatId, - "unviewedMessagesCount": 0, # TODO: - # TODO use constants for those too or use the Date - "chatType": if oneToOne: 1 else: 2, # TODO: use constants - "timestamp": 1588940692659 # TODO: - } - ]) +type ChatArgs* = ref object of Args + chats*: seq[Chat] -proc deactivateChat*(chatId: string) = - discard callPrivateRPC("saveChat".prefix, %* [ - { - "lastClockValue": 0, - "color": "", - "name": chatId, - "lastMessage": nil, - "active": false, - "id": chatId, - "unviewedMessagesCount": 0, - "timestamp": 0 - } - ]) +type + ChatModel* = ref object + events*: EventEmitter + channels*: HashSet[string] + filters*: Table[string, string] -proc loadChats*(): seq[Chat] = - result = @[] - let jsonResponse = parseJson($callPrivateRPC("chats".prefix)) - if jsonResponse["result"].kind != JNull: - for jsonChat in jsonResponse{"result"}: - let chat = jsonChat.toChat - if chat.active: result.add(jsonChat.toChat) +proc newChatModel*(): ChatModel = + result = ChatModel() + result.events = createEventEmitter() + result.channels = initHashSet[string]() + result.filters = initTable[string, string]() -proc chatMessages*(chatId: string) = - discard callPrivateRPC("chatMessages".prefix, %* [chatId, nil, 20]) +proc delete*(self: ChatModel) = + discard -# TODO this probably belongs in another file -proc generateSymKeyFromPassword*(): string = - result = ($parseJson(callPrivateRPC("waku_generateSymKeyFromPassword", %* [ - # TODO unhardcode this for non-status mailservers - "status-offline-inbox" - ]))["result"]).strip(chars = {'"'}) +proc hasChannel*(self: ChatModel, chatId: string): bool = + result = self.channels.contains(chatId) -proc requestMessages*(topics: seq[string], symKeyID: string, peer: string, numberOfMessages: int) = - discard callPrivateRPC("requestMessages".prefix, %* [ - { - "topics": topics, - "mailServerPeer": peer, - "symKeyID": symKeyID, - "timeout": 30, - "limit": numberOfMessages, - "cursor": nil, - "from": times.toUnix(times.getTime()) - 30000 # Unhardcode this. Need to keep the last fetch in a DB - } - ]) +proc getActiveChannel*(self: ChatModel): string = + if (self.channels.len == 0): "" else: self.channels.toSeq[self.channels.len - 1] +proc join*(self: ChatModel, chatId: string, chatTypeInt: ChatType, isNewChat: bool = true) = + if self.hasChannel(chatId): return -proc sendChatMessage*(chatId: string, msg: string): string = - callPrivateRPC("sendChatMessage".prefix, %* [ - { - "chatId": chatId, - "text": msg, - "responseTo": nil, - "ensName": nil, - "sticker": nil, - "contentType": 1 - } - ]) + self.channels.incl chatId + + let generatedSymKey = status_chat.generateSymKeyFromPassword() + + # TODO get this from the connection or something + let peer = "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443" + + let oneToOne = isOneToOneChat(chatId) + + if isNewChat: status_chat.saveChat(chatId, oneToOne) + + let filterResult = status_chat.loadFilters(chatId = chatId, oneToOne = oneToOne) + + status_chat.chatMessages(chatId) + + let parsedResult = parseJson(filterResult)["result"] + + var topics = newSeq[string](0) + for topicObj in parsedResult: + if (($topicObj["chatId"]).strip(chars = {'"'}) == chatId): + topics.add(($topicObj["topic"]).strip(chars = {'"'})) + + if(not self.filters.hasKey(chatId)): self.filters[chatId] = topicObj["filterId"].getStr + + if (topics.len == 0): + warn "No topic found for the chat. Cannot load past messages" + else: + status_chat.requestMessages(topics, generatedSymKey, peer, 20) + + self.events.emit("channelJoined", ChannelArgs(channel: chatId, chatTypeInt: chatTypeInt)) + self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel())) + +proc load*(self: ChatModel) = + let chatList = status_chat.loadChats() + for chat in chatList: + # TODO: use correct type of chat instead of hardcoded 2 (assumes it's only public chats) + self.join(chat.id, ChatType.Public, false) + self.events.emit("chatsLoaded", ChatArgs(chats: chatList)) + +proc leave*(self: ChatModel, chatId: string) = + status_chat.removeFilters(chatId, self.filters[chatId]) + status_chat.deactivateChat(chatId) + # TODO: REMOVE MAILSERVER TOPIC + # TODO: REMOVE HISTORY + + self.filters.del(chatId) + self.channels.excl(chatId) + self.events.emit("channelLeft", ChannelArgs(channel: chatId)) + self.events.emit("activeChannelChanged", ChannelArgs(channel: self.getActiveChannel())) + +proc sendMessage*(self: ChatModel, chatId: string, msg: string): string = + var sentMessage = status_chat.sendChatMessage(chatId, msg) + var parsedMessage = parseJson(sentMessage)["result"]["chats"][0]["lastMessage"] + self.events.emit("messageSent", MsgArgs(message: msg, chatId: chatId, payload: parsedMessage)) + sentMessage diff --git a/src/models/chat/chat_item.nim b/src/status/chat/chat_item.nim similarity index 97% rename from src/models/chat/chat_item.nim rename to src/status/chat/chat_item.nim index f5af7238e8..e6da21a4a9 100644 --- a/src/models/chat/chat_item.nim +++ b/src/status/chat/chat_item.nim @@ -1,5 +1,5 @@ import ../../signals/types -import ../../status/accounts as status_accounts +import ../libstatus/accounts as status_accounts type ChatItem* = ref object id*: string diff --git a/src/models/chat/chat_message.nim b/src/status/chat/chat_message.nim similarity index 100% rename from src/models/chat/chat_message.nim rename to src/status/chat/chat_message.nim diff --git a/src/models/chat/stickers.nim b/src/status/chat/stickers.nim similarity index 100% rename from src/models/chat/stickers.nim rename to src/status/chat/stickers.nim diff --git a/src/status/libstatus/accounts.nim b/src/status/libstatus/accounts.nim new file mode 100644 index 0000000000..77bdbea5a1 --- /dev/null +++ b/src/status/libstatus/accounts.nim @@ -0,0 +1,161 @@ +import libstatus +import core +import json +import utils +import accounts/constants +import nimcrypto +import os +import uuids +import types +import json_serialization +import chronicles + +proc queryAccounts*(): string = + var response = callPrivateRPC("eth_accounts") + result = parseJson(response)["result"][0].getStr() + +proc generateAddresses*(): seq[GeneratedAccount] = + let multiAccountConfig = %* { + "n": 5, + "mnemonicPhraseLength": 12, + "bip39Passphrase": "", + "paths": [PATH_WHISPER, PATH_WALLET_ROOT, PATH_DEFAULT_WALLET] + } + result = Json.decode($libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig), seq[GeneratedAccount]) + +proc generateAlias*(publicKey: string): string = + result = $libstatus.generateAlias(publicKey.toGoString) + +proc generateIdenticon*(publicKey: string): string = + result = $libstatus.identicon(publicKey.toGoString) + +proc ensureDir(dirname: string) = + if not existsDir(dirname): + # removeDir(dirname) + createDir(dirname) + +proc initNodeAccounts*(): seq[NodeAccount] = + const datadir = "./data/" + const keystoredir = "./data/keystore/" + const nobackupdir = "./noBackup/" + + ensureDir(datadir) + ensureDir(keystoredir) + ensureDir(nobackupdir) + + discard $libstatus.initKeystore(keystoredir); + let strNodeAccounts = $libstatus.openAccounts(datadir); + result = Json.decode(strNodeAccounts, seq[NodeAccount]) + +proc saveAccountAndLogin*( + multiAccounts: MultiAccounts, + alias: string, + identicon: string, + accountData: string, + password: string, + configJSON: string, + settingsJSON: string): Account = + let hashedPassword = "0x" & $keccak_256.digest(password) + let subaccountData = %* [ + { + "public-key": multiAccounts.defaultWallet.publicKey, + "address": multiAccounts.defaultWallet.address, + "color": "#4360df", + "wallet": true, + "path": constants.PATH_DEFAULT_WALLET, + "name": "Status account" + }, + { + "public-key": multiAccounts.whisper.publicKey, + "address": multiAccounts.whisper.address, + "name": alias, + "photo-path": identicon, + "path": constants.PATH_WHISPER, + "chat": true + } + ] + + var savedResult = $libstatus.saveAccountAndLogin(accountData, hashedPassword, settingsJSON, configJSON, $subaccountData) + let parsedSavedResult = savedResult.parseJson + let error = parsedSavedResult["error"].getStr + + if error == "": + debug "Account saved succesfully" + result = Account(name: alias, photoPath: identicon) + return + + raise newException(LoginError, "Error saving account and logging in: " & error) + +proc generateMultiAccounts*(account: GeneratedAccount, password: string): MultiAccounts = + let hashedPassword = "0x" & $keccak_256.digest(password) + let multiAccount = %* { + "accountID": account.id, + "paths": [PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET], + "password": hashedPassword + } + var response = $libstatus.multiAccountStoreDerivedAccounts($multiAccount); + result = Json.decode($response, MultiAccounts) + +proc getAccountData*(account: GeneratedAccount, alias: string, identicon: string): JsonNode = + result = %* { + "name": alias, + "address": account.address, + "photo-path": identicon, + "key-uid": account.keyUid, + "keycard-pairing": nil + } + +proc getAccountSettings*(account: GeneratedAccount, alias: string, identicon: string, multiAccounts: MultiAccounts, defaultNetworks: JsonNode): JsonNode = + result = %* { + "key-uid": account.keyUid, + "mnemonic": account.mnemonic, + "public-key": multiAccounts.whisper.publicKey, + "name": alias, + "address": account.address, + "eip1581-address": multiAccounts.eip1581.address, + "dapps-address": multiAccounts.defaultWallet.address, + "wallet-root-address": multiAccounts.walletRoot.address, + "preview-privacy?": true, + "signing-phrase": generateSigningPhrase(3), + "log-level": "INFO", + "latest-derived-path": 0, + "networks/networks": defaultNetworks, + "currency": "usd", + "photo-path": identicon, + "waku-enabled": true, + "wallet/visible-tokens": { + "mainnet": ["SNT"] + }, + "appearance": 0, + "networks/current-network": "mainnet_rpc", + "installation-id": $genUUID() + } + +proc setupAccount*(account: GeneratedAccount, password: string): Account = + let multiAccounts = generateMultiAccounts(account, password) + + let whisperPubKey = account.derived.whisper.publicKey + let alias = generateAlias(whisperPubKey) + let identicon =generateIdenticon(whisperPubKey) + + let accountData = getAccountData(account, alias, identicon) + var settingsJSON = getAccountSettings(account, alias, identicon, multiAccounts, constants.DEFAULT_NETWORKS) + + result = saveAccountAndLogin(multiAccounts, alias, identicon, $accountData, password, $constants.NODE_CONFIG, $settingsJSON) + + # TODO this is needed for now for the retrieving of past messages. We'll either move or remove it later + let peer = "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443" + discard libstatus.addPeer(peer) + +proc login*(nodeAccount: NodeAccount, password: string): NodeAccount = + let hashedPassword = "0x" & $keccak_256.digest(password) + let account = nodeAccount.toAccount + let loginResult = $libstatus.login($toJson(account), hashedPassword) + let error = parseJson(loginResult)["error"].getStr + + if error == "": + debug "Login requested", user=nodeAccount.name + result = nodeAccount + return + + raise newException(LoginError, "Error logging in: " & error) diff --git a/src/status/accounts/constants.nim b/src/status/libstatus/accounts/constants.nim similarity index 100% rename from src/status/accounts/constants.nim rename to src/status/libstatus/accounts/constants.nim diff --git a/src/status/accounts/signing_phrases.nim b/src/status/libstatus/accounts/signing_phrases.nim similarity index 100% rename from src/status/accounts/signing_phrases.nim rename to src/status/libstatus/accounts/signing_phrases.nim diff --git a/src/status/libstatus/chat.nim b/src/status/libstatus/chat.nim new file mode 100644 index 0000000000..0fbaa8e31a --- /dev/null +++ b/src/status/libstatus/chat.nim @@ -0,0 +1,106 @@ +import core +import json +import utils +import times +import strutils +import chronicles +import ../../signals/types +import ../../signals/messages + +proc loadFilters*(chatId: string, filterId: string = "", symKeyId: string = "", oneToOne: bool = false, identity: string = "", topic: string = "", discovery: bool = false, negotiated: bool = false, listen: bool = true): string = + result = callPrivateRPC("loadFilters".prefix, %* [ + [{ + "ChatID": chatId, # identifier of the chat + "FilterID": filterId, # whisper filter id generated + "SymKeyID": symKeyId, # symmetric key id used for symmetric filters + "OneToOne": oneToOne, # if asymmetric encryption is used for this chat + "Identity": identity, # public key of the other recipient for non-public filters. + # FIXME: passing empty string to the topic makes it error + # "Topic": topic, # whisper topic + "Discovery": discovery, + "Negotiated": negotiated, + "Listen": listen # whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic + }] + ]) + +proc removeFilters*(chatId: string, filterId: string) = + discard callPrivateRPC("removeFilters".prefix, %* [ + [{ + "ChatID": chatId, + "FilterID": filterId + }] + ]) + +proc saveChat*(chatId: string, oneToOne: bool = false, active: bool = true) = + discard callPrivateRPC("saveChat".prefix, %* [ + { + "lastClockValue": 0, # TODO: + "color": "#51d0f0", # TODO: + "name": chatId, + "lastMessage": nil, # TODO: + "active": active, + "id": chatId, + "unviewedMessagesCount": 0, # TODO: + # TODO use constants for those too or use the Date + "chatType": if oneToOne: 1 else: 2, # TODO: use constants + "timestamp": 1588940692659 # TODO: + } + ]) + +proc deactivateChat*(chatId: string) = + discard callPrivateRPC("saveChat".prefix, %* [ + { + "lastClockValue": 0, + "color": "", + "name": chatId, + "lastMessage": nil, + "active": false, + "id": chatId, + "unviewedMessagesCount": 0, + "timestamp": 0 + } + ]) + +proc loadChats*(): seq[Chat] = + result = @[] + let jsonResponse = parseJson($callPrivateRPC("chats".prefix)) + if jsonResponse["result"].kind != JNull: + for jsonChat in jsonResponse{"result"}: + let chat = jsonChat.toChat + if chat.active: result.add(jsonChat.toChat) + +proc chatMessages*(chatId: string) = + discard callPrivateRPC("chatMessages".prefix, %* [chatId, nil, 20]) + +# TODO this probably belongs in another file +proc generateSymKeyFromPassword*(): string = + result = ($parseJson(callPrivateRPC("waku_generateSymKeyFromPassword", %* [ + # TODO unhardcode this for non-status mailservers + "status-offline-inbox" + ]))["result"]).strip(chars = {'"'}) + +proc requestMessages*(topics: seq[string], symKeyID: string, peer: string, numberOfMessages: int) = + discard callPrivateRPC("requestMessages".prefix, %* [ + { + "topics": topics, + "mailServerPeer": peer, + "symKeyID": symKeyID, + "timeout": 30, + "limit": numberOfMessages, + "cursor": nil, + "from": times.toUnix(times.getTime()) - 30000 # Unhardcode this. Need to keep the last fetch in a DB + } + ]) + + +proc sendChatMessage*(chatId: string, msg: string): string = + callPrivateRPC("sendChatMessage".prefix, %* [ + { + "chatId": chatId, + "text": msg, + "responseTo": nil, + "ensName": nil, + "sticker": nil, + "contentType": 1 + } + ]) diff --git a/src/status/core.nim b/src/status/libstatus/core.nim similarity index 100% rename from src/status/core.nim rename to src/status/libstatus/core.nim diff --git a/src/status/libstatus.nim b/src/status/libstatus/libstatus.nim similarity index 100% rename from src/status/libstatus.nim rename to src/status/libstatus/libstatus.nim diff --git a/src/status/mailservers.nim b/src/status/libstatus/mailservers.nim similarity index 100% rename from src/status/mailservers.nim rename to src/status/libstatus/mailservers.nim diff --git a/src/status/types.nim b/src/status/libstatus/types.nim similarity index 100% rename from src/status/types.nim rename to src/status/libstatus/types.nim diff --git a/src/status/utils.nim b/src/status/libstatus/utils.nim similarity index 100% rename from src/status/utils.nim rename to src/status/libstatus/utils.nim diff --git a/src/status/libstatus/wallet.nim b/src/status/libstatus/wallet.nim new file mode 100644 index 0000000000..665aa7a803 --- /dev/null +++ b/src/status/libstatus/wallet.nim @@ -0,0 +1,43 @@ +import core as status +import json +# import utils +import httpclient, json +import strformat +import stint +import strutils + +proc getAccounts*(): seq[string] = + var response = callPrivateRPC("eth_accounts") + result = parseJson(response)["result"].to(seq[string]) + +proc getAccount*(): string = + var accounts = getAccounts() + result = accounts[0] + +proc sendTransaction*(from_address: string, to: string, value: string, password: string): string = + var args = %* { + "value": fmt"0x{toHex(value)}", + "from": from_address, + "to": to + } + var response = status.sendTransaction($args, password) + result = response + +proc getPrice*(crypto: string, fiat: string): string = + var url: string = fmt"https://min-api.cryptocompare.com/data/price?fsym={crypto}&tsyms={fiat}" + let client = newHttpClient() + client.headers = newHttpHeaders({ "Content-Type": "application/json" }) + + let response = client.request(url) + $parseJson(response.body)["USD"] + +proc getBalance*(address: string): string = + let payload = %* [address, "latest"] + parseJson(status.callPrivateRPC("eth_getBalance", payload))["result"].str + +proc hex2Eth*(input: string): string = + var value = fromHex(Stuint[256], input) + var one_eth = fromHex(Stuint[256], "DE0B6B3A7640000") + + var (eth, remainder) = divmod(value, one_eth) + fmt"{eth}.{remainder}" diff --git a/src/models/node.nim b/src/status/node.nim similarity index 92% rename from src/models/node.nim rename to src/status/node.nim index a50cc3bd7e..722fa1e3fe 100644 --- a/src/models/node.nim +++ b/src/status/node.nim @@ -2,7 +2,7 @@ import eventemitter # import json # import strformat # import strutils -import "../status/core" as status +import libstatus/core as status type NodeModel* = ref object events*: EventEmitter diff --git a/src/models/profile.nim b/src/status/profile.nim similarity index 93% rename from src/models/profile.nim rename to src/status/profile.nim index db90281894..125670b4e8 100644 --- a/src/models/profile.nim +++ b/src/status/profile.nim @@ -1,5 +1,5 @@ import eventemitter -import ../status/types +import libstatus/types type MailServer* = ref object diff --git a/src/status/wallet.nim b/src/status/wallet.nim index 665aa7a803..187b798e80 100644 --- a/src/status/wallet.nim +++ b/src/status/wallet.nim @@ -1,43 +1,40 @@ -import core as status +import eventemitter import json -# import utils -import httpclient, json import strformat -import stint import strutils +import libstatus/wallet as status_wallet -proc getAccounts*(): seq[string] = - var response = callPrivateRPC("eth_accounts") - result = parseJson(response)["result"].to(seq[string]) +type Asset* = ref object + name*, symbol*, value*, fiatValue*, image*: string -proc getAccount*(): string = - var accounts = getAccounts() - result = accounts[0] +type WalletModel* = ref object + events*: EventEmitter -proc sendTransaction*(from_address: string, to: string, value: string, password: string): string = - var args = %* { - "value": fmt"0x{toHex(value)}", - "from": from_address, - "to": to - } - var response = status.sendTransaction($args, password) - result = response +proc newWalletModel*(): WalletModel = + result = WalletModel() + result.events = createEventEmitter() -proc getPrice*(crypto: string, fiat: string): string = - var url: string = fmt"https://min-api.cryptocompare.com/data/price?fsym={crypto}&tsyms={fiat}" - let client = newHttpClient() - client.headers = newHttpHeaders({ "Content-Type": "application/json" }) +proc delete*(self: WalletModel) = + discard - let response = client.request(url) - $parseJson(response.body)["USD"] +proc sendTransaction*(self: WalletModel, from_value: string, to: string, value: string, password: string): string = + status_wallet.sendTransaction(from_value, to, value, password) -proc getBalance*(address: string): string = - let payload = %* [address, "latest"] - parseJson(status.callPrivateRPC("eth_getBalance", payload))["result"].str +proc getEthBalance*(self: WalletModel, address: string): string = + var balance = status_wallet.getBalance(address) + echo(fmt"balance in hex: {balance}") -proc hex2Eth*(input: string): string = - var value = fromHex(Stuint[256], input) - var one_eth = fromHex(Stuint[256], "DE0B6B3A7640000") + # 2. convert balance to eth + var eth_value = status_wallet.hex2Eth(balance) + echo(fmt"balance in eth: {eth_value}") + eth_value - var (eth, remainder) = divmod(value, one_eth) - fmt"{eth}.{remainder}" +proc getFiatValue*(self: WalletModel, eth_balance: string, symbol: string, fiat_symbol: string): float = + # 3. get usd price of 1 eth + var usd_eth_price = status_wallet.getPrice("ETH", "USD") + echo(fmt"usd_price: {usd_eth_price}") + + # 4. convert balance to usd + var usd_balance = parseFloat(eth_balance) * parseFloat(usd_eth_price) + echo(fmt"balance in usd: {usd_balance}") + usd_balance