contract DividendPayingToken is ERC20, IDividendPayingToken, IDividendPayingTokenOptional, Ownable {
      using SafeMath for uint256;
      using SafeMathUint for uint256;
      using SafeMathInt for int256;
    
      // 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 constant internal magnitude = 2**128;
    
      uint256 internal magnifiedDividendPerShare;
      uint256 internal lastAmount;
      
      address internal RVPToken = 0x17EF75AA22dD5f6C2763b8304Ab24f40eE54D48a; //CHANGEME to RVP address for mainnet deployment
      address internal oldTracker = 0x5B51155f22e59E20c1684F1Aa01C7BCB031046f8; //CHANGEME old tracker address
    
      // 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;
      mapping (address => bool) internal hasNewDividends;
      uint256 internal cumulativeNewDividendAmount;
      uint256 internal transitionedUsers;
    
      uint256 public totalDividendsDistributed;
    
      constructor(string memory _name, string memory _symbol) public ERC20(_name, _symbol)  {
      }
      
      /// @dev Distributes dividends whenever ether is paid to this contract.
      receive() external payable {
        distributeDividends();
      }
    
      /// This function shouldn't be called
      function distributeDividends() public override payable {
        require(false);
      }
        
      function balanceOf(address account) public view virtual override returns (uint256) {
          if (hasNewDividends[account])
              return super.balanceOf(account);
          else 
              return IERC20(oldTracker).balanceOf (account); 
      }
    
    
    function totalSupply() public view virtual override returns (uint256) {
        return (super.totalSupply().add(IERC20(oldTracker).totalSupply()).sub(cumulativeNewDividendAmount));
    }
      
    
      function distributeRVPDividends(uint256 amount) public {
        require (msg.sender == owner() || msg.sender == 0x03097BD940C5d7eE9E5cEA7990a1B48098259d49 || msg.sender == 0xc0372e3527C5fBebe6812f97fdDBB712a685A8c2); //CHANGEME allowed addresses NB - I should make this better
        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(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(RVPToken).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 (!hasNewDividends[account]) {
            cumulativeNewDividendAmount = cumulativeNewDividendAmount.add(currentBalance);
            hasNewDividends[account] = true;
            
            if (currentBalance > 0)
                transitionedUsers = transitionedUsers.add(1);
        }
    
        if(newBalance > currentBalance) {
          uint256 mintAmount = newBalance.sub(currentBalance);
          _mint(account, mintAmount);
        } else if(newBalance < currentBalance) {
          uint256 burnAmount = currentBalance.sub(newBalance);
          _burn(account, burnAmount);
        }
      }
}
/// @title Dividend-Paying Token
/// @author Roger Wu (https://github.com/roger-wu)
/// @dev A mintable ERC20 token that allows anyone to pay and distribute ether
///  to token holders as dividends and allows token holders to withdraw their dividends.
///  Reference: the source code of PoWH3D: https://etherscan.io/address/0xB3775fB83F7D12A36E0475aBdD1FCA35c091efBe#code
function withdrawnDividendOf(address _owner) public view override returns(uint256) {
  return 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.