Contract Source Code:
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822ProxiableUpgradeable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967Upgradeable {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeaconUpgradeable {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/IERC1967Upgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import {Initializable} from "../utils/Initializable.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
function __ERC1967Upgrade_init() internal onlyInitializing {
}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
AddressUpgradeable.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
AddressUpgradeable.functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
interface HMTokenInterface {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
/// @param _owner The address from which the balance will be retrieved
/// @return balance The balance
function balanceOf(address _owner) external view returns (uint256 balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transfer(
address _to,
uint256 _value
) external returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transferFrom(
address _from,
address _to,
uint256 _value
) external returns (bool success);
function transferBulk(
address[] calldata _tos,
uint256[] calldata _values,
uint256 _txId
) external returns (uint256 _bulkCount);
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of tokens to be approved for transfer
/// @return success Whether the approval was successful or not
function approve(
address _spender,
uint256 _value
) external returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return remaining Amount of remaining tokens allowed to spent
function allowance(
address _owner,
address _spender
) external view returns (uint256 remaining);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
interface IEscrow {
enum EscrowStatuses {
Launched,
Pending,
Partial,
Paid,
Complete,
Cancelled
}
function status() external view returns (EscrowStatuses);
function addTrustedHandlers(address[] memory _handlers) external;
function setup(
address _reputationOracle,
address _recordingOracle,
address _exchangeOracle,
uint8 _reputationOracleFeePercentage,
uint8 _recordingOracleFeePercentage,
uint8 _exchangeOracleFeePercentage,
string memory _url,
string memory _hash
) external;
function abort() external;
function cancel() external returns (bool);
function complete() external;
function storeResults(string memory _url, string memory _hash) external;
function bulkPayOut(
address[] memory _recipients,
uint256[] memory _amounts,
string memory _url,
string memory _hash,
uint256 _txId
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
interface IRewardPool {
/**
* @dev Keep track of slashers how much they slashed per allocations
*/
struct Reward {
address escrowAddress;
address slasher;
uint256 tokens; // Tokens allocated to a escrowAddress
}
function addReward(
address _escrowAddress,
address _staker,
address _slasher,
uint256 _tokens
) external;
function getRewards(
address _escrowAddress
) external view returns (Reward[] memory);
function distributeReward(address _escrowAddress) external;
function withdraw(address to) external;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import '../libs/Stakes.sol';
interface IStaking {
/**
* @dev Possible states an allocation can be
* States:
* - Null = Staker == address(0)
* - Pending = not Null && tokens > 0 && escrowAddress status == Pending
* - Active = Pending && escrowAddress status == Launched
* - Closed = Active && closedAt != 0
* - Completed = Closed && closedAt && escrowAddress status == Complete
*/
enum AllocationState {
Null,
Pending,
Active,
Closed,
Completed
}
/**
* @dev Possible sort fields
* Fields:
* - None = Do not sort
* - Stake = Sort by stake amount
*/
enum SortField {
None,
Stake
}
/**
* @dev Allocate HMT tokens for the purpose of serving queries of a subgraph deployment
* An allocation is created in the allocate() function and consumed in claim()
*/
struct Allocation {
address escrowAddress;
address staker;
uint256 tokens; // Tokens allocated to a escrowAddress
uint256 createdAt; // Time when allocation was created
uint256 closedAt; // Time when allocation was closed
}
function rewardPool() external view returns (address);
function setMinimumStake(uint256 _minimumStake) external;
function setLockPeriod(uint32 _lockPeriod) external;
function setRewardPool(address _rewardPool) external;
function isAllocation(address _escrowAddress) external view returns (bool);
function hasStake(address _indexer) external view returns (bool);
function hasAvailableStake(address _indexer) external view returns (bool);
function getAllocation(
address _escrowAddress
) external view returns (Allocation memory);
function getAllocationState(
address _escrowAddress
) external view returns (AllocationState);
function getStakedTokens(address _staker) external view returns (uint256);
function getStaker(
address _staker
) external view returns (Stakes.Staker memory);
function stake(uint256 _tokens) external;
function unstake(uint256 _tokens) external;
function withdraw() external;
function slash(
address _slasher,
address _staker,
address _escrowAddress,
uint256 _tokens
) external;
function allocate(address escrowAddress, uint256 _tokens) external;
function closeAllocation(address _escrowAddress) external;
function getListOfStakers()
external
view
returns (address[] memory, Stakes.Staker[] memory);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import '../utils/SafeMath.sol';
import '../utils/Math.sol';
/**
* @title Structures, methods and data are available to manage the staker state.
*/
library Stakes {
using SafeMath for uint256;
using Stakes for Stakes.Staker;
struct Staker {
uint256 tokensStaked; // Tokens staked by the Staker
uint256 tokensAllocated; // Tokens allocated for jobs
uint256 tokensLocked; // Tokens locked for withdrawal
uint256 tokensLockedUntil; // Tokens locked until time
}
/**
* @dev Deposit tokens to the staker stake.
* @param stake Staker struct
* @param _tokens Amount of tokens to deposit
*/
function deposit(Stakes.Staker storage stake, uint256 _tokens) internal {
stake.tokensStaked = stake.tokensStaked.add(_tokens);
}
/**
* @dev Release tokens from the staker stake.
* @param stake Staker struct
* @param _tokens Amount of tokens to release
*/
function release(Stakes.Staker storage stake, uint256 _tokens) internal {
stake.tokensStaked = stake.tokensStaked.sub(_tokens);
}
/**
* @dev Add tokens from the main stack to tokensAllocated.
* @param stake Staker struct
* @param _tokens Amount of tokens to allocate
*/
function allocate(Stakes.Staker storage stake, uint256 _tokens) internal {
stake.tokensAllocated = stake.tokensAllocated.add(_tokens);
}
/**
* @dev Unallocate tokens from a escrowAddress back to the main stack.
* @param stake Staker struct
* @param _tokens Amount of tokens to unallocate
*/
function unallocate(Stakes.Staker storage stake, uint256 _tokens) internal {
stake.tokensAllocated = stake.tokensAllocated.sub(_tokens);
}
/**
* @dev Lock tokens until a lock period pass.
* @param stake Staker struct
* @param _tokens Amount of tokens to unstake
* @param _period Period in blocks that need to pass before withdrawal
*/
function lockTokens(
Stakes.Staker storage stake,
uint256 _tokens,
uint256 _period
) internal {
uint256 lockingPeriod = _period;
if (stake.tokensLocked > 0) {
lockingPeriod = Math.weightedAverage(
Math.diffOrZero(stake.tokensLockedUntil, block.number), // Remaining lock period
stake.tokensLocked,
_period,
_tokens
);
}
stake.tokensLocked = stake.tokensLocked.add(_tokens);
stake.tokensLockedUntil = block.number.add(lockingPeriod);
}
/**
* @dev Unlock tokens.
* @param stake Staker struct
* @param _tokens Amount of tokens to unkock
*/
function unlockTokens(
Stakes.Staker storage stake,
uint256 _tokens
) internal {
stake.tokensLocked = stake.tokensLocked.sub(_tokens);
if (stake.tokensLocked == 0) {
stake.tokensLockedUntil = 0;
}
}
/**
* @dev Return all tokens available for withdrawal.
* @param stake Staker struct
* @return Amount of tokens available for withdrawal
*/
function withdrawTokens(
Stakes.Staker storage stake
) internal returns (uint256) {
uint256 tokensToWithdraw = stake.tokensWithdrawable();
if (tokensToWithdraw > 0) {
stake.unlockTokens(tokensToWithdraw);
stake.release(tokensToWithdraw);
}
return tokensToWithdraw;
}
/**
* @dev Return all tokens available in stake.
* @param stake Staker struct
* @return Token amount
*/
function tokensAvailable(
Stakes.Staker memory stake
) internal pure returns (uint256) {
return stake.tokensStaked.sub(stake.tokensUsed());
}
/**
* @dev Return all tokens used in allocations and locked for withdrawal.
* @param stake Staker struct
* @return Token amount
*/
function tokensUsed(
Stakes.Staker memory stake
) internal pure returns (uint256) {
return stake.tokensAllocated.add(stake.tokensLocked);
}
/**
* @dev Return the amount of tokens staked which are not locked.
* @param stake Staker struct
* @return Token amount
*/
function tokensSecureStake(
Stakes.Staker memory stake
) internal pure returns (uint256) {
return stake.tokensStaked.sub(stake.tokensLocked);
}
/**
* @dev Tokens available for withdrawal after lock period.
* @param stake Staker struct
* @return Token amount
*/
function tokensWithdrawable(
Stakes.Staker memory stake
) internal view returns (uint256) {
if (
stake.tokensLockedUntil == 0 ||
block.number < stake.tokensLockedUntil
) {
return 0;
}
return stake.tokensLocked;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import './interfaces/HMTokenInterface.sol';
import './interfaces/IEscrow.sol';
import './interfaces/IRewardPool.sol';
import './interfaces/IStaking.sol';
import './libs/Stakes.sol';
import './utils/Math.sol';
/**
* @title Staking contract
* @dev The Staking contract allows Operator, Exchange Oracle, Recording Oracle and Reputation Oracle to stake to Escrow.
*/
contract Staking is IStaking, OwnableUpgradeable, UUPSUpgradeable {
using SafeMath for uint256;
using Stakes for Stakes.Staker;
// Token address
address public token;
// Reward pool address
address public override rewardPool;
// Minimum amount of tokens an staker needs to stake
uint256 public minimumStake;
// Time in blocks to unstake
uint32 public lockPeriod;
// Staker stakes: staker => Stake
mapping(address => Stakes.Staker) public stakes;
// List of stakers
address[] public stakers;
// Allocations : escrowAddress => Allocation
mapping(address => IStaking.Allocation) public allocations;
/**
* @dev Emitted when `staker` stake `tokens` amount.
*/
event StakeDeposited(address indexed staker, uint256 tokens);
/**
* @dev Emitted when `staker` unstaked and locked `tokens` amount `until` block.
*/
event StakeLocked(address indexed staker, uint256 tokens, uint256 until);
/**
* @dev Emitted when `staker` withdraws `tokens` staked.
*/
event StakeWithdrawn(address indexed staker, uint256 tokens);
/**
* @dev Emitted when `staker` was slashed for a total of `tokens` amount.
*/
event StakeSlashed(
address indexed staker,
uint256 tokens,
address indexed escrowAddress,
address slasher
);
/**
* @dev Emitted when `staker` allocated `tokens` amount to `escrowAddress`.
*/
event StakeAllocated(
address indexed staker,
uint256 tokens,
address indexed escrowAddress,
uint256 createdAt
);
/**
* @dev Emitted when `staker` close an allocation `escrowAddress`.
*/
event AllocationClosed(
address indexed staker,
uint256 tokens,
address indexed escrowAddress,
uint256 closedAt
);
/**
* @dev Emitted when `owner` set new value for `minimumStake`.
*/
event SetMinumumStake(uint256 indexed minimumStake);
/**
* @dev Emitted when `owner` set new value for `lockPeriod`.
*/
event SetLockPeriod(uint32 indexed lockPeriod);
/**
* @dev Emitted when `owner` set new value for `rewardPool`.
*/
event SetRewardPool(address indexed rewardPool);
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(
address _token,
uint256 _minimumStake,
uint32 _lockPeriod
) external payable virtual initializer {
__Ownable_init_unchained();
__Staking_init_unchained(_token, _minimumStake, _lockPeriod);
}
function __Staking_init_unchained(
address _token,
uint256 _minimumStake,
uint32 _lockPeriod
) internal onlyInitializing {
token = _token;
_setMinimumStake(_minimumStake);
_setLockPeriod(_lockPeriod);
}
/**
* @dev Set the minimum stake amount.
* @param _minimumStake Minimum stake
*/
function setMinimumStake(
uint256 _minimumStake
) external override onlyOwner {
_setMinimumStake(_minimumStake);
}
/**
* @dev Set the minimum stake amount.
* @param _minimumStake Minimum stake
*/
function _setMinimumStake(uint256 _minimumStake) private {
require(_minimumStake > 0, 'Must be a positive number');
minimumStake = _minimumStake;
emit SetMinumumStake(minimumStake);
}
/**
* @dev Set the lock period for unstaking.
* @param _lockPeriod Period in blocks to wait for token withdrawals after unstaking
*/
function setLockPeriod(uint32 _lockPeriod) external override onlyOwner {
_setLockPeriod(_lockPeriod);
}
/**
* @dev Set the lock period for unstaking.
* @param _lockPeriod Period in blocks to wait for token withdrawals after unstaking
*/
function _setLockPeriod(uint32 _lockPeriod) private {
require(_lockPeriod > 0, 'Must be a positive number');
lockPeriod = _lockPeriod;
emit SetLockPeriod(lockPeriod);
}
/**
* @dev Set the destionations of the rewards.
* @param _rewardPool Reward pool address
*/
function setRewardPool(address _rewardPool) external override onlyOwner {
_setRewardPool(_rewardPool);
}
/**
* @dev Set the destionations of the rewards.
* @param _rewardPool Reward pool address
*/
function _setRewardPool(address _rewardPool) private {
require(_rewardPool != address(0), 'Must be a valid address');
rewardPool = _rewardPool;
emit SetRewardPool(_rewardPool);
}
/**
* @dev Return if escrowAddress is use for allocation.
* @param _escrowAddress Address used as signer by the staker for an allocation
* @return True if _escrowAddress already used
*/
function isAllocation(
address _escrowAddress
) external view override returns (bool) {
return _getAllocationState(_escrowAddress) != AllocationState.Null;
}
/**
* @dev Getter that returns if an staker has any stake.
* @param _staker Address of the staker
* @return True if staker has staked tokens
*/
function hasStake(address _staker) external view override returns (bool) {
return stakes[_staker].tokensStaked > 0;
}
/**
* @dev Getter that returns if an staker has any available stake.
* @param _staker Address of the staker
* @return True if staker has available tokens staked
*/
function hasAvailableStake(
address _staker
) external view override returns (bool) {
return stakes[_staker].tokensAvailable() > 0;
}
/**
* @dev Return the allocation by escrow address.
* @param _escrowAddress Address used as allocation identifier
* @return Allocation data
*/
function getAllocation(
address _escrowAddress
) external view override returns (Allocation memory) {
return _getAllocation(_escrowAddress);
}
/**
* @dev Return the allocation by job ID.
* @param _escrowAddress Address used as allocation identifier
* @return Allocation data
*/
function _getAllocation(
address _escrowAddress
) private view returns (Allocation memory) {
return allocations[_escrowAddress];
}
/**
* @dev Return the current state of an allocation.
* @param _escrowAddress Address used as the allocation identifier
* @return AllocationState
*/
function getAllocationState(
address _escrowAddress
) external view override returns (AllocationState) {
return _getAllocationState(_escrowAddress);
}
/**
* @dev Return the current state of an allocation, partially depends on job status
* @param _escrowAddress Job identifier (Escrow address)
* @return AllocationState
*/
function _getAllocationState(
address _escrowAddress
) private view returns (AllocationState) {
Allocation storage allocation = allocations[_escrowAddress];
if (allocation.staker == address(0)) {
return AllocationState.Null;
}
IEscrow escrow = IEscrow(_escrowAddress);
IEscrow.EscrowStatuses escrowStatus = escrow.status();
if (
allocation.createdAt != 0 &&
allocation.tokens > 0 &&
escrowStatus == IEscrow.EscrowStatuses.Pending
) {
return AllocationState.Pending;
}
if (
allocation.closedAt == 0 &&
escrowStatus == IEscrow.EscrowStatuses.Launched
) {
return AllocationState.Active;
}
if (
allocation.closedAt == 0 &&
(escrowStatus == IEscrow.EscrowStatuses.Complete ||
escrowStatus == IEscrow.EscrowStatuses.Cancelled)
) {
return AllocationState.Completed;
}
return AllocationState.Closed;
}
/**
* @dev Get the total amount of tokens staked by the staker.
* @param _staker Address of the staker
* @return Amount of tokens staked by the staker
*/
function getStakedTokens(
address _staker
) external view override returns (uint256) {
return stakes[_staker].tokensStaked;
}
/**
* @dev Get staker data by the staker address.
* @param _staker Address of the staker
* @return Staker's data
*/
function getStaker(
address _staker
) external view override returns (Stakes.Staker memory) {
return stakes[_staker];
}
/**
* @dev Get list of stakers
* @return List of staker's addresses, and stake data
*/
function getListOfStakers()
external
view
override
returns (address[] memory, Stakes.Staker[] memory)
{
address[] memory _stakerAddresses = stakers;
uint256 _stakersCount = _stakerAddresses.length;
if (_stakersCount == 0) {
return (new address[](0), new Stakes.Staker[](0));
}
Stakes.Staker[] memory _stakers = new Stakes.Staker[](_stakersCount);
for (uint256 _i = 0; _i < _stakersCount; _i++) {
_stakers[_i] = stakes[_stakerAddresses[_i]];
}
return (_stakerAddresses, _stakers);
}
/**
* @dev Deposit tokens on the staker stake.
* @param _tokens Amount of tokens to stake
*/
function stake(uint256 _tokens) external override {
require(_tokens > 0, 'Must be a positive number');
Stakes.Staker memory staker = stakes[msg.sender];
require(
staker.tokensSecureStake().add(_tokens) >= minimumStake,
'Total stake is below the minimum threshold'
);
if (staker.tokensStaked == 0) {
staker = Stakes.Staker(0, 0, 0, 0);
stakes[msg.sender] = staker;
stakers.push(msg.sender);
}
_safeTransferFrom(msg.sender, address(this), _tokens);
stakes[msg.sender].deposit(_tokens);
emit StakeDeposited(msg.sender, _tokens);
}
/**
* @dev Unstake tokens from the staker stake, lock them until lock period expires.
* @param _tokens Amount of tokens to unstake
*/
function unstake(uint256 _tokens) external override {
Stakes.Staker storage staker = stakes[msg.sender];
require(_tokens > 0, 'Must be a positive number');
require(
staker.tokensAvailable() >= _tokens,
'Insufficient amount to unstake'
);
uint256 newStake = staker.tokensSecureStake().sub(_tokens);
require(
newStake == 0 || newStake >= minimumStake,
'Total stake is below the minimum threshold'
);
uint256 tokensToWithdraw = staker.tokensWithdrawable();
if (tokensToWithdraw > 0) {
_withdraw(msg.sender);
}
staker.lockTokens(_tokens, lockPeriod);
emit StakeLocked(
msg.sender,
staker.tokensLocked,
staker.tokensLockedUntil
);
}
/**
* @dev Withdraw staker tokens based on the locking period.
*/
function withdraw() external override {
_withdraw(msg.sender);
}
/**
* @dev Withdraw staker tokens once the lock period has passed.
* @param _staker Address of staker to withdraw funds from
*/
function _withdraw(address _staker) private {
uint256 tokensToWithdraw = stakes[_staker].withdrawTokens();
require(
tokensToWithdraw > 0,
'Stake has no available tokens for withdrawal'
);
_safeTransfer(_staker, tokensToWithdraw);
emit StakeWithdrawn(_staker, tokensToWithdraw);
}
/**
* @dev Slash the staker stake allocated to the escrow.
* @param _staker Address of staker to slash
* @param _escrowAddress Escrow address
* @param _tokens Amount of tokens to slash from the indexer stake
*/
function slash(
address _slasher,
address _staker,
address _escrowAddress,
uint256 _tokens
) external override onlyOwner {
require(_escrowAddress != address(0), 'Must be a valid address');
Stakes.Staker storage staker = stakes[_staker];
Allocation storage allocation = allocations[_escrowAddress];
require(_tokens > 0, 'Must be a positive number');
require(
_tokens <= allocation.tokens,
'Slash tokens exceed allocated ones'
);
staker.unallocate(_tokens);
allocation.tokens = allocation.tokens.sub(_tokens);
staker.release(_tokens);
_safeTransfer(rewardPool, _tokens);
// Keep record on Reward Pool
IRewardPool(rewardPool).addReward(
_escrowAddress,
_staker,
_slasher,
_tokens
);
emit StakeSlashed(_staker, _tokens, _escrowAddress, _slasher);
}
/**
* @dev Allocate available tokens to an escrow.
* @param _escrowAddress The allocationID will work to identify collected funds related to this allocation
* @param _tokens Amount of tokens to allocate
*/
function allocate(
address _escrowAddress,
uint256 _tokens
) external override {
_allocate(msg.sender, _escrowAddress, _tokens);
}
/**
* @dev Allocate available tokens to an escrow.
* @param _staker Staker address to allocate funds from.
* @param _escrowAddress The escrow address which collected funds related to this allocation
* @param _tokens Amount of tokens to allocate
*/
function _allocate(
address _staker,
address _escrowAddress,
uint256 _tokens
) private {
require(_escrowAddress != address(0), 'Must be a valid address');
require(
stakes[msg.sender].tokensAvailable() >= _tokens,
'Insufficient amount of tokens in the stake'
);
require(_tokens > 0, 'Must be a positive number');
require(
_getAllocationState(_escrowAddress) == AllocationState.Null,
'Allocation already exists'
);
Allocation memory allocation = Allocation(
_escrowAddress, // Escrow address
_staker, // Staker address
_tokens, // Tokens allocated
block.number, // createdAt
0 // closedAt
);
allocations[_escrowAddress] = allocation;
stakes[_staker].allocate(allocation.tokens);
emit StakeAllocated(
_staker,
allocation.tokens,
_escrowAddress,
allocation.createdAt
);
}
/**
* @dev Close an allocation and free the staked tokens.
* @param _escrowAddress The allocation identifier
*/
function closeAllocation(address _escrowAddress) external override {
require(_escrowAddress != address(0), 'Must be a valid address');
_closeAllocation(_escrowAddress);
}
/**
* @dev Close an allocation and free the staked tokens.
* @param _escrowAddress The allocation identifier
*/
function _closeAllocation(address _escrowAddress) private {
Allocation storage allocation = allocations[_escrowAddress];
require(
allocation.staker == msg.sender,
'Only the allocator can close the allocation'
);
AllocationState allocationState = _getAllocationState(_escrowAddress);
require(
allocationState == AllocationState.Completed,
'Allocation has no completed state'
);
allocation.closedAt = block.number;
uint256 diffInBlocks = Math.diffOrZero(
allocation.closedAt,
allocation.createdAt
);
require(diffInBlocks > 0, 'Allocation cannot be closed so early');
uint256 _tokens = allocation.tokens;
stakes[allocation.staker].unallocate(_tokens);
allocation.tokens = 0;
emit AllocationClosed(
allocation.staker,
_tokens,
_escrowAddress,
allocation.closedAt
);
}
function _safeTransfer(address to, uint256 value) internal {
SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(token), to, value);
}
function _safeTransferFrom(
address from,
address to,
uint256 value
) internal {
SafeERC20Upgradeable.safeTransferFrom(
IERC20Upgradeable(token),
from,
to,
value
);
}
// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address) internal override onlyOwner {}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[43] private __gap;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import './SafeMath.sol';
/**
* @title Math Library
* @notice A collection of functions to perform math operations
*/
library Math {
using SafeMath for uint256;
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Calculates the weighted average of two values pondering each of these
* values based on configured weights. The contribution of each value N is
* weightN/(weightA + weightB).
* @param valueA The amount for value A
* @param weightA The weight to use for value A
* @param valueB The amount for value B
* @param weightB The weight to use for value B
*/
function weightedAverage(
uint256 valueA,
uint256 weightA,
uint256 valueB,
uint256 weightB
) internal pure returns (uint256) {
return
valueA.mul(weightA).add(valueB.mul(weightB)).div(
weightA.add(weightB)
);
}
/**
* @dev Returns the difference between two numbers or zero if negative.
*/
function diffOrZero(uint256 x, uint256 y) internal pure returns (uint256) {
return (x > y) ? x.sub(y) : 0;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(
uint256 value,
Rounding rounding
) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return
result +
(rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(
uint256 value,
Rounding rounding
) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return
result +
(rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
/**
* @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, 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) {
return sub(a, b, 'SafeMath: subtraction overflow');
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* 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);
uint256 c = a - b;
return c;
}
/**
* @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) {
// 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 0;
}
uint256 c = a * b;
require(c / a == b, 'SafeMath: multiplication overflow');
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts 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) {
return div(a, b, 'SafeMath: division by zero');
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message 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,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts 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) {
return mod(a, b, 'SafeMath: modulo by zero');
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message 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,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}