nest3.0从架构解析到克隆三(NestOffer之Nest_3_OfferMain)

我们在之前的文件介绍了nest的token和mapping,本节介绍的是报价机部分核心Nest_3_OfferMain。

返回总章 我们在之前的文件介绍了nest的token和mapping,本节介绍的是报价机部分核心Nest_3_OfferMain。

报价机的组成

NestOffer有三个文件: Nest_3_MiningContract,矿池存储和出矿逻辑; Nest_3_OfferMain,报价、吃单与nest分配; Nest_3_OfferPrice,价格的查询与调用。 简单说就是,Nest_3_OfferMain调用Nest_3_OfferPrice实现价格的功能,而调用Nest_3_MiningContract涉及到了基本的挖矿逻辑。 我们接下来对Nest_3_OfferMain做详细的描述

Nest_3_OfferMain的架构解析

我们先用流水账的方式给大家说一下Nest_3_OfferMain的架构。 1.基本定义与初始化 2.报价挖矿 3.生成报价单 4.吃单-支出ETH 买入ERC20 5.吃单-支出erc20 买入ETH 6.取出资产,结算挖矿产出 7.关联合约 另外顺便说一下,整个合约非常的复杂,我们将在后面重点难点部分进行继续的讲解,在这里,大家理解几个最重要的函数就行。

