diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim index 95497f0e7f..abc32e39d0 100644 --- a/src/app/boot/app_controller.nim +++ b/src/app/boot/app_controller.nim @@ -128,7 +128,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController = result.keychainService = keychain_service.newService(statusFoundation.events) result.ethService = eth_service.newService() result.accountsService = accounts_service.newService(statusFoundation.fleetConfiguration) - result.networkService = network_service.newService(result.settingsService) + result.networkService = network_service.newService(statusFoundation.events, result.settingsService) result.contactsService = contacts_service.newService( statusFoundation.events, statusFoundation.threadpool, result.settingsService ) @@ -304,10 +304,8 @@ proc load(self: AppController) = self.tokenService.init() self.dappPermissionsService.init() self.providerService.init() - self.walletAccountService.init() self.transactionService.init() self.stickersService.init() - self.networkService.init() self.activityCenterService.init() self.savedAddressService.init() self.aboutService.init() @@ -321,6 +319,9 @@ proc load(self: AppController) = singletonInstance.engine.setRootContextProperty("localAccountSensitiveSettings", self.localAccountSensitiveSettingsVariant) singletonInstance.engine.setRootContextProperty("globalUtils", self.globalUtilsVariant) + self.networkService.init() + self.walletAccountService.init() + # other global instances self.buildAndRegisterLocalAccountSensitiveSettings() self.buildAndRegisterUserProfile() diff --git a/src/app/modules/main/io_interface.nim b/src/app/modules/main/io_interface.nim index 96564c587c..955a8d071b 100644 --- a/src/app/modules/main/io_interface.nim +++ b/src/app/modules/main/io_interface.nim @@ -14,7 +14,7 @@ include ./private_interfaces/module_app_search_delegate_interface include ./private_interfaces/module_browser_section_delegate_interface include ./private_interfaces/module_communities_section_delegate_interface include ./private_interfaces/module_node_section_delegate_interface - +include ./private_interfaces/module_networks_delegate_interface # This way (using concepts) is used only for the modules managed by AppController type diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 612ee89e1d..34ca355a64 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -19,6 +19,7 @@ import stickers/module as stickers_module import activity_center/module as activity_center_module import communities/module as communities_module import node_section/module as node_section_module +import networks/module as networks_module import ../../../app_service/service/keychain/service as keychain_service import ../../../app_service/service/chat/service as chat_service @@ -70,6 +71,7 @@ type communitiesModule: communities_module.AccessInterface appSearchModule: app_search_module.AccessInterface nodeSectionModule: node_section_module.AccessInterface + networksModule: networks_module.AccessInterface moduleLoaded: bool # Forward declaration @@ -141,7 +143,7 @@ proc newModule*[T]( result.profileSectionModule = profile_section_module.newModule( result, events, accountsService, settingsService, profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService, - devicesService, mailserversService, chatService, ensService, walletAccountService, networkService, + devicesService, mailserversService, chatService, ensService, walletAccountService, ) result.stickersModule = stickers_module.newModule(result, events, stickersService) result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService, @@ -150,6 +152,7 @@ proc newModule*[T]( result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService, messageService) result.nodeSectionModule = node_section_module.newModule(result, events, settingsService, nodeService, nodeConfigurationService) + result.networksModule = networks_module.newModule(result, events, networkService, walletAccountService) method delete*[T](self: Module[T]) = self.chatSectionModule.delete @@ -164,6 +167,7 @@ method delete*[T](self: Module[T]) = self.browserSectionModule.delete self.appSearchModule.delete self.nodeSectionModule.delete + self.networksModule.delete self.view.delete self.viewVariant.delete self.controller.delete @@ -342,10 +346,12 @@ method load*[T]( self.chatSectionModule.load(events, settingsService, contactsService, chatService, communityService, messageService, gifService, mailserversService) for cModule in self.communitySectionsModule.values: cModule.load(events, settingsService, contactsService, chatService, communityService, messageService, gifService, mailserversService) + self.browserSectionModule.load() # self.nodeManagementSectionModule.load() self.profileSectionModule.load() self.stickersModule.load() + self.networksModule.load() self.activityCenterModule.load() self.communitiesModule.load() self.appSearchModule.load() @@ -391,6 +397,9 @@ proc checkIfModuleDidLoad [T](self: Module[T]) = if(not self.appSearchModule.isLoaded()): return + if(not self.networksModule.isLoaded()): + return + self.moduleLoaded = true self.delegate.mainDidLoad() @@ -424,6 +433,9 @@ proc profileSectionDidLoad*[T](self: Module[T]) = method nodeSectionDidLoad*[T](self: Module[T]) = self.checkIfModuleDidLoad() +method networksModuleDidLoad*[T](self: Module[T]) = + self.checkIfModuleDidLoad() + method viewDidLoad*[T](self: Module[T]) = self.checkIfModuleDidLoad() diff --git a/src/app/modules/main/networks/controller.nim b/src/app/modules/main/networks/controller.nim new file mode 100644 index 0000000000..5007f24cdc --- /dev/null +++ b/src/app/modules/main/networks/controller.nim @@ -0,0 +1,39 @@ +import ./controller_interface +import ../../../core/eventemitter +import ../../../../app_service/service/network/service as network_service +import ../../../../app_service/service/wallet_account/service as wallet_account_service +import ./io_interface + +export controller_interface + +type + Controller* = ref object of controller_interface.AccessInterface + delegate: io_interface.AccessInterface + events: EventEmitter + networkService: network_service.Service + walletAccountService: wallet_account_service.Service + +proc newController*( + delegate: io_interface.AccessInterface, + events: EventEmitter, + networkService: network_service.Service, + walletAccountService: wallet_account_service.Service, +): Controller = + result = Controller() + result.delegate = delegate + result.events = events + result.networkService = networkService + result.walletAccountService = walletAccountService + +method delete*(self: Controller) = + discard + +method init*(self: Controller) = + self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args): + self.delegate.refreshNetworks() + +method getNetworks*(self: Controller): seq[NetworkDto] = + return self.networkService.getNetworks() + +method toggleNetwork*(self: Controller, chainId: int) = + self.walletAccountService.toggleNetworkEnabled(chainId) \ No newline at end of file diff --git a/src/app/modules/main/profile_section/wallet/networks/controller_interface.nim b/src/app/modules/main/networks/controller_interface.nim similarity index 63% rename from src/app/modules/main/profile_section/wallet/networks/controller_interface.nim rename to src/app/modules/main/networks/controller_interface.nim index 152a1cabe6..d13ec9791e 100644 --- a/src/app/modules/main/profile_section/wallet/networks/controller_interface.nim +++ b/src/app/modules/main/networks/controller_interface.nim @@ -1,4 +1,4 @@ -import ../../../../../../app_service/service/network/dto +import ../../../../app_service/service/network/dto type AccessInterface* {.pure inheritable.} = ref object of RootObj @@ -11,4 +11,7 @@ method init*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") method getNetworks*(self: AccessInterface): seq[NetworkDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method toggleNetwork*(self: AccessInterface, chainId: int) {.base.} = raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/profile_section/wallet/networks/io_interface.nim b/src/app/modules/main/networks/io_interface.nim similarity index 78% rename from src/app/modules/main/profile_section/wallet/networks/io_interface.nim rename to src/app/modules/main/networks/io_interface.nim index 16fa526214..cd15d134b6 100644 --- a/src/app/modules/main/profile_section/wallet/networks/io_interface.nim +++ b/src/app/modules/main/networks/io_interface.nim @@ -19,6 +19,11 @@ method isLoaded*(self: AccessInterface): bool {.base.} = method viewDidLoad*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") +method toggleNetwork*(self: AccessInterface, chainId: int) {.base.} = + raise newException(ValueError, "No implementation available") + +method refreshNetworks*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") type ## Abstract class (concept) which must be implemented by object/s used in this diff --git a/src/app/modules/main/profile_section/wallet/networks/item.nim b/src/app/modules/main/networks/item.nim similarity index 90% rename from src/app/modules/main/profile_section/wallet/networks/item.nim rename to src/app/modules/main/networks/item.nim index a38eee2f64..36ea3ea5b7 100644 --- a/src/app/modules/main/profile_section/wallet/networks/item.nim +++ b/src/app/modules/main/networks/item.nim @@ -11,6 +11,7 @@ type nativeCurrencyName: string nativeCurrencySymbol: string isTest: bool + isEnabled: bool proc initItem*( chainId: int, @@ -21,7 +22,8 @@ proc initItem*( blockExplorerURL: string, nativeCurrencyName: string, nativeCurrencySymbol: string, - isTest: bool + isTest: bool, + isEnabled: bool, ): Item = result.chainId = chainId result.nativeCurrencyDecimals = nativeCurrencyDecimals @@ -32,6 +34,7 @@ proc initItem*( result.nativeCurrencyName = nativeCurrencyName result.nativeCurrencySymbol = nativeCurrencySymbol result.isTest = isTest + result.isEnabled = isEnabled proc `$`*(self: Item): string = result = fmt"""NetworkItem( @@ -44,6 +47,7 @@ proc `$`*(self: Item): string = nativeCurrencyName:{self.nativeCurrencyName}, nativeCurrencySymbol:{self.nativeCurrencySymbol}, isTest:{self.isTest} + isEnabled:{self.isEnabled} ]""" proc getChainId*(self: Item): int = @@ -71,4 +75,7 @@ proc getNativeCurrencySymbol*(self: Item): string = return self.nativeCurrencySymbol proc getIsTest*(self: Item): bool = - return self.isTest \ No newline at end of file + return self.isTest + +proc getIsEnabled*(self: Item): bool = + return self.isEnabled \ No newline at end of file diff --git a/src/app/modules/main/profile_section/wallet/networks/model.nim b/src/app/modules/main/networks/model.nim similarity index 95% rename from src/app/modules/main/profile_section/wallet/networks/model.nim rename to src/app/modules/main/networks/model.nim index 4c7c8645bf..42cb7ccb1d 100644 --- a/src/app/modules/main/profile_section/wallet/networks/model.nim +++ b/src/app/modules/main/networks/model.nim @@ -13,6 +13,7 @@ type NativeCurrencyName NativeCurrencySymbol IsTest + IsEnabled QtObject: type @@ -57,6 +58,7 @@ QtObject: ModelRole.NativeCurrencyName.int:"nativeCurrencyName", ModelRole.NativeCurrencySymbol.int:"nativeCurrencySymbol", ModelRole.IsTest.int:"isTest", + ModelRole.IsEnabled.int:"isEnabled", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -88,6 +90,8 @@ QtObject: result = newQVariant(item.getNativeCurrencySymbol()) of ModelRole.IsTest: result = newQVariant(item.getIsTest()) + of ModelRole.IsEnabled: + result = newQVariant(item.getIsEnabled()) proc setItems*(self: Model, items: seq[Item]) = self.beginResetModel() diff --git a/src/app/modules/main/profile_section/wallet/networks/module.nim b/src/app/modules/main/networks/module.nim similarity index 64% rename from src/app/modules/main/profile_section/wallet/networks/module.nim rename to src/app/modules/main/networks/module.nim index f0e629f66a..05c33399c2 100644 --- a/src/app/modules/main/profile_section/wallet/networks/module.nim +++ b/src/app/modules/main/networks/module.nim @@ -1,9 +1,10 @@ import NimQml import ../io_interface as delegate_interface import io_interface, view, controller -import ../../../../../global/global_singleton -import ../../../../../core/eventemitter -import ../../../../../../app_service/service/network/service as network_service +import ../../../global/global_singleton +import ../../../core/eventemitter +import ../../../../app_service/service/network/service as network_service +import ../../../../app_service/service/wallet_account/service as wallet_account_service export io_interface @@ -19,25 +20,30 @@ proc newModule*( delegate: delegate_interface.AccessInterface, events: EventEmitter, networkService: networkService.Service, + walletAccountService: wallet_account_service.Service, ): Module = result = Module() result.delegate = delegate result.view = view.newView(result) result.viewVariant = newQVariant(result.view) - result.controller = controller.newController(result, events, networkService) + result.controller = controller.newController(result, events, networkService, walletAccountService) result.moduleLoaded = false - singletonInstance.engine.setRootContextProperty("profileSectionWalletNetworkModule", result.viewVariant) + singletonInstance.engine.setRootContextProperty("networksModule", result.viewVariant) method delete*(self: Module) = self.view.delete self.viewVariant.delete self.controller.delete -method load*(self: Module) = +method refreshNetworks*(self: Module) = let networks = self.controller.getNetworks() self.view.load(networks) +method load*(self: Module) = + self.controller.init() + self.refreshNetworks() + method isLoaded*(self: Module): bool = return self.moduleLoaded @@ -46,4 +52,7 @@ proc checkIfModuleDidLoad(self: Module) = self.delegate.networksModuleDidLoad() method viewDidLoad*(self: Module) = - self.checkIfModuleDidLoad() \ No newline at end of file + self.checkIfModuleDidLoad() + +method toggleNetwork*(self: Module, chainId: int) = + self.controller.toggleNetwork(chainId) \ No newline at end of file diff --git a/src/app/modules/main/profile_section/wallet/networks/view.nim b/src/app/modules/main/networks/view.nim similarity index 73% rename from src/app/modules/main/profile_section/wallet/networks/view.nim rename to src/app/modules/main/networks/view.nim index 99987f74b8..5406b45d8c 100644 --- a/src/app/modules/main/profile_section/wallet/networks/view.nim +++ b/src/app/modules/main/networks/view.nim @@ -1,6 +1,6 @@ import NimQml, sequtils, sugar -import ../../../../../../app_service/service/network/dto +import ../../../../app_service/service/network/dto import ./io_interface import ./model import ./item @@ -9,6 +9,7 @@ QtObject: type View* = ref object of QObject delegate: io_interface.AccessInterface + enabled: Model layer1: Model layer2: Model test: Model @@ -25,6 +26,7 @@ QtObject: result.layer1 = newModel() result.layer2 = newModel() result.test = newModel() + result.enabled = newModel() result.setup() proc layer1Changed*(self: View) {.signal.} @@ -54,6 +56,15 @@ QtObject: read = getTest notify = testChanged + proc enabledChanged*(self: View) {.signal.} + + proc getEnabled(self: View): QVariant {.slot.} = + return newQVariant(self.enabled) + + QtProperty[QVariant] enabled: + read = getEnabled + notify = enabledChanged + proc load*(self: View, networks: seq[NetworkDto]) = let items = networks.map(n => initItem( n.chainId, @@ -64,10 +75,19 @@ QtObject: n.blockExplorerURL, n.nativeCurrencyName, n.nativeCurrencySymbol, - n.isTest + n.isTest, + n.enabled, )) self.layer1.setItems(items.filter(i => i.getLayer() == 1 and not i.getIsTest())) self.layer2.setItems(items.filter(i => i.getLayer() == 2 and not i.getIsTest())) self.test.setItems(items.filter(i => i.getIsTest())) + self.enabled.setItems(items.filter(i => i.getIsEnabled())) - self.delegate.viewDidLoad() \ No newline at end of file + self.layer1Changed() + self.layer2Changed() + self.testChanged() + + self.delegate.viewDidLoad() + + proc toggleNetwork*(self: View, chainId: int) {.slot.} = + self.delegate.toggleNetwork(chainId) \ No newline at end of file diff --git a/src/app/modules/main/private_interfaces/module_networks_delegate_interface.nim b/src/app/modules/main/private_interfaces/module_networks_delegate_interface.nim new file mode 100644 index 0000000000..5729b7d4cb --- /dev/null +++ b/src/app/modules/main/private_interfaces/module_networks_delegate_interface.nim @@ -0,0 +1,2 @@ +method networksModuleDidLoad*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/profile_section/io_interface.nim b/src/app/modules/main/profile_section/io_interface.nim index 17e6b5513b..b44e734a13 100644 --- a/src/app/modules/main/profile_section/io_interface.nim +++ b/src/app/modules/main/profile_section/io_interface.nim @@ -80,9 +80,6 @@ method ensUsernamesModuleDidLoad*(self: AccessInterface) {.base.} = method getEnsUsernamesModule*(self: AccessInterface): QVariant {.base.} = raise newException(ValueError, "No implementation available") -method walletModuleDidLoad*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - type ## Abstract class (concept) which must be implemented by object/s used in this ## module. diff --git a/src/app/modules/main/profile_section/module.nim b/src/app/modules/main/profile_section/module.nim index 4a74cd3e41..0a656f4c56 100644 --- a/src/app/modules/main/profile_section/module.nim +++ b/src/app/modules/main/profile_section/module.nim @@ -15,7 +15,6 @@ import ../../../../app_service/service/mailservers/service as mailservers_servic import ../../../../app_service/service/chat/service as chat_service import ../../../../app_service/service/ens/service as ens_service import ../../../../app_service/service/wallet_account/service_interface as wallet_account_service -import ../../../../app_service/service/network/service as network_service import ./profile/module as profile_module import ./contacts/module as contacts_module @@ -27,7 +26,6 @@ import ./devices/module as devices_module import ./sync/module as sync_module import ./notifications/module as notifications_module import ./ens_usernames/module as ens_usernames_module -import ./wallet/module as wallet_module export io_interface @@ -49,7 +47,6 @@ type syncModule: sync_module.AccessInterface notificationsModule: notifications_module.AccessInterface ensUsernamesModule: ens_usernames_module.AccessInterface - walletModule: wallet_module.AccessInterface proc newModule*[T](delegate: T, events: EventEmitter, @@ -66,7 +63,6 @@ proc newModule*[T](delegate: T, chatService: chat_service.Service, ensService: ens_service.Service, walletAccountService: wallet_account_service.ServiceInterface, - networkService: network_service.Service, ): Module[T] = result = Module[T]() result.delegate = delegate @@ -87,7 +83,6 @@ proc newModule*[T](delegate: T, result.ensUsernamesModule = ens_usernames_module.newModule( result, events, settingsService, ensService, walletAccountService ) - result.walletModule = wallet_module.newModule(result, events, networkService) singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant) @@ -100,7 +95,6 @@ method delete*[T](self: Module[T]) = self.advancedModule.delete self.devicesModule.delete self.syncModule.delete - self.walletModule.delete self.view.delete self.viewVariant.delete @@ -118,7 +112,6 @@ method load*[T](self: Module[T]) = self.syncModule.load() self.notificationsModule.load() self.ensUsernamesModule.load() - self.walletModule.load() method isLoaded*[T](self: Module[T]): bool = return self.moduleLoaded @@ -154,9 +147,6 @@ proc checkIfModuleDidLoad[T](self: Module[T]) = if(not self.ensUsernamesModule.isLoaded()): return - if(not self.walletModule.isLoaded()): - return - self.moduleLoaded = true self.delegate.profileSectionDidLoad() @@ -169,9 +159,6 @@ method profileModuleDidLoad*[T](self: Module[T]) = method getProfileModule*[T](self: Module[T]): QVariant = self.profileModule.getModuleAsVariant() -method walletModuleDidLoad*[T](self: Module[T]) = - self.checkIfModuleDidLoad() - method contactsModuleDidLoad*[T](self: Module[T]) = self.checkIfModuleDidLoad() diff --git a/src/app/modules/main/profile_section/wallet/io_interface.nim b/src/app/modules/main/profile_section/wallet/io_interface.nim deleted file mode 100644 index 93426ecbb4..0000000000 --- a/src/app/modules/main/profile_section/wallet/io_interface.nim +++ /dev/null @@ -1,3 +0,0 @@ -# Defines how parent module accesses this module -include ./private_interfaces/module_base_interface -include ./private_interfaces/module_access_interface \ No newline at end of file diff --git a/src/app/modules/main/profile_section/wallet/module.nim b/src/app/modules/main/profile_section/wallet/module.nim deleted file mode 100644 index 76a022f2bc..0000000000 --- a/src/app/modules/main/profile_section/wallet/module.nim +++ /dev/null @@ -1,48 +0,0 @@ -import NimQml -import ./io_interface -import ../../../../global/global_singleton -import ../../../../core/eventemitter -import ../../../../../app_service/service/network/service as network_service -import ../io_interface as delegate_interface - -import ./networks/module as networks_module - -export io_interface - -type - Module* = ref object of io_interface.AccessInterface - delegate: delegate_interface.AccessInterface - moduleLoaded: bool - - networksModule: networks_module.AccessInterface - - -proc newModule*( - delegate: delegate_interface.AccessInterface, - events: EventEmitter, - networkService: network_service.Service, -): Module = - result = Module() - result.delegate = delegate - result.moduleLoaded = false - - result.networksModule = networks_module.newModule(result, events, networkService) - -method delete*(self: Module) = - self.networksModule.delete - -method load*(self: Module) = - self.networksModule.load() - -method isLoaded*(self: Module): bool = - return self.moduleLoaded - -proc checkIfModuleDidLoad(self: Module) = - if(not self.networksModule.isLoaded()): - return - - self.moduleLoaded = true - self.delegate.walletModuleDidLoad() - -method networksModuleDidLoad*(self: Module) = - self.checkIfModuleDidLoad() diff --git a/src/app/modules/main/profile_section/wallet/networks/controller.nim b/src/app/modules/main/profile_section/wallet/networks/controller.nim deleted file mode 100644 index 2fb178b997..0000000000 --- a/src/app/modules/main/profile_section/wallet/networks/controller.nim +++ /dev/null @@ -1,31 +0,0 @@ -import ./controller_interface -import ../../../../../core/eventemitter -import ../../../../../../app_service/service/network/service as network_service -import ./io_interface - -export controller_interface - -type - Controller* = ref object of controller_interface.AccessInterface - delegate: io_interface.AccessInterface - events: EventEmitter - networkService: network_service.Service - -proc newController*( - delegate: io_interface.AccessInterface, - events: EventEmitter, - networkService: network_service.Service -): Controller = - result = Controller() - result.delegate = delegate - result.events = events - result.networkService = networkService - -method delete*(self: Controller) = - discard - -method init*(self: Controller) = - discard - -method getNetworks*(self: Controller): seq[NetworkDto] = - return self.networkService.getNetworks() \ No newline at end of file diff --git a/src/app/modules/main/profile_section/wallet/private_interfaces/module_access_interface.nim b/src/app/modules/main/profile_section/wallet/private_interfaces/module_access_interface.nim deleted file mode 100644 index 34810f8cad..0000000000 --- a/src/app/modules/main/profile_section/wallet/private_interfaces/module_access_interface.nim +++ /dev/null @@ -1,13 +0,0 @@ -import NimQml - -method delete*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - -method load*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - -method isLoaded*(self: AccessInterface): bool {.base.} = - raise newException(ValueError, "No implementation available") - -method networksModuleDidLoad*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/profile_section/wallet/private_interfaces/module_base_interface.nim b/src/app/modules/main/profile_section/wallet/private_interfaces/module_base_interface.nim deleted file mode 100644 index a31e963994..0000000000 --- a/src/app/modules/main/profile_section/wallet/private_interfaces/module_base_interface.nim +++ /dev/null @@ -1,5 +0,0 @@ -type - AccessInterface* {.pure inheritable.} = ref object of RootObj - -# Since nim doesn't support using concepts in second level nested types we -# define delegate interfaces within access interface. diff --git a/src/app/modules/main/wallet_section/account_tokens/module.nim b/src/app/modules/main/wallet_section/account_tokens/module.nim index d82be2d264..d2a1ec395e 100644 --- a/src/app/modules/main/wallet_section/account_tokens/module.nim +++ b/src/app/modules/main/wallet_section/account_tokens/module.nim @@ -55,6 +55,9 @@ method load*(self: Module) = self.events.on(SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED) do(e:Args): self.switchAccount(self.currentAccountIndex) + self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args): + self.switchAccount(self.currentAccountIndex) + self.controller.init() self.view.load() diff --git a/src/app/modules/main/wallet_section/accounts/module.nim b/src/app/modules/main/wallet_section/accounts/module.nim index d094b18056..71b949cf0d 100644 --- a/src/app/modules/main/wallet_section/accounts/module.nim +++ b/src/app/modules/main/wallet_section/accounts/module.nim @@ -85,6 +85,9 @@ method load*(self: Module) = self.events.on(SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED) do(e:Args): self.refreshWalletAccounts() + + self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args): + self.refreshWalletAccounts() self.controller.init() self.view.load() diff --git a/src/app/modules/main/wallet_section/all_tokens/controller.nim b/src/app/modules/main/wallet_section/all_tokens/controller.nim index 0079b28b9e..015fb6b69b 100644 --- a/src/app/modules/main/wallet_section/all_tokens/controller.nim +++ b/src/app/modules/main/wallet_section/all_tokens/controller.nim @@ -34,6 +34,9 @@ method init*(self: Controller) = self.events.on(SIGNAL_TOKEN_DETAILS_LOADED) do(e:Args): let args = TokenDetailsLoadedArgs(e) self.delegate.tokenDetailsWereResolved(args.tokenDetails) + + self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args): + self.delegate.refreshTokens() method getTokens*(self: Controller): seq[token_service.TokenDto] = for tokens in self.tokenService.getTokens().values: diff --git a/src/app/modules/main/wallet_section/current_account/module.nim b/src/app/modules/main/wallet_section/current_account/module.nim index 6a5f37daf7..06b47a59c5 100644 --- a/src/app/modules/main/wallet_section/current_account/module.nim +++ b/src/app/modules/main/wallet_section/current_account/module.nim @@ -47,6 +47,9 @@ method load*(self: Module) = self.events.on(SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED) do(e:Args): self.switchAccount(self.currentAccountIndex) + self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args): + self.switchAccount(self.currentAccountIndex) + self.controller.init() self.view.load() @@ -63,4 +66,4 @@ method switchAccount*(self: Module, accountIndex: int) = self.view.setData(walletAccount) method update*(self: Module, address: string, accountName: string, color: string) = - self.controller.update(address, accountName, color) + self.controller.update(address, accountName, color) diff --git a/src/app/modules/main/wallet_section/module.nim b/src/app/modules/main/wallet_section/module.nim index fa0af40732..626fa0bda0 100644 --- a/src/app/modules/main/wallet_section/module.nim +++ b/src/app/modules/main/wallet_section/module.nim @@ -98,6 +98,8 @@ method load*[T](self: Module[T]) = self.setTotalCurrencyBalance() self.events.on(SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED) do(e:Args): self.setTotalCurrencyBalance() + self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args): + self.setTotalCurrencyBalance() self.controller.init() self.view.load() diff --git a/src/app_service/common/network_constants.nim b/src/app_service/common/network_constants.nim index c273dabd7e..4efd275d1e 100644 --- a/src/app_service/common/network_constants.nim +++ b/src/app_service/common/network_constants.nim @@ -238,7 +238,7 @@ var NODE_CONFIG* = %* { { "chainId": 10, "chainName": "Optimistic Ethereum", - "rpcUrl": "https://mainnet.infura.io/v3/" & INFURA_TOKEN_RESOLVED, + "rpcUrl": "https://optimism-mainnet.infura.io/v3/" & INFURA_TOKEN_RESOLVED, "blockExplorerUrl": "https://optimistic.etherscan.io", "iconUrl": "", "nativeCurrencyName": "Ether", diff --git a/src/app_service/service/network/service.nim b/src/app_service/service/network/service.nim index 216c2d5b48..b1061aa95b 100644 --- a/src/app_service/service/network/service.nim +++ b/src/app_service/service/network/service.nim @@ -1,7 +1,6 @@ import json, json_serialization, chronicles, atomics -import options - +import ../../../app/core/eventemitter import ../../../app/global/global_singleton import ../../../backend/network as status_network import ../settings/service as settings_service @@ -15,6 +14,7 @@ logScope: type Service* = ref object of network_interface.ServiceInterface + events: EventEmitter networks: seq[NetworkDto] networksInited: bool dirty: Atomic[bool] @@ -24,8 +24,9 @@ type method delete*(self: Service) = discard -proc newService*(settingsService: settings_service.Service): Service = +proc newService*(events: EventEmitter, settingsService: settings_service.Service): Service = result = Service() + result.events = events result.settingsService = settingsService method init*(self: Service) = @@ -78,3 +79,9 @@ method getNetwork*(self: Service, networkType: NetworkType): NetworkDto = # Will be removed, this is used in case of legacy chain Id return NetworkDto(chainId: networkType.toChainId()) + +method toggleNetwork*(self: Service, chainId: int) = + let network = self.getNetwork(chainId) + + network.enabled = not network.enabled + self.upsertNetwork(network) \ No newline at end of file diff --git a/src/app_service/service/network/service_interface.nim b/src/app_service/service/network/service_interface.nim index 119003a6e3..5101011654 100644 --- a/src/app_service/service/network/service_interface.nim +++ b/src/app_service/service/network/service_interface.nim @@ -29,3 +29,6 @@ method getNetwork*(self: ServiceInterface, networkType: NetworkType): NetworkDto method getNetwork*(self: ServiceInterface, chainId: int): NetworkDto {.base.} = raise newException(ValueError, "No implementation available") + +method toggleNetwork*(self: ServiceInterface, chainId: int) {.base.} = + raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app_service/service/token/service.nim b/src/app_service/service/token/service.nim index d72a25eaba..2c275783fc 100644 --- a/src/app_service/service/token/service.nim +++ b/src/app_service/service/token/service.nim @@ -23,6 +23,7 @@ include async_tasks const DEFAULT_VISIBLE_TOKENS = {1: @["SNT"], 3: @["STT"], 4: @["STT"]}.toTable() # Signals which may be emitted by this service: const SIGNAL_TOKEN_DETAILS_LOADED* = "tokenDetailsLoaded" +const SIGNAL_TOKEN_LIST_RELOADED* = "tokenListReloaded" type TokenDetailsLoadedArgs* = ref object of Args @@ -67,13 +68,16 @@ QtObject: proc init*(self: Service) = try: + self.tokens = initTable[NetworkDto, seq[TokenDto]]() var activeTokenSymbols = self.settingsService.getWalletVisibleTokens() let networks = self.networkService.getEnabledNetworks() let responseCustomTokens = custom_tokens.getCustomTokens() for network in networks: - if not activeTokenSymbols.hasKey(network.chainId): + if not activeTokenSymbols.hasKey(network.chainId) and DEFAULT_VISIBLE_TOKENS.hasKey(network.chainId): activeTokenSymbols[network.chainId] = DEFAULT_VISIBLE_TOKENS[network.chainId] + else: + activeTokenSymbols[network.chainId] = @[] let responseTokens = token_backend.getTokens(network.chainId) let default_tokens = map( @@ -93,10 +97,7 @@ QtObject: error "error: ", errDesription return - proc getTokens*(self: Service, useCache: bool = true): Table[NetworkDto, seq[TokenDto]] = - if not useCache: - self.init() - + proc getTokens*(self: Service): Table[NetworkDto, seq[TokenDto]] = return self.tokens proc getVisibleTokens*(self: Service): seq[TokenDto] = diff --git a/src/app_service/service/wallet_account/service.nim b/src/app_service/service/wallet_account/service.nim index 34b972448d..b99fe6fbaa 100644 --- a/src/app_service/service/wallet_account/service.nim +++ b/src/app_service/service/wallet_account/service.nim @@ -25,6 +25,7 @@ const SIGNAL_WALLET_ACCOUNT_DELETED* = "walletAccount/accountDeleted" const SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED* = "walletAccount/currencyUpdated" const SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED* = "walletAccount/tokenVisibilityUpdated" const SIGNAL_WALLET_ACCOUNT_UPDATED* = "walletAccount/walletAccountUpdated" +const SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED* = "walletAccount/networkEnabledUpdated" var priceCache {.threadvar.}: Table[string, float64] @@ -76,13 +77,17 @@ proc fetchAccounts(): seq[WalletAccountDto] = ).filter(a => not a.isChat) proc fetchNativeChainBalance(network: NetworkDto, accountAddress: string): float64 = - let key = "0x0" & accountAddress + let key = "0x0" & accountAddress & $network.chainId if balanceCache.hasKey(key): return balanceCache[key] - let nativeBalanceResponse = status_go_eth.getNativeChainBalance(network.chainId, accountAddress) - result = parsefloat(hex2Balance(nativeBalanceResponse.result.getStr, network.nativeCurrencyDecimals)) - balanceCache[key] = result + try: + let nativeBalanceResponse = status_go_eth.getNativeChainBalance(network.chainId, accountAddress) + result = parsefloat(hex2Balance(nativeBalanceResponse.result.getStr, network.nativeCurrencyDecimals)) + balanceCache[key] = result + except Exception as e: + error "Error getting balance", message = e.msg + result = 0.0 type AccountSaved = ref object of Args account: WalletAccountDto @@ -94,6 +99,8 @@ type CurrencyUpdated = ref object of Args type TokenVisibilityToggled = ref object of Args +type NetwordkEnabledToggled = ref object of Args + type WalletAccountUpdated = ref object of Args account: WalletAccountDto @@ -297,6 +304,12 @@ method toggleTokenVisible*(self: Service, chainId: int, symbol: string) = self.refreshBalances() self.events.emit(SIGNAL_WALLET_ACCOUNT_TOKEN_VISIBILITY_UPDATED, TokenVisibilityToggled()) +method toggleNetworkEnabled*(self: Service, chainId: int) = + self.networkService.toggleNetwork(chainId) + self.tokenService.init() + self.refreshBalances() + self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled()) + method updateWalletAccount*(self: Service, address: string, accountName: string, color: string) = let account = self.accounts[address] status_go_accounts.updateAccount( diff --git a/src/backend/core.nim b/src/backend/core.nim index 8c065d3465..932cc4d85b 100644 --- a/src/backend/core.nim +++ b/src/backend/core.nim @@ -11,16 +11,12 @@ proc callRPC*(inputJSON: string): string = return $status_go.callRPC(inputJSON) proc callPrivateRPCRaw*(inputJSON: string): string {.raises: [].} = - result = $status_go.callPrivateRPC(inputJSON) + result = $status_go.callPrivateRPC(inputJSON) -proc callPrivateRPC*(methodName: string, payload = %* []): RpcResponse[JsonNode] - {.raises: [RpcException, ValueError, Defect, SerializationError].} = +proc makePrivateRpcCall*( + methodName: string, inputJSON: JsonNode +): RpcResponse[JsonNode] {.raises: [RpcException, ValueError, Defect, SerializationError].} = try: - let inputJSON = %* { - "jsonrpc": "2.0", - "method": methodName, - "params": %payload - } debug "NewBE_callPrivateRPC", rpc_method=methodName let rpcResponseRaw = status_go.callPrivateRPC($inputJSON) result = Json.decode(rpcResponseRaw, RpcResponse[JsonNode]) @@ -38,6 +34,27 @@ proc callPrivateRPC*(methodName: string, payload = %* []): RpcResponse[JsonNode] error "error doing rpc request", methodName = methodName, exception=e.msg raise newException(RpcException, e.msg) +proc callPrivateRPCWithChainId*( + methodName: string, chainId: int, payload = %* [] +): RpcResponse[JsonNode] {.raises: [RpcException, ValueError, Defect, SerializationError].} = + let inputJSON = %* { + "jsonrpc": "2.0", + "method": methodName, + "chainId": chainId, + "params": %payload + } + return makePrivateRpcCall(methodName, inputJSON) + +proc callPrivateRPC*( + methodName: string, payload = %* [] +): RpcResponse[JsonNode] {.raises: [RpcException, ValueError, Defect, SerializationError].} = + let inputJSON = %* { + "jsonrpc": "2.0", + "method": methodName, + "params": %payload + } + return makePrivateRpcCall(methodName, inputJSON) + proc signMessage*(rpcParams: string): string = return $status_go.signMessage(rpcParams) diff --git a/src/backend/eth.nim b/src/backend/eth.nim index 4f543dec48..4ec7f9734f 100644 --- a/src/backend/eth.nim +++ b/src/backend/eth.nim @@ -12,7 +12,7 @@ proc getBlockByNumber*(blockNumber: string): RpcResponse[JsonNode] {.raises: [Ex proc getNativeChainBalance*(chainId: int, address: string): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* [address, "latest"] - return core.callPrivateRPC("eth_getBalance", payload) + return core.callPrivateRPCWithChainId("eth_getBalance", chainId, payload) proc sendTransaction*(transactionData: string, password: string): RpcResponse[JsonNode] {.raises: [Exception].} = core.sendTransaction(transactionData, password) diff --git a/ui/app/AppLayouts/Profile/stores/WalletStore.qml b/ui/app/AppLayouts/Profile/stores/WalletStore.qml index 47e45768b8..a28ef004a9 100644 --- a/ui/app/AppLayouts/Profile/stores/WalletStore.qml +++ b/ui/app/AppLayouts/Profile/stores/WalletStore.qml @@ -3,7 +3,7 @@ import QtQuick 2.13 QtObject { id: root - property var layer1Networks: profileSectionWalletNetworkModule.layer1 - property var layer2Networks: profileSectionWalletNetworkModule.layer2 - property var testNetworks: profileSectionWalletNetworkModule.test + property var layer1Networks: networksModule.layer1 + property var layer2Networks: networksModule.layer2 + property var testNetworks: networksModule.test } diff --git a/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml b/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml index 805034ace6..e03ae042d1 100644 --- a/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml +++ b/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml @@ -9,7 +9,6 @@ Item { id: root width: selectRectangle.width height: childrenRect.height - signal toggleNetwork(int chainId) property var store @@ -23,7 +22,7 @@ Item { StyledText { id: text - text: qsTr("All networks") + text: qsTr("Select networks") anchors.left: parent.left anchors.leftMargin: Style.current.padding anchors.verticalCenter: parent.verticalCenter @@ -56,10 +55,13 @@ Item { Grid { id: enabledNetworks - columns: 2 + columns: 4 spacing: 2 visible: (chainRepeater.count > 0) + anchors.top: selectRectangle.bottom + anchors.topMargin: Style.current.padding + Repeater { id: chainRepeater model: store.enabledNetworks @@ -87,8 +89,10 @@ Item { NetworkSelectPopup { id: selectPopup x: (parent.width - width) - y: (root.height - networkFilterPanel.height) - model: store.allNetworks + layer1Networks: store.layer1Networks + layer2Networks: store.layer2Networks + testNetworks: store.testNetworks + onToggleNetwork: { store.toggleNetwork(chainId) } diff --git a/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml b/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml index 2c10e59007..7539768963 100644 --- a/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml +++ b/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml @@ -16,8 +16,11 @@ Popup { modal: false width: 360 height: 432 - closePolicy: Popup.CloseOnEscape - property var model + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent + property var layer1Networks + property var layer2Networks + property var testNetworks + signal toggleNetwork(int chainId) background: Rectangle { @@ -49,32 +52,51 @@ Popup { width: popup.width spacing: Style.current.padding - Repeater { - id: chainRepeater - model: popup.model + Repeater { + id: chainRepeater1 + model: popup.layer1Networks - Item { - width: content.width - height: 40 - StatusBaseText { - anchors.left: parent.left - anchors.leftMargin: Style.current.bigPadding - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Style.current.primaryTextFontSize - text: model.chainName - color: Theme.palette.directColor1 - } + delegate: chainItem + } - StatusCheckBox { - anchors.right: parent.right - anchors.rightMargin: Style.current.bigPadding - anchors.verticalCenter: parent.verticalCenter - checked: model.enabled - onCheckedChanged: { - if(checked !== model.enabled){ - popup.toggleNetwork(model.chainId) - } - } + Repeater { + id: chainRepeater2 + model: popup.layer2Networks + + delegate: chainItem + } + + Repeater { + id: chainRepeater3 + model: popup.testNetworks + + delegate: chainItem + } + } + } + + Component { + id: chainItem + Item { + width: content.width + height: 40 + StatusBaseText { + anchors.left: parent.left + anchors.leftMargin: Style.current.bigPadding + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Style.current.primaryTextFontSize + text: model.chainName + color: Theme.palette.directColor1 + } + + StatusCheckBox { + anchors.right: parent.right + anchors.rightMargin: Style.current.bigPadding + anchors.verticalCenter: parent.verticalCenter + checked: model.isEnabled + onCheckedChanged: { + if (model.isEnabled !== checked) { + popup.toggleNetwork(model.chainId) } } } diff --git a/ui/app/AppLayouts/Wallet/stores/RootStore.qml b/ui/app/AppLayouts/Wallet/stores/RootStore.qml index 2944a12a4e..f6d6813326 100644 --- a/ui/app/AppLayouts/Wallet/stores/RootStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/RootStore.qml @@ -33,6 +33,12 @@ QtObject { property var savedAddresses: walletSectionSavedAddresses.model + + property var layer1Networks: networksModule.layer1 + property var layer2Networks: networksModule.layer2 + property var testNetworks: networksModule.test + property var enabledNetworks: networksModule.enabled + // This should be exposed to the UI via "walletModule", WalletModule should use // Accounts Service which keeps the info about that (isFirstTimeAccountLogin). // Then in the View of WalletModule we may have either QtProperty or @@ -184,4 +190,8 @@ QtObject { function deleteSavedAddress(address) { walletSectionSavedAddresses.deleteSavedAddress(address) } + + function toggleNetwork(chainId) { + networksModule.toggleNetwork(chainId) + } }