### 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

This incident was due to the mis-calculation by the protocol on the adopted weighted constant product invariant for non 50-50 ratio pools. There is no flashloan or price manipulation involved. The consequence of mis-calculated invariant allows for draining of affected pool funds. Currently, the bug has been exploited to attack 9 non 50-50 ratio pools with the estimated loss of $11M.

### Details

#### Incorrect Weighted Constant Product Invariant Calculation

The `vSwap`

pool is initially forked from `UniswapV2`

but with the support of non 50-50 ratio
pools. The non 50-50 ratio pools require a different approach to calculate the weighted constant
product, i.e.,
`reserve0^(weight0/50) * reserve1^(weight1/50) <= balance0Adjusted^(weight0/50) * balance1Adjusted^(weight1/50)`

.
Because of the required exponentiation function, ValueDeFi makes use of the Bancor formula to calculate
the above constant product as shown below.

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

This attack leads to more than $11M loss from the affected 9 pools. And most of the attacker’s funds from the above exploitations are currently held in this wallet: b88a. We are actively monitoring this wallet for any movement.

### About Us

PeckShield Inc. is an industry leading blockchain security company with the goal of elevating the security, privacy, and usability of the current blockchain ecosystem. For any business or media inquiries (including the need for smart contract auditing), please contact us at telegram, twitter, or email.