`emergencyClose()` may fail to repay any debt
the `emergencyClose()` function may become ineffective, preventing the contract from repaying any outstanding debt, leading to potential financial losses.\\nWhen the contract is paused, all the liquidity from GMX is withdrawn (in term of `tokenA` and tokenB).\\nThe `emergencyClose()` function is called after the contract is paused due some reasons, possibly when the strategy incurs bad debts or when the contract gets hacked, High volatility, and so on...\\nThis function is responsible for repaying all the amounts of `tokenA` and `tokenB` borrowed from the `lendingVault` contract. It then sets the contract's status to `closed`. After that, users who hold `svToken` shares can withdraw the remaining assets from the contract.\\nThe issue with this function lies in its assumptions, which are not accurate. It assumes that the withdrawn amounts from GMX are always sufficient to cover the whole debt.\\n```\\n   function emergencyClose(GMXTypes.Store storage self, uint256 deadline) external {\\n        // Revert if the status is Paused.\\n        GMXChecks.beforeEmergencyCloseChecks(self);\\n\\n        // Repay all borrowed assets; 1e18 == 100% shareRatio to repay\\n        GMXTypes.RepayParams memory _rp;\\n        (_rp.repayTokenAAmt, _rp.repayTokenBAmt) = GMXManager.calcRepay(self, 1e18);\\n\\n        (bool _swapNeeded, address _tokenFrom, address _tokenTo, uint256 _tokenToAmt) =\\n            GMXManager.calcSwapForRepay(self, _rp);\\n\\n        if (_swapNeeded) {\\n            ISwap.SwapParams memory _sp;\\n\\n            _sp.tokenIn = _tokenFrom;\\n            _sp.tokenOut = _tokenTo;\\n            _sp.amountIn = IERC20(_tokenFrom).balanceOf(address(this));\\n            _sp.amountOut = _tokenToAmt;\\n            _sp.slippage = self.minSlippage;\\n            _sp.deadline = deadline;\\n\\n            GMXManager.swapTokensForExactTokens(self, _sp);\\n        }\\n        GMXManager.repay(self, _rp.repayTokenAAmt, _rp.repayTokenBAmt);\\n\\n        self.status = GMXTypes.Status.Closed;\\n\\n        emit EmergencyClose(_rp.repayTokenAAmt, _rp.repayTokenBAmt);\\n    }\\n  }\\n```\\n\\nPlease note that `_rp.repayTokenAAmt` and `_rp.repayTokenBAmt` represent the entire debt, and these values remain the same even if a swap is needed.\\nThe function checks if a swap is needed to cover its debt, and here's how it determines whether a swap is required:\\n```\\n  function calcSwapForRepay(GMXTypes.Store storage self, GMXTypes.RepayParams memory rp)\\n        external\\n        view\\n        returns (bool, address, address, uint256)\\n    {\\n        address _tokenFrom;\\n        address _tokenTo;\\n        uint256 _tokenToAmt;\\n        if (rp.repayTokenAAmt > self.tokenA.balanceOf(address(this))) {\\n            // If more tokenA is needed for repayment\\n            _tokenToAmt = rp.repayTokenAAmt - self.tokenA.balanceOf(address(this));\\n            _tokenFrom = address(self.tokenB);\\n            _tokenTo = address(self.tokenA);\\n\\n            return (true, _tokenFrom, _tokenTo, _tokenToAmt);\\n        } else if (rp.repayTokenBAmt > self.tokenB.balanceOf(address(this))) {\\n            // If more tokenB is needed for repayment\\n            _tokenToAmt = rp.repayTokenBAmt - self.tokenB.balanceOf(address(this));\\n            _tokenFrom = address(self.tokenA);\\n            _tokenTo = address(self.tokenB);\\n\\n            return (true, _tokenFrom, _tokenTo, _tokenToAmt);\\n        } else {\\n            // If there is enough to repay both tokens\\n            return (false, address(0), address(0), 0);\\n        }\\n    }\\n```\\n\\nIn plain English, this function in this case assumes: if the contract's balance of one of the tokens (e.g., tokenA) is insufficient to cover `tokenA` debt, it means that the contract balance of the other token (tokenB) should be greater than the debt of `tokenB`, and the value of the remaining balance of `tokenB` after paying off the `tokenB` debt should be equal or greater than the required value to cover the debt of `tokenA`\\nThe two main issues with this assumption are:\\nIf the contract balance of `tokenFrom` is not enough to be swapped for `_tokenToAmt` of `tokenTo`, the swap will revert, causing the function to revert each time it is called when the balance of `tokenFrom` is insufficient.(in most cases in delta long strategy since it's only borrow one token), This is highly likely since emergency closures occur when something detrimental has happened, (such as bad debts).\\nThe second issue arises when the balance of tokenFrom(EX: tokenA) becomes less than `_rp.repayTokenAAmt` after a swap. In this case, the `repay` call will revert when the `lendingVault` contract attempts to `transferFrom` the strategy contract for an amount greater than its balance. ex :\\n`tokenA` balance = 100, debtA = 80.\\ntokenB balance = 50 , debtB = 70.\\nafter swap `tokenA` for 20 tokenB .\\n`tokenA` balance = 75 , debtA = 80 : in this case `repay` will keep revert .\\nso if the contract accumulates bad debts(in value), the `emergencyClose()` function will always revert, preventing any debt repayment.\\nAnother critical factor to consider is the time between the `pause` action and the emergency `close` action. During periods of high volatility, the `pause` action temporarily halts the contract, but the prices of the two assets may continue to decline. The emergency `close` function can only be triggered by the owner, who operates a time-lock wallet. In the time between the `pause` and `close` actions, the prices may drop significantly and this condition will met since the `swap` is needed in almost all cases.
the debt need to be repayed in the `pause` action. and in case of `resume` just re-borrow again.
`emergencyClose()` function will consistently fail to repay any debt.\\nlenders may lose all their funds
```\\n   function emergencyClose(GMXTypes.Store storage self, uint256 deadline) external {\\n        // Revert if the status is Paused.\\n        GMXChecks.beforeEmergencyCloseChecks(self);\\n\\n        // Repay all borrowed assets; 1e18 == 100% shareRatio to repay\\n        GMXTypes.RepayParams memory _rp;\\n        (_rp.repayTokenAAmt, _rp.repayTokenBAmt) = GMXManager.calcRepay(self, 1e18);\\n\\n        (bool _swapNeeded, address _tokenFrom, address _tokenTo, uint256 _tokenToAmt) =\\n            GMXManager.calcSwapForRepay(self, _rp);\\n\\n        if (_swapNeeded) {\\n            ISwap.SwapParams memory _sp;\\n\\n            _sp.tokenIn = _tokenFrom;\\n            _sp.tokenOut = _tokenTo;\\n            _sp.amountIn = IERC20(_tokenFrom).balanceOf(address(this));\\n            _sp.amountOut = _tokenToAmt;\\n            _sp.slippage = self.minSlippage;\\n            _sp.deadline = deadline;\\n\\n            GMXManager.swapTokensForExactTokens(self, _sp);\\n        }\\n        GMXManager.repay(self, _rp.repayTokenAAmt, _rp.repayTokenBAmt);\\n\\n        self.status = GMXTypes.Status.Closed;\\n\\n        emit EmergencyClose(_rp.repayTokenAAmt, _rp.repayTokenBAmt);\\n    }\\n  }\\n```\\n