The Uniswap router contract still retains an approval after an unsuccessful swap
Description
The buy
function of the Launchpad contract will execute _swapRemainingQuote
to attempt swapping the remaining USDC tokens if the available LaunchToken supply, before reaching BONDING_SUPPLY
, was insufficient. After moving liquidity to the Uniswap pair contract, the Uniswap router will be assigned the remaining USDC tokens, and router.swapExactTokensForTokens
will be executed within a try-catch block. If the swap execution reverts, the remaining USDC tokens will be transferred back to the user. However, in this case, the router will still retain approval for the transfer of these tokens.
function _swapRemainingQuote(address token, address recipient, uint256 remainingQuote)
internal
returns (uint256, uint256)
{
// Transfer the remaining quote from the user
address(quoteAsset).safeTransferFrom(msg.sender, address(this), remainingQuote);
// Prepare swap path
address[] memory path = new address[](2);
path[0] = address(quoteAsset);
path[1] = token;
// Approve router to spend remaining quote
address(quoteAsset).safeApprove(address(router), remainingQuote);
try router.swapExactTokensForTokens(
remainingQuote,
1, // Accept any amount (user has already authorized worstAmountInQuote)
path,
recipient,
block.timestamp + 300
) returns (uint256[] memory amounts) {
// Return the tokens received and quote used
return (amounts[1], remainingQuote);
} catch {
// If swap fails, return the additional quote tokens to the user
address(quoteAsset).safeTransfer(msg.sender, remainingQuote);
return (0, 0);
}
}
Impact
If the swapExactTokensForTokens
execution reverts, the Uniswap router will still retain approval for transferring USDC tokens from the Launchpad contract. This creates a security risk, as the approved router contract could potentially be used to swap and transfer USDC tokens without additional authorization, leading to a potential loss of funds from the Launchpad contract.
The current router implementation does not allow setting a custom sender address and only uses msg.sender
. However, if the router were to support specifying an arbitrary sender address in the future, the severity of this issue would increase significantly, as it could enable an attacker to directly swap tokens from the Launchpad contract.
Recommendations
We recommend revoking the approval to prevent a scenario where USDC tokens from the Launchpad could be used through the router contract after an unsuccessful swap.
Remediation
This issue has been acknowledged by Liquid Labs, Inc., and a fix was implemented in commit 15eadc2b↗.
Liquid Labs, Inc. provided the following response:
This commit (same as 3.3) also addresses 3.5 by revoking token approvals to the uniswap router if the graduation slippage spillover swap fails.