If the collateral is a fee-on-transfer token, repayment will be blocked
As we all know, some tokens will deduct fees when transferring token. In this way, the actual amount of token received by the receiver will be less than the amount sent. If the collateral is this type of token, the amount of collateral recorded in the contract will bigger than the actual amount. When the borrower repays the loan, the amount of collateral withdrawn will be insufficient, causing tx revert.\\nThe `_bidCollaterals` mapping of `CollateralManager` records the `CollateralInfo` of each bidId. This structure records the collateral information provided by the user when creating a bid for a loan. A lender can accept a loan by calling  `TellerV2.lenderAcceptBid` that will eventually transfer the user's collateral from the user address to the CollateralEscrowV1 contract corresponding to the loan. The whole process will deduct fee twice.\\n```\\n//CollateralManager.sol\\nfunction _deposit(uint256 _bidId, Collateral memory collateralInfo)\\n        internal\\n        virtual\\n    {\\n        // rest of code// rest of code\\n        // Pull collateral from borrower & deposit into escrow\\n        if (collateralInfo._collateralType == CollateralType.ERC20) {\\n            IERC20Upgradeable(collateralInfo._collateralAddress).transferFrom( //transferFrom first time\\n                borrower,\\n                address(this),\\n                collateralInfo._amount\\n            );\\n            IERC20Upgradeable(collateralInfo._collateralAddress).approve(\\n                escrowAddress,\\n                collateralInfo._amount\\n            );\\n            collateralEscrow.depositAsset(  //transferFrom second time\\n                CollateralType.ERC20,\\n                collateralInfo._collateralAddress,\\n                collateralInfo._amount,   //this value is from user's input\\n                0\\n            );\\n        }\\n        // rest of code// rest of code\\n    }\\n```\\n\\nThe amount of collateral recorded by the CollateralEscrowV1 contract is equal to the amount originally submitted by the user.\\nWhen the borrower repays the loan, `collateralManager.withdraw` will be triggered. This function internally calls `CollateralEscrowV1.withdraw`. Since the balance of the collateral in the CollateralEscrowV1 contract is less than the amount to be withdrawn, the entire transaction reverts.\\n```\\n//CollateralEscrowV1.sol\\nfunction _withdrawCollateral(\\n        Collateral memory _collateral,\\n        address _collateralAddress,\\n        uint256 _amount,\\n        address _recipient\\n    ) internal {\\n        // Withdraw ERC20\\n        if (_collateral._collateralType == CollateralType.ERC20) {\\n            IERC20Upgradeable(_collateralAddress).transfer(   //revert\\n                _recipient,\\n                _collateral._amount //_collateral.balanceOf(address(this)) < _collateral._amount\\n            );\\n        }\\n    // rest of code// rest of code\\n    }\\n```\\n
Two ways to fix this issue.\\nThe `afterBalance-beforeBalance` method should be used when recording the amount of collateral.\\n`         --- a/teller-protocol-v2/packages/contracts/contracts/escrow/CollateralEscrowV1.sol\\n         +++ b/teller-protocol-v2/packages/contracts/contracts/escrow/CollateralEscrowV1.sol\\n         @@ -165,7 +165,7 @@ contract CollateralEscrowV1 is OwnableUpgradeable, ICollateralEscrowV1 {\\n                  if (_collateral._collateralType == CollateralType.ERC20) {\\n                      IERC20Upgradeable(_collateralAddress).transfer(\\n                          _recipient,\\n         -                _collateral._amount\\n         +                IERC20Upgradeable(_collateralAddress).balanceOf(address(this))\\n                      );\\n                  }`
The borrower's collateral is stuck in the instance of CollateralEscrowV1. Non-professional users will never know that they need to manually transfer some collateral into CollateralEscrowV1 to successfully repay.\\nThis issue blocked the user's repayment, causing the loan to be liquidated.\\nThe liquidator will not succeed by calling `TellerV2.liquidateLoanFull`.
```\\n//CollateralManager.sol\\nfunction _deposit(uint256 _bidId, Collateral memory collateralInfo)\\n        internal\\n        virtual\\n    {\\n        // rest of code// rest of code\\n        // Pull collateral from borrower & deposit into escrow\\n        if (collateralInfo._collateralType == CollateralType.ERC20) {\\n            IERC20Upgradeable(collateralInfo._collateralAddress).transferFrom( //transferFrom first time\\n                borrower,\\n                address(this),\\n                collateralInfo._amount\\n            );\\n            IERC20Upgradeable(collateralInfo._collateralAddress).approve(\\n                escrowAddress,\\n                collateralInfo._amount\\n            );\\n            collateralEscrow.depositAsset(  //transferFrom second time\\n                CollateralType.ERC20,\\n                collateralInfo._collateralAddress,\\n                collateralInfo._amount,   //this value is from user's input\\n                0\\n            );\\n        }\\n        // rest of code// rest of code\\n    }\\n```\\n