When a UUPS proxy is upgraded, the new implementation must maintain the exact same storage layout as the old one. In the original ThunderLoan contract, the variables are declared in order: s_tokenToAssetToken, s_feePrecision, and s_flashLoanFee. The upgraded contract removes the s_feePrecision variable and replaces it with a compile-time constant (FEE_PRECISION). Because Solidity constants do not occupy storage slots, every variable declared after it shifts up by one slot. Consequently, the new s_flashLoanFee variable now points to the storage slot previously occupied by s_feePrecision. Upon upgrade, it reads the old s_feePrecision value (1e18) as the fee, corrupting the fee from 0.3% (3e15) to 100% (1e18) and making all flashloans prohibitively expensive.
Likelihood: High. The storage layout shift is deterministic; it will occur automatically the moment the upgrade is executed on any deployed instance.
Impact: High. The flashloan fee is corrupted to 100%, making the protocol unusable. The corruption happens silently without emitting an event, requiring manual owner intervention to reset the fee.
The PoC upgrades the proxy and asserts that the fee changes from 0.3% (3e15) to 100% (1e18).
Preserve the storage layout by leaving a placeholder variable where the old one existed.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.