HIGH severity: PTRP - Potential Transfer Revert Propagation. The contract sends funds to a _marketingWalletAddress as part of the transfer flow, which may revert from incoming payment.

Vulnerable code:
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;



import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

import "../interfaces/IUniswapV2Factory.sol";

import "../interfaces/IUniswapV2Router02.sol";

import "../interfaces/IUniswapV2Pair.sol";

import "../libs/SafeMathInt.sol";

import "../libs/SafeMathUint.sol";

import "../libs/IterableMapping.sol";



interface DividendPayingTokenInterface {

    /// @notice View the amount of dividend in wei that an address can withdraw.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` can withdraw.

    function dividendOf(address _owner) external view returns (uint256);



    /// @notice Withdraws the ether distributed to the sender.

    /// @dev SHOULD transfer `dividendOf(msg.sender)` wei to `msg.sender`, and `dividendOf(msg.sender)` SHOULD be 0 after the transfer.

    ///  MUST emit a `DividendWithdrawn` event if the amount of ether transferred is greater than 0.

    function withdrawDividend() external;



    /// @dev This event MUST emit when ether is distributed to token holders.

    /// @param from The address which sends ether to this contract.

    /// @param weiAmount The amount of distributed ether in wei.

    event DividendsDistributed(address indexed from, uint256 weiAmount);



    /// @dev This event MUST emit when an address withdraws their dividend.

    /// @param to The address which withdraws ether from this contract.

    /// @param weiAmount The amount of withdrawn ether in wei.

    event DividendWithdrawn(address indexed to, uint256 weiAmount);

}



interface DividendPayingTokenOptionalInterface {

    /// @notice View the amount of dividend in wei that an address can withdraw.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` can withdraw.

    function withdrawableDividendOf(address _owner)

        external

        view

        returns (uint256);



    /// @notice View the amount of dividend in wei that an address has withdrawn.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` has withdrawn.

    function withdrawnDividendOf(address _owner)

        external

        view

        returns (uint256);



    /// @notice View the amount of dividend in wei that an address has earned in total.

    /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` has earned in total.

    function accumulativeDividendOf(address _owner)

        external

        view

        returns (uint256);

}



contract DividendPayingToken is

    ERC20Upgradeable,

    OwnableUpgradeable,

    DividendPayingTokenInterface,

    DividendPayingTokenOptionalInterface

{

    using SafeMath for uint256;

    using SafeMathUint for uint256;

    using SafeMathInt for int256;



    address public rewardToken;



    // With `magnitude`, we can properly distribute dividends even if the amount of received ether is small.

    // For more discussion about choosing the value of `magnitude`,

    //  see https://github.com/ethereum/EIPs/issues/1726#issuecomment-472352728

    uint256 internal constant magnitude = 2**128;



    uint256 internal magnifiedDividendPerShare;



    // About dividendCorrection:

    // If the token balance of a `_user` is never changed, the dividend of `_user` can be computed with:

    //   `dividendOf(_user) = dividendPerShare * balanceOf(_user)`.

    // When `balanceOf(_user)` is changed (via minting/burning/transferring tokens),

    //   `dividendOf(_user)` should not be changed,

    //   but the computed value of `dividendPerShare * balanceOf(_user)` is changed.

    // To keep the `dividendOf(_user)` unchanged, we add a correction term:

    //   `dividendOf(_user) = dividendPerShare * balanceOf(_user) + dividendCorrectionOf(_user)`,

    //   where `dividendCorrectionOf(_user)` is updated whenever `balanceOf(_user)` is changed:

    //   `dividendCorrectionOf(_user) = dividendPerShare * (old balanceOf(_user)) - (new balanceOf(_user))`.

    // So now `dividendOf(_user)` returns the same value before and after `balanceOf(_user)` is changed.

    mapping(address => int256) internal magnifiedDividendCorrections;

    mapping(address => uint256) internal withdrawnDividends;



    uint256 public totalDividendsDistributed;



    function __DividendPayingToken_init(

        address _rewardToken,

        string memory _name,

        string memory _symbol

    ) internal onlyInitializing {

        __Ownable_init();

        __ERC20_init(_name, _symbol);

        rewardToken = _rewardToken;

    }



    function distributeCAKEDividends(uint256 amount) public onlyOwner {

        require(totalSupply() > 0);



        if (amount > 0) {

            magnifiedDividendPerShare = magnifiedDividendPerShare.add(

                (amount).mul(magnitude) / totalSupply()

            );

            emit DividendsDistributed(msg.sender, amount);



            totalDividendsDistributed = totalDividendsDistributed.add(amount);

        }

    }



    /// @notice Withdraws the ether distributed to the sender.

    /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.

    function withdrawDividend() public virtual override {

        _withdrawDividendOfUser(payable(msg.sender));

    }



    /// @notice Withdraws the ether distributed to the sender.

    /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.

    function _withdrawDividendOfUser(address payable user)

        internal

        returns (uint256)

    {

        uint256 _withdrawableDividend = withdrawableDividendOf(user);

        if (_withdrawableDividend > 0) {

            withdrawnDividends[user] = withdrawnDividends[user].add(

                _withdrawableDividend

            );

            emit DividendWithdrawn(user, _withdrawableDividend);

            bool success = IERC20(rewardToken).transfer(

                user,

                _withdrawableDividend

            );



            if (!success) {

                withdrawnDividends[user] = withdrawnDividends[user].sub(

                    _withdrawableDividend

                );

                return 0;

            }



            return _withdrawableDividend;

        }



        return 0;

    }



    /// @notice View the amount of dividend in wei that an address can withdraw.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` can withdraw.

