Skip to content

Conversation

@boldbitcoin
Copy link
Contributor

@boldbitcoin boldbitcoin commented Dec 16, 2025

🚀 Overall Enhanced PSBT

📋 Summary

This PR introduces a dedicated wallet mode: PSBT only - the main feature that transforms the wallet into a specialized PSBT-focused experience. Alongside this, it adds comprehensive support for generating output descriptors for all three Bitcoin address types (Legacy, SegWit Native, SegWit Compatible) while maintaining full backward compatibility with existing wallets.

✨ Features

🎯 Main Feature: Dedicated Wallet Mode - PSBT Only

  • PSBT-Focused Experience: New dedicated PSBT screen designed specifically for PSBT operations
  • Streamlined Workflow: Optimized UI/UX for PSBT creation, signing, and management
  • Enhanced PSBT Handling: Improved PSBT processing and display capabilities
  • Transport Mode Integration: Seamless integration with transport mode selector for PSBT signing

🎯 Multi-Address Type Output Descriptors

  • Legacy (BIP44): pkh([fingerprint/44'/coinType'/0']xpub/0/*)
  • SegWit Native (BIP84): wpkh([fingerprint/84'/coinType'/0']xpub/0/*)
  • SegWit Compatible (BIP49): sh(wpkh([fingerprint/49'/coinType'/0']xpub/0/*))

🔄 Backward Compatibility Strategy

  • Old Wallets (created_at ≤ 1765894825732):
    • All descriptors use BIP44 derivation path (44')
    • Different descriptor formats: pkh, wpkh, sh(wpkh)
    • Ensures existing funds remain visible after update
  • New Wallets (created_at > 1765894825732):
    • Use optimized BIP84/BIP49 paths for SegWit address types
    • Proper descriptor formats matching derivation paths

🎨 UI/UX Enhancements

PSBT Screen (Dedicated Wallet Mode)

  • New dedicated PSBT-only screen - The core feature of this PR
  • Optimized layout specifically designed for PSBT operations
  • Collapsible "Bold Connect" section (closed by default)
  • Display all three output descriptor types with individual actions:
    • Copy to clipboard
    • Share as file
    • Show QR code
  • Consistent styling with shadows, borders, and spacing
  • Transport mode selector integration for PSBT signing
  • Enhanced PSBT workflow and user experience

Keyshare Modal (Wallet Home)

  • Display wallet creation timestamp (created_at)
  • Show all three output descriptors with individual copy/share/QR buttons
  • Consistent UI matching PSBTScreen design
  • Removed single outputDescriptor field in favor of outputDescriptors object

🛠️ Technical Improvements

Code Organization

  • Centralized Logic: New generateAllOutputDescriptors() utility function in utils.js
  • DRY Principle: Eliminated duplicate descriptor generation code
  • Type Safety: Updated TypeScript interfaces for descriptor objects

Native Module Updates

  • Go: Added addressType parameter to GetOutputDescriptor() function
  • iOS: Updated Swift and Objective-C bindings
  • Android: Updated Kotlin bindings

Derivation Path Logic

  • Updated getDerivePathForNetwork() to support address types
  • Automatic legacy wallet detection based on creation timestamp
  • Smart path selection based on wallet age and address type

🔧 Technical Details

Migration Strategy

  • Timestamp Threshold: 1765894825732 (December 2025)
  • Detection: Automatic via isLegacyWallet(created_at) utility
  • Zero User Action: Seamless migration, no breaking changes

File Changes

  • Go: BBMTLib/tss/common.go - Enhanced descriptor generation
  • Native: iOS/Android bindings updated
  • UI: PSBTScreen.tsx, KeyshareModal.tsx, WalletHome.tsx
  • Utils: utils.js - New utility functions

✅ Testing Checklist

  • Old wallets continue to work with existing funds
  • New wallets use optimized paths
  • All three descriptor types generate correctly
  • UI displays all descriptors properly
  • Copy/share/QR actions work for each descriptor
  • Backward compatibility verified
  • No breaking changes

📸 Screenshots

Add screenshots of the new PSBT Screen and Keyshare Modal showing all three descriptors

🔗 Related Issues

Link any related issues here

🚦 Breaking Changes

None - This PR is fully backward compatible. Existing wallets continue to function exactly as before.

📝 Notes

  • The timestamp-based detection ensures smooth migration
  • Old wallets show all three descriptor formats but use BIP44 paths
  • New wallets automatically get optimized paths
  • All descriptor generation logic is centralized for easier maintenance
  • Removed outputDescriptor field, now using only outputDescriptors object

Ready for Review

bbtc added 10 commits December 14, 2025 15:22
- Created PSBTModal.foss.tsx that removes react-native-vision-camera dependency
- Uses BarcodeZxingScan for both iOS and Android platforms
- Maintains full feature parity with standard version including animated QR support
- Android keeps continuous scanning, iOS uses recursive scanning for animated QR
- Updated CHANGELOG.md with F-Droid compatibility entry
- Added push trigger to ensure tests run on direct pushes to branches
- Maintains same path filters as pull_request trigger
- Prevents bugs from entering main branch without test validation
- Fixes continuous integration for changes pushed directly to branches
…bility

- Add support for generating output descriptors for Legacy, SegWit Native, and SegWit Compatible address types
- Implement timestamp-based legacy wallet detection (created_at <= 1765894825732)
- Old wallets: All descriptors use BIP44 path with different formats (pkh/wpkh/sh(wpkh))
- New wallets: Use optimized BIP84/BIP49 paths for SegWit address types
- Add new PSBT Screen with collapsible Bold Connect section
- Display all three descriptor types in PSBTScreen and KeyshareModal
- Add wallet creation timestamp display in KeyshareModal
- Centralize descriptor generation logic in utils.js (generateAllOutputDescriptors)
- Update Go native module to accept addressType parameter
- Update iOS and Android native bindings
- Improve UI/UX consistency across PSBT-related screens

Breaking changes: None (fully backward compatible)
- Keep v2.1.1 version numbers (2.1.1, versionCode 34)
- Merge CHANGELOG.md entries
- Keep v2.1.1 MobileNostrPairing.foss.tsx (with PSBT support)
- Resolve iOS project file version conflicts
- Resolve workflow file conflicts
@boldbitcoin boldbitcoin changed the title feat: Multi-Address Type Output Descriptors with Backward Compatibility Overall Enhanced PSBT Dec 16, 2025
Copy link
Contributor

@HalFinneyIsMyHomeBoy HalFinneyIsMyHomeBoy left a comment

Choose a reason for hiding this comment

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

Still doing manual testing, but inspected the new code in psbt.go.

All logging of the pubkey+chaincode should be removed (or at least truncated) because it's sensitive data and could lead to a vulnerability.

Please see lines 64, 98-99, 202, 759, 793-794, 897 in psbt.go

if keyshareData.ChainCodeHex == "" {
return "", fmt.Errorf("keyshare missing chain_code_hex")
}
Logf("Keyshare parsed: pub_key (hex, full)=%s, chaincode (hex, full)=%s", keyshareData.PubKey, keyshareData.ChainCodeHex)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove or truncate logging of pubkey+chaincode

if xpubPath != "" {
Logf("COMPARISON: PSBT xpub is at path %s (account level)", xpubPath)
Logf("COMPARISON: Deriving from keyshare master key to PSBT xpub path: %s", xpubPath)
Logf("COMPARISON: Keyshare master pub_key (hex)=%s", keyshareData.PubKey)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove or truncate logging of pubkey+chaincode

@boldbitcoin
Copy link
Contributor Author

Ah btw if u check in release mode logs are suppressed thats propagated


// Derive the public key from keyshare using GetDerivedPubKey with the path from PSBT
// Use the keyshare's pub_key and chaincode to derive the corresponding public key
Logf("Input %d: Deriving public key from keyshare - xpub: %s, chaincode: %s, path: %s", i, keyshareData.PubKey, keyshareData.ChainCodeHex, inputDerivePath)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove or truncate logging of pubkey+chaincode

if keyshareData.ChainCodeHex == "" {
return "", fmt.Errorf("keyshare missing chain_code_hex")
}
Logf("Keyshare parsed: pub_key (hex, full)=%s, chaincode (hex, full)=%s", keyshareData.PubKey, keyshareData.ChainCodeHex)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove or truncate logging of pubkey+chaincode

if xpubPath != "" {
Logf("COMPARISON: PSBT xpub is at path %s (account level)", xpubPath)
Logf("COMPARISON: Deriving from keyshare master key to PSBT xpub path: %s", xpubPath)
Logf("COMPARISON: Keyshare master pub_key (hex)=%s", keyshareData.PubKey)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove or truncate logging of pubkey+chaincode

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see now. I missed that.

Still working on manual testing now.
I'll let you know if I find any issues.


// Derive the public key from keyshare using GetDerivedPubKey with the path from PSBT
// Use the keyshare's pub_key and chaincode to derive the corresponding public key
Logf("Input %d: Deriving public key from keyshare - xpub: %s, chaincode: %s, path: %s", i, keyshareData.PubKey, keyshareData.ChainCodeHex, inputDerivePath)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove or truncate logging of pubkey+chaincode

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Feel free to remove them.
As pointed out for help debugging purposes in dev mode they are logged.
In release mode almost no logs are enabled - all suppressed, and propagated.

https://github.com/BoldBitcoinWallet/BoldWallet/blob/main/App.tsx#L160

I truncated the pubkey + chaincode logging in
psbt.go as an extra precaution.
Copy link
Contributor

@HalFinneyIsMyHomeBoy HalFinneyIsMyHomeBoy left a comment

Choose a reason for hiding this comment

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

Even though logging is disabled in release mode, I truncated the pubkey+chaincode logging as a precaution.

Tested manually and approved!! works like a charm!

@HalFinneyIsMyHomeBoy HalFinneyIsMyHomeBoy merged commit bc84aa7 into main Dec 17, 2025
1 check passed
@boldbitcoin boldbitcoin deleted the v2.1.1 branch December 19, 2025 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants