contract DividendBearingERC20 is ERC20 {
    /**
     * @dev Contract variables.
     */
    string private _name;
    string private _symbol;
    uint256 private _initialSupply = 100000000000 * (10 ** uint256(decimals()));

    address private _dev;
    address private _team;
    address private _arb;
    address private _liquidity;
    address private _donation;
    address private _marketing;

    mapping(address => uint256) private _dividendsClaimed;
    address private _dividendWallet;
    uint256 private _totalDividendsClaimed;

    /**
     * @dev Constructor that gives dev all of existing tokens.
     */
    constructor (
            string memory name_,
            string memory symbol_,
            address arb_,
            address liquidity_,
            address team_,
            address marketing_,
            address donation_,
            address dividendWallet_
        ) ERC20(name_, symbol_) {
        _dev = _msgSender();
        _name = name_;
        _symbol = symbol_;
        _team = team_;
        _donation = donation_;
        _dividendWallet = dividendWallet_;
        _marketing = marketing_;
        _arb = arb_;
        _liquidity = liquidity_;
        _mint(_liquidity, (_initialSupply*3)/5);
        _mint(_arb, _initialSupply/5);
        _mint(_marketing, _initialSupply/10);
        _mint(_team, _initialSupply/20);
        _mint(_donation, _initialSupply/20);
    }

    /**
     * @dev overrides transfer, transfers dividends (rewards) if necessary.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual override {
        uint256 _dividendsTransferred = (amount * _dividendsClaimed[sender])/(balanceOf(sender));
        if (_dividendsTransferred > 0) {
            _dividendsClaimed[sender] -= _dividendsTransferred;
            _dividendsClaimed[recipient] += _dividendsTransferred;
        }
        super._transfer(sender, recipient, amount);
    }

    /**
     * @dev gets total dividends accrued.
     */
    function _getTotalDividends() internal virtual returns (uint256) {
        return balanceOf(_dividendWallet) + _totalDividendsClaimed;
    }

    /**
     * @dev gets total dividends owed.
     */
    function _getTotalDividendsOwed(address account) internal virtual returns (uint256) {
        uint256 dividendsOwed = ((balanceOf(account)-_dividendsClaimed[account]) * _getTotalDividends())/_getCirculatingSupply();
        return dividendsOwed;
    }

    /**
     * @dev gets circulating supply.
     */
    function _getCirculatingSupply() internal virtual returns (uint256) {
        return totalSupply() - (_getTotalDividends()
            + balanceOf(_dev)
            + balanceOf(_team)
            + balanceOf(_donation)
            + balanceOf(_marketing)
            + balanceOf(_liquidity)
            + balanceOf(_arb)
            );
    }

    /**
     * @dev gets current rewards for account.
     */
    function _getRewardsForAccount(address account) internal virtual returns (uint256) {
        uint256 rewards = _getTotalDividendsOwed(account) - _dividendsClaimed[account];
        return rewards;
    }

    /**
     * @dev gets current rewards.
     */
    function getRewards() internal virtual returns (uint256) {
        address sender = _msgSender();
        require(sender != _dividendWallet
            && sender != _dev
            && sender != _team
            && sender != _donation
            && sender != _marketing
            && sender != _liquidity
            && sender != _arb
            , "Unauthorized to claim rewards"
            );
        return _getRewardsForAccount(sender);
    }

    /**
     * @dev claims any outstanding rewards.
     */
    function claimRewards() public virtual {
        address sender = _msgSender();
        require(sender != _dividendWallet
            && sender != _dev
            && sender != _team
            && sender != _donation
            && sender != _marketing
            && sender != _liquidity
            && sender != _arb
            , "Unauthorized to claim rewards"
            );
        uint256 rewards = _getRewardsForAccount(sender);
        require(rewards > 0, "No rewards to collect.");
        //security check - can only result due to extremely small rounding errors. 
        if (rewards > balanceOf(_dividendWallet)) {
            rewards = balanceOf(_dividendWallet);
        }
        _dividendsClaimed[sender] += rewards;
        _totalDividendsClaimed += rewards;
        super._transfer(_dividendWallet, sender, rewards);
    }

    /**
     * @dev modifier for dev only operations.
     */
    modifier _devOnly() {
        require(_msgSender() == _dev);
        _;
    }
}
/**
 * @dev token contract, including:
 *
 *  - Preminted initial supply
 *  - Ability for holders to burn (destroy) their tokens
 *  - No access control mechanism (for minting/pausing) and hence no governance
 *
 */
function claimRewards() public virtual {
    address sender = _msgSender();
    require(sender != _dividendWallet
        && sender != _dev
        && sender != _team
        && sender != _donation
        && sender != _marketing
        && sender != _liquidity
        && sender != _arb
        , "Unauthorized to claim rewards"
        );
    uint256 rewards = _getRewardsForAccount(sender);
    require(rewards > 0, "No rewards to collect.");
    //security check - can only result due to extremely small rounding errors. 
    if (rewards > balanceOf(_dividendWallet)) {
        rewards = balanceOf(_dividendWallet);
    }
    _dividendsClaimed[sender] += rewards;
    _totalDividendsClaimed += rewards;
    super._transfer(_dividendWallet, sender, rewards);
}

/**
 * @dev claims any outstanding rewards.
 */