**Description:** The `_refundERC20` function is not protected due to lack of safety guard and it also peforms external calls before updating state variables, it fails to follow CEI format.
An attacker can exploit this to drain multiple tokens from the contract by reentering during the token transfer.
```javascript
function _refundERC20(address _to) internal {
i_WETH.safeTransfer(_to, balances[_to][address(i_WETH)]);
i_WBTC.safeTransfer(_to, balances[_to][address(i_WBTC)]);
i_USDC.safeTransfer(_to, balances[_to][address(i_USDC)]);
balances[_to][address(i_USDC)] = 0;
balances[_to][address(i_WBTC)] = 0;
balances[_to][address(i_WETH)] = 0;
}
```
**Impact:**
1.complete draining of contract's WETH, WBTC, and USDC tokens
2.might affects all users' balances
**Proof of Concept:**
**Recommended Mitigation:**
1. consider using Openzeppelin's ReentrancyGuard implementation.
2. The locked state should be set to true immediately before the function logic (_) and reset to false only after the logic is executed. A proper implementation should look like this:
```diff
modifier nonReentrant() {
require(!locked, "No re-entrancy");
+ locked = true; // Set lock before the function execution
_;
locked = false; // Reset lock after the function execution
}
function _refundERC20(address _to) internal {
// First store the amounts
+ uint256 wethAmount = balances[_to][address(i_WETH)];
+ uint256 wbtcAmount = balances[_to][address(i_WBTC)];
+ uint256 usdcAmount = balances[_to][address(i_USDC)];
// Zero out balances
balances[_to][address(i_WETH)] = 0;
balances[_to][address(i_WBTC)] = 0;
balances[_to][address(i_USDC)] = 0;
// Then transfer using stored amounts
i_WETH.safeTransfer(_to, wethAmount);
i_WBTC.safeTransfer(_to, wbtcAmount);
i_USDC.safeTransfer(_to, usdcAmount);
}
```