nest3.0从架构解析到克隆二(从token到mapping)
nest3.0相对于2.0做了全新的开发,尽管里面的很多源码都是复用的,但结构发生了翻天覆地的变化。其中一共非常关键的内容就是mapping的变化。
IBNEST与token设计
NEST的token是在2019年就设计完毕了。其宣传的是报价挖矿得币,猛一看有点像比特币,但其实区别非常的大。NEST的token在早期就一次性都出来了,只不过是存在一个专门的地址,而每一次的报价就通过函数调用而获得一次打款。
这种灵活的方式其实非常值得借鉴,就是我们在做很多token的时候,不一定太依赖于某种新的方案。我们往往采用的是成熟的方案,与折中的行为来完成。
Nest_3_VoteFactory与mapping
预言机是一套非常复杂的智能合约,如何来进行相关合约的升级呢?在nest2.0当中有一个专门的mapping来存储这些合约的地址。简单说就是,当某一个合约升级后,将其对应的合约地址更新一下就可以了。
但在nest3.0里面却找不到这个mapping了。其实这只是层窗户纸罢了,我在这里告诉大家,只是换了个地方,改了一个名字而已。
现在合约名称叫Nest_3_VoteFactory,位于VoteContract里面的Nest_3_VoteFactory.sol文件。
Nest_3_VoteFactory的结构
主要分四部分:
第一部分是基本定义,对需要的相关变量进行定义;
第二部分是做智能合约的映射,以及各种权限的修改;
第三部分是进行投票的设定和使用;
第四部分是紧急事件处理;
Nest_3_VoteFactory的变量定义
using SafeMath for uint256; uint256 _limitTime = 7 days; // Vote duration投票持续时间 uint256 _NNLimitTime = 1 days; // NestNode raising time NestNode筹集时间 uint256 _circulationProportion = 51; // Proportion of votes to pass 通过票数比例 uint256 _NNUsedCreate = 10; // The minimum number of NNs to create a voting contract创建投票合约最小 NN 数量 uint256 _NNCreateLimit = 100; // The minimum number of NNs needed to start voting开启投票需要筹集 NN 最小数量 uint256 _emergencyTime = 0; // The emergency state start time紧急状态启动时间 uint256 _emergencyTimeLimit = 3 days; // The emergency state duration紧急状态持续时间 uint256 _emergencyNNAmount = 1000; // The number of NNs required to switch the emergency state切换紧急状态需要nn数量 ERC20 _NNToken; // NestNode Token守护者节点Token(NestNode) ERC20 _nestToken; // NestToken mapping(string => address) _contractAddress; // Voting contract mapping投票合约映射 mapping(address => bool) _modifyAuthority; // Modify permissions修改权限 mapping(address => address) _myVote; // Personal voting address我的投票 mapping(address => uint256) _emergencyPerson; // Emergency state personal voting number紧急状态个人存储量 mapping(address => bool) _contractData; // Voting contract data投票合约集合 bool _stateOfEmergency = false; // Emergency state紧急状态 address _destructionAddress; // Destroy contract address销毁合约地址
Nest_3_VoteFactory的合约映射
这个里面主要是3个内容。
第一个是修改超级用户;
第二个是增加智能合约地址与name的对应;
第三个是将相关的智能合约进行刷新。
constructor () public { _modifyAuthority[address(msg.sender)] = true; //将修改权限者(也叫超级用户)。 }
/** nest * @dev Reset contract 重置合约 */ function changeMapping() public onlyOwner { _NNToken = ERC20(checkAddress("nestNode")); _destructionAddress = address(checkAddress("nest.v3.destruction")); _nestToken = ERC20(address(checkAddress("nest"))); } //这个地方刷新nestnode,nest.v3.destruction,以及nestnode
// Check address function checkAddress(string memory name) public view returns (address contractAddress) { return _contractAddress[name]; } //查看合约地址 // Add contract mapping address function addContractAddress(string memory name, address contractAddress) public onlyOwner { _contractAddress[name] = contractAddress; } //将合约名称与地址对应 // Add administrator address function addSuperMan(address superMan) public onlyOwner { _modifyAuthority[superMan] = true; } //增加管理地址 function addSuperManPrivate(address superMan) private { _modifyAuthority[superMan] = true; } // Delete administrator address //删除管理地址 function deleteSuperMan(address superMan) public onlyOwner { _modifyAuthority[superMan] = false; } function deleteSuperManPrivate(address superMan) private { _modifyAuthority[superMan] = false; } //解除合约管理员权限 // Delete voting contract data //删除投票合约集合 function deleteContractData(address contractAddress) public onlyOwner { _contractData[contractAddress] = false; } // Check whether the administrator //查看是否管理员 function checkOwners(address man) public view returns (bool) { return _modifyAuthority[man]; } // Administrator only //仅管理员操作 modifier onlyOwner() { require(checkOwners(msg.sender), "No authority"); _; }
Nest_3_VoteFactory的投票管理
主要是三个内容:
1.创建普通投票
2.创建NN投票
3.查看投票
/** * @dev Create voting contract 创建投票合约 * @param implementContract The executable contract address for voting 投票可执行合约地址 * @param nestNodeAmount Number of NNs to pledge 质押 NN 数量 */ function createVote(address implementContract, uint256 nestNodeAmount) public { require(address(tx.origin) == address(msg.sender), "It can't be a contract"); require(nestNodeAmount >= _NNUsedCreate); Nest_3_VoteContract newContract = new Nest_3_VoteContract(implementContract, _stateOfEmergency, nestNodeAmount); //建立一个新的投票,这里主要是初始化一个Nest_3_VoteContract结构体 require(_NNToken.transferFrom(address(tx.origin), address(newContract), nestNodeAmount), "Authorization transfer failed"); //传输nn数量 _contractData[address(newContract)] = true; //新投票成立 emit ContractAddress(address(newContract)); //监听新合约地址事件 } /** * @dev Use NEST to vote 使用nest投票 * @param contractAddress Vote contract address 投票合约地址 */ function nestVote(address contractAddress) public { require(address(msg.sender) == address(tx.origin), "It can't be a contract"); require(_contractData[contractAddress], "It's not a voting contract"); //先检测地址是否合法 require(!checkVoteNow(address(msg.sender))); //如果投票未结束,或者发送者投票为0则继续 //检查投票者 Nest_3_VoteContract newContract = Nest_3_VoteContract(contractAddress); //建立一个用于投票的合约 newContract.nestVote(); //投票 _myVote[address(tx.origin)] = contractAddress; //我的投票地址为contractAddress } /** * @dev Vote using NestNode Token 使用 nestNode 投票 * @param contractAddress Vote contract address 投票合约地址 * @param NNAmount Amount of NNs to pledge 质押 NN 数量 */ function nestNodeVote(address contractAddress, uint256 NNAmount) public { require(address(msg.sender) == address(tx.origin), "It can't be a contract"); require(_contractData[contractAddress], "It's not a voting contract"); Nest_3_VoteContract newContract = Nest_3_VoteContract(contractAddress); //建立一个用于投票的合约 require(_NNToken.transferFrom(address(tx.origin), address(newContract), NNAmount), "Authorization transfer failed"); //将币传输到合约地址 newContract.nestNodeVote(NNAmount); } /** * @dev Excecute contract 执行投票 * @param contractAddress Vote contract address 投票合约地址 */ function startChange(address contractAddress) public { require(address(msg.sender) == address(tx.origin), "It can't be a contract"); require(_contractData[contractAddress], "It's not a voting contract"); Nest_3_VoteContract newContract = Nest_3_VoteContract(contractAddress); //获得这个地址的智能合约 require(_stateOfEmergency == newContract.checkStateOfEmergency()); //检测是不是状态一致 addSuperManPrivate(address(newContract)); //使得这个地址获取超级用户权力 newContract.startChange(); //运行(但目前没有这个接口文件) deleteSuperManPrivate(address(newContract)); //解除超级用户权限 }
/** * @dev Check my voting 查看我的投票 * @param user Address to check 参与投票地址 * @return address Address recently participated in the voting contract address 是否正在参与投票 */ function checkMyVote(address user) public view returns (address) { return _myVote[user]; } // Check the voting time //检查投票时间 function checkLimitTime() public view returns (uint256) { return _limitTime; }
Nest_3_VoteFactory紧急事件处理
一般出现了严重的问题,比如token出现严重bug,或者有大量的币被盗,才启用。
一般来说,需要守护者节点2/3以上的同意才行。
基本原则就是快速完成映射,然后锁死合约。
/** * @dev Switch emergency state-transfer in NestNode Token 切换紧急状态-转入NestNode * @param amount Amount of NNs to transfer 转入 NestNode 数量 */ function sendNestNodeForStateOfEmergency(uint256 amount) public { //单独调用的函数 require(_NNToken.transferFrom(address(tx.origin), address(this), amount)); //用户将自己的nn转入到这个合约地址里面 _emergencyPerson[address(tx.origin)] = _emergencyPerson[address(tx.origin)].add(amount); //_emergencyPerson数组里面的该地址的nn增加。 } /** * @dev Switch emergency state-transfer out NestNode Token 切换紧急状态-取出NestNode */ function turnOutNestNodeForStateOfEmergency() public { require(_emergencyPerson[address(tx.origin)] > 0); require(_NNToken.transfer(address(tx.origin), _emergencyPerson[address(tx.origin)])); //检测本地址是否应该有币要转移,然后把nn转移到本地址 _emergencyPerson[address(tx.origin)] = 0; uint256 nestAmount = _nestToken.balanceOf(address(this)); //检测本地址有多少nest require(_nestToken.transfer(address(_destructionAddress), nestAmount)); //一并销毁 } /** * @dev Modify emergency state 修改紧急状态 */ function changeStateOfEmergency() public { if (_stateOfEmergency) { require(now > _emergencyTime.add(_emergencyTimeLimit)); //now为当前时间戳 _stateOfEmergency = false; _emergencyTime = 0; //如果为紧急状态,看是否结束,结束则赋值为false } else { require(_emergencyPerson[address(msg.sender)] > 0); //本人是否为注册 require(_NNToken.balanceOf(address(this)) >= _emergencyNNAmount); //总量是否达标, _stateOfEmergency = true; //然后就执行 _emergencyTime = now; // } }
// Check the NestNode raising time //查看NestNode筹集时间 function checkNNLimitTime() public view returns (uint256) { return _NNLimitTime; } // Check the voting proportion to pass //查看通过投票比例 function checkCirculationProportion() public view returns (uint256) { return _circulationProportion; } // Check the minimum number of NNs to create a voting contract //查看创建投票合约最小 NN 数量 function checkNNUsedCreate() public view returns (uint256) { return _NNUsedCreate; } // Check the minimum number of NNs raised to start a vote //查看创建投票筹集 NN 最小数量 function checkNNCreateLimit() public view returns (uint256) { return _NNCreateLimit; } // Check whether in emergency state //查看是否是紧急状态 function checkStateOfEmergency() public view returns (bool) { return _stateOfEmergency; } // Check the start time of the emergency state //查看紧急状态启动时间 function checkEmergencyTime() public view returns (uint256) { return _emergencyTime; } // Check the duration of the emergency state //查看紧急状态持续时间 function checkEmergencyTimeLimit() public view returns (uint256) { return _emergencyTimeLimit; } // Check the amount of personal pledged NNs //查看个人 NN 存储量 function checkEmergencyPerson(address user) public view returns (uint256) { return _emergencyPerson[user]; } // Check the number of NNs required for the emergency // 查看紧急状态需要 NN 数量 function checkEmergencyNNAmount() public view returns (uint256) { return _emergencyNNAmount; } // Verify voting contract data //验证投票合约 function checkContractData(address contractAddress) public view returns (bool) { return _contractData[contractAddress]; } // Modify voting time //修改投票时间 function changeLimitTime(uint256 num) public onlyOwner { require(num > 0, "Parameter needs to be greater than 0"); _limitTime = num; } // Modify the NestNode raising time //修改NestNode筹集时间 function changeNNLimitTime(uint256 num) public onlyOwner { require(num > 0, "Parameter needs to be greater than 0"); _NNLimitTime = num; } // Modify the voting proportion //修改通过投票比例 function changeCirculationProportion(uint256 num) public onlyOwner { require(num > 0, "Parameter needs to be greater than 0"); _circulationProportion = num; } // Modify the minimum number of NNs to create a voting contract //修改创建投票合约最小 NN 数量 function changeNNUsedCreate(uint256 num) public onlyOwner { _NNUsedCreate = num; } // Modify the minimum number of NNs to raised to start a voting //修改创建投票筹集 NN 最小数量 function checkNNCreateLimit(uint256 num) public onlyOwner { _NNCreateLimit = num; } // Modify the emergency state duration //修改紧急状态持续时间 function changeEmergencyTimeLimit(uint256 num) public onlyOwner { require(num > 0); _emergencyTimeLimit = num.mul(1 days); } // Modify the number of NNs required for emergency state //修改紧急状态需要 NN 数量 function changeEmergencyNNAmount(uint256 num) public onlyOwner { require(num > 0); _emergencyNNAmount = num; }
简单总结
Nest_3_VoteFactory是除了报价部分外最重要的部分,他将token,公投,以及合约映射无缝连接到了一起。
我曾经一度奇怪为什么要这么做,把mapping分开单独不可以吗?
后来大概有点明白开发小组的意思了,他们的目的是将紧急处理部分与mapping合在一起,以免最糟糕的情况发生,就是mapping也被黑客掌握了。
而目前的这种情况的,随着后期将所有权限都转交给投票系统后,整个系统将变得更加的安全。