Fomo3Dlong源码分析

2018-07-30  本文已影响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的分发,中间涉及到日志的处理。

根据该轮游戏当前的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);
    }
空投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
        // 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);
    }
上一篇下一篇

猜你喜欢

热点阅读