Smart contract unable to operate due to lack of token funds
Description
Brief/Intro
When _earmark is called in consecutive blocks, the queryGraph interval becomes zero-length, causing no funds to be earmarked. As a result, transmuter redemptions are never paid and users debt won't be repaid.
Vulnerability Details
The function _earmark calculates the amount to earmark using:
If _earmark is called in consecutive blocks (e.g., due to the permissionless poke function or frequent protocol activity via withdraw, mint, burn, repay, redeem), then:
lastEarmarkBlock + 1 == block.number
queryGraph returns 0 for a zero-length interval
No new funds are earmarked, preventing transmutation progress and debt repayment.
Example scenario (using poke)
A user deposits and mints alAsset at block 0, setting lastEarmarkBlock = 0.
At block 1, a user calls poke().
_earmark computes queryGraph(0 + 1, 1) → 0.
lastEarmarkBlock is updated to 1.
If this continues each block, amount always equals 0, causing earmarked funds to never accumulate.
Impact Details
Because transmuter redemptions depend on earmarked debt, this behaviour leads to:
Users receiving no funds upon redemption.
The protocol failing to automatically repay debt.
This issue can occur naturally due to normal transaction flow, not just via malicious spam.
Recommendation
Add a guard to skip execution when the block interval is zero:
This ensures that _earmark only runs when there has been at least one full block of accumulation.
Proof of Concept
Proof Of Concept
In AlchemistV3.t.sol, in the setup function deployCoreContracts, change the timeToTransmute from 5_256_000 to 5000 (This is just for testing purposes, as if we attempt to poke 5_256_000) times in the test, it will result in a OOG error.
Then, add the following test, and run in the console forge test --mt test_loss_of_redeemed_funds_when_poking_every_block -vv. Feel free to change the value of rollAmount to see how the amount of consecutive _earmarked calls affects the amounts earmarked and redeemed.
Logs
We can clearly see that calling _earmarked consecutively results in a linearly loss of funds redeemed.