> For the complete documentation index, see [llms.txt](https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/tutorials/tutorial-3-approvals-and-safe-approvals/vulnerability-examples/erc20-approval-reset-requirement.md).

# ERC20 Approval Reset Requirement

{% hint style="info" %}
[**Book an audit with Zokyo**](https://www.zokyo.io/)
{% endhint %}

{% hint style="info" %}
This type of vulnerability is prevalent in decentralized exchanges (DEX)
{% endhint %}

ERC20 tokens like Tether (USDT) pose unique challenges due to their requirement of resetting approval to zero before setting a new approval amount. This requirement, aimed at mitigating front-running attacks, could lead to transaction failures if not properly managed.

Consider the following function, `_swapAssetOut()`, where an asset is swapped via a stable swap pool:

```
// Original code
SafeERC20.safeApprove(IERC20(_assetIn), address(pool), _amountIn);
amountIn = pool.swapExactOut(_amountOut, _assetIn, _assetOut, _maxIn);
```

In the above snippet, the `safeApprove` function sets the approval for the `_assetIn` amount, and then `swapExactOut` is used to perform the actual swap. This code might fail if `_assetIn` is a token like USDT, which requires that an existing non-zero approval be reset to zero before assigning it a new value.

The failure happens because `safeApprove` attempts to change the approval from a non-zero value to another non-zero value, which USDT does not permit. Hence, the function reverts, leading to the failure of the entire transaction.

To solve this problem, the approval must first be set to zero, and only then can the new approval value be set. This procedure can be performed using the `safeApprove` and `safeIncreaseAllowance` functions, as follows:

```
// Revised code
SafeERC20.safeApprove(IERC20(_assetIn), address(pool), 0); // First reset the allowance to 0
SafeERC20.safeIncreaseAllowance(IERC20(_assetIn), address(pool), _amountIn); // Then set the new allowance
amountIn = pool.swapExactOut(_amountOut, _assetIn, _assetOut, _maxIn);
```

This revision takes into account the approval requirements of tokens like USDT, first resetting the allowance to zero before setting it to the desired value. This approach ensures the function's successful execution, even with tokens that require approval resetting. By adopting this pattern when dealing with ERC20 tokens, developers can prevent contract failures when interacting with tokens like USDT.

Real bug bounty examples:

* [\[L-06\] Unsafe approve](https://github.com/code-423n4/2021-07-connext-findings/issues/13)
* [\[M-17\] Unsafe approve would halt the auction and burn the bond](https://github.com/code-423n4/2021-09-defiprotocol-findings/issues/35)
* [\[M-05\] Did Not Approve To Zero First Causing Certain Token Transfer To Fail](https://github.com/code-423n4/2022-06-connext-findings/issues/154)

This vulnerability is generally classed as medium risk, but could be high risk depending on the implementation