1.基本定义与初始化

    struct Nest_3_OfferPriceData {
        // The unique identifier is determined by the position of the offer in the array, and is converted to each other through a fixed algorithm (toindex(), toaddress())
        //唯一标识通过报价单在数组中的位置确定,通过固定的算法(toIndex(), toAddress())来互相转化
        address owner;                                  //  Offering owner
        //  报价单拥有者
        bool deviate;                                   //  Whether it deviates 
        //  是否偏离
        address tokenAddress;                           //  The erc20 contract address of the target offer token
        //  目标报价token的ERC20合约地址

        uint256 ethAmount;                              //  The ETH amount in the offer list
        //  报价单中的eth资产账本
        uint256 tokenAmount;                            //  The token amount in the offer list
        //  报价单中的token资产账本
        uint256 dealEthAmount;                          //  The remaining number of tradable ETH
        //  剩余可成交eth数量
        uint256 dealTokenAmount;                        //  The remaining number of tradable tokens
        //  剩余可成交token数量

        uint256 blockNum;                               //  The block number where the offer is located
        //  报价单所在的区块编号
        uint256 serviceCharge;                          //  The fee for mining
        //  用于挖矿的手续费

        // 通过判断ethAmount、tokenAmount、serviceCharge都为0来确定是否已经领取资产
        // Determine whether the asset has been collected by judging that ethamount, tokenamount, and servicecharge are all 0
    }

    Nest_3_OfferPriceData [] _prices;                   //  Array used to save offers
    //  用于保存报价单的数组

    mapping(address => bool) _tokenAllow;               //  List of allowed mining token
    //  可报价挖矿token
    Nest_3_VoteFactory _voteFactory;                    //  Vote contract
    //  投票合约
    Nest_3_OfferPrice _offerPrice;                      //  Price contract
    //  价格合约,这里面就用到三个函数,增加,改变,更新
    Nest_3_MiningContract _miningContract;              //  Mining contract
    //  挖矿合约
    Nest_NodeAssignment _NNcontract;                    //  NestNode contract
    //  守护者节点合约
    ERC20 _nestToken;                                   //  NestToken
    Nest_3_Abonus _abonus;                              //  Bonus pool
    //  分红池
    address _coderAddress;                              //  Developer address
    //  开发者地址
    uint256 _miningETH = 10;                            //  Offering mining fee ratio
    //  报价挖矿手续费挖矿比例
    uint256 _tranEth = 1;                               //  Taker fee ratio
    //  吃单手续费比例
    uint256 _tranAddition = 2;                          //  Additional transaction multiple
    //  交易加成
    uint256 _coderAmount = 5;                           //  Developer ratio
    //  开发者比例
    uint256 _NNAmount = 15;                             //  NestNode ratio
    //  守护者节点比例
    uint256 _leastEth = 10 ether;                       //  Minimum offer of ETH
    //  最少报价ETH
    uint256 _offerSpan = 10 ether;                      //  ETH Offering span
    //  报价 ETH 跨度
    uint256 _deviate = 10;                              //  Price deviation - 10%
    //  价格偏差 10%
    uint256 _deviationFromScale = 10;                   //  Deviation from asset scale
    //  偏离资产规模
    uint32 _blockLimit = 25;                            //  Block interval upper limit
    //  区块间隔上限
    mapping(uint256 => uint256) _offerBlockEth;         //  Block offer fee
    //  区块报价手续费
    mapping(uint256 => uint256) _offerBlockMining;      //  Block mining amount
    //  区块挖矿量用户所得

    //  log报价合约, token地址,eth数量,erc20数量,持续区块,手续费数量
    //  Log offering contract, token address, number of eth, number of erc20, number of continuous blocks, number of fees
    event OfferContractAddress(address contractAddress, address tokenAddress, uint256 ethAmount, uint256 erc20Amount, uint256 continued, uint256 serviceCharge);
    //  Log transaction, transaction initiator, transaction token address, number of transaction token, token address, number of token, traded offering contract address, traded user address
    //  log交易,交易发起人,交易token地址,交易token数量,买进token地址,买进token数量,被交易报价合约地址,被交易用户地址
    event OfferTran(address tranSender, address tranToken, uint256 tranAmount,address otherToken, uint256 otherAmount, address tradedContract, address tradedOwner);        

     /**
    * @dev Initialization method
    初始化方法
    * @param voteFactory Voting contract address
    投票合约地址
    */
    constructor (address voteFactory) public {
        Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory));
        _voteFactory = voteFactoryMap; 
        _offerPrice = Nest_3_OfferPrice(address(voteFactoryMap.checkAddress("nest.v3.offerPrice")));            
        _miningContract = Nest_3_MiningContract(address(voteFactoryMap.checkAddress("nest.v3.miningSave")));
        _abonus = Nest_3_Abonus(voteFactoryMap.checkAddress("nest.v3.abonus"));
        _nestToken = ERC20(voteFactoryMap.checkAddress("nest"));                                         
        _NNcontract = Nest_NodeAssignment(address(voteFactoryMap.checkAddress("nodeAssignment")));      
        _coderAddress = voteFactoryMap.checkAddress("nest.v3.coder");
        require(_nestToken.approve(address(_NNcontract), uint256(10000000000 ether)), "Authorization failed");
        //这个表示的是nestToken将自己的100亿授权给nodeAssignment。
        //可现在的问题是,那100亿明明是在创建者的手里,有这样的规划又如何。
    }

     /**
    * @dev Reset voting contract
    重置投票合约
    * @param voteFactory Voting contract address
    投票合约地址
    */
    function changeMapping(address voteFactory) public onlyOwner {
        Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory));
        _voteFactory = voteFactoryMap; 
        _offerPrice = Nest_3_OfferPrice(address(voteFactoryMap.checkAddress("nest.v3.offerPrice")));            
        _miningContract = Nest_3_MiningContract(address(voteFactoryMap.checkAddress("nest.v3.miningSave")));
        _abonus = Nest_3_Abonus(voteFactoryMap.checkAddress("nest.v3.abonus"));
        _nestToken = ERC20(voteFactoryMap.checkAddress("nest"));                                           
        _NNcontract = Nest_NodeAssignment(address(voteFactoryMap.checkAddress("nodeAssignment")));      
        _coderAddress = voteFactoryMap.checkAddress("nest.v3.coder");
        require(_nestToken.approve(address(_NNcontract), uint256(10000000000 ether)), "Authorization failed");
    }
    //构建失败了也没关系,重新构建。

