diff --git a/Features/Assets/Sources/ViewModels/AssetsFilterViewModel.swift b/Features/Assets/Sources/ViewModels/AssetsFilterViewModel.swift index f280aeeef..3b55e60de 100644 --- a/Features/Assets/Sources/ViewModels/AssetsFilterViewModel.swift +++ b/Features/Assets/Sources/ViewModels/AssetsFilterViewModel.swift @@ -48,7 +48,7 @@ public struct AssetsFilterViewModel: Sendable, Equatable { case .swap(let type): switch type { case .pay: [.enabled, .swappable, .hasBalance] - case .receive(let chains, let assetIds): + case .receive(let chains, let assetIds, _): [ .enabled, .chainsOrAssets( @@ -65,6 +65,17 @@ public struct AssetsFilterViewModel: Sendable, Equatable { } } + var preferredChain: Chain? { + switch type { + case .swap(let swapType): + switch swapType { + case .receive(_, _, let chain): chain + case .pay: nil + } + case .send, .receive, .buy, .manage, .priceAlert, .deposit, .withdraw: nil + } + } + var showHasBalanceToggle: Bool { switch type { case .send, .receive, .buy, .swap, .priceAlert, .deposit, .withdraw: false diff --git a/Features/Assets/Sources/ViewModels/SelectAssetViewModel.swift b/Features/Assets/Sources/ViewModels/SelectAssetViewModel.swift index efd71fda2..a03e822e6 100644 --- a/Features/Assets/Sources/ViewModels/SelectAssetViewModel.swift +++ b/Features/Assets/Sources/ViewModels/SelectAssetViewModel.swift @@ -74,7 +74,7 @@ public final class SelectAssetViewModel { self.filterModel = filter self.searchModel = AssetSearchViewModel(selectType: selectType) - self.assetsQuery = ObservableQuery(AssetsRequest(walletId: wallet.walletId, filters: filter.filters), initialValue: []) + self.assetsQuery = ObservableQuery(AssetsRequest(walletId: wallet.walletId, filters: filter.filters, preferredChain: filter.preferredChain), initialValue: []) self.recentsQuery = ObservableQuery( RecentActivityRequest( walletId: wallet.walletId, diff --git a/Features/Swap/Sources/Scenes/SwapScene.swift b/Features/Swap/Sources/Scenes/SwapScene.swift index c7e372865..48daf4bfe 100644 --- a/Features/Swap/Sources/Scenes/SwapScene.swift +++ b/Features/Swap/Sources/Scenes/SwapScene.swift @@ -108,7 +108,7 @@ extension SwapScene { private var swapToSectionView: some View { Section { SwapTokenView( - model: model.swapTokenModel(type: .receive(chains: [], assetIds: [])), + model: model.swapTokenModel(type: .receive(chains: [], assetIds: [], preferredChain: nil)), text: $model.toValue, showLoading: model.isLoading, disabledTextField: true, diff --git a/Features/Swap/Sources/ViewModels/SwapSceneViewModel.swift b/Features/Swap/Sources/ViewModels/SwapSceneViewModel.swift index 9a4ce2337..287e8682e 100644 --- a/Features/Swap/Sources/ViewModels/SwapSceneViewModel.swift +++ b/Features/Swap/Sources/ViewModels/SwapSceneViewModel.swift @@ -220,7 +220,7 @@ extension SwapSceneViewModel { func onSelectAssetReceive() { guard let fromAsset = fromAsset else { return } let (chains, assetIds) = swapQuotesProvider.supportedAssets(for: fromAsset.asset.id) - isPresentingInfoSheet = .selectAsset(.receive(chains: chains, assetIds: assetIds)) + isPresentingInfoSheet = .selectAsset(.receive(chains: chains, assetIds: assetIds, preferredChain: fromAsset.asset.chain)) } func onSelectSwapDetails() { diff --git a/Packages/Primitives/Sources/SelectAssetType.swift b/Packages/Primitives/Sources/SelectAssetType.swift index 9b7560942..d2555450b 100644 --- a/Packages/Primitives/Sources/SelectAssetType.swift +++ b/Packages/Primitives/Sources/SelectAssetType.swift @@ -38,12 +38,12 @@ public extension SelectAssetType { public enum SelectAssetSwapType: Identifiable, Hashable, Sendable { case pay - case receive(chains: [Chain], assetIds: [AssetId]) - + case receive(chains: [Chain], assetIds: [AssetId], preferredChain: Chain?) + public var id: String { switch self { case .pay: "pay" - case .receive(let chains, let assetIds): "receive_\(chains)_\(assetIds)" + case .receive(let chains, let assetIds, let preferredChain): "receive_\(chains)_\(assetIds)_\(preferredChain?.rawValue ?? "")" } } } diff --git a/Packages/Store/Sources/Requests/AssetsRequest.swift b/Packages/Store/Sources/Requests/AssetsRequest.swift index 0df17d20c..454b34d62 100644 --- a/Packages/Store/Sources/Requests/AssetsRequest.swift +++ b/Packages/Store/Sources/Requests/AssetsRequest.swift @@ -9,24 +9,27 @@ public struct AssetsRequest: DatabaseQueryable { public var walletId: WalletId public var searchBy: String public var filters: [AssetsRequestFilter] + public var preferredChain: Chain? public init( walletId: WalletId, searchBy: String = "", - filters: [AssetsRequestFilter] = [] + filters: [AssetsRequestFilter] = [], + preferredChain: Chain? = nil ) { self.walletId = walletId self.searchBy = searchBy self.filters = filters + self.preferredChain = preferredChain } public func fetch(_ db: Database) throws -> [AssetData] { let searchBy = searchBy.trim() - + let filters = if searchBy.isEmpty { filters } else { - filters + [.search(searchBy, hasPriorityAssets: try hasPriorityAssets(db, query: searchBy))] + filters + [.search(searchBy, hasPriorityAssets: try hasPriorityAssets(db, query: searchBy), preferredChain: preferredChain)] } if filters.contains(.priceAlerts) { @@ -73,12 +76,14 @@ extension AssetsRequest { static private func applyFilter(request: QueryInterfaceRequest, _ filter: AssetsRequestFilter) -> QueryInterfaceRequest { switch filter { - case .search(let query, let hasPriorityAssets): + case .search(let query, let hasPriorityAssets, let preferredChain): + let chainOrder = preferredChain.map { (AssetRecord.Columns.chain == $0.rawValue).desc } if hasPriorityAssets { return request.joining(required: AssetRecord.search .filter(SearchRecord.Columns.query == query) ) .order( + chainOrder, TableAlias(name: SearchRecord.databaseTableName)[SearchRecord.Columns.priority].ascNullsLast, TableAlias(name: AssetRecord.databaseTableName)[AssetRecord.Columns.rank].desc ) @@ -90,6 +95,7 @@ extension AssetsRequest { AssetRecord.Columns.tokenId.like("%%\(query)%%") ) .order( + chainOrder, AssetRecord.Columns.rank.desc ) case .hasBalance: diff --git a/Packages/Store/Sources/Types/AssetsRequestFilter.swift b/Packages/Store/Sources/Types/AssetsRequestFilter.swift index 6f07eb915..9ee3f41ce 100644 --- a/Packages/Store/Sources/Types/AssetsRequestFilter.swift +++ b/Packages/Store/Sources/Types/AssetsRequestFilter.swift @@ -1,9 +1,10 @@ // Copyright (c). Gem Wallet. All rights reserved. import Foundation +import Primitives public enum AssetsRequestFilter { - case search(String, hasPriorityAssets: Bool) + case search(String, hasPriorityAssets: Bool, preferredChain: Chain? = nil) case enabled case buyable case swappable diff --git a/Packages/Store/Tests/StoreTests/Requests/AssetsRequestTests.swift b/Packages/Store/Tests/StoreTests/Requests/AssetsRequestTests.swift index 878ead692..d85ac2fda 100644 --- a/Packages/Store/Tests/StoreTests/Requests/AssetsRequestTests.swift +++ b/Packages/Store/Tests/StoreTests/Requests/AssetsRequestTests.swift @@ -143,6 +143,20 @@ struct AssetsRequestTests { } } + @Test func testSearchPreferredChain() throws { + let assets: [AssetBasic] = .mock() + [.mock(asset: .mockTronUSDT())] + let db = DB.mockAssets(assets: assets) + + try db.dbQueue.read { db in + let result = try AssetsRequest.mock( + filters: [.search("USDT", hasPriorityAssets: false)], + preferredChain: .tron + ).fetch(db) + + #expect(result.first?.asset == .mockTronUSDT()) + } + } + @Test func testOrder() throws { let db = DB.mockAssets() let priceStore = PriceStore(db: db) @@ -181,8 +195,9 @@ extension AssetsRequest { static func mock( walletId: WalletId = .mock(), searchBy: String = "", - filters: [AssetsRequestFilter] = [] + filters: [AssetsRequestFilter] = [], + preferredChain: Chain? = nil ) -> AssetsRequest { - AssetsRequest(walletId: walletId, searchBy: searchBy, filters: filters) + AssetsRequest(walletId: walletId, searchBy: searchBy, filters: filters, preferredChain: preferredChain) } }