美文网首页
Fomo3Dlong源码分析

Fomo3Dlong源码分析

作者: 未来工程科技 | 来源:发表于2018-07-30 00:17 被阅读0次

    主要类结构

    fomo3dlong主要类结构

    otherFomo3D,收益分发的接口,1% to pot swap。
    PlayerBookInterface,游戏玩家信息的统一管理接口。
    F3DexternalSettingsInterface,游戏启动参数设置接口。
    JIincForwarderInterface,开发社区收益分发的接口,2% to com。
    DiviesInterface, p3d收益分发的接口。

    核心流程分析

    这里只分析两类核心流程,购买Key与领取收益。

    购买Key

    fallback function

    默认战队:2,即为蛇战队
    function() isActivated() isHuman() isWithinLimits(msg.value) public payable
    

    buyXid、buyXaddr、buyXname三个方法除了多一些推荐人与战队设置相关的处理,其他逻辑与function()逻辑一致,最终入口是buyCore

    function buyCore(uint256 _pID, uint256 _affID, uint256 _team, F3Ddatasets.EventReturns memory _eventData_)
            private
    

    还有一种是根据收益购买Key,主要包括reLoadXid、reLoadXaddr、reLoadXname三个方法,计算收益并复购Key。

    buyCore核心调用流程:

    buyCore核心调用流程

    early round eth limiter是为了早期限制,当该轮游戏参与的ETH低于100ETH时,每个人限购1ETH。

    在核心调用流程里面,主要涉及到Key的计算、游戏时间更新、空投奖励、玩家与游戏轮次信息更新以及大家最关注最核心的eth的分发,中间涉及到日志的处理。

    • Key的相关计算
    根据该轮游戏当前的Eth和购买Key的Eth计算可以购买Key的数量。
        /**
         * @dev calculates number of keys received given X eth 
         * @param _curEth current amount of eth in contract 
         * @param _newEth eth being spent
         * @return amount of ticket purchased
         */
        function keysRec(uint256 _curEth, uint256 _newEth)
            internal
            pure
            returns (uint256)
        {
            return(keys((_curEth).add(_newEth)).sub(keys(_curEth)));
        }
    
        /**
         * @dev calculates how many keys would exist with given an amount of eth
         * @param _eth eth "in contract"
         * @return number of keys that would exist
         */
        function keys(uint256 _eth) 
            internal
            pure
            returns(uint256)
        {
            return ((((((_eth).mul(1000000000000000000)).mul(312500000000000000000000000)).add(5624988281256103515625000000000000000000000000000000000000000000)).sqrt()).sub(74999921875000000000000000000000)) / (156250000);
        }
    
    • 游戏时间更新
      当购买的Key大于等于1整个的时候,更新游戏时间,更新该轮游戏最新的游戏玩家为当前玩家,更新该轮游戏最新的战队为当前玩家所属的战队。

    • 空投奖励
      当参与购买的eth大于等于0.1ETH的时候(同时空投参数airDropTracker_加1),是可以参与空投奖励游戏,根据一些参数计算seed(0-999),如果seed < airDropTracker_,即获得空头奖励(同时airDropTracker_清零),该奖励根据参与购买的ETH数量相关,分三个奖励等级。
      注意:这里可以在某些情况下增大赢取空头奖励的概率,因为一些参数并不是完全随机。

    空投seed计算所在的方法:
    function airdrop()
            private 
            view 
            returns(bool)
        {
            uint256 seed = uint256(keccak256(abi.encodePacked(
                
                (block.timestamp).add
                (block.difficulty).add
                ((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
                (block.gaslimit).add
                ((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
                (block.number)
                
            )));
            if((seed - ((seed / 1000) * 1000)) < airDropTracker_)
                return(true);
            else
                return(false);
        }
    
    空投的三个奖励等级:
    if (airdrop() == true)
     {
        // gib muni
        uint256 _prize;
        if (_eth >= 10000000000000000000)// _eth >= 10eth
        {
            // calculate prize and give it to winner
            _prize = ((airDropPot_).mul(75)) / 100;//空投奖励总量的75%
            plyr_[_pID].win = (plyr_[_pID].win).add(_prize);
                        
            // adjust airDropPot 
            airDropPot_ = (airDropPot_).sub(_prize);
                        
            // let event know a tier 3 prize was won 
            _eventData_.compressedData += 300000000000000000000000000000000;
        } else if (_eth >= 1000000000000000000 && _eth < 10000000000000000000) {//1eth <= _eth < 10eth
            // calculate prize and give it to winner
            _prize = ((airDropPot_).mul(50)) / 100;//空投奖励总量的50%
            plyr_[_pID].win = (plyr_[_pID].win).add(_prize);
                        
            // adjust airDropPot 
            airDropPot_ = (airDropPot_).sub(_prize);
                        
            // let event know a tier 2 prize was won 
            _eventData_.compressedData += 200000000000000000000000000000000;
        } else if (_eth >= 100000000000000000 && _eth < 1000000000000000000) {//0.1eth <=_eth < 1eth
            // calculate prize and give it to winner
            _prize = ((airDropPot_).mul(25)) / 100;//空投奖励总量的25%
            plyr_[_pID].win = (plyr_[_pID].win).add(_prize);
                        
            // adjust airDropPot 
             airDropPot_ = (airDropPot_).sub(_prize);
                        
             // let event know a tier 3 prize was won 
             _eventData_.compressedData += 300000000000000000000000000000000;
        }
        // set airdrop happened bool to true
        _eventData_.compressedData += 10000000000000000000000000000000;
        // let event know how much was won 
        _eventData_.compressedData += _prize * 1000000000000000000000000000000000;
                    
        // reset air drop tracker
        airDropTracker_ = 0;
    }
    
    • 玩家与游戏轮次信息更新
     // update player 
     plyrRnds_[_pID][_rID].keys = _keys.add(plyrRnds_[_pID][_rID].keys);//该轮游戏玩家所拥有的总的keys
     plyrRnds_[_pID][_rID].eth = _eth.add(plyrRnds_[_pID][_rID].eth);//该轮游戏玩家的参与的总的eth
                
     // update round
     round_[_rID].keys = _keys.add(round_[_rID].keys);//该轮游戏的总keys
     round_[_rID].eth = _eth.add(round_[_rID].eth);//该轮游戏的总eth
     rndTmEth_[_rID][_team] = _eth.add(rndTmEth_[_rID][_team]);//该轮游戏的战队的总eth
    
    • 大家最关注最核心的eth的分发
      分为distributeExternal和distributeInternal两类。
      分发规则:
            // Team allocation structures
            // 0 = whales
            // 1 = bears
            // 2 = sneks
            // 3 = bulls
    
            // Team allocation percentages
            // (F3D, P3D) + (Pot , Referrals, Community)
                // Referrals / Community rewards are mathematically designed to come from the winner's share of the pot.
            fees_[0] = F3Ddatasets.TeamFee(30,6);   //50% to pot, 10% to aff, 2% to com, 1% to pot swap, 1% to air drop pot
            fees_[1] = F3Ddatasets.TeamFee(43,0);   //43% to pot, 10% to aff, 2% to com, 1% to pot swap, 1% to air drop pot
            fees_[2] = F3Ddatasets.TeamFee(56,10);  //20% to pot, 10% to aff, 2% to com, 1% to pot swap, 1% to air drop pot
            fees_[3] = F3Ddatasets.TeamFee(43,8);   //35% to pot, 10% to aff, 2% to com, 1% to pot swap, 1% to air drop pot
    

    distributeExternal分发
    贡献2%给开发社区。

    // pay 2% out to community rewards
            uint256 _com = _eth / 50;
            uint256 _p3d;
            if (!address(Jekyll_Island_Inc).call.value(_com)(bytes4(keccak256("deposit()"))))
            {
                // This ensures Team Just cannot influence the outcome of FoMo3D with
                // bank migrations by breaking outgoing transactions.
                // Something we would never do. But that's not the point.
                // We spent 2000$ in eth re-deploying just to patch this, we hold the 
                // highest belief that everything we create should be trustless.
                // Team JUST, The name you shouldn't have to trust.
                _p3d = _com;
                _com = 0;
            }
    

    贡献1%给Fomo3D short。

    // pay 1% out to FoMo3D short
            uint256 _long = _eth / 100;
            otherF3D_.potSwap.value(_long)();
    

    贡献10%给推荐人,如果推荐人不存在,则给p3d

    // distribute share to affiliate
            uint256 _aff = _eth / 10;
            
            // decide what to do with affiliate share of fees
            // affiliate must not be self, and must have a name registered
            if (_affID != _pID && plyr_[_affID].name != '') {
                plyr_[_affID].aff = _aff.add(plyr_[_affID].aff);
                emit F3Devents.onAffiliatePayout(_affID, plyr_[_affID].addr, plyr_[_affID].name, _rID, _pID, _aff, now);
            } else {
                _p3d = _aff; //这里注意,如果前面的!address(Jekyll_Island_Inc).call.value(_com)(bytes4(keccak256("deposit()")))调用失败,则_p3 = _com,这部分eth会直接损失
            }
    

    按照战队的分成比例贡献给p3d

    // pay out p3d
            _p3d = _p3d.add((_eth.mul(fees_[_team].p3d)) / (100));
            if (_p3d > 0)
            {
                // deposit to divies contract
                Divies.deposit.value(_p3d)();
                
                // set up event data
                _eventData_.P3DAmount = _p3d.add(_eventData_.P3DAmount);
            }
    

    distributeInternal分发

        /**
         * @dev distributes eth based on fees to gen and pot
         */
        function distributeInternal(uint256 _rID, uint256 _pID, uint256 _eth, uint256 _team, uint256 _keys, F3Ddatasets.EventReturns memory _eventData_)
            private
            returns(F3Ddatasets.EventReturns)
        {
            // calculate gen share
            uint256 _gen = (_eth.mul(fees_[_team].gen)) / 100;//F3D部分
            
            // toss 1% into airdrop pot 1%空投奖励
            uint256 _air = (_eth / 100);
            airDropPot_ = airDropPot_.add(_air);
            
            // update eth balance (eth = eth - (com share + pot swap share + aff share + p3d share + airdrop pot share))
            _eth = _eth.sub(((_eth.mul(14)) / 100).add((_eth.mul(fees_[_team].p3d)) / 100));//剩余部分为F3D部分与pot奖池部分
            
            // calculate pot  奖池部分
            uint256 _pot = _eth.sub(_gen);
            
            // distribute gen share (thats what updateMasks() does) and adjust
            // balances for dust.
            uint256 _dust = updateMasks(_rID, _pID, _gen, _keys);
            if (_dust > 0)//分发该轮游戏的Key分红奖励后可能会剩余一点
                _gen = _gen.sub(_dust);
            
            // add eth to pot
            round_[_rID].pot = _pot.add(_dust).add(round_[_rID].pot);
            
            // set up event data
            _eventData_.genAmount = _gen.add(_eventData_.genAmount);
            _eventData_.potAmount = _pot;
            
            return(_eventData_);
        }
    
        /**
         * @dev updates masks for round and player when keys are bought
         * @return dust left over 
         */
        function updateMasks(uint256 _rID, uint256 _pID, uint256 _gen, uint256 _keys)
            private
            returns(uint256)
        {
            /* MASKING NOTES
                earnings masks are a tricky thing for people to wrap their minds around.
                the basic thing to understand here.  is were going to have a global
                tracker based on profit per share for each round, that increases in
                relevant proportion to the increase in share supply.
                
                the player will have an additional mask that basically says "based
                on the rounds mask, my shares, and how much i've already withdrawn,
                how much is still owed to me?"
            */
            
            // calc profit per key & round mask based on this buy:  (dust goes to pot)
            uint256 _ppt = (_gen.mul(1000000000000000000)) / (round_[_rID].keys);//F3D分红部分对每Key的增加收益
            round_[_rID].mask = _ppt.add(round_[_rID].mask);//该轮次的每Key收益增加
                
            // calculate player earning from their own buy (only based on the keys
            // they just bought).  & update player earnings mask
            uint256 _pearn = (_ppt.mul(_keys)) / (1000000000000000000);
            plyrRnds_[_pID][_rID].mask = (((round_[_rID].mask.mul(_keys)) / (1000000000000000000)).sub(_pearn)).add(plyrRnds_[_pID][_rID].mask);//用户买了之后自己参与的部分应该算做已领取的分红Key收益
            
            // calculate & return dust 如果不能整除,就有余数,这一部分收益返回归pot奖池所有
            return(_gen.sub((_ppt.mul(round_[_rID].keys)) / (1000000000000000000)));
        }
    

    领取收益

    玩家的收益主要来源包括:空投奖金、赢取的奖金、最终的战队分红、Key分红、推荐奖励、其它原因导致的eth退回。

    领取收益涉及到的主要方法

    收益的计算核心逻辑:

    function withdrawEarnings(uint256 _pID)
            private
            returns(uint256)
        {
            // update gen vault
            updateGenVault(_pID, plyr_[_pID].lrnd);
            
            // from vaults 
            uint256 _earnings = (plyr_[_pID].win).add(plyr_[_pID].gen).add(plyr_[_pID].aff);//收益为赢取的奖金 + gen vault + 推荐奖励
            if (_earnings > 0)
            {
                plyr_[_pID].win = 0;
                plyr_[_pID].gen = 0;
                plyr_[_pID].aff = 0;
            }
    
            return(_earnings);
        }
    
    function updateGenVault(uint256 _pID, uint256 _rIDlast)
            private 
        {
            uint256 _earnings = calcUnMaskedEarnings(_pID, _rIDlast);//计算Key分红收益
            if (_earnings > 0)
            {
                // put in gen vault
                plyr_[_pID].gen = _earnings.add(plyr_[_pID].gen);//Key分红收益添加到plyr_[_pID].gen,存储gen vault
                // zero out their earnings by updating mask
                plyrRnds_[_pID][_rIDlast].mask = _earnings.add(plyrRnds_[_pID][_rIDlast].mask);//更新玩家已经领取的Key分红收益
            }
        }
    
    function calcUnMaskedEarnings(uint256 _pID, uint256 _rIDlast)
            private
            view
            returns(uint256)
        {
            return(  (((round_[_rIDlast].mask).mul(plyrRnds_[_pID][_rIDlast].keys)) / (1000000000000000000)).sub(plyrRnds_[_pID][_rIDlast].mask)  );//玩家Key分红收益 = 该轮游戏的每Key收益 X 玩家该轮游戏所拥有的Key数 - 玩家该轮已经领取的Key分红收益。
        }
    

    合约风险

    function potSwap()
            external
            payable
        {
            // setup local rID
            uint256 _rID = rID_ + 1;
            
            round_[_rID].pot = round_[_rID].pot.add(msg.value);
            emit F3Devents.onPotSwapDeposit(_rID, msg.value);
        }
    

    相关文章

      网友评论

          本文标题:Fomo3Dlong源码分析

          本文链接:https://www.haomeiwen.com/subject/txwtvftx.html