Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Features/FiatConnect/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ let package = Package(
.package(name: "Localization", path: "../../Packages/Localization"),
.package(name: "Store", path: "../../Packages/Store"),
.package(name: "PrimitivesComponents", path: "../../Packages/PrimitivesComponents"),
.package(name: "FeatureServices", path: "../../Packages/FeatureServices"),
],
targets: [
.target(
Expand All @@ -36,6 +37,7 @@ let package = Package(
"Localization",
"Store",
"PrimitivesComponents",
.product(name: "BalanceService", package: "FeatureServices"),
],
path: "Sources"
),
Expand All @@ -44,6 +46,7 @@ let package = Package(
dependencies: [
"FiatConnect",
.product(name: "PrimitivesTestKit", package: "Primitives"),
.product(name: "BalanceServiceTestKit", package: "FeatureServices"),
],
path: "Tests"
),
Expand Down
21 changes: 18 additions & 3 deletions Features/FiatConnect/Sources/ViewModels/FiatSceneViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import Formatters
import Validators
import BigInt
import BalanceService

@MainActor
@Observable
Expand All @@ -26,7 +27,9 @@
private let assetAddress: AssetAddress
private let currencyFormatter: CurrencyFormatter
private let valueFormatter = ValueFormatter(locale: .US, style: .medium)
private let walletId: WalletId
private let wallet: Wallet
private let assetsEnabler: any AssetsEnabler
private var walletId: WalletId { wallet.walletId }

public let assetQuery: ObservableQuery<AssetRequest>
var assetData: AssetData { assetQuery.value }
Expand All @@ -43,28 +46,30 @@
fiatService: any GemAPIFiatService,
currencyFormatter: CurrencyFormatter = CurrencyFormatter(currencyCode: Currency.usd.rawValue),
assetAddress: AssetAddress,
walletId: WalletId,
wallet: Wallet,
assetsEnabler: any AssetsEnabler,
type: FiatQuoteType = .buy,
amount: Int? = nil
) {
self.fiatService = fiatService
self.currencyFormatter = currencyFormatter
self.assetAddress = assetAddress
self.walletId = walletId
self.wallet = wallet
self.assetsEnabler = assetsEnabler
self.type = type
self.assetQuery = ObservableQuery(AssetRequest(walletId: walletId, assetId: assetAddress.asset.id), initialValue: .with(asset: assetAddress.asset))

Check failure on line 60 in Features/FiatConnect/Sources/ViewModels/FiatSceneViewModel.swift

View workflow job for this annotation

GitHub Actions / Build and Test iPhone simulator

'self' used in property access 'walletId' before all stored properties are initialized

let buyOperation = BuyOperation(
service: fiatService,
asset: assetAddress.asset,
currencyFormatter: currencyFormatter,
walletId: walletId

Check failure on line 66 in Features/FiatConnect/Sources/ViewModels/FiatSceneViewModel.swift

View workflow job for this annotation

GitHub Actions / Build and Test iPhone simulator

'self' used in property access 'walletId' before all stored properties are initialized
)
let sellOperation = SellOperation(
service: fiatService,
asset: assetAddress.asset,
currencyFormatter: currencyFormatter,
walletId: walletId

Check failure on line 72 in Features/FiatConnect/Sources/ViewModels/FiatSceneViewModel.swift

View workflow job for this annotation

GitHub Actions / Build and Test iPhone simulator

'self' used in property access 'walletId' before all stored properties are initialized
)

self.buyViewModel = FiatOperationViewModel(
Expand Down Expand Up @@ -191,6 +196,7 @@
}

urlState = .data(())
Task { await enableAsset() }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid potential UI blocking, it's safer to run the asset enabling logic on a background thread. The current implementation with Task inherits the main actor context, which could lead to UI freezes if enableAsset() performs synchronous I/O operations.

I'm suggesting a change to the enableAsset() function to make it synchronous and launch a Task.detached for background execution. Consequently, this call site should be updated to a direct synchronous call.

Suggested change
Task { await enableAsset() }
enableAsset()

await UIApplication.shared.open(url, options: [:])
} catch {
urlState = .error(error)
Expand Down Expand Up @@ -243,6 +249,15 @@
BalanceViewModel(asset: asset, balance: assetData.balance, formatter: valueFormatter)
}

private func enableAsset() async {
guard type == .buy else { return }
do {
try await assetsEnabler.enableAssets(wallet: wallet, assetIds: [asset.id], enabled: true)
} catch {
debugLog("FiatSceneViewModel enableAsset error: \(error)")
}
}
Comment on lines +252 to +259

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential UI blocking from synchronous I/O operations within assetsEnabler.enableAssets, this logic should be executed on a background thread.

I recommend changing this function to be synchronous and using Task.detached to perform the asset enabling work in the background. This ensures the main thread remains responsive.

    private func enableAsset() {
        guard type == .buy else { return }

        // Capture properties to use in the detached task
        let wallet = self.wallet
        let asset = self.asset
        let assetsEnabler = self.assetsEnabler

        Task.detached {
            do {
                try await assetsEnabler.enableAssets(wallet: wallet, assetIds: [asset.id], enabled: true)
            } catch {
                debugLog("FiatSceneViewModel enableAsset error: \(error)")
            }
        }
    }


