refactor(settings-service): settings improved

Since we had 2 services dealing with the same `status-go` settings, this
commit merges them into a single one. Also we have new public methods
exposed what minimizes a possibility for error since a key for each setting
is kept in the service.
This commit is contained in:
Sale Djenic 2021-11-22 19:40:03 +01:00
parent 7c36e98cf3
commit 7a9784b854
29 changed files with 1133 additions and 443 deletions

View File

@ -12,14 +12,12 @@ import ../../app_service/service/token/service as token_service
import ../../app_service/service/transaction/service as transaction_service
import ../../app_service/service/collectible/service as collectible_service
import ../../app_service/service/wallet_account/service as wallet_account_service
import ../../app_service/service/setting/service as setting_service
import ../../app_service/service/bookmarks/service as bookmark_service
import ../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../app_service/service/mnemonic/service as mnemonic_service
import ../../app_service/service/privacy/service as privacy_service
import ../../app_service/service/provider/service as provider_service
import ../../app_service/service/ens/service as ens_service
import ../../app_service/service/profile/service as profile_service
import ../../app_service/service/settings/service as settings_service
import ../../app_service/service/about/service as about_service
@ -92,7 +90,6 @@ type
transactionService: transaction_service.Service
collectibleService: collectible_service.Service
walletAccountService: wallet_account_service.Service
settingService: setting_service.Service
bookmarkService: bookmark_service.Service
dappPermissionsService: dapp_permissions_service.Service
ensService: ens_service.Service
@ -167,7 +164,6 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
# Services
result.osNotificationService = os_notification_service.newService(statusFoundation.status.events)
result.keychainService = keychain_service.newService(statusFoundation.status.events)
result.settingService = setting_service.newService()
result.settingsService = settings_service.newService()
result.accountsService = accounts_service.newService()
result.contactsService = contacts_service.newService(statusFoundation.status.events, statusFoundation.threadpool)
@ -175,9 +171,9 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.communityService = community_service.newService(result.chatService)
result.messageService = message_service.newService(statusFoundation.status.events, statusFoundation.threadpool)
result.tokenService = token_service.newService(statusFoundation.status.events, statusFoundation.threadpool,
result.settingService, result.settingsService)
result.collectibleService = collectible_service.newService(result.settingService)
result.walletAccountService = wallet_account_service.newService(statusFoundation.status.events, result.settingService,
result.settingsService)
result.collectibleService = collectible_service.newService(result.settingsService)
result.walletAccountService = wallet_account_service.newService(statusFoundation.status.events, result.settingsService,
result.tokenService)
result.transactionService = transaction_service.newService(statusFoundation.status.events, statusFoundation.threadpool,
result.walletAccountService)
@ -212,7 +208,6 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.collectibleService,
result.walletAccountService,
result.bookmarkService,
result.settingService,
result.profileService,
result.settingsService,
result.contactsService,
@ -236,18 +231,6 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.connect()
#################################################
# Adding status and statusFoundation here now is just because of having a controll
# over order of execution while we integrating this refactoring architecture
# into the current app state.
# Once we complete refactoring process we will get rid of "status" part/lib.
#
# This to will be adapted to appropriate modules later:
# result.login = login.newController(statusFoundation.status, statusFoundation)
# result.onboarding = onboarding.newController(statusFoundation.status)
# singletonInstance.engine.setRootContextProperty("loginModel", result.login.variant)
# singletonInstance.engine.setRootContextProperty("onboardingModel", result.onboarding.variant)
#result.connect()
proc delete*(self: AppController) =
self.osNotificationService.delete
self.contactsService.delete
@ -279,7 +262,7 @@ proc delete*(self: AppController) =
self.tokenService.delete
self.transactionService.delete
self.collectibleService.delete
self.settingService.delete
self.settingsService.delete
self.walletAccountService.delete
self.aboutService.delete
self.dappPermissionsService.delete
@ -323,13 +306,12 @@ proc start*(self: AppController) =
self.startupModule.load()
proc load(self: AppController) =
self.settingService.init()
self.settingsService.init()
self.contactsService.init()
self.chatService.init()
self.communityService.init()
self.bookmarkService.init()
self.tokenService.init()
self.settingsService.init()
self.dappPermissionsService.init()
self.ensService.init()
self.providerService.init()
@ -337,12 +319,9 @@ proc load(self: AppController) =
self.transactionService.init()
self.languageService.init()
#################################################
# Once SettingService gets added, `pubKey` should be fetched from there, instead the following line:
let pubKey = self.settingsService.getPubKey()
let pubKey = self.settingsService.getPublicKey()
singletonInstance.localAccountSensitiveSettings.setFileName(pubKey)
singletonInstance.engine.setRootContextProperty("localAccountSensitiveSettings", self.localAccountSensitiveSettingsVariant)
#################################################
# other global instances
self.buildAndRegisterLocalAccountSensitiveSettings()
@ -361,24 +340,34 @@ proc userLoggedIn*(self: AppController) =
self.load()
proc buildAndRegisterLocalAccountSensitiveSettings(self: AppController) =
var pubKey = self.settingsService.getPubKey()
var pubKey = self.settingsService.getPublicKey()
singletonInstance.localAccountSensitiveSettings.setFileName(pubKey)
singletonInstance.engine.setRootContextProperty("localAccountSensitiveSettings", self.localAccountSensitiveSettingsVariant)
proc buildAndRegisterUserProfile(self: AppController) =
let loggedInAccount = self.accountsService.getLoggedInAccount()
let pubKey = self.settingsService.getPubKey()
let sendUserStatus = self.settingsService.getSendUserStatus()
let pubKey = self.settingsService.getPublicKey()
let sendUserStatus = self.settingsService.getSendStatusUpdates()
## This is still not in use. Read a comment in UserProfile.
## let currentUserStatus = self.settingsService.getCurrentUserStatus()
let obj = self.settingsService.getIdentityImage(loggedInAccount.keyUid)
let loggedInAccount = self.accountsService.getLoggedInAccount()
var thumbnail, large: string
for img in loggedInAccount.images:
if(img.imgType == "large"):
large = img.uri
elif(img.imgType == "thumbnail"):
thumbnail = img.uri
let meAsContact = self.contactsService.getContactById(pubKey)
var ensName: string
if(meAsContact.ensVerified):
ensName = prettyEnsName(meAsContact.name)
singletonInstance.userProfile.setFixedData(loggedInAccount.name, loggedInAccount.keyUid, loggedInAccount.identicon,
pubKey)
singletonInstance.userProfile.setEnsName("") # in this moment we don't know ens name
singletonInstance.userProfile.setThumbnailImage(obj.thumbnail)
singletonInstance.userProfile.setLargeImage(obj.large)
singletonInstance.userProfile.setEnsName(ensName)
singletonInstance.userProfile.setThumbnailImage(thumbnail)
singletonInstance.userProfile.setLargeImage(large)
singletonInstance.userProfile.setUserStatus(sendUserStatus)
singletonInstance.engine.setRootContextProperty("userProfile", self.userProfileVariant)

View File

@ -12,7 +12,7 @@ QtObject:
thumbnailImage: string
largeImage: string
userStatus: bool
currentUserStatus: int
#currentUserStatus: int
proc setup(self: UserProfile) =
self.QObject.setup

View File

@ -35,11 +35,11 @@ method getDappsAddress*(self: Controller): string =
return self.settingsService.getDappsAddress()
method setDappsAddress*(self: Controller, address: string) =
if self.settingsService.setDappsAddress(address):
if self.settingsService.saveDappsAddress(address):
self.delegate.onDappAddressChanged(address)
method getCurrentNetworkDetails*(self: Controller): NetworkDetails =
return self.settingsService.getCurrentNetworkDetails()
method getCurrentNetworkId*(self: Controller): int =
return self.settingsService.getCurrentNetworkId()
method disconnect*(self: Controller) =
discard self.dappPermissionsService.revoke("web3".toPermission())

View File

