Vulnerability Details
In CurveAdapter#executeSwapExactInputSingle()
function, it will call to curve to swap token through exchange_with_best_rate()
function:
function executeSwapExactInputSingle(SwapExactInputSinglePayload calldata swapPayload)
external
returns (uint256 amountOut)
{
IERC20(swapPayload.tokenIn).transferFrom(msg.sender, address(this), swapPayload.amountIn);
address curveStrategyRouterCache = curveStrategyRouter;
IERC20(swapPayload.tokenIn).approve(curveStrategyRouterCache, swapPayload.amountIn);
uint256 expectedAmountOut = getExpectedOutput(swapPayload.tokenIn, swapPayload.tokenOut, swapPayload.amountIn);
uint256 amountOutMinimum = calculateAmountOutMin(expectedAmountOut);
return ICurveSwapRouter(curveStrategyRouterCache).exchange_with_best_rate({
_from: swapPayload.tokenIn,
_to: swapPayload.tokenOut,
_amount: swapPayload.amountIn,
_expected: amountOutMinimum,
_receiver: swapPayload.recipient
});
}
In exchange_with_best_rate
function, receiver is always caller, which is CurveAdapter
contract:
def exchange_with_best_rate(
_from: address,
_to: address,
_amount: uint256,
_expected: uint256,
_receiver: address = msg.sender,
)
And after swapping, it do not transfer token to actual recipient, lead to token stuck in the contract
Impact
Swapped token stuck in the contract
Recommendations
In CurveAdapter#executeSwapExactInputSingle()
function, transfer token to recipient after swapping