    function dividendOf(address _owner) public view override returns (uint256) {

        return withdrawableDividendOf(_owner);

    }



    /// @notice View the amount of dividend in wei that an address can withdraw.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` can withdraw.

    function withdrawableDividendOf(address _owner)

        public

        view

        override

        returns (uint256)

    {

        return accumulativeDividendOf(_owner).sub(withdrawnDividends[_owner]);

    }



    /// @notice View the amount of dividend in wei that an address has withdrawn.

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` has withdrawn.

    function withdrawnDividendOf(address _owner)

        public

        view

        override

        returns (uint256)

    {

        return withdrawnDividends[_owner];

    }



    /// @notice View the amount of dividend in wei that an address has earned in total.

    /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)

    /// = (magnifiedDividendPerShare * balanceOf(_owner) + magnifiedDividendCorrections[_owner]) / magnitude

    /// @param _owner The address of a token holder.

    /// @return The amount of dividend in wei that `_owner` has earned in total.

    function accumulativeDividendOf(address _owner)

        public

        view

        override

        returns (uint256)

    {

        return

            magnifiedDividendPerShare

                .mul(balanceOf(_owner))

                .toInt256Safe()

                .add(magnifiedDividendCorrections[_owner])

                .toUint256Safe() / magnitude;

    }



    /// @dev Internal function that transfer tokens from one address to another.

    /// Update magnifiedDividendCorrections to keep dividends unchanged.

    /// @param from The address to transfer from.

    /// @param to The address to transfer to.

    /// @param value The amount to be transferred.

    function _transfer(

        address from,

        address to,

        uint256 value

    ) internal virtual override {

        require(false);



        int256 _magCorrection = magnifiedDividendPerShare

            .mul(value)

            .toInt256Safe();

        magnifiedDividendCorrections[from] = magnifiedDividendCorrections[from]

            .add(_magCorrection);

        magnifiedDividendCorrections[to] = magnifiedDividendCorrections[to].sub(

            _magCorrection

        );

    }



    /// @dev Internal function that mints tokens to an account.

    /// Update magnifiedDividendCorrections to keep dividends unchanged.

    /// @param account The account that will receive the created tokens.

    /// @param value The amount that will be created.

    function _mint(address account, uint256 value) internal override {

        super._mint(account, value);



        magnifiedDividendCorrections[account] = magnifiedDividendCorrections[

            account

        ].sub((magnifiedDividendPerShare.mul(value)).toInt256Safe());

    }



    /// @dev Internal function that burns an amount of the token of a given account.

    /// Update magnifiedDividendCorrections to keep dividends unchanged.

    /// @param account The account whose tokens will be burnt.

    /// @param value The amount that will be burnt.

    function _burn(address account, uint256 value) internal override {

        super._burn(account, value);



        magnifiedDividendCorrections[account] = magnifiedDividendCorrections[

            account

        ].add((magnifiedDividendPerShare.mul(value)).toInt256Safe());

    }



    function _setBalance(address account, uint256 newBalance) internal {

        uint256 currentBalance = balanceOf(account);



        if (newBalance > currentBalance) {

            uint256 mintAmount = newBalance.sub(currentBalance);

            _mint(account, mintAmount);

        } else if (newBalance < currentBalance) {

            uint256 burnAmount = currentBalance.sub(newBalance);

            _burn(account, burnAmount);

        }

    }

}



contract DividendTokenDividendTracker is OwnableUpgradeable, DividendPayingToken {

    using SafeMath for uint256;

    using SafeMathInt for int256;

    using IterableMapping for IterableMapping.Map;



    IterableMapping.Map private tokenHoldersMap;

    uint256 public lastProcessedIndex;



    mapping(address => bool) public excludedFromDividends;



    mapping(address => uint256) public lastClaimTimes;



    uint256 public claimWait;

    uint256 public minimumTokenBalanceForDividends;



    event ExcludeFromDividends(address indexed account);

    event ClaimWaitUpdated(uint256 indexed newValue, uint256 indexed oldValue);



    event Claim(

        address indexed account,

        uint256 amount,

        bool indexed automatic

    );



    constructor() {

        

    }



    function initialize(

        address rewardToken_,

        uint256 minimumTokenBalanceForDividends_

    ) external initializer {

        DividendPayingToken.__DividendPayingToken_init(

            rewardToken_,

            "DIVIDEND_TRACKER",

            "DIVIDEND_TRACKER"

        );

        claimWait = 3600;

        minimumTokenBalanceForDividends = minimumTokenBalanceForDividends_;

    }



    function _transfer(

        address,

        address,

        uint256

    ) internal pure override {

        require(false, "Dividend_Tracker: No transfers allowed");

    }



    function withdrawDividend() public pure override {

        require(

            false,

            "Dividend_Tracker: withdrawDividend disabled. Use the 'claim' function on the main BABYTOKEN contract."

        );

    }



    function excludeFromDividends(address account) external onlyOwner {

        require(!excludedFromDividends[account]);

        excludedFromDividends[account] = true;



        _setBalance(account, 0);

        tokenHoldersMap.remove(account);



        emit ExcludeFromDividends(account);

    }



    function isExcludedFromDividends(address account)

        public

        view

        returns (bool)

    {

        return excludedFromDividends[account];

    }



    function updateClaimWait(uint256 newClaimWait) external onlyOwner {

        require(

            newClaimWait >= 3600 && newClaimWait <= 86400,

            "Dividend_Tracker: claimWait must be updated to between 1 and 24 hours"

        );

        require(

            newClaimWait != claimWait,

            "Dividend_Tracker: Cannot update claimWait to same value"

        );

        emit ClaimWaitUpdated(newClaimWait, claimWait);

        claimWait = newClaimWait;

    }



    function updateMinimumTokenBalanceForDividends(uint256 amount)

        external

        onlyOwner

    {

        minimumTokenBalanceForDividends = amount;

    }



    function getLastProcessedIndex() external view returns (uint256) {

        return lastProcessedIndex;

    }



    function getNumberOfTokenHolders() external view returns (uint256) {

        return tokenHoldersMap.keys.length;

    }



    function getAccount(address _account)

        public

        view

        returns (

            address account,

            int256 index,

            int256 iterationsUntilProcessed,

            uint256 withdrawableDividends,

            uint256 totalDividends,

            uint256 lastClaimTime,

            uint256 nextClaimTime,

            uint256 secondsUntilAutoClaimAvailable

        )

    {

        account = _account;



        index = tokenHoldersMap.getIndexOfKey(account);



        iterationsUntilProcessed = -1;



        if (index >= 0) {

            if (uint256(index) > lastProcessedIndex) {

                iterationsUntilProcessed = index.sub(

                    int256(lastProcessedIndex)

                );

            } else {

                uint256 processesUntilEndOfArray = tokenHoldersMap.keys.length >

                    lastProcessedIndex

                    ? tokenHoldersMap.keys.length.sub(lastProcessedIndex)

                    : 0;



                iterationsUntilProcessed = index.add(

                    int256(processesUntilEndOfArray)

                );

            }

        }



        withdrawableDividends = withdrawableDividendOf(account);

        totalDividends = accumulativeDividendOf(account);



        lastClaimTime = lastClaimTimes[account];



        nextClaimTime = lastClaimTime > 0 ? lastClaimTime.add(claimWait) : 0;



        secondsUntilAutoClaimAvailable = nextClaimTime > block.timestamp

            ? nextClaimTime.sub(block.timestamp)

            : 0;

    }



    function getAccountAtIndex(uint256 index)

        public

        view

        returns (

            address,

            int256,

            int256,

            uint256,

            uint256,

            uint256,

            uint256,

            uint256

        )

    {

        if (index >= tokenHoldersMap.size()) {

            return (address(0), -1, -1, 0, 0, 0, 0, 0);

        }



        address account = tokenHoldersMap.getKeyAtIndex(index);



        return getAccount(account);

    }



    function canAutoClaim(uint256 lastClaimTime) private view returns (bool) {

        if (lastClaimTime > block.timestamp) {

            return false;

        }



        return block.timestamp.sub(lastClaimTime) >= claimWait;

    }



    function setBalance(address payable account, uint256 newBalance)

        external

        onlyOwner

    {

        if (excludedFromDividends[account]) {

            return;

        }

        if (newBalance >= minimumTokenBalanceForDividends) {

            _setBalance(account, newBalance);

            tokenHoldersMap.set(account, newBalance);

        } else {

            _setBalance(account, 0);

            tokenHoldersMap.remove(account);

        }

        processAccount(account, true);

    }



    function process(uint256 gas)

        public

        returns (

            uint256,

            uint256,

            uint256

        )

    {

        uint256 numberOfTokenHolders = tokenHoldersMap.keys.length;



        if (numberOfTokenHolders == 0) {

            return (0, 0, lastProcessedIndex);

        }



        uint256 _lastProcessedIndex = lastProcessedIndex;



        uint256 gasUsed = 0;



        uint256 gasLeft = gasleft();



        uint256 iterations = 0;

        uint256 claims = 0;



        while (gasUsed < gas && iterations < numberOfTokenHolders) {

            _lastProcessedIndex++;



            if (_lastProcessedIndex >= tokenHoldersMap.keys.length) {

                _lastProcessedIndex = 0;

            }



            address account = tokenHoldersMap.keys[_lastProcessedIndex];



            if (canAutoClaim(lastClaimTimes[account])) {

                if (processAccount(payable(account), true)) {

                    claims++;

                }

            }



            iterations++;



            uint256 newGasLeft = gasleft();



            if (gasLeft > newGasLeft) {

                gasUsed = gasUsed.add(gasLeft.sub(newGasLeft));

            }



            gasLeft = newGasLeft;

        }



        lastProcessedIndex = _lastProcessedIndex;



        return (iterations, claims, lastProcessedIndex);

    }



    function processAccount(address payable account, bool automatic)

        public

        onlyOwner

        returns (bool)

    {

        uint256 amount = _withdrawDividendOfUser(account);



        if (amount > 0) {

            lastClaimTimes[account] = block.timestamp;

            emit Claim(account, amount, automatic);

            return true;

        }



        return false;

    }

}



Vulnerability type: CWE-703|CWE-755