0xlmanini
medium
USSDRebalancer.sol#BuyUSSDSellCollateral is used when USSD's price w.r.t. DAI is below a given threshold, thus the system must sell some of its collateral for DAI and then sell such DAI for USSD, pumping its price w.r.t. DAI. When a given collateral's value is able to cover for the whole amount of DAI to be bought, the system sells just enough of such collateral to cover for such DAI amount.
The issue arises in BuyUSSDSellCollateral#L121 where the Rebalancer computes the exact amount of collateral to be sold on Uniswap, as amountToSellUnits
.
This amount should be in the decimal precision of the collateral token being considered at that moment.
In reality, the amount calculated is in collateral[i].token.decimals - 18
decimal precision.
Knowing that both amountToBuyLeftUSD
and collateralval
are in 18 dp, this line's decimal precision check evaluates to: collateral[i].token.decimals() * ((1e18 * 1e18 / 1e18) / 1e18) / 1e18 == collateral[i].token.decimals() / 1e18
.
Thus amountToSellUnits
has 0 decimal precision digits for collateral tokens that use 18 decimals, and is set to 0
for tokens using less.
amountToSellUnits
is then directly passed as an argument to UniV3SwapInput()
, which sells that exact amount of tokens into Uniswap.
As a consequence, the system will receive much less tokens than expected from the pool, as it has provided such a tiny amount of input tokens.
USSDRebalancer.sol#BuyUSSDSellCollateral USSD.sol#UniV3SwapInput()
Manual Review
Change the calculation of amountToSellUnits
to:
- uint256 amountToSellUnits = IERC20Upgradeable(collateral[i].token).balanceOf(USSD) * ((amountToBuyLeftUSD * 1e18 / collateralval) / 1e18) / 1e18;
+ uint256 amountToSellUnits = IERC20Upgradeable(collateral[i].token).balanceOf(USSD) * (amountToBuyLeftUSD * 1e18 / collateralval) / 1e18;