Open sherlock-admin3 opened 4 months ago
Valid
1 comment(s) were left on this issue during the judging contest.
panprog commented:
medium. While amounts provided are from the trusted admin, who is supposed to provide exact amounts to add liquidity in correct ratio of token amounts, the fact that live balance of the contract is used makes it possible for the balance to change from the time admin provides the amounts, making the transaction revert. Additionally, current contract balances might be in so high disproportion, that admin will simply not have enough funds to create correct ratio to add liquidity.
The protocol team fixed this issue in the following PRs/commits: https://github.com/Zivoe/zivoe-core-foundry/pull/264
The Lead Senior Watson signed off on the fix.
BiasedMerc
medium
OCL_ZVE::pushToLockerMulti() will revert due to incorrect assert() statements when interacting with UniswapV2
Summary
OCL_ZVE::pushToLockerMulti()
verifies that the allowances for both tokens is 0 after providing liquidity to UniswapV2 or Sushi routers, however there is a high likelihood that one allowance will not be 0, due to setting a 90% minimum liquidity provided value. Therefore, the function will revert most of the time breaking core functionality of the locker, making the contract useless.Vulnerability Detail
The DAO can add liquidity to UniswapV2 or Sushi through
OCL_ZVE::pushToLockerMulti()
function, whereaddLiquidity
is called onrouter
:OCL_ZVE.sol#L198C78-L198
OCL_ZVE.sol#L90
The router is intended to be Uniswap v2 or Sushi (Sushi router uses the same code as Uniswap v2 0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f).
UniswapV2Router02::addLiquidity
When calling the function 4 variables relevant to this issue are passed:
amountADesired
andamountBDesired
are the ideal amount of tokens we want to deposit, whilstamountAMin
andamountBMin
are the minimum amounts of tokens we want to deposit. Meaning the true amount that will deposit be deposited for each token will be inbetween those 2 values, e.g:amountAMin <= amountA <= amountADesired
. WhereamountA
is how much oftokenA
will be transfered.The transfered amount are
amountA
andamountB
which are calculated as follows: UniswapV2Router02::_addLiquidityUniswapV2Router02::_addLiquidity
receives a quote for how much of each token can be added and validates that the values fall within theamountAMin
andamountADesired
range. Unless the exactly correct amounts are passed asamountADesired
andamountBDesired
then the amount of one of the two tokens will be less than the desired amount.Now lets look at how
OCL_ZVE
interacts with the Uniswapv2 router:OCL_ZVE::addLiquidity
The function first increases the allowances for both tokens to
balPairAsset
andbalZVE
respectively.When calling the router,
balPairAsset
andvalZVE
are provided as the desired amount of liquidity to add, however(balPairAsset * 9) / 10
and(balZVE * 9) / 10
are also passed as minimums for how much liquidity we want to add.As the final transfered value will be between:
(balPairAsset * 9) / 10 <= x <= balPairAsset
therefore the allowance after providing liquidity will be:0 <= IERC20(pairAsset).allowance(address(this), router) <= balPairAsset - (balPairAsset * 9) / 10
however the function expects the allowance to be 0 for both tokens after providing liquidity. The same applies to theZVE
allowance.This means that in most cases one of the assert statements will not be met, leading to the add liquidity call to revert. This is unintended behaviour, as the function passed a
90%
minimum amount, however the allowance asserts do not take this into consideration.Impact
Calls to
OCL_ZVE::pushToLockerMulti()
will revert a majority of the time, causing core functionality of providing liquidity through the locker to be broken.Code Snippet
OCL_ZVE.sol#L198C78-L198 UniswapV2Router02.sol#L61-L76 UniswapV2Router02.sol#L33-L60 OCL_ZVE.sol#L191-L209
Tool used
Manual Review
Recommendation
The project wants to clear allowances after all transfers, therefore set the router allowance to 0 after providing liquidity using the returned value from the router:
This will remove the left over allowance after providing liquidity, ensuring the allowance is 0.