ValueDeFi Incident: Incorrect Weighted Constant Product Invariant Calculation

[Disclaimer] This analysis is based on the initial finding by @FrankResearcher!

Started at 07:41:39 PM +UTC, May 7, 2021, ValueDeFi’s vSwap contract was exploited to drain a number of pools at the loss of about $11M. The incident was due to the improper use of a complex exponentiation power() function behind the calculation and enforcement of the weighted constant product invariant. It is worthwhile to mention that vSwap uses the weighted constant product invariant formula for non 50-50 ratio pools. In the following, we elaborate the technical details.

Summary

Details

Incorrect Weighted Constant Product Invariant Calculation

Note the power() routine takes four arguments (baseN, baseD, expN, and expD) and is used to calculate an integer approximation of (baseN/baseD)^(expN/expD)*(2^precision) where precision is used for the calculated result. However, there is a caveat in how this power() function should be used. It makes an explicit assumption that baseN must be no less than baseD, i.e., baseN >= baseD. In this attack, the pool’s swap() function are called with a crafted input that intentionally violates the above assumption. As a result, the weighted constant product enforcement is passed while the pool funds are being drained.

We started the analysis from the transaction behind one specific hack: 2fd0…c2de. This transaction has a number of operations against the non 50–50 ratio vBSWAP-WBNB pool and our elaboration only focuses on the first swap() operation operation. Specifically, this swap() operation in essence trades in 0.05 WBNB and trades out 1 WEI vBSWAP and 3,543.083896847545353949 WBNB! The purpose of trade-out of 1 WEI leads to balance0Adjusted = reserve0 - 1 WEI, which causes the execution to take the else-branch in the above figure. And the violated assumption on
balance1Adjusted >= reserve1 corrupts the power() execution, hence passing the constant product enforcement.

If we examine the root cause behind this attack, the vulnerability stems from the improper use of a complex exponentiation power() function, which unfortunately lies in the critical path for invariant calcuation and enforcement. In the meantime, we also strongly suggest to make the assumption explicit in the power() function by adding the following requirement: require(baseN >= baseD)!

The Funds

About Us

A Blockchain Security Company (https://peckshield.com)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store