# Peapods Update Security Review // 09-03-2024 ### Scope https://github.com/peapodsfinance/contracts/pull/34/files ### Commit hash and branch [677606deaafbb8651f26473c88994c131560e413](https://github.com/peapodsfinance/contracts/pull/34/commits/677606deaafbb8651f26473c88994c131560e413) ## [M-1] If the pod has transfer tax then calling `manualProcessFee` is impossible ### Summary `manualProcessFee` function would not work if the pod has transfer tax ### Vulnerability Details When `manualProcessFee` called by anyone it calls the internal `_transfer` function ```solidity= function manualProcessFee(uint256 _slip) external { _transfer(address(this), address(this), 0); address _rewards = StakingPoolToken(lpStakingPool).poolRewards(); ITokenRewards(_rewards).depositFromPairedLpToken( 0, _slip > 50 ? 50 : _slip // 5% max ); } ``` Since the `_amount` passed is 0 the `_fee` will be "0". However, if the `_fee` is "0" the if logic will set it to "1". Hence, the last transfer will fail because `_fee` (1) > `_amount` (0) ```solidity= function _transfer( address _from, address _to, uint256 _amount ) internal virtual override { . . uint256 _fee; if (_swapping == 0 && _swapAndFeeOn == 1) { . . if (config.hasTransferTax && !_buy && !_sell) { _fee = _amount / 10000; // 0.01% -> _fee = _fee == 0 ? 1 : _fee; super._transfer(_from, address(this), _fee); } } . // dev: _amount = 0, _fee = 1 ===== underflow -> super._transfer(_from, _to, _amount - _fee); } ``` ### Links to code https://github.com/peapodsfinance/contracts/blob/7caaf1d848def38f4060d934bdf70edd5b56c52f/contracts/DecentralizedIndex.sol#L317-L324 https://github.com/peapodsfinance/contracts/blob/7caaf1d848def38f4060d934bdf70edd5b56c52f/contracts/DecentralizedIndex.sol#L161-L169 ### Impact Mislogic ### Recommendation `_fee = _fee == 0 ? 1 : _fee;` this logic inside the `_transfer` function can be removed. If the fee to be taken is too less, then maybe it is considerable to not take the fee at all. - [ ] Fixed - [ ] Will not fix ## [M-2] `setPartner` can be used to harm the pod ### Summary Partner can set the such new partner address that would harm the pod ### Vulnerability Details Partner can set a new partner address by calling this function: ```solidity= function setPartner(address _partner) external onlyPartner { config.partner = _partner; } ``` However, if the partner sets this to say an address that is blacklisted, then the entire pod transactions would fail Potentially setting it to V2_ROUTER, address(this) and V2_POOL would also make things complicated. ### Links to code https://github.com/peapodsfinance/contracts/blob/7caaf1d848def38f4060d934bdf70edd5b56c52f/contracts/DecentralizedIndex.sol#L434-L436 ### Impact Partner can harm the pod ### Recommendation Don't let partner to set new partner address to addresses that would harm the pod. Few addresses I think should be restricted for partner to transfer the partner address: **1- blacklist addresses** **2- V2_POOL** **3- address(this)** - [ ] Fixed - [ ] Will not fix ## [M-3] If the pods underlying token/s is an another pod with transfer tax, then bonds would not work ### Summary If the pods underlying token has an another pTKN with transfer tax, the transfer validation would fail hence the core logic would not work. ### Vulnerability Details When users bond this is the part where the transfer from the user to pod happens: ```solidity= function bond( address _token, uint256 _amount, uint256 _amountMintMin ) external override lock noSwapOrFee { . . . for (uint256 _i; _i < indexTokens.length; _i++) { uint256 _transferAmt = _firstIn ? getInitialAmount(_token, _amount, indexTokens[_i].token) : (IERC20(indexTokens[_i].token).balanceOf(address(this)) * _tokenAmtSupplyRatioX96) / FixedPoint96.Q96; -> _transferFromAndValidate( IERC20(indexTokens[_i].token), _msgSender(), _transferAmt ); } . } ``` Say that the `_transferAmt` calculated as "10" and the underlying token is an another pTKN that has transfer tax of 10% (for simplicity let's say 10%). `_transferFromAndValidate` will fail because when the "10" tokens are transferred from the user to the destination pod, since there is a 10% transfer tax, the "1" of those tokens will be sent to the pTKN that is being transfered. Hence, only 9 tokens will be received by the destination pod. The require statement inside will revert as we can observe in below code snippet: ```solidity= function _transferFromAndValidate( IERC20 _token, address _sender, uint256 _amount // dev: 10 ) internal { // dev: balance before = 0 uint256 _balanceBefore = _token.balanceOf(address(this)); // dev: 1 sent to the pod, so only 9 actually transferred _token.safeTransferFrom(_sender, address(this), _amount); // dev: 9 >= 0 + 10 ? REVERT -> require( _token.balanceOf(address(this)) >= _balanceBefore + _amount, 'TFRVAL' ); } ``` ### Links to code https://github.com/peapodsfinance/contracts/blob/7caaf1d848def38f4060d934bdf70edd5b56c52f/contracts/WeightedIndex.sol#L119-L163 https://github.com/peapodsfinance/contracts/blob/7caaf1d848def38f4060d934bdf70edd5b56c52f/contracts/DecentralizedIndex.sol#L249-L260 ### Impact Mislogic ### Recommendation I guess you can not use the `_transferFromAndValidate`. I don't see that it brings any additional security, and also debond not uses it but only bond. So my suggestion would be to remove `_transferFromAndValidate` completely from contracts code and use the safeTransfer - [ ] Fixed - [ ] Will not fix ### Low Severity Issues and Best Practices * Modify this function to support new reward tokens ```solidity= function manualProcessFee(uint256 _slip) external { _transfer(address(this), address(this), 0); address _rewards = StakingPoolToken(lpStakingPool).poolRewards(); ITokenRewards(_rewards).depositFromPairedLpToken( 0, _slip > 50 ? 50 : _slip // 5% max ); } ``` - [ ] Fixed - [ ] Will not fix