2.报价挖矿

    /**
    * @dev Offering mining
    报价挖矿
    * @param ethAmount Offering ETH amount 
    报价 eth数量
    * @param erc20Amount Offering erc20 token amount
    报价 erc20数量
    * @param erc20Address Offering erc20 token address
    报价 erc20地址
    */
    function offer(uint256 ethAmount, uint256 erc20Amount, address erc20Address) public payable {
        require(address(msg.sender) == address(tx.origin), "It can't be a contract");
        require(_tokenAllow[erc20Address], "Token not allow");
        //看erc20Address是否在列表范围内
        //  Judge whether the price deviates
        //判断价格是否偏离
        uint256 ethMining;
        bool isDeviate = comparativePrice(ethAmount,erc20Amount,erc20Address);
        //第一次必然为0
        //获得报价比较价格
        if (isDeviate) {
            require(ethAmount >= _leastEth.mul(_deviationFromScale), "EthAmount needs to be no less than 10 times of the minimum scale");
            ethMining = _leastEth.mul(_miningETH).div(1000);
        } else {
            ethMining = ethAmount.mul(_miningETH).div(1000);
            //因此这里必然是第二个
        }
        //做一个挖矿判断

        require(msg.value >= ethAmount.add(ethMining), "msg.value needs to be equal to the quoted eth quantity plus Mining handling fee");
        uint256 subValue = msg.value.sub(ethAmount.add(ethMining));
        if (subValue > 0) {
            repayEth(address(msg.sender), subValue);
        }
        //多余的eth返回
        //  Create an offer
        //  创建报价单
        createOffer(ethAmount, erc20Amount, erc20Address, ethMining, isDeviate);
        //  Transfer in offer asset - erc20 to this contract
        // 转入报价资产erc20-交易资产到当前合约
        ERC20(erc20Address).safeTransferFrom(address(msg.sender), address(this), erc20Amount);
        //  Mining
        //挖矿开始
        uint256 miningAmount = _miningContract.oreDrawing();
        _abonus.switchToEth.value(ethMining)(address(_nestToken));
        if (miningAmount > 0) {
            uint256 coder = miningAmount.mul(_coderAmount).div(100);
            uint256 NN = miningAmount.mul(_NNAmount).div(100);
            uint256 other = miningAmount.sub(coder).sub(NN);
            _offerBlockMining[block.number] = other;
            _NNcontract.bookKeeping(NN);   
            if (coder > 0) {
                _nestToken.safeTransfer(_coderAddress, coder);  
            }
        }
        //如果挖矿出来了,则转账。
        _offerBlockEth[block.number] = _offerBlockEth[block.number].add(ethMining);
    }

3.生成报价单

    /**
    * @dev Create offer
    生成报价单
    * @param ethAmount Offering ETH amount
    报价 eth数量
    * @param erc20Amount Offering erc20 amount
    报价 erc20数量
    * @param erc20Address Offering erc20 address
    报价 erc20地址
    * @param mining Offering mining fee (0 for takers)
    报价挖矿手续费(吃单为 0)
    * @param isDeviate Whether the current price chain deviates
    当前价格链是否偏离
    */
    function createOffer(uint256 ethAmount, uint256 erc20Amount, address erc20Address, uint256 mining, bool isDeviate) private {
        // Check offer conditions
        // 检查报价条件
        require(ethAmount >= _leastEth, "Eth scale is smaller than the minimum scale");
        require(ethAmount % _offerSpan == 0, "Non compliant asset span");
        require(erc20Amount % (ethAmount.div(_offerSpan)) == 0, "Asset quantity is not divided");
        require(erc20Amount > 0);
        // Create offering contract
        // 创建报价合约
        emit OfferContractAddress(toAddress(_prices.length), address(erc20Address), ethAmount, erc20Amount,_blockLimit,mining);
        _prices.push(Nest_3_OfferPriceData(

            msg.sender,
            isDeviate,
            erc20Address,

            ethAmount,
            erc20Amount,

            ethAmount, 
            erc20Amount, 

            block.number, 
            mining

        )); 
        // Record price
        //记录价格
        _offerPrice.addPrice(ethAmount, erc20Amount, block.number.add(_blockLimit), erc20Address, address(msg.sender));
    }

