The getPoolShareWeight function returns a user's pool share weight by calculating how many SPARTAN the user's LP tokens account for. However, this approach is vulnerable to flash loan manipulation since an attacker can swap a large number of TOKEN to SPARTAN to increase the number of SPARTAN in the pool, thus effectively increasing his pool share weight.
Proof of Concept
According to the implementation of getPoolShareWeight, a user's pool share weight is calculated by uints * baseAmount / totalSupply, where uints is the number of user's LP tokens, totalSupply is the total supply of LP tokens, and baseAmount is the number of SPARTAN in the pool. Thus, a user's pool share weight is proportional to the number of SPARTAN in the pool. Consider the following attack scenario:
Supposing the attacked pool is SPARTAN-WBNB. The attacker first prepares some LP tokens (WBNB-SPP) by adding liquidity to the pool.
The attacker then swaps a large number of WBNB to SPARTAN, which increases the pool's baseAmount. He could split his trade into small amounts to reduce slip-based fees.
The attacker now wants to increase his weight in the DaoVault. He adds his LP tokens to the pool by calling the deposit function of Dao.
Dao then calls depositLP of DaoVault, causing the attacker's weight to be recalculated. Due to the large proportion of SPARTAN in the pool, the attacker's weight is artificially increased.
With a higher member weight, the attacker can, for example, vote the current proposal with more votes than he should have or obtain more rewards when calling harvest of the Dao contract.
The attacker then swaps back SPARTAN to WBNB and only loses the slip-based fees.
A possible mitigation is to record the current timestamp when a user's weight in the DaoVault or BondVault is recalculated and force the new weight to take effect only after a certain period, e.g., a block time. This would prevent the attacker from launching the attack since there is typically no guarantee that he could arbitrage the WBNB back in the next block.
Handle
shw
Vulnerability details
Impact
The
getPoolShareWeight
function returns a user's pool share weight by calculating how many SPARTAN the user's LP tokens account for. However, this approach is vulnerable to flash loan manipulation since an attacker can swap a large number of TOKEN to SPARTAN to increase the number of SPARTAN in the pool, thus effectively increasing his pool share weight.Proof of Concept
According to the implementation of
getPoolShareWeight,
a user's pool share weight is calculated byuints * baseAmount / totalSupply
, whereuints
is the number of user's LP tokens,totalSupply
is the total supply of LP tokens, andbaseAmount
is the number of SPARTAN in the pool. Thus, a user's pool share weight is proportional to the number of SPARTAN in the pool. Consider the following attack scenario:baseAmount
. He could split his trade into small amounts to reduce slip-based fees.DaoVault
. He adds his LP tokens to the pool by calling thedeposit
function ofDao.
Dao
then callsdepositLP
ofDaoVault
, causing the attacker's weight to be recalculated. Due to the large proportion of SPARTAN in the pool, the attacker's weight is artificially increased.harvest
of theDao
contract.Referenced code: Utils.sol#L46-L50 Utils.sol#L70-L77 DaoVault.sol#L44-L56 Dao.sol#L201 Dao.sol#L570
Recommended Mitigation Steps
A possible mitigation is to record the current timestamp when a user's weight in the
DaoVault
orBondVault
is recalculated and force the new weight to take effect only after a certain period, e.g., a block time. This would prevent the attacker from launching the attack since there is typically no guarantee that he could arbitrage the WBNB back in the next block.