--- ### Lack of Slippage Protection - Write-up The very next vulnerability we're going to write up is found within `swapExactOutput` and is classified as a `lack of slippage protection`. ```js // @Audit-High - Needs slippage protection - maxInputAmount function swapExactOutput( IERC20 inputToken, IERC20 outputToken, uint256 outputAmount, uint64 deadline ) public revertIfZero(outputAmount) revertIfDeadlinePassed(deadline) returns (uint256 inputAmount) { uint256 inputReserves = inputToken.balanceOf(address(this)); uint256 outputReserves = outputToken.balanceOf(address(this)); inputAmount = getInputAmountBasedOnOutput(outputAmount, inputReserves, outputReserves); _swap(inputToken, inputAmount, outputToken, outputAmount); } ``` I suspect this is going to be a `high severity` bug, but let's assess `impact` and `likelihood` once more. - **Impact:** High -> a swap may be significant worse for a user than expected - **Likelihood:** -> Medium/High -> MEV (learn later), market conditions change all the time Slippage protection is a necessary consideration in nearly all token swaps. I want you to take a moment to pause the read into some of the real-world examples identified in audits on [**Solodit**](https://solodit.xyz/). Let's write up our second `high severity` finding! Compare your write up to mine below - challenge yourself not to peek! <details> <summary>[H-2] Lack of slippage protection in TSwapPool::swapExactOutput causes users to potentially receive way fewer tokens</summary> ### [H-2] Lack of slippage protection in TSwapPool::swapExactOutput causes users to potentially receive way fewer tokens **Description:** The `swapExactOutput` function does not include any sort of slippage protection. This function is similar to what is done in `TSwapPool::swapExactInput`, where the function specifies a `minOutputAmount`, the `swapExactOutput` function should specify a `maxInputAmount`. **Impact:** If market conditions change before the transaciton processes, the user could get a much worse swap. **Proof of Concept:** 1. The price of 1 WETH right now is 1,000 USDC 2. User inputs a `swapExactOutput` looking for 1 WETH 1. inputToken = USDC 2. outputToken = WETH 3. outputAmount = 1 4. deadline = whatever 3. The function does not offer a maxInput amount 4. As the transaction is pending in the mempool, the market changes! And the price moves HUGE -> 1 WETH is now 10,000 USDC. 10x more than the user expected 5. The transaction completes, but the user sent the protocol 10,000 USDC instead of the expected 1,000 USDC **Recommended Mitigation:** We should include a `maxInputAmount` so the user only has to spend up to a specific amount, and can predict how much they will spend on the protocol. ```diff function swapExactOutput( IERC20 inputToken, + uint256 maxInputAmount, . . . inputAmount = getInputAmountBasedOnOutput(outputAmount, inputReserves, outputReserves); + if(inputAmount > maxInputAmount){ + revert(); + } _swap(inputToken, inputAmount, outputToken, outputAmount); ``` </details> ### Wrap Up I'll mention as an aside that there's _some_ argument for the above to be considered a `medium severity` vulnerability, this pertains to user approvals and things of an accountability nature, but for this we'll leave it as a `high`. Let's tackle the next finding, in the next lesson!
Slippage Protection Lacking in SwapExactOutput, Add Max Input for Safety. Patrick elaborates with a Proof-Of-Concept Scenario.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Solidity Developer
Smart Contract SecurityDuration: 25min
Duration: 1h 18min
Duration: 35min
Duration: 2h 16min
Duration: 5h 03min
Duration: 5h 22min
Duration: 4h 33min
Duration: 2h 01min
Duration: 1h 40min
Testimonials
Read what our students have to say about this course.
Chainlink
Chainlink
Gustavo Gonzalez
Solutions Engineer at OpenZeppelin
Francesco Andreoli
Lead Devrel at Metamask
Albert Hu
DeForm Founding Engineer
Radek
Senior Developer Advocate at Ceramic
Boidushya
WalletConnect
Idris
Developer Relations Engineer at Axelar