For the complete documentation index, see llms.txt. This page is also available as Markdown.

89053 bc high wormhole miner volume fees are permanently unclaimable because the credit creates no zk tree leaf

Submitted on Aug 16th 2026 at 19:37:20 UTC by @tinnohofficial for Audit Comp | Quantus

  • Report ID: #89053

  • Report Type: Blockchain/DLT

  • Report severity: High

  • Target: https://github.com/immunefi-team/audit-comp-quantus-chain

  • Impacts:

    • Permanent freezing of unclaimed yield

Description

Brief/Intro

QPoW miners are paid to Poseidon-derived wormhole addresses. These addresses have no Dilithium signing key, so their funds can only be claimed through a ZK-tree leaf that commits the recipient and amount.

The wormhole pallet credits the miner's volume-fee share to the correct address, but does not create that leaf. The balance is visible in System::Account, yet the miner can neither sign from the address nor prove a wormhole exit for the fee. Every successfully credited miner volume fee is therefore permanently unclaimable without privileged recovery.

Vulnerability Details

Wormhole credits require a ZK-tree leaf

For a normal user exit, process_exit_bundle performs both required operations:

See pallets/wormhole/src/lib.rs:822-859.

record_transfer increments TransferCount and inserts a leaf containing the recipient, transfer count, asset ID, and exact amount:

See pallets/wormhole/src/lib.rs:1280-1310 and pallets/zk-tree/src/lib.rs:114-147.

Normal block rewards follow the same rule by calling record_transfer_proof immediately after minting: pallets/mining-rewards/src/lib.rs:230-237.

The miner-fee branch omits the leaf

The miner-fee branch only changes the balance and emits an event:

See pallets/wormhole/src/lib.rs:942-983. There is no record_transfer or record_transfer_proof call.

Nothing records the leaf indirectly:

  • increase_balance is event-free, as documented at pallets/wormhole/src/lib.rs:822-827 and tested by exit_credits_emit_no_scannable_transfer_events.

  • MinerVolumeFeePaid is not one of the balance events scanned by WormholeProofRecorderExtension: runtime/src/transaction_extensions.rs:329-395.

  • The settlement calls are bare unsigned extrinsics, so the extension's normal signed-transaction scan does not process them.

The credited address cannot spend normally

extract_author_from_digest derives the author with derive_wormhole_address(preimage): primitives/wormhole/src/lib.rs:122-150. MINING.md:41-48 confirms that mining rewards use this wormhole address.

The miner therefore has only two possible spend paths, and both are unavailable for this fee:

  1. A normal balance transfer is impossible because no Dilithium signing key exists for the Poseidon-derived address.

  2. A wormhole exit is impossible because no leaf commits the miner-fee amount.

A later block reward does not recover the fee. Its leaf commits only the later reward amount, not the account's full free balance.

Distinction from the public Eiger findings

This is not the previously reported author-derivation bug:

  • EQ-QNT-WORMHOLE-F-03 reported that the pallet decoded the raw preimage as the author. That was fixed by deriving the correct wormhole address. The current code now credits the correct address, but still omits the leaf needed to claim the credit.

  • EQ-QNT-WORMHOLE-F-05 concerned missing signed transfer call variants in the proof recorder. This fee is an event-free internal balance credit inside a bare unsigned settlement call, so that fix does not cover it.

The current defect has a different root cause and requires a different fix: record a leaf for the correctly derived author.

Impact Details

The runtime assigns 50% of each computed wormhole volume fee to the block author: runtime/src/configs/mod.rs:728-738. Whenever that credit succeeds, the full miner share becomes permanently unclaimable.

The protocol emits MinerVolumeFeePaid and displays a real free balance, but the miner cannot spend or claim it. No later reward sweeps the missing amount. Recovery of already-stranded fees requires privileged governance or a storage migration.

This directly matches High - Permanent freezing of unclaimed yield: the frozen value is protocol-allocated miner-fee revenue, not user principal.

Record a transfer immediately after each successful miner-fee credit:

The settlement weight must also include this additional ZK-tree insertion. Previously stranded balances require a separate migration or privileged recovery.

References

  • pallets/wormhole/src/lib.rs:822-859 - user exit credit followed by record_transfer.

  • pallets/wormhole/src/lib.rs:942-983 - miner-fee credit with no leaf.

  • pallets/wormhole/src/lib.rs:1280-1330 - leaf creation and transfer-count update.

  • pallets/zk-tree/src/lib.rs:114-147 - leaf fields, including the exact amount.

  • pallets/mining-rewards/src/lib.rs:230-237 - normal miner reward followed by proof recording.

  • primitives/wormhole/src/lib.rs:97-150 - wormhole author derivation.

  • runtime/src/configs/mod.rs:728-738 - volume-fee configuration.

  • MINING.md:41-48 - miner rewards use derived wormhole addresses.

Proof of Concept

The PoC submits the pallet's production private-batch fixture through the real verify_private_batch call. In the same settlement:

  • The user exit receives a balance and TransferCount = 1, proving its leaf was inserted.

  • The block author receives the miner fee but remains at TransferCount = 0, proving no leaf was inserted.

  • A second test shows that a later block-reward leaf commits only the reward and does not cover the stranded fee.

Run

From audit-comp-quantus-chain:

1

Copy the PoC

Copy the PoC to pallets/wormhole/src/poc_miner_fee.rs.

2

Register the test module

Add the following above the existing #[cfg(test)] mod tests; in pallets/wormhole/src/lib.rs:

3

Run the tests

Observed Output

Tested against frozen chain commit 3b243b8:

PoC Code

Was this helpful?