Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "../lib/openzeppelin/contracts/3.4.1/token/ERC20/IERC20.sol";
import "./interfaces/IERC1155Preset.sol";
import "./interfaces/StrongPoolInterface.sol";
import "./lib/AdminAccessControl.sol";
import "./lib/rewards.sol";
contract NodesV2 is AdminAccessControl {
event Requested(address indexed miner);
event Claimed(address indexed miner, uint256 reward);
event Paid(address indexed entity, uint128 nodeId, bool isRenewal, uint256 upToBlockNumber);
IERC20 public strongToken;
StrongPoolInterface public strongPool;
bool public initDone;
uint256 public activeEntities;
address payable public feeCollector;
uint256 public rewardPerBlockNumerator;
uint256 public rewardPerBlockDenominator;
uint256 public rewardPerBlockNumeratorNew;
uint256 public rewardPerBlockDenominatorNew;
uint256 public rewardPerBlockNewEffectiveBlock;
uint256 public claimingFeeNumerator;
uint256 public claimingFeeDenominator;
uint256 public requestingFeeInWei;
uint256 public strongFeeInWei;
uint256 public recurringFeeInWei;
uint256 public recurringPaymentCycleInBlocks;
uint256 public rewardBalance;
uint256 public claimingFeeInWei;
uint256 public gracePeriodInBlocks;
uint128 public maxNodes;
uint256 public maxPaymentPeriods;
mapping(bytes => uint256) public entityNodePaidOnBlock;
mapping(bytes => uint256) public entityNodeClaimedOnBlock;
mapping(address => uint128) public entityNodeCount;
function init(
address _strongTokenAddress,
address _strongPoolAddress,
uint256 _rewardPerBlockNumeratorValue,
uint256 _rewardPerBlockDenominatorValue,
uint256 _requestingFeeInWeiValue,
uint256 _strongFeeInWeiValue,
uint256 _recurringFeeInWeiValue,
uint256 _recurringPaymentCycleInBlocksValue,
uint256 _claimingFeeNumeratorValue,
uint256 _claimingFeeDenominatorValue
) public {
require(!initDone, "init done");
strongToken = IERC20(_strongTokenAddress);
strongPool = StrongPoolInterface(_strongPoolAddress);
rewardPerBlockNumerator = _rewardPerBlockNumeratorValue;
rewardPerBlockDenominator = _rewardPerBlockDenominatorValue;
requestingFeeInWei = _requestingFeeInWeiValue;
strongFeeInWei = _strongFeeInWeiValue;
recurringFeeInWei = _recurringFeeInWeiValue;
claimingFeeNumerator = _claimingFeeNumeratorValue;
claimingFeeDenominator = _claimingFeeDenominatorValue;
recurringPaymentCycleInBlocks = _recurringPaymentCycleInBlocksValue;
maxNodes = 100;
initDone = true;
}
//
// Getters
// -------------------------------------------------------------------------------------------------------------------
function canBePaid(address _entity, uint128 _nodeId) public view returns (bool) {
return !hasNodeExpired(_entity, _nodeId) && !hasMaxPayments(_entity, _nodeId);
}
function doesNodeExist(address _entity, uint128 _nodeId) public view returns (bool) {
return entityNodePaidOnBlock[getNodeId(_entity, _nodeId)] > 0;
}
function hasNodeExpired(address _entity, uint128 _nodeId) public view returns (bool) {
uint256 blockLastPaidOn = entityNodePaidOnBlock[getNodeId(_entity, _nodeId)];
return block.number > blockLastPaidOn + recurringPaymentCycleInBlocks + gracePeriodInBlocks;
}
function hasMaxPayments(address _entity, uint128 _nodeId) public view returns (bool) {
uint256 blockLastPaidOn = entityNodePaidOnBlock[getNodeId(_entity, _nodeId)];
uint256 limit = block.number + recurringPaymentCycleInBlocks * maxPaymentPeriods;
return blockLastPaidOn + recurringPaymentCycleInBlocks >= limit;
}
function getNodeId(address _entity, uint128 _nodeId) public view returns (bytes memory) {
uint128 id = _nodeId != 0 ? _nodeId : entityNodeCount[_entity] + 1;
return abi.encodePacked(_entity, id);
}
function getNodePaidOn(address _entity, uint128 _nodeId) public view returns (uint256) {
return entityNodePaidOnBlock[getNodeId(_entity, _nodeId)];
}
function getReward(address _entity, uint128 _nodeId) public view returns (uint256) {
return getRewardByBlock(_entity, _nodeId, block.number);
}
function getRewardAll(address _entity, uint256 _blockNumber) public view returns (uint256) {
uint256 rewardsAll = 0;
for (uint128 i = 1; i <= entityNodeCount[_entity]; i++) {
rewardsAll = rewardsAll + getRewardByBlock(_entity, i, _blockNumber > 0 ? _blockNumber : block.number);
}
return rewardsAll;
}
function getRewardByBlock(address _entity, uint128 _nodeId, uint256 _blockNumber) public view returns (uint256) {
bytes memory id = getNodeId(_entity, _nodeId);
uint256 blockLastClaimedOn = entityNodeClaimedOnBlock[id] != 0 ? entityNodeClaimedOnBlock[id] : entityNodePaidOnBlock[id];
if (_blockNumber > block.number) return 0;
if (blockLastClaimedOn == 0) return 0;
if (_blockNumber < blockLastClaimedOn) return 0;
uint256[2] memory rewardBlocks = rewards.blocks(blockLastClaimedOn, rewardPerBlockNewEffectiveBlock, _blockNumber);
uint256 rewardOld = rewardPerBlockDenominator > 0 ? rewardBlocks[0] * rewardPerBlockNumerator / rewardPerBlockDenominator : 0;
uint256 rewardNew = rewardPerBlockDenominatorNew > 0 ? rewardBlocks[1] * rewardPerBlockNumeratorNew / rewardPerBlockDenominatorNew : 0;
return rewardOld + rewardNew;
}
function isEntityActive(address _entity) public view returns (bool) {
return doesNodeExist(_entity, 1) && !hasNodeExpired(_entity, 1);
}
//
// Actions
// -------------------------------------------------------------------------------------------------------------------
function requestAccess() public payable {
require(entityNodeCount[msg.sender] < maxNodes, "limit reached");
require(msg.value == requestingFeeInWei, "invalid fee");
uint128 nodeId = entityNodeCount[msg.sender] + 1;
bytes memory id = getNodeId(msg.sender, nodeId);
activeEntities ++;
entityNodePaidOnBlock[id] = block.number;
entityNodeClaimedOnBlock[id] = block.number;
entityNodeCount[msg.sender] = entityNodeCount[msg.sender] + 1;
feeCollector.transfer(msg.value);
strongToken.transferFrom(msg.sender, feeCollector, strongFeeInWei);
emit Paid(msg.sender, nodeId, false, entityNodePaidOnBlock[id] + recurringPaymentCycleInBlocks);
}
function payFee(uint128 _nodeId) public payable {
address sender = msg.sender == address(this) ? tx.origin : msg.sender;
bytes memory id = getNodeId(sender, _nodeId);
require(doesNodeExist(sender, _nodeId), "doesnt exist");
require(hasNodeExpired(sender, _nodeId) == false, "too late");
require(hasMaxPayments(sender, _nodeId) == false, "too soon");
require(msg.value == recurringFeeInWei, "invalid fee");
feeCollector.transfer(msg.value);
entityNodePaidOnBlock[id] = entityNodePaidOnBlock[id] + recurringPaymentCycleInBlocks;
emit Paid(sender, _nodeId, true, entityNodePaidOnBlock[id]);
}
function claim(uint128 _nodeId, uint256 _blockNumber, bool _toStrongPool) public payable returns (bool) {
address sender = msg.sender == address(this) ? tx.origin : msg.sender;
bytes memory id = getNodeId(sender, _nodeId);
uint256 blockLastClaimedOn = entityNodeClaimedOnBlock[id] != 0 ? entityNodeClaimedOnBlock[id] : entityNodePaidOnBlock[id];
uint256 blockLastPaidOn = entityNodePaidOnBlock[id];
require(blockLastClaimedOn != 0, "never claimed");
require(_blockNumber <= block.number, "invalid block");
require(_blockNumber > blockLastClaimedOn, "too soon");
if (recurringFeeInWei != 0) {
require(_blockNumber < blockLastPaidOn + recurringPaymentCycleInBlocks, "pay fee");
}
uint256 reward = getRewardByBlock(sender, _nodeId, _blockNumber);
require(reward > 0, "no reward");
uint256 fee = reward * claimingFeeNumerator / claimingFeeDenominator;
require(msg.value >= fee, "invalid fee");
feeCollector.transfer(msg.value);
if (_toStrongPool) {
strongToken.approve(address(strongPool), reward);
strongPool.mineFor(sender, reward);
} else {
strongToken.transfer(sender, reward);
}
rewardBalance -= reward;
entityNodeClaimedOnBlock[id] = _blockNumber;
emit Claimed(sender, reward);
return true;
}
function claimAll(uint256 _blockNumber, bool _toStrongPool) public payable {
uint256 value = msg.value;
for (uint16 i = 1; i <= entityNodeCount[msg.sender]; i++) {
uint256 reward = getRewardByBlock(msg.sender, i, _blockNumber);
uint256 fee = reward * claimingFeeNumerator / claimingFeeDenominator;
require(value >= fee, "invalid fee");
require(this.claim{value : fee}(i, _blockNumber, _toStrongPool), "claim failed");
value -= fee;
}
}
function payAll(uint256 _nodeCount) public payable {
require(_nodeCount > 0, "invalid value");
require(msg.value == recurringFeeInWei * _nodeCount, "invalid fee");
for (uint16 nodeId = 1; nodeId <= entityNodeCount[msg.sender]; nodeId++) {
if (!canBePaid(msg.sender, nodeId)) {
continue;
}
this.payFee{value : recurringFeeInWei}(nodeId);
_nodeCount -= 1;
}
require(_nodeCount == 0, "invalid count");
}
//
// Admin
// -------------------------------------------------------------------------------------------------------------------
function deposit(uint256 _amount) public onlyRole(adminControl.SUPER_ADMIN()) {
require(_amount > 0);
strongToken.transferFrom(msg.sender, address(this), _amount);
rewardBalance += _amount;
}
function withdraw(address _destination, uint256 _amount) public onlyRole(adminControl.SUPER_ADMIN()) {
require(_amount > 0);
require(rewardBalance >= _amount, "not enough");
strongToken.transfer(_destination, _amount);
rewardBalance -= _amount;
}
function updateFeeCollector(address payable _newFeeCollector) public onlyRole(adminControl.SUPER_ADMIN()) {
require(_newFeeCollector != address(0));
feeCollector = _newFeeCollector;
}
function updateRequestingFee(uint256 _feeInWei) public onlyRole(adminControl.SERVICE_ADMIN()) {
requestingFeeInWei = _feeInWei;
}
function updateStrongFee(uint256 _feeInWei) public onlyRole(adminControl.SERVICE_ADMIN()) {
strongFeeInWei = _feeInWei;
}
function updateClaimingFee(uint256 _numerator, uint256 _denominator) public onlyRole(adminControl.SERVICE_ADMIN()) {
require(_denominator != 0);
claimingFeeNumerator = _numerator;
claimingFeeDenominator = _denominator;
}
function updateRecurringFee(uint256 _feeInWei) public onlyRole(adminControl.SERVICE_ADMIN()) {
recurringFeeInWei = _feeInWei;
}
function updateRecurringPaymentCycleInBlocks(uint256 _blocks) public onlyRole(adminControl.SERVICE_ADMIN()) {
require(_blocks > 0);
recurringPaymentCycleInBlocks = _blocks;
}
function updateGracePeriodInBlocks(uint256 _blocks) public onlyRole(adminControl.SERVICE_ADMIN()) {
require(_blocks > 0);
gracePeriodInBlocks = _blocks;
}
function updateLimits(uint128 _maxNodes, uint256 _maxPaymentPeriods) public onlyRole(adminControl.SERVICE_ADMIN()) {
maxNodes = _maxNodes;
maxPaymentPeriods = _maxPaymentPeriods;
}
function updateRewardPerBlock(uint256 _numerator, uint256 _denominator) public onlyRole(adminControl.SERVICE_ADMIN()) {
require(_denominator != 0);
rewardPerBlockNumerator = _numerator;
rewardPerBlockDenominator = _denominator;
}
function updateRewardPerBlockNew(uint256 _numerator, uint256 _denominator, uint256 _effectiveBlock) public onlyRole(adminControl.SERVICE_ADMIN()) {
require(_denominator != 0);
rewardPerBlockNumeratorNew = _numerator;
rewardPerBlockDenominatorNew = _denominator;
rewardPerBlockNewEffectiveBlock = _effectiveBlock != 0 ? _effectiveBlock : block.number;
}
function setTokenContract(address strongTokenAddress) external onlyRole(adminControl.SUPER_ADMIN()) {
strongToken = IERC20(strongTokenAddress);
}
function withdrawToken(IERC20 token, address recipient, uint256 amount) external onlyRole(adminControl.SUPER_ADMIN()) {
require(token.transfer(recipient, amount));
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155Preset {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
/**
* @dev Creates `amount` new tokens for `to`, of token type `id`.
*
* See {ERC1155-_mint}.
*
* Requirements:
*
* - the caller must have the `MINTER_ROLE`.
*/
function mint(address to, uint256 id, uint256 amount, bytes memory data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}.
*/
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external;
function getOwnerIdByIndex(address owner, uint256 index) external view returns (uint256);
function getOwnerIdIndex(address owner, uint256 id) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
interface StrongPoolInterface {
function mineFor(address miner, uint256 amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "../interfaces/IAdminControl.sol";
abstract contract AdminAccessControl {
IAdminControl public adminControl;
modifier onlyRole(uint8 _role) {
require(address(adminControl) == address(0) || adminControl.hasRole(_role, msg.sender), "no access");
_;
}
function addAdminControlContract(address _contract) public onlyRole(0) {
adminControl = IAdminControl(_contract);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "./SafeMath.sol";
library rewards {
using SafeMath for uint256;
function blocks(uint256 lastClaimedOnBlock, uint256 newRewardBlock, uint256 blockNumber) internal pure returns (uint256[2] memory) {
if (lastClaimedOnBlock >= blockNumber) return [uint256(0), uint256(0)];
if (blockNumber <= newRewardBlock || newRewardBlock == 0) {
return [blockNumber.sub(lastClaimedOnBlock), uint256(0)];
}
else if (lastClaimedOnBlock >= newRewardBlock) {
return [uint256(0), blockNumber.sub(lastClaimedOnBlock)];
}
else {
return [newRewardBlock.sub(lastClaimedOnBlock), blockNumber.sub(newRewardBlock)];
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;
interface IAdminControl {
function hasRole(uint8 _role, address _account) external view returns (bool);
function SUPER_ADMIN() external view returns (uint8);
function ADMIN() external view returns (uint8);
function SERVICE_ADMIN() external view returns (uint8);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
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;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}