I've built this simple contract that execute reflection
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";
contract DemoCoin is ERC20, Ownable {
using SafeMath for uint256;
using Address for address;
uint256 private constant MAX = ~uint256(0);
uint256 private _tTotal = 10000 * 10**9;
uint256 private _rTotal = (MAX - (MAX % _tTotal));
uint256 public _tFeeTotal;
uint256 private _taxFee = 10;
mapping(address => uint256) private _rOwned;
mapping(address => uint256) private _tOwned;
mapping(address => mapping(address => uint256)) private _allowances;
mapping(address => bool) private _isExcludedFromFee;
mapping(address => bool) private _isExcluded;
address[] private _excluded;
constructor() ERC20("DemoCoin", "RNG") {
_rOwned[_msgSender()] = _rTotal;
emit Transfer(address(0), _msgSender(), _tTotal);
}
//Getting account balance:
function balanceOf(address account) public view override returns (uint256) {
if (_isExcluded[account]) return _tOwned[account];
require(
_rOwned[account] <= _rTotal,
"Amount must be less than total reflections"
);
uint256 currentRate = _getRate();
return _rOwned[account].div(currentRate);
}
function _getRate() private view returns (uint256) {
(uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
return rSupply.div(tSupply);
}
function _getCurrentSupply() public view returns (uint256, uint256) {
uint256 rSupply = _rTotal;
uint256 tSupply = _tTotal;
for (uint256 i = 0; i < _excluded.length; i++) {
if (
_rOwned[_excluded[i]] > rSupply ||
_tOwned[_excluded[i]] > tSupply
) return (_rTotal, _tTotal);
rSupply = rSupply.sub(_rOwned[_excluded[i]]);
tSupply = tSupply.sub(_tOwned[_excluded[i]]);
}
if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
return (rSupply, tSupply);
}
function _transfer(
address from,
address to,
uint256 amount
) internal override {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(amount > 0, "Transfer amount must be greater than zero");
//step 1: get current rate
uint256 rate = _getRate();
//step 2: get tFee
uint256 tFee = calculateTaxFee(amount);
//step 3: get reflection Values of amount and fee, calculateTaxFee(amount) = tFee(the trueFee from the amount)
//which then need to multipy by current rate = [rFee]
uint256 rAmount = amount.mul(rate);
uint256 rFee = tFee.mul(rate);
//step 4: calculate reflection amount to transfer
uint256 rTransferAmount = rAmount.sub(rFee);
//step 5: deduct full reflection amount from sender & add amount minus fees to recipient
_rOwned[from] = _rOwned[from].sub(rAmount);
_rOwned[to] = _rOwned[to].add(rTransferAmount);
//step 5: update balances of total reflection avaliable
_rTotal = _rTotal.sub(rTransferAmount);
_reflectFee(rFee, tFee);
}
function _reflectFee(uint256 rFee, uint256 tFee) private {
_rTotal = _rTotal.sub(rFee);
_tFeeTotal = _tFeeTotal.add(tFee);
}
function calculateTaxFee(uint256 _amount) private view returns (uint256) {
return _amount.mul(_taxFee).div(10**2);
}
}
Now I'm experiencing strange behavior, if _tTotal
is set to 10000 * 10 ** 9
meaning 10000 tokens with 9 decimals
I make the first transfer to user 1 of 100
user1 = 90 // after fee deducted
then I make second transfer to user2 of 100
user2 = 90 // after fee deducted
At this point user1 should have received reflection but when I get balanceOf(user1) its still = 90
Now let's take the above example but now the _tTotal is just 10000
with 0 decimals
If I do the steps again user1 does get reflection and balanceOf(user1) = 91
can someone explain why this is happening?