Transaction Hash:
Block:
11703816 at Jan-22-2021 06:56:23 AM +UTC
Transaction Fee:
0.004157131076707609 ETH
$10.03
Gas Used:
56,947 Gas / 73.000001347 Gwei
Emitted Events:
148 |
Nest_NToken.Transfer( from=Nest_3_TokenSave, to=[Sender] 0x8282568fc223156c945fc549893a3bc84a1f3bf2, value=4040000000000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x03904F4B...a46c99102 | (NEST Protocol: Token Verification) | ||||
0x8282568f...84A1F3bf2 |
0.242787355141840592 Eth
Nonce: 194
|
0.238630224065132983 Eth
Nonce: 195
| 0.004157131076707609 | ||
0x99C85bb6...993Cb89E3
Miner
| (BeePool) | 347.52168538936895233 Eth | 347.525842520445659939 Eth | 0.004157131076707609 | |
0xE4EcBca3...ddb26b49d |
Execution Trace
Nest_3_TokenAbonus.takeOut( amount=4040000000000000000000, token=0xE4EcBca33c5e29d34263400912157d4ddb26b49d )
-
Nest_3_TokenSave.checkAmount( sender=0x8282568fC223156c945fC549893A3bC84A1F3bf2, token=0xE4EcBca33c5e29d34263400912157d4ddb26b49d ) => ( 4040000000000000000000 )
Nest_3_TokenSave.takeOut( num=4040000000000000000000, token=0xE4EcBca33c5e29d34263400912157d4ddb26b49d, target=0x8282568fC223156c945fC549893A3bC84A1F3bf2 )
-
Nest_3_VoteFactory.checkAddress( name=nest.v3.tokenAbonus ) => ( contractAddress=0x19E1d193A448bD13097EFC2aea867468726e67c5 )
-
Nest_NToken.transfer( to=0x8282568fC223156c945fC549893A3bC84A1F3bf2, value=4040000000000000000000 ) => ( True )
-
takeOut[Nest_3_TokenAbonus (ln:103)]
checkAmount[Nest_3_TokenAbonus (ln:105)]
checkVoteNow[Nest_3_TokenAbonus (ln:107)]
takeOut[Nest_3_TokenAbonus (ln:109)]
File 1 of 4: Nest_3_TokenAbonus
File 2 of 4: Nest_3_TokenSave
File 3 of 4: Nest_NToken
File 4 of 4: Nest_3_VoteFactory
pragma solidity 0.6.0; /** * @title Dividend logic * @dev Some operations about dividend,logic and asset separation */ contract Nest_3_TokenAbonus { using address_make_payable for address; using SafeMath for uint256; ERC20 _nestContract; Nest_3_TokenSave _tokenSave; // Lock-up contract Nest_3_Abonus _abonusContract; // ETH bonus pool Nest_3_VoteFactory _voteFactory; // Voting contract Nest_3_Leveling _nestLeveling; // Leveling contract address _destructionAddress; // Destroy contract address uint256 _timeLimit = 168 hours; // Bonus period uint256 _nextTime = 1596168000; // Next bonus time uint256 _getAbonusTimeLimit = 60 hours; // During of triggering calculation of bonus uint256 _times = 0; // Bonus ledger uint256 _expectedIncrement = 3; // Expected bonus increment ratio uint256 _expectedSpanForNest = 100000000 ether; // NEST expected bonus increment threshold uint256 _expectedSpanForNToken = 1000000 ether; // NToken expected bonus increment threshold uint256 _expectedMinimum = 100 ether; // Expected minimum bonus uint256 _savingLevelOne = 10; // Saving threshold level 1 uint256 _savingLevelTwo = 20; // Saving threshold level 2 uint256 _savingLevelTwoSub = 100 ether; // Function parameters of savings threshold level 2 uint256 _savingLevelThree = 30; // Function parameters of savings threshold level 3 uint256 _savingLevelThreeSub = 600 ether; // Function parameters of savings threshold level 3 mapping(address => uint256) _abonusMapping; // Bonus pool snapshot - token address (NEST or NToken) => number of ETH in the bonus pool mapping(address => uint256) _tokenAllValueMapping; // Number of tokens (circulation) - token address (NEST or NToken) ) => total circulation mapping(address => mapping(uint256 => uint256)) _tokenAllValueHistory; // NEST or NToken circulation snapshot - token address (NEST or NToken) => number of periods => total circulation mapping(address => mapping(uint256 => mapping(address => uint256))) _tokenSelfHistory; // Personal lockup - NEST or NToken snapshot token address (NEST or NToken) => period => user address => total circulation mapping(address => mapping(uint256 => bool)) _snapshot; // Whether snapshot - token address (NEST or NToken) => number of periods => whether to take a snapshot mapping(uint256 => mapping(address => mapping(address => bool))) _getMapping; // Receiving records - period => token address (NEST or NToken) => user address => whether received // Log token address, amount event GetTokenLog(address tokenAddress, uint256 tokenAmount); /** * @dev Initialization method * @param voteFactory Voting contract address */ constructor (address voteFactory) public { Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory)); _voteFactory = voteFactoryMap; _nestContract = ERC20(address(voteFactoryMap.checkAddress("nest"))); _tokenSave = Nest_3_TokenSave(address(voteFactoryMap.checkAddress("nest.v3.tokenSave"))); address payable addr = address(voteFactoryMap.checkAddress("nest.v3.abonus")).make_payable(); _abonusContract = Nest_3_Abonus(addr); address payable levelingAddr = address(voteFactoryMap.checkAddress("nest.v3.leveling")).make_payable(); _nestLeveling = Nest_3_Leveling(levelingAddr); _destructionAddress = address(voteFactoryMap.checkAddress("nest.v3.destruction")); } /** * @dev Modify voting contract * @param voteFactory Voting contract address */ function changeMapping(address voteFactory) public onlyOwner { Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory)); _voteFactory = voteFactoryMap; _nestContract = ERC20(address(voteFactoryMap.checkAddress("nest"))); _tokenSave = Nest_3_TokenSave(address(voteFactoryMap.checkAddress("nest.v3.tokenSave"))); address payable addr = address(voteFactoryMap.checkAddress("nest.v3.abonus")).make_payable(); _abonusContract = Nest_3_Abonus(addr); address payable levelingAddr = address(voteFactoryMap.checkAddress("nest.v3.leveling")).make_payable(); _nestLeveling = Nest_3_Leveling(levelingAddr); _destructionAddress = address(voteFactoryMap.checkAddress("nest.v3.destruction")); } /** * @dev Deposit * @param amount Deposited amount * @param token Locked token address */ function depositIn(uint256 amount, address token) public { uint256 nowTime = now; uint256 nextTime = _nextTime; uint256 timeLimit = _timeLimit; if (nowTime < nextTime) { // Bonus triggered require(!(nowTime >= nextTime.sub(timeLimit) && nowTime <= nextTime.sub(timeLimit).add(_getAbonusTimeLimit))); } else { // Bonus not triggered uint256 times = (nowTime.sub(_nextTime)).div(_timeLimit); // Calculate the time when bonus should be started uint256 startTime = _nextTime.add((times).mul(_timeLimit)); // Calculate the time when bonus should be stopped uint256 endTime = startTime.add(_getAbonusTimeLimit); require(!(nowTime >= startTime && nowTime <= endTime)); } _tokenSave.depositIn(amount, token, address(msg.sender)); } /** * @dev Withdrawing * @param amount Withdrawing amount * @param token Token address */ function takeOut(uint256 amount, address token) public { require(amount > 0, "Parameter needs to be greater than 0"); require(amount <= _tokenSave.checkAmount(address(msg.sender), token), "Insufficient storage balance"); if (token == address(_nestContract)) { require(!_voteFactory.checkVoteNow(address(tx.origin)), "Voting"); } _tokenSave.takeOut(amount, token, address(msg.sender)); } /** * @dev Receiving * @param token Receiving token address */ function getAbonus(address token) public { uint256 tokenAmount = _tokenSave.checkAmount(address(msg.sender), token); require(tokenAmount > 0, "Insufficient storage balance"); reloadTime(); reloadToken(token); uint256 nowTime = now; require(nowTime >= _nextTime.sub(_timeLimit) && nowTime <= _nextTime.sub(_timeLimit).add(_getAbonusTimeLimit), "Not time to draw"); require(!_getMapping[_times.sub(1)][token][address(msg.sender)], "Have received"); _tokenSelfHistory[token][_times.sub(1)][address(msg.sender)] = tokenAmount; require(_tokenAllValueMapping[token] > 0, "Total flux error"); uint256 selfNum = tokenAmount.mul(_abonusMapping[token]).div(_tokenAllValueMapping[token]); require(selfNum > 0, "No limit available"); _getMapping[_times.sub(1)][token][address(msg.sender)] = true; _abonusContract.getETH(selfNum, token,address(msg.sender)); emit GetTokenLog(token, selfNum); } /** * @dev Update bonus time and stage ledger */ function reloadTime() private { uint256 nowTime = now; // The current time must exceed the bonus time if (nowTime >= _nextTime) { 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); } } } /** * @dev Snapshot of the amount of tokens * @param token Receiving token address */ function reloadToken(address token) private { if (!_snapshot[token][_times.sub(1)]) { levelingResult(token); _abonusMapping[token] = _abonusContract.getETHNum(token); _tokenAllValueMapping[token] = allValue(token); _tokenAllValueHistory[token][_times.sub(1)] = allValue(token); _snapshot[token][_times.sub(1)] = true; } } /** * @dev Leveling settlement * @param token Receiving token address */ function levelingResult(address token) private { uint256 steps; if (token == address(_nestContract)) { steps = allValue(token).div(_expectedSpanForNest); } else { steps = allValue(token).div(_expectedSpanForNToken); } uint256 minimumAbonus = _expectedMinimum; for (uint256 i = 0; i < steps; i++) { minimumAbonus = minimumAbonus.add(minimumAbonus.mul(_expectedIncrement).div(100)); } uint256 thisAbonus = _abonusContract.getETHNum(token); if (thisAbonus > minimumAbonus) { uint256 levelAmount = 0; if (thisAbonus > 5000 ether) { levelAmount = thisAbonus.mul(_savingLevelThree).div(100).sub(_savingLevelThreeSub); } else if (thisAbonus > 1000 ether) { levelAmount = thisAbonus.mul(_savingLevelTwo).div(100).sub(_savingLevelTwoSub); } else { levelAmount = thisAbonus.mul(_savingLevelOne).div(100); } if (thisAbonus.sub(levelAmount) < minimumAbonus) { _abonusContract.getETH(thisAbonus.sub(minimumAbonus), token, address(this)); _nestLeveling.switchToEth.value(thisAbonus.sub(minimumAbonus))(token); } else { _abonusContract.getETH(levelAmount, token, address(this)); _nestLeveling.switchToEth.value(levelAmount)(token); } } else { uint256 ethValue = _nestLeveling.tranEth(minimumAbonus.sub(thisAbonus), token, address(this)); _abonusContract.switchToEth.value(ethValue)(token); } } // Next bonus time, current bonus deadline, ETH number, NEST number, NEST participating in bonus, bonus to receive, approved amount, balance, whether bonus can be paid function getInfo(address token) public view returns (uint256 nextTime, uint256 getAbonusTime, uint256 ethNum, uint256 tokenValue, uint256 myJoinToken, uint256 getEth, uint256 allowNum, uint256 leftNum, bool allowAbonus) { uint256 nowTime = now; if (nowTime >= _nextTime.sub(_timeLimit) && nowTime <= _nextTime.sub(_timeLimit).add(_getAbonusTimeLimit) && _times > 0 && _snapshot[token][_times.sub(1)]) { // Bonus have been triggered, and during the time of this bonus, display snapshot data allowAbonus = _getMapping[_times.sub(1)][token][address(msg.sender)]; ethNum = _abonusMapping[token]; tokenValue = _tokenAllValueMapping[token]; } else { // Display real-time data ethNum = _abonusContract.getETHNum(token); tokenValue = allValue(token); allowAbonus = _getMapping[_times][token][address(msg.sender)]; } myJoinToken = _tokenSave.checkAmount(address(msg.sender), token); if (allowAbonus == true) { getEth = 0; } else { getEth = myJoinToken.mul(ethNum).div(tokenValue); } nextTime = getNextTime(); getAbonusTime = nextTime.sub(_timeLimit).add(_getAbonusTimeLimit); allowNum = ERC20(token).allowance(address(msg.sender), address(_tokenSave)); leftNum = ERC20(token).balanceOf(address(msg.sender)); } /** * @dev View next bonus time * @return Next bonus time */ function getNextTime() public view returns (uint256) { uint256 nowTime = now; if (_nextTime > nowTime) { return _nextTime; } else { uint256 time = (nowTime.sub(_nextTime)).div(_timeLimit); return _nextTime.add(_timeLimit.mul(time.add(1))); } } /** * @dev View total circulation * @return Total circulation */ function allValue(address token) public view returns (uint256) { if (token == address(_nestContract)) { uint256 all = 10000000000 ether; uint256 leftNum = all.sub(_nestContract.balanceOf(address(_voteFactory.checkAddress("nest.v3.miningSave")))).sub(_nestContract.balanceOf(address(_destructionAddress))); return leftNum; } else { return ERC20(token).totalSupply(); } } /** * @dev View bonus period * @return Bonus period */ function checkTimeLimit() public view returns (uint256) { return _timeLimit; } /** * @dev View duration of triggering calculation of bonus * @return Bonus period */ function checkGetAbonusTimeLimit() public view returns (uint256) { return _getAbonusTimeLimit; } /** * @dev View current lowest expected bonus * @return Current lowest expected bonus */ function checkMinimumAbonus(address token) public view returns (uint256) { uint256 miningAmount; if (token == address(_nestContract)) { miningAmount = allValue(token).div(_expectedSpanForNest); } else { miningAmount = allValue(token).div(_expectedSpanForNToken); } uint256 minimumAbonus = _expectedMinimum; for (uint256 i = 0; i < miningAmount; i++) { minimumAbonus = minimumAbonus.add(minimumAbonus.mul(_expectedIncrement).div(100)); } return minimumAbonus; } /** * @dev Check whether the bonus token is snapshoted * @param token Token address * @return Whether snapshoted */ function checkSnapshot(address token) public view returns (bool) { return _snapshot[token][_times.sub(1)]; } /** * @dev Check the expected bonus incremental ratio * @return Expected bonus increment ratio */ function checkeExpectedIncrement() public view returns (uint256) { return _expectedIncrement; } /** * @dev View expected minimum bonus * @return Expected minimum bonus */ function checkExpectedMinimum() public view returns (uint256) { return _expectedMinimum; } /** * @dev View savings threshold * @return Save threshold */ function checkSavingLevelOne() public view returns (uint256) { return _savingLevelOne; } function checkSavingLevelTwo() public view returns (uint256) { return _savingLevelTwo; } function checkSavingLevelThree() public view returns (uint256) { return _savingLevelThree; } /** * @dev View NEST liquidity snapshot * @param token Locked token address * @param times Bonus snapshot period */ function checkTokenAllValueHistory(address token, uint256 times) public view returns (uint256) { return _tokenAllValueHistory[token][times]; } /** * @dev View personal lock-up NEST snapshot * @param times Bonus snapshot period * @param user User address * @return The number of personal locked NEST snapshots */ function checkTokenSelfHistory(address token, uint256 times, address user) public view returns (uint256) { return _tokenSelfHistory[token][times][user]; } // View the period number of bonus function checkTimes() public view returns (uint256) { return _times; } // NEST expected bonus increment threshold function checkExpectedSpanForNest() public view returns (uint256) { return _expectedSpanForNest; } // NToken expected bonus increment threshold function checkExpectedSpanForNToken() public view returns (uint256) { return _expectedSpanForNToken; } // View the function parameters of savings threshold level 3 function checkSavingLevelTwoSub() public view returns (uint256) { return _savingLevelTwoSub; } // View the function parameters of savings threshold level 3 function checkSavingLevelThreeSub() public view returns (uint256) { return _savingLevelThreeSub; } /** * @dev Update bonus period * @param hour Bonus period (hours) */ function changeTimeLimit(uint256 hour) public onlyOwner { require(hour > 0, "Parameter needs to be greater than 0"); _timeLimit = hour.mul(1 hours); } /** * @dev Update collection period * @param hour Collection period (hours) */ function changeGetAbonusTimeLimit(uint256 hour) public onlyOwner { require(hour > 0, "Parameter needs to be greater than 0"); _getAbonusTimeLimit = hour; } /** * @dev Update expected bonus increment ratio * @param num Expected bonus increment ratio */ function changeExpectedIncrement(uint256 num) public onlyOwner { require(num > 0, "Parameter needs to be greater than 0"); _expectedIncrement = num; } /** * @dev Update expected minimum bonus * @param num Expected minimum bonus */ function changeExpectedMinimum(uint256 num) public onlyOwner { require(num > 0, "Parameter needs to be greater than 0"); _expectedMinimum = num; } /** * @dev Update saving threshold * @param threshold Saving threshold */ function changeSavingLevelOne(uint256 threshold) public onlyOwner { _savingLevelOne = threshold; } function changeSavingLevelTwo(uint256 threshold) public onlyOwner { _savingLevelTwo = threshold; } function changeSavingLevelThree(uint256 threshold) public onlyOwner { _savingLevelThree = threshold; } /** * @dev Update the function parameters of savings threshold level 2 */ function changeSavingLevelTwoSub(uint256 num) public onlyOwner { _savingLevelTwoSub = num; } /** * @dev Update the function parameters of savings threshold level 3 */ function changeSavingLevelThreeSub(uint256 num) public onlyOwner { _savingLevelThreeSub = num; } /** * @dev Update NEST expected bonus incremental threshold * @param num Threshold */ function changeExpectedSpanForNest(uint256 num) public onlyOwner { _expectedSpanForNest = num; } /** * @dev Update NToken expected bonus incremental threshold * @param num Threshold */ function changeExpectedSpanForNToken(uint256 num) public onlyOwner { _expectedSpanForNToken = num; } receive() external payable { } // Administrator only modifier onlyOwner(){ require(_voteFactory.checkOwners(address(msg.sender)), "No authority"); _; } } // NEST and NToken lock-up contracts interface Nest_3_TokenSave { function depositIn(uint256 num, address token, address target) external; function checkAmount(address sender, address token) external view returns(uint256); function takeOut(uint256 num, address token, address target) external; } // ETH bonus pool interface Nest_3_Abonus { function getETH(uint256 num, address token, address target) external; function getETHNum(address token) external view returns (uint256); function switchToEth(address token) external payable; } // Leveling contract interface Nest_3_Leveling { function tranEth(uint256 amount, address token, address target) external returns (uint256); function switchToEth(address token) external payable; } // Voting factory contract interface Nest_3_VoteFactory { // Check if there is a vote currently participating function checkVoteNow(address user) external view returns(bool); // Check address function checkAddress(string calldata name) external view returns (address contractAddress); // Check whether the administrator function checkOwners(address man) external view returns (bool); } // ERC20 contract interface ERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } library address_make_payable { function make_payable(address x) internal pure returns (address payable) { return address(uint160(x)); } }
File 2 of 4: Nest_3_TokenSave
pragma solidity 0.6.0; /** * @title NEST and NToken lock-up contract * @dev NEST and NToken deposit and withdrawal */ contract Nest_3_TokenSave { using SafeMath for uint256; Nest_3_VoteFactory _voteFactory; // Voting contract mapping(address => mapping(address => uint256)) _baseMapping; // Ledger token=>user=>amount /** * @dev initialization method * @param voteFactory Voting contract address */ constructor(address voteFactory) public { _voteFactory = Nest_3_VoteFactory(voteFactory); } /** * @dev Reset voting contract * @param voteFactory Voting contract address */ function changeMapping(address voteFactory) public onlyOwner { _voteFactory = Nest_3_VoteFactory(voteFactory); } /** * @dev Withdrawing * @param num Withdrawing amount * @param token Lock-up token address * @param target Transfer target */ function takeOut(uint256 num, address token, address target) public onlyContract { require(num <= _baseMapping[token][address(target)], "Insufficient storage balance"); _baseMapping[token][address(target)] = _baseMapping[token][address(target)].sub(num); ERC20(token).transfer(address(target), num); } /** * @dev Depositing * @param num Depositing amount * @param token Lock-up token address * @param target Depositing target */ function depositIn(uint256 num, address token, address target) public onlyContract { require(ERC20(token).transferFrom(address(target),address(this),num), "Authorization transfer failed"); _baseMapping[token][address(target)] = _baseMapping[token][address(target)].add(num); } /** * @dev Check the amount * @param sender Check address * @param token Lock-up token address * @return uint256 Check address corresponding lock-up limit */ function checkAmount(address sender, address token) public view returns(uint256) { return _baseMapping[token][address(sender)]; } // Administrators only modifier onlyOwner(){ require(_voteFactory.checkOwners(address(msg.sender)), "No authority"); _; } // Only for bonus logic contract modifier onlyContract(){ require(_voteFactory.checkAddress("nest.v3.tokenAbonus") == address(msg.sender), "No authority"); _; } } // ERC20 contract interface ERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } // Voting factory interface Nest_3_VoteFactory { // Check address function checkAddress(string calldata name) external view returns (address contractAddress); // Check whether the administrator function checkOwners(address man) external view returns (bool); } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
File 3 of 4: Nest_NToken
pragma solidity 0.6.0; library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // voting contract interface Nest_3_VoteFactory { // Check address function checkAddress(string calldata name) external view returns (address contractAddress); // check whether the administrator function checkOwners(address man) external view returns (bool); } /** * @title NToken contract * @dev Include standard erc20 method, mining method, and mining data */ interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } contract Nest_NToken is IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; // Balance ledger mapping (address => mapping (address => uint256)) private _allowed; // Approval ledger uint256 private _totalSupply = 0 ether; // Total supply string public name; // Token name string public symbol; // Token symbol uint8 public decimals = 18; // Precision uint256 public _createBlock; // Create block number uint256 public _recentlyUsedBlock; // Recently used block number Nest_3_VoteFactory _voteFactory; // Voting factory contract address _bidder; // Owner /** * @dev Initialization method * @param _name Token name * @param _symbol Token symbol * @param voteFactory Voting factory contract address * @param bidder Successful bidder address */ constructor (string memory _name, string memory _symbol, address voteFactory, address bidder) public { name = _name; symbol = _symbol; _createBlock = block.number; _recentlyUsedBlock = block.number; _voteFactory = Nest_3_VoteFactory(address(voteFactory)); _bidder = bidder; } /** * @dev Reset voting contract method * @param voteFactory Voting contract address */ function changeMapping (address voteFactory) public onlyOwner { _voteFactory = Nest_3_VoteFactory(address(voteFactory)); } /** * @dev Additional issuance * @param value Additional issuance amount */ function increaseTotal(uint256 value) public { address offerMain = address(_voteFactory.checkAddress("nest.nToken.offerMain")); require(address(msg.sender) == offerMain, "No authority"); _balances[offerMain] = _balances[offerMain].add(value); _totalSupply = _totalSupply.add(value); _recentlyUsedBlock = block.number; } /** * @dev Check the total amount of tokens * @return Total supply */ function totalSupply() override public view returns (uint256) { return _totalSupply; } /** * @dev Check address balance * @param owner Address to be checked * @return Return the balance of the corresponding address */ function balanceOf(address owner) override public view returns (uint256) { return _balances[owner]; } /** * @dev Check block information * @return createBlock Initial block number * @return recentlyUsedBlock Recently mined and issued block */ function checkBlockInfo() public view returns(uint256 createBlock, uint256 recentlyUsedBlock) { return (_createBlock, _recentlyUsedBlock); } /** * @dev Check owner's approved allowance to the spender * @param owner Approving address * @param spender Approved address * @return Approved amount */ function allowance(address owner, address spender) override public view returns (uint256) { return _allowed[owner][spender]; } /** * @dev Transfer method * @param to Transfer target * @param value Transfer amount * @return Whether the transfer is successful */ function transfer(address to, uint256 value) override public returns (bool) { _transfer(msg.sender, to, value); return true; } /** * @dev Approval method * @param spender Approval target * @param value Approval amount * @return Whether the approval is successful */ function approve(address spender, uint256 value) override public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /** * @dev Transfer tokens when approved * @param from Transfer-out account address * @param to Transfer-in account address * @param value Transfer amount * @return Whether approved transfer is successful */ function transferFrom(address from, address to, uint256 value) override public returns (bool) { _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value); _transfer(from, to, value); emit Approval(from, msg.sender, _allowed[from][msg.sender]); return true; } /** * @dev Increase the allowance * @param spender Approval target * @param addedValue Amount to increase * @return whether increase is successful */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Decrease the allowance * @param spender Approval target * @param subtractedValue Amount to decrease * @return Whether decrease is successful */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Transfer method * @param to Transfer target * @param value Transfer amount */ function _transfer(address from, address to, uint256 value) internal { _balances[from] = _balances[from].sub(value); _balances[to] = _balances[to].add(value); emit Transfer(from, to, value); } /** * @dev Check the creator * @return Creator address */ function checkBidder() public view returns(address) { return _bidder; } /** * @dev Transfer creator * @param bidder New creator address */ function changeBidder(address bidder) public { require(address(msg.sender) == _bidder); _bidder = bidder; } // Administrator only modifier onlyOwner(){ require(_voteFactory.checkOwners(msg.sender)); _; } }
File 4 of 4: Nest_3_VoteFactory
pragma solidity 0.6.0; /** * @title Voting factory + mapping * @dev Vote creating method */ contract Nest_3_VoteFactory { using SafeMath for uint256; uint256 _limitTime = 7 days; // Vote duration uint256 _NNLimitTime = 1 days; // NestNode raising time uint256 _circulationProportion = 51; // Proportion of votes to pass uint256 _NNUsedCreate = 10; // The minimum number of NNs to create a voting contract uint256 _NNCreateLimit = 100; // The minimum number of NNs needed to start voting 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 ERC20 _NNToken; // NestNode Token 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 event ContractAddress(address contractAddress); /** * @dev Initialization method */ constructor () public { _modifyAuthority[address(msg.sender)] = true; } /** * @dev Reset contract */ function changeMapping() public onlyOwner { _NNToken = ERC20(checkAddress("nestNode")); _destructionAddress = address(checkAddress("nest.v3.destruction")); _nestToken = ERC20(address(checkAddress("nest"))); } /** * @dev Create voting contract * @param implementContract The executable contract address for voting * @param nestNodeAmount Number of NNs to pledge */ 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); require(_NNToken.transferFrom(address(tx.origin), address(newContract), nestNodeAmount), "Authorization transfer failed"); _contractData[address(newContract)] = true; emit ContractAddress(address(newContract)); } /** * @dev Use NEST to vote * @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))); Nest_3_VoteContract newContract = Nest_3_VoteContract(contractAddress); newContract.nestVote(); _myVote[address(tx.origin)] = contractAddress; } /** * @dev Vote using NestNode Token * @param contractAddress Vote contract address * @param NNAmount Amount of NNs to pledge */ 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 Switch emergency state-transfer in NestNode Token * @param amount Amount of NNs to transfer */ function sendNestNodeForStateOfEmergency(uint256 amount) public { require(_NNToken.transferFrom(address(tx.origin), address(this), amount)); _emergencyPerson[address(tx.origin)] = _emergencyPerson[address(tx.origin)].add(amount); } /** * @dev Switch emergency state-transfer out NestNode Token */ function turnOutNestNodeForStateOfEmergency() public { require(_emergencyPerson[address(tx.origin)] > 0); require(_NNToken.transfer(address(tx.origin), _emergencyPerson[address(tx.origin)])); _emergencyPerson[address(tx.origin)] = 0; uint256 nestAmount = _nestToken.balanceOf(address(this)); require(_nestToken.transfer(address(_destructionAddress), nestAmount)); } /** * @dev Modify emergency state */ function changeStateOfEmergency() public { if (_stateOfEmergency) { require(now > _emergencyTime.add(_emergencyTimeLimit)); _stateOfEmergency = false; _emergencyTime = 0; } else { require(_emergencyPerson[address(msg.sender)] > 0); require(_NNToken.balanceOf(address(this)) >= _emergencyNNAmount); _stateOfEmergency = true; _emergencyTime = now; } } /** * @dev Check whether participating in the voting * @param user Address to check * @return bool Whether voting */ function checkVoteNow(address user) public view returns (bool) { if (_myVote[user] == address(0x0)) { return false; } else { Nest_3_VoteContract vote = Nest_3_VoteContract(_myVote[user]); if (vote.checkContractEffective() || vote.checkPersonalAmount(user) == 0) { return false; } return true; } } /** * @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; } // Check the NestNode raising time 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 function checkNNUsedCreate() public view returns (uint256) { return _NNUsedCreate; } // Check the minimum number of NNs raised to start a vote 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 function checkEmergencyPerson(address user) public view returns (uint256) { return _emergencyPerson[user]; } // Check the number of NNs required for the emergency 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 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 function changeNNUsedCreate(uint256 num) public onlyOwner { _NNUsedCreate = num; } // Modify the minimum number of NNs to raised to start a voting 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 function changeEmergencyNNAmount(uint256 num) public onlyOwner { require(num > 0); _emergencyNNAmount = num; } // 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"); _; } } /** * @title Voting contract */ contract Nest_3_VoteContract { using SafeMath for uint256; Nest_3_Implement _implementContract; // Executable contract Nest_3_TokenSave _tokenSave; // Lock-up contract Nest_3_VoteFactory _voteFactory; // Voting factory contract Nest_3_TokenAbonus _tokenAbonus; // Bonus logic contract ERC20 _nestToken; // NestToken ERC20 _NNToken; // NestNode Token address _miningSave; // Mining pool contract address _implementAddress; // Executable contract address address _destructionAddress; // Destruction contract address uint256 _createTime; // Creation time uint256 _endTime; // End time uint256 _totalAmount; // Total votes uint256 _circulation; // Passed votes uint256 _destroyedNest; // Destroyed NEST uint256 _NNLimitTime; // NestNode raising time uint256 _NNCreateLimit; // Minimum number of NNs to create votes uint256 _abonusTimes; // Period number of used snapshot in emergency state uint256 _allNNAmount; // Total number of NNs bool _effective = false; // Whether vote is effective bool _nestVote = false; // Whether NEST vote can be performed bool _isChange = false; // Whether NEST vote is executed bool _stateOfEmergency; // Whether the contract is in emergency state mapping(address => uint256) _personalAmount; // Number of personal votes mapping(address => uint256) _personalNNAmount; // Number of NN personal votes /** * @dev Initialization method * @param contractAddress Executable contract address * @param stateOfEmergency Whether in emergency state * @param NNAmount Amount of NNs */ constructor (address contractAddress, bool stateOfEmergency, uint256 NNAmount) public { Nest_3_VoteFactory voteFactory = Nest_3_VoteFactory(address(msg.sender)); _voteFactory = voteFactory; _nestToken = ERC20(voteFactory.checkAddress("nest")); _NNToken = ERC20(voteFactory.checkAddress("nestNode")); _implementContract = Nest_3_Implement(address(contractAddress)); _implementAddress = address(contractAddress); _destructionAddress = address(voteFactory.checkAddress("nest.v3.destruction")); _personalNNAmount[address(tx.origin)] = NNAmount; _allNNAmount = NNAmount; _createTime = now; _endTime = _createTime.add(voteFactory.checkLimitTime()); _NNLimitTime = voteFactory.checkNNLimitTime(); _NNCreateLimit = voteFactory.checkNNCreateLimit(); _stateOfEmergency = stateOfEmergency; if (stateOfEmergency) { // If in emergency state, read the last two periods of bonus lock-up and total circulation data _tokenAbonus = Nest_3_TokenAbonus(voteFactory.checkAddress("nest.v3.tokenAbonus")); _abonusTimes = _tokenAbonus.checkTimes().sub(2); require(_abonusTimes > 0); _circulation = _tokenAbonus.checkTokenAllValueHistory(address(_nestToken),_abonusTimes).mul(voteFactory.checkCirculationProportion()).div(100); } else { _miningSave = address(voteFactory.checkAddress("nest.v3.miningSave")); _tokenSave = Nest_3_TokenSave(voteFactory.checkAddress("nest.v3.tokenSave")); _circulation = (uint256(10000000000 ether).sub(_nestToken.balanceOf(address(_miningSave))).sub(_nestToken.balanceOf(address(_destructionAddress)))).mul(voteFactory.checkCirculationProportion()).div(100); } if (_allNNAmount >= _NNCreateLimit) { _nestVote = true; } } /** * @dev NEST voting */ function nestVote() public onlyFactory { require(now <= _endTime, "Voting time exceeded"); require(!_effective, "Vote in force"); require(_nestVote); require(_personalAmount[address(tx.origin)] == 0, "Have voted"); uint256 amount; if (_stateOfEmergency) { // If in emergency state, read the last two periods of bonus lock-up and total circulation data amount = _tokenAbonus.checkTokenSelfHistory(address(_nestToken),_abonusTimes, address(tx.origin)); } else { amount = _tokenSave.checkAmount(address(tx.origin), address(_nestToken)); } _personalAmount[address(tx.origin)] = amount; _totalAmount = _totalAmount.add(amount); ifEffective(); } /** * @dev NEST voting cancellation */ function nestVoteCancel() public { require(address(msg.sender) == address(tx.origin), "It can't be a contract"); require(now <= _endTime, "Voting time exceeded"); require(!_effective, "Vote in force"); require(_personalAmount[address(tx.origin)] > 0, "No vote"); _totalAmount = _totalAmount.sub(_personalAmount[address(tx.origin)]); _personalAmount[address(tx.origin)] = 0; } /** * @dev NestNode voting * @param NNAmount Amount of NNs */ function nestNodeVote(uint256 NNAmount) public onlyFactory { require(now <= _createTime.add(_NNLimitTime), "Voting time exceeded"); require(!_nestVote); _personalNNAmount[address(tx.origin)] = _personalNNAmount[address(tx.origin)].add(NNAmount); _allNNAmount = _allNNAmount.add(NNAmount); if (_allNNAmount >= _NNCreateLimit) { _nestVote = true; } } /** * @dev Withdrawing lock-up NNs */ function turnOutNestNode() public { if (_nestVote) { // Normal NEST voting if (!_stateOfEmergency || !_effective) { // Non-emergency state require(now > _endTime, "Vote unenforceable"); } } else { // NN voting require(now > _createTime.add(_NNLimitTime)); } require(_personalNNAmount[address(tx.origin)] > 0); // Reverting back the NNs require(_NNToken.transfer(address(tx.origin), _personalNNAmount[address(tx.origin)])); _personalNNAmount[address(tx.origin)] = 0; // Destroying NEST Tokens uint256 nestAmount = _nestToken.balanceOf(address(this)); _destroyedNest = _destroyedNest.add(nestAmount); require(_nestToken.transfer(address(_destructionAddress), nestAmount)); } /** * @dev Execute the contract */ function startChange() public onlyFactory { require(!_isChange); _isChange = true; if (_stateOfEmergency) { require(_effective, "Vote unenforceable"); } else { require(_effective && now > _endTime, "Vote unenforceable"); } // Add the executable contract to the administrator list _voteFactory.addSuperMan(address(_implementContract)); // Execute _implementContract.doit(); // Delete the authorization _voteFactory.deleteSuperMan(address(_implementContract)); } /** * @dev check whether the vote is effective */ function ifEffective() private { if (_totalAmount >= _circulation) { _effective = true; } } /** * @dev Check whether the vote is over */ function checkContractEffective() public view returns (bool) { if (_effective || now > _endTime) { return true; } return false; } // Check the executable implement contract address function checkImplementAddress() public view returns (address) { return _implementAddress; } // Check the voting start time function checkCreateTime() public view returns (uint256) { return _createTime; } // Check the voting end time function checkEndTime() public view returns (uint256) { return _endTime; } // Check the current total number of votes function checkTotalAmount() public view returns (uint256) { return _totalAmount; } // Check the number of votes to pass function checkCirculation() public view returns (uint256) { return _circulation; } // Check the number of personal votes function checkPersonalAmount(address user) public view returns (uint256) { return _personalAmount[user]; } // Check the destroyed NEST function checkDestroyedNest() public view returns (uint256) { return _destroyedNest; } // Check whether the contract is effective function checkEffective() public view returns (bool) { return _effective; } // Check whether in emergency state function checkStateOfEmergency() public view returns (bool) { return _stateOfEmergency; } // Check NestNode raising time function checkNNLimitTime() public view returns (uint256) { return _NNLimitTime; } // Check the minimum number of NNs to create a vote function checkNNCreateLimit() public view returns (uint256) { return _NNCreateLimit; } // Check the period number of snapshot used in the emergency state function checkAbonusTimes() public view returns (uint256) { return _abonusTimes; } // Check number of personal votes function checkPersonalNNAmount(address user) public view returns (uint256) { return _personalNNAmount[address(user)]; } // Check the total number of NNs function checkAllNNAmount() public view returns (uint256) { return _allNNAmount; } // Check whether NEST voting is available function checkNestVote() public view returns (bool) { return _nestVote; } // Check whether it has been excecuted function checkIsChange() public view returns (bool) { return _isChange; } // Vote Factory contract only modifier onlyFactory() { require(address(_voteFactory) == address(msg.sender), "No authority"); _; } } // Executable contract interface Nest_3_Implement { // Execute function doit() external; } // NEST lock-up contract interface Nest_3_TokenSave { // Check lock-up amount function checkAmount(address sender, address token) external view returns (uint256); } // Bonus logic contract interface Nest_3_TokenAbonus { // Check NEST circulation snapshot function checkTokenAllValueHistory(address token, uint256 times) external view returns (uint256); // Check NEST user balance snapshot function checkTokenSelfHistory(address token, uint256 times, address user) external view returns (uint256); // Check bonus ledger period function checkTimes() external view returns (uint256); } // Erc20 contract interface ERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }