diff --git a/Gem.xcodeproj/project.pbxproj b/Gem.xcodeproj/project.pbxproj index e0a7def7..f959329c 100644 --- a/Gem.xcodeproj/project.pbxproj +++ b/Gem.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ 8325539A2C0FB11C00C9CA0C /* CurrencySceneViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832553992C0FB11C00C9CA0C /* CurrencySceneViewModelTests.swift */; }; 832A705E2C88CE0A00045367 /* SelectWalletScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832A705D2C88CE0A00045367 /* SelectWalletScene.swift */; }; 832A70602C88CE9600045367 /* SellectWalletViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832A705F2C88CE9600045367 /* SellectWalletViewModel.swift */; }; + 83352B642C92F898003D52F3 /* WalletSupportedChains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83352B632C92F898003D52F3 /* WalletSupportedChains.swift */; }; + 83352B6A2C93435F003D52F3 /* WalletSupportedChainsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83352B692C93435F003D52F3 /* WalletSupportedChainsTests.swift */; }; 833A0C852C80C11B0004DBA9 /* ChainsFilterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 833A0C842C80C11B0004DBA9 /* ChainsFilterType.swift */; }; 833A0C872C80C2A50004DBA9 /* ChainsFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 833A0C862C80C2A50004DBA9 /* ChainsFilterViewModel.swift */; }; 835644FD2C501C2200C6B4DB /* SwapError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835644FC2C501C2200C6B4DB /* SwapError.swift */; }; @@ -584,6 +586,8 @@ 832553992C0FB11C00C9CA0C /* CurrencySceneViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencySceneViewModelTests.swift; sourceTree = ""; }; 832A705D2C88CE0A00045367 /* SelectWalletScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletScene.swift; sourceTree = ""; }; 832A705F2C88CE9600045367 /* SellectWalletViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SellectWalletViewModel.swift; sourceTree = ""; }; + 83352B632C92F898003D52F3 /* WalletSupportedChains.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSupportedChains.swift; sourceTree = ""; }; + 83352B692C93435F003D52F3 /* WalletSupportedChainsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSupportedChainsTests.swift; sourceTree = ""; }; 833A0C842C80C11B0004DBA9 /* ChainsFilterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainsFilterType.swift; sourceTree = ""; }; 833A0C862C80C2A50004DBA9 /* ChainsFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainsFilterViewModel.swift; sourceTree = ""; }; 835644FC2C501C2200C6B4DB /* SwapError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapError.swift; sourceTree = ""; }; @@ -1027,6 +1031,14 @@ path = ViewModels; sourceTree = ""; }; + 83352B682C93433D003D52F3 /* Types */ = { + isa = PBXGroup; + children = ( + 83352B692C93435F003D52F3 /* WalletSupportedChainsTests.swift */, + ); + path = Types; + sourceTree = ""; + }; 83A681902C46F1E000A3636B /* Types */ = { isa = PBXGroup; children = ( @@ -1175,6 +1187,7 @@ C3549B3229C4395B00B4BE01 /* Assets */ = { isa = PBXGroup; children = ( + 83352B682C93433D003D52F3 /* Types */, C3549B3329C4396000B4BE01 /* ViewModels */, ); path = Assets; @@ -1422,6 +1435,7 @@ C3D1C4EF2A2EBB0C006E8EEA /* RecipientAddress.swift */, 8374DC592C6CDF6C00183109 /* AddTokenInput.swift */, 833A0C842C80C11B0004DBA9 /* ChainsFilterType.swift */, + 83352B632C92F898003D52F3 /* WalletSupportedChains.swift */, ); path = Types; sourceTree = ""; @@ -2457,6 +2471,7 @@ D847E3512ABCD49C00A56F07 /* TransactionsService.swift in Sources */, D8B978022AAA4C28009933B5 /* NotificationsViewModel.swift in Sources */, C3FB448E2A7AE4070056F124 /* NameResolveViewModel.swift in Sources */, + 83352B642C92F898003D52F3 /* WalletSupportedChains.swift in Sources */, D8B978002AAA4B97009933B5 /* NotificationsScene.swift in Sources */, 83AE20732C7CB43500A38809 /* AssetsFilterScene.swift in Sources */, D80700502BBB6ABA00ED770B /* CreateWalletNavigationStack.swift in Sources */, @@ -2664,6 +2679,7 @@ C3A7CB9129CFD6E600431341 /* WalletHeaderViewModelTests.swift in Sources */, D8C4A2352C8785A2006FABE8 /* FiatQuoteViewModelTests.swift in Sources */, C30952C6299C39D80004C0F9 /* walletTests.swift in Sources */, + 83352B6A2C93435F003D52F3 /* WalletSupportedChainsTests.swift in Sources */, C3A7CB9929D35EC200431341 /* WalletSceneViewModelTests.swift in Sources */, C3A7CB9729D3569C00431341 /* PriceViewModelTests.swift in Sources */, 8325539A2C0FB11C00C9CA0C /* CurrencySceneViewModelTests.swift in Sources */, diff --git a/Gem/Assets/Types/WalletSupportedChains.swift b/Gem/Assets/Types/WalletSupportedChains.swift new file mode 100644 index 00000000..99347631 --- /dev/null +++ b/Gem/Assets/Types/WalletSupportedChains.swift @@ -0,0 +1,28 @@ +// Copyright (c). Gem Wallet. All rights reserved. + +import Foundation +import Primitives +import Settings + +enum WalletSupportedChains { + case all + case withTokens +} + +// MARK: - Model extensions + +extension Primitives.Wallet { + func chains(type: WalletSupportedChains) -> [Chain] { + let supportedChains: [Chain] + switch type { + case .all: + supportedChains = AssetConfiguration.allChains + case .withTokens: + supportedChains = AssetConfiguration.supportedChainsWithTokens + } + + let walletChains = accounts.map { $0.chain }.asSet() + return walletChains.intersection(supportedChains).asArray() + .sorted { AssetScore.defaultRank(chain: $0) > AssetScore.defaultRank(chain: $1) } + } +} diff --git a/Gem/Assets/ViewModels/AddTokenViewModel.swift b/Gem/Assets/ViewModels/AddTokenViewModel.swift index a100a37a..5341e88f 100644 --- a/Gem/Assets/ViewModels/AddTokenViewModel.swift +++ b/Gem/Assets/ViewModels/AddTokenViewModel.swift @@ -3,7 +3,6 @@ import Foundation import Primitives import SwiftUI -import Settings import Blockchain import Components import Style @@ -20,12 +19,8 @@ class AddTokenViewModel { init(wallet: Wallet, service: AddTokenService) { self.service = service - - let availableChains = AssetConfiguration.supportedChainsWithTokens.asSet() - .intersection(wallet.accounts.map { $0.chain }.asSet()) - .asArray() - .sorted { AssetScore.defaultRank(chain: $0) > AssetScore.defaultRank(chain: $1) } - self.input = AddTokenInput(chains: availableChains) + let chains = wallet.chains(type: .withTokens) + self.input = AddTokenInput(chains: chains) } var title: String { Localized.Wallet.AddToken.title } diff --git a/Gem/Assets/ViewModels/AssetsFilterViewModel.swift b/Gem/Assets/ViewModels/AssetsFilterViewModel.swift index e962df11..019b8cf1 100644 --- a/Gem/Assets/ViewModels/AssetsFilterViewModel.swift +++ b/Gem/Assets/ViewModels/AssetsFilterViewModel.swift @@ -7,7 +7,8 @@ import Settings struct AssetsFilterViewModel { private let type: SelectAssetType - let allChains: [Chain] = AssetConfiguration.allChains + + let allChains: [Chain] var assetsRequest: AssetsRequest @@ -30,6 +31,7 @@ struct AssetsFilterViewModel { filters: Self.defaultFilters(type: type) ) self.type = type + self.allChains = wallet.chains(type: .all) } static func defaultFilters(type: SelectAssetType) -> [AssetsRequestFilter] { diff --git a/Gem/Assets/ViewModels/SelectAssetViewModel.swift b/Gem/Assets/ViewModels/SelectAssetViewModel.swift index 72b75163..3d5b5a8a 100644 --- a/Gem/Assets/ViewModels/SelectAssetViewModel.swift +++ b/Gem/Assets/ViewModels/SelectAssetViewModel.swift @@ -2,7 +2,6 @@ import Foundation import Keystore import Primitives import Store -import Settings import Components @Observable @@ -53,7 +52,7 @@ class SelectAssetViewModel { } var showAddToken: Bool { - selectType == .manage && wallet.accounts.map { $0.chain }.asSet().intersection(AssetConfiguration.supportedChainsWithTokens).count > 0 + selectType == .manage && !filterModel.allChains.isEmpty } } diff --git a/Gem/Wallet/Services/WalletsService.swift b/Gem/Wallet/Services/WalletsService.swift index 01287812..f5358061 100644 --- a/Gem/Wallet/Services/WalletsService.swift +++ b/Gem/Wallet/Services/WalletsService.swift @@ -230,10 +230,7 @@ class WalletsService { // func setupWallet(_ wallet: Wallet) throws { - let chains = wallet.accounts.map { $0.chain }.asSet() - .intersection(AssetConfiguration.allChains) - .map { $0 } - + let chains = wallet.chains(type: .all) try enableAssetBalances(wallet: wallet, chains: chains) } diff --git a/GemTests/Assets/Types/WalletSupportedChainsTests.swift b/GemTests/Assets/Types/WalletSupportedChainsTests.swift new file mode 100644 index 00000000..233767d5 --- /dev/null +++ b/GemTests/Assets/Types/WalletSupportedChainsTests.swift @@ -0,0 +1,41 @@ +import XCTest +import Primitives +@testable import Gem + +final class WalletSupportedChainsTests: XCTestCase { + func testChainsAll() { + let wallet = Wallet.mock(accounts: [ + .mock(chain: .bitcoin), + .mock(chain: .doge), + .mock(chain: .ethereum) + ]) + + let result = wallet.chains(type: .all) + let expectedChains: [Chain] = [.bitcoin, .ethereum, .doge] + XCTAssertEqual(result, expectedChains) + } + + func testChainsWithTokens() { + let wallet = Wallet.mock(accounts: [ + .mock(chain: .bitcoin), + .mock(chain: .doge), + .mock(chain: .ethereum) + ]) + + let result = wallet.chains(type: .withTokens) + let expectedChains: [Chain] = [.ethereum] + XCTAssertEqual(result, expectedChains) + } + + func testChainSorting() { + let wallet = Wallet.mock(accounts: [ + .mock(chain: .doge), + .mock(chain: .ethereum), + .mock(chain: .bitcoin) + ]) + + let result = wallet.chains(type: .all) + let expectedChains: [Chain] = [.bitcoin, .ethereum, .doge] + XCTAssertEqual(result, expectedChains) + } +} diff --git a/Packages/Primitives/TestKit/Account+PrimitivesTestKit.swift b/Packages/Primitives/TestKit/Account+PrimitivesTestKit.swift new file mode 100644 index 00000000..3dfcbafe --- /dev/null +++ b/Packages/Primitives/TestKit/Account+PrimitivesTestKit.swift @@ -0,0 +1,17 @@ +// Copyright (c). Gem Wallet. All rights reserved. + +import Foundation +import Primitives + +public extension Account { + static func mock( + chain: Chain = .mock() + ) -> Account { + Account( + chain: chain, + address: .empty, + derivationPath: .empty, + extendedPublicKey: .empty + ) + } +} diff --git a/Packages/Primitives/TestKit/Wallet+PrimitivesTestKit.swift b/Packages/Primitives/TestKit/Wallet+PrimitivesTestKit.swift index ec58cd26..fee1ee1a 100644 --- a/Packages/Primitives/TestKit/Wallet+PrimitivesTestKit.swift +++ b/Packages/Primitives/TestKit/Wallet+PrimitivesTestKit.swift @@ -5,13 +5,14 @@ import Primitives public extension Wallet { static func mock( + accounts: [Account] = [] ) -> Wallet { Wallet( id: "", name: "", index: 0, type: .multicoin, - accounts: [], + accounts: accounts, order: 0, isPinned: false )