feat(@desktop/wallet): Add new go api to get token market values not bundled with token balances
fixes #12668
This commit is contained in:
parent
94159746ea
commit
3a41a81890
|
@ -175,7 +175,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
|
|||
)
|
||||
result.chatService = chat_service.newService(statusFoundation.events, statusFoundation.threadpool, result.contactsService)
|
||||
result.tokenService = token_service.newService(
|
||||
statusFoundation.events, statusFoundation.threadpool, result.networkService
|
||||
statusFoundation.events, statusFoundation.threadpool, result.networkService, result.settingsService
|
||||
)
|
||||
result.currencyService = currency_service.newService(
|
||||
statusFoundation.events, statusFoundation.threadpool, result.tokenService, result.settingsService
|
||||
|
@ -227,7 +227,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
|
|||
result.tokensService = tokens_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
||||
result.transactionService, result.tokenService, result.settingsService, result.walletAccountService, result.activityCenterService, result.communityService)
|
||||
result.providerService = provider_service.newService(statusFoundation.events, statusFoundation.threadpool, result.ensService)
|
||||
result.networkConnectionService = network_connection_service.newService(statusFoundation.events, result.walletAccountService, result.networkService, result.nodeService)
|
||||
result.networkConnectionService = network_connection_service.newService(statusFoundation.events,
|
||||
result.walletAccountService, result.networkService, result.nodeService, result.tokenService)
|
||||
result.sharedUrlsService = shared_urls_service.newService(statusFoundation.events, statusFoundation.threadpool)
|
||||
# Modules
|
||||
result.startupModule = startup_module.newModule[AppController](
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import ./io_interface
|
||||
|
||||
import ../../../../core/eventemitter
|
||||
import ../../../../../app_service/service/token/service as token_service
|
||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||
import app/core/eventemitter
|
||||
import app_service/service/token/service as token_service
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
import app_service/service/currency/dto
|
||||
|
||||
type
|
||||
Controller* = ref object of RootObj
|
||||
|
@ -52,3 +53,24 @@ proc getFlatTokensList*(self: Controller): var seq[TokenItem] =
|
|||
|
||||
proc getTokenBySymbolList*(self: Controller): var seq[TokenBySymbolItem] =
|
||||
return self.tokenService.getTokenBySymbolList()
|
||||
|
||||
proc getTokenDetails*(self: Controller, symbol: string): TokenDetailsItem =
|
||||
return self.tokenService.getTokenDetails(symbol)
|
||||
|
||||
proc getMarketValuesBySymbol*(self: Controller, symbol: string): TokenMarketValuesItem =
|
||||
return self.tokenService.getMarketValuesBySymbol(symbol)
|
||||
|
||||
proc getPriceBySymbol*(self: Controller, symbol: string): float64 =
|
||||
return self.tokenService.getPriceBySymbol(symbol)
|
||||
|
||||
proc getCurrentCurrencyFormat*(self: Controller): CurrencyFormatDto =
|
||||
return self.walletAccountService.getCurrencyFormat(self.tokenService.getCurrency())
|
||||
|
||||
proc rebuildMarketData*(self: Controller) =
|
||||
self.tokenService.rebuildMarketData()
|
||||
|
||||
proc getTokensDetailsLoading*(self: Controller): bool =
|
||||
self.tokenService.getTokensDetailsLoading()
|
||||
|
||||
proc getTokensMarketValuesLoading*(self: Controller): bool =
|
||||
self.tokenService.getTokensMarketValuesLoading()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import NimQml, Tables, strutils
|
||||
|
||||
import ./io_interface
|
||||
import ./io_interface, ./market_details_item
|
||||
|
||||
const SOURCES_DELIMITER = ";"
|
||||
|
||||
|
@ -28,22 +28,31 @@ type
|
|||
# properties below this are optional and may not exist in case of community minted assets
|
||||
# built from chainId and address using networks service
|
||||
WebsiteUrl
|
||||
MarketValues
|
||||
MarketDetails
|
||||
DetailsLoading
|
||||
MarketDetailsLoading
|
||||
|
||||
QtObject:
|
||||
type FlatTokensModel* = ref object of QAbstractListModel
|
||||
delegate: io_interface.FlatTokenModelDataSource
|
||||
marketValuesDelegate: io_interface.TokenMarketValuesDataSource
|
||||
tokenMarketDetails: seq[MarketDetailsItem]
|
||||
|
||||
proc setup(self: FlatTokensModel) =
|
||||
self.QAbstractListModel.setup
|
||||
self.tokenMarketDetails = @[]
|
||||
|
||||
proc delete(self: FlatTokensModel) =
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newFlatTokensModel*(delegate: io_interface.FlatTokenModelDataSource): FlatTokensModel =
|
||||
proc newFlatTokensModel*(
|
||||
delegate: io_interface.FlatTokenModelDataSource,
|
||||
marketValuesDelegate: io_interface.TokenMarketValuesDataSource
|
||||
): FlatTokensModel =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
result.delegate = delegate
|
||||
result.marketValuesDelegate = marketValuesDelegate
|
||||
|
||||
method rowCount(self: FlatTokensModel, index: QModelIndex = nil): int =
|
||||
return self.delegate.getFlatTokensList().len
|
||||
|
@ -69,7 +78,9 @@ QtObject:
|
|||
ModelRole.CommunityId.int:"communityId",
|
||||
ModelRole.Description.int:"description",
|
||||
ModelRole.WebsiteUrl.int:"websiteUrl",
|
||||
ModelRole.MarketValues.int:"marketValues",
|
||||
ModelRole.MarketDetails.int:"marketDetails",
|
||||
ModelRole.DetailsLoading.int:"detailsLoading",
|
||||
ModelRole.MarketDetailsLoading.int:"marketDetailsLoading",
|
||||
}.toTable
|
||||
|
||||
method data(self: FlatTokensModel, index: QModelIndex, role: int): QVariant =
|
||||
|
@ -101,16 +112,43 @@ QtObject:
|
|||
result = newQVariant(ord(item.`type`))
|
||||
of ModelRole.CommunityId:
|
||||
result = newQVariant(item.communityId)
|
||||
# ToDo fetching of market values not done yet
|
||||
of ModelRole.Description:
|
||||
result = newQVariant("")
|
||||
let tokenDetails = self.delegate.getTokenDetails(item.symbol)
|
||||
result = if not tokenDetails.isNil: newQVariant(tokenDetails.description)
|
||||
else: newQVariant("")
|
||||
of ModelRole.WebsiteUrl:
|
||||
result = newQVariant("")
|
||||
of ModelRole.MarketValues:
|
||||
result = newQVariant("")
|
||||
let tokenDetails = self.delegate.getTokenDetails(item.symbol)
|
||||
result = if not tokenDetails.isNil: newQVariant(tokenDetails.assetWebsiteUrl)
|
||||
else: newQVariant("")
|
||||
of ModelRole.MarketDetails:
|
||||
result = newQVariant(self.tokenMarketDetails[index.row])
|
||||
of ModelRole.DetailsLoading:
|
||||
result = newQVariant(self.delegate.getTokensDetailsLoading())
|
||||
of ModelRole.MarketDetailsLoading:
|
||||
result = newQVariant(self.delegate.getTokensMarketValuesLoading())
|
||||
|
||||
|
||||
proc modelsAboutToUpdate*(self: FlatTokensModel) =
|
||||
self.beginResetModel()
|
||||
self.beginResetModel()
|
||||
|
||||
proc modelsUpdated*(self: FlatTokensModel) =
|
||||
self.endResetModel()
|
||||
self.tokenMarketDetails = @[]
|
||||
for token in self.delegate.getFlatTokensList():
|
||||
self.tokenMarketDetails.add(newMarketDetailsItem(self.marketValuesDelegate, token.symbol))
|
||||
self.endResetModel()
|
||||
|
||||
proc tokensMarketValuesUpdated*(self: FlatTokensModel) =
|
||||
for i in countup(0, self.rowCount()):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
defer: index.delete
|
||||
self.dataChanged(index, index, @[ModelRole.MarketDetails.int, ModelRole.MarketDetailsLoading.int])
|
||||
|
||||
proc tokensDetailsUpdated*(self: FlatTokensModel) =
|
||||
for i in countup(0, self.rowCount()):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
defer: index.delete
|
||||
self.dataChanged(index, index, @[ModelRole.Description.int, ModelRole.WebsiteUrl.int, ModelRole.DetailsLoading.int])
|
||||
|
||||
proc currencyFormatsUpdated*(self: FlatTokensModel) =
|
||||
for mD in self.tokenMarketDetails:
|
||||
mD.updateCurrencyFormat()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import app_service/service/token/service_items
|
||||
import app_service/service/currency/dto
|
||||
|
||||
type
|
||||
SourcesOfTokensModelDataSource* = tuple[
|
||||
|
@ -6,11 +7,23 @@ type
|
|||
]
|
||||
type
|
||||
FlatTokenModelDataSource* = tuple[
|
||||
getFlatTokensList: proc(): var seq[TokenItem]
|
||||
getFlatTokensList: proc(): var seq[TokenItem],
|
||||
getTokenDetails: proc(symbol: string): TokenDetailsItem,
|
||||
getTokensDetailsLoading: proc(): bool,
|
||||
getTokensMarketValuesLoading: proc(): bool,
|
||||
]
|
||||
type
|
||||
TokenBySymbolModelDataSource* = tuple[
|
||||
getTokenBySymbolList: proc(): var seq[TokenBySymbolItem]
|
||||
getTokenBySymbolList: proc(): var seq[TokenBySymbolItem],
|
||||
getTokenDetails: proc(symbol: string): TokenDetailsItem,
|
||||
getTokensDetailsLoading: proc(): bool,
|
||||
getTokensMarketValuesLoading: proc(): bool,
|
||||
]
|
||||
type
|
||||
TokenMarketValuesDataSource* = tuple[
|
||||
getMarketValuesBySymbol: proc(symbol: string): TokenMarketValuesItem,
|
||||
getPriceBySymbol: proc(symbol: string): float64,
|
||||
getCurrentCurrencyFormat: proc(): CurrencyFormatDto,
|
||||
]
|
||||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
@ -49,6 +62,9 @@ method getFlatTokenModelDataSource*(self: AccessInterface): FlatTokenModelDataSo
|
|||
method getTokenBySymbolModelDataSource*(self: AccessInterface): TokenBySymbolModelDataSource {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getTokenMarketValuesDataSource*(self: AccessInterface): TokenMarketValuesDataSource {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
# View Delegate Interface
|
||||
# Delegate for the view must be declared here due to use of QtObject and multi
|
||||
# inheritance, which is not well supported in Nim.
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
import NimQml
|
||||
|
||||
import ./io_interface
|
||||
import app/modules/shared_models/currency_amount
|
||||
import app/modules/shared/wallet_utils
|
||||
import app_service/service/currency/dto
|
||||
|
||||
QtObject:
|
||||
type MarketDetailsItem* = ref object of QObject
|
||||
delegate: io_interface.TokenMarketValuesDataSource
|
||||
currencyFormat: CurrencyFormatDto
|
||||
symbol: string
|
||||
|
||||
proc setup*(self: MarketDetailsItem) =
|
||||
self.QObject.setup
|
||||
|
||||
proc delete*(self: MarketDetailsItem) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newMarketDetailsItem*(
|
||||
delegate: io_interface.TokenMarketValuesDataSource, symbol: string): MarketDetailsItem =
|
||||
new(result)
|
||||
result.setup()
|
||||
result.delegate = delegate
|
||||
result.symbol = symbol
|
||||
result.currencyFormat = delegate.getCurrentCurrencyFormat()
|
||||
|
||||
proc updateCurrencyFormat*(self: MarketDetailsItem) =
|
||||
self.currencyFormat = self.delegate.getCurrentCurrencyFormat()
|
||||
|
||||
proc marketCapChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc marketCap*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
return newQVariant(self.delegate.getMarketValuesBySymbol(self.symbol).marketCap)
|
||||
QtProperty[QVariant] marketCap:
|
||||
read = marketCap
|
||||
notify = marketCapChanged
|
||||
|
||||
proc highDayChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc highDay*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
return newQVariant(self.delegate.getMarketValuesBySymbol(self.symbol).highDay)
|
||||
QtProperty[QVariant] highDay:
|
||||
read = highDay
|
||||
notify = highDayChanged
|
||||
|
||||
proc lowDayChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc lowDay*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
return newQVariant(self.delegate.getMarketValuesBySymbol(self.symbol).lowDay)
|
||||
QtProperty[QVariant] lowDay:
|
||||
read = lowDay
|
||||
notify = lowDayChanged
|
||||
|
||||
proc changePctHourChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc changePctHour*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
return newQVariant(self.delegate.getMarketValuesBySymbol(self.symbol).changePctHour)
|
||||
QtProperty[QVariant] changePctHour:
|
||||
read = changePctHour
|
||||
notify = changePctHourChanged
|
||||
|
||||
proc changePctDayChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc changePctDay*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
return newQVariant(self.delegate.getMarketValuesBySymbol(self.symbol).changePctDay)
|
||||
QtProperty[QVariant] changePctDay:
|
||||
read = changePctDay
|
||||
notify = changePctDayChanged
|
||||
|
||||
proc changePct24hourChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc changePct24hour*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
return newQVariant(self.delegate.getMarketValuesBySymbol(self.symbol).changePct24hour)
|
||||
QtProperty[QVariant] changePct24hour:
|
||||
read = changePct24hour
|
||||
notify = changePct24hourChanged
|
||||
|
||||
proc change24hourChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc change24hour*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
return newQVariant(self.delegate.getMarketValuesBySymbol(self.symbol).change24hour)
|
||||
QtProperty[QVariant] change24hour:
|
||||
read = change24hour
|
||||
notify = change24hourChanged
|
||||
|
||||
proc currencyPriceChanged*(self: MarketDetailsItem) {.signal.}
|
||||
proc currencyPrice*(self: MarketDetailsItem): QVariant {.slot.} =
|
||||
let price = self.delegate.getPriceBySymbol(self.symbol)
|
||||
return newQVariant(currencyAmountToItem(price, self.currencyFormat))
|
||||
QtProperty[QVariant] currencyPrice:
|
||||
read = currencyPrice
|
||||
notify = currencyPriceChanged
|
|
@ -3,11 +3,13 @@ import NimQml
|
|||
import ./io_interface, ./view, ./controller
|
||||
import ../io_interface as delegate_interface
|
||||
|
||||
import ../../../../global/global_singleton
|
||||
import ../../../../core/eventemitter
|
||||
import ../../../../../app_service/service/token/service as token_service
|
||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||
import ../../../../../app_service/service/token/dto
|
||||
import app/global/global_singleton
|
||||
import app/core/eventemitter
|
||||
import app_service/service/token/service as token_service
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
import app_service/service/token/dto
|
||||
import app_service/service/currency/service
|
||||
import app_service/service/settings/service
|
||||
|
||||
export io_interface
|
||||
|
||||
|
@ -41,11 +43,25 @@ method delete*(self: Module) =
|
|||
method load*(self: Module) =
|
||||
singletonInstance.engine.setRootContextProperty("walletSectionAllTokens", newQVariant(self.view))
|
||||
|
||||
self.events.on(SIGNAL_CURRENCY_UPDATED) do(e:Args):
|
||||
self.controller.rebuildMarketData()
|
||||
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args):
|
||||
self.controller.rebuildMarketData()
|
||||
|
||||
# Passing on the events for changes in model to abstract model
|
||||
self.events.on(SIGNAL_TOKENS_LIST_ABOUT_TO_BE_UPDATED) do(e: Args):
|
||||
self.view.modelsAboutToUpdate()
|
||||
self.events.on(SIGNAL_TOKENS_LIST_UPDATED) do(e: Args):
|
||||
self.view.modelsUpdated()
|
||||
self.events.on(SIGNAL_TOKENS_DETAILS_UPDATED) do(e: Args):
|
||||
self.view.tokensDetailsUpdated()
|
||||
self.events.on(SIGNAL_TOKENS_MARKET_VALUES_UPDATED) do(e: Args):
|
||||
self.view.tokensMarketValuesUpdated()
|
||||
self.events.on(SIGNAL_TOKENS_PRICES_UPDATED) do(e: Args):
|
||||
self.view.tokensMarketValuesUpdated()
|
||||
|
||||
self.events.on(SIGNAL_CURRENCY_FORMATS_UPDATED) do(e:Args):
|
||||
self.view.currencyFormatsUpdated()
|
||||
|
||||
self.controller.init()
|
||||
self.view.load()
|
||||
|
@ -77,30 +93,34 @@ method fetchHistoricalBalanceForTokenAsJson*(self: Module, address: string, allA
|
|||
method tokenBalanceHistoryDataResolved*(self: Module, balanceHistoryJson: string) =
|
||||
self.view.setTokenBalanceHistoryDataReady(balanceHistoryJson)
|
||||
|
||||
proc getFlatTokensList*(self: Module): var seq[TokenItem] =
|
||||
return self.controller.getFlatTokensList()
|
||||
|
||||
proc getTokenBySymbolList*(self: Module): var seq[TokenBySymbolItem] =
|
||||
return self.controller.getTokenBySymbolList()
|
||||
|
||||
proc getSourcesOfTokensList*(self: Module): var seq[SupportedSourcesItem] =
|
||||
return self.controller.getSourcesOfTokensList()
|
||||
|
||||
# Interfaces for getting lists from the service files into the abstract models
|
||||
|
||||
method getSourcesOfTokensModelDataSource*(self: Module): SourcesOfTokensModelDataSource =
|
||||
return (
|
||||
getSourcesOfTokensList: proc(): var seq[SupportedSourcesItem] = self.getSourcesOfTokensList()
|
||||
getSourcesOfTokensList: proc(): var seq[SupportedSourcesItem] = self.controller.getSourcesOfTokensList()
|
||||
)
|
||||
|
||||
method getFlatTokenModelDataSource*(self: Module): FlatTokenModelDataSource =
|
||||
return (
|
||||
getFlatTokensList: proc(): var seq[TokenItem] = self.getFlatTokensList()
|
||||
getFlatTokensList: proc(): var seq[TokenItem] = self.controller.getFlatTokensList(),
|
||||
getTokenDetails: proc(symbol: string): TokenDetailsItem = self.controller.getTokenDetails(symbol),
|
||||
getTokensDetailsLoading: proc(): bool = self.controller.getTokensDetailsLoading(),
|
||||
getTokensMarketValuesLoading: proc(): bool = self.controller.getTokensMarketValuesLoading()
|
||||
)
|
||||
|
||||
method getTokenBySymbolModelDataSource*(self: Module): TokenBySymbolModelDataSource =
|
||||
return (
|
||||
getTokenBySymbolList: proc(): var seq[TokenBySymbolItem] = self.getTokenBySymbolList()
|
||||
getTokenBySymbolList: proc(): var seq[TokenBySymbolItem] = self.controller.getTokenBySymbolList(),
|
||||
getTokenDetails: proc(symbol: string): TokenDetailsItem = self.controller.getTokenDetails(symbol),
|
||||
getTokensDetailsLoading: proc(): bool = self.controller.getTokensDetailsLoading(),
|
||||
getTokensMarketValuesLoading: proc(): bool = self.controller.getTokensMarketValuesLoading()
|
||||
)
|
||||
|
||||
method getTokenMarketValuesDataSource*(self: Module): TokenMarketValuesDataSource =
|
||||
return (
|
||||
getMarketValuesBySymbol: proc(symbol: string): TokenMarketValuesItem = self.controller.getMarketValuesBySymbol(symbol),
|
||||
getPriceBySymbol: proc(symbol: string): float64 = self.controller.getPriceBySymbol(symbol),
|
||||
getCurrentCurrencyFormat: proc(): CurrencyFormatDto = self.controller.getCurrentCurrencyFormat()
|
||||
)
|
||||
|
||||
method filterChanged*(self: Module, addresses: seq[string]) =
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import NimQml, Tables, strutils
|
||||
|
||||
import ./io_interface, ./address_per_chain_model
|
||||
import ./io_interface, ./address_per_chain_model, ./market_details_item
|
||||
|
||||
const SOURCES_DELIMITER = ";"
|
||||
|
||||
|
@ -27,24 +27,31 @@ type
|
|||
# properties below this are optional and may not exist in case of community minted assets
|
||||
# built from chainId and address using networks service
|
||||
WebsiteUrl
|
||||
MarketValues
|
||||
MarketDetails
|
||||
|
||||
QtObject:
|
||||
type TokensBySymbolModel* = ref object of QAbstractListModel
|
||||
delegate: io_interface.TokenBySymbolModelDataSource
|
||||
marketValuesDelegate: io_interface.TokenMarketValuesDataSource
|
||||
addressPerChainModel: seq[AddressPerChainModel]
|
||||
tokenMarketDetails: seq[MarketDetailsItem]
|
||||
|
||||
proc setup(self: TokensBySymbolModel) =
|
||||
self.QAbstractListModel.setup
|
||||
self.addressPerChainModel = @[]
|
||||
self.tokenMarketDetails = @[]
|
||||
|
||||
proc delete(self: TokensBySymbolModel) =
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newTokensBySymbolModel*(delegate: io_interface.TokenBySymbolModelDataSource): TokensBySymbolModel =
|
||||
proc newTokensBySymbolModel*(
|
||||
delegate: io_interface.TokenBySymbolModelDataSource,
|
||||
marketValuesDelegate: io_interface.TokenMarketValuesDataSource
|
||||
): TokensBySymbolModel =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
result.delegate = delegate
|
||||
result.marketValuesDelegate = marketValuesDelegate
|
||||
|
||||
method rowCount(self: TokensBySymbolModel, index: QModelIndex = nil): int =
|
||||
return self.delegate.getTokenBySymbolList().len
|
||||
|
@ -69,7 +76,7 @@ QtObject:
|
|||
ModelRole.CommunityId.int:"communityId",
|
||||
ModelRole.Description.int:"description",
|
||||
ModelRole.WebsiteUrl.int:"websiteUrl",
|
||||
ModelRole.MarketValues.int:"marketValues",
|
||||
ModelRole.MarketDetails.int:"marketDetails",
|
||||
}.toTable
|
||||
|
||||
method data(self: TokensBySymbolModel, index: QModelIndex, role: int): QVariant =
|
||||
|
@ -99,13 +106,16 @@ QtObject:
|
|||
result = newQVariant(ord(item.`type`))
|
||||
of ModelRole.CommunityId:
|
||||
result = newQVariant(item.communityId)
|
||||
# ToDo fetching of market values not done yet
|
||||
of ModelRole.Description:
|
||||
result = newQVariant("")
|
||||
let tokenDetails = self.delegate.getTokenDetails(item.symbol)
|
||||
result = if not tokenDetails.isNil: newQVariant(tokenDetails.description)
|
||||
else: newQVariant("")
|
||||
of ModelRole.WebsiteUrl:
|
||||
result = newQVariant("")
|
||||
of ModelRole.MarketValues:
|
||||
result = newQVariant("")
|
||||
let tokenDetails = self.delegate.getTokenDetails(item.symbol)
|
||||
result = if not tokenDetails.isNil: newQVariant(tokenDetails.assetWebsiteUrl)
|
||||
else: newQVariant("")
|
||||
of ModelRole.MarketDetails:
|
||||
result = newQVariant(self.tokenMarketDetails[index.row])
|
||||
|
||||
proc modelsAboutToUpdate*(self: TokensBySymbolModel) =
|
||||
self.beginResetModel()
|
||||
|
@ -113,5 +123,27 @@ QtObject:
|
|||
proc modelsUpdated*(self: TokensBySymbolModel) =
|
||||
self.addressPerChainModel = @[]
|
||||
for index in countup(0, self.delegate.getTokenBySymbolList().len):
|
||||
self.addressPerChainModel.add(newAddressPerChainModel(self.delegate,index))
|
||||
self.addressPerChainModel.add(newAddressPerChainModel(self.delegate, index))
|
||||
|
||||
self.tokenMarketDetails = @[]
|
||||
for token in self.delegate.getTokenBySymbolList():
|
||||
if token.communityId.isEmptyOrWhitespace:
|
||||
self.tokenMarketDetails.add(newMarketDetailsItem(self.marketValuesDelegate, token.symbol))
|
||||
|
||||
self.endResetModel()
|
||||
|
||||
proc tokensMarketValuesUpdated*(self: TokensBySymbolModel) =
|
||||
for i in countup(0, self.rowCount()):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
defer: index.delete
|
||||
self.dataChanged(index, index, @[ModelRole.MarketDetails.int])
|
||||
|
||||
proc tokensDetailsUpdated*(self: TokensBySymbolModel) =
|
||||
for i in countup(0, self.rowCount()):
|
||||
let index = self.createIndex(i, 0, nil)
|
||||
defer: index.delete
|
||||
self.dataChanged(index, index, @[ModelRole.Description.int, ModelRole.WebsiteUrl.int])
|
||||
|
||||
proc currencyFormatsUpdated*(self: TokensBySymbolModel) =
|
||||
for mD in self.tokenMarketDetails:
|
||||
mD.updateCurrencyFormat()
|
||||
|
|
|
@ -29,8 +29,12 @@ QtObject:
|
|||
result.marketHistoryIsLoading = false
|
||||
result.balanceHistoryIsLoading = false
|
||||
result.sourcesOfTokensModel = newSourcesOfTokensModel(delegate.getSourcesOfTokensModelDataSource())
|
||||
result.flatTokensModel = newFlatTokensModel(delegate.getFlatTokenModelDataSource())
|
||||
result.tokensBySymbolModel = newTokensBySymbolModel(delegate.getTokenBySymbolModelDataSource())
|
||||
result.flatTokensModel = newFlatTokensModel(
|
||||
delegate.getFlatTokenModelDataSource(),
|
||||
delegate.getTokenMarketValuesDataSource())
|
||||
result.tokensBySymbolModel = newTokensBySymbolModel(
|
||||
delegate.getTokenBySymbolModelDataSource(),
|
||||
delegate.getTokenMarketValuesDataSource())
|
||||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
||||
|
@ -112,3 +116,15 @@ QtObject:
|
|||
self.sourcesOfTokensModel.modelsUpdated()
|
||||
self.flatTokensModel.modelsUpdated()
|
||||
self.tokensBySymbolModel.modelsUpdated()
|
||||
|
||||
proc tokensMarketValuesUpdated*(self: View) =
|
||||
self.flatTokensModel.tokensMarketValuesUpdated()
|
||||
self.tokensBySymbolModel.tokensMarketValuesUpdated()
|
||||
|
||||
proc tokensDetailsUpdated*(self: View) =
|
||||
self.flatTokensModel.tokensDetailsUpdated()
|
||||
self.tokensBySymbolModel.tokensDetailsUpdated()
|
||||
|
||||
proc currencyFormatsUpdated*(self: View) =
|
||||
self.flatTokensModel.currencyFormatsUpdated()
|
||||
self.tokensBySymbolModel.currencyFormatsUpdated()
|
||||
|
|
|
@ -4,10 +4,11 @@ import ../../../app/global/global_singleton
|
|||
import ../../../app/core/eventemitter
|
||||
import ../../../app/core/signals/types
|
||||
|
||||
import ../wallet_account/service as wallet_service
|
||||
import ../network/service as network_service
|
||||
import ../node/service as node_service
|
||||
import app_service/service/wallet_account/service as wallet_service
|
||||
import app_service/service/network/service as network_service
|
||||
import app_service/service/node/service as node_service
|
||||
import backend/connection_status as connection_status_backend
|
||||
import app_service/service/token/service as token_service
|
||||
import backend/collectibles as collectibles_backend
|
||||
|
||||
logScope:
|
||||
|
@ -54,6 +55,7 @@ QtObject:
|
|||
walletService: wallet_service.Service
|
||||
networkService: network_service.Service
|
||||
nodeService: node_service.Service
|
||||
tokenService: token_service.Service
|
||||
connectionStatus: Table[string, ConnectionStatus]
|
||||
|
||||
# Forward declaration
|
||||
|
@ -72,6 +74,7 @@ QtObject:
|
|||
walletService: wallet_service.Service,
|
||||
networkService: network_service.Service,
|
||||
nodeService: node_service.Service,
|
||||
tokenService: token_service.Service
|
||||
): Service =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
|
@ -80,6 +83,7 @@ QtObject:
|
|||
result.walletService = walletService
|
||||
result.networkService = networkService
|
||||
result.nodeService = nodeService
|
||||
result.tokenService = tokenService
|
||||
result.connectionStatus = {BLOCKCHAINS: newConnectionStatus(),
|
||||
MARKET: newConnectionStatus(),
|
||||
COLLECTIBLES: newConnectionStatus()}.toTable
|
||||
|
@ -225,7 +229,9 @@ QtObject:
|
|||
if(self.connectionStatus.hasKey(MARKET)):
|
||||
self.connectionStatus[MARKET].connectionState = ConnectionState.Retrying
|
||||
self.events.emit(SIGNAL_CONNECTION_UPDATE, self.convertConnectionStatusToNetworkConnectionsArgs(MARKET, self.connectionStatus[MARKET]))
|
||||
# TODO: remove once market values are removed from tokenService
|
||||
self.walletService.reloadAccountTokens()
|
||||
self.tokenService.rebuildMarketData()
|
||||
|
||||
proc collectiblesRetry*(self: Service) {.slot.} =
|
||||
if(self.connectionStatus.hasKey(COLLECTIBLES)):
|
||||
|
@ -236,6 +242,7 @@ QtObject:
|
|||
proc networkConnected*(self: Service, connected: bool) =
|
||||
if connected:
|
||||
self.walletService.reloadAccountTokens()
|
||||
self.tokenService.rebuildMarketData()
|
||||
discard collectibles_backend.refetchOwnedCollectibles()
|
||||
else:
|
||||
if(self.connectionStatus.hasKey(BLOCKCHAINS)):
|
||||
|
@ -249,4 +256,3 @@ QtObject:
|
|||
if self.connectionStatus.hasKey(website) and self.connectionStatus[website].completelyDown:
|
||||
return false
|
||||
return true
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import times
|
||||
import times, strformat
|
||||
import backend/backend as backend
|
||||
|
||||
include app_service/common/json_utils
|
||||
|
@ -9,25 +9,71 @@ include app_service/common/json_utils
|
|||
const DAYS_IN_WEEK = 7
|
||||
const HOURS_IN_DAY = 24
|
||||
|
||||
type
|
||||
GetTokenListTaskArg = ref object of QObjectTaskArg
|
||||
|
||||
const getSupportedTokenList*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[GetTokenListTaskArg](argEncoded)
|
||||
var response: RpcResponse[JsonNode]
|
||||
let arg = decode[QObjectTaskArg](argEncoded)
|
||||
var output = %*{
|
||||
"supportedTokensJson": "",
|
||||
"error": ""
|
||||
}
|
||||
try:
|
||||
response = backend.getTokenList()
|
||||
let output = %* {
|
||||
"supportedTokensJson": response,
|
||||
"error": ""
|
||||
}
|
||||
arg.finish(output)
|
||||
let response = backend.getTokenList()
|
||||
output["supportedTokensJson"] = %*response
|
||||
except Exception as e:
|
||||
let output = %* {
|
||||
"supportedTokensJson": response,
|
||||
"error": e.msg
|
||||
}
|
||||
arg.finish(output)
|
||||
output["error"] = %* fmt"Error fetching supported tokens: {e.msg}"
|
||||
arg.finish(output)
|
||||
|
||||
type
|
||||
FetchTokensMarketValuesTaskArg = ref object of QObjectTaskArg
|
||||
symbols: seq[string]
|
||||
currency: string
|
||||
|
||||
const fetchTokensMarketValuesTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[FetchTokensMarketValuesTaskArg](argEncoded)
|
||||
var output = %*{
|
||||
"tokenMarketValues": "",
|
||||
"error": ""
|
||||
}
|
||||
try:
|
||||
let response = backend.fetchMarketValues(arg.symbols, arg.currency)
|
||||
output["tokenMarketValues"] = %*response
|
||||
except Exception as e:
|
||||
output["error"] = %* fmt"Error fetching market values: {e.msg}"
|
||||
arg.finish(output)
|
||||
|
||||
type
|
||||
FetchTokensDetailsTaskArg = ref object of QObjectTaskArg
|
||||
symbols: seq[string]
|
||||
|
||||
const fetchTokensDetailsTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[FetchTokensDetailsTaskArg](argEncoded)
|
||||
var output = %*{
|
||||
"tokensDetails": "",
|
||||
"error": ""
|
||||
}
|
||||
try:
|
||||
let response = backend.fetchTokenDetails(arg.symbols)
|
||||
output["tokensDetails"] = %*response
|
||||
except Exception as e:
|
||||
output["error"] = %* fmt"Error fetching token details: {e.msg}"
|
||||
arg.finish(output)
|
||||
|
||||
type
|
||||
FetchTokensPricesTaskArg = ref object of QObjectTaskArg
|
||||
symbols: seq[string]
|
||||
currencies: seq[string]
|
||||
|
||||
const fetchTokensPricesTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[FetchTokensPricesTaskArg](argEncoded)
|
||||
var output = %*{
|
||||
"tokensPrices": "",
|
||||
"error": ""
|
||||
}
|
||||
try:
|
||||
let response = backend.fetchPrices(arg.symbols, arg.currencies)
|
||||
output["tokensPrices"] = %*response
|
||||
except Exception as e:
|
||||
output["error"] = %* fmt"Error fetching prices: {e.msg}"
|
||||
arg.finish(output)
|
||||
|
||||
type
|
||||
GetTokenHistoricalDataTaskArg = ref object of QObjectTaskArg
|
||||
|
|
|
@ -65,3 +65,18 @@ proc `$`*(self: TokenSourceDto): string =
|
|||
source: {self.source},
|
||||
version: {self.version}
|
||||
]"""
|
||||
|
||||
type
|
||||
TokenMarketValuesDto* = object
|
||||
marketCap* {.serializedFieldName("MKTCAP").}: float64
|
||||
highDay* {.serializedFieldName("HIGHDAY").}: float64
|
||||
lowDay* {.serializedFieldName("LOWDAY").}: float64
|
||||
changePctHour* {.serializedFieldName("CHANGEPCTHOUR").}: float64
|
||||
changePctDay* {.serializedFieldName("CHANGEPCTDAY").}: float64
|
||||
changePct24hour* {.serializedFieldName("CHANGEPCT24HOUR").}: float64
|
||||
change24hour* {.serializedFieldName("CHANGE24HOUR").}: float64
|
||||
|
||||
type
|
||||
TokenDetailsDto* = object
|
||||
description* {.serializedFieldName("Description").}: string
|
||||
assetWebsiteUrl* {.serializedFieldName("AssetWebsiteUrl").}: string
|
||||
|
|
|
@ -5,10 +5,12 @@ from web3/conversions import `$`
|
|||
import backend/backend as backend
|
||||
|
||||
import app_service/service/network/service as network_service
|
||||
import app_service/service/settings/service as settings_service
|
||||
import app_service/service/wallet_account/dto/account_dto
|
||||
|
||||
import app/core/eventemitter
|
||||
import app/core/tasks/[qt, threadpool]
|
||||
import app/core/signals/types
|
||||
import app_service/common/cache
|
||||
import ../../../constants as main_constants
|
||||
import ./dto, ./service_items
|
||||
|
@ -33,6 +35,9 @@ const SIGNAL_TOKEN_HISTORICAL_DATA_LOADED* = "tokenHistoricalDataLoaded"
|
|||
const SIGNAL_BALANCE_HISTORY_DATA_READY* = "tokenBalanceHistoryDataReady"
|
||||
const SIGNAL_TOKENS_LIST_UPDATED* = "tokensListUpdated"
|
||||
const SIGNAL_TOKENS_LIST_ABOUT_TO_BE_UPDATED* = "tokensListAboutToBeUpdated"
|
||||
const SIGNAL_TOKENS_DETAILS_UPDATED* = "tokensDetailsUpdated"
|
||||
const SIGNAL_TOKENS_MARKET_VALUES_UPDATED* = "tokensMarketValuesUpdated"
|
||||
const SIGNAL_TOKENS_PRICES_UPDATED* = "tokensPricesValuesUpdated"
|
||||
|
||||
type
|
||||
TokenHistoricalDataArgs* = ref object of Args
|
||||
|
@ -52,6 +57,7 @@ QtObject:
|
|||
events: EventEmitter
|
||||
threadpool: ThreadPool
|
||||
networkService: network_service.Service
|
||||
settingsService: settings_service.Service
|
||||
|
||||
# TODO: remove these once community usage of this service is removed etc...
|
||||
tokens: Table[int, seq[TokenDto]]
|
||||
|
@ -63,13 +69,17 @@ QtObject:
|
|||
sourcesOfTokensList: seq[SupportedSourcesItem]
|
||||
flatTokenList: seq[TokenItem]
|
||||
tokenBySymbolList: seq[TokenBySymbolItem]
|
||||
# TODO: Table[symbol, TokenDetails] fetched from cryptocompare
|
||||
# will be done under https://github.com/status-im/status-desktop/issues/12668
|
||||
tokenDetailsList: Table[string, TokenDetails]
|
||||
|
||||
tokenDetailsTable: Table[string, TokenDetailsItem]
|
||||
tokenMarketValuesTable: Table[string, TokenMarketValuesItem]
|
||||
tokenPriceTable: Table[string, float64]
|
||||
tokensDetailsLoading: bool
|
||||
tokensPricesLoading: bool
|
||||
tokensMarketDetailsLoading: bool
|
||||
|
||||
proc getCurrency*(self: Service): string
|
||||
proc updateCachedTokenPrice(self: Service, crypto: string, fiat: string, price: float64)
|
||||
proc jsonToPricesMap(node: JsonNode): Table[string, Table[string, float64]]
|
||||
proc rebuildMarketData*(self: Service)
|
||||
|
||||
proc delete*(self: Service) =
|
||||
self.QObject.delete
|
||||
|
@ -78,12 +88,14 @@ QtObject:
|
|||
events: EventEmitter,
|
||||
threadpool: ThreadPool,
|
||||
networkService: network_service.Service,
|
||||
settingsService: settings_service.Service
|
||||
): Service =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.events = events
|
||||
result.threadpool = threadpool
|
||||
result.networkService = networkService
|
||||
result.settingsService = settingsService
|
||||
result.tokens = initTable[int, seq[TokenDto]]()
|
||||
result.priceCache = newTimedCache[float64]()
|
||||
result.tokenList = @[]
|
||||
|
@ -92,95 +104,223 @@ QtObject:
|
|||
result.sourcesOfTokensList = @[]
|
||||
result.flatTokenList = @[]
|
||||
result.tokenBySymbolList = @[]
|
||||
result.tokenDetailsList = initTable[string, TokenDetails]()
|
||||
result.tokenDetailsTable = initTable[string, TokenDetailsItem]()
|
||||
result.tokenMarketValuesTable = initTable[string, TokenMarketValuesItem]()
|
||||
result.tokenPriceTable = initTable[string, float64]()
|
||||
result.tokensDetailsLoading = true
|
||||
result.tokensPricesLoading = true
|
||||
result.tokensMarketDetailsLoading = true
|
||||
|
||||
proc fetchTokensMarketValues(self: Service, symbols: seq[string]) =
|
||||
self.tokensMarketDetailsLoading = true
|
||||
let arg = FetchTokensMarketValuesTaskArg(
|
||||
tptr: cast[ByteAddress](fetchTokensMarketValuesTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "tokensMarketValuesRetrieved",
|
||||
symbols: symbols,
|
||||
currency: self.getCurrency()
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc tokensMarketValuesRetrieved(self: Service, response: string) {.slot.} =
|
||||
# this is emited so that the models can notify about market values being available
|
||||
self.tokensMarketDetailsLoading = false
|
||||
defer: self.events.emit(SIGNAL_TOKENS_MARKET_VALUES_UPDATED, Args())
|
||||
try:
|
||||
let parsedJson = response.parseJson
|
||||
var errorString: string
|
||||
var tokenMarketValues, tokensResult: JsonNode
|
||||
discard parsedJson.getProp("tokenMarketValues", tokenMarketValues)
|
||||
discard parsedJson.getProp("error", errorString)
|
||||
discard tokenMarketValues.getProp("result", tokensResult)
|
||||
|
||||
if not errorString.isEmptyOrWhitespace:
|
||||
raise newException(Exception, "Error getting tokens market values: " & errorString)
|
||||
if tokensResult.isNil or tokensResult.kind == JNull:
|
||||
return
|
||||
|
||||
for (symbol, marketValuesObj) in tokensResult.pairs:
|
||||
let marketValuesDto = Json.decode($marketValuesObj, dto.TokenMarketValuesDto, allowUnknownFields = true)
|
||||
self.tokenMarketValuesTable[symbol] = TokenMarketValuesItem(
|
||||
marketCap: marketValuesDto.marketCap,
|
||||
highDay: marketValuesDto.highDay,
|
||||
lowDay: marketValuesDto.lowDay,
|
||||
changePctHour: marketValuesDto.changePctHour,
|
||||
changePctDay: marketValuesDto.changePctDay,
|
||||
changePct24hour: marketValuesDto.changePct24hour,
|
||||
change24hour: marketValuesDto.change24hour)
|
||||
except Exception as e:
|
||||
let errDesription = e.msg
|
||||
error "error: ", errDesription
|
||||
|
||||
proc fetchTokensDetails(self: Service, symbols: seq[string]) =
|
||||
self.tokensDetailsLoading = true
|
||||
let arg = FetchTokensDetailsTaskArg(
|
||||
tptr: cast[ByteAddress](fetchTokensDetailsTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "tokensDetailsRetrieved",
|
||||
symbols: symbols
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc tokensDetailsRetrieved(self: Service, response: string) {.slot.} =
|
||||
self.tokensDetailsLoading = false
|
||||
# this is emited so that the models can notify about details being available
|
||||
defer: self.events.emit(SIGNAL_TOKENS_DETAILS_UPDATED, Args())
|
||||
try:
|
||||
let parsedJson = response.parseJson
|
||||
var errorString: string
|
||||
var tokensDetails, tokensResult: JsonNode
|
||||
discard parsedJson.getProp("tokensDetails", tokensDetails)
|
||||
discard parsedJson.getProp("error", errorString)
|
||||
discard tokensDetails.getProp("result", tokensResult)
|
||||
|
||||
if not errorString.isEmptyOrWhitespace:
|
||||
raise newException(Exception, "Error getting tokens details: " & errorString)
|
||||
if tokensResult.isNil or tokensResult.kind == JNull:
|
||||
return
|
||||
|
||||
for (symbol, tokenDetailsObj) in tokensResult.pairs:
|
||||
let tokenDetailsDto = Json.decode($tokenDetailsObj, dto.TokenDetailsDto, allowUnknownFields = true)
|
||||
self.tokenDetailsTable[symbol] = TokenDetailsItem(
|
||||
description: tokenDetailsDto.description,
|
||||
assetWebsiteUrl: tokenDetailsDto.assetWebsiteUrl)
|
||||
except Exception as e:
|
||||
let errDesription = e.msg
|
||||
error "error: ", errDesription
|
||||
|
||||
proc fetchTokensPrices(self: Service, symbols: seq[string]) =
|
||||
self.tokensPricesLoading = true
|
||||
let arg = FetchTokensPricesTaskArg(
|
||||
tptr: cast[ByteAddress](fetchTokensPricesTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "tokensPricesRetrieved",
|
||||
symbols: symbols,
|
||||
currencies: @[self.getCurrency()]
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc tokensPricesRetrieved(self: Service, response: string) {.slot.} =
|
||||
self.tokensPricesLoading = false
|
||||
# this is emited so that the models can notify about prices being available
|
||||
defer: self.events.emit(SIGNAL_TOKENS_PRICES_UPDATED, Args())
|
||||
try:
|
||||
let parsedJson = response.parseJson
|
||||
var errorString: string
|
||||
var tokensPrices, tokensResult: JsonNode
|
||||
discard parsedJson.getProp("tokensPrices", tokensPrices)
|
||||
discard parsedJson.getProp("error", errorString)
|
||||
discard tokensPrices.getProp("result", tokensResult)
|
||||
|
||||
if not errorString.isEmptyOrWhitespace:
|
||||
raise newException(Exception, "Error getting tokens details: " & errorString)
|
||||
if tokensResult.isNil or tokensResult.kind == JNull:
|
||||
return
|
||||
|
||||
for (symbol, prices) in tokensResult.pairs:
|
||||
for (currency, price) in prices.pairs:
|
||||
if cmpIgnoreCase(self.getCurrency(), currency) == 0:
|
||||
self.tokenPriceTable[symbol] = price.getFloat
|
||||
except Exception as e:
|
||||
let errDesription = e.msg
|
||||
error "error: ", errDesription
|
||||
|
||||
# Callback to process the response of getSupportedTokensList call
|
||||
proc supportedTokensListRetrieved(self: Service, response: string) {.slot.} =
|
||||
# this is emited so that the models can know that the seq it depends on has been updated
|
||||
defer: self.events.emit(SIGNAL_TOKENS_LIST_UPDATED, Args())
|
||||
try:
|
||||
let parsedJson = response.parseJson
|
||||
var errorString: string
|
||||
var supportedTokensJson, tokensResult: JsonNode
|
||||
discard parsedJson.getProp("supportedTokensJson", supportedTokensJson)
|
||||
discard parsedJson.getProp("error", errorString)
|
||||
discard supportedTokensJson.getProp("result", tokensResult)
|
||||
|
||||
let parsedJson = response.parseJson
|
||||
var errorString: string
|
||||
var supportedTokensJson, tokensResult: JsonNode
|
||||
discard parsedJson.getProp("supportedTokensJson", supportedTokensJson)
|
||||
discard parsedJson.getProp("supportedTokensJson", errorString)
|
||||
discard supportedTokensJson.getProp("result", tokensResult)
|
||||
if not errorString.isEmptyOrWhitespace:
|
||||
raise newException(Exception, "Error getting supported tokens list: " & errorString)
|
||||
let sourcesList = if tokensResult.isNil or tokensResult.kind == JNull: @[]
|
||||
else: Json.decode($tokensResult, seq[TokenSourceDto], allowUnknownFields = true)
|
||||
|
||||
if not errorString.isEmptyOrWhitespace:
|
||||
raise newException(Exception, "Error getting supported tokens list: " & errorString)
|
||||
let sourcesList = if tokensResult.isNil or tokensResult.kind == JNull: @[]
|
||||
else: Json.decode($tokensResult, seq[TokenSourceDto], allowUnknownFields = true)
|
||||
let supportedNetworkChains = self.networkService.getAllNetworkChainIds()
|
||||
var flatTokensList: Table[string, TokenItem] = initTable[string, TokenItem]()
|
||||
var tokenBySymbolList: Table[string, TokenBySymbolItem] = initTable[string, TokenBySymbolItem]()
|
||||
var tokenSymbols: seq[string] = @[]
|
||||
|
||||
let supportedNetworkChains = self.networkService.getAllNetworkChainIds()
|
||||
var flatTokensList: Table[string, TokenItem] = initTable[string, TokenItem]()
|
||||
var tokenBySymbolList: Table[string, TokenBySymbolItem] = initTable[string, TokenBySymbolItem]()
|
||||
for s in sourcesList:
|
||||
let newSource = SupportedSourcesItem(name: s.name, updatedAt: s.updatedAt, source: s.source, version: s.version, tokensCount: s.tokens.len)
|
||||
self.sourcesOfTokensList.add(newSource)
|
||||
|
||||
for s in sourcesList:
|
||||
let newSource = SupportedSourcesItem(name: s.name, updatedAt: s.updatedAt, source: s.source, version: s.version, tokensCount: s.tokens.len)
|
||||
self.sourcesOfTokensList.add(newSource)
|
||||
for token in s.tokens:
|
||||
# Remove tokens that are not on list of supported status networks
|
||||
if supportedNetworkChains.contains(token.chainID):
|
||||
# logic for building flat tokens list
|
||||
let unique_key = $token.chainID & token.address
|
||||
if flatTokensList.hasKey(unique_key):
|
||||
flatTokensList[unique_key].sources.add(s.name)
|
||||
else:
|
||||
let tokenType = if s.name == "native" : TokenType.Native
|
||||
else: TokenType.ERC20
|
||||
flatTokensList[unique_key] = TokenItem(
|
||||
key: unique_key,
|
||||
name: token.name,
|
||||
symbol: token.symbol,
|
||||
sources: @[s.name],
|
||||
chainID: token.chainID,
|
||||
address: token.address,
|
||||
decimals: token.decimals,
|
||||
image: "",
|
||||
`type`: tokenType,
|
||||
communityId: token.communityID)
|
||||
|
||||
for token in s.tokens:
|
||||
# Remove tokens that are not on list of supported status networks
|
||||
if supportedNetworkChains.contains(token.chainID):
|
||||
# logic for building flat tokens list
|
||||
let unique_key = $token.chainID & token.address
|
||||
if flatTokensList.hasKey(unique_key):
|
||||
flatTokensList[unique_key].sources.add(s.name)
|
||||
else:
|
||||
let tokenType = if s.name == "native" : TokenType.Native
|
||||
else: TokenType.ERC20
|
||||
flatTokensList[unique_key] = TokenItem(
|
||||
key: unique_key,
|
||||
name: token.name,
|
||||
symbol: token.symbol,
|
||||
sources: @[s.name],
|
||||
chainID: token.chainID,
|
||||
address: token.address,
|
||||
decimals: token.decimals,
|
||||
image: "",
|
||||
`type`: tokenType,
|
||||
communityId: token.communityID)
|
||||
# logic for building tokens by symbol list
|
||||
# In case the token is not a community token the unique key is symbol
|
||||
# In case this is a community token the only param reliably unique is its address
|
||||
# as there is always a rare case that a user can create two or more community token
|
||||
# with same symbol and cannot be avoided
|
||||
let token_by_symbol_key = if token.communityID.isEmptyOrWhitespace: token.symbol
|
||||
else: token.address
|
||||
if tokenBySymbolList.hasKey(token_by_symbol_key):
|
||||
if not tokenBySymbolList[token_by_symbol_key].sources.contains(s.name):
|
||||
tokenBySymbolList[token_by_symbol_key].sources.add(s.name)
|
||||
# this logic is to check if an entry for same chainId as been made already,
|
||||
# in that case we simply add it to address per chain
|
||||
var addedChains: seq[int] = @[]
|
||||
for addressPerChain in tokenBySymbolList[token_by_symbol_key].addressPerChainId:
|
||||
addedChains.add(addressPerChain.chainId)
|
||||
if not addedChains.contains(token.chainID):
|
||||
tokenBySymbolList[token_by_symbol_key].addressPerChainId.add(AddressPerChain(chainId: token.chainID, address: token.address))
|
||||
else:
|
||||
let tokenType = if s.name == "native": TokenType.Native
|
||||
else: TokenType.ERC20
|
||||
tokenBySymbolList[token_by_symbol_key] = TokenBySymbolItem(
|
||||
key: token_by_symbol_key,
|
||||
name: token.name,
|
||||
symbol: token.symbol,
|
||||
sources: @[s.name],
|
||||
addressPerChainId: @[AddressPerChain(chainId: token.chainID, address: token.address)],
|
||||
decimals: token.decimals,
|
||||
image: "",
|
||||
`type`: tokenType,
|
||||
communityId: token.communityID)
|
||||
if token.communityID.isEmptyOrWhitespace:
|
||||
tokenSymbols.add(token.symbol)
|
||||
|
||||
# logic for building tokens by symbol list
|
||||
# In case the token is not a community token the unique key is symbol
|
||||
# In case this is a community token the only param reliably unique is its address
|
||||
# as there is always a rare case that a user can create two or more community token
|
||||
# with same symbol and cannot be avoided
|
||||
let token_by_symbol_key = if token.communityID.isEmptyOrWhitespace: token.symbol
|
||||
else: token.address
|
||||
if tokenBySymbolList.hasKey(token_by_symbol_key):
|
||||
if not tokenBySymbolList[token_by_symbol_key].sources.contains(s.name):
|
||||
tokenBySymbolList[token_by_symbol_key].sources.add(s.name)
|
||||
# this logic is to check if an entry for same chainId as been made already,
|
||||
# in that case we simply add it to address per chain
|
||||
var addedChains: seq[int] = @[]
|
||||
for addressPerChain in tokenBySymbolList[token_by_symbol_key].addressPerChainId:
|
||||
addedChains.add(addressPerChain.chainId)
|
||||
if not addedChains.contains(token.chainID):
|
||||
tokenBySymbolList[token_by_symbol_key].addressPerChainId.add(AddressPerChain(chainId: token.chainID, address: token.address))
|
||||
else:
|
||||
let tokenType = if s.name == "native": TokenType.Native
|
||||
else: TokenType.ERC20
|
||||
tokenBySymbolList[token_by_symbol_key] = TokenBySymbolItem(
|
||||
key: token_by_symbol_key,
|
||||
name: token.name,
|
||||
symbol: token.symbol,
|
||||
sources: @[s.name],
|
||||
addressPerChainId: @[AddressPerChain(chainId: token.chainID, address: token.address)],
|
||||
decimals: token.decimals,
|
||||
image: "",
|
||||
`type`: tokenType,
|
||||
communityId: token.communityID)
|
||||
|
||||
self.flatTokenList = toSeq(flatTokensList.values)
|
||||
self.flatTokenList.sort(cmpTokenItem)
|
||||
self.tokenBySymbolList = toSeq(tokenBySymbolList.values)
|
||||
self.tokenBySymbolList.sort(cmpTokenBySymbolItem)
|
||||
self.fetchTokensMarketValues(tokenSymbols)
|
||||
self.fetchTokensDetails(tokenSymbols)
|
||||
self.fetchTokensPrices(tokenSymbols)
|
||||
self.flatTokenList = toSeq(flatTokensList.values)
|
||||
self.flatTokenList.sort(cmpTokenItem)
|
||||
self.tokenBySymbolList = toSeq(tokenBySymbolList.values)
|
||||
self.tokenBySymbolList.sort(cmpTokenBySymbolItem)
|
||||
except Exception as e:
|
||||
let errDesription = e.msg
|
||||
error "error: ", errDesription
|
||||
|
||||
proc getSupportedTokensList(self: Service) =
|
||||
# this is emited so that the models can know that an update is about to happen
|
||||
self.events.emit(SIGNAL_TOKENS_LIST_ABOUT_TO_BE_UPDATED, Args())
|
||||
let arg = GetTokenListTaskArg(
|
||||
let arg = QObjectTaskArg(
|
||||
tptr: cast[ByteAddress](getSupportedTokenList),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "supportedTokensListRetrieved",
|
||||
|
@ -246,8 +386,16 @@ QtObject:
|
|||
return
|
||||
self.loadData()
|
||||
self.getSupportedTokensList()
|
||||
# ToDo: on self.events.on(SignalType.Message.event) do(e: Args):
|
||||
# update and populate internal list and then emit signal
|
||||
|
||||
self.events.on(SignalType.Wallet.event) do(e:Args):
|
||||
var data = WalletSignal(e)
|
||||
case data.eventType:
|
||||
of "wallet-tick-reload":
|
||||
self.rebuildMarketData()
|
||||
# update and populate internal list and then emit signal when new custom token detected?
|
||||
|
||||
proc getCurrency*(self: Service): string =
|
||||
return self.settingsService.getCurrency()
|
||||
|
||||
proc getSourcesOfTokensList*(self: Service): var seq[SupportedSourcesItem] =
|
||||
return self.sourcesOfTokensList
|
||||
|
@ -258,6 +406,32 @@ QtObject:
|
|||
proc getTokenBySymbolList*(self: Service): var seq[TokenBySymbolItem] =
|
||||
return self.tokenBySymbolList
|
||||
|
||||
proc getTokenDetails*(self: Service, symbol: string): TokenDetailsItem =
|
||||
if not self.tokenDetailsTable.hasKey(symbol):
|
||||
return TokenDetailsItem()
|
||||
return self.tokenDetailsTable[symbol]
|
||||
|
||||
proc getMarketValuesBySymbol*(self: Service, symbol: string): TokenMarketValuesItem =
|
||||
if not self.tokenMarketValuesTable.hasKey(symbol):
|
||||
return TokenMarketValuesItem()
|
||||
return self.tokenMarketValuesTable[symbol]
|
||||
|
||||
proc getPriceBySymbol*(self: Service, symbol: string): float64 =
|
||||
if not self.tokenPriceTable.hasKey(symbol):
|
||||
return 0.0
|
||||
return self.tokenPriceTable[symbol]
|
||||
|
||||
proc getTokensDetailsLoading*(self: Service): bool =
|
||||
return self.tokensDetailsLoading
|
||||
|
||||
proc getTokensMarketValuesLoading*(self: Service): bool =
|
||||
return self.tokensPricesLoading and self.tokensMarketDetailsLoading
|
||||
|
||||
proc rebuildMarketData*(self: Service) =
|
||||
let symbols = self.tokenDetailsTable.keys.toSeq()
|
||||
self.fetchTokensMarketValues(symbols)
|
||||
self.fetchTokensPrices(symbols)
|
||||
|
||||
# TODO: Remove after https://github.com/status-im/status-desktop/issues/12513
|
||||
proc getTokenList*(self: Service): seq[TokenDto] =
|
||||
return self.tokenList
|
||||
|
|
|
@ -81,10 +81,36 @@ proc `$`*(self: TokenBySymbolItem): string =
|
|||
]"""
|
||||
|
||||
# In case of community tokens only the description will be available
|
||||
type TokenDetails* = ref object of RootObj
|
||||
type TokenDetailsItem* = ref object of RootObj
|
||||
description*: string
|
||||
websiteUrl*: string
|
||||
marketValues*: TokenMarketValuesDto
|
||||
assetWebsiteUrl*: string
|
||||
|
||||
proc `$`*(self: TokenDetailsItem): string =
|
||||
result = fmt"""TokenDetailsItem[
|
||||
description: {self.description},
|
||||
assetWebsiteUrl: {self.assetWebsiteUrl}
|
||||
]"""
|
||||
|
||||
type
|
||||
TokenMarketValuesItem* = object
|
||||
marketCap*: float64
|
||||
highDay*: float64
|
||||
lowDay*: float64
|
||||
changePctHour*: float64
|
||||
changePctDay*: float64
|
||||
changePct24hour*: float64
|
||||
change24hour*: float64
|
||||
|
||||
proc `$`*(self: TokenMarketValuesItem): string =
|
||||
result = fmt"""TokenBySymbolItem[
|
||||
marketCap: {self.marketCap},
|
||||
highDay: {self.highDay},
|
||||
lowDay: {self.lowDay},
|
||||
changePctHour: {self.changePctHour},
|
||||
changePctDay: {self.changePctDay},
|
||||
changePct24hour: {self.changePct24hour},
|
||||
change24hour: {self.change24hour}
|
||||
]"""
|
||||
|
||||
proc cmpTokenItem*(x, y: TokenItem): int =
|
||||
cmp(x.name, y.name)
|
||||
|
|
|
@ -138,6 +138,10 @@ rpc(getTransfersForIdentities, "wallet"):
|
|||
rpc(getWalletToken, "wallet"):
|
||||
accounts: seq[string]
|
||||
|
||||
rpc(fetchMarketValues, "wallet"):
|
||||
symbols: seq[string]
|
||||
currency: string
|
||||
|
||||
rpc(startWallet, "wallet"):
|
||||
discard
|
||||
|
||||
|
|
Loading…
Reference in New Issue