89134 bc high miner volume fee credits lack zk tree leaves permanently freezing block author fees
Submitted on Aug 17th 2026 at 12:13:42 UTC by @Kangaroo59250 for Audit Comp | Quantus
Report ID: #89134
Report Type: Blockchain/DLT
Report severity: High
Target: https://github.com/immunefi-team/audit-comp-quantus-chain
Impacts:
Permanent freezing of funds
Description
Summary
Every successful wormhole settlement credits the block author with a share of the settlement’s volume fee. The credit is applied to the author’s Poseidon-derived wormhole address, but no corresponding transfer proof—or ZK-tree leaf—is recorded.
Unlike a normal signature-controlled account, the derived block-author address is not backed by a Dilithium signing key. Value credited to it can only be recovered through the wormhole exit mechanism, which requires a leaf committing to (to, transfer_count, asset_id, amount) in a block header’s zk_tree_root.
Because the miner volume-fee credit has no leaf, the miner cannot construct a valid membership witness for it. Every successfully credited miner volume fee is therefore permanently unwithdrawable through the current protocol.
Vulnerability Details
process_exit_bundle in pallets/wormhole/src/lib.rs handles three related value flows inconsistently.
Aggregator rebate
At pallets/wormhole/src/lib.rs:919-933, the optional aggregator rebate is credited with increase_balance, but no leaf is recorded.
An ordinary signature-controlled aggregator account can spend the rebate normally. An aggregator that deliberately selects a wormhole address would encounter the same locking behavior, but this is not the primary issue described in this report.
Miner volume fee
At pallets/wormhole/src/lib.rs:944-983, the miner’s volume-fee share is credited to the block author with:
On success, the pallet emits:
However, it does not call Self::record_transfer or record_transfer_proof. The miner’s balance increases, but the ZK tree contains no leaf representing that credit.
The author is obtained through qp_wormhole::extract_author_from_digest in primitives/wormhole/src/lib.rs:109-151. It takes the QPoW pre-runtime digest preimage and derives:
This produces the Poseidon-derived wormhole address to which mining compensation is paid. The miner can use the corresponding wormhole secret to spend valid leaves, but cannot sign an ordinary transaction from the derived address.
Self::record_transfer, at pallets/wormhole/src/lib.rs:1280-1330, is the production path that increments the recipient’s transfer count and inserts the transfer into pallet-zk-tree. Since the miner fee path never reaches it, no membership witness can be generated for the credited fee.
This is inconsistent with pallets/mining-rewards/src/lib.rs:220-298. Successful mining-reward mints are immediately followed by:
The mining-rewards tests explicitly reference the earlier Eiger audit finding EQ-QNT-WORMHOLE-F-03: Miner Rewards Silently Burned Due to Incorrect Preimage Handling. The existing mining-reward implementation records leaves specifically so rewards sent to miner wormhole addresses remain withdrawable. The same protection is missing from the volume-fee distribution path.
Impact Details
The defect affects every miner volume-fee credit for which increase_balance succeeds.
The runtime volume-fee rate is four basis points:
VolumeFeesBurnRate is 50%, so the block author receives:
For sufficiently large settlements, the frozen miner share approaches approximately 0.020008% of the wormhole exit volume. Small settlements can have a higher effective rate because the fee is rounded up to a complete 0.01 QUAN circuit quantum.
The smallest fee is one quantum, or 0.01 QUAN, making the minimum miner share 0.005 QUAN. The runtime existential deposit is only 0.001 QUAN, so even a fresh block-author account can be created by the minimum credit. Consequently, the issue is not limited to miners whose addresses already hold mining rewards.
The affected balance is visible on-chain and announced as paid through MinerVolumeFeePaid, but the miner cannot withdraw it through either available authorization mechanism:
The Poseidon-derived address has no corresponding Dilithium signing key.
The missing ZK-tree leaf prevents construction of a valid wormhole exit proof.
The loss recurs on every settlement with a valid block author and accumulates over the chain’s lifetime.
Recovering historical credits requires a runtime upgrade. Historical successful credits can be identified from MinerVolumeFeePaid events where archival or indexed chain history is available, after which the missing leaves can be backfilled. Already-credited balances must not be minted a second time during remediation.
Recommendation
Every representable credit to a miner wormhole address must be accompanied by a ZK-tree leaf, atomically with the balance credit.
A direct per-settlement record_transfer call is insufficient because the minimum miner share is 0.005 QUAN, while ZK-tree leaves quantize amounts to 0.01 QUAN. Recording a sub-quantum amount would produce a leaf whose encoded amount is zero.
Implement per-miner accumulation before crediting the keyless address:
Define a terminal-dust policy
Define an explicit terminal-dust policy for miners that receive no future fees. Completely preserving arbitrary sub-quantum value would require increasing the circuit’s amount precision; otherwise the protocol must document an appropriate rounding, burning, or reassignment rule.
Update the pallet’s weights and benchmarks to include the additional ZK-tree insertion.
For historical successful credits, use MinerVolumeFeePaid history to aggregate missing amounts per miner and insert leaves for the already-credited, whole-quantum portions. Do not mint those amounts again. Historical sub-quantum remainders should be handled under the chosen migration policy.
Add regression coverage asserting that:
A whole-quantum miner-fee payment advances the author’s transfer count and inserts a matching leaf.
Multiple sub-quantum fees are accumulated into a withdrawable whole-quantum leaf.
No zero-value leaf is inserted.
Failed credits do not create leaves or emit
MinerVolumeFeePaid.
References
pallets/wormhole/src/lib.rs:818-860— exit payouts are credited and recordedpallets/wormhole/src/lib.rs:919-933— aggregator rebate creditpallets/wormhole/src/lib.rs:944-983— miner volume-fee credit without proof recordingpallets/wormhole/src/lib.rs:1082-1093— quantized volume-fee calculationpallets/wormhole/src/lib.rs:1280-1330— transfer-count update and ZK-tree insertionpallets/mining-rewards/src/lib.rs:220-298— mining rewards record transfer proofsprimitives/wormhole/src/lib.rs:97-151— miner wormhole-address derivationpallets/zk-tree/src/tree.rs:135-149— leaf amount quantizationruntime/src/lib.rs:97-102— token unit and existential depositruntime/src/configs/mod.rs:730-736— volume-fee parametersRepository commit:
3b243b870a5442a6e5f443056f67bbba87d472f5
Proof of Concept
Add the following test to pallets/wormhole/src/tests.rs, immediately before test_verify_private_batch_cannot_replay:
Run:
On commit 3b243b870a5442a6e5f443056f67bbba87d472f5, the test passes:
The test demonstrates all three required conditions:
The miner fee is successfully credited to the author’s balance.
The author’s transfer count does not advance.
No newly inserted ZK-tree leaf covers the credited amount.
Was this helpful?