@ -1,5 +1,3 @@
import ../../../../../app_service/service/settings/service as settings_service
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for any input/interaction with this module.
@ -16,7 +14,7 @@ method getDappsAddress*(self: AccessInterface): string {.base.} =
method setDappsAddress*(self: AccessInterface, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrentNetworkDetails*(self: AccessInterface): NetworkDetails {.base.} =
method getCurrentNetworkId*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method disconnect*(self: AccessInterface) {.base.} =

View File

@ -36,7 +36,7 @@ method delete*(self: Module) =
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("providerModule", self.viewVariant)
self.view.dappsAddress = self.controller.getDappsAddress()
self.view.networkId = self.controller.getCurrentNetworkDetails().config.networkId
self.view.networkId = self.controller.getCurrentNetworkId()
self.view.load()
method isLoaded*(self: Module): bool =

View File

@ -1,4 +1,4 @@
import item, controller_interface, io_interface
import item, controller_interface, io_interface, chronicles
import ../../global/global_singleton
import ../../../app_service/service/settings/service_interface as settings_service
@ -12,6 +12,9 @@ import eventemitter
export controller_interface
logScope:
topics = "main-module-controller"
type
Controller* = ref object of controller_interface.AccessInterface
delegate: io_interface.AccessInterface
@ -139,5 +142,7 @@ method getNumOfNotificaitonsForCommunity*(self: Controller, communityId: string)
result.mentions += chat.unviewedMentionsCount
method setUserStatus*(self: Controller, status: bool) =
self.settingsService.setSendUserStatus(status)
singletonInstance.userProfile.setUserStatus(status)
if(self.settingsService.saveSendStatusUpdates(status)):
singletonInstance.userProfile.setUserStatus(status)
else:
error "error updating user status"

View File

@ -18,14 +18,12 @@ import ../../../app_service/service/token/service as token_service
import ../../../app_service/service/transaction/service as transaction_service
import ../../../app_service/service/collectible/service as collectible_service
import ../../../app_service/service/wallet_account/service as wallet_account_service
import ../../../app_service/service/setting/service as setting_service
import ../../../app_service/service/bookmarks/service as bookmark_service
import ../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../app_service/service/provider/service as provider_service
import ../../../app_service/service/profile/service as profile_service
import ../../../app_service/service/accounts/service as accounts_service
import ../../../app_service/service/settings/service as settings_service
import ../../../app_service/service/settings/service_interface as settings_service
import ../../../app_service/service/contacts/service as contacts_service
import ../../../app_service/service/about/service as about_service
import ../../../app_service/service/language/service as language_service
@ -63,7 +61,6 @@ proc newModule*[T](
collectibleService: collectible_service.Service,
walletAccountService: wallet_account_service.Service,
bookmarkService: bookmark_service.ServiceInterface,
settingService: setting_service.Service,
profileService: profile_service.ServiceInterface,
settingsService: settings_service.ServiceInterface,
contactsService: contacts_service.Service,
@ -87,7 +84,7 @@ proc newModule*[T](
communityService, messageService)
result.communitySectionsModule = initOrderedTable[string, chat_section_module.AccessInterface]()
result.walletSectionModule = wallet_section_module.newModule[Module[T]](result, events, tokenService,
transactionService, collectible_service, walletAccountService, settingService)
transactionService, collectible_service, walletAccountService, settingsService)
result.browserSectionModule = browser_section_module.newModule(result, bookmarkService, settingsService,
dappPermissionsService, providerService)
result.profileSectionModule = profile_section_module.newModule(result, events, accountsService, settingsService,

View File

@ -4,7 +4,7 @@ import controller_interface
import ../../../../app_service/service/profile/service as profile_service
import ../../../../app_service/service/accounts/service as accounts_service
import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/settings/service_interface as settings_service
import ../../../../app_service/service/language/service as language_service
import ../../../../app_service/service/mnemonic/service as mnemonic_service
import ../../../../app_service/service/privacy/service as privacy_service
@ -22,7 +22,10 @@ type
mnemonicService: mnemonic_service.ServiceInterface
privacyService: privacy_service.ServiceInterface
proc newController*[T](delegate: T, accountsService: accounts_service.ServiceInterface, settingsService: settings_service.ServiceInterface, profileService: profile_service.ServiceInterface, languageService: language_service.ServiceInterface, mnemonicService: mnemonic_service.ServiceInterface, privacyService: privacy_service.ServiceInterface): Controller[T] =
proc newController*[T](delegate: T, accountsService: accounts_service.ServiceInterface,
settingsService: settings_service.ServiceInterface, profileService: profile_service.ServiceInterface,
languageService: language_service.ServiceInterface, mnemonicService: mnemonic_service.ServiceInterface,
privacyService: privacy_service.ServiceInterface): Controller[T] =
result = Controller[T]()
result.delegate = delegate
result.profileService = profileService
@ -42,10 +45,14 @@ method enableDeveloperFeatures*[T](self: Controller[T]) =
self.settingsService.enableDeveloperFeatures()
method toggleTelemetry*[T](self: Controller[T]) =
self.settingsService.toggleTelemetry()
var value = ""
if(not self.isTelemetryEnabled()):
value = DEFAULT_TELEMETRY_SERVER_URL
discard self.settingsService.saveTelemetryServerUrl(value)
method isTelemetryEnabled*[T](self: Controller[T]): bool =
return self.settingsService.isTelemetryEnabled()
return self.settingsService.getTelemetryServerUrl().len > 0
method toggleAutoMessage*[T](self: Controller[T]) =
self.settingsService.toggleAutoMessage()
@ -54,7 +61,11 @@ method isAutoMessageEnabled*[T](self: Controller[T]): bool =
return self.settingsService.isAutoMessageEnabled()
method toggleDebug*[T](self: Controller[T]) =
self.settingsService.toggleDebug()
discard
# Need to sort out this
#self.settingsService.toggleDebug()
method isDebugEnabled*[T](self: Controller[T]): bool =
return self.settingsService.isDebugEnabled()
return true
# Need to sort out this
#return self.settingsService.isDebugEnabled()

View File

@ -4,7 +4,7 @@ import ../../../global/global_singleton
import ../../../../app_service/service/profile/service as profile_service
import ../../../../app_service/service/accounts/service as accounts_service
import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/settings/service_interface as settings_service
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/about/service as about_service
import ../../../../app_service/service/language/service as language_service

View File

@ -3,7 +3,7 @@ import ./controller_interface
import ../../../../global/global_singleton
import ../../../../../app_service/service/profile/service as profile_service
import ../../../../../app_service/service/accounts/service as accounts_service
import ../../../../../app_service/service/settings/service as settings_service
import ../../../../../app_service/service/settings/service_interface as settings_service
import ./item as item
import status/types/identity_image
@ -17,7 +17,8 @@ type
settingsService: settings_service.ServiceInterface
accountsService: accounts_service.ServiceInterface
proc newController*[T](delegate: T, accountsService: accounts_service.ServiceInterface, settingsService: settings_service.ServiceInterface, profileService: profile_service.ServiceInterface): Controller[T] =
proc newController*[T](delegate: T, accountsService: accounts_service.ServiceInterface,
settingsService: settings_service.ServiceInterface, profileService: profile_service.ServiceInterface): Controller[T] =
result = Controller[T]()
result.delegate = delegate
result.profileService = profileService
@ -32,7 +33,6 @@ method init*[T](self: Controller[T]) =
method getProfile*[T](self: Controller[T]): item.Item =
var network = self.settingsService.getNetwork()
var appearance = self.settingsService.getAppearance()
var messagesFromContactsOnly = self.settingsService.getMessagesFromContactsOnly()

View File

@ -5,7 +5,7 @@ import ../../../../global/global_singleton
import ../../../../../app_service/service/profile/service as profile_service
import ../../../../../app_service/service/accounts/service as accounts_service
import ../../../../../app_service/service/settings/service as settings_service
import ../../../../../app_service/service/settings/service_interface as settings_service
import status/types/identity_image
@ -19,7 +19,8 @@ type
viewVariant: QVariant
moduleLoaded: bool
proc newModule*[T](delegate: T, accountsService: accounts_service.ServiceInterface, settingsService: settings_service.ServiceInterface, profileService: profile_service.ServiceInterface): Module[T] =
proc newModule*[T](delegate: T, accountsService: accounts_service.ServiceInterface,
settingsService: settings_service.ServiceInterface, profileService: profile_service.ServiceInterface): Module[T] =
result = Module[T]()
result.delegate = delegate
result.view = newView(result)

View File

@ -1,5 +1,5 @@
import ./controller_interface
import ../../../../app_service/service/setting/service as setting_service
import ../../../../app_service/service/settings/service_interface as settings_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
export controller_interface
@ -7,17 +7,17 @@ export controller_interface
type
Controller*[T: controller_interface.DelegateInterface] = ref object of controller_interface.AccessInterface
delegate: T
settingService: setting_service.ServiceInterface
settingsService: settings_service.ServiceInterface
walletAccountService: wallet_account_service.ServiceInterface
proc newController*[T](
delegate: T,
settingService: setting_service.ServiceInterface,
settingsService: settings_service.ServiceInterface,
walletAccountService: wallet_account_service.ServiceInterface,
): Controller[T] =
result = Controller[T]()
result.delegate = delegate
result.settingService = settingService
result.settingsService = settingsService
result.walletAccountService = walletAccountService
method delete*[T](self: Controller[T]) =
@ -26,8 +26,14 @@ method delete*[T](self: Controller[T]) =
method init*[T](self: Controller[T]) =
discard
method getSetting*[T](self: Controller[T]): setting_service.SettingDto =
return self.settingService.getSetting()
method getCurrency*[T](self: Controller[T]): string =
return self.settingsService.getCurrency()
method getSigningPhrase*[T](self: Controller[T]): string =
return self.settingsService.getSigningPhrase()
method isMnemonicBackedUp*[T](self: Controller[T]): bool =
return self.settingsService.getMnemonic().len > 0
method getCurrencyBalance*[T](self: Controller[T]): float64 =
return self.walletAccountService.getCurrencyBalance()

View File

@ -1,5 +1,3 @@
import ../../../../app_service/service/setting/service_interface as setting_service
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for any input/interaction with this module.
@ -10,7 +8,13 @@ method delete*(self: AccessInterface) {.base.} =
method init*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getSetting*(self: AccessInterface): setting_service.SettingDto {.base.} =
method getCurrency*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method getSigningPhrase*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method isMnemonicBackedUp*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrencyBalance*(self: AccessInterface): float64 {.base.} =

View File

@ -17,7 +17,7 @@ import ../../../../app_service/service/token/service as token_service
import ../../../../app_service/service/transaction/service as transaction_service
import ../../../../app_service/service/collectible/service as collectible_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
import ../../../../app_service/service/setting/service as setting_service
import ../../../../app_service/service/settings/service_interface as settings_service
import io_interface
export io_interface
@ -44,13 +44,13 @@ proc newModule*[T](
transactionService: transaction_service.Service,
collectibleService: collectible_service.ServiceInterface,
walletAccountService: wallet_account_service.ServiceInterface,
settingService: setting_service.ServiceInterface
settingsService: settings_service.ServiceInterface
): Module[T] =
result = Module[T]()
result.delegate = delegate
result.events = events
result.moduleLoaded = false
result.controller = newController(result, settingService, walletAccountService)
result.controller = newController(result, settingsService, walletAccountService)
result.view = newView(result)
result.accountTokensModule = account_tokens_module.newModule[Module[T]](result, events, walletAccountService)
@ -102,8 +102,10 @@ method load*[T](self: Module[T]) =
self.transactionsModule.load()
self.switchAccount(0)
let setting = self.controller.getSetting()
self.view.updateFromSetting(setting)
let currency = self.controller.getCurrency()
let signingPhrase = self.controller.getSigningPhrase()
let mnemonicBackedUp = self.controller.isMnemonicBackedUp()
self.view.setData(currency, signingPhrase, mnemonicBackedUp)
self.setTotalCurrencyBalance()
self.moduleLoaded = true
self.delegate.walletSectionDidLoad()

View File

@ -1,6 +1,5 @@
import NimQml
import ../../../../app_service/service/setting/service as setting_service
import ./io_interface
QtObject:
@ -65,8 +64,8 @@ QtObject:
self.totalCurrencyBalance = totalCurrencyBalance
self.totalCurrencyBalanceChanged()
proc updateFromSetting*(self: View, setting: setting_service.SettingDto) =
self.currentCurrency = setting.currency
self.currentCurrencyChanged()
self.signingPhrase = setting.signingPhrase
self.isMnemonicBackedUp = setting.isMnemonicBackedUp
proc setData*(self: View, currency, signingPhrase: string, mnemonicBackedUp: bool) =
self.currentCurrency = currency
self.signingPhrase = signingPhrase
self.isMnemonicBackedUp = mnemonicBackedUp
self.currentCurrencyChanged()

View File

@ -1,7 +1,7 @@
import chronicles, sequtils, json
import ./service_interface, ./dto
import ../setting/service as setting_service
import ../settings/service_interface as settings_service
import status/statusgo_backend_new/collectibles as collectibles
@ -14,21 +14,21 @@ logScope:
type
Service* = ref object of service_interface.ServiceInterface
settingService: setting_service.ServiceInterface
settingsService: settings_service.ServiceInterface
method delete*(self: Service) =
discard
proc newService*(settingService: setting_service.ServiceInterface): Service =
proc newService*(settingsService: settings_service.ServiceInterface): Service =
result = Service()
result.settingService = settingService
result.settingsService = settingsService
method init*(self: Service) =
discard
method getCollections(self: Service, address: string): seq[CollectionDto] =
try:
let networkId = self.settingService.getSetting().currentNetwork.id
let networkId = self.settingsService.getCurrentNetworkId()
let response = collectibles.getOpenseaCollections(networkId, address)
return map(response.result.getElems(), proc(x: JsonNode): CollectionDto = x.toCollectionDto())
except Exception as e:
@ -38,7 +38,7 @@ method getCollections(self: Service, address: string): seq[CollectionDto] =
method getCollectibles(self: Service, address: string, collectionSlug: string): seq[CollectibleDto] =
try:
let networkId = self.settingService.getSetting().currentNetwork.id
let networkId = self.settingsService.getCurrentNetworkId()
let response = collectibles.getOpenseaAssets(networkId, address, collectionSlug, limit)
return map(response.result.getElems(), proc(x: JsonNode): CollectibleDto = x.toCollectibleDto())
except Exception as e:

View File

@ -4,13 +4,14 @@ import options
import strutils
include ../../common/json_utils
import ../dapp_permissions/service as dapp_permissions_service
import ../settings/service as settings_service
import ../settings/service_interface as settings_service
import ../ens/service as ens_service
import service_interface
import status/statusgo_backend_new/permissions as status_go_permissions
import status/statusgo_backend_new/accounts as status_go_accounts
import status/statusgo_backend_new/core as status_go_core
import status/statusgo_backend_new/provider as status_go_provider
from stew/base32 import nil
from stew/base58 import nil
import stew/byteutils
export service_interface
@ -18,6 +19,74 @@ logScope:
topics = "provider-service"
const HTTPS_SCHEME* = "https"
const IPFS_GATEWAY* = ".infura.status.im"
const SWARM_GATEWAY* = "swarm-gateways.net"
type
RequestTypes {.pure.} = enum
Web3SendAsyncReadOnly = "web3-send-async-read-only",
HistoryStateChanged = "history-state-changed",
APIRequest = "api-request"
Unknown = "unknown"
ResponseTypes {.pure.} = enum
Web3SendAsyncCallback = "web3-send-async-callback",
APIResponse = "api-response",
Web3ResponseError = "web3-response-error"
type
Payload = ref object
id: JsonNode
rpcMethod: string
Web3SendAsyncReadOnly = ref object
messageId: JsonNode
payload: Payload
request: string
hostname: string
APIRequest = ref object
isAllowed: bool
messageId: JsonNode
permission: Permission
hostname: string
const AUTH_METHODS = toHashSet(["eth_accounts", "eth_coinbase", "eth_sendTransaction", "eth_sign", "keycard_signTypedData", "eth_signTypedData", "eth_signTypedData_v3", "personal_sign", "personal_ecRecover"])
const SIGN_METHODS = toHashSet(["eth_sign", "personal_sign", "eth_signTypedData", "eth_signTypedData_v3"])
const ACC_METHODS = toHashSet(["eth_accounts", "eth_coinbase"])
proc requestType(message: string): RequestTypes =
let data = message.parseJson
result = RequestTypes.Unknown
try:
result = parseEnum[RequestTypes](data["type"].getStr())
except:
warn "Unknown request type received", value=data["permission"].getStr()
proc toWeb3SendAsyncReadOnly(message: string): Web3SendAsyncReadOnly =
let data = message.parseJson
result = Web3SendAsyncReadOnly(
messageId: data["messageId"],
request: $data["payload"],
hostname: data{"hostname"}.getStr(),
payload: Payload(
id: data["payload"]{"id"},
rpcMethod: data["payload"]["method"].getStr()
)
)
proc toAPIRequest(message: string): APIRequest =
let data = message.parseJson
result = APIRequest(
messageId: data["messageId"],
isAllowed: data{"isAllowed"}.getBool(),
permission: data["permission"].getStr().toPermission(),
hostname: data{"hostname"}.getStr()
)
type
Service* = ref object of service_interface.ServiceInterface
@ -39,18 +108,217 @@ proc newService*(dappPermissionsService: dapp_permissions_service.ServiceInterfa
method init*(self: Service) =
discard
proc process(self: Service, data: Web3SendAsyncReadOnly): string =
if AUTH_METHODS.contains(data.payload.rpcMethod) and not self.dappPermissionsService.hasPermission(data.hostname, Permission.Web3):
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"error": {
"code": 4100
}
}
method ensResourceURL*(self: Service, username: string, url: string): (string, string, string, string, bool) =
let (scheme, host, path) = self.ensService.resourceUrl(username)
if host == "":
if data.payload.rpcMethod == "eth_sendTransaction":
try:
let request = data.request.parseJson
let fromAddress = request["params"][0]["from"].getStr()
let to = request["params"][0]{"to"}.getStr()
let value = if (request["params"][0]["value"] != nil):
request["params"][0]["value"].getStr()
else:
"0"
let password = request["password"].getStr()
let selectedGasLimit = request["selectedGasLimit"].getStr()
let selectedGasPrice = request["selectedGasPrice"].getStr()
let selectedTipLimit = request{"selectedTipLimit"}.getStr()
let selectedOverallLimit = request{"selectedOverallLimit"}.getStr()
let txData = if (request["params"][0].hasKey("data") and request["params"][0]["data"].kind != JNull):
request["params"][0]["data"].getStr()
else:
""
var success: bool
var errorMessage = ""
var response = ""
var validInput: bool = true
# TODO: use the transaction service to send the trx
#[
let eip1559Enabled = self.wallet.isEIP1559Enabled()
try:
validateTransactionInput(fromAddress, to, "", value, selectedGasLimit, selectedGasPrice, txData, eip1559Enabled, selectedTipLimit, selectedOverallLimit, "dummy")
except Exception as e:
validInput = false
success = false
errorMessage = e.msg
if validInput:
# TODO make this async
response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, eip1559Enabled, selectedTipLimit, selectedOverallLimit, password, success, txData)
errorMessage = if not success:
if response == "":
"web3-response-error"
else:
response
else:
""
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"error": errorMessage,
"result": {
"jsonrpc": "2.0",
"id": data.payload.id,
"result": if (success): response else: ""
}
}
]#
# TODO: delete this:
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"error": "",
"result": {
"jsonrpc": "2.0",
"id": data.payload.id,
"result": ""
}
}
except Exception as e:
error "Error sending the transaction", msg = e.msg
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"error": {
"code": 4100,
"message": e.msg
}
}
if SIGN_METHODS.contains(data.payload.rpcMethod):
try:
let request = data.request.parseJson
var params = request["params"]
let password = hashPassword(request["password"].getStr())
let dappAddress = self.settingsService.getDappsAddress()
var rpcResult = "{}"
case data.payload.rpcMethod:
of "eth_signTypedData", "eth_signTypedData_v3":
rpcResult = signTypedData(params[1].getStr(), dappAddress, password)
else:
rpcResult = signMessage($ %* {
"data": params[0].getStr(),
"password": password,
"account": dappAddress
})
let jsonRpcResult = rpcResult.parseJson
let success: bool = not jsonRpcResult.hasKey("error")
let errorMessage = if success: "" else: jsonRpcResult["error"]{"message"}.getStr()
let response = if success: jsonRpcResult["result"].getStr() else: ""
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"error": errorMessage,
"result": {
"jsonrpc": "2.0",
"id": if data.payload.id == nil: newJNull() else: data.payload.id,
"result": if (success): response else: ""
}
}
except Exception as e:
error "Error signing message", msg = e.msg
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"error": {
"code": 4100,
"message": e.msg
}
}
if ACC_METHODS.contains(data.payload.rpcMethod):
let dappAddress = self.settingsService.getDappsAddress()
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"result": {
"jsonrpc": "2.0",
"id": data.payload.id,
"result": if data.payload.rpcMethod == "eth_coinbase": newJString(dappAddress) else: %*[dappAddress]
}
}
let rpcResult = callRPC(data.request)
return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId,
"error": (if rpcResult == "": newJString("web3-response-error") else: newJNull()),
"result": rpcResult.parseJson
}
proc process(self: Service, data: APIRequest): string =
var value:JsonNode = case data.permission
of Permission.Web3: %* [self.settingsService.getDappsAddress()]
of Permission.ContactCode: %* self.settingsService.getPublicKey()
of Permission.Unknown: newJNull()
let isAllowed = data.isAllowed and data.permission != Permission.Unknown
info "API request received", host=data.hostname, value=data.permission, isAllowed
if isAllowed:
discard self.dappPermissionsService.addPermission(data.hostname, data.permission)
return $ %* {
"type": ResponseTypes.APIResponse,
"isAllowed": isAllowed,
"permission": data.permission,
"messageId": data.messageId,
"data": value
}
method postMessage*(self: Service, message: string): string =
case message.requestType():
of RequestTypes.Web3SendAsyncReadOnly: self.process(message.toWeb3SendAsyncReadOnly())
of RequestTypes.HistoryStateChanged: """{"type":"TODO-IMPLEMENT-THIS"}""" ############# TODO:
of RequestTypes.APIRequest: self.process(message.toAPIRequest())
else: """{"type":"TODO-IMPLEMENT-THIS"}""" ##################### TODO:
method ensResourceURL*(self: Service, ens: string, url: string): (string, string, string, string, bool) =
let contentHash = self.ensService.getContentHash(ens)
if contentHash.isNone(): # ENS does not have a content hash
return (url, url, HTTPS_SCHEME, "", false)
return (url, host, scheme, path, true)
let decodedHash = self.ensService.decodeENSContentHash(contentHash.get())
method postMessage*(self: Service, requestType: string, message: string): string =
try:
return $providerRequest(requestType, message).result
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
case decodedHash[0]:
of ENSType.IPFS:
let
base58bytes = base58.decode(base58.BTCBase58, decodedHash[1])
base32Hash = base32.encode(base32.Base32Lower, base58bytes)
result = (url, base32Hash & IPFS_GATEWAY, HTTPS_SCHEME, "", true)
of ENSType.SWARM:
result = (url, SWARM_GATEWAY, HTTPS_SCHEME,
"/bzz:/" & decodedHash[1] & "/", true)
of ENSType.IPNS:
result = (url, decodedHash[1], HTTPS_SCHEME, "", true)
else:
warn "Unknown content for", ens, contentHash