private func selectAmount(_ amount: Int) {
currentViewModel.reset()
currentViewModel.inputValidationModel.update(text: String(amount))
Expand Down
6 changes: 4 additions & 2 deletions Features/FiatConnect/Tests/FiatSceneViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Primitives
import PrimitivesTestKit
import Formatters
import BigInt
import BalanceServiceTestKit

@testable import FiatConnect

Expand All @@ -16,13 +17,14 @@ final class FiatSceneViewModelTests {
service: any GemAPIFiatService = GemAPIService(),
currencyFormatter: CurrencyFormatter = .init(locale: Locale.US, currencyCode: Currency.usd.rawValue),
assetAddress: AssetAddress = .mock(),
walletId: WalletId = .mock()
wallet: Wallet = .mock()
) -> FiatSceneViewModel {
FiatSceneViewModel(
fiatService: service,
currencyFormatter: currencyFormatter,
assetAddress: assetAddress,
walletId: walletId
wallet: wallet,
assetsEnabler: .mock()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Preferences

public struct AmountNavigationView: View {
@Environment(\.fiatService) private var fiatService
@Environment(\.assetsEnabler) private var assetsEnabler
@State private var model: AmountSceneViewModel

public init(model: AmountSceneViewModel) {
Expand All @@ -27,10 +28,10 @@ public struct AmountNavigationView: View {
switch $0 {
case let .infoAction(type):
InfoSheetScene(type: type)
case let .fiatConnect(assetAddress, walletId):
case let .fiatConnect(assetAddress, wallet):
NavigationStack {
FiatConnectNavigationView(
model: FiatSceneViewModel(fiatService: fiatService, assetAddress: assetAddress, walletId: walletId)
model: FiatSceneViewModel(fiatService: fiatService, assetAddress: assetAddress, wallet: wallet, assetsEnabler: assetsEnabler)
)
.navigationBarTitleDisplayMode(.inline)
.toolbar { ToolbarDismissItem(type: .close, placement: .topBarLeading) }
Expand Down
6 changes: 4 additions & 2 deletions Features/Transfer/Sources/Scenes/ConfirmTransferScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Primitives

public struct ConfirmTransferScene: View {
@Environment(\.fiatService) private var fiatService
@Environment(\.assetsEnabler) private var assetsEnabler
@State private var model: ConfirmTransferSceneViewModel

public init(model: ConfirmTransferSceneViewModel) {
Expand Down Expand Up @@ -59,13 +60,14 @@ public struct ConfirmTransferScene: View {
.presentationDetents([.large])
.presentationBackground(Colors.grayBackground)
}
case .fiatConnect(let assetAddress, let walletId):
case .fiatConnect(let assetAddress, let wallet):
NavigationStack {
FiatConnectNavigationView(
model: FiatSceneViewModel(
fiatService: fiatService,
assetAddress: assetAddress,
walletId: walletId
wallet: wallet,
assetsEnabler: assetsEnabler
)
)
.navigationBarTitleDisplayMode(.inline)
Expand Down
2 changes: 1 addition & 1 deletion Features/Transfer/Sources/Types/AmountSheetType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import PrimitivesComponents

enum AmountSheetType: Identifiable {
case infoAction(InfoSheetType)
case fiatConnect(assetAddress: AssetAddress, walletId: WalletId)
case fiatConnect(assetAddress: AssetAddress, wallet: Wallet)
case leverageSelector(selection: SelectionState<LeverageOption>)
case autoclose(AutocloseOpenData)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ enum ConfirmTransferSheetType: Identifiable, Sendable {
case networkFeeSelector
case payloadDetails
case url(URL)
case fiatConnect(assetAddress: AssetAddress, walletId: WalletId)
case fiatConnect(assetAddress: AssetAddress, wallet: Wallet)
case swapDetails
case perpetualDetails(PerpetualDetailsViewModel)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ private extension AmountSceneViewModel {
func onSelectBuy() {
let senderAddress = (try? wallet.account(for: asset.chain).address) ?? ""
let assetAddress = AssetAddress(asset: asset, address: senderAddress)
isPresentingSheet = .fiatConnect(assetAddress: assetAddress, walletId: wallet.walletId)
isPresentingSheet = .fiatConnect(assetAddress: assetAddress, wallet: wallet)
}

var inputValidators: [any TextValidator] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ extension ConfirmTransferSceneViewModel {
private func onSelectBuy() {
isPresentingSheet = .fiatConnect(
assetAddress: feeAssetAddress,
walletId: wallet.walletId
wallet: wallet
)
}
private func onSelectConfirmTransfer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct SelectAssetSceneNavigationStack: View {
FiatConnectNavigationView(
model: viewModelFactory.fiatScene(
assetAddress: input.assetAddress,
walletId: model.wallet.walletId
wallet: model.wallet
)
)
case .deposit:
Expand Down
4 changes: 2 additions & 2 deletions Gem/Navigation/Assets/SelectedAssetNavigationStack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct SelectedAssetNavigationStack: View {
FiatConnectNavigationView(
model: viewModelFactory.fiatScene(
assetAddress: input.assetAddress,
walletId: wallet.walletId,
wallet: wallet,
type: .buy,
amount: amount
)
Expand All @@ -68,7 +68,7 @@ struct SelectedAssetNavigationStack: View {
FiatConnectNavigationView(
model: viewModelFactory.fiatScene(
assetAddress: input.assetAddress,
walletId: wallet.walletId,
wallet: wallet,
type: .sell,
amount: amount
)
Expand Down
5 changes: 3 additions & 2 deletions Gem/Services/ViewModelFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,15 @@ public struct ViewModelFactory: Sendable {
@MainActor
public func fiatScene(
assetAddress: AssetAddress,
walletId: WalletId,
wallet: Wallet,
type: FiatQuoteType = .buy,
amount: Int? = nil
) -> FiatSceneViewModel {
FiatSceneViewModel(
fiatService: fiatService,
assetAddress: assetAddress,
walletId: walletId,
wallet: wallet,
assetsEnabler: assetsEnabler,
type: type,
amount: amount
)
Expand Down
Loading