mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-18 01:27:25 +00:00
fix(@desktop/wallet): show all tokens in wallet that have balance > 0
Fixes #5859
This commit is contained in:
parent
64882dffbe
commit
3a3b2c9dc9
@ -1,8 +1,10 @@
|
|||||||
import NimQml
|
import NimQml, Tables
|
||||||
|
|
||||||
import ../../../../global/global_singleton
|
import ../../../../global/global_singleton
|
||||||
import ../../../../core/eventemitter
|
import ../../../../core/eventemitter
|
||||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||||
|
import ../../../shared_models/token_model as token_model
|
||||||
|
import ../../../shared_models/token_item as token_item
|
||||||
|
|
||||||
import ./io_interface, ./view, ./controller
|
import ./io_interface, ./view, ./controller
|
||||||
import ../io_interface as delegate_interface
|
import ../io_interface as delegate_interface
|
||||||
@ -18,6 +20,8 @@ type
|
|||||||
moduleLoaded: bool
|
moduleLoaded: bool
|
||||||
currentAccountIndex: int
|
currentAccountIndex: int
|
||||||
|
|
||||||
|
proc onTokensRebuilt(self: Module, accountsTokens: OrderedTable[string, seq[WalletTokenDto]])
|
||||||
|
|
||||||
proc newModule*(
|
proc newModule*(
|
||||||
delegate: delegate_interface.AccessInterface,
|
delegate: delegate_interface.AccessInterface,
|
||||||
events: EventEmitter,
|
events: EventEmitter,
|
||||||
@ -34,10 +38,21 @@ proc newModule*(
|
|||||||
method delete*(self: Module) =
|
method delete*(self: Module) =
|
||||||
self.view.delete
|
self.view.delete
|
||||||
|
|
||||||
|
proc setAssets(self: Module, tokens: seq[WalletTokenDto]) =
|
||||||
|
var items: seq[Item]
|
||||||
|
for t in tokens:
|
||||||
|
if(t.totalBalance.balance == 0):
|
||||||
|
continue
|
||||||
|
let item = token_item.initItem(t.name, t.symbol, t.totalBalance.balance, t.address, t.totalBalance.currencyBalance)
|
||||||
|
items.add(item)
|
||||||
|
|
||||||
|
self.view.getAssetsModel().setItems(items)
|
||||||
|
|
||||||
method switchAccount*(self: Module, accountIndex: int) =
|
method switchAccount*(self: Module, accountIndex: int) =
|
||||||
self.currentAccountIndex = accountIndex
|
self.currentAccountIndex = accountIndex
|
||||||
let walletAccount = self.controller.getWalletAccount(accountIndex)
|
let walletAccount = self.controller.getWalletAccount(accountIndex)
|
||||||
self.view.setData(walletAccount)
|
self.view.setData(walletAccount)
|
||||||
|
self.setAssets(walletAccount.tokens)
|
||||||
|
|
||||||
method load*(self: Module) =
|
method load*(self: Module) =
|
||||||
singletonInstance.engine.setRootContextProperty("browserSectionCurrentAccount", newQVariant(self.view))
|
singletonInstance.engine.setRootContextProperty("browserSectionCurrentAccount", newQVariant(self.view))
|
||||||
@ -47,6 +62,10 @@ method load*(self: Module) =
|
|||||||
self.switchAccount(0)
|
self.switchAccount(0)
|
||||||
self.view.connectedAccountDeleted()
|
self.view.connectedAccountDeleted()
|
||||||
|
|
||||||
|
self.events.on(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e:Args):
|
||||||
|
let arg = TokensPerAccountArgs(e)
|
||||||
|
self.onTokensRebuilt(arg.accountsTokens)
|
||||||
|
|
||||||
self.controller.init()
|
self.controller.init()
|
||||||
self.view.load()
|
self.view.load()
|
||||||
self.switchAccount(0)
|
self.switchAccount(0)
|
||||||
@ -60,3 +79,9 @@ method viewDidLoad*(self: Module) =
|
|||||||
method switchAccountByAddress*(self: Module, address: string) =
|
method switchAccountByAddress*(self: Module, address: string) =
|
||||||
let accountIndex = self.controller.getIndex(address)
|
let accountIndex = self.controller.getIndex(address)
|
||||||
self.switchAccount(accountIndex)
|
self.switchAccount(accountIndex)
|
||||||
|
|
||||||
|
proc onTokensRebuilt(self: Module, accountsTokens: OrderedTable[string, seq[WalletTokenDto]]) =
|
||||||
|
let walletAccount = self.controller.getWalletAccount(self.currentAccountIndex)
|
||||||
|
if not accountsTokens.contains(walletAccount.address):
|
||||||
|
return
|
||||||
|
self.setAssets(accountsTokens[walletAccount.address])
|
@ -25,12 +25,14 @@ QtObject:
|
|||||||
self.QObject.setup
|
self.QObject.setup
|
||||||
|
|
||||||
proc delete*(self: View) =
|
proc delete*(self: View) =
|
||||||
|
self.assets.delete
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.delegate = delegate
|
|
||||||
result.setup()
|
result.setup()
|
||||||
|
result.delegate = delegate
|
||||||
|
result.assets = token_model.newModel()
|
||||||
|
|
||||||
proc load*(self: View) =
|
proc load*(self: View) =
|
||||||
self.delegate.viewDidLoad()
|
self.delegate.viewDidLoad()
|
||||||
@ -107,11 +109,12 @@ QtObject:
|
|||||||
read = getCurrencyBalance
|
read = getCurrencyBalance
|
||||||
notify = currencyBalanceChanged
|
notify = currencyBalanceChanged
|
||||||
|
|
||||||
proc getAssets(self: View): QVariant {.slot.} =
|
proc getAssetsModel*(self: View): token_model.Model =
|
||||||
return newQVariant(self.assets)
|
return self.assets
|
||||||
|
|
||||||
proc assetsChanged(self: View) {.signal.}
|
proc assetsChanged(self: View) {.signal.}
|
||||||
|
proc getAssets*(self: View): QVariant {.slot.} =
|
||||||
|
return newQVariant(self.assets)
|
||||||
QtProperty[QVariant] assets:
|
QtProperty[QVariant] assets:
|
||||||
read = getAssets
|
read = getAssets
|
||||||
notify = assetsChanged
|
notify = assetsChanged
|
||||||
@ -151,20 +154,6 @@ proc setData*(self: View, dto: wallet_account_service.WalletAccountDto) =
|
|||||||
self.emoji = dto.emoji
|
self.emoji = dto.emoji
|
||||||
self.emojiChanged()
|
self.emojiChanged()
|
||||||
|
|
||||||
let assets = token_model.newModel()
|
|
||||||
|
|
||||||
assets.setItems(
|
|
||||||
dto.tokens.map(t => token_item.initItem(
|
|
||||||
t.name,
|
|
||||||
t.symbol,
|
|
||||||
t.balance.chainBalance,
|
|
||||||
t.address,
|
|
||||||
t.balance.currencyBalance,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
self.assets = assets
|
|
||||||
self.assetsChanged()
|
|
||||||
|
|
||||||
proc isAddressCurrentAccount*(self: View, address: string): bool =
|
proc isAddressCurrentAccount*(self: View, address: string): bool =
|
||||||
return self.address == address
|
return self.address == address
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@ method refreshWalletAccounts*(self: Module) =
|
|||||||
w.tokens.map(t => token_item.initItem(
|
w.tokens.map(t => token_item.initItem(
|
||||||
t.name,
|
t.name,
|
||||||
t.symbol,
|
t.symbol,
|
||||||
t.balance.chainBalance,
|
t.totalBalance.balance,
|
||||||
t.address,
|
t.address,
|
||||||
t.balance.currencyBalance,
|
t.totalBalance.currencyBalance,
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import NimQml
|
import NimQml, Tables
|
||||||
|
|
||||||
import ../../../../global/global_singleton
|
import ../../../../global/global_singleton
|
||||||
import ../../../../core/eventemitter
|
import ../../../../core/eventemitter
|
||||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||||
|
import ../../../shared_models/token_model as token_model
|
||||||
|
import ../../../shared_models/token_item as token_item
|
||||||
|
|
||||||
import ./io_interface, ./view, ./controller
|
import ./io_interface, ./view, ./controller
|
||||||
import ../io_interface as delegate_interface
|
import ../io_interface as delegate_interface
|
||||||
@ -18,6 +20,8 @@ type
|
|||||||
moduleLoaded: bool
|
moduleLoaded: bool
|
||||||
currentAccountIndex: int
|
currentAccountIndex: int
|
||||||
|
|
||||||
|
proc onTokensRebuilt(self: Module, accountsTokens: OrderedTable[string, seq[WalletTokenDto]])
|
||||||
|
|
||||||
proc newModule*(
|
proc newModule*(
|
||||||
delegate: delegate_interface.AccessInterface,
|
delegate: delegate_interface.AccessInterface,
|
||||||
events: EventEmitter,
|
events: EventEmitter,
|
||||||
@ -50,6 +54,10 @@ method load*(self: Module) =
|
|||||||
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args):
|
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args):
|
||||||
self.switchAccount(self.currentAccountIndex)
|
self.switchAccount(self.currentAccountIndex)
|
||||||
|
|
||||||
|
self.events.on(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e:Args):
|
||||||
|
let arg = TokensPerAccountArgs(e)
|
||||||
|
self.onTokensRebuilt(arg.accountsTokens)
|
||||||
|
|
||||||
self.controller.init()
|
self.controller.init()
|
||||||
self.view.load()
|
self.view.load()
|
||||||
|
|
||||||
@ -60,10 +68,30 @@ method viewDidLoad*(self: Module) =
|
|||||||
self.moduleLoaded = true
|
self.moduleLoaded = true
|
||||||
self.delegate.currentAccountModuleDidLoad()
|
self.delegate.currentAccountModuleDidLoad()
|
||||||
|
|
||||||
|
proc setAssetsAndBalance(self: Module, tokens: seq[WalletTokenDto]) =
|
||||||
|
var totalCurrencyBalanceForAllAssets = 0.0
|
||||||
|
var items: seq[Item]
|
||||||
|
for t in tokens:
|
||||||
|
if(t.totalBalance.balance == 0):
|
||||||
|
continue
|
||||||
|
let item = token_item.initItem(t.name, t.symbol, t.totalBalance.balance, t.address, t.totalBalance.currencyBalance)
|
||||||
|
items.add(item)
|
||||||
|
totalCurrencyBalanceForAllAssets += t.totalBalance.currencyBalance
|
||||||
|
|
||||||
|
self.view.getAssetsModel().setItems(items)
|
||||||
|
self.view.setCurrencyBalance(totalCurrencyBalanceForAllAssets)
|
||||||
|
|
||||||
method switchAccount*(self: Module, accountIndex: int) =
|
method switchAccount*(self: Module, accountIndex: int) =
|
||||||
self.currentAccountIndex = accountIndex
|
self.currentAccountIndex = accountIndex
|
||||||
let walletAccount = self.controller.getWalletAccount(accountIndex)
|
let walletAccount = self.controller.getWalletAccount(accountIndex)
|
||||||
self.view.setData(walletAccount)
|
self.view.setData(walletAccount)
|
||||||
|
self.setAssetsAndBalance(walletAccount.tokens)
|
||||||
|
|
||||||
method update*(self: Module, address: string, accountName: string, color: string, emoji: string) =
|
method update*(self: Module, address: string, accountName: string, color: string, emoji: string) =
|
||||||
self.controller.update(address, accountName, color, emoji)
|
self.controller.update(address, accountName, color, emoji)
|
||||||
|
|
||||||
|
proc onTokensRebuilt(self: Module, accountsTokens: OrderedTable[string, seq[WalletTokenDto]]) =
|
||||||
|
let walletAccount = self.controller.getWalletAccount(self.currentAccountIndex)
|
||||||
|
if not accountsTokens.contains(walletAccount.address):
|
||||||
|
return
|
||||||
|
self.setAssetsAndBalance(accountsTokens[walletAccount.address])
|
@ -25,12 +25,14 @@ QtObject:
|
|||||||
self.QObject.setup
|
self.QObject.setup
|
||||||
|
|
||||||
proc delete*(self: View) =
|
proc delete*(self: View) =
|
||||||
|
self.assets.delete
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.delegate = delegate
|
|
||||||
result.setup()
|
result.setup()
|
||||||
|
result.delegate = delegate
|
||||||
|
result.assets = token_model.newModel()
|
||||||
|
|
||||||
proc load*(self: View) =
|
proc load*(self: View) =
|
||||||
self.delegate.viewDidLoad()
|
self.delegate.viewDidLoad()
|
||||||
@ -103,20 +105,22 @@ QtObject:
|
|||||||
read = getIsChat
|
read = getIsChat
|
||||||
notify = isChatChanged
|
notify = isChatChanged
|
||||||
|
|
||||||
proc getCurrencyBalance(self: View): QVariant {.slot.} =
|
|
||||||
return newQVariant(self.currencyBalance)
|
|
||||||
|
|
||||||
proc currencyBalanceChanged(self: View) {.signal.}
|
proc currencyBalanceChanged(self: View) {.signal.}
|
||||||
|
proc getCurrencyBalance*(self: View): QVariant {.slot.} =
|
||||||
|
return newQVariant(self.currencyBalance)
|
||||||
|
proc setCurrencyBalance*(self: View, value: float) =
|
||||||
|
self.currencyBalance = value
|
||||||
|
self.currencyBalanceChanged()
|
||||||
QtProperty[QVariant] currencyBalance:
|
QtProperty[QVariant] currencyBalance:
|
||||||
read = getCurrencyBalance
|
read = getCurrencyBalance
|
||||||
notify = currencyBalanceChanged
|
notify = currencyBalanceChanged
|
||||||
|
|
||||||
proc getAssets(self: View): QVariant {.slot.} =
|
proc getAssetsModel*(self: View): token_model.Model =
|
||||||
return newQVariant(self.assets)
|
return self.assets
|
||||||
|
|
||||||
proc assetsChanged(self: View) {.signal.}
|
proc assetsChanged(self: View) {.signal.}
|
||||||
|
proc getAssets*(self: View): QVariant {.slot.} =
|
||||||
|
return newQVariant(self.assets)
|
||||||
QtProperty[QVariant] assets:
|
QtProperty[QVariant] assets:
|
||||||
read = getAssets
|
read = getAssets
|
||||||
notify = assetsChanged
|
notify = assetsChanged
|
||||||
@ -158,23 +162,6 @@ QtObject:
|
|||||||
if(self.isChat != dto.isChat):
|
if(self.isChat != dto.isChat):
|
||||||
self.isChat = dto.isChat
|
self.isChat = dto.isChat
|
||||||
self.isChatChanged()
|
self.isChatChanged()
|
||||||
if(self.currencyBalance != dto.getCurrencyBalance()):
|
|
||||||
self.currencyBalance = dto.getCurrencyBalance()
|
|
||||||
self.currencyBalanceChanged()
|
|
||||||
if(self.emoji != dto.emoji):
|
if(self.emoji != dto.emoji):
|
||||||
self.emoji = dto.emoji
|
self.emoji = dto.emoji
|
||||||
self.emojiChanged()
|
self.emojiChanged()
|
||||||
|
|
||||||
let assets = token_model.newModel()
|
|
||||||
|
|
||||||
assets.setItems(
|
|
||||||
dto.tokens.map(t => token_item.initItem(
|
|
||||||
t.name,
|
|
||||||
t.symbol,
|
|
||||||
t.balance.chainBalance,
|
|
||||||
t.address,
|
|
||||||
t.balance.currencyBalance,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
self.assets = assets
|
|
||||||
self.assetsChanged()
|
|
@ -1,6 +1,5 @@
|
|||||||
import os, json, sequtils, strutils, uuids
|
import os, json, sequtils, strutils, uuids
|
||||||
import json_serialization, chronicles
|
import json_serialization, chronicles
|
||||||
import times as times
|
|
||||||
|
|
||||||
import ./dto/accounts as dto_accounts
|
import ./dto/accounts as dto_accounts
|
||||||
import ./dto/generated_accounts as dto_generated_accounts
|
import ./dto/generated_accounts as dto_generated_accounts
|
||||||
|
@ -72,3 +72,206 @@ const getDerivedAddressForPrivateKeyTask*: Task = proc(argEncoded: string) {.gcs
|
|||||||
}
|
}
|
||||||
arg.finish(output)
|
arg.finish(output)
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Async timer
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
type
|
||||||
|
TimerTaskArg = ref object of QObjectTaskArg
|
||||||
|
timeoutInMilliseconds: int
|
||||||
|
|
||||||
|
const timerTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[TimerTaskArg](argEncoded)
|
||||||
|
sleep(arg.timeoutInMilliseconds)
|
||||||
|
arg.finish("")
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Async building token
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
type
|
||||||
|
BuildTokensTaskArg = ref object of QObjectTaskArg
|
||||||
|
walletAddresses: seq[string]
|
||||||
|
currency: string
|
||||||
|
networks: seq[NetworkDto]
|
||||||
|
|
||||||
|
proc getCustomTokens(): seq[TokenDto] =
|
||||||
|
try:
|
||||||
|
let responseCustomTokens = backend.getCustomTokens()
|
||||||
|
result = map(responseCustomTokens.result.getElems(), proc(x: JsonNode): TokenDto = x.toTokenDto(@[]))
|
||||||
|
except Exception as e:
|
||||||
|
error "error fetching custom tokens: ", message = e.msg
|
||||||
|
|
||||||
|
proc getTokensForChainId(chainId: int): seq[TokenDto] =
|
||||||
|
try:
|
||||||
|
let responseTokens = backend.getTokens(chainId)
|
||||||
|
let defaultTokens = map(responseTokens.result.getElems(),
|
||||||
|
proc(x: JsonNode): TokenDto = x.toTokenDto(@[], hasIcon=true, isCustom=false)
|
||||||
|
)
|
||||||
|
result.add(defaultTokens)
|
||||||
|
except Exception as e:
|
||||||
|
error "error fetching tokens: ", message = e.msg, chainId=chainId
|
||||||
|
|
||||||
|
proc prepareSymbols(networkSymbols: seq[string], allTokens: seq[TokenDto]): seq[seq[string]] =
|
||||||
|
# we have to use up to 300 characters in a single request when we're fetching prices
|
||||||
|
let charsMaxLenght = 300
|
||||||
|
result.add(@[])
|
||||||
|
var networkSymbolsIndex = 0
|
||||||
|
var tokenSymbolsIndex = 0
|
||||||
|
while networkSymbolsIndex < networkSymbols.len or tokenSymbolsIndex < allTokens.len:
|
||||||
|
var currentCharsLen = 0
|
||||||
|
var reachTheEnd = false
|
||||||
|
while networkSymbolsIndex < networkSymbols.len:
|
||||||
|
if(currentCharsLen + networkSymbols[networkSymbolsIndex].len >= charsMaxLenght):
|
||||||
|
reachTheEnd = true
|
||||||
|
result.add(@[])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
currentCharsLen += networkSymbols[networkSymbolsIndex].len + 1 # we add one for ','
|
||||||
|
result[result.len - 1].add(networkSymbols[networkSymbolsIndex])
|
||||||
|
networkSymbolsIndex.inc
|
||||||
|
while not reachTheEnd and tokenSymbolsIndex < allTokens.len:
|
||||||
|
if(currentCharsLen + allTokens[tokenSymbolsIndex].symbol.len >= charsMaxLenght):
|
||||||
|
reachTheEnd = true
|
||||||
|
result.add(@[])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
currentCharsLen += allTokens[tokenSymbolsIndex].symbol.len + 1 # we add one for ','
|
||||||
|
result[result.len - 1].add(allTokens[tokenSymbolsIndex].symbol)
|
||||||
|
tokenSymbolsIndex.inc
|
||||||
|
|
||||||
|
proc fetchNativeChainBalance(chainId: int, nativeCurrencyDecimals: int, accountAddress: string): float64 =
|
||||||
|
result = 0.0
|
||||||
|
try:
|
||||||
|
let nativeBalanceResponse = status_go_eth.getNativeChainBalance(chainId, accountAddress)
|
||||||
|
result = parsefloat(hex2Balance(nativeBalanceResponse.result.getStr, nativeCurrencyDecimals))
|
||||||
|
except Exception as e:
|
||||||
|
error "error getting balance", message = e.msg
|
||||||
|
|
||||||
|
proc fetchPrices(networkSymbols: seq[string], allTokens: seq[TokenDto], currency: string): Table[string, float] =
|
||||||
|
let allSymbols = prepareSymbols(networkSymbols, allTokens)
|
||||||
|
for symbols in allSymbols:
|
||||||
|
try:
|
||||||
|
let response = backend.fetchPrices(symbols, currency)
|
||||||
|
for (symbol, value) in response.result.pairs:
|
||||||
|
result[symbol] = value.getFloat
|
||||||
|
except Exception as e:
|
||||||
|
error "error fetching prices: ", message = e.msg
|
||||||
|
|
||||||
|
proc getTokensBalances(walletAddresses: seq[string], allTokens: seq[TokenDto]): JsonNode =
|
||||||
|
try:
|
||||||
|
result = newJObject()
|
||||||
|
let tokensAddresses = allTokens.map(t => t.addressAsString())
|
||||||
|
# We need to check, we should use `chainIdsFromSettings` instead `chainIds` deduced from the allTokens list?
|
||||||
|
let chainIds = deduplicate(allTokens.map(t => t.chainId))
|
||||||
|
let tokensBalancesResponse = backend.getTokensBalancesForChainIDs(chainIds, walletAddresses, tokensAddresses)
|
||||||
|
result = tokensBalancesResponse.result
|
||||||
|
except Exception as e:
|
||||||
|
error "error fetching tokens balances: ", message = e.msg
|
||||||
|
|
||||||
|
proc groupNetworksBySymbol(networks: seq[NetworkDto]): Table[string, seq[NetworkDto]] =
|
||||||
|
for network in networks:
|
||||||
|
if not result.hasKey(network.nativeCurrencySymbol):
|
||||||
|
result[network.nativeCurrencySymbol] = @[]
|
||||||
|
result[network.nativeCurrencySymbol].add(network)
|
||||||
|
|
||||||
|
proc getNetworkByCurrencySymbol(networks: seq[NetworkDto], networkNativeCurrencySymbol: string): NetworkDto =
|
||||||
|
for network in networks:
|
||||||
|
if network.nativeCurrencySymbol != networkNativeCurrencySymbol:
|
||||||
|
continue
|
||||||
|
return network
|
||||||
|
|
||||||
|
proc groupTokensBySymbol(tokens: seq[TokenDto]): Table[string, seq[TokenDto]] =
|
||||||
|
for token in tokens:
|
||||||
|
if not result.hasKey(token.symbol):
|
||||||
|
result[token.symbol] = @[]
|
||||||
|
result[token.symbol].add(token)
|
||||||
|
|
||||||
|
proc getTokenForSymbol(tokens: seq[TokenDto], symbol: string): TokenDto =
|
||||||
|
for token in tokens:
|
||||||
|
if token.symbol != symbol:
|
||||||
|
continue
|
||||||
|
return token
|
||||||
|
|
||||||
|
const prepareTokensTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[BuildTokensTaskArg](argEncoded)
|
||||||
|
|
||||||
|
var networkSymbols: seq[string]
|
||||||
|
var chainIdsFromSettings: seq[int]
|
||||||
|
for network in arg.networks:
|
||||||
|
networkSymbols.add(network.nativeCurrencySymbol)
|
||||||
|
chainIdsFromSettings.add(network.chainId)
|
||||||
|
|
||||||
|
var allTokens: seq[TokenDto]
|
||||||
|
allTokens.add(getCustomTokens())
|
||||||
|
for chainId in chainIdsFromSettings:
|
||||||
|
allTokens.add(getTokensForChainId(chainId))
|
||||||
|
allTokens = deduplicate(allTokens)
|
||||||
|
|
||||||
|
var prices = fetchPrices(networkSymbols, allTokens, arg.currency)
|
||||||
|
let tokenBalances = getTokensBalances(arg.walletAddresses, allTokens)
|
||||||
|
|
||||||
|
var builtTokensPerAccount = %*{ }
|
||||||
|
for address in arg.walletAddresses:
|
||||||
|
var builtTokens: seq[WalletTokenDto]
|
||||||
|
|
||||||
|
let groupedNetworks = groupNetworksBySymbol(arg.networks)
|
||||||
|
for networkNativeCurrencySymbol, networks in groupedNetworks.pairs:
|
||||||
|
var balancesPerChain = initTable[int, BalanceDto]()
|
||||||
|
for network in networks:
|
||||||
|
let chainBalance = fetchNativeChainBalance(network.chainId, network.nativeCurrencyDecimals, address)
|
||||||
|
balancesPerChain[network.chainId] = BalanceDto(
|
||||||
|
balance: chainBalance,
|
||||||
|
currencyBalance: chainBalance * prices[network.nativeCurrencySymbol]
|
||||||
|
)
|
||||||
|
let networkDto = getNetworkByCurrencySymbol(arg.networks, networkNativeCurrencySymbol)
|
||||||
|
var totalTokenBalance: BalanceDto
|
||||||
|
totalTokenBalance.balance = toSeq(balancesPerChain.values).map(x => x.balance).foldl(a + b)
|
||||||
|
totalTokenBalance.currencyBalance = totalTokenBalance.balance * prices[networkDto.nativeCurrencySymbol]
|
||||||
|
builtTokens.add(WalletTokenDto(
|
||||||
|
name: networkDto.nativeCurrencyName,
|
||||||
|
address: "0x0000000000000000000000000000000000000000",
|
||||||
|
symbol: networkDto.nativeCurrencySymbol,
|
||||||
|
decimals: networkDto.nativeCurrencyDecimals,
|
||||||
|
hasIcon: true,
|
||||||
|
color: "blue",
|
||||||
|
isCustom: false,
|
||||||
|
totalBalance: totalTokenBalance,
|
||||||
|
balancesPerChain: balancesPerChain
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let groupedTokens = groupTokensBySymbol(allTokens)
|
||||||
|
for symbol, tokens in groupedTokens.pairs:
|
||||||
|
var balancesPerChain = initTable[int, BalanceDto]()
|
||||||
|
for token in tokens:
|
||||||
|
let balanceForToken = tokenBalances{address}{token.addressAsString()}.getStr
|
||||||
|
let chainBalanceForToken = parsefloat(hex2Balance(balanceForToken, token.decimals))
|
||||||
|
balancesPerChain[token.chainId] = BalanceDto(
|
||||||
|
balance: chainBalanceForToken,
|
||||||
|
currencyBalance: chainBalanceForToken * prices[token.symbol]
|
||||||
|
)
|
||||||
|
let tokenDto = getTokenForSymbol(allTokens, symbol)
|
||||||
|
var totalTokenBalance: BalanceDto
|
||||||
|
totalTokenBalance.balance = toSeq(balancesPerChain.values).map(x => x.balance).foldl(a + b)
|
||||||
|
totalTokenBalance.currencyBalance = totalTokenBalance.balance * prices[tokenDto.symbol]
|
||||||
|
builtTokens.add(WalletTokenDto(
|
||||||
|
name: tokenDto.name,
|
||||||
|
address: $tokenDto.address,
|
||||||
|
symbol: tokenDto.symbol,
|
||||||
|
decimals: tokenDto.decimals,
|
||||||
|
hasIcon: tokenDto.hasIcon,
|
||||||
|
color: tokenDto.color,
|
||||||
|
isCustom: tokenDto.isCustom,
|
||||||
|
totalBalance: totalTokenBalance,
|
||||||
|
balancesPerChain: balancesPerChain
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
var tokensJArray = newJArray()
|
||||||
|
for wtDto in builtTokens:
|
||||||
|
tokensJarray.add(walletTokenDtoToJson(wtDto))
|
||||||
|
builtTokensPerAccount[address] = tokensJArray
|
||||||
|
|
||||||
|
arg.finish(builtTokensPerAccount)
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import tables, json, sequtils, sugar
|
import tables, json, sequtils, sugar, strutils
|
||||||
|
|
||||||
include ../../common/json_utils
|
include ../../common/json_utils
|
||||||
|
|
||||||
type BalanceDto* = ref object of RootObj
|
type BalanceDto* = object
|
||||||
chainBalance*: float64
|
balance*: float64
|
||||||
currencyBalance*: float64
|
currencyBalance*: float64
|
||||||
|
|
||||||
type
|
type
|
||||||
WalletTokenDto* = ref object of RootObj
|
WalletTokenDto* = object
|
||||||
name*: string
|
name*: string
|
||||||
address*: string
|
address*: string
|
||||||
symbol*: string
|
symbol*: string
|
||||||
@ -15,8 +15,8 @@ type
|
|||||||
hasIcon*: bool
|
hasIcon*: bool
|
||||||
color*: string
|
color*: string
|
||||||
isCustom*: bool
|
isCustom*: bool
|
||||||
balance*: BalanceDto
|
totalBalance*: BalanceDto
|
||||||
balances*: Table[int, BalanceDto]
|
balancesPerChain*: Table[int, BalanceDto]
|
||||||
|
|
||||||
type
|
type
|
||||||
WalletAccountDto* = ref object of RootObj
|
WalletAccountDto* = ref object of RootObj
|
||||||
@ -73,4 +73,45 @@ proc toWalletAccountDto*(jsonObj: JsonNode): WalletAccountDto =
|
|||||||
discard jsonObj.getProp("derived-from", result.derivedfrom)
|
discard jsonObj.getProp("derived-from", result.derivedfrom)
|
||||||
|
|
||||||
proc getCurrencyBalance*(self: WalletAccountDto): float64 =
|
proc getCurrencyBalance*(self: WalletAccountDto): float64 =
|
||||||
return self.tokens.map(t => t.balance.currencyBalance).foldl(a + b, 0.0)
|
return self.tokens.map(t => t.totalBalance.currencyBalance).foldl(a + b, 0.0)
|
||||||
|
|
||||||
|
proc toBalanceDto*(jsonObj: JsonNode): BalanceDto =
|
||||||
|
result = BalanceDto()
|
||||||
|
discard jsonObj.getProp("balance", result.balance)
|
||||||
|
discard jsonObj.getProp("currencyBalance", result.currencyBalance)
|
||||||
|
|
||||||
|
proc toWalletTokenDto*(jsonObj: JsonNode): WalletTokenDto =
|
||||||
|
result = WalletTokenDto()
|
||||||
|
discard jsonObj.getProp("name", result.name)
|
||||||
|
discard jsonObj.getProp("address", result.address)
|
||||||
|
discard jsonObj.getProp("symbol", result.symbol)
|
||||||
|
discard jsonObj.getProp("decimals", result.decimals)
|
||||||
|
discard jsonObj.getProp("hasIcon", result.hasIcon)
|
||||||
|
discard jsonObj.getProp("color", result.color)
|
||||||
|
discard jsonObj.getProp("isCustom", result.isCustom)
|
||||||
|
|
||||||
|
var totalBalanceObj: JsonNode
|
||||||
|
if(jsonObj.getProp("totalBalance", totalBalanceObj)):
|
||||||
|
result.totalBalance = toBalanceDto(totalBalanceObj)
|
||||||
|
|
||||||
|
var balancesPerChainObj: JsonNode
|
||||||
|
if(jsonObj.getProp("balancesPerChain", balancesPerChainObj)):
|
||||||
|
for chainId, balanceObj in balancesPerChainObj:
|
||||||
|
result.balancesPerChain[parseInt(chainId)] = toBalanceDto(balanceObj)
|
||||||
|
|
||||||
|
proc walletTokenDtoToJson*(dto: WalletTokenDto): JsonNode =
|
||||||
|
var balancesPerChainJsonObj = newJObject()
|
||||||
|
for k, v in dto.balancesPerChain.pairs:
|
||||||
|
balancesPerChainJsonObj[$k] = %* v
|
||||||
|
|
||||||
|
result = %* {
|
||||||
|
"name": dto.name,
|
||||||
|
"address": dto.address,
|
||||||
|
"symbol": dto.symbol,
|
||||||
|
"decimals": dto.decimals,
|
||||||
|
"hasIcon": dto.hasIcon,
|
||||||
|
"color": dto.color,
|
||||||
|
"isCustom": dto.isCustom,
|
||||||
|
"totalBalance": %* dto.totalBalance,
|
||||||
|
"balancesPerChain": balancesPerChainJsonObj
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import Tables, NimQml, json, sequtils, sugar, chronicles, strformat, stint, httpclient, net, strutils
|
import NimQml, Tables, json, sequtils, sugar, chronicles, strformat, stint, httpclient, net, strutils, os
|
||||||
import web3/[ethtypes, conversions]
|
import web3/[ethtypes, conversions]
|
||||||
|
|
||||||
import ../settings/service as settings_service
|
import ../settings/service as settings_service
|
||||||
@ -6,6 +6,7 @@ import ../accounts/service as accounts_service
|
|||||||
import ../token/service as token_service
|
import ../token/service as token_service
|
||||||
import ../network/service as network_service
|
import ../network/service as network_service
|
||||||
import ../../common/account_constants
|
import ../../common/account_constants
|
||||||
|
import ../../../app/global/global_singleton
|
||||||
|
|
||||||
import dto
|
import dto
|
||||||
import derived_address
|
import derived_address
|
||||||
@ -23,8 +24,6 @@ export derived_address
|
|||||||
logScope:
|
logScope:
|
||||||
topics = "wallet-account-service"
|
topics = "wallet-account-service"
|
||||||
|
|
||||||
include async_tasks
|
|
||||||
|
|
||||||
const SIGNAL_WALLET_ACCOUNT_SAVED* = "walletAccount/accountSaved"
|
const SIGNAL_WALLET_ACCOUNT_SAVED* = "walletAccount/accountSaved"
|
||||||
const SIGNAL_WALLET_ACCOUNT_DELETED* = "walletAccount/accountDeleted"
|
const SIGNAL_WALLET_ACCOUNT_DELETED* = "walletAccount/accountDeleted"
|
||||||
const SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED* = "walletAccount/currencyUpdated"
|
const SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED* = "walletAccount/currencyUpdated"
|
||||||
@ -32,6 +31,7 @@ const SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED* = "walletAccount/tokenVisi
|
|||||||
const SIGNAL_WALLET_ACCOUNT_UPDATED* = "walletAccount/walletAccountUpdated"
|
const SIGNAL_WALLET_ACCOUNT_UPDATED* = "walletAccount/walletAccountUpdated"
|
||||||
const SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED* = "walletAccount/networkEnabledUpdated"
|
const SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED* = "walletAccount/networkEnabledUpdated"
|
||||||
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_READY* = "walletAccount/derivedAddressesReady"
|
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_READY* = "walletAccount/derivedAddressesReady"
|
||||||
|
const SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT* = "walletAccount/tokensRebuilt"
|
||||||
|
|
||||||
var
|
var
|
||||||
balanceCache {.threadvar.}: Table[string, float64]
|
balanceCache {.threadvar.}: Table[string, float64]
|
||||||
@ -56,19 +56,6 @@ proc fetchAccounts(): seq[WalletAccountDto] =
|
|||||||
x => x.toWalletAccountDto()
|
x => x.toWalletAccountDto()
|
||||||
).filter(a => not a.isChat)
|
).filter(a => not a.isChat)
|
||||||
|
|
||||||
proc fetchNativeChainBalance(network: NetworkDto, accountAddress: string): float64 =
|
|
||||||
let key = "0x0" & accountAddress & $network.chainId
|
|
||||||
if balanceCache.hasKey(key):
|
|
||||||
return balanceCache[key]
|
|
||||||
|
|
||||||
try:
|
|
||||||
let nativeBalanceResponse = status_go_eth.getNativeChainBalance(network.chainId, accountAddress)
|
|
||||||
result = parsefloat(hex2Balance(nativeBalanceResponse.result.getStr, network.nativeCurrencyDecimals))
|
|
||||||
balanceCache[key] = result
|
|
||||||
except Exception as e:
|
|
||||||
error "Error getting balance", message = e.msg
|
|
||||||
result = 0.0
|
|
||||||
|
|
||||||
type AccountSaved = ref object of Args
|
type AccountSaved = ref object of Args
|
||||||
account: WalletAccountDto
|
account: WalletAccountDto
|
||||||
|
|
||||||
@ -88,20 +75,33 @@ type DerivedAddressesArgs* = ref object of Args
|
|||||||
derivedAddresses*: seq[DerivedAddressDto]
|
derivedAddresses*: seq[DerivedAddressDto]
|
||||||
error*: string
|
error*: string
|
||||||
|
|
||||||
|
type TokensPerAccountArgs* = ref object of Args
|
||||||
|
accountsTokens*: OrderedTable[string, seq[WalletTokenDto]] # [wallet address, list of tokens]
|
||||||
|
|
||||||
|
const CheckBalanceIntervalInMilliseconds = 15 * 60 * 1000 # 15 mins
|
||||||
|
|
||||||
|
include async_tasks
|
||||||
|
include ../../common/json_utils
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type Service* = ref object of QObject
|
type Service* = ref object of QObject
|
||||||
events: EventEmitter
|
closingApp: bool
|
||||||
threadpool: ThreadPool
|
ignoreTimeInitiatedTokensBuild: bool
|
||||||
settingsService: settings_service.Service
|
events: EventEmitter
|
||||||
accountsService: accounts_service.Service
|
threadpool: ThreadPool
|
||||||
tokenService: token_service.Service
|
settingsService: settings_service.Service
|
||||||
networkService: network_service.Service
|
accountsService: accounts_service.Service
|
||||||
accounts: OrderedTable[string, WalletAccountDto]
|
tokenService: token_service.Service
|
||||||
|
networkService: network_service.Service
|
||||||
|
walletAccounts: OrderedTable[string, WalletAccountDto]
|
||||||
|
|
||||||
priceCache: TimedCache
|
priceCache: TimedCache
|
||||||
|
|
||||||
|
# Forward declaration
|
||||||
|
proc buildAllTokens(self: Service, calledFromTimerOrInit = false)
|
||||||
|
|
||||||
proc delete*(self: Service) =
|
proc delete*(self: Service) =
|
||||||
|
self.closingApp = true
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc newService*(
|
proc newService*(
|
||||||
@ -114,88 +114,17 @@ QtObject:
|
|||||||
): Service =
|
): Service =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.QObject.setup
|
result.QObject.setup
|
||||||
|
result.closingApp = false
|
||||||
|
result.ignoreTimeInitiatedTokensBuild = false
|
||||||
result.events = events
|
result.events = events
|
||||||
result.threadpool = threadpool
|
result.threadpool = threadpool
|
||||||
result.settingsService = settingsService
|
result.settingsService = settingsService
|
||||||
result.accountsService = accountsService
|
result.accountsService = accountsService
|
||||||
result.tokenService = tokenService
|
result.tokenService = tokenService
|
||||||
result.networkService = networkService
|
result.networkService = networkService
|
||||||
result.accounts = initOrderedTable[string, WalletAccountDto]()
|
result.walletAccounts = initOrderedTable[string, WalletAccountDto]()
|
||||||
result.priceCache = newTimedCache()
|
result.priceCache = newTimedCache()
|
||||||
|
|
||||||
proc buildTokens(
|
|
||||||
self: Service,
|
|
||||||
account: WalletAccountDto,
|
|
||||||
prices: Table[string, float],
|
|
||||||
tokenBalances: JsonNode
|
|
||||||
): seq[WalletTokenDto] =
|
|
||||||
var groupedNetwork = initTable[string, seq[NetworkDto]]()
|
|
||||||
for network in self.networkService.getEnabledNetworks():
|
|
||||||
if not groupedNetwork.hasKey(network.nativeCurrencyName):
|
|
||||||
groupedNetwork[network.nativeCurrencyName] = @[]
|
|
||||||
|
|
||||||
groupedNetwork[network.nativeCurrencyName].add(network)
|
|
||||||
for currencyName, networks in groupedNetwork.pairs:
|
|
||||||
var balances = initTable[int, BalanceDto]()
|
|
||||||
for network in networks:
|
|
||||||
let chainBalance = fetchNativeChainBalance(network, account.address)
|
|
||||||
balances[network.chainId] = BalanceDto(
|
|
||||||
chainBalance: chainBalance,
|
|
||||||
currencyBalance: chainBalance * prices[network.nativeCurrencySymbol]
|
|
||||||
)
|
|
||||||
|
|
||||||
let totalChainBalance = toSeq(balances.values).map(x => x.chainBalance).foldl(a + b)
|
|
||||||
let balance = BalanceDto(
|
|
||||||
chainBalance: totalChainBalance,
|
|
||||||
currencyBalance: totalChainBalance * prices[networks[0].nativeCurrencySymbol]
|
|
||||||
)
|
|
||||||
result.add(WalletTokenDto(
|
|
||||||
name: currencyName,
|
|
||||||
address: "0x0000000000000000000000000000000000000000",
|
|
||||||
symbol: networks[0].nativeCurrencySymbol,
|
|
||||||
decimals: networks[0].nativeCurrencyDecimals,
|
|
||||||
hasIcon: true,
|
|
||||||
color: "blue",
|
|
||||||
isCustom: false,
|
|
||||||
balance: balance,
|
|
||||||
balances: balances
|
|
||||||
))
|
|
||||||
|
|
||||||
var groupedToken = initTable[string, seq[TokenDto]]()
|
|
||||||
for token in self.tokenService.getVisibleTokens():
|
|
||||||
if not groupedToken.hasKey(token.symbol):
|
|
||||||
groupedToken[token.symbol] = @[]
|
|
||||||
groupedToken[token.symbol].add(token)
|
|
||||||
|
|
||||||
for symbol, tokens in groupedToken.pairs:
|
|
||||||
var balances = initTable[int, BalanceDto]()
|
|
||||||
for token in tokens:
|
|
||||||
let chainBalance = parsefloat(hex2Balance(tokenBalances{token.addressAsString()}.getStr, token.decimals))
|
|
||||||
balances[token.chainId] = BalanceDto(
|
|
||||||
chainBalance: chainBalance,
|
|
||||||
currencyBalance: chainBalance * prices[symbol]
|
|
||||||
)
|
|
||||||
|
|
||||||
let totalChainBalance = toSeq(balances.values).map(x => x.chainBalance).foldl(a + b)
|
|
||||||
let balance = BalanceDto(
|
|
||||||
chainBalance: totalChainBalance,
|
|
||||||
currencyBalance: totalChainBalance * prices[symbol]
|
|
||||||
)
|
|
||||||
|
|
||||||
result.add(
|
|
||||||
WalletTokenDto(
|
|
||||||
name: tokens[0].name,
|
|
||||||
address: $tokens[0].address,
|
|
||||||
symbol: symbol,
|
|
||||||
decimals: tokens[0].decimals,
|
|
||||||
hasIcon: tokens[0].hasIcon,
|
|
||||||
color: tokens[0].color,
|
|
||||||
isCustom: tokens[0].isCustom,
|
|
||||||
balance: balance,
|
|
||||||
balances: balances
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
proc getPrice*(self: Service, crypto: string, fiat: string): float64 =
|
proc getPrice*(self: Service, crypto: string, fiat: string): float64 =
|
||||||
let cacheKey = crypto & fiat
|
let cacheKey = crypto & fiat
|
||||||
if self.priceCache.isCached(cacheKey):
|
if self.priceCache.isCached(cacheKey):
|
||||||
@ -214,68 +143,27 @@ QtObject:
|
|||||||
error "error: ", errDesription
|
error "error: ", errDesription
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
proc fetchPrices(self: Service): Table[string, float] =
|
|
||||||
let currency = self.settingsService.getCurrency()
|
|
||||||
|
|
||||||
var symbols: seq[string] = @[]
|
|
||||||
|
|
||||||
for network in self.networkService.getEnabledNetworks():
|
|
||||||
symbols.add(network.nativeCurrencySymbol)
|
|
||||||
|
|
||||||
for token in self.tokenService.getVisibleTokens():
|
|
||||||
symbols.add(token.symbol)
|
|
||||||
|
|
||||||
var prices = initTable[string, float]()
|
|
||||||
if symbols.len == 0:
|
|
||||||
return prices
|
|
||||||
|
|
||||||
try:
|
|
||||||
let response = backend.fetchPrices(symbols, currency)
|
|
||||||
for (symbol, value) in response.result.pairs:
|
|
||||||
prices[symbol] = value.getFloat
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
let errDesription = e.msg
|
|
||||||
error "error: ", errDesription
|
|
||||||
|
|
||||||
return prices
|
|
||||||
|
|
||||||
proc fetchBalances(self: Service, accounts: seq[string]): JsonNode =
|
|
||||||
let visibleTokens = self.tokenService.getVisibleTokens()
|
|
||||||
let tokens = visibleTokens.map(t => t.addressAsString())
|
|
||||||
let chainIds = visibleTokens.map(t => t.chainId)
|
|
||||||
return backend.getTokensBalancesForChainIDs(chainIds, accounts, tokens).result
|
|
||||||
|
|
||||||
proc refreshBalances(self: Service) =
|
|
||||||
let prices = self.fetchPrices()
|
|
||||||
let accounts = toSeq(self.accounts.keys)
|
|
||||||
let balances = self.fetchBalances(accounts)
|
|
||||||
|
|
||||||
for account in toSeq(self.accounts.values):
|
|
||||||
account.tokens = self.buildTokens(account, prices, balances{account.address})
|
|
||||||
|
|
||||||
proc init*(self: Service) =
|
proc init*(self: Service) =
|
||||||
|
signalConnect(singletonInstance.localAccountSensitiveSettings, "isWalletEnabledChanged()", self, "onIsWalletEnabledChanged()", 2)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let accounts = fetchAccounts()
|
let accounts = fetchAccounts()
|
||||||
|
|
||||||
for account in accounts:
|
for account in accounts:
|
||||||
self.accounts[account.address] = account
|
self.walletAccounts[account.address] = account
|
||||||
|
|
||||||
self.refreshBalances()
|
self.buildAllTokens(true)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
let errDesription = e.msg
|
let errDesription = e.msg
|
||||||
error "error: ", errDesription
|
error "error: ", errDesription
|
||||||
return
|
return
|
||||||
|
|
||||||
proc getAccountByAddress*(self: Service, address: string): WalletAccountDto =
|
proc getAccountByAddress*(self: Service, address: string): WalletAccountDto =
|
||||||
if not self.accounts.hasKey(address):
|
if not self.walletAccounts.hasKey(address):
|
||||||
return
|
return
|
||||||
|
return self.walletAccounts[address]
|
||||||
return self.accounts[address]
|
|
||||||
|
|
||||||
proc getWalletAccounts*(self: Service): seq[WalletAccountDto] =
|
proc getWalletAccounts*(self: Service): seq[WalletAccountDto] =
|
||||||
return toSeq(self.accounts.values)
|
return toSeq(self.walletAccounts.values)
|
||||||
|
|
||||||
proc getWalletAccount*(self: Service, accountIndex: int): WalletAccountDto =
|
proc getWalletAccount*(self: Service, accountIndex: int): WalletAccountDto =
|
||||||
if(accountIndex < 0 or accountIndex >= self.getWalletAccounts().len):
|
if(accountIndex < 0 or accountIndex >= self.getWalletAccounts().len):
|
||||||
@ -293,17 +181,13 @@ QtObject:
|
|||||||
|
|
||||||
proc addNewAccountToLocalStore(self: Service) =
|
proc addNewAccountToLocalStore(self: Service) =
|
||||||
let accounts = fetchAccounts()
|
let accounts = fetchAccounts()
|
||||||
let prices = self.fetchPrices()
|
|
||||||
|
|
||||||
var newAccount = accounts[0]
|
var newAccount = accounts[0]
|
||||||
for account in accounts:
|
for account in accounts:
|
||||||
if not self.accounts.haskey(account.address):
|
if not self.walletAccounts.haskey(account.address):
|
||||||
newAccount = account
|
newAccount = account
|
||||||
break
|
break
|
||||||
|
self.walletAccounts[newAccount.address] = newAccount
|
||||||
let balances = self.fetchBalances(@[newAccount.address])
|
self.buildAllTokens()
|
||||||
newAccount.tokens = self.buildTokens(newAccount, prices, balances{newAccount.address})
|
|
||||||
self.accounts[newAccount.address] = newAccount
|
|
||||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
|
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
|
||||||
|
|
||||||
proc generateNewAccount*(self: Service, password: string, accountName: string, color: string, emoji: string, path: string, derivedFrom: string): string =
|
proc generateNewAccount*(self: Service, password: string, accountName: string, color: string, emoji: string, path: string, derivedFrom: string): string =
|
||||||
@ -363,35 +247,35 @@ QtObject:
|
|||||||
|
|
||||||
proc deleteAccount*(self: Service, address: string) =
|
proc deleteAccount*(self: Service, address: string) =
|
||||||
discard status_go_accounts.deleteAccount(address)
|
discard status_go_accounts.deleteAccount(address)
|
||||||
let accountDeleted = self.accounts[address]
|
let accountDeleted = self.walletAccounts[address]
|
||||||
self.accounts.del(address)
|
self.walletAccounts.del(address)
|
||||||
|
|
||||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountDeleted(account: accountDeleted))
|
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountDeleted(account: accountDeleted))
|
||||||
|
|
||||||
proc updateCurrency*(self: Service, newCurrency: string) =
|
proc updateCurrency*(self: Service, newCurrency: string) =
|
||||||
discard self.settingsService.saveCurrency(newCurrency)
|
discard self.settingsService.saveCurrency(newCurrency)
|
||||||
self.refreshBalances()
|
self.buildAllTokens()
|
||||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED, CurrencyUpdated())
|
self.events.emit(SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED, CurrencyUpdated())
|
||||||
|
|
||||||
proc toggleTokenVisible*(self: Service, chainId: int, address: string) =
|
proc toggleTokenVisible*(self: Service, chainId: int, address: string) =
|
||||||
self.tokenService.toggleVisible(chainId, address)
|
self.tokenService.toggleVisible(chainId, address)
|
||||||
self.refreshBalances()
|
self.buildAllTokens()
|
||||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED, TokenVisibilityToggled())
|
self.events.emit(SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED, TokenVisibilityToggled())
|
||||||
|
|
||||||
proc toggleNetworkEnabled*(self: Service, chainId: int) =
|
proc toggleNetworkEnabled*(self: Service, chainId: int) =
|
||||||
self.networkService.toggleNetwork(chainId)
|
self.networkService.toggleNetwork(chainId)
|
||||||
self.tokenService.init()
|
self.tokenService.init()
|
||||||
self.refreshBalances()
|
self.buildAllTokens()
|
||||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
|
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
|
||||||
|
|
||||||
method toggleTestNetworksEnabled*(self: Service) =
|
method toggleTestNetworksEnabled*(self: Service) =
|
||||||
discard self.settings_service.toggleTestNetworksEnabled()
|
discard self.settingsService.toggleTestNetworksEnabled()
|
||||||
self.tokenService.init()
|
self.tokenService.init()
|
||||||
self.refreshBalances()
|
self.buildAllTokens()
|
||||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
|
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
|
||||||
|
|
||||||
proc updateWalletAccount*(self: Service, address: string, accountName: string, color: string, emoji: string) =
|
proc updateWalletAccount*(self: Service, address: string, accountName: string, color: string, emoji: string) =
|
||||||
let account = self.accounts[address]
|
let account = self.walletAccounts[address]
|
||||||
status_go_accounts.updateAccount(
|
status_go_accounts.updateAccount(
|
||||||
accountName,
|
accountName,
|
||||||
account.address,
|
account.address,
|
||||||
@ -452,4 +336,67 @@ QtObject:
|
|||||||
error: error
|
error: error
|
||||||
))
|
))
|
||||||
|
|
||||||
|
proc onStartBuildingTokensTimer*(self: Service, response: string) {.slot.} =
|
||||||
|
if self.ignoreTimeInitiatedTokensBuild:
|
||||||
|
self.ignoreTimeInitiatedTokensBuild = false
|
||||||
|
return
|
||||||
|
|
||||||
|
self.buildAllTokens(true)
|
||||||
|
|
||||||
|
proc startBuildingTokensTimer(self: Service) =
|
||||||
|
if(self.closingApp):
|
||||||
|
return
|
||||||
|
|
||||||
|
let arg = TimerTaskArg(
|
||||||
|
tptr: cast[ByteAddress](timerTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: "onStartBuildingTokensTimer",
|
||||||
|
timeoutInMilliseconds: CheckBalanceIntervalInMilliseconds
|
||||||
|
)
|
||||||
|
self.threadpool.start(arg)
|
||||||
|
|
||||||
|
proc onAllTokensBuilt*(self: Service, response: string) {.slot.} =
|
||||||
|
let responseObj = response.parseJson
|
||||||
|
if (responseObj.kind != JObject):
|
||||||
|
info "prepared tokens are not a json object"
|
||||||
|
return
|
||||||
|
|
||||||
|
var data = TokensPerAccountArgs()
|
||||||
|
let walletAddresses = toSeq(self.walletAccounts.keys)
|
||||||
|
for wAddress in walletAddresses:
|
||||||
|
var tokensArr: JsonNode
|
||||||
|
var tokens: seq[WalletTokenDto]
|
||||||
|
if(responseObj.getProp(wAddress, tokensArr)):
|
||||||
|
tokens = map(tokensArr.getElems(), proc(x: JsonNode): WalletTokenDto = x.toWalletTokenDto())
|
||||||
|
self.walletAccounts[wAddress].tokens = tokens
|
||||||
|
data.accountsTokens[wAddress] = tokens
|
||||||
|
|
||||||
|
self.events.emit(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT, data)
|
||||||
|
|
||||||
|
# run timer again...
|
||||||
|
self.startBuildingTokensTimer()
|
||||||
|
|
||||||
|
proc buildAllTokens(self: Service, calledFromTimerOrInit = false) =
|
||||||
|
if(self.closingApp or not singletonInstance.localAccountSensitiveSettings.getIsWalletEnabled()):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Since we don't have a way to re-run TimerTaskArg (to stop it and run again), we introduced some flags which will
|
||||||
|
# just ignore buildAllTokens in case that proc is called by some action in the time window between two successive calls
|
||||||
|
# initiated by TimerTaskArg.
|
||||||
|
if not calledFromTimerOrInit:
|
||||||
|
self.ignoreTimeInitiatedTokensBuild = true
|
||||||
|
|
||||||
|
let walletAddresses = toSeq(self.walletAccounts.keys)
|
||||||
|
|
||||||
|
let arg = BuildTokensTaskArg(
|
||||||
|
tptr: cast[ByteAddress](prepareTokensTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: "onAllTokensBuilt",
|
||||||
|
walletAddresses: walletAddresses,
|
||||||
|
currency: self.settingsService.getCurrency(),
|
||||||
|
networks: self.networkService.getEnabledNetworks()
|
||||||
|
)
|
||||||
|
self.threadpool.start(arg)
|
||||||
|
|
||||||
|
proc onIsWalletEnabledChanged*(self: Service) {.slot.} =
|
||||||
|
self.buildAllTokens()
|
Loading…
x
Reference in New Issue
Block a user