View File

@ -1,63 +0,0 @@
import json, options
include ../../common/json_utils
const DEFAULT_NETWORK_SLUG = "mainnet_rpc"
const DEFAULT_CURRENCY = "usd"
type NetworkDto* = ref object of RootObj
id*: int
slug*: string
etherscanLink*: string
name*: string
type
SettingDto* = ref object of RootObj
currentNetwork*: NetworkDto
activeTokenSymbols*: seq[string]
rawActiveTokenSymbols*: JsonNode
signingPhrase*: string
currency*: string
mnemonic*: string
walletRootAddress*: string
latestDerivedPath*: int
proc toSettingDto*(jsonObj: JsonNode): SettingDto =
result = SettingDto()
discard jsonObj.getProp("signing-phrase", result.signingPhrase)
discard jsonObj.getProp("wallet-root-address", result.walletRootAddress)
discard jsonObj.getProp("latest-derived-path", result.latestDerivedPath)
discard jsonObj.getProp("mnemonic", result.mnemonic)
if not jsonObj.getProp("currency", result.currency):
result.currency = DEFAULT_CURRENCY
var currentNetworkSlug: string
if not jsonObj.getProp("networks/current-network", currentNetworkSlug):
currentNetworkSlug = DEFAULT_NETWORK_SLUG
var networks: JsonNode
discard jsonObj.getProp("networks/networks", networks)
for networkJson in networks.getElems():
if networkJson{"id"}.getStr != currentNetworkSlug:
continue
var networkDto = NetworkDto()
discard networkJson{"config"}.getProp("NetworkId", networkDto.id)
discard networkJson.getProp("id", networkDto.slug)
discard networkJson.getProp("name", networkDto.name)
discard networkJson.getProp("etherscan-link", networkDto.etherscanLink)
result.currentNetwork = networkDto
break
result.rawActiveTokenSymbols = newJObject()
result.activeTokenSymbols = @[]
if jsonObj.hasKey("wallet/visible-tokens"):
result.rawActiveTokenSymbols = parseJson(jsonObj{"wallet/visible-tokens"}.getStr)
for symbol in result.rawActiveTokenSymbols{$result.currentNetwork.id}.getElems():
result.activeTokenSymbols.add(symbol.getStr)
proc isMnemonicBackedUp*(self: SettingDto): bool =
return self.mnemonic == ""