4.吃单-支出ETH 买入ERC20

    /**
    * @dev Taker order - pay ETH and buy erc20
    吃单-支出ETH 买入ERC20
    * @param ethAmount The amount of ETH of this offer
    本次报价 eth数量
    * @param tokenAmount The amount of erc20 of this offer
     本次报价 erc20数量
    * @param contractAddress The target offer address
    吃单目标地址
    * @param tranEthAmount The amount of ETH of taker order
    吃单交易 eth数量
    * @param tranTokenAmount The amount of erc20 of taker order
    吃单交易 erc20数量
    * @param tranTokenAddress The erc20 address of taker order
    吃单交易 erc20地址
    */
    function sendEthBuyErc(uint256 ethAmount, uint256 tokenAmount, address contractAddress, uint256 tranEthAmount, uint256 tranTokenAmount, address tranTokenAddress) public payable {
        require(address(msg.sender) == address(tx.origin), "It can't be a contract");
        // Get the offer data structure
        // 获取报价单数据结构
        uint256 index = toIndex(contractAddress);
        Nest_3_OfferPriceData memory offerPriceData = _prices[index]; 
        //  Check the price, compare the current offer to the last effective price
        //  检测价格, 当前报价对比上一个有效价格
        bool thisDeviate = comparativePrice(ethAmount,tokenAmount,tranTokenAddress);
        bool isDeviate;
        if (offerPriceData.deviate == true) {
            isDeviate = true;
        } else {
            isDeviate = thisDeviate;
        }
        // Limit the taker order only be twice the amount of the offer to prevent large-amount attacks
         // 限制吃单报价每次只能是吃单规模的两倍,防止大额攻击
        if (offerPriceData.deviate) {
            //  The taker order deviates  x2
            //  被吃单偏离 x2
            require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
        } else {
            if (isDeviate) {
                //  If the taken offer is normal and the taker order deviates x10
                //  被吃单正常,本次偏离 x10
                require(ethAmount >= tranEthAmount.mul(_deviationFromScale), "EthAmount needs to be no less than 10 times of transaction scale");
            } else {
                //  If the taken offer is normal and the taker order is normal x2
                //  被吃单正常,本次正常 x2
                require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
            }
        }

        uint256 serviceCharge = tranEthAmount.mul(_tranEth).div(1000);
        require(msg.value == ethAmount.add(tranEthAmount).add(serviceCharge), "msg.value needs to be equal to the quotation eth quantity plus transaction eth plus transaction handling fee");
        require(tranEthAmount % _offerSpan == 0, "Transaction size does not meet asset span");

        // Check whether the conditions for taker order are satisfied
        // 检查吃单条件是否满足
        require(checkContractState(offerPriceData.blockNum) == 0, "Offer status error");
        require(offerPriceData.dealEthAmount >= tranEthAmount, "Insufficient trading eth");
        require(offerPriceData.dealTokenAmount >= tranTokenAmount, "Insufficient trading token");
        require(offerPriceData.tokenAddress == tranTokenAddress, "Wrong token address");
        require(tranTokenAmount == offerPriceData.dealTokenAmount * tranEthAmount / offerPriceData.dealEthAmount, "Wrong token amount");

        // Update the offer information
         // 更新报价单信息
        offerPriceData.ethAmount = offerPriceData.ethAmount.add(tranEthAmount);
        offerPriceData.tokenAmount = offerPriceData.tokenAmount.sub(tranTokenAmount);
        offerPriceData.dealEthAmount = offerPriceData.dealEthAmount.sub(tranEthAmount);
        offerPriceData.dealTokenAmount = offerPriceData.dealTokenAmount.sub(tranTokenAmount);
        _prices[index] = offerPriceData;
        // Create a new offer
        // 创建一个新报价
        createOffer(ethAmount, tokenAmount, tranTokenAddress, 0, isDeviate);
        // Transfer in erc20 + offer asset to this contract
        // 转入报价资产erc20-交易资产到当前合约
        if (tokenAmount > tranTokenAmount) {
            ERC20(tranTokenAddress).safeTransferFrom(address(msg.sender), address(this), tokenAmount.sub(tranTokenAmount));
        } else {
            ERC20(tranTokenAddress).safeTransfer(address(msg.sender), tranTokenAmount.sub(tokenAmount));
        }
        // Modify price
        // 修改价格
        _offerPrice.changePrice(tranEthAmount, tranTokenAmount, tranTokenAddress, offerPriceData.blockNum.add(_blockLimit));
        emit OfferTran(address(msg.sender), address(0x0), tranEthAmount, address(tranTokenAddress), tranTokenAmount, contractAddress, offerPriceData.owner);
        // Transfer fee
        // 转手续费
        if (serviceCharge > 0) {
            _abonus.switchToEth.value(serviceCharge)(address(_nestToken));
        }
    }

