Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.
Merged
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
2 changes: 2 additions & 0 deletions Features/FiatConnect/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ let package = Package(
"Store",
"PrimitivesComponents",
.product(name: "FiatService", package: "FeatureServices"),
.product(name: "BalanceService", package: "FeatureServices"),
],
path: "Sources"
),
Expand All @@ -47,6 +48,7 @@ let package = Package(
"FiatConnect",
.product(name: "PrimitivesTestKit", package: "Primitives"),
.product(name: "FiatServiceTestKit", package: "FeatureServices"),
.product(name: "BalanceServiceTestKit", package: "FeatureServices"),
],
path: "Tests"
),
Expand Down
29 changes: 22 additions & 7 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 FiatService
import BalanceService

@MainActor
@Observable
Expand All @@ -22,8 +23,9 @@ public final class FiatSceneViewModel {
static let suggestedAmounts: [Int] = [100, 250]
}

let walletId: WalletId
let fiatService: FiatService
private let wallet: Wallet
private let assetsEnabler: any AssetsEnabler
private let assetAddress: AssetAddress
private let currencyFormatter: CurrencyFormatter
private let valueFormatter = ValueFormatter(locale: .US, style: .medium)
Expand All @@ -43,28 +45,30 @@ public final class FiatSceneViewModel {
fiatService: FiatService,
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))
self.assetQuery = ObservableQuery(AssetRequest(walletId: wallet.walletId, assetId: assetAddress.asset.id), initialValue: .with(asset: assetAddress.asset))

let buyOperation = BuyOperation(
service: fiatService,
asset: assetAddress.asset,
currencyFormatter: currencyFormatter,
walletId: walletId
walletId: wallet.walletId
)
let sellOperation = SellOperation(
service: fiatService,
asset: assetAddress.asset,
currencyFormatter: currencyFormatter,
walletId: walletId
walletId: wallet.walletId
)

