Context
The Bitkit App needs a reliable app-facing error state when a user enters the wrong Trezor PIN. This came up while tracking the hardware-wallet polishing follow-up in synonymdev/bitkit-android#1030, and iOS will need the same typed signal when it reaches the same Trezor flows. Without a typed signal, the app can only treat the operation as a generic device failure/loading state, which makes retry UX unclear and can interact badly with reconnect/backoff logic.
Trezor protocol already exposes this as Failure_PinInvalid after PinMatrixAck. python-trezor handles the same flow by checking for PinInvalid, PinCancelled, and PinExpected immediately after sending the PIN and raising a PIN-specific exception.
trezor-connect-rs also defines DeviceError::InvalidPin, and bitkit-core already has TrezorError::InvalidPin; however, current trezor-connect-rs 0.3.2 appears to return some protocol Failure responses as generic DeviceError { code, message } / Failure { code, message }, so the typed error can be lost before it reaches mobile bindings.
This can also be handled in trezor-connect-rs, but it appears easier and sufficient to normalize it in bitkit-core because bitkit-core is the mobile-facing adapter that owns the stable TrezorError contract for the Bitkit App on Android and iOS.
Scope
Preserve Trezor PIN failure semantics in bitkit-core's public FFI error surface.
- Map Trezor protobuf
FailureType codes from upstream generic device failures to typed TrezorError variants where possible:
Failure_PinInvalid (7) -> TrezorError::InvalidPin
Failure_PinCancelled (6) -> TrezorError::PinCancelled
Failure_PinExpected (5) -> TrezorError::PinRequired
- optionally
Failure_ActionCancelled (4) -> TrezorError::UserCancelled
- Apply the mapping for both upstream
DeviceError::Failure { code, message } and DeviceError::DeviceError { code, message } if both can carry those protocol codes.
- Keep unknown failure codes as generic
TrezorError::DeviceError so existing behavior is preserved.
- Add tests proving numeric/protobuf PIN failure codes surface as typed bitkit-core errors through the existing conversion path.
- Regenerate mobile bindings and publish a release so the Bitkit App can consume the typed errors on Android and iOS.
Bitkit App usage after release
The Bitkit App should use the typed InvalidPin signal to:
- clear the submitted/spinner state on PIN entry;
- show explicit copy such as "Incorrect PIN. Try again.";
- let the user retry deliberately;
- avoid reconnecting, refreshing features, or opening a new transport while the device is still mid-flow.
Acceptance criteria
- Wrong Trezor PIN failures are exposed to the Bitkit App as
TrezorError.InvalidPin, not only as generic device errors.
- PIN cancelled/expected protocol failures are mapped to the existing typed PIN errors where available.
- Existing generic device failures remain generic unless their protocol code is one of the known PIN/action codes.
- Mobile bindings expose the updated behavior in a released bitkit-core artifact.
Context
The Bitkit App needs a reliable app-facing error state when a user enters the wrong Trezor PIN. This came up while tracking the hardware-wallet polishing follow-up in synonymdev/bitkit-android#1030, and iOS will need the same typed signal when it reaches the same Trezor flows. Without a typed signal, the app can only treat the operation as a generic device failure/loading state, which makes retry UX unclear and can interact badly with reconnect/backoff logic.
Trezor protocol already exposes this as
Failure_PinInvalidafterPinMatrixAck.python-trezorhandles the same flow by checking forPinInvalid,PinCancelled, andPinExpectedimmediately after sending the PIN and raising a PIN-specific exception.trezor-connect-rsalso definesDeviceError::InvalidPin, and bitkit-core already hasTrezorError::InvalidPin; however, currenttrezor-connect-rs 0.3.2appears to return some protocolFailureresponses as genericDeviceError { code, message }/Failure { code, message }, so the typed error can be lost before it reaches mobile bindings.This can also be handled in
trezor-connect-rs, but it appears easier and sufficient to normalize it in bitkit-core because bitkit-core is the mobile-facing adapter that owns the stableTrezorErrorcontract for the Bitkit App on Android and iOS.Scope
Preserve Trezor PIN failure semantics in bitkit-core's public FFI error surface.
FailureTypecodes from upstream generic device failures to typedTrezorErrorvariants where possible:Failure_PinInvalid(7) ->TrezorError::InvalidPinFailure_PinCancelled(6) ->TrezorError::PinCancelledFailure_PinExpected(5) ->TrezorError::PinRequiredFailure_ActionCancelled(4) ->TrezorError::UserCancelledDeviceError::Failure { code, message }andDeviceError::DeviceError { code, message }if both can carry those protocol codes.TrezorError::DeviceErrorso existing behavior is preserved.Bitkit App usage after release
The Bitkit App should use the typed
InvalidPinsignal to:Acceptance criteria
TrezorError.InvalidPin, not only as generic device errors.