View File

@ -1,51 +0,0 @@
import chronicles, json
import ./service_interface, ./dto
import status/statusgo_backend_new/settings as status_go
export service_interface
logScope:
topics = "setting-service"
type
Service* = ref object of service_interface.ServiceInterface
setting: SettingDto
method delete*(self: Service) =
discard
proc newService*(): Service =
result = Service()
method init*(self: Service) =
try:
let response = status_go.getSettings()
self.setting = response.result.toSettingDto()
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return
method saveSetting*(
self: Service, attribute: string, value: string | JsonNode | bool | int | seq[string]
): SettingDto =
case attribute:
of "latest-derived-path":
self.setting.latestDerivedPath = cast[int](value)
status_go.saveSettings(attribute, self.setting.latestDerivedPath)
of "currency":
self.setting.currency = cast[string](value)
status_go.saveSettings(attribute, self.setting.currency)
of "wallet/visible-tokens":
let newValue = cast[seq[string]](value)
self.setting.activeTokenSymbols = newValue
self.setting.rawActiveTokenSymbols[$self.setting.currentNetwork.id] = newJArray()
self.setting.rawActiveTokenSymbols[$self.setting.currentNetwork.id] = %* newValue
status_go.saveSettings(attribute, $self.setting.rawActiveTokenSymbols)
return self.setting
method getSetting*(self: Service): SettingDto =
return self.setting

View File

