SmartVaultV3 has a swap function that allows the loaner to swap one the collateral for another accepted token, without having to withdraw. As parameters the function takes, the token in, the token out, and the amount to swap. Out of the user control is the minimum amount to receive, and the fee of the pool to use. The fee used is always 3000
(0,3%). The minimum amount out is calculated (calculateMinimumAmountOut function) and it can range from 0 to the minimum amount to keep the vault collateralized.
The user can make a swap with unintended losses being incurred, be it from an actor frontrunning or from the liquidity pool not having enough liquidity. Control over the minimum amount out and the fee tier should be given to the user.
The swap function starts by calculateMinimumAmountOut(), which checks the minimum amount of tokenOut to receive to keep the loan at the minimum of collateralization. It will then call UniswapV3 Router with the calculated minimum amount of token out and the hardcoded fee of 3000 (0,3%).
Some awful scenarios can occur:
User gets nothing for his swap
The user will make a swap of tokenA to tokenB.
The amount defined by the user is 10. Looking at the current market rate between TokenA and TokenB, he expects to receive 5 TokenB
10 TokenA or 5 TokenB is an amount unnecessary for the health of the vault. The MinimumAmountOut is defined as 0.
The swap is done and the user instead of 5 TokenB, receives dust amounts of TokenB.
User loan is put at the edge of liquidation, being liquidated a few blocks after the swap
The user will make a swap of tokenA to tokenB.
The amount defined by the user is 10. Looking at the current market rate between TokenA and TokenB, he expects to receive 5 TokenB
2 TokenB is the minimum necessary to keep the vault at the edge of liquidation. The MinimumAmountOut is defined as 2 TokenB.
The swap is done and the user instead of 5 TokenB, receives 2 TokenB.
A few blocks after with a slight variation on the price of the collateral tokens the vault is undercollateralised. The vault is liquidated and the user loses his collateral.
The reason for receiving less amounts of TokenB than predicted by the current market rate, could be that there is a frontrunner that used up liquidity for the swap, or that the used UNIV3 pool simply did not have enough liquidity.
There is not enough predictability on the results of the swap.
One of the accepted tokens, PAXG, at the moment has barely any liquidity on UniswapV3 for any pool fee.
Manual review.
The control of amount out and fee tier should be given to the user, and a check should be made, if the amount out of the received token will keep the vault collateralized.
@@ -209,21 +216,26 @@ contract SmartVaultV3 is ISmartVault {
uint256 collateralValueMinusSwapValue = euroCollateral() - calculator.tokenToEur(getToken(_inTokenSymbol), _amount);
return collateralValueMinusSwapValue >= requiredCollateralValue ?
0 : calculator.eurToToken(getToken(_outTokenSymbol), requiredCollateralValue - collateralValueMinusSwapValue);
}
- function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount) external onlyOwner {
+ function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount, uint256 _minAmountOut, uint24 _fee) external onlyOwner {
uint256 swapFee = _amount * ISmartVaultManagerV3(manager).swapFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
address inToken = getSwapAddressFor(_inToken);
uint256 minimumAmountOut = calculateMinimumAmountOut(_inToken, _outToken, _amount);
+ require(_minAmountOut >= minimumAmountOut);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: inToken,
tokenOut: getSwapAddressFor(_outToken),
- fee: 3000,
+ fee: _fee,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount - swapFee,
- amountOutMinimum: minimumAmountOut,
+ amountOutMinimum: _minAmountOut,
sqrtPriceLimitX96: 0
});
inToken == ISmartVaultManagerV3(manager).weth() ?
executeNativeSwapAndFee(params, swapFee) :
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.