diff --git a/cktap-ffi/src/lib.rs b/cktap-ffi/src/lib.rs index d043171..fe46ff2 100644 --- a/cktap-ffi/src/lib.rs +++ b/cktap-ffi/src/lib.rs @@ -14,7 +14,7 @@ use crate::sats_chip::SatsChip; use crate::tap_signer::TapSigner; use futures::lock::Mutex; use rust_cktap::shared::FactoryRootKey; -use rust_cktap::shared::{Certificate, Read}; +use rust_cktap::shared::{Certificate, Read, Wait}; use std::fmt::Debug; use std::sync::Arc; @@ -84,3 +84,12 @@ async fn check_cert(card: &mut (impl Certificate + Send + Sync)) -> Result<(), C }), } } + +async fn wait_step(card: &mut (impl Wait + Send + Sync)) -> Result, CkTapError> { + if card.auth_delay().is_none() { + return Ok(None); + } + + let remaining_delay = card.wait(None).await.map_err(CkTapError::from)?; + Ok(remaining_delay.map(|delay| delay as u8)) +} diff --git a/cktap-ffi/src/sats_card.rs b/cktap-ffi/src/sats_card.rs index cea2cda..4b53893 100644 --- a/cktap-ffi/src/sats_card.rs +++ b/cktap-ffi/src/sats_card.rs @@ -1,10 +1,10 @@ // Copyright (c) 2025 rust-cktap contributors // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::check_cert; use crate::error::{ CertsError, CkTapError, DeriveError, DumpError, ReadError, SignPsbtError, UnsealError, }; +use crate::{check_cert, wait_step}; use futures::lock::Mutex; use rust_cktap::descriptor::Wpkh; use rust_cktap::shared::{Authentication, Nfc, Read, Wait}; @@ -77,6 +77,12 @@ impl SatsCard { Ok(()) } + /// Wait one second of auth delay and return the remaining delay, if any. + pub async fn wait_step(&self) -> Result, CkTapError> { + let mut card = self.0.lock().await; + wait_step(&mut *card).await + } + /// Verify the card has authentic Coinkite root certificate pub async fn check_cert(&self) -> Result<(), CertsError> { let mut card = self.0.lock().await; diff --git a/cktap-swift/Sources/CKTap/cktap_ffi.swift b/cktap-swift/Sources/CKTap/cktap_ffi.swift index d39b580..66082d2 100644 --- a/cktap-swift/Sources/CKTap/cktap_ffi.swift +++ b/cktap-swift/Sources/CKTap/cktap_ffi.swift @@ -606,6 +606,11 @@ public protocol SatsCardProtocol: AnyObject, Sendable { */ func wait() async throws + /** + * Wait one second of auth delay and return the remaining delay, if any. + */ + func waitStep() async throws -> UInt8? + } open class SatsCard: SatsCardProtocol, @unchecked Sendable { fileprivate let handle: UInt64 @@ -649,11 +654,6 @@ open class SatsCard: SatsCardProtocol, @unchecked Sendable { // No primary constructor declared for this class. deinit { - if handle == 0 { - // Mock objects have handle=0 don't try to free them - return - } - try! rustCall { uniffi_cktap_ffi_fn_free_satscard(handle, $0) } } @@ -859,8 +859,27 @@ open func wait()async throws { ) } - + /** + * Wait one second of auth delay and return the remaining delay, if any. + */ +open func waitStep()async throws -> UInt8? { + return + try await uniffiRustCallAsync( + rustFutureFunc: { + uniffi_cktap_ffi_fn_method_satscard_wait_step( + self.uniffiCloneHandle() + + ) + }, + pollFunc: ffi_cktap_ffi_rust_future_poll_rust_buffer, + completeFunc: ffi_cktap_ffi_rust_future_complete_rust_buffer, + freeFunc: ffi_cktap_ffi_rust_future_free_rust_buffer, + liftFunc: FfiConverterOptionUInt8.lift, + errorHandler: FfiConverterTypeCkTapError_lift + ) +} + } @@ -890,6 +909,7 @@ public struct FfiConverterTypeSatsCard: FfiConverter { } + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -974,11 +994,6 @@ open class SatsChip: SatsChipProtocol, @unchecked Sendable { // No primary constructor declared for this class. deinit { - if handle == 0 { - // Mock objects have handle=0 don't try to free them - return - } - try! rustCall { uniffi_cktap_ffi_fn_free_satschip(handle, $0) } } @@ -1157,7 +1172,6 @@ open func xpub(master: Bool, cvc: String)async throws -> String { } - } @@ -1187,6 +1201,7 @@ public struct FfiConverterTypeSatsChip: FfiConverter { } + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1271,11 +1286,6 @@ open class TapSigner: TapSignerProtocol, @unchecked Sendable { // No primary constructor declared for this class. deinit { - if handle == 0 { - // Mock objects have handle=0 don't try to free them - return - } - try! rustCall { uniffi_cktap_ffi_fn_free_tapsigner(handle, $0) } } @@ -1454,7 +1464,6 @@ open func xpub(master: Bool, cvc: String)async throws -> String { } - } @@ -1484,6 +1493,7 @@ public struct FfiConverterTypeTapSigner: FfiConverter { } + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1501,7 +1511,7 @@ public func FfiConverterTypeTapSigner_lower(_ value: TapSigner) -> UInt64 { -public struct SatsCardStatus: Equatable, Hashable { +public struct SatsCardStatus { public var proto: UInt64 public var ver: String public var birth: UInt64 @@ -1525,16 +1535,60 @@ public struct SatsCardStatus: Equatable, Hashable { self.cardIdent = cardIdent self.authDelay = authDelay } - - - - } #if compiler(>=6) extension SatsCardStatus: Sendable {} #endif + +extension SatsCardStatus: Equatable, Hashable { + public static func ==(lhs: SatsCardStatus, rhs: SatsCardStatus) -> Bool { + if lhs.proto != rhs.proto { + return false + } + if lhs.ver != rhs.ver { + return false + } + if lhs.birth != rhs.birth { + return false + } + if lhs.activeSlot != rhs.activeSlot { + return false + } + if lhs.numSlots != rhs.numSlots { + return false + } + if lhs.addr != rhs.addr { + return false + } + if lhs.pubkey != rhs.pubkey { + return false + } + if lhs.cardIdent != rhs.cardIdent { + return false + } + if lhs.authDelay != rhs.authDelay { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(proto) + hasher.combine(ver) + hasher.combine(birth) + hasher.combine(activeSlot) + hasher.combine(numSlots) + hasher.combine(addr) + hasher.combine(pubkey) + hasher.combine(cardIdent) + hasher.combine(authDelay) + } +} + + + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1583,7 +1637,7 @@ public func FfiConverterTypeSatsCardStatus_lower(_ value: SatsCardStatus) -> Rus } -public struct SatsChipStatus: Equatable, Hashable { +public struct SatsChipStatus { public var proto: UInt64 public var ver: String public var birth: UInt64 @@ -1603,16 +1657,52 @@ public struct SatsChipStatus: Equatable, Hashable { self.cardIdent = cardIdent self.authDelay = authDelay } - - - - } #if compiler(>=6) extension SatsChipStatus: Sendable {} #endif + +extension SatsChipStatus: Equatable, Hashable { + public static func ==(lhs: SatsChipStatus, rhs: SatsChipStatus) -> Bool { + if lhs.proto != rhs.proto { + return false + } + if lhs.ver != rhs.ver { + return false + } + if lhs.birth != rhs.birth { + return false + } + if lhs.path != rhs.path { + return false + } + if lhs.pubkey != rhs.pubkey { + return false + } + if lhs.cardIdent != rhs.cardIdent { + return false + } + if lhs.authDelay != rhs.authDelay { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(proto) + hasher.combine(ver) + hasher.combine(birth) + hasher.combine(path) + hasher.combine(pubkey) + hasher.combine(cardIdent) + hasher.combine(authDelay) + } +} + + + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1657,7 +1747,7 @@ public func FfiConverterTypeSatsChipStatus_lower(_ value: SatsChipStatus) -> Rus } -public struct SlotDetails: Equatable, Hashable { +public struct SlotDetails { public var privkey: String? public var pubkey: String public var pubkeyDescriptor: String @@ -1669,16 +1759,36 @@ public struct SlotDetails: Equatable, Hashable { self.pubkey = pubkey self.pubkeyDescriptor = pubkeyDescriptor } - - - - } #if compiler(>=6) extension SlotDetails: Sendable {} #endif + +extension SlotDetails: Equatable, Hashable { + public static func ==(lhs: SlotDetails, rhs: SlotDetails) -> Bool { + if lhs.privkey != rhs.privkey { + return false + } + if lhs.pubkey != rhs.pubkey { + return false + } + if lhs.pubkeyDescriptor != rhs.pubkeyDescriptor { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(privkey) + hasher.combine(pubkey) + hasher.combine(pubkeyDescriptor) + } +} + + + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1715,7 +1825,7 @@ public func FfiConverterTypeSlotDetails_lower(_ value: SlotDetails) -> RustBuffe } -public struct TapSignerStatus: Equatable, Hashable { +public struct TapSignerStatus { public var proto: UInt64 public var ver: String public var birth: UInt64 @@ -1737,16 +1847,56 @@ public struct TapSignerStatus: Equatable, Hashable { self.cardIdent = cardIdent self.authDelay = authDelay } - - - - } #if compiler(>=6) extension TapSignerStatus: Sendable {} #endif + +extension TapSignerStatus: Equatable, Hashable { + public static func ==(lhs: TapSignerStatus, rhs: TapSignerStatus) -> Bool { + if lhs.proto != rhs.proto { + return false + } + if lhs.ver != rhs.ver { + return false + } + if lhs.birth != rhs.birth { + return false + } + if lhs.path != rhs.path { + return false + } + if lhs.numBackups != rhs.numBackups { + return false + } + if lhs.pubkey != rhs.pubkey { + return false + } + if lhs.cardIdent != rhs.cardIdent { + return false + } + if lhs.authDelay != rhs.authDelay { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(proto) + hasher.combine(ver) + hasher.combine(birth) + hasher.combine(path) + hasher.combine(numBackups) + hasher.combine(pubkey) + hasher.combine(cardIdent) + hasher.combine(authDelay) + } +} + + + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -1796,7 +1946,7 @@ public func FfiConverterTypeTapSignerStatus_lower(_ value: TapSignerStatus) -> R /** * Errors returned by the CkTap card. */ -public enum CardError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum CardError: Swift.Error { @@ -1811,21 +1961,8 @@ public enum CardError: Swift.Error, Equatable, Hashable, Foundation.LocalizedErr case BadCbor case BackupFirst case RateLimited - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension CardError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -1926,10 +2063,25 @@ public func FfiConverterTypeCardError_lower(_ value: CardError) -> RustBuffer { } +extension CardError: Equatable, Hashable {} + + + + +extension CardError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `certs` command. */ -public enum CertsError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum CertsError: Swift.Error { @@ -1939,21 +2091,8 @@ public enum CertsError: Swift.Error, Equatable, Hashable, Foundation.LocalizedEr ) case InvalidRootCert(msg: String ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension CertsError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2023,10 +2162,25 @@ public func FfiConverterTypeCertsError_lower(_ value: CertsError) -> RustBuffer } +extension CertsError: Equatable, Hashable {} + + + + +extension CertsError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `change` command. */ -public enum ChangeError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum ChangeError: Swift.Error { @@ -2037,21 +2191,8 @@ public enum ChangeError: Swift.Error, Equatable, Hashable, Foundation.LocalizedE case TooLong(len: UInt64 ) case SameAsOld - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension ChangeError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2125,6 +2266,21 @@ public func FfiConverterTypeChangeError_lower(_ value: ChangeError) -> RustBuffe return FfiConverterTypeChangeError.lower(value) } + +extension ChangeError: Equatable, Hashable {} + + + + +extension ChangeError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -2136,13 +2292,9 @@ public enum CkTapCard { ) case satsChip(SatsChip ) - - - - - } + #if compiler(>=6) extension CkTapCard: Sendable {} #endif @@ -2209,10 +2361,14 @@ public func FfiConverterTypeCkTapCard_lower(_ value: CkTapCard) -> RustBuffer { + + + + /** * Errors returned by the card, CBOR deserialization or value encoding, or the APDU transport. */ -public enum CkTapError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum CkTapError: Swift.Error { @@ -2225,21 +2381,8 @@ public enum CkTapError: Swift.Error, Equatable, Hashable, Foundation.LocalizedEr case Transport(msg: String ) case UnknownCardType - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension CkTapError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2322,10 +2465,25 @@ public func FfiConverterTypeCkTapError_lower(_ value: CkTapError) -> RustBuffer } +extension CkTapError: Equatable, Hashable {} + + + + +extension CkTapError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `derive` command. */ -public enum DeriveError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum DeriveError: Swift.Error { @@ -2335,21 +2493,8 @@ public enum DeriveError: Swift.Error, Equatable, Hashable, Foundation.LocalizedE ) case InvalidChainCode(msg: String ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension DeriveError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2419,10 +2564,25 @@ public func FfiConverterTypeDeriveError_lower(_ value: DeriveError) -> RustBuffe } +extension DeriveError: Equatable, Hashable {} + + + + +extension DeriveError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `dump` command. */ -public enum DumpError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum DumpError: Swift.Error { @@ -2441,21 +2601,8 @@ public enum DumpError: Swift.Error, Equatable, Hashable, Foundation.LocalizedErr */ case SlotTampered(slot: UInt8 ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension DumpError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2541,29 +2688,31 @@ public func FfiConverterTypeDumpError_lower(_ value: DumpError) -> RustBuffer { } -public enum KeyError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +extension DumpError: Equatable, Hashable {} - - - case Secp256k1(msg: String - ) - case KeyFromSlice(msg: String - ) - - - +extension DumpError: Foundation.LocalizedError { public var errorDescription: String? { String(reflecting: self) } +} + + + + + +public enum KeyError: Swift.Error { + + + case Secp256k1(msg: String + ) + case KeyFromSlice(msg: String + ) } -#if compiler(>=6) -extension KeyError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2625,10 +2774,25 @@ public func FfiConverterTypeKeyError_lower(_ value: KeyError) -> RustBuffer { } +extension KeyError: Equatable, Hashable {} + + + + +extension KeyError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `read` command. */ -public enum ReadError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum ReadError: Swift.Error { @@ -2636,21 +2800,8 @@ public enum ReadError: Swift.Error, Equatable, Hashable, Foundation.LocalizedErr ) case Key(err: KeyError ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension ReadError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2712,7 +2863,22 @@ public func FfiConverterTypeReadError_lower(_ value: ReadError) -> RustBuffer { } -public enum SignPsbtError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +extension ReadError: Equatable, Hashable {} + + + + +extension ReadError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + +public enum SignPsbtError: Swift.Error { @@ -2740,21 +2906,8 @@ public enum SignPsbtError: Swift.Error, Equatable, Hashable, Foundation.Localize ) case Base64Encoding(msg: String ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension SignPsbtError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2896,10 +3049,25 @@ public func FfiConverterTypeSignPsbtError_lower(_ value: SignPsbtError) -> RustB } +extension SignPsbtError: Equatable, Hashable {} + + + + +extension SignPsbtError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `status` command. */ -public enum StatusError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum StatusError: Swift.Error { @@ -2907,21 +3075,8 @@ public enum StatusError: Swift.Error, Equatable, Hashable, Foundation.LocalizedE ) case Key(err: KeyError ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension StatusError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -2983,10 +3138,25 @@ public func FfiConverterTypeStatusError_lower(_ value: StatusError) -> RustBuffe } +extension StatusError: Equatable, Hashable {} + + + + +extension StatusError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `unseal` command. */ -public enum UnsealError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum UnsealError: Swift.Error { @@ -2994,21 +3164,8 @@ public enum UnsealError: Swift.Error, Equatable, Hashable, Foundation.LocalizedE ) case Key(err: KeyError ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension UnsealError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -3070,10 +3227,25 @@ public func FfiConverterTypeUnsealError_lower(_ value: UnsealError) -> RustBuffe } +extension UnsealError: Equatable, Hashable {} + + + + +extension UnsealError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + /** * Errors returned by the `xpub` command. */ -public enum XpubError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError { +public enum XpubError: Swift.Error { @@ -3081,21 +3253,8 @@ public enum XpubError: Swift.Error, Equatable, Hashable, Foundation.LocalizedErr ) case Bip32(msg: String ) - - - - - - - public var errorDescription: String? { - String(reflecting: self) - } - } -#if compiler(>=6) -extension XpubError: Sendable {} -#endif #if swift(>=5.8) @_documentation(visibility: private) @@ -3157,6 +3316,21 @@ public func FfiConverterTypeXpubError_lower(_ value: XpubError) -> RustBuffer { } +extension XpubError: Equatable, Hashable {} + + + + +extension XpubError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + + public protocol CkTransport: AnyObject, Sendable { @@ -3172,8 +3346,9 @@ fileprivate struct UniffiCallbackInterfaceCkTransport { // Create the VTable using a series of closures. // Swift automatically converts these into C callback functions. // - // Store the vtable directly. - static let vtable: UniffiVTableCallbackInterfaceCkTransport = UniffiVTableCallbackInterfaceCkTransport( + // This creates 1-element array, since this seems to be the only way to construct a const + // pointer that we can pass to the Rust code. + static let vtable: [UniffiVTableCallbackInterfaceCkTransport] = [UniffiVTableCallbackInterfaceCkTransport( uniffiFree: { (uniffiHandle: UInt64) -> () in do { try FfiConverterCallbackInterfaceCkTransport.handleMap.remove(handle: uniffiHandle) @@ -3231,19 +3406,11 @@ fileprivate struct UniffiCallbackInterfaceCkTransport { droppedCallback: uniffiOutDroppedCallback ) } - ) - - // Rust stores this pointer for future callback invocations, so it must live - // for the process lifetime (not just for the init function call). - static let vtablePtr: UnsafePointer = { - let ptr = UnsafeMutablePointer.allocate(capacity: 1) - ptr.initialize(to: vtable) - return UnsafePointer(ptr) - }() + )] } private func uniffiCallbackInitCkTransport() { - uniffi_cktap_ffi_fn_init_callback_vtable_cktransport(UniffiCallbackInterfaceCkTransport.vtablePtr) + uniffi_cktap_ffi_fn_init_callback_vtable_cktransport(UniffiCallbackInterfaceCkTransport.vtable) } // FfiConverter protocol for callback interfaces @@ -3452,9 +3619,7 @@ fileprivate func uniffiRustCallAsync( pollResult = await withUnsafeContinuation { pollFunc( rustFuture, - { handle, pollResult in - uniffiFutureContinuationCallback(handle: handle, pollResult: pollResult) - }, + uniffiFutureContinuationCallback, uniffiContinuationHandleMap.insert(obj: $0) ) } @@ -3482,22 +3647,11 @@ private func uniffiTraitInterfaceCallAsync( droppedCallback: UnsafeMutablePointer ) { let task = Task { - // Note: it's important we call either `handleSuccess` or `handleError` exactly once. Each - // call consumes an Arc reference, which means there should be no possibility of a double - // call. The following code is structured so that will will never call both `handleSuccess` - // and `handleError`, even in the face of weird errors. - // - // On platforms that need extra machinery to make C-ABI calls, like JNA or ctypes, it's - // possible that we fail to make either call. However, it doesn't seem like this is - // possible on Swift since swift can just make the C call directly. - var callResult: T do { - callResult = try await makeCall() + handleSuccess(try await makeCall()) } catch { handleError(CALL_UNEXPECTED_ERROR, FfiConverterString.lower(String(describing: error))) - return } - handleSuccess(callResult) } let handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert(obj: task) droppedCallback.pointee = UniffiForeignFutureDroppedCallbackStruct( @@ -3514,19 +3668,13 @@ private func uniffiTraitInterfaceCallAsyncWithError( droppedCallback: UnsafeMutablePointer ) { let task = Task { - // See the note in uniffiTraitInterfaceCallAsync for details on `handleSuccess` and - // `handleError`. - var callResult: T do { - callResult = try await makeCall() + handleSuccess(try await makeCall()) } catch let error as E { handleError(CALL_ERROR, lowerError(error)) - return } catch { handleError(CALL_UNEXPECTED_ERROR, FfiConverterString.lower(String(describing: error))) - return } - handleSuccess(callResult) } let handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert(obj: task) droppedCallback.pointee = UniffiForeignFutureDroppedCallbackStruct( @@ -3595,100 +3743,103 @@ private let initializationResult: InitializationResult = { if bindings_contract_version != scaffolding_contract_version { return InitializationResult.contractVersionMismatch } - if (uniffi_cktap_ffi_checksum_func_to_cktap() != 32899) { + if (uniffi_cktap_ffi_checksum_func_to_cktap() != 56485) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_cktap_ffi_checksum_method_satscard_address() != 9818) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_address() != 37827) { + if (uniffi_cktap_ffi_checksum_method_satscard_check_cert() != 6533) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_check_cert() != 25375) { + if (uniffi_cktap_ffi_checksum_method_satscard_dump() != 37004) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_dump() != 20225) { + if (uniffi_cktap_ffi_checksum_method_satscard_new_slot() != 45340) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_new_slot() != 360) { + if (uniffi_cktap_ffi_checksum_method_satscard_nfc() != 40391) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_nfc() != 5150) { + if (uniffi_cktap_ffi_checksum_method_satscard_read() != 43229) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_read() != 18530) { + if (uniffi_cktap_ffi_checksum_method_satscard_sign_psbt() != 883) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_sign_psbt() != 16908) { + if (uniffi_cktap_ffi_checksum_method_satscard_status() != 20150) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_status() != 2484) { + if (uniffi_cktap_ffi_checksum_method_satscard_unseal() != 57458) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_unseal() != 18864) { + if (uniffi_cktap_ffi_checksum_method_satscard_wait() != 18368) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satscard_wait() != 29851) { + if (uniffi_cktap_ffi_checksum_method_satscard_wait_step() != 22961) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_change() != 64965) { + if (uniffi_cktap_ffi_checksum_method_satschip_change() != 49089) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_check_cert() != 22418) { + if (uniffi_cktap_ffi_checksum_method_satschip_check_cert() != 60748) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_derive() != 35847) { + if (uniffi_cktap_ffi_checksum_method_satschip_derive() != 63960) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_init() != 43462) { + if (uniffi_cktap_ffi_checksum_method_satschip_init() != 64376) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_nfc() != 32869) { + if (uniffi_cktap_ffi_checksum_method_satschip_nfc() != 6460) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_read() != 49709) { + if (uniffi_cktap_ffi_checksum_method_satschip_read() != 36900) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_sign_psbt() != 141) { + if (uniffi_cktap_ffi_checksum_method_satschip_sign_psbt() != 39519) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_status() != 7960) { + if (uniffi_cktap_ffi_checksum_method_satschip_status() != 14916) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_wait() != 13706) { + if (uniffi_cktap_ffi_checksum_method_satschip_wait() != 25914) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_satschip_xpub() != 63340) { + if (uniffi_cktap_ffi_checksum_method_satschip_xpub() != 24217) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_change() != 63099) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_change() != 45) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_check_cert() != 18657) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_check_cert() != 64898) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_derive() != 36393) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_derive() != 1802) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_init() != 19476) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_init() != 56161) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_nfc() != 36157) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_nfc() != 1711) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_read() != 700) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_read() != 26591) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_sign_psbt() != 3541) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_sign_psbt() != 19540) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_status() != 53193) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_status() != 24164) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_wait() != 44324) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_wait() != 32878) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_tapsigner_xpub() != 48830) { + if (uniffi_cktap_ffi_checksum_method_tapsigner_xpub() != 22073) { return InitializationResult.apiChecksumMismatch } - if (uniffi_cktap_ffi_checksum_method_cktransport_transmit_apdu() != 56609) { + if (uniffi_cktap_ffi_checksum_method_cktransport_transmit_apdu() != 15044) { return InitializationResult.apiChecksumMismatch } diff --git a/cktap-swift/Tests/CKTapTests/CKTapTests.swift b/cktap-swift/Tests/CKTapTests/CKTapTests.swift index da80d75..f45fa7d 100644 --- a/cktap-swift/Tests/CKTapTests/CKTapTests.swift +++ b/cktap-swift/Tests/CKTapTests/CKTapTests.swift @@ -74,4 +74,19 @@ final class CKTapTests: XCTestCase { print("SatsChip xpub: \(xpub)") } } + + func testWaitStepWhenNoDelayIsActive() async throws { + let cardEmulator = CardEmulator() + let card = try await toCktap(transport: cardEmulator) + + switch card { + case .satsCard(let satsCard): + let remainingDelay = try await satsCard.waitStep() + XCTAssertNil(remainingDelay) + case .tapSigner: + throw XCTSkip("waitStep is only exposed on SatsCard in this release") + case .satsChip: + throw XCTSkip("waitStep is only exposed on SatsCard in this release") + } + } }