change bip329 wallet labels export to only assert spendable false for frozen coins and omit otherwise
What changed, and why it matters
This commit fixes how Sparrow Wallet exports coin labels in the BIP-329 format. Previously, the export incorrectly marked every unspent coin as 'spendable=true' in the exported file, even though the BIP-329 specification says the 'spendable' field should only be used to mark coins as frozen (not spendable). Other wallets importing this file could have treated frozen coins as spendable, or made incorrect assumptions about the user's coins. The fix now only writes 'spendable=false' for frozen coins and leaves the field out otherwise.
Review whether any prior exported BIP-329 label files contain incorrect spendable=true entries and consider re-exporting after updating. Users relying on BIP-329 imports in other wallets should verify that frozen coins are correctly interpreted. No immediate code action is needed beyond applying the patch.
Security signals we found
Incorrect BIP-329 field semantics in wallet label export
Potential for importing wallets to misclassify frozen coins as spendable
Privacy/information disclosure from asserting spendable=true on all unspent UTXOs
Evidence from the diff
In WalletLabels.java, the BIP-329 export logic for the ‘spendable’ field on output labels was changed. The old code set spendable to true for any unspent, non-frozen UTXO and null for spent outputs. The new code only sets spendable to Boolean.FALSE when the UTXO is frozen, and null in all other cases. This aligns with BIP-329, which states the spendable field is optional and should only be used to assert that an output is not spendable (frozen). The change reduces the risk that importing wallets misinterpret labels or that users accidentally expose more state than intended.
Changed components
src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.javaBIP-329 wallet label export featureInspect captured patch +1 / −1
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java b/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
index 6f89b21..7cc818c 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
@@ -100,7 +100,7 @@ public class WalletLabels implements WalletImport, WalletExport {
for(Map.Entry<BlockTransactionHashIndex, WalletNode> txoEntry : exportWallet.getWalletTxos().entrySet()) {
BlockTransactionHashIndex txo = txoEntry.getKey();
WalletNode addressNode = txoEntry.getValue();
- Boolean spendable = (txo.isSpent() ? null : txo.getStatus() != Status.FROZEN);
+ Boolean spendable = (txo.isSpent() || txo.getStatus() != Status.FROZEN) ? null : Boolean.FALSE;
labels.add(new InputOutputLabel(Type.output, txo.toString(), txo.getLabel(), origin, spendable, addressNode.getDerivationPath().substring(1), txo.getValue(),
confirmingTxs.contains(txo.getHash()) ? null : txo.getHeight(), txo.getDate(), getFiatValue(txo, fiatRates)));
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.