我们上一篇文章对NESTtoken 与 IBMapping[1]做了解析,本文则对 NEST_MiningSave,NESTAbonus 继续进行解析。
什么是 modifier
首先说一下 modifier 在 solidity 中做的是什么工作。简单说就是给继承这个 modifier 修饰的 function 加上一个特定的约束
代码语言:javascript复制 modifier isOwner() {
if (msg.sender != owner) {
throw;
}
_; // 继续执行余下的代码体(其实就是isOwner里的实际代码)
}
doSomething() isOwner {
// 将会检查调用者是不是Owner
// code
}
NEST_MiningSave 的前置条件
NEST_MiningSave.sol 是矿池合约。这个内容相对来说比较简单,看源码解析部分即可,最主要的内容是给挖矿函数调用转账用的。整个合约都在 NEST_MiningSave 当中:从 nesttoken 里面引出了 ERC20,从 ibmapping 里面引出了 IBMapping;主要内容是 NEST_MiningSave,里面首先是对前面两个合约的初始化。这里注意的是,需要在 IBMapping 里面设置一些对应的智能合约地址。所以安装本合约需要两个前置条件。1, 在 IBMapping 里面设置 nest 对应的 token 智能合约地址 2, 在 IBMapping 里面设置 miningCalculation 对应的智能合约地址。
NEST_MiningSave 流程
1.初始化合约,默认输入是 IBMapping 对应的合约地址(特别注意) 2.将 IBMapping 里面找到 nest(就是 token 合约)对应的合约地址 3.modifier onlyOwner()检测是否是超级用户,不是则不执行 4.modifier onlyMiningCalculation(),检测是否是挖矿计算器(mappingContract.checkAddress) 这里需要特别注意,orePoolLogic.sol 对应的应该就是 miningCalculation。由于本节的初始化并不需要 orePoolLogic.sol,而 orePoolLogic.sol 的初始化需要 orePoolLogic.sol,因此,我们认为,这个挖矿存储是先编译的,而 orePoolLogic.sol 是后编译的。5.changeMapping,超级用户权限才能使用。修改 IBMapping 合约地址,并重置 token 地址(这应该是用于 token 分叉的) 6.关于 turnOut
代码语言:javascript复制function turnOut(uint256 amount, address to) public onlyMiningCalculation returns(uint256) {
//先检查是否是挖矿计算器智能合约
uint256 leftNum = nestContract.balanceOf(address(this));
//获取这个合约里面还有多少币
if (leftNum >= amount) {
nestContract.transfer(to, amount);
return amount;
} else {
return 0;
//如果取的值比合约里面的少,则传输,否则返回0.
}
}
解释:首先检测是否是挖矿计算器地址。如果是是如果调用的的剩余 token 数量够,则往某地址转账(前提是已经通过了 approve 的授权) 这个函数显然是给挖矿函数调用转账用的。也是本智能合约最主要的内容。
NESTAbonus
NESTAbonus 是分红合约,包含四个合约——分红 nest 锁仓,分红池合约,平准合约,分红逻辑合约。NESTAbonus 的结构很清晰,但源码阅读起来还是很难的,我就是尽量的说。分红逻辑合约,就是 NESTAbonus 本身的初始化。这次初始化比较复杂,需要五个合约的前置。其中 tokn,mapping 在上一节已经讲完了;nestsave(分红池锁仓),abonus(分红池合约),nestleving(平准合约),这三个合约都在本文件里面。分红池锁仓,也就是分红的 nest 池子;分红池合约,也就是 eth 的分红池子;平准合约,与前一个的区别是,第一个转账金额大则失败,而后面是转账金额大则一次性去除。后者是平仓,拿出所有 eth 用的,用于紧急情况。总的功能就是存 nest;取 nest;第一次从 nestleving 取 eth 到 NESTAbonus,然后再取到用户地址(由 NESTAbonus 的 getETH 函数完成)。注意,除了 token 合约里面出现 100 亿外,这里也出现了。简单总结,这四个函数有一个很有意思的特点,就是对于 eth 怎么存进去的没有提,我感觉是挖矿的手续费直接存入,以及其他的直接存入。我在下面对几个合约进行更加详细的描述。ps1:if(msg.sender == tx.origin)如果调用者是一个账户,上面的条件永远是 True。如果是合约账户,则条件就为 False.ps2:在一个简单的调用链中,A->B->C->D,D 里面的 msg.sender 将会是 C,而 tx.origin 将一直是 A。
NESTSave——分红池锁仓合约
说明:将 nest 进行存储的合约。
代码语言:javascript复制contract NESTSave {
using SafeMath for uint256;
mapping (address => uint256) baseMapping; // General ledger
IBNEST nestContract; // Nest contract
IBMapping mappingContract; // Mapping contract
/**
* @dev Initialization method
* @param map Mapping contract address
*/
constructor(address map) public {
mappingContract = IBMapping(map);
//一个IBMapping的合约地址导入
nestContract = IBNEST(address(mappingContract.checkAddress("nest")));
//一个token合约的导入
}
/**
* @dev Change mapping contract
* @param map Mapping contract address
改变映射地址
*/
function changeMapping(address map) public onlyOwner{
mappingContract = IBMapping(map);
nestContract = IBNEST(address(mappingContract.checkAddress("nest")));
}
/**
* @dev Take out nest
* @param num Quantity taken out
转出
*/
function takeOut(uint256 num) public onlyContract {
require(isContract(address(tx.origin)) == false);
require(num <= baseMapping[tx.origin]);
baseMapping[address(tx.origin)] = baseMapping[address(tx.origin)].sub(num);
nestContract.transfer(address(tx.origin), num);
}
/**
* @dev Deposit in nest
* @param num Deposit quantity
转入
*/
function depositIn(uint256 num) public onlyContract {
require(isContract(address(tx.origin)) == false);
require(nestContract.balanceOf(address(tx.origin)) >= num);
require(nestContract.allowance(address(tx.origin), address(this)) >= num);
require(nestContract.transferFrom(address(tx.origin),address(this),num));
baseMapping[address(tx.origin)] = baseMapping[address(tx.origin)].add(num);
}
/**
* @dev Take out all
转入者自行转出
*/
function takeOutPrivate() public {
require(isContract(address(msg.sender)) == false);
require(baseMapping[msg.sender] > 0);
nestContract.transfer(address(msg.sender), baseMapping[msg.sender]);
baseMapping[address(msg.sender)] = 0;
}
//查询某个地址在池子里有多少nest
function checkAmount(address sender) public view returns(uint256) {
return baseMapping[address(sender)];
}
modifier onlyOwner(){
require(mappingContract.checkOwners(msg.sender) == true);
_;
}
modifier onlyContract(){
require(mappingContract.checkAddress("nestAbonus") == msg.sender);
_;
}
function isContract(address addr) public view returns (bool) {
uint size;
assembly { size := extcodesize(addr) }
return size > 0;
}
}
Abonus——分红池合约
分红池合约,说白了就是分红。
代码语言:javascript复制contract Abonus {
using address_make_payable for address;
IBMapping mappingContract; // Mapping contract
/**
* @dev Initialization method
* @param map Mapping contract address
*/
constructor(address map) public {
mappingContract = IBMapping(map);
}
/**
* @dev Change mapping contract
* @param map Mapping contract address
很重要的一个函数,就是更改mapping的地址
*/
function changeMapping(address map) public onlyOwner{
mappingContract = IBMapping(map);
}
/**
* @dev Draw ETH
* @param num Draw amount
* @param target Transfer target
提以太坊,特别注意,只有nestAbonus才能提币
*/
function getETH(uint256 num, address target) public onlyContract {
require(num <= getETHNum());
address payable addr = target.make_payable();
//返回一个可支付地址赋值给addr
addr.transfer(num);
//发送num到addr。
}
//获悉本地址在这个池子里面有多少eth
function getETHNum() public view returns (uint256) {
return address(this).balance;
}
modifier onlyContract(){
require(mappingContract.checkAddress("nestAbonus") == msg.sender);
_;
}
modifier onlyOwner(){
require(mappingContract.checkOwners(msg.sender) == true);
_;
}
function () external payable {
}
}
NESTLeveling——平准合约
代码语言:javascript复制contract NESTLeveling {
using address_make_payable for address;
IBMapping mappingContract; // Mapping contract
/**
* @dev Initialization method
* @param map Mapping contract address
*/
constructor (address map) public {
mappingContract = IBMapping(map);
}
/**
* @dev Change mapping contract
* @param map Mapping contract address
*/
function changeMapping(address map) public onlyOwner {
mappingContract = IBMapping(map);
}
/**
* @dev Transfer ETH
* @param amount Transfer quantity
* @param target Transfer target
给某个地址转账eth,发送者必须是nestAbonus才行。
*/
function tranEth(uint256 amount, address target) public {
require(address(msg.sender) == address(mappingContract.checkAddress("nestAbonus")));
uint256 tranAmount = amount;
if (amount > address(this).balance) {
tranAmount = address(this).balance;
}
address payable addr = target.make_payable();
addr.transfer(tranAmount);
}
//这个this说的是NESTLeveling对应的自身地址,而eth就是存储在这里的。
function () external payable {
}
modifier onlyOwner(){
require(mappingContract.checkOwners(msg.sender) == true);
_;
}
}
NESTAbonus——分行逻辑合约
代码语言:javascript复制contract NESTAbonus {
using address_make_payable for address;
using SafeMath for uint256;
IBNEST nestContract;
IBMapping mappingContract;
NESTSave baseMapping;
Abonus abonusContract;
NESTLeveling nestLeveling;
uint256 timeLimit = 168 hours; // Dividend period
//分红时间段
uint256 nextTime = 1587700800; // Next dividend time
//下一次分红时间
uint256 getAbonusTimeLimit = 60 hours; // Trigger calculation settlement time
//获取奖金的时间限制
uint256 ethNum = 0; // ETH amount
//eth的数量
uint256 nestAllValue = 0; // Nest circulation
//nest的价值
uint256 times = 0; // Dividend book
//分红时间
uint256 expectedIncrement = 3; // Expected dividend increment proportion
//预期股利增加比例
uint256 expectedMinimum = 100 ether; // Expected minimum dividend
//预期最小分红
uint256 levelingProportion = 10; // Proportion of dividends deducted
//股息扣除比例
mapping(uint256 => mapping(address => bool)) getMapping; // Dividend collection record
//股息搜集记录
/**
* @dev Initialization method
* @param map Mapping contract address
*/
constructor (address map) public {
mappingContract = IBMapping(map);
nestContract = IBNEST(address(mappingContract.checkAddress("nest")));
baseMapping = NESTSave(address(mappingContract.checkAddress("nestSave")));
address payable addr = address(mappingContract.checkAddress("abonus")).make_payable();
abonusContract = Abonus(addr);
address payable levelingAddr = address(mappingContract.checkAddress("nestLeveling")).make_payable();
nestLeveling = NESTLeveling(levelingAddr);
}
/**
* @dev Change mapping contract
* @param map Mapping contract address
修改mapping及其下面的合约,算上mapping,一共更改5个合约,其中nest是token,剩下三个都是本合约里面的结构体。
*/
function changeMapping(address map) public onlyOwner {
mappingContract = IBMapping(map);
nestContract = IBNEST(address(mappingContract.checkAddress("nest")));
baseMapping = NESTSave(address(mappingContract.checkAddress("nestSave")));
address payable addr = address(mappingContract.checkAddress("abonus")).make_payable();
abonusContract = Abonus(addr);
address payable levelingAddr = address(mappingContract.checkAddress("nestLeveling")).make_payable();
nestLeveling = NESTLeveling(levelingAddr);
}
/**
* @dev Deposit in nest
存入
* @param amount Deposit quantity
*/
function depositIn(uint256 amount) public {
require(address(tx.origin) == address(msg.sender));
//如果调用者是一个账户,上面的条件永远是True。如果是合约账户,则条件就为False.
uint256 nowTime = now;
if (nowTime < nextTime) {
require(!(nowTime >= nextTime.sub(timeLimit) && nowTime <= nextTime.sub(timeLimit).add(getAbonusTimeLimit)));
} else {
require(!(nowTime >= nextTime && nowTime <= nextTime.add(getAbonusTimeLimit)));
uint256 time = (nowTime.sub(nextTime)).div(timeLimit);
uint256 startTime = nextTime.add((time).mul(timeLimit));
uint256 endTime = startTime.add(getAbonusTimeLimit);
require(!(nowTime >= startTime && nowTime <= endTime));
}
baseMapping.depositIn(amount);
//经过了一系列的时间判断后,调用NESTSave转入的命令(通过NESTAbonus身份),然后用用户的身份运行
//在一个简单的调用链中,A->B->C->D,D里面的msg.sender将会是C,而tx.origin将一直是A。
}
/**
* @dev Take out nest
取出nest
* @param amount Quantity taken out
*/
function takeOut(uint256 amount) public {
require(address(tx.origin) == address(msg.sender));
require(amount != 0);
require(amount <= baseMapping.checkAmount(address(msg.sender)));
baseMapping.takeOut(amount);
}
/**
* @dev Receive dividend
发币减值
*/
function getETH() public {
require(address(tx.origin) == address(msg.sender));
reloadTimeAndMapping ();
//时间校验,并提出来eth到abonusContract
uint256 nowTime = now;
require(nowTime >= nextTime.sub(timeLimit) && nowTime <= nextTime.sub(timeLimit).add(getAbonusTimeLimit));
require(getMapping[times.sub(1)][address(msg.sender)] != true);
uint256 nestAmount = baseMapping.checkAmount(address(msg.sender));
require(nestAmount > 0);
require(nestAllValue > 0);
uint256 selfEth = nestAmount.mul(ethNum).div(nestAllValue);
require(selfEth > 0);
getMapping[times.sub(1)][address(msg.sender)] = true;
abonusContract.getETH(selfEth, address(msg.sender));
//然后将上面转到abonusContract通过Abonus合约里面的getETH发送到申请分红人的地址里面。
//之所以分两步,是因为这样最安全。
}
//转币,是一个私有函数,用于往分红池转账
function levelingResult() private {
abonusContract.getETH(abonusContract.getETHNum().mul(levelingProportion).div(100), address(nestLeveling));
uint256 miningAmount = allValue().div(100000000 ether);
uint256 minimumAbonus = expectedMinimum;
for (uint256 i = 0; i < miningAmount; i ) {
minimumAbonus = minimumAbonus.add(minimumAbonus.mul(expectedIncrement).div(100));
}
uint256 nowEth = abonusContract.getETHNum();
if (nowEth < minimumAbonus) {
nestLeveling.tranEth(minimumAbonus.sub(nowEth), address(abonusContract));
//这个表示的是从nestLeveling里面转eth币出来,到abonusContract合约地址里面
}
}
//证据分红池内容,具体怎么样没看懂。
function reloadTimeAndMapping() private {
uint256 nowTime = now;
if (nowTime >= nextTime) {
levelingResult();
uint256 time = (nowTime.sub(nextTime)).div(timeLimit);
uint256 startTime = nextTime.add((time).mul(timeLimit));
uint256 endTime = startTime.add(getAbonusTimeLimit);
if (nowTime >= startTime && nowTime <= endTime) {
nextTime = getNextTime();
times = times.add(1);
ethNum = abonusContract.getETHNum();
nestAllValue = allValue();
}
}
}
//获取池子信息
function getInfo() public view returns (uint256 _nextTime, uint256 _getAbonusTime, uint256 _ethNum, uint256 _nestValue, uint256 _myJoinNest, uint256 _getEth, uint256 _allowNum, uint256 _leftNum, bool allowAbonus) {
}
放在后面的话
这方面内容一直很零散,大概写了半年多,都快忘的差不多了。我会在后面慢慢的修改和补充,让看起来更加的完整。我们在下一节将对剩下的几个合约做介绍。
参考资料
[1]
NESTtoken与IBMapping: https://learnblockchain.cn/article/2054