move 'models' to status lib for clarity
This commit is contained in:
parent
f16de508ed
commit
73069255cd
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,7 +3,7 @@ import Tables
|
|||
import strformat
|
||||
import random
|
||||
|
||||
import ../../../models/chat
|
||||
import ../../../status/chat
|
||||
|
||||
const accountColors* = [
|
||||
"#9B832F",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import NimQml, Tables
|
||||
import ../../../models/chat
|
||||
import ../../../status/chat
|
||||
|
||||
type
|
||||
ChatMessageRoles {.pure.} = enum
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import NimQml
|
||||
import ../../models/node
|
||||
import ../../status/node
|
||||
|
||||
QtObject:
|
||||
type NodeView* = ref object of QObject
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import NimQml
|
||||
import Tables
|
||||
import strformat
|
||||
import ../../../models/profile
|
||||
import ../../../status/profile
|
||||
|
||||
type
|
||||
ContactRoles {.pure.} = enum
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import NimQml
|
||||
import Tables
|
||||
import ../../../models/profile
|
||||
import ../../../status/profile
|
||||
|
||||
type
|
||||
MailServerRoles {.pure.} = enum
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import NimQml
|
||||
import ../../../models/profile
|
||||
import ../../../status/profile
|
||||
|
||||
QtObject:
|
||||
type ProfileInfoView* = ref object of QObject
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import NimQml
|
||||
import Tables
|
||||
import views/asset_list
|
||||
import ../../models/wallet
|
||||
import ../../status/wallet
|
||||
|
||||
QtObject:
|
||||
type
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import NimQml
|
||||
import Tables
|
||||
import strformat
|
||||
import ../../../models/wallet
|
||||
import ../../../status/wallet
|
||||
|
||||
type
|
||||
AssetRoles {.pure.} = enum
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import json
|
||||
import chronicles
|
||||
import ../status/types
|
||||
import ../status/libstatus/types
|
||||
import json_serialization
|
||||
|
||||
type SignalSubscriber* = ref object of RootObj
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
||||
}
|
||||
])
|
|
@ -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}"
|
|
@ -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
|
|
@ -1,5 +1,5 @@
|
|||
import eventemitter
|
||||
import ../status/types
|
||||
import libstatus/types
|
||||
|
||||
type
|
||||
MailServer* = ref object
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue