V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
czz5242199
V2EX  ›  问与答

分红币的实现原理

  •  
  •   czz5242199 · 2021-07-22 10:40:54 +08:00 · 944 次点击
    这是一个创建于 1014 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近市场上出现了很多分红币,比如最近流行的( BabyDoge, MiniDoge 之类的),大概模式都是交易手续费的 x% 按照持有比例分给所有持币人,今天我们来解析一下背后的代码实现方式。

    第一想法肯定是计算出分红的手续费之后,按照比例给所有人加上,solidity 代码如下:

    // 分红总金额
    uint profit;
    
    // 当前总持币量
    uint totalAmounts;
    
    for (uint i = 0; i < users.length; i++) {
    // 给每个用户分红
        amounts[i] += amounts[i] / totalAmounts \* profit;
    }
    

    但这样做会有一个很大的问题:随着持币人数过多,每一笔转账消耗的计算资源会急速增长,甚至超出交易的单笔上限。

    目前分红类代币采用了一个很聪明的做法,使用了类似于金融中的通缩概念:“如果货币总量减少,每个人手上的货币不就变得更值钱的,相当于变相完成了分红“

    接下来我们来看源代码是怎么实现的

    // 存储用户的虚拟数量
    mapping(address => uint256) private _rOwned;
    // 真正的发行量(比如发行了 1w 枚币,精度为 0,_tTotal = 10000 )
    uint _tTotal;
    
    uint256 private constant MAX = ~uint256(0);
    // 最大的一个可以整除 _tTotal 的数,这个数字类似于“虚拟的货币总量”
    uint _rTotal = (MAX - (MAX % _tTotal));
    假设在合约部署时需要把 1w 枚币发给 owner,代码如下
    
    constructor() {
        _tTotal = 10000;
    
        // 初始化 rTotal
        uint256 private constant MAX = ~uint256(0);
        uint _rTotal = (MAX - (MAX % _tTotal));
    
        // 把所有的币发给 owner
        _rOwned[owner] = _rTotal;
    }
    

    那么此时怎么计算用户余额呢?我们来看 balanceOf 函数

    function balanceOf(address account) public view override returns (uint256) {
        uint256 currentRate = _rTotal / _tTotal;
        return _rOwned[account] / currentRate;
    }
    

    看起来就是先用 虚拟货币总量 / 真实货币总量 得到一个比例,然后除以这个比例即可拿到真实的余额。

    我们再看一下 最重要的 transfer 函数是怎么实现的,我们假设分币比例是 3%

    function transfer(address from, address to, uint amount) public {
        uint currentRate = _rTotal / _tTotal;
        uint rAmount = amount _ currentRate;
        // 3%的分红
        uint rProfit = amount _ currentRate _ 3 / 100;
        // 转让人扣除 100%
        _rOwned[from] = _rOwned[from] - rAmount;
        // 接收人收到 97%
        _rOwned[to] = _rOwned[to] + rAmount _ 97 / 100;
    
        // 剩下 3%扣除总的虚拟货币,这时候所有人的 banlanceOf 函数计算都会按照比例增长
        _rTotal = _rTotal - rProfit;
    }
    

    不得不说整套体系设计得挺厉害的,虽然存在一定的计算误差,但大大提高了计算效率。

    联系作者

    微信:czz5242199

    telegram: @zhuozhongcao

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2466 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 13:44 · PVG 21:44 · LAX 06:44 · JFK 09:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.