safemoon分红机制原理解析

safemoon分红机制原理解析

在社区里提问了这个问题,自己做个总结 ### 合约源码 [https://cn.etherscan.com/address/0xcd7492db29e2ab436e819b249452ee1bbdf52214#code](https://cn.etherscan.com/address/0xcd7492db29e2ab436e819b249452ee1bbdf52214#code) ### 基本原理 每一笔转账都会触发分红,但是分红不会触发转账,只是修改一个系数,即修改每个用户的占比。 在别人进行转账时,用户的rOwned不变,系数currentRate变小,实际余额变大。 我觉得需要理解的一点是:`在用户转账成功后,还未分红的时候,用户的_rOwned占比即为分红后的占比`。 ### 举例说明 假设用户所有转账即为分红 _tTotal = 100,_rTotal = 10000 _rOwned[A] = 7000,_rOwned[B] = 2000,_rOwned[C] = 1000 用户B发起转账交易1000,即1000用做被分红。 1. 常规分红计算 _rOwned[A] = 70 + 70/90*10 = 700/9 _rOwned[B] = 10 + 10/90*10 = 100/9 _rOwned[C] = 10 + 10/90*10 = 100/9 2. 占比分红 _rOwned[A] = 7000/9000*100 = 700/9 _rOwned[B] = 1000/9000*100 = 100/9 _rOwned[C] = 1000/9000*100 = 100/9 ### 余额核心代码 ``` contract SMI is Context, IERC20, Ownable { mapping (address => uint256) private _rOwned; mapping (address => uint256) private _tOwned; uint256 private constant MAX = ~uint256(0); //最大值 uint256 private constant _tTotal = 100000 * 10**6 * 10**9; // 实际总量 uint256 private _rTotal = (MAX - (MAX % _tTotal)); // 映射的总量 function balanceOf(address account) public view override returns (uint256) { if (_isExcluded[account]) return _tOwned[account]; //不参与分红的用户 return tokenFromReflection(_rOwned[account]);//参与分红的用户 } function tokenFromReflection(uint256 rAmount) public view returns(uint256) { require(rAmount <= _rTotal, "Amount must be less than total reflections"); uint256 currentRate = _getRate(); return rAmount.div(currentRate); } function _getRate() private view returns(uint256) { (uint256 rSupply, uint256 tSupply) = _getCurrentSupply(); return rSupply.div(tSupply); } function _getCurrentSupply() private 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); } } ```

在社区里提问了这个问题,自己做个总结

合约源码

https://cn.etherscan.com/address/0xcd7492db29e2ab436e819b249452ee1bbdf52214#code

基本原理

每一笔转账都会触发分红,但是分红不会触发转账,只是修改一个系数,即修改每个用户的占比。 在别人进行转账时,用户的rOwned不变,系数currentRate变小,实际余额变大。 我觉得需要理解的一点是:在用户转账成功后,还未分红的时候,用户的_rOwned占比即为分红后的占比

举例说明

假设用户所有转账即为分红 _tTotal = 100,_rTotal = 10000 _rOwned[A] = 7000,_rOwned[B] = 2000,_rOwned[C] = 1000 用户B发起转账交易1000,即1000用做被分红。

  1. 常规分红计算

    _rOwned[A] = 70 + 70/90*10 = 700/9

    _rOwned[B] = 10 + 10/90*10 = 100/9

    _rOwned[C] = 10 + 10/90*10 = 100/9

  2. 占比分红

    _rOwned[A] = 7000/9000*100 = 700/9

    _rOwned[B] = 1000/9000*100 = 100/9

    _rOwned[C] = 1000/9000*100 = 100/9

余额核心代码

contract SMI is Context, IERC20, Ownable {
    mapping (address => uint256) private _rOwned; 
    mapping (address => uint256) private _tOwned;

    uint256 private constant MAX = ~uint256(0); //最大值
    uint256 private constant _tTotal = 100000 * 10**6 * 10**9; // 实际总量
    uint256 private _rTotal = (MAX - (MAX % _tTotal)); // 映射的总量

    function balanceOf(address account) public view override returns (uint256) {
        if (_isExcluded[account]) return _tOwned[account]; //不参与分红的用户
        return tokenFromReflection(_rOwned[account]);//参与分红的用户
    }
    function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
        require(rAmount &lt;= _rTotal, "Amount must be less than total reflections");
        uint256 currentRate =  _getRate();
        return rAmount.div(currentRate);
    }
    function _getRate() private view returns(uint256) {
        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
        return rSupply.div(tSupply);
    }

    function _getCurrentSupply() private view returns(uint256, uint256) {
        uint256 rSupply = _rTotal;
        uint256 tSupply = _tTotal;      
        for (uint256 i = 0; i &lt; _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 &lt; _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
        return (rSupply, tSupply);
    }
}

  • 发表于 2021-09-06 10:31
  • 阅读 ( 392 )
  • 学分 ( 1 )
  • 分类:以太坊

评论