self.buyViewModel = FiatOperationViewModel(
Expand Down Expand Up @@ -185,12 +189,13 @@ extension FiatSceneViewModel {
urlState = .loading

do {
guard let url = try await fiatService.getQuoteUrl(walletId: walletId.id, quoteId: selectedQuote.id).redirectUrl.asURL else {
guard let url = try await fiatService.getQuoteUrl(walletId: wallet.walletId.id, quoteId: selectedQuote.id).redirectUrl.asURL else {
urlState = .noData
return
}

urlState = .data(())
Task { await enableAsset() }
await UIApplication.shared.open(url, options: [:])
} catch {
urlState = .error(error)
Expand Down Expand Up @@ -239,6 +244,16 @@ extension FiatSceneViewModel {
// MARK: - Private

extension FiatSceneViewModel {
private func enableAsset() async {
do {
try await assetsEnabler.enableAssets(wallet: wallet, assetIds: [asset.id], enabled: true)
} catch {
debugLog("FiatSceneViewModel enableAsset error: \(error)")
}
Comment on lines +250 to +252
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

The error from enableAssets is only logged to the debug console. This means that in release builds, any failure to enable the asset will be silent. Consider using a more robust logging mechanism to track these errors in production.

}

var walletId: WalletId { wallet.walletId }

private var balanceModel: BalanceViewModel {
BalanceViewModel(asset: asset, balance: assetData.balance, formatter: valueFormatter)
}
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 @@ -8,6 +8,7 @@ import Formatters
import FiatService
import FiatServiceTestKit
import BigInt
import BalanceServiceTestKit

@testable import FiatConnect

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

Expand Down
2 changes: 0 additions & 2 deletions Features/Transfer/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ let package = Package(
.package(name: "Stake", path: "../Stake"),
.package(name: "WalletConnector", path: "../WalletConnector"),
.package(name: "InfoSheet", path: "../InfoSheet"),
.package(name: "FiatConnect", path: "../FiatConnect"),
.package(name: "Swap", path: "../Swap"),
.package(name: "Perpetuals", path: "../Perpetuals"),
.package(name: "EventPresenterService", path: "../EventPresenterService"),
Expand Down Expand Up @@ -63,7 +62,6 @@ let package = Package(
"Stake",
"WalletConnector",
"InfoSheet",
"FiatConnect",
"Swap",
"Perpetuals",
"EventPresenterService",
Expand Down
6 changes: 3 additions & 3 deletions Features/Transfer/Sources/Scenes/AmountScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import SwiftUI
import struct Stake.ValidatorViewModel
import struct Stake.ValidatorView

struct AmountScene: View {
public struct AmountScene: View {
@FocusState private var focusedField: Bool

private var model: AmountSceneViewModel

init(model: AmountSceneViewModel) {
public init(model: AmountSceneViewModel) {
self.model = model
}

var body: some View {
public var body: some View {
@Bindable var model = model
List {
CurrencyInputValidationView(
Expand Down
55 changes: 2 additions & 53 deletions Features/Transfer/Sources/Scenes/ConfirmTransferScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@ import SwiftUI
import Components
import Style
import Localization
import InfoSheet
import PrimitivesComponents
import FiatConnect
import Swap
import Preferences
import Primitives

public struct ConfirmTransferScene: View {
@State private var model: ConfirmTransferSceneViewModel
@Bindable var model: ConfirmTransferSceneViewModel

public init(model: ConfirmTransferSceneViewModel) {
_model = State(initialValue: model)
self.model = model
}

public var body: some View {
Expand All @@ -36,56 +33,8 @@ public struct ConfirmTransferScene: View {
)
.taskOnce { model.fetch() }
.navigationTitle(model.title)
// TODO: - move to navigation view
.navigationBarTitleDisplayMode(.inline)
.activityIndicator(isLoading: model.confirmingState.isLoading, message: model.progressMessage)
.sheet(item: $model.isPresentingSheet) {
switch $0 {
case .info(let type):
InfoSheetScene(type: type)
case .url(let url):
SFSafariView(url: url)
case .networkFeeSelector:
NetworkFeeSheet(model: model.feeModel)
case .payloadDetails:
NavigationStack {
SimulationPayloadDetailsScene(
primaryFields: model.primaryPayloadFields,
secondaryFields: model.secondaryPayloadFields,
fieldViewModel: model.payloadFieldViewModel(for:),
contextMenuItems: model.contextMenuItems(for:)
)
.presentationDetents([.large])
.presentationBackground(Colors.grayBackground)
}
case .fiatConnect(let assetAddress, let walletId):
NavigationStack {
FiatConnectNavigationView(
model: FiatSceneViewModel(
fiatService: model.fiatService,
assetAddress: assetAddress,
walletId: walletId
)
)
.navigationBarTitleDisplayMode(.inline)
.toolbarDismissItem(type: .close, placement: .topBarLeading)
}
case .swapDetails:
if case let .swapDetails(model) = model.detailsViewModel.itemModel {
NavigationStack {
SwapDetailsView(model: Bindable(model))
.presentationDetentsForCurrentDeviceSize(expandable: true)
.presentationBackground(Colors.grayBackground)
}
}
case .perpetualDetails(let model):
NavigationStack {
PerpetualDetailsView(model: model)
.presentationDetentsForCurrentDeviceSize(expandable: true)
.presentationBackground(Colors.grayBackground)
}
}
}
.alertSheet($model.isPresentingAlertMessage)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Features/Transfer/Sources/Types/AmountDataProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import BigInt
import Primitives

enum AmountDataProvider: AmountDataProvidable, @unchecked Sendable {
public enum AmountDataProvider: AmountDataProvidable, @unchecked Sendable {
case transfer(AmountTransferViewModel)
case stake(AmountStakeViewModel)
case freeze(AmountFreezeViewModel)
Expand Down
6 changes: 3 additions & 3 deletions Features/Transfer/Sources/Types/AmountSheetType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import Components
import Perpetuals
import PrimitivesComponents

enum AmountSheetType: Identifiable {
public 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)

var id: String {
public var id: String {
switch self {
case let .infoAction(type): "info-action-\(type.id)"
case .fiatConnect: "fiat-connect"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import Primitives
import Components
import PrimitivesComponents

enum ConfirmTransferSheetType: Identifiable, Sendable {
public enum ConfirmTransferSheetType: Identifiable, Sendable {
case info(InfoSheetType)
case networkFeeSelector
case payloadDetails
case url(URL)
case fiatConnect(assetAddress: AssetAddress, walletId: WalletId)
case fiatConnect(assetAddress: AssetAddress, wallet: Wallet)
case swapDetails
case perpetualDetails(PerpetualDetailsViewModel)

var id: String {
public var id: String {
switch self {
case let .info(type): "info-\(type.id)"
case let .url(url): "url-\(url)"
Expand Down
12 changes: 6 additions & 6 deletions Features/Transfer/Sources/Types/SelectionState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import Foundation

@Observable
final class SelectionState<T> {
let options: [T]
var selected: T
let isEnabled: Bool
let title: String
public final class SelectionState<T> {
public let options: [T]
public var selected: T
public let isEnabled: Bool
public let title: String

init(
public init(
options: [T],
selected: T,
isEnabled: Bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Foundation
import Localization
import Primitives

final class AmountEarnViewModel: AmountDataProvidable {
public final class AmountEarnViewModel: AmountDataProvidable {
let asset: Asset
let action: EarnType
private let earnService: any EarnDataProvidable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Primitives
import PrimitivesComponents
import Stake

final class AmountFreezeViewModel: AmountDataProvidable {
public final class AmountFreezeViewModel: AmountDataProvidable {
enum Action {
case freeze
case unfreeze
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct AmountPerpetualLimits {
}

@Observable
final class AmountPerpetualViewModel: AmountDataProvidable {
public final class AmountPerpetualViewModel: AmountDataProvidable {
let asset: Asset
let data: PerpetualRecipientData
let leverageSelection: SelectionState<LeverageOption>?
Expand Down
Loading
Loading