Lack of reentrancy protection in token interactions
Token operations may potentially re-enter the system. For example, `univTransfer` may perform a low-level `to.call{value}()` and, depending on the token's specification (e.g. `ERC-20` extension or `ERC-20` compliant ERC-777), `token` may implement callbacks when being called as `token.safeTransfer(to, amount)` (or token.transfer*()).\\nTherefore, it is crucial to strictly adhere to the checks-effects pattern and safeguard affected methods using a mutex.\\n```\\nfunction univTransfer(\\n IERC20 token,\\n address payable to,\\n uint256 amount\\n) internal {\\n if (amount > 0) {\\n if (isFTM(token)) {\\n (bool sent, ) = to.call{ value: amount }("");\\n require(sent, "Failed to send Ether");\\n } else {\\n token.safeTransfer(to, amount);\\n }\\n }\\n}\\n```\\n\\n`withdraw` is `nonReentrant` while `paybackAndWithdraw` is not, which appears to be inconsistent\\n```\\n/\\*\\*\\n \\* @dev Paybacks the underlying asset and withdraws collateral in a single function call from activeProvider\\n \\* @param \\_paybackAmount: amount of underlying asset to be payback, pass -1 to pay full amount\\n \\* @param \\_collateralAmount: amount of collateral to be withdrawn, pass -1 to withdraw maximum amount\\n \\*/\\nfunction paybackAndWithdraw(int256 \\_paybackAmount, int256 \\_collateralAmount) external payable {\\n updateF1155Balances();\\n \\_internalPayback(\\_paybackAmount);\\n \\_internalWithdraw(\\_collateralAmount);\\n}\\n```\\n\\n```\\n/\\*\\*\\n \\* @dev Paybacks Vault's type underlying to activeProvider - called by users\\n \\* @param \\_repayAmount: token amount of underlying to repay, or\\n \\* pass any 'negative number' to repay full ammount\\n \\* Emits a {Repay} event.\\n \\*/\\nfunction payback(int256 \\_repayAmount) public payable override {\\n updateF1155Balances();\\n \\_internalPayback(\\_repayAmount);\\n}\\n```\\n\\n`depositAndBorrow` is not `nonReentrant` while `borrow()` is which appears to be inconsistent\\n```\\n/\\*\\*\\n \\* @dev Deposits collateral and borrows underlying in a single function call from activeProvider\\n \\* @param \\_collateralAmount: amount to be deposited\\n \\* @param \\_borrowAmount: amount to be borrowed\\n \\*/\\nfunction depositAndBorrow(uint256 \\_collateralAmount, uint256 \\_borrowAmount) external payable {\\n updateF1155Balances();\\n \\_internalDeposit(\\_collateralAmount);\\n \\_internalBorrow(\\_borrowAmount);\\n}\\n```\\n\\n```\\n/\\*\\*\\n \\* @dev Borrows Vault's type underlying amount from activeProvider\\n \\* @param \\_borrowAmount: token amount of underlying to borrow\\n \\* Emits a {Borrow} event.\\n \\*/\\nfunction borrow(uint256 \\_borrowAmount) public override nonReentrant {\\n updateF1155Balances();\\n \\_internalBorrow(\\_borrowAmount);\\n}\\n```\\n\\nHere's an example call stack for `depositAndBorrow` that outlines how a reentrant `ERC20` token (e.g. ERC777) may call back into `depositAndBorrow` again, `updateBalances` twice in the beginning before tokens are even transferred and then continues to call `internalDeposit`, `internalBorrow`, `internalBorrow` without an update before the 2nd borrow. Note that both `internalDeposit` and `internalBorrow` read indexes that may now be outdated.\\n```\\ndepositAndBorrow\\n updateBalances\\n internalDeposit ->\\n ERC777(collateralAsset).safeTransferFrom() ---> calls back!\\n ---callback:beforeTokenTransfer---->\\n !! depositAndBorrow\\n updateBalances\\n internalDeposit\\n --> ERC777.safeTransferFrom()\\n <--\\n \\_deposit\\n mint\\n internalBorrow\\n mint\\n \\_borrow\\n ERC777(borrowAsset).univTransfer(msg.sender) --> might call back\\n\\n <-------------------------------\\n \\_deposit\\n mint\\n internalBorrow\\n mint\\n \\_borrow \\n --> ERC777(borrowAsset).univTransfer(msg.sender) --> might call back\\n <--\\n```\\n
Consider decorating methods that may call back to untrusted sources (i.e., native token transfers, callback token operations) as `nonReentrant` and strictly follow the checks-effects pattern for all contracts in the code-base.
```\\nfunction univTransfer(\\n IERC20 token,\\n address payable to,\\n uint256 amount\\n) internal {\\n if (amount > 0) {\\n if (isFTM(token)) {\\n (bool sent, ) = to.call{ value: amount }("");\\n require(sent, "Failed to send Ether");\\n } else {\\n token.safeTransfer(to, amount);\\n }\\n }\\n}\\n```\\n