Forced feeCollector update during ownership transfer leads to potential fee misdirection
transferOwnership and rotateToPublicKey silently overwrite feeCollector with the new owner address, redirecting protocol fees away from the configured treasury until the new owner manually restores it.
Description
Both transferOwnership() and rotateToPublicKey() automatically
overwrite feeCollector with the new owner address as a side effect of
transferring ownership. There is no way to transfer ownership without also
redirecting all protocol fees.
Vulnerable Scenario
- The owner has
feeCollectorset to a dedicated fee-receiving address (e.g., a multisig or treasury). - The owner calls
rotateToPublicKey()to rotate to the next key in the pre-rotation chain. feeCollectoris silently overwritten tolatest.prerotatedKeyHashat line 754, beforetransferOwnership()overwrites it again at line 203.- All protocol fees now flow to the new owner address instead of the dedicated treasury.
- The new owner must immediately call
setFeeCollector()to restore the intended fee destination, creating a race window where fees can be misdirected.
Impact
Protocol fees are silently redirected to the new owner address on every
ownership transfer or key rotation. If the new owner is not monitoring for
this, fees accumulate in an unintended address. During the window between
ownership transfer and a corrective setFeeCollector() call, any
wrap/unwrap operations will send fees to the wrong destination.
Recommendation
Decouple the feeCollector update from ownership transfer. Remove
feeCollector = newOwner from transferOwnership() and
feeCollector = latest.prerotatedKeyHash from rotateToPublicKey(). If
automatic fee redirection is desired, make it opt-in via a separate
parameter or a dedicated function call after the transfer.
Resolution
YadaCoin, Confirmed. Removed the feeCollector state variable
entirely. Fees now flow directly to owner(), eliminating the forced
overwrite issue.
Zealynx, Fixed. Confirmed the removal of feeCollector resolves the
fee misdirection vector. Fresh deployment strategy addresses any storage
layout concerns from the refactor.

