Skip to content
Draft
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
7 changes: 4 additions & 3 deletions Bitkit/AppScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ struct AppScene: View {
// Created ahead of `transfer` so the hardware-wallet transfer flow can reach the funding
// (compose/sign/broadcast) and device-session (reconnect) capabilities.
let trezorManager = TrezorManager()
let hwWalletManager = HwWalletManager()
let hwWalletManager = HwWalletManager(session: trezorManager)

_transfer = StateObject(wrappedValue: TransferViewModel(
transferService: transferService,
sheetViewModel: sheetViewModel,
hwFunding: hwWalletManager,
hwConnecting: trezorManager,
hwConnecting: hwWalletManager,
hwFeeRateProvider: {
guard let rates = await feeEstimatesManager.getEstimates() else { return nil }
return UInt64(TransactionSpeed.fast.getFeeRate(from: rates))
Expand Down Expand Up @@ -903,7 +903,8 @@ struct AppScene: View {
private func pushHardwareDevices() {
hwWalletManager.updateDevices(
knownDevices: trezorManager.knownDevices,
connectedDeviceId: trezorManager.connectedDevice?.id
connectedDeviceId: trezorManager.connectedDevice?.id,
connectedWalletId: trezorManager.connectedWalletId
)
}

Expand Down
8 changes: 4 additions & 4 deletions Bitkit/MainNavView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -420,17 +420,17 @@ struct MainNavView: View {
case .buyBitcoin: BuyBitcoinView()
case .savingsWallet: SavingsWalletScreen()
case .spendingWallet: SpendingWalletScreen()
case let .hardwareWallet(deviceId): HardwareWalletScreen(deviceId: deviceId)
case let .hardwareWallet(walletId): HardwareWalletScreen(walletId: walletId)
case .scanner: ScannerScreen()

// Transfer
case .transferIntro: TransferIntroView()
case .fundingOptions: FundingOptions()
case .spendingIntro: SpendingIntroView()
case let .spendingIntroHw(deviceId): SpendingIntroView(deviceId: deviceId)
case let .spendingIntroHw(walletId): SpendingIntroView(walletId: walletId)
case .spendingAmount: SpendingAmount()
case let .spendingAmountHw(deviceId): SpendingAmountHw(deviceId: deviceId)
case let .spendingHwSign(deviceId): SpendingHwSign(deviceId: deviceId)
case let .spendingAmountHw(walletId): SpendingAmountHw(walletId: walletId)
case let .spendingHwSign(walletId): SpendingHwSign(walletId: walletId)
case .spendingHwSigned: SpendingHwSigned()
case let .spendingConfirm(order): SpendingConfirm(order: order)
case let .spendingAdvanced(order): SpendingAdvancedView(order: order)
Expand Down
47 changes: 47 additions & 0 deletions Bitkit/Managers/HwDeviceSessioning.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import BitkitCore

/// The live Trezor session and its stored entries, as the watch-only layer needs them.
///
/// Implemented by `TrezorManager` and injected into `HwWalletManager`, so the watch-only layer can
/// reason about which wallet a session belongs to without either manager referencing the other.
/// Everything here is device-level on purpose: resolving a wallet identity to the transport it is
/// reachable over is the watch-only layer's job, since it owns the wallet grouping.
@MainActor
protocol HwDeviceSessioning: AnyObject, Sendable {
/// Stored entries read fresh. A connect that just wrote one lands here before the
/// `updateDevices(...)` push does, so session operations must not read the pushed snapshot.
var storedDevices: [TrezorKnownDevice] { get }
var connectedDeviceId: String? { get }
/// Identity the live session opened; nil when no session is open or none could be resolved.
var connectedWalletId: String? { get }
var connectedFeatures: TrezorFeatures? { get }

func ensureConnected(deviceId: String) async throws
/// Opens `deviceId` with an explicit wallet selection, with or without a live session.
@discardableResult
func connectWithWalletMode(
deviceId: String,
mode: TrezorWalletMode,
passphrase: String
) async throws -> TrezorFeatures
func disconnectStaleSession(deviceId: String) async
func isKnownBluetoothDevice(deviceId: String) -> Bool
func warmUpConnection(deviceId: String)
/// Forgets every stored entry of `walletId`, keeping transport credentials while another
/// identity of the same device remains paired.
func forgetWallet(walletId: String) async
}

extension TrezorManager: HwDeviceSessioning {
var storedDevices: [TrezorKnownDevice] {
knownDevices
}

var connectedDeviceId: String? {
connectedDevice?.id
}

var connectedFeatures: TrezorFeatures? {
deviceFeatures
}
}
Loading