Merge branch 'staging' into masternode-operator-reward
What changed, and why it matters
This commit changes how a Firo cryptocurrency wallet picks a special 'owner address' when setting up a masternode. Previously, the wallet only made sure the owner address was different from the collateral address. Now it also checks that the owner address is different from the payout address. This prevents the same address from being accidentally reused for two different roles, which could reduce privacy or cause bookkeeping problems. There is no direct evidence in the commit that this fixes an active security vulnerability, but it is a defensive improvement.
Review whether any other masternode-related address derivations (operator, voting, etc.) need similar distinctness checks, and confirm the change is covered by tests. No urgent action is required unless the wallet already exposed users to address reuse in the field.
Security signals we found
Address reuse prevention for masternode owner/payout roles
Defensive validation of derived addresses before use
Exception raised when a suitable distinct address cannot be derived
Evidence from the diff
In lib/wallets/wallet/impl/firo_wallet.dart, the masternode owner-address derivation loop is tightened. A new local helper isUsableOwner() rejects null addresses, the collateral address, and now also the payout address. The for-loop and final validation now use this helper. The exception message is updated to mention both excluded addresses. The change is small and appears to be a merge from a staging branch into a feature branch.
Changed components
lib/wallets/wallet/impl/firo_wallet.dartFiro masternode owner address derivationInspect captured patch +9 / −8
### lib/wallets/wallet/impl/firo_wallet.dart
@@ -1019,20 +1019,21 @@ class FiroWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T>
);
}
+ bool isUsableOwner(Address? address) =>
+ address != null &&
+ address.value != collateralAddress &&
+ address.value != payoutAddress;
+
Address? ownerAddress = await getCurrentReceivingAddress();
const maxOwnerAttempts = 32;
- for (
- var i = 0;
- i < maxOwnerAttempts &&
- (ownerAddress == null || ownerAddress.value == collateralAddress);
- i++
- ) {
+ for (var i = 0; i < maxOwnerAttempts && !isUsableOwner(ownerAddress); i++) {
await generateNewReceivingAddress();
ownerAddress = await getCurrentReceivingAddress();
}
- if (ownerAddress == null || ownerAddress.value == collateralAddress) {
+ if (ownerAddress == null || !isUsableOwner(ownerAddress)) {
throw Exception(
- "Could not derive owner address distinct from collateral address.",
+ "Could not derive owner address distinct from collateral and payout "
+ "addresses.",
);
}
Why this scored 42/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.