@ -1,22 +0,0 @@
import json
import ./dto
export dto
type
ServiceInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for this service access.
method delete*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method init*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getSetting*(self: ServiceInterface): SettingDto {.base.} =
raise newException(ValueError, "No implementation available")
method saveSetting*(
self: ServiceInterface, attribute: string, value: string | JsonNode | bool | int | seq[string]
): SettingDto {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,5 +0,0 @@
type
IdentityImage* = ref object
thumbnail*: string
large*: string

View File

@ -1,12 +0,0 @@
{.used.}
import json_serialization
import node_config
type
NetworkDetails* = object
id*: string
name*: string
etherscanLink* {.serializedFieldName("etherscan-link").}: string
config*: NodeConfig

View File

@ -1,9 +0,0 @@
import json_serialization
import upstream_config
type
NodeConfig* = object
networkId* {.serializedFieldName("NetworkId").}: int
dataDir* {.serializedFieldName("DataDir").}: string
upstreamConfig* {.serializedFieldName("UpstreamConfig").}: UpstreamConfig

View File

@ -0,0 +1,147 @@
import json, options
include ../../../common/json_utils
type UpstreamConfig* = object
enabled*: bool
url*: string
type Config* = object
networkId*: int
dataDir*: string
upstreamConfig*: UpstreamConfig
type Network* = object
id*: string
etherscanLink*: string
name*: string
config*: Config
type PinnedMailservers* = object
ethProd*: string
type CurrentUserStatus* = object
statusType*: int
clock*: int64
text*: string
type WalletVisibleTokens* = object
tokens*: seq[string]
type
SettingsDto* = object # There is no point to keep all these info as settings, but we must follow status-go response
address*: string
currency*: string
currentNetwork*: string
availableNetworks*: seq[Network]
dappsAddress*: string
eip1581Address*: string
installationId*: string
keyUid*: string
latestDerivedPath*: int
linkPreviewRequestEnabled*: bool
messagesFromContactsOnly*: bool
mnemonic*: string
name*: string # user alias
photoPath*: string
pinnedMailservers*: PinnedMailservers
previewPrivacy*: bool
publicKey*: string
signingPhrase*: string
defaultSyncPeriod*: int
sendPushNotifications*: bool
appearance*: int
profilePicturesShowTo*: int
profilePicturesVisibility*: int
useMailservers*: bool
walletRootAddress*: string
sendStatusUpdates*: bool
telemetryServerUrl*: string
fleet*: string
currentUserStatus*: CurrentUserStatus
walletVisibleTokens*: WalletVisibleTokens
proc toUpstreamConfig*(jsonObj: JsonNode): UpstreamConfig =
discard jsonObj.getProp("Enabled", result.enabled)
discard jsonObj.getProp("URL", result.url)
proc toConfig*(jsonObj: JsonNode): Config =
discard jsonObj.getProp("NetworkId", result.networkId)
discard jsonObj.getProp("DataDir", result.dataDir)
var upstreamConfigObj: JsonNode
if(jsonObj.getProp("UpstreamConfig", upstreamConfigObj)):
result.upstreamConfig = toUpstreamConfig(upstreamConfigObj)
proc toNetwork*(jsonObj: JsonNode): Network =
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("etherscan-link", result.etherscanLink)
discard jsonObj.getProp("name", result.name)
var configObj: JsonNode
if(jsonObj.getProp("config", configObj)):
result.config = toConfig(configObj)
proc toPinnedMailservers*(jsonObj: JsonNode): PinnedMailservers =
discard jsonObj.getProp("eth.prod", result.ethProd)
proc toCurrentUserStatus*(jsonObj: JsonNode): CurrentUserStatus =
discard jsonObj.getProp("statusType", result.statusType)
discard jsonObj.getProp("clock", result.clock)
discard jsonObj.getProp("text", result.text)
proc toWalletVisibleTokens*(jsonObj: JsonNode, networkId: string): WalletVisibleTokens =
for netId, tokenArr in jsonObj:
if(netId != networkId or tokenArr.kind != JArray):
continue
for token in tokenArr:
result.tokens.add(token.getStr)
proc toSettingsDto*(jsonObj: JsonNode): SettingsDto =
discard jsonObj.getProp("address", result.address)
discard jsonObj.getProp("currency", result.currency)
discard jsonObj.getProp("networks/current-network", result.currentNetwork)
var networksArr: JsonNode
if(jsonObj.getProp("networks/networks", networksArr)):
if(networksArr.kind == JArray):
for networkObj in networksArr:
result.availableNetworks.add(toNetwork(networkObj))
discard jsonObj.getProp("dapps-address", result.dappsAddress)
discard jsonObj.getProp("eip1581-address", result.eip1581Address)
discard jsonObj.getProp("installation-id", result.installationId)
discard jsonObj.getProp("key-uid", result.keyUid)
discard jsonObj.getProp("latest-derived-path", result.latestDerivedPath)
discard jsonObj.getProp("link-preview-request-enabled", result.linkPreviewRequestEnabled)
discard jsonObj.getProp("messages-from-contacts-only", result.messagesFromContactsOnly)
discard jsonObj.getProp("mnemonic", result.mnemonic)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("photo-path", result.photoPath)
discard jsonObj.getProp("preview-privacy?", result.previewPrivacy)
discard jsonObj.getProp("public-key", result.publicKey)
discard jsonObj.getProp("signing-phrase", result.signingPhrase)
discard jsonObj.getProp("default-sync-period", result.defaultSyncPeriod)
discard jsonObj.getProp("send-push-notifications?", result.sendPushNotifications)
discard jsonObj.getProp("appearance", result.appearance)
discard jsonObj.getProp("profile-pictures-show-to", result.profilePicturesShowTo)
discard jsonObj.getProp("profile-pictures-visibility", result.profilePicturesVisibility)
discard jsonObj.getProp("use-mailservers?", result.useMailservers)
discard jsonObj.getProp("wallet-root-address", result.walletRootAddress)
discard jsonObj.getProp("send-status-updates?", result.sendStatusUpdates)
discard jsonObj.getProp("telemetry-server-url", result.telemetryServerUrl)
discard jsonObj.getProp("fleet", result.fleet)
var pinnedMailserversObj: JsonNode
if(jsonObj.getProp("pinned-mailservers", pinnedMailserversObj)):
result.pinnedMailservers = toPinnedMailservers(pinnedMailserversObj)
var currentUserStatusObj: JsonNode
if(jsonObj.getProp("current-user-status", currentUserStatusObj)):
result.currentUserStatus = toCurrentUserStatus(currentUserStatusObj)
var walletVisibleTokensObj: JsonNode
if(jsonObj.getProp("wallet/visible-tokens", walletVisibleTokensObj)):
result.walletVisibleTokens = toWalletVisibleTokens(walletVisibleTokensObj, result.currentNetwork)

View File

@ -1,6 +0,0 @@
import json_serialization
type
UpstreamConfig* = object
enabled* {.serializedFieldName("Enabled").}: bool
url* {.serializedFieldName("URL").}: string

View File

@ -1,28 +1,45 @@
import json, json_serialization, sugar, sequtils, chronicles
# import status/statusgo_backend_new/custom_tokens as custom_tokens
import json, tables, sugar, sequtils, strutils, atomics, os
import chronicles, json
import status/statusgo_backend/settings as status_go_settings
import status/statusgo_backend/accounts as status_accounts
from status/types/setting import Setting
import ./service_interface, ./dto
import dto/network_details
import dto/node_config
import dto/upstream_config
import service_interface, ./dto/settings
import status/statusgo_backend_new/settings as status_go
export service_interface
logScope:
topics = "settings-service"
const DEFAULT_NETWORK_NAME = "mainnet_rpc"
const TELEMETRY_BASE_URL = "https://telemetry.status.im"
# Setting keys:
const KEY_ADDRESS = "address"
const KEY_CURRENCY = "currency"
const KEY_NETWORKS_CURRENT_NETWORK = "networks/current-network"
const KEY_DAPPS_ADDRESS = "dapps-address"
const KEY_EIP1581_ADDRESS = "eip1581-address"
const KEY_INSTALLATION_ID = "installation-id"
const KEY_KEY_UID = "key-uid"
const KEY_LATEST_DERIVED_PATH = "latest-derived-path"
const KEY_LINK_PREVIEW_REQUEST_ENABLED = "link-preview-request-enabled"
const KEY_MESSAGES_FROM_CONTACTS_ONLY = "messages-from-contacts-only"
const KEY_MNEMONIC = "mnemonic"
const KEY_NAME = "name"
const KEY_PHOTO_PATH = "photo-path"
const KEY_PREVIEW_PRIVACY = "preview-privacy?"
const KEY_PUBLIC_KEY = "public-key"
const KEY_SIGNING_PHRASE = "signing-phrase"
const KEY_DEFAULT_SYNC_PERIOD = "default-sync-period"
const KEY_SEND_PUSH_NOTIFICATIONS = "send-push-notifications?"
const KEY_APPEARANCE = "appearance"
const KEY_PROFILE_PICTURES_SHOW_TO = "profile-pictures-show-to"
const KEY_PROFILE_PICTURES_VISIBILITY = "profile-pictures-visibility"
const KEY_USE_MAILSERVERS = "use-mailservers?"
const KEY_WALLET_ROOT_ADDRESS = "wallet-root-address"
const KEY_SEND_STATUS_UPDATES = "send-status-updates?"
const KEY_TELEMETRY_SERVER_URL = "telemetry-server-url"
const KEY_FLEET = "fleet"
const KEY_WALLET_VISIBLE_TOKENS = "wallet/visible-tokens"
type
Service* = ref object of ServiceInterface
# profile: Dto
type
Service* = ref object of service_interface.ServiceInterface
settings: SettingsDto
method delete*(self: Service) =
discard
@ -32,69 +49,289 @@ proc newService*(): Service =
method init*(self: Service) =
try:
echo "init"
let response = status_go.getSettings()
self.settings = response.result.toSettingsDto()
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return
method getPubKey*(self: Service): string=
return status_go_settings.getSetting(Setting.PublicKey, "0x0")
proc saveSetting(self: Service, attribute: string, value: string | JsonNode | bool | int): bool =
let response = status_go.saveSettings(attribute, value)
if(not response.error.isNil):
error "error saving settings: ", errDescription = response.error.message
return false
method getNetwork*(self: Service): string =
return status_go_settings.getSetting(Setting.Networks_CurrentNetwork, DEFAULT_NETWORK_NAME)
return true
method getAppearance*(self: Service): int =
let appearance: int = status_go_settings.getSetting[int](Setting.Appearance, 0)
return appearance
method saveAddress*(self: Service, value: string): bool =
if(self.saveSetting(KEY_ADDRESS, value)):
self.settings.address = value
return true
return false
method getMessagesFromContactsOnly*(self: Service): bool =
return status_go_settings.getSetting[bool](Setting.MessagesFromContactsOnly)
method getAddress*(self: Service): string =
return self.settings.address
method getSendUserStatus*(self: Service): bool =
return status_go_settings.getSetting[bool](Setting.SendUserStatus)
method saveCurrency*(self: Service, value: string): bool =
if(self.saveSetting(KEY_CURRENCY, value)):
self.settings.currency = value
return true
return false
method setSendUserStatus*(self: Service, value: bool) =
# this will be done in a proper way in `base_bc`, so far this is just a fix
discard status_go_settings.saveSetting(Setting.SendUserStatus, value)
method getCurrency*(self: Service): string =
if(self.settings.currency.len == 0):
self.settings.currency = DEFAULT_CURRENCY
method getCurrentUserStatus*(self: Service): int =
let userStatus = status_go_settings.getSetting[JsonNode](Setting.CurrentUserStatus)
return userStatus{"statusType"}.getInt()
return self.settings.currency
method getIdentityImage*(self: Service, address: string): IdentityImage =
var obj = status_accounts.getIdentityImage(address)
var identityImage = IdentityImage(thumbnail: obj.thumbnail, large: obj.large)
return identityImage
method saveCurrentNetwork*(self: Service, value: string): bool =
if(self.saveSetting(KEY_NETWORKS_CURRENT_NETWORK, value)):
self.settings.currentNetwork = value
return true
return false
method getCurrentNetwork*(self: Service): string =
if(self.settings.currentNetwork.len == 0):
self.settings.currentNetwork = DEFAULT_CURRENT_NETWORK
return self.settings.currentNetwork
method saveDappsAddress*(self: Service, value: string): bool =
if(self.saveSetting(KEY_DAPPS_ADDRESS, value)):
self.settings.dappsAddress = value
return true
return false
method getDappsAddress*(self: Service): string =
return status_go_settings.getSetting[string](Setting.DappsAddress)
return self.settings.dappsAddress
method setDappsAddress*(self: Service, address: string): bool =
let r = status_go_settings.saveSetting(Setting.DappsAddress, address)
return r.error == ""
method saveEip1581Address*(self: Service, value: string): bool =
if(self.saveSetting(KEY_EIP1581_ADDRESS, value)):
self.settings.eip1581Address = value
return true
return false
method getCurrentNetworkDetails*(self: Service): NetworkDetails =
let currNetwork = getSetting[string](Setting.Networks_CurrentNetwork, DEFAULT_NETWORK_NAME)
let networks = getSetting[seq[NetworkDetails]](Setting.Networks_Networks)
for n in networks:
if n.id == currNetwork:
method getEip1581Address*(self: Service): string =
return self.settings.eip1581Address
method saveInstallationId*(self: Service, value: string): bool =
if(self.saveSetting(KEY_INSTALLATION_ID, value)):
self.settings.installationId = value
return true
return false
method getInstallationId*(self: Service): string =
return self.settings.installationId
method saveKeyUid*(self: Service, value: string): bool =
if(self.saveSetting(KEY_KEY_UID, value)):
self.settings.keyUid = value
return true
return false
method getKeyUid*(self: Service): string =
return self.settings.keyUid
method saveLatestDerivedPath*(self: Service, value: int): bool =
if(self.saveSetting(KEY_LATEST_DERIVED_PATH, value)):
self.settings.latestDerivedPath = value
return true
return false
method getLatestDerivedPath*(self: Service): int =
self.settings.latestDerivedPath
method saveLinkPreviewRequestEnabled*(self: Service, value: bool): bool =
if(self.saveSetting(KEY_LINK_PREVIEW_REQUEST_ENABLED, value)):
self.settings.linkPreviewRequestEnabled = value
return true
return false
method getLinkPreviewRequestEnabled*(self: Service): bool =
self.settings.linkPreviewRequestEnabled
method saveMessagesFromContactsOnly*(self: Service, value: bool): bool =
if(self.saveSetting(KEY_MESSAGES_FROM_CONTACTS_ONLY, value)):
self.settings.messagesFromContactsOnly = value
return true
return false
method getMessagesFromContactsOnly*(self: Service): bool =
self.settings.messagesFromContactsOnly
method saveMnemonic*(self: Service, value: string): bool =
if(self.saveSetting(KEY_MNEMONIC, value)):
self.settings.mnemonic = value
return true
return false
method getMnemonic*(self: Service): string =
return self.settings.mnemonic
method saveName*(self: Service, value: string): bool =
if(self.saveSetting(KEY_NAME, value)):
self.settings.name = value
return true
return false
method getName*(self: Service): string =
return self.settings.name
method savePhotoPath*(self: Service, value: string): bool =
if(self.saveSetting(KEY_PHOTO_PATH, value)):
self.settings.photoPath = value
return true
return false
method getPhotoPath*(self: Service): string =
return self.settings.photoPath
method savePreviewPrivacy*(self: Service, value: bool): bool =
if(self.saveSetting(KEY_PREVIEW_PRIVACY, value)):
self.settings.previewPrivacy = value
return true
return false
method getPreviewPrivacy*(self: Service): bool =
self.settings.previewPrivacy
method savePublicKey*(self: Service, value: string): bool =
if(self.saveSetting(KEY_PUBLIC_KEY, value)):
self.settings.publicKey = value
return true
return false
method getPublicKey*(self: Service): string =
return self.settings.publicKey
method saveSigningPhrase*(self: Service, value: string): bool =
if(self.saveSetting(KEY_SIGNING_PHRASE, value)):
self.settings.signingPhrase = value
return true
return false
method getSigningPhrase*(self: Service): string =
return self.settings.signingPhrase
method saveDefaultSyncPeriod*(self: Service, value: int): bool =
if(self.saveSetting(KEY_DEFAULT_SYNC_PERIOD, value)):
self.settings.defaultSyncPeriod = value
return true
return false
method getDefaultSyncPeriod*(self: Service): int =
self.settings.defaultSyncPeriod
method saveSendPushNotifications*(self: Service, value: bool): bool =
if(self.saveSetting(KEY_SEND_PUSH_NOTIFICATIONS, value)):
self.settings.sendPushNotifications = value
return true
return false
method getSendPushNotifications*(self: Service): bool =
self.settings.sendPushNotifications
method saveAppearance*(self: Service, value: int): bool =
if(self.saveSetting(KEY_APPEARANCE, value)):
self.settings.appearance = value
return true
return false
method getAppearance*(self: Service): int =
self.settings.appearance
method saveProfilePicturesShowTo*(self: Service, value: int): bool =
if(self.saveSetting(KEY_PROFILE_PICTURES_SHOW_TO, value)):
self.settings.profilePicturesShowTo = value
return true
return false
method getProfilePicturesShowTo*(self: Service): int =
self.settings.profilePicturesShowTo
method saveProfilePicturesVisibility*(self: Service, value: int): bool =
if(self.saveSetting(KEY_PROFILE_PICTURES_VISIBILITY, value)):
self.settings.profilePicturesVisibility = value
return true
return false
method getProfilePicturesVisibility*(self: Service): int =
self.settings.profilePicturesVisibility
method saveUseMailservers*(self: Service, value: bool): bool =
if(self.saveSetting(KEY_USE_MAILSERVERS, value)):
self.settings.useMailservers = value
return true
return false
method getUseMailservers*(self: Service): bool =
self.settings.useMailservers
method saveWalletRootAddress*(self: Service, value: string): bool =
if(self.saveSetting(KEY_WALLET_ROOT_ADDRESS, value)):
self.settings.walletRootAddress = value
return true
return false
method getWalletRootAddress*(self: Service): string =
return self.settings.walletRootAddress
method saveSendStatusUpdates*(self: Service, value: bool): bool =
if(self.saveSetting(KEY_SEND_STATUS_UPDATES, value)):
self.settings.sendStatusUpdates = value
return true
return false
method getSendStatusUpdates*(self: Service): bool =
self.settings.sendStatusUpdates
method saveTelemetryServerUrl*(self: Service, value: string): bool =
if(self.saveSetting(KEY_TELEMETRY_SERVER_URL, value)):
self.settings.telemetryServerUrl = value
return true
return false
method getTelemetryServerUrl*(self: Service): string =
return self.settings.telemetryServerUrl
method saveFleet*(self: Service, value: string): bool =
if(self.saveSetting(KEY_FLEET, value)):
self.settings.fleet = value
return true
return false
method getFleet*(self: Service): string =
return self.settings.fleet
method getAvailableNetworks*(self: Service): seq[Network] =
return self.settings.availableNetworks
method getCurrentNetworkDetails*(self: Service): Network =
for n in self.settings.availableNetworks:
if(n.id == self.getCurrentNetwork()):
return n
# we should never be here
error "error: current network is not among available networks"
method enableDeveloperFeatures*(self: Service) =
discard status_go_settings.saveSetting(Setting.TelemetryServerUrl, TELEMETRY_BASE_URL)
discard status_go_settings.saveSetting(Setting.AutoMessageEnabled, true)
var nodeConfig = status_go_settings.getNodeConfig()
nodeConfig["LogLevel"] = newJString($LogLevel.DEBUG)
discard status_go_settings.saveSetting(Setting.NodeConfig, nodeConfig)
quit(QuitSuccess) # quits the app TODO: change this to logout instead when supported
method getCurrentNetworkId*(self: Service): int =
self.getCurrentNetworkDetails().config.networkId
method getCurrentUserStatus*(self: Service): CurrentUserStatus =
self.settings.currentUserStatus
method getPinnedMailservers*(self: Service): PinnedMailservers =
self.settings.pinnedMailservers
method getWalletVisibleTokens*(self: Service): seq[string] =
self.settings.walletVisibleTokens.tokens
method toggleTelemetry*(self: Service) =
let telemetryServerUrl = status_go_settings.getSetting[string](Setting.TelemetryServerUrl)
var newValue = ""
if telemetryServerUrl == "":
newValue = TELEMETRY_BASE_URL
newValue = "https://telemetry.status.im"
discard status_go_settings.saveSetting(Setting.TelemetryServerUrl, newValue)
@ -116,7 +353,16 @@ method toggleDebug*(self: Service) =
else:
nodeConfig["LogLevel"] = newJString($LogLevel.INFO)
discard status_go_settings.saveSetting(Setting.NodeConfig, nodeConfig)
quit(QuitSuccess) # quits the app TODO: change this to logout instead when supported
method isDebugEnabled*(self: Service): bool =
let nodeConfig = status_go_settings.getNodeConfig()
return nodeConfig["LogLevel"].getStr() != $LogLevel.INFO
method saveWalletVisibleTokens*(self: Service, tokens: seq[string]): bool =
var obj = newJObject()
obj[self.getCurrentNetwork()] = %* tokens
if(self.saveSetting(KEY_WALLET_VISIBLE_TOKENS, obj)):
self.settings.walletVisibleTokens.tokens = tokens
return true
return false

View File

@ -1,14 +1,13 @@
import dto
import dto/network_details
import dto/node_config
import dto/upstream_config
import ./dto/settings as settings_dto
export dto
export network_details
export node_config
export upstream_config
export settings_dto
type
# Default values:
const DEFAULT_CURRENT_NETWORK* = "mainnet_rpc"
const DEFAULT_CURRENCY* = "usd"
const DEFAULT_TELEMETRY_SERVER_URL* = "https://telemetry.status.im"
type
ServiceInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for this service access.
@ -18,43 +17,106 @@ method delete*(self: ServiceInterface) {.base.} =
method init*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getPubKey*(self: ServiceInterface): string {.base.} =
method saveAddress*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getNetwork*(self: ServiceInterface): string {.base.} =
method getAddress*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method getAppearance*(self: ServiceInterface): int {.base.} =
method saveCurrency*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getMessagesFromContactsOnly*(self: ServiceInterface): bool {.base.} =
method getCurrency*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method getSendUserStatus*(self: ServiceInterface): bool {.base.} =
method saveCurrentNetwork*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method setSendUserStatus*(self: ServiceInterface, value: bool) {.base.} =
method getCurrentNetwork*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrentUserStatus*(self: ServiceInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method getIdentityImage*(self: ServiceInterface, address: string): IdentityImage {.base.} =
method saveDappsAddress*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getDappsAddress*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method setDappsAddress*(self: ServiceInterface, address: string): bool {.base.} =
method saveEip1581Address*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrentNetworkDetails*(self: ServiceInterface): NetworkDetails {.base.} =
method getEip1581Address*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method toggleTelemetry*(self: ServiceInterface) {.base.} =
method saveInstallationId*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method isTelemetryEnabled*(self: ServiceInterface): bool {.base.} =
method getInstallationId*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveKeyUid*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getKeyUid*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveLatestDerivedPath*(self: ServiceInterface, value: int): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getLatestDerivedPath*(self: ServiceInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method saveLinkPreviewRequestEnabled*(self: ServiceInterface, value: bool): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getLinkPreviewRequestEnabled*(self: ServiceInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method saveMessagesFromContactsOnly*(self: ServiceInterface, value: bool): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getMessagesFromContactsOnly*(self: ServiceInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method saveMnemonic*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getMnemonic*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveName*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getName*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method savePhotoPath*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getPhotoPath*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method savePreviewPrivacy*(self: ServiceInterface, value: bool): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getPreviewPrivacy*(self: ServiceInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method savePublicKey*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getPublicKey*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveSigningPhrase*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getSigningPhrase*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveDefaultSyncPeriod*(self: ServiceInterface, value: int): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getDefaultSyncPeriod*(self: ServiceInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method toggleAutoMessage*(self: ServiceInterface) {.base.} =
@ -66,8 +128,77 @@ method isAutoMessageEnabled*(self: ServiceInterface): bool {.base.} =
method toggleDebug*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isDebugEnabled*(self: ServiceInterface): bool {.base.} =
method saveSendPushNotifications*(self: ServiceInterface, value: bool): bool {.base.} =
raise newException(ValueError, "No implementation available")
method enableDeveloperFeatures*(self: ServiceInterface) {.base.} =
method getSendPushNotifications*(self: ServiceInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method saveAppearance*(self: ServiceInterface, value: int): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getAppearance*(self: ServiceInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method saveProfilePicturesShowTo*(self: ServiceInterface, value: int): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getProfilePicturesShowTo*(self: ServiceInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method saveProfilePicturesVisibility*(self: ServiceInterface, value: int): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getProfilePicturesVisibility*(self: ServiceInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method saveUseMailservers*(self: ServiceInterface, value: bool): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getUseMailservers*(self: ServiceInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method saveWalletRootAddress*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getWalletRootAddress*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveSendStatusUpdates*(self: ServiceInterface, value: bool): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getSendStatusUpdates*(self: ServiceInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method saveTelemetryServerUrl*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getTelemetryServerUrl*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveFleet*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getFleet*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method getAvailableNetworks*(self: ServiceInterface): seq[Network] {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrentNetworkDetails*(self: ServiceInterface): Network {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrentNetworkId*(self: ServiceInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrentUserStatus*(self: ServiceInterface): CurrentUserStatus {.base.} =
raise newException(ValueError, "No implementation available")
method getPinnedMailservers*(self: ServiceInterface): PinnedMailservers {.base.} =
raise newException(ValueError, "No implementation available")
method getWalletVisibleTokens*(self: ServiceInterface): seq[string] {.base.} =
raise newException(ValueError, "No implementation available")
method saveWalletVisibleTokens*(self: ServiceInterface, tokens: seq[string]): bool {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -4,8 +4,7 @@ from sugar import `=>`
import web3/ethtypes
from web3/conversions import `$`
import status/statusgo_backend_new/custom_tokens as custom_tokens
import ../setting/service as setting_service
import ../settings/service as settings_service
import ../settings/service_interface as settings_service
import ../../../app/core/tasks/[qt, threadpool]
import ./dto, ./static_token
@ -39,8 +38,7 @@ QtObject:
type Service* = ref object of QObject
events: EventEmitter
threadpool: ThreadPool
settingService: setting_service.Service
settingsService: settings_service.Service
settingsService: settings_service.ServiceInterface
tokens: seq[TokenDto]
proc delete*(self: Service) =
@ -49,21 +47,19 @@ QtObject:
proc newService*(
events: EventEmitter,
threadpool: ThreadPool,
settingService: setting_service.Service,
settingsService: settings_service.Service
settingsService: settings_service.ServiceInterface
): Service =
new(result, delete)
result.QObject.setup
result.events = events
result.threadpool = threadpool
result.settingService = settingService
result.settingsService = settingsService
result.tokens = @[]
proc getDefaultVisibleSymbols(self: Service): seq[string] =
let networkSlug = self.settingService.getSetting().currentNetwork.slug
let networkSlug = self.settingsService.getCurrentNetwork()
if networkSlug == "mainnet_rpc":
if networkSlug == DEFAULT_CURRENT_NETWORK:
return @["SNT"]
if networkSlug == "testnet_rpc" or networkSlug == "rinkeby_rpc":
@ -74,7 +70,7 @@ QtObject:
proc init*(self: Service) =
try:
var activeTokenSymbols = self.settingService.getSetting().activeTokenSymbols
var activeTokenSymbols = self.settingsService.getWalletVisibleTokens()
if activeTokenSymbols.len == 0:
activeTokenSymbols = self.getDefaultVisibleSymbols()
@ -89,7 +85,7 @@ QtObject:
static_tokens,
map(response.result.getElems(), proc(x: JsonNode): TokenDto = x.toTokenDto(activeTokenSymbols))
).filter(
proc(x: TokenDto): bool = x.chainId == self.settingService.getSetting().currentNetwork.id
proc(x: TokenDto): bool = x.chainId == self.settingsService.getCurrentNetworkId()
)
except Exception as e:
@ -104,7 +100,7 @@ QtObject:
custom_tokens.addCustomToken(address, name, symbol, decimals, "")
let token = newDto(
name,
self.settingService.getSetting().currentNetwork.id,
self.settingsService.getCurrentNetworkId(),
fromHex(Address, address),
symbol,
decimals,
@ -123,7 +119,7 @@ QtObject:
break
let visibleSymbols = self.tokens.filter(t => t.isVisible).map(t => t.symbol)
discard self.settingService.saveSetting("wallet/visible-tokens", visibleSymbols)
discard self.settingsService.saveWalletVisibleTokens(visibleSymbols)
self.events.emit("token/visibilityToggled", VisibilityToggled(token: tokenChanged))
proc removeCustomToken*(self: Service, address: string) =
@ -145,7 +141,7 @@ QtObject:
))
proc getTokenDetails*(self: Service, address: string) =
let chainId = self.settingsService.getCurrentNetworkDetails().config.networkId
let chainId = self.settingsService.getCurrentNetworkId()
let arg = GetTokenDetailsTaskArg(
tptr: cast[ByteAddress](getTokenDetailsTask),
vptr: cast[ByteAddress](self.vptr),

View File

@ -2,14 +2,13 @@ import Tables, json, sequtils, sugar, chronicles, strformat, stint, httpclient,
import web3/[ethtypes, conversions]
import eventemitter
import ../setting/service as setting_service
import ../settings/service_interface as settings_service
import ../token/service as token_service
import ../../common/account_constants
import ../../../constants
import ./service_interface, ./dto
import status/statusgo_backend_new/accounts as status_go_accounts
import status/statusgo_backend_new/tokens as status_go_tokens
import status/statusgo_backend_new/eth as status_go_eth
export service_interface
@ -61,7 +60,21 @@ proc fetchAccounts(): seq[WalletAccountDto] =
return response.result.getElems().map(
x => x.toWalletAccountDto()
).filter(a => not a.isChat)
proc fetchTokenBalance(tokenAddress, accountAddress: string, decimals: int): float64 =
let key = tokenAddress & accountAddress
if balanceCache.hasKey(key):
return balanceCache[key]
try:
let tokenBalanceResponse = status_go_eth.getTokenBalance(tokenAddress, accountAddress)
result = parsefloat(hex2Balance(tokenBalanceResponse.result.getStr, decimals))
balanceCache[key] = result
except Exception as e:
error "Error getting token balance", msg = e.msg
proc fetchEthBalance(accountAddress: string): float64 =
let key = "0x0" & accountAddress
if balanceCache.hasKey(key):
@ -88,7 +101,7 @@ type WalletAccountUpdated = ref object of Args
type
Service* = ref object of service_interface.ServiceInterface
events: EventEmitter
settingService: setting_service.Service
settingsService: settings_service.ServiceInterface
tokenService: token_service.Service
accounts: OrderedTable[string, WalletAccountDto]
@ -96,11 +109,11 @@ method delete*(self: Service) =
discard
proc newService*(
events: EventEmitter, settingService: setting_service.Service, tokenService: token_service.Service
): Service =
events: EventEmitter, settingsService: settings_service.ServiceInterface, tokenService: token_service.Service):
Service =
result = Service()
result.events = events
result.settingService = settingService
result.settingsService = settingsService
result.tokenService = tokenService
result.accounts = initOrderedTable[string, WalletAccountDto]()
@ -110,8 +123,7 @@ method getVisibleTokens(self: Service): seq[TokenDto] =
method buildTokens(
self: Service,
account: WalletAccountDto,
prices: Table[string, float64],
balances: JsonNode,
prices: Table[string, float64]
): seq[WalletTokenDto] =
let balance = fetchEthBalance(account.address)
result = @[WalletTokenDto(
@ -127,7 +139,7 @@ method buildTokens(
)]
for token in self.getVisibleTokens():
let balance = parsefloat(hex2Balance(balances{token.addressAsString()}.getStr, token.decimals))
let balance = fetchTokenBalance($token.address, account.address, token.decimals)
result.add(
WalletTokenDto(
name: token.name,
@ -143,26 +155,18 @@ method buildTokens(
)
method fetchPrices(self: Service): Table[string, float64] =
let currency = self.settingService.getSetting().currency
let currency = self.settingsService.getCurrency()
var prices = {"ETH": fetchPrice("ETH", currency)}.toTable
for token in self.getVisibleTokens():
prices[token.symbol] = fetchPrice(token.symbol, currency)
return prices
method fetchBalances(self: Service, accounts: seq[string]): JsonNode =
let network = self.settingService.getSetting().currentNetwork
let tokens = self.getVisibleTokens().map(t => t.addressAsString())
return status_go_tokens.getBalances(network.id, accounts, tokens).result
method 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})
account.tokens = self.buildTokens(account, prices)
method init*(self: Service) =
try:
@ -189,74 +193,128 @@ method getWalletAccount*(self: Service, accountIndex: int): WalletAccountDto =
method getCurrencyBalance*(self: Service): float64 =
return self.getWalletAccounts().map(a => a.getCurrencyBalance()).foldl(a + b, 0.0)
method addNewAccountToLocalStore(self: Service) =
let accounts = fetchAccounts()
let prices = self.fetchPrices()
method getDefaultAccount(self: Service): string =
return status_go_eth.getAccounts().result[0].getStr
var newAccount = accounts[0]
for account in accounts:
if not self.accounts.haskey(account.address):
newAccount = account
break
method saveAccount(
self: Service,
address: string,
name: string,
password: string,
color: string,
accountType: string,
isADerivedAccount = true,
walletIndex: int = 0,
id: string = "",
publicKey: string = "",
): string =
try:
status_go_accounts.saveAccount(
address,
name,
password,
color,
accountType,
isADerivedAccount = true,
walletIndex,
id,
publicKey,
)
let accounts = fetchAccounts()
let prices = self.fetchPrices()
let balances = self.fetchBalances(@[newAccount.address])
newAccount.tokens = self.buildTokens(newAccount, prices, balances{newAccount.address})
self.accounts[newAccount.address] = newAccount
self.events.emit("walletAccount/accountSaved", AccountSaved(account: newAccount))
var newAccount = accounts[0]
for account in accounts:
if not self.accounts.haskey(account.address):
newAccount = account
break
newAccount.tokens = self.buildTokens(newAccount, prices)
self.accounts[newAccount.address] = newAccount
self.events.emit("walletAccount/accountSaved", AccountSaved(account: newAccount))
except Exception as e:
return fmt"Error adding new account: {e.msg}"
method generateNewAccount*(self: Service, password: string, accountName: string, color: string): string =
try:
discard status_go_accounts.generateAccount(
password,
accountName,
color,
)
except Exception as e:
return fmt"Error generating new account: {e.msg}"
let
walletRootAddress = self.settingsService.getWalletRootAddress()
walletIndex = self.settingsService.getLatestDerivedPath() + 1
defaultAccount = self.getDefaultAccount()
isPasswordOk = status_go_accounts.verifyAccountPassword(defaultAccount, password, KEYSTOREDIR)
self.addNewAccountToLocalStore()
if not isPasswordOk:
return "Error generating new account: invalid password"
let accountResponse = status_go_accounts.loadAccount(walletRootAddress, password)
let accountId = accountResponse.result{"id"}.getStr
let path = "m/" & $walletIndex
let deriveResponse = status_go_accounts.deriveAccounts(accountId, @[path])
let errMsg = self.saveAccount(
deriveResponse.result[path]{"address"}.getStr,
accountName,
password,
color,
status_go_accounts.GENERATED,
true,
walletIndex,
accountId,
deriveResponse.result[path]{"publicKey"}.getStr
)
if errMsg != "":
return errMsg
discard self.settingsService.saveLatestDerivedPath(walletIndex)
return ""
method addAccountsFromPrivateKey*(self: Service, privateKey: string, password: string, accountName: string, color: string): string =
try:
discard status_go_accounts.addAccountWithPrivateKey(
privateKey,
password,
accountName,
color,
)
except Exception as e:
return fmt"Error adding account with private key: {e.msg}"
let
accountResponse = status_go_accounts.multiAccountImportPrivateKey(privateKey)
defaultAccount = self.getDefaultAccount()
isPasswordOk = status_go_accounts.verifyAccountPassword(defaultAccount, password, KEYSTOREDIR)
self.addNewAccountToLocalStore()
return ""
if not isPasswordOk:
return "Error generating new account: invalid password"
method addAccountsFromSeed*(self: Service, mnemonic: string, password: string, accountName: string, color: string): string =
try:
discard status_go_accounts.addAccountWithMnemonic(
mnemonic,
password,
accountName,
color,
)
except Exception as e:
return fmt"Error adding account with mnemonic: {e.msg}"
return self.saveAccount(
accountResponse.result{"address"}.getStr,
accountName,
password,
color,
status_go_accounts.KEY,
false,
0,
accountResponse.result{"accountId"}.getStr,
accountResponse.result{"publicKey"}.getStr,
)
self.addNewAccountToLocalStore()
return ""
method addAccountsFromSeed*(self: Service, seedPhrase: string, password: string, accountName: string, color: string): string =
let mnemonic = replace(seedPhrase, ',', ' ')
let paths = @[PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET]
let accountResponse = status_go_accounts.multiAccountImportMnemonic(mnemonic)
let accountId = accountResponse.result{"id"}.getStr
let deriveResponse = status_go_accounts.deriveAccounts(accountId, paths)
let
defaultAccount = self.getDefaultAccount()
isPasswordOk = status_go_accounts.verifyAccountPassword(defaultAccount, password, KEYSTOREDIR)
if not isPasswordOk:
return "Error generating new account: invalid password"
return self.saveAccount(
deriveResponse.result[PATH_DEFAULT_WALLET]{"address"}.getStr,
accountName,
password,
color,
status_go_accounts.SEED,
true,
0,
accountId,
deriveResponse.result[PATH_DEFAULT_WALLET]{"publicKey"}.getStr
)
method addWatchOnlyAccount*(self: Service, address: string, accountName: string, color: string): string =
try:
discard status_go_accounts.addAccountWatch(
address,
accountName,
color,
)
except Exception as e:
return fmt"Error adding account with mnemonic: {e.msg}"
self.addNewAccountToLocalStore()
return ""
return self.saveAccount(address, accountName, "", color, status_go_accounts.WATCH, false)
method deleteAccount*(self: Service, address: string) =
discard status_go_accounts.deleteAccount(address)
@ -266,7 +324,7 @@ method deleteAccount*(self: Service, address: string) =
self.events.emit("walletAccount/accountDeleted", AccountDeleted(account: accountDeleted))
method updateCurrency*(self: Service, newCurrency: string) =
discard self.settingService.saveSetting("currency", newCurrency)
discard self.settingsService.saveCurrency(newCurrency)
self.refreshBalances()
self.events.emit("walletAccount/currencyUpdated", CurrencyUpdated())