5.吃单-支出erc20 买入ETH

    /**
    * @dev Taker order - pay erc20 and buy ETH
    吃单-支出erc20 买入ETH
    * @param ethAmount The amount of ETH of this offer
    本次报价 eth数量
    * @param tokenAmount The amount of erc20 of this offer
    本次报价 erc20数量
    * @param contractAddress The target offer address
    吃单目标地址
    * @param tranEthAmount The amount of ETH of taker order
    吃单交易 eth数量
    * @param tranTokenAmount The amount of erc20 of taker order
    吃单交易 erc20数量
    * @param tranTokenAddress The erc20 address of taker order
    吃单交易 erc20地址
    */
    function sendErcBuyEth(uint256 ethAmount, uint256 tokenAmount, address contractAddress, uint256 tranEthAmount, uint256 tranTokenAmount, address tranTokenAddress) public payable {
        require(address(msg.sender) == address(tx.origin), "It can't be a contract");
        // Get the offer data structure
        // 获取报价单数据结构
        uint256 index = toIndex(contractAddress);
        Nest_3_OfferPriceData memory offerPriceData = _prices[index]; 
        // Check the price, compare the current offer to the last effective price
        //  检测价格, 当前报价对比上一个有效价格
        bool thisDeviate = comparativePrice(ethAmount,tokenAmount,tranTokenAddress);
        bool isDeviate;
        if (offerPriceData.deviate == true) {
            isDeviate = true;
        } else {
            isDeviate = thisDeviate;
        }
        // Limit the taker order only be twice the amount of the offer to prevent large-amount attacks
        // 限制吃单报价每次只能是吃单规模的两倍,防止大额攻击
        if (offerPriceData.deviate) {
            //  The taker order deviates  x2
            //  被吃单偏离 x2
            require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
        } else {
            if (isDeviate) {
                //  If the taken offer is normal and the taker order deviates x10
                //  被吃单正常,本次偏离 x10
                require(ethAmount >= tranEthAmount.mul(_deviationFromScale), "EthAmount needs to be no less than 10 times of transaction scale");
            } else {
                //  If the taken offer is normal and the taker order is normal x2 
                //  被吃单正常,本次正常 x2 
                require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
            }
        }
        uint256 serviceCharge = tranEthAmount.mul(_tranEth).div(1000);
        require(msg.value == ethAmount.sub(tranEthAmount).add(serviceCharge), "msg.value needs to be equal to the quoted eth quantity plus transaction handling fee");
        require(tranEthAmount % _offerSpan == 0, "Transaction size does not meet asset span");

        // Check whether the conditions for taker order are satisfied
        // 检查吃单条件是否满足
        require(checkContractState(offerPriceData.blockNum) == 0, "Offer status error");
        require(offerPriceData.dealEthAmount >= tranEthAmount, "Insufficient trading eth");
        require(offerPriceData.dealTokenAmount >= tranTokenAmount, "Insufficient trading token");
        require(offerPriceData.tokenAddress == tranTokenAddress, "Wrong token address");
        require(tranTokenAmount == offerPriceData.dealTokenAmount * tranEthAmount / offerPriceData.dealEthAmount, "Wrong token amount");

        // Update the offer information
        // 更新报价单信息
        offerPriceData.ethAmount = offerPriceData.ethAmount.sub(tranEthAmount);
        offerPriceData.tokenAmount = offerPriceData.tokenAmount.add(tranTokenAmount);
        offerPriceData.dealEthAmount = offerPriceData.dealEthAmount.sub(tranEthAmount);
        offerPriceData.dealTokenAmount = offerPriceData.dealTokenAmount.sub(tranTokenAmount);
        _prices[index] = offerPriceData;
        // Create a new offer
         // 创建一个新报价
        createOffer(ethAmount, tokenAmount, tranTokenAddress, 0, isDeviate);
        // Transfer in erc20 + offer asset to this contract
        // 转入买ETH的资产+报价资产到当前合约
        ERC20(tranTokenAddress).safeTransferFrom(address(msg.sender), address(this), tranTokenAmount.add(tokenAmount));
        // Modify price
         // 修改价格
        _offerPrice.changePrice(tranEthAmount, tranTokenAmount, tranTokenAddress, offerPriceData.blockNum.add(_blockLimit));
        emit OfferTran(address(msg.sender), address(tranTokenAddress), tranTokenAmount, address(0x0), tranEthAmount, contractAddress, offerPriceData.owner);
        // Transfer fee
        // 转手续费
        if (serviceCharge > 0) {
            _abonus.switchToEth.value(serviceCharge)(address(_nestToken));
        }
    }

6.取出资产,结算挖矿产出

    /**
    * @dev Withdraw the assets, and settle the mining
     取出资产,结算挖矿产出
    * @param contractAddress The offer address to withdraw
    取回报价单地址
    */
    function turnOut(address contractAddress) public {
        require(address(msg.sender) == address(tx.origin), "It can't be a contract");
        uint256 index = toIndex(contractAddress);
        Nest_3_OfferPriceData storage offerPriceData = _prices[index]; 
        require(checkContractState(offerPriceData.blockNum) == 1, "Offer status error");

        // Withdraw ETH
        // 取出ETH
        if (offerPriceData.ethAmount > 0) {
            uint256 payEth = offerPriceData.ethAmount;
            offerPriceData.ethAmount = 0;
            repayEth(offerPriceData.owner, payEth);
        }

        // Withdraw erc20
        // 取出ERC20
        if (offerPriceData.tokenAmount > 0) {
            uint256 payErc = offerPriceData.tokenAmount;
            offerPriceData.tokenAmount = 0;
            ERC20(address(offerPriceData.tokenAddress)).safeTransfer(offerPriceData.owner, payErc);

        }
        // Mining settlement
        // 挖矿结算
        if (offerPriceData.serviceCharge > 0) {
            uint256 myMiningAmount = offerPriceData.serviceCharge.mul(_offerBlockMining[offerPriceData.blockNum]).div(_offerBlockEth[offerPriceData.blockNum]);
            _nestToken.safeTransfer(offerPriceData.owner, myMiningAmount);
            offerPriceData.serviceCharge = 0;
        }

    }

7.关联合约

// NestNode assignment contract
/ 守护者节点存储合约
interface Nest_NodeAssignment {
    function bookKeeping(uint256 amount) external;
}

// Mining pool logic
// 矿池逻辑 
interface Nest_3_MiningContract {
    // Offering mining
     // 报价出矿
    function oreDrawing() external returns (uint256);
}

// Voting contract
// 投票合约
interface Nest_3_VoteFactory {
    // Check address
    function checkAddress(string calldata name) external view returns (address contractAddress);
    // Check whether administrator
    function checkOwners(address man) external view returns (bool);
}

// Price contract
interface Nest_3_OfferPrice {
    function addPrice(uint256 ethAmount, uint256 tokenAmount, uint256 endBlock, address tokenAddress, address offerOwner) external;
    function changePrice(uint256 ethAmount, uint256 tokenAmount, address tokenAddress, uint256 endBlock) external;
    function updateAndCheckPricePrivate(address tokenAddress) external view returns(uint256 ethAmount, uint256 erc20Amount);
}

// Bonus pool contract
// 分红池合约
interface Nest_3_Abonus {
    function switchToEth(address token) external payable;
}
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
问答区块链
问答区块链
致力于人工智能与区块链相结合下的智能设备自治