forked from lightningdevkit/ldk-node
-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add multi-address type support for on-chain wallet #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ben-kaufman
wants to merge
12
commits into
main
Choose a base branch
from
feat/multi-address-types
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+7,078
−986
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
df146d2 to
af29894
Compare
Collaborator
|
LGTM! |
coreyphillips
approved these changes
Feb 11, 2026
|
@ben-kaufman Please create release, I can't test because I'm missing it. |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dev/ldk-node into feat/multi-address-types
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Adds multi-address type wallet support, allowing a single LDK Node instance to manage on-chain funds across Legacy (P2PKH), NestedSegwit (P2SH-P2WPKH), NativeSegwit (P2WPKH), and Taproot (P2TR) address types simultaneously. Users migrating between address types can continue monitoring and spending funds from previous address types without manual consolidation.
New
bdk-wallet-aggregatecrateA new standalone crate (
crates/bdk-wallet-aggregate/) wraps multiple BDK wallets behind a singleAggregateWalletabstraction. It has no dependency onldk-nodeinternals and manages cross-wallet transaction building, UTXO selection, signing, and fee bumping.lib.rs— CoreAggregateWalletstruct: owns a primary wallet and N secondary wallets keyed by address type. Aggregates balances, delegates sync and persistence per wallet, and builds transactions using unified coin selection across all loaded wallets.utxo.rs— Collects UTXOs across all wallets, filters by witness compatibility, estimates weight per script type, and runs coin selection using BDK algorithms (BranchAndBound, LargestFirst, OldestFirst, SingleRandomDraw).signing.rs— Multi-wallet PSBT signing: routes each input to the owning wallet, injects P2SH-P2WPKH redeem scripts, and extracts the final signed transaction.rbf.rs— Cross-wallet RBF: preserves original inputs, recalculates fees at the new rate, adjusts the change output, and adds inputs from secondary wallets when the existing change cannot absorb the fee increase.types.rs— Shared types (Error,UtxoPsbtInfo,CoinSelectionAlgorithm).Public API additions
Configuration:
Config::address_type— primary wallet address type (default:NativeSegwit)Config::address_types_to_monitor— additional address types to track alongside the primaryBuilder::set_address_type()/Builder::set_address_types_to_monitor()Node:
Node::get_balance_for_address_type(AddressType)— query balance for a specific address typeNode::list_monitored_address_types()— list all loaded wallet typesOnchainPayment:
OnchainPayment::new_address_for_type(AddressType)— generate a receiving address for any monitored typeNew types:
AddressTypeenum:Legacy,NestedSegwit,NativeSegwit,TaprootAddressTypeBalance:total_sats,spendable_satsUnified coin selection
All transaction paths (send, send-all, channel funding, RBF, CPFP) use unified coin selection that pools UTXOs from all loaded wallets and selects optimally across the full set using BDK's coin selection algorithms. This means the algorithm can freely choose the best UTXOs regardless of which wallet owns them — for example, picking a single large Taproot UTXO instead of combining three small NativeSegwit UTXOs.
Channel funding and scripts
get_shutdown_scriptpubkeyreturnErr(())instead of panickingRBF safety
RBF only ever adjusts wallet-owned change outputs — recipient outputs are never reduced. When there is no change output (e.g. after a send-all), RBF returns an error rather than modifying the recipient amount. When the change output cannot absorb the fee increase, additional inputs are sourced from secondary wallets.
Chain sync
Secondary wallets sync in parallel alongside the primary wallet using
tokio::task::JoinSetfor both Esplora and Electrum backends. Per-wallet sync timestamps are tracked inNodeMetricsto determine full-scan vs incremental sync. A failed secondary sync logs a warning but does not fail the overall sync operation.Persistence and migration
Each wallet's data is stored under a namespaced key by address type. For migration compatibility, the NativeSegwit wallet falls back to the legacy un-namespaced storage location, so existing wallet data is read transparently without any migration step.
Internal changes to
ldk-nodeWalletstruct wrapsAggregateWalletinstead of a single BDKPersistedWallet; persistence is handled internally by the cratesend_all_to_addresswithretain_reserves=falsetakes a dedicated drain path that sweeps all wallets into a single transaction