Transaction Hash:
Block:
22111205 at Mar-23-2025 05:52:11 PM +UTC
Transaction Fee:
0.000173840111657677 ETH
$0.44
Gas Used:
130,523 Gas / 1.331873399 Gwei
Emitted Events:
52 |
TransparentUpgradeableProxy.0xa803098eab41616e8c09907603003b82c457356a707199ad558994e618783053( 0xa803098eab41616e8c09907603003b82c457356a707199ad558994e618783053, 00000000000000000000000000000000000000000003b0168027729ebd31ebd6 )
|
53 |
AdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x00000000000000000000000056968bb1168b0e9314dca1eb3d1e7aaf0d32263e, 0x000000000000000000000000dc718fdd9809b1d3cc4728bd733845104d70619a, 0000000000000000000000000000000000000000000000092381087debdf32d0 )
|
54 |
TransparentUpgradeableProxy.0x47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4( 0x47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4, 0x000000000000000000000000dc718fdd9809b1d3cc4728bd733845104d70619a, 0000000000000000000000000000000000000000000000092381087debdf32d0 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x56968bB1...f0d32263e | |||||
0xCC4304A3...f52e44EFe | |||||
0xDC718FDd...04d70619A |
0.000419353807130558 Eth
Nonce: 143
|
0.000245513695472881 Eth
Nonce: 144
| 0.000173840111657677 | ||
0xe688b84b...2CDB71127
Miner
| (Fee Recipient: 0xe68...127) | 3,376.373421839360262889 Eth | 3,376.373530066070948634 Eth | 0.000108226710685745 |
Execution Trace
TransparentUpgradeableProxy.CALL( )
LockedStaking.DELEGATECALL( )
AdminUpgradeabilityProxy.a9059cbb( )
-
SwapToken.transfer( recipient=0xDC718FDd9809b1D3cC4728Bd733845104d70619A, amount=168579032063630324432 ) => ( True )
-
File 1 of 4: TransparentUpgradeableProxy
File 2 of 4: AdminUpgradeabilityProxy
File 3 of 4: LockedStaking
File 4 of 4: SwapToken
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins. contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy { constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {} } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../Proxy.sol"; import "./ERC1967Upgrade.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializating the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) payable { assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); _upgradeToAndCall(_logic, _data, false); } /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../ERC1967/ERC1967Proxy.sol"; /** * @dev This contract implements a proxy that is upgradeable by an admin. * * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector * clashing], which can potentially be used in an attack, this contract uses the * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two * things that go hand in hand: * * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if * that call matches one of the admin functions exposed by the proxy itself. * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the * implementation. If the admin tries to call a function on the implementation it will fail with an error that says * "admin cannot fallback to proxy target". * * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due * to sudden errors when trying to call a function from the proxy implementation. * * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. */ constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) { assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); _changeAdmin(admin_); } /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. */ modifier ifAdmin() { if (msg.sender == _getAdmin()) { _; } else { _fallback(); } } /** * @dev Returns the current admin. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function admin() external ifAdmin returns (address admin_) { admin_ = _getAdmin(); } /** * @dev Returns the current implementation. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function implementation() external ifAdmin returns (address implementation_) { implementation_ = _implementation(); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. * * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ function changeAdmin(address newAdmin) external virtual ifAdmin { _changeAdmin(newAdmin); } /** * @dev Upgrade the implementation of the proxy. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeToAndCall(newImplementation, bytes(""), false); } /** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. */ function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin { _upgradeToAndCall(newImplementation, data, true); } /** * @dev Returns the current admin. */ function _admin() internal view virtual returns (address) { return _getAdmin(); } /** * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. */ function _beforeFallback() internal virtual override { require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); super._beforeFallback(); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./TransparentUpgradeableProxy.sol"; import "../../access/Ownable.sol"; /** * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. */ contract ProxyAdmin is Ownable { /** * @dev Returns the current implementation of `proxy`. * * Requirements: * * - This contract must be the admin of `proxy`. */ function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); require(success); return abi.decode(returndata, (address)); } /** * @dev Returns the current admin of `proxy`. * * Requirements: * * - This contract must be the admin of `proxy`. */ function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); require(success); return abi.decode(returndata, (address)); } /** * @dev Changes the admin of `proxy` to `newAdmin`. * * Requirements: * * - This contract must be the current admin of `proxy`. */ function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { proxy.changeAdmin(newAdmin); } /** * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. * * Requirements: * * - This contract must be the admin of `proxy`. */ function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { proxy.upgradeTo(implementation); } /** * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See * {TransparentUpgradeableProxy-upgradeToAndCall}. * * Requirements: * * - This contract must be the admin of `proxy`. */ function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner { proxy.upgradeToAndCall{value: msg.value}(implementation, data); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { // solhint-disable-next-line no-inline-assembly assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback () external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive () external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overriden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual { } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.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._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // 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; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.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 { _setImplementation(newImplementation); emit Upgraded(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal { address oldImplementation = _getImplementation(); // Initial upgrade and setup call _setImplementation(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } // Perform rollback test if not already in progress StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT); if (!rollbackTesting.value) { // Trigger rollback using upgradeTo from the new implementation rollbackTesting.value = true; Address.functionDelegateCall( newImplementation, abi.encodeWithSignature( "upgradeTo(address)", oldImplementation ) ); rollbackTesting.value = false; // Check rollback was effective require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades"); // Finally reset to the new implementation and log the upgrade _setImplementation(newImplementation); emit Upgraded(newImplementation); } } /** * @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) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } /** * @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 Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.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"); StorageSlot.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 Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require( Address.isContract(newBeacon), "ERC1967: new beacon is not a contract" ); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @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 pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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://diligence.consensys.net/posts/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.5.11/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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // SPDX-License-Identifier: MIT 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: * ``` * 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`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.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 Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = 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"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /* * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../ERC1967/ERC1967Upgrade.sol"; /** * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify * continuation of the upgradability. * * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is ERC1967Upgrade { function upgradeTo(address newImplementation) external virtual { _authorizeUpgrade(newImplementation); _upgradeToAndCallSecure(newImplementation, bytes(""), false); } function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual { _authorizeUpgrade(newImplementation); _upgradeToAndCallSecure(newImplementation, data, true); } function _authorizeUpgrade(address newImplementation) internal virtual; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; abstract contract Proxiable is UUPSUpgradeable { function _authorizeUpgrade(address newImplementation) internal override { _beforeUpgrade(newImplementation); } function _beforeUpgrade(address newImplementation) internal virtual; } contract ChildOfProxiable is Proxiable { function _beforeUpgrade(address newImplementation) internal virtual override {} }
File 2 of 4: AdminUpgradeabilityProxy
// File: @openzeppelin/upgrades/contracts/upgradeability/Proxy.sol pragma solidity ^0.5.0; /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: @openzeppelin/upgrades/contracts/utils/Address.sol pragma solidity ^0.5.0; /** * Utility library of inline functions on addresses * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version. */ library OpenZeppelinUpgradesAddress { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param account address of the account to check * @return whether the target address is a contract */ function isContract(address account) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: @openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseUpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract BaseUpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address indexed implementation); /** * @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; /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) internal { require(OpenZeppelinUpgradesAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: @openzeppelin/upgrades/contracts/upgradeability/UpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title UpgradeabilityProxy * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing * implementation and init data. */ contract UpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Contract constructor. * @param _logic Address of the initial implementation. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, bytes memory _data) public payable { assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)); _setImplementation(_logic); if(_data.length > 0) { (bool success,) = _logic.delegatecall(_data); require(success); } } } // File: @openzeppelin/upgrades/contracts/upgradeability/BaseAdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseAdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @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 Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @return The address of the proxy admin. */ function admin() external ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ function changeAdmin(address newAdmin) external ifAdmin { require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin { _upgradeTo(newImplementation); (bool success,) = newImplementation.delegatecall(data); require(success); } /** * @return The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // File: @openzeppelin/upgrades/contracts/upgradeability/AdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title AdminUpgradeabilityProxy * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for * initializing the implementation, admin, and init data. */ contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy { /** * Contract constructor. * @param _logic address of the initial implementation. * @param _admin Address of the proxy administrator. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable { assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)); _setAdmin(_admin); } }
File 3 of 4: LockedStaking
//SPDX-License-Identifier: Unlicense pragma solidity 0.8.17; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) /** * @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.5.11/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 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); } } } /** * @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; } } // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) // OpenZeppelin Contracts v4.4.1 (utils/Context.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; } /** * @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; } /** * @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 anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing 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; } // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/BitMaps.sol) /** * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. */ library BitMaps { struct BitMap { mapping(uint256 => uint256) _data; } /** * @dev Returns whether the bit at `index` is set. */ function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); return bitmap._data[bucket] & mask != 0; } /** * @dev Sets the bit at `index` to the boolean `value`. */ function setTo(BitMap storage bitmap, uint256 index, bool value) internal { if (value) { set(bitmap, index); } else { unset(bitmap, index); } } /** * @dev Sets the bit at `index`. */ function set(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] |= mask; } /** * @dev Unsets the bit at `index`. */ function unset(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] &= ~mask; } } /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } } /// @notice Optimized sorts and operations for sorted arrays. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Sort.sol) library LibSort { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INSERTION SORT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // - Faster on small arrays (32 or lesser elements). // - Faster on almost sorted arrays. // - Smaller bytecode. // - May be suitable for view functions intended for off-chain querying. /// @dev Sorts the array in-place with insertion sort. function insertionSort(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let n := mload(a) // Length of `a`. mstore(a, 0) // For insertion sort's inner loop to terminate. let h := add(a, shl(5, n)) // High slot. let s := 0x20 let w := not(31) for { let i := add(a, s) } 1 {} { i := add(i, s) if gt(i, h) { break } let k := mload(i) // Key. let j := add(i, w) // The slot before the current slot. let v := mload(j) // The value of `j`. if iszero(gt(v, k)) { continue } for {} 1 {} { mstore(add(j, s), v) j := add(j, w) // `sub(j, 0x20)`. v := mload(j) if iszero(gt(v, k)) { break } } mstore(add(j, s), k) } mstore(a, n) // Restore the length of `a`. } } /// @dev Sorts the array in-place with insertion sort. function insertionSort(int256[] memory a) internal pure { _convertTwosComplement(a); insertionSort(_toUints(a)); _convertTwosComplement(a); } /// @dev Sorts the array in-place with insertion sort. function insertionSort(address[] memory a) internal pure { insertionSort(_toUints(a)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTRO-QUICKSORT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // - Faster on larger arrays (more than 32 elements). // - Robust performance. // - Larger bytecode. /// @dev Sorts the array in-place with intro-quicksort. function sort(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { let w := not(31) let s := 0x20 let n := mload(a) // Length of `a`. mstore(a, 0) // For insertion sort's inner loop to terminate. // Let the stack be the start of the free memory. let stack := mload(0x40) for {} iszero(lt(n, 2)) {} { // Push `l` and `h` to the stack. // The `shl` by 5 is equivalent to multiplying by `0x20`. let l := add(a, s) let h := add(a, shl(5, n)) let j := l // forgefmt: disable-next-item for {} iszero(or(eq(j, h), gt(mload(j), mload(add(j, s))))) {} { j := add(j, s) } // If the array is already sorted. if eq(j, h) { break } j := h // forgefmt: disable-next-item for {} iszero(gt(mload(j), mload(add(j, w)))) {} { j := add(j, w) // `sub(j, 0x20)`. } // If the array is reversed sorted. if eq(j, l) { for {} 1 {} { let t := mload(l) mstore(l, mload(h)) mstore(h, t) h := add(h, w) // `sub(h, 0x20)`. l := add(l, s) if iszero(lt(l, h)) { break } } break } // Push `l` and `h` onto the stack. mstore(stack, l) mstore(add(stack, s), h) stack := add(stack, 0x40) break } for { let stackBottom := mload(0x40) } iszero(eq(stack, stackBottom)) {} { // Pop `l` and `h` from the stack. stack := sub(stack, 0x40) let l := mload(stack) let h := mload(add(stack, s)) // Do insertion sort if `h - l <= 0x20 * 12`. // Threshold is fine-tuned via trial and error. if iszero(gt(sub(h, l), 0x180)) { // Hardcode sort the first 2 elements. let i := add(l, s) if iszero(lt(mload(l), mload(i))) { let t := mload(i) mstore(i, mload(l)) mstore(l, t) } for {} 1 {} { i := add(i, s) if gt(i, h) { break } let k := mload(i) // Key. let j := add(i, w) // The slot before the current slot. let v := mload(j) // The value of `j`. if iszero(gt(v, k)) { continue } for {} 1 {} { mstore(add(j, s), v) j := add(j, w) v := mload(j) if iszero(gt(v, k)) { break } } mstore(add(j, s), k) } continue } // Pivot slot is the average of `l` and `h`. let p := add(shl(5, shr(6, add(l, h))), and(31, l)) // Median of 3 with sorting. { let e0 := mload(l) let e2 := mload(h) let e1 := mload(p) if iszero(lt(e0, e1)) { let t := e0 e0 := e1 e1 := t } if iszero(lt(e0, e2)) { let t := e0 e0 := e2 e2 := t } if iszero(lt(e1, e2)) { let t := e1 e1 := e2 e2 := t } mstore(p, e1) mstore(h, e2) mstore(l, e0) } // Hoare's partition. { // The value of the pivot slot. let x := mload(p) p := h for { let i := l } 1 {} { for {} 1 {} { i := add(i, s) if iszero(gt(x, mload(i))) { break } } let j := p for {} 1 {} { j := add(j, w) if iszero(lt(x, mload(j))) { break } } p := j if iszero(lt(i, p)) { break } // Swap slots `i` and `p`. let t := mload(i) mstore(i, mload(p)) mstore(p, t) } } // If slice on right of pivot is non-empty, push onto stack. { mstore(stack, add(p, s)) // Skip `mstore(add(stack, 0x20), h)`, as it is already on the stack. stack := add(stack, shl(6, lt(add(p, s), h))) } // If slice on left of pivot is non-empty, push onto stack. { mstore(stack, l) mstore(add(stack, s), p) stack := add(stack, shl(6, gt(p, l))) } } mstore(a, n) // Restore the length of `a`. } } /// @dev Sorts the array in-place with intro-quicksort. function sort(int256[] memory a) internal pure { _convertTwosComplement(a); sort(_toUints(a)); _convertTwosComplement(a); } /// @dev Sorts the array in-place with intro-quicksort. function sort(address[] memory a) internal pure { sort(_toUints(a)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER USEFUL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, the `uniquifySorted` methods will not revert if the // array is not sorted -- it will simply remove consecutive duplicate elements. /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { // If the length of `a` is greater than 1. if iszero(lt(mload(a), 2)) { let x := add(a, 0x20) let y := add(a, 0x40) let end := add(a, shl(5, add(mload(a), 1))) for {} 1 {} { if iszero(eq(mload(x), mload(y))) { x := add(x, 0x20) mstore(x, mload(y)) } y := add(y, 0x20) if eq(y, end) { break } } mstore(a, shr(5, sub(x, a))) } } } /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(int256[] memory a) internal pure { uniquifySorted(_toUints(a)); } /// @dev Removes duplicate elements from a ascendingly sorted memory array. function uniquifySorted(address[] memory a) internal pure { uniquifySorted(_toUints(a)); } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function searchSorted(uint256[] memory a, uint256 needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(a, needle, 0); } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function searchSorted(int256[] memory a, int256 needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(_toUints(a), uint256(needle), 1 << 255); } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function searchSorted(address[] memory a, address needle) internal pure returns (bool found, uint256 index) { (found, index) = _searchSorted(_toUints(a), uint256(uint160(needle)), 0); } /// @dev Reverses the array in-place. function reverse(uint256[] memory a) internal pure { /// @solidity memory-safe-assembly assembly { if iszero(lt(mload(a), 2)) { let s := 0x20 let w := not(31) let h := add(a, shl(5, mload(a))) for { a := add(a, s) } 1 {} { let t := mload(a) mstore(a, mload(h)) mstore(h, t) h := add(h, w) a := add(a, s) if iszero(lt(a, h)) { break } } } } } /// @dev Reverses the array in-place. function reverse(int256[] memory a) internal pure { reverse(_toUints(a)); } /// @dev Reverses the array in-place. function reverse(address[] memory a) internal pure { reverse(_toUints(a)); } /// @dev Returns whether the array is sorted in ascending order. function isSorted(uint256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := iszero(gt(p, mload(a))) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is sorted in ascending order. function isSorted(int256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := iszero(sgt(p, mload(a))) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is sorted in ascending order. function isSorted(address[] memory a) internal pure returns (bool result) { result = isSorted(_toUints(a)); } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := lt(p, mload(a)) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if iszero(lt(mload(a), 2)) { let end := add(a, shl(5, mload(a))) for { a := add(a, 0x20) } 1 {} { let p := mload(a) a := add(a, 0x20) result := slt(p, mload(a)) if iszero(mul(result, xor(a, end))) { break } } } } } /// @dev Returns whether the array is strictly ascending (sorted and uniquified). function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) { result = isSortedAndUniquified(_toUints(a)); } /// @dev Returns the sorted set difference of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _difference(a, b, 0); } /// @dev Returns the sorted set difference between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_difference(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set difference between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function difference(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_difference(_toUints(a), _toUints(b), 0)); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _intersection(a, b, 0); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_intersection(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function intersection(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_intersection(_toUints(a), _toUints(b), 0)); } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) { c = _union(a, b, 0); } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(int256[] memory a, int256[] memory b) internal pure returns (int256[] memory c) { c = _toInts(_union(_toUints(a), _toUints(b), 1 << 255)); } /// @dev Returns the sorted set union between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function union(address[] memory a, address[] memory b) internal pure returns (address[] memory c) { c = _toAddresses(_union(_toUints(a), _toUints(b), 0)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Reinterpret cast to an uint256 array. function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Reinterpret cast to an uint256 array. function _toUints(address[] memory a) private pure returns (uint256[] memory casted) { /// @solidity memory-safe-assembly assembly { // As any address written to memory will have the upper 96 bits // of the word zeroized (as per Solidity spec), we can directly // compare these addresses as if they are whole uint256 words. casted := a } } /// @dev Reinterpret cast to an int array. function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Reinterpret cast to an address array. function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) { /// @solidity memory-safe-assembly assembly { casted := a } } /// @dev Converts an array of signed two-complement integers /// to unsigned integers suitable for sorting. function _convertTwosComplement(int256[] memory a) private pure { /// @solidity memory-safe-assembly assembly { let w := shl(255, 1) for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} { a := add(a, 0x20) mstore(a, add(mload(a), w)) } } } /// @dev Returns whether `a` contains `needle`, /// and the index of the nearest element less than or equal to `needle`. function _searchSorted(uint256[] memory a, uint256 needle, uint256 signed) private pure returns (bool found, uint256 index) { /// @solidity memory-safe-assembly assembly { let m := 0 // Middle slot. let s := 0x20 let l := add(a, s) // Slot of the start of search. let h := add(a, shl(5, mload(a))) // Slot of the end of search. for { needle := add(signed, needle) } 1 {} { // Average of `l` and `h`. m := add(shl(5, shr(6, add(l, h))), and(31, l)) let t := add(signed, mload(m)) found := eq(t, needle) if or(gt(l, h), found) { break } // Decide whether to search the left or right half. if iszero(gt(needle, t)) { h := sub(m, s) continue } l := add(m, s) } // `m` will be less than `add(a, 0x20)` in the case of an empty array, // or when the value is less than the smallest value in the array. let t := iszero(lt(m, add(a, s))) index := shr(5, mul(sub(m, add(a, s)), t)) found := and(found, t) } } /// @dev Returns the sorted set difference of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _difference(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { b := add(b, s) continue } k := add(k, s) mstore(k, u) a := add(a, s) } for {} iszero(gt(a, aEnd)) {} { k := add(k, s) mstore(k, mload(a)) a := add(a, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } /// @dev Returns the sorted set intersection between `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _intersection(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { k := add(k, s) mstore(k, u) a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { b := add(b, s) continue } a := add(a, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } /// @dev Returns the sorted set union of `a` and `b`. /// Note: Behaviour is undefined if inputs are not sorted and uniquified. function _union(uint256[] memory a, uint256[] memory b, uint256 signed) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { let s := 0x20 let aEnd := add(a, shl(5, mload(a))) let bEnd := add(b, shl(5, mload(b))) c := mload(0x40) // Set `c` to the free memory pointer. a := add(a, s) b := add(b, s) let k := c for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} { let u := mload(a) let v := mload(b) if iszero(xor(u, v)) { k := add(k, s) mstore(k, u) a := add(a, s) b := add(b, s) continue } if iszero(lt(add(u, signed), add(v, signed))) { k := add(k, s) mstore(k, v) b := add(b, s) continue } k := add(k, s) mstore(k, u) a := add(a, s) } for {} iszero(gt(a, aEnd)) {} { k := add(k, s) mstore(k, mload(a)) a := add(a, s) } for {} iszero(gt(b, bEnd)) {} { k := add(k, s) mstore(k, mload(b)) b := add(b, s) } mstore(c, shr(5, sub(k, c))) // Store the length of `c`. mstore(0x40, add(k, s)) // Allocate the memory for `c`. } } } /*/////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ error MustProlongLock(uint256 oldDuration, uint256 newDuration); error AmountIsZero(); error TransferFailed(); error NothingToClaim(); error LockStillActive(); error DurationOutOfBounds(uint256 duration); error UpdateToSmallerMultiplier(uint16 oldMultiplier, uint16 newMultiplier); error ZeroAddress(); error ZeroPrecision(); error ZeroAmount(); error MaxLocksSucceeded(); error MaxRewardsSucceeded(); error CanOnlyAddFutureRewards(); error NotRewardoor(); error CantAutoCompound(); error AlreadyAutoCompound(); error NotAutoCompoundEnabled(); error RewardStartEqEnd(); error IntervalNotRoundedWithEpoch(); error CantChangePast(); error CantUpdateExpiredLock(); contract LockedStaking is Initializable, OwnableUpgradeable { using BitMaps for BitMaps.BitMap; using FixedPointMathLib for uint256; /*/////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event LockAdded(address indexed from, uint208 amount, uint32 end, uint16 multiplier); event LockUpdated(address indexed from, uint8 index, uint208 amount, uint32 end, uint16 multiplier); event Unlock(address indexed from, uint256 amount, uint256 index); event Claim(address indexed from, uint256 amount); event RewardAdded(uint256 start, uint256 end, uint256 amountPerSecond); event RewardUpdated(uint256 index, uint256 start, uint256 end, uint256 amountPerSecond); event RewardRemoved(uint256 index); event AutoCompoundEnabled(address indexed from, uint256 index, uint256 shares); event AutoCompoundDisabled(address indexed from, uint256 index, uint256 amount); event AutoCompounded(uint256 compoundAmount); event RewardoorSet(address indexed rewardoor, bool value); /*/////////////////////////////////////////////////////////////// IMMUTABLES & CONSTANTS //////////////////////////////////////////////////////////////*/ uint256 public constant MAX_LOCK_COUNT = 5; uint256 public constant MAX_REWARD_COUNT = 5; uint256 public constant MAX_MULTIPLIER = 998; uint256 public constant EPOCH_DURATION = 8 * 60 * 60; uint256 public constant ALGORITHM_THRESHOLD_IN_EPOCHS = 5; /*/////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ struct Lock { uint16 multiplier; uint32 end; uint208 amount; } struct Reward { uint32 start; uint32 end; uint192 amountPerSecond; } struct TotalReward { uint256 start; uint256 end; uint256 epochReward; } struct CompoundVars { uint256 from; uint256 to; uint256 currentPeriod; uint256 compoundClaimable; uint256 epochRewards; uint256 currCompLastAccRewardWeight; } /*/////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ IERC20 public swapToken; uint256 public precision; // no longer used but kept for upgradeability Reward[] public rewards; mapping(address => Lock[]) public locks; mapping(address => uint256) public userLastAccRewardsWeight; uint256 public lastRewardUpdate; uint256 public totalScore; uint256 public accRewardWeight; mapping(address => bool) public rewardoors; BitMaps.BitMap private lockCompoundedBitMap; uint256 public compoundAmount; uint256 public compoundShares; uint256 public compoundLastAccRewardWeight; /*/////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ modifier onlyRewardoor() { if (!rewardoors[msg.sender]) revert NotRewardoor(); _; } constructor() { _disableInitializers(); } /*/////////////////////////////////////////////////////////////// EXTERNAL //////////////////////////////////////////////////////////////*/ function initialize(address _swapToken, uint256 _precision) external initializer { if (_swapToken == address(0)) revert ZeroAddress(); if (_precision == 0) revert ZeroPrecision(); swapToken = IERC20(_swapToken); precision = _precision; __Ownable_init(); } /// @notice Adds new reward function addReward( uint32 start, uint32 end, uint192 amountPerSecond ) external onlyRewardoor { if (rewards.length == MAX_REWARD_COUNT) revert MaxRewardsSucceeded(); if (amountPerSecond == 0) revert AmountIsZero(); if (start == end) revert RewardStartEqEnd(); if (start < block.timestamp || end < block.timestamp) revert CanOnlyAddFutureRewards(); if (start % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); if (end % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); rewards.push(Reward(start, end, amountPerSecond)); if (!IERC20(swapToken).transferFrom(msg.sender, address(this), (end - start) * amountPerSecond)) revert TransferFailed(); emit RewardAdded(start, end, amountPerSecond); } /// @notice Removes existing reward and sends remaining reward to owner function removeReward(uint256 index) external onlyRewardoor { updateRewardsWeight(); Reward memory reward = rewards[index]; rewards[index] = rewards[rewards.length - 1]; rewards.pop(); // if rewards are not unlocked completely, send remaining to owner if (reward.end > block.timestamp) { uint256 lockedRewards = (reward.end - max(block.timestamp, reward.start)) * reward.amountPerSecond; if (!IERC20(swapToken).transfer(msg.sender, lockedRewards)) revert TransferFailed(); } emit RewardRemoved(index); } /// @notice Updates existing reward, cant change reward start if its already started function updateReward( uint256 index, uint256 newStart, uint256 newEnd, uint256 newAmountPerSecond ) external onlyRewardoor { if (newStart % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); if (newEnd % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch(); if (newAmountPerSecond == 0) revert ZeroAmount(); updateRewardsWeight(); Reward storage reward = rewards[index]; uint256 oldEnd = reward.end; if (oldEnd < block.timestamp) revert CantChangePast(); if (newEnd < block.timestamp) revert CanOnlyAddFutureRewards(); uint256 oldStart = reward.start; if ((oldStart < block.timestamp || newStart < block.timestamp) && newStart != oldStart) revert CantChangePast(); uint256 newTotalRewards = (newEnd - newStart) * newAmountPerSecond; uint256 oldTotalRewards = (oldEnd - oldStart) * reward.amountPerSecond; if (newStart != oldStart) { reward.start = uint32(newStart); } reward.end = uint32(newEnd); reward.amountPerSecond = uint192(newAmountPerSecond); if (oldTotalRewards > newTotalRewards) { if (!IERC20(swapToken).transfer(msg.sender, oldTotalRewards - newTotalRewards)) revert TransferFailed(); } else if (oldTotalRewards != newTotalRewards) { if (!IERC20(swapToken).transferFrom(msg.sender, address(this), newTotalRewards - oldTotalRewards)) revert TransferFailed(); } emit RewardUpdated(index, newStart, newEnd, newAmountPerSecond); } /// @notice Sets address eligibility to add/update rewards function setRewardoor(address addr, bool value) external onlyOwner { rewardoors[addr] = value; emit RewardoorSet(addr, value); } /// @notice Creates new lock for a user, adds potential claimable amount to it function addLock(uint208 amount, uint256 duration) external { if (amount == 0) revert AmountIsZero(); if (locks[msg.sender].length == MAX_LOCK_COUNT) revert MaxLocksSucceeded(); uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); uint256 addedAmount = claimable + amount; userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; uint32 end = uint32(block.timestamp + duration); uint16 multiplier = getDurationMultiplier(duration); locks[msg.sender].push(Lock(multiplier, end, uint208(addedAmount))); totalScore += multiplier * addedAmount; if (!IERC20(swapToken).transferFrom(msg.sender, address(this), amount)) revert TransferFailed(); if (claimable != 0) { emit Claim(msg.sender, claimable); } emit LockAdded(msg.sender, uint208(addedAmount), end, multiplier); } /// @notice adds claimable to current lock, keeping the same end function compound(uint8 index) external { uint256 bitMapIndex = getBitMapIndex(index, msg.sender); if (lockCompoundedBitMap.get(bitMapIndex)) revert AlreadyAutoCompound(); uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); if (claimable == 0) revert NothingToClaim(); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; Lock storage lock = locks[msg.sender][index]; if (lock.end < block.timestamp) revert CantUpdateExpiredLock(); uint208 newAmount = uint208(lock.amount + claimable); uint16 multiplier = lock.multiplier; lock.amount = newAmount; totalScore += claimable * multiplier; emit Claim(msg.sender, claimable); emit LockUpdated(msg.sender, index, newAmount, lock.end, multiplier); } /// @notice adds amount + potential claimable to existing lock, keeping the same end /// @dev if lock has auto compound enabled, adjusts the compoundLastAccRewardWeight to have the same current claimable amount function updateLockAmount(uint256 index, uint208 amount) external { if (amount == 0) revert AmountIsZero(); uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); uint256 addedAmount = amount + claimable; Lock storage lock = locks[msg.sender][index]; if (lock.end < block.timestamp) revert CantUpdateExpiredLock(); uint208 newAmount; if (lockCompoundedBitMap.get(getBitMapIndex(index, msg.sender))) { uint256 oldCompoundAmount = compoundAmount; compoundLastAccRewardWeight = calculateCompAccRewardWeightIn( oldCompoundAmount, addedAmount, newAccRewardsWeight, compoundLastAccRewardWeight ); uint256 newShares = convertToAutoCompoundShares(addedAmount); compoundAmount = oldCompoundAmount + addedAmount; compoundShares += newShares; newAmount = uint208(lock.amount + newShares); } else { newAmount = uint208(lock.amount + addedAmount); } lock.amount = newAmount; uint16 multiplier = lock.multiplier; userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; totalScore += addedAmount * multiplier; if (!IERC20(swapToken).transferFrom(msg.sender, address(this), amount)) revert TransferFailed(); if (claimable != 0) { emit Claim(msg.sender, claimable); } emit LockUpdated(msg.sender, uint8(index), newAmount, lock.end, multiplier); } /// @notice claims for current locks and increases duration of existing lock function updateLockDuration(uint8 index, uint256 duration) external { uint256 newAccRewardsWeight = updateRewardsWeight(); Lock storage lock = locks[msg.sender][index]; uint32 end = uint32(block.timestamp + duration); if (lock.end >= end) revert MustProlongLock(lock.end, end); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; uint16 multiplier = getDurationMultiplier(duration); lock.end = end; uint16 oldMultiplier = lock.multiplier; if (oldMultiplier > multiplier) revert UpdateToSmallerMultiplier(oldMultiplier, multiplier); lock.multiplier = multiplier; uint208 amount = lock.amount; totalScore += (multiplier - oldMultiplier) * amount; if (claimable != 0) { if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed(); emit Claim(msg.sender, claimable); } emit LockUpdated(msg.sender, index, amount, end, multiplier); } /// @notice claims for current locks function claim() external { uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); if (claimable == 0) revert NothingToClaim(); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed(); emit Claim(msg.sender, claimable); } /// @notice returns locked amount + potential claimable to user and deletes lock from array function unlock(uint256 index) external { uint256 newAccRewardsWeight = updateRewardsWeight(); Lock storage lock = locks[msg.sender][index]; if (lock.end > block.timestamp) revert LockStillActive(); uint256 bitMapIndex = getBitMapIndex(index, msg.sender); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); bool isLockAutoCompound = lockCompoundedBitMap.get(bitMapIndex); uint256 amount; if (isLockAutoCompound) { uint256 shares = lock.amount; amount = convertToAutoCompoundAssets(shares); compoundLastAccRewardWeight = calculateCompAccRewardWeightOut( compoundAmount, amount, newAccRewardsWeight, compoundLastAccRewardWeight ); compoundAmount -= amount; compoundShares -= shares; } else { amount = lock.amount; } userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; unchecked { totalScore -= amount * lock.multiplier; } uint256 lastLockIndex; unchecked { lastLockIndex = locks[msg.sender].length - 1; } if (index == lastLockIndex) { if (isLockAutoCompound) { lockCompoundedBitMap.unset(bitMapIndex); } } else { locks[msg.sender][index] = locks[msg.sender][lastLockIndex]; uint256 lastLockBitMapIndex = getBitMapIndex(lastLockIndex, msg.sender); if (isLockAutoCompound) { if (!lockCompoundedBitMap.get(lastLockBitMapIndex)) { lockCompoundedBitMap.unset(bitMapIndex); } else { lockCompoundedBitMap.unset(lastLockBitMapIndex); } } else if (lockCompoundedBitMap.get(lastLockBitMapIndex)) { lockCompoundedBitMap.set(bitMapIndex); lockCompoundedBitMap.unset(lastLockBitMapIndex); } } locks[msg.sender].pop(); if (!IERC20(swapToken).transfer(msg.sender, amount + claimable)) revert TransferFailed(); if (claimable != 0) { emit Claim(msg.sender, claimable); } emit Unlock(msg.sender, amount, index); } /// @notice enables auto compound for existing lock, automatically adding all future rewards to principal /// @dev adjusts compoundLastAccRewardWeight so that current compound claimable remains the same function enableAutoCompound(uint256 index) external { uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); Lock storage lock = locks[msg.sender][index]; if (lock.multiplier != MAX_MULTIPLIER) revert CantAutoCompound(); uint256 bitMapIndex = getBitMapIndex(index, msg.sender); if (lockCompoundedBitMap.get(bitMapIndex)) revert AlreadyAutoCompound(); lockCompoundedBitMap.set(bitMapIndex); uint256 lockAmount = lock.amount + claimable; uint256 shares = convertToAutoCompoundShares(lockAmount); compoundLastAccRewardWeight = calculateCompAccRewardWeightIn( compoundAmount, lockAmount, newAccRewardsWeight, compoundLastAccRewardWeight ); compoundAmount += lockAmount; compoundShares += shares; lock.amount = uint208(shares); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; if (claimable != 0) { totalScore += claimable * MAX_MULTIPLIER; emit Claim(msg.sender, claimable); } emit AutoCompoundEnabled(msg.sender, index, shares); } /// @notice disables auto compound for existing lock, stops automatically adding all future rewards to principal /// @dev adjusts compoundLastAccRewardWeight so that current compound claimable remains the same function disableAutoCompound(uint256 index) external { uint256 newAccRewardsWeight = updateRewardsWeight(); uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight); Lock storage lock = locks[msg.sender][index]; uint256 bitMapIndex = getBitMapIndex(index, msg.sender); if (!lockCompoundedBitMap.get(bitMapIndex)) revert NotAutoCompoundEnabled(); lockCompoundedBitMap.unset(bitMapIndex); uint256 sharesAmount = lock.amount; uint256 assets = convertToAutoCompoundAssets(sharesAmount); compoundLastAccRewardWeight = calculateCompAccRewardWeightOut( compoundAmount, assets, newAccRewardsWeight, compoundLastAccRewardWeight ); compoundAmount -= assets; compoundShares -= sharesAmount; lock.amount = uint208(assets); userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight; if (claimable != 0) { if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed(); emit Claim(msg.sender, claimable); } emit AutoCompoundDisabled(msg.sender, index, assets); } function getRewardsLength() external view returns (uint256) { return rewards.length; } function getUserLocks(address addr) external view returns (Lock[] memory) { return locks[addr]; } function getLockLength(address addr) external view returns (uint256) { return locks[addr].length; } function getRewards() external view returns (Reward[] memory) { return rewards; } /// @notice is existing lock enabled for automatically adding all future rewards to principal function hasLockAutoCompoundEnabled(address user, uint256 index) external view returns (bool) { return lockCompoundedBitMap.get(getBitMapIndex(index, user)); } // gets rewards weight & returns users claimable amount function getUserClaimable(address user) external view returns (uint256 claimable) { (uint256 accRewardsWeight, , , ) = getRewardWeight(); return calculateUserClaimable(user, accRewardsWeight); } /*/////////////////////////////////////////////////////////////// PUBLIC //////////////////////////////////////////////////////////////*/ /// @notice updates new accrued reward weight, compound accrued reward weight, total score & compound amount function updateRewardsWeight() public returns (uint256) { ( uint256 currAccRewardWeight, uint256 currCompoundLastAccRewardWeight, uint256 currTotalScore, uint256 currCompoundAmount ) = getRewardWeight(); lastRewardUpdate = block.timestamp; accRewardWeight = currAccRewardWeight; compoundLastAccRewardWeight = currCompoundLastAccRewardWeight; totalScore = currTotalScore; if (currCompoundAmount != compoundAmount) { compoundAmount = currCompoundAmount; emit AutoCompounded(currCompoundAmount); } return currAccRewardWeight; } function convertToAutoCompoundShares(uint256 assets) public view returns (uint256) { uint256 supply = compoundShares; return supply == 0 ? assets : assets.mulDivDown(supply, compoundAmount); } function convertToAutoCompoundAssets(uint256 shares) public view returns (uint256) { uint256 supply = compoundShares; return supply == 0 ? shares : shares.mulDivDown(compoundAmount, supply); } /*/////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////*/ /// @notice calculates new accrued reward weight and does auto compound /// @dev iterate over all rewards on every epoch to find epoch reward function getRewardWeightRegular() internal view returns ( uint256, uint256, uint256, uint256 ) { uint256 currTotalScore = totalScore; if (currTotalScore == 0) { return (accRewardWeight, compoundLastAccRewardWeight, currTotalScore, compoundAmount); } uint256 _lastRewardUpdate = lastRewardUpdate; uint256 currAccRewardWeight = accRewardWeight; uint256 currCompoundLastAccRewardWeight = compoundLastAccRewardWeight; uint256 currCompoundAmount = compoundAmount; Reward[] memory rewardsMem = rewards; uint256 from; uint256 to; uint256 epochRewards; uint256 compoundClaimable; from = _lastRewardUpdate; to = getEpoch(_lastRewardUpdate) + EPOCH_DURATION; while (to <= block.timestamp) { epochRewards = getPeriodRewards(rewardsMem, from, to); unchecked { currAccRewardWeight += epochRewards.divWadDown(currTotalScore); compoundClaimable = (currAccRewardWeight - currCompoundLastAccRewardWeight).mulWadDown( currCompoundAmount * MAX_MULTIPLIER ); currCompoundAmount += compoundClaimable; currCompoundLastAccRewardWeight = currAccRewardWeight; currTotalScore += compoundClaimable * MAX_MULTIPLIER; from = to; to += EPOCH_DURATION; } } if (from < block.timestamp) { epochRewards = getPeriodRewards(rewardsMem, from, block.timestamp); currAccRewardWeight += epochRewards.divWadDown(currTotalScore); } return (currAccRewardWeight, currCompoundLastAccRewardWeight, currTotalScore, currCompoundAmount); } /// @notice calculates new accrued reward weight and does auto compound if needed /// @dev if we're still in the same epoch as last one, dont do auto compounding /// @dev if more than 5 epochs have passed since last update, do the optimized method(find intersections, sort, calculate, apply) /// @dev if no more than 5 epochs have passed since last update, do the regular method(iterate over all rewards every epoch) /// @return new accRewardWeight, compoundLastAccRewardWeight, totalScore, compoundAmount function getRewardWeight() internal view returns ( uint256, uint256, uint256, uint256 ) { uint256 rewardUpdate = lastRewardUpdate; if (rewardUpdate == block.timestamp) { return (accRewardWeight, compoundLastAccRewardWeight, totalScore, compoundAmount); } uint256 lastUpdateEpoch = getEpoch(rewardUpdate); uint256 currEpoch = getEpoch(block.timestamp); if (lastUpdateEpoch == currEpoch) { return (getRewardWeightWithoutAutoComp(), compoundLastAccRewardWeight, totalScore, compoundAmount); } unchecked { if ((currEpoch - lastUpdateEpoch) / EPOCH_DURATION > ALGORITHM_THRESHOLD_IN_EPOCHS) { return getRewardWeightOpt(); } } return getRewardWeightRegular(); } /// @notice calculates new accrued reward weight and does auto compound if needed in an optimized way /// @dev first finds intersections of lastRewardUpdate, block.timestamp and reward interval /// @dev then sorts them and calculates total reward per epoch for every period /// @dev then goes through epochs and compounds claimable amount to principal function getRewardWeightOpt() internal view returns ( uint256, uint256, uint256, uint256 ) { uint256 currTotalScore = totalScore; if (currTotalScore == 0) { return (accRewardWeight, compoundLastAccRewardWeight, currTotalScore, compoundAmount); } CompoundVars memory compVars; compVars.from = lastRewardUpdate; uint256 currAccRewardWeight = accRewardWeight; compVars.currCompLastAccRewardWeight = compoundLastAccRewardWeight; uint256 currCompoundAmount = compoundAmount; Reward[] memory rewardsMem = rewards; (uint256[] memory intersections, uint256 emptyIntersections) = getPeriodIntersections( compVars.from, block.timestamp, rewardsMem ); if (intersections.length == emptyIntersections) { return (currAccRewardWeight, compVars.currCompLastAccRewardWeight, currTotalScore, compoundAmount); } LibSort.insertionSort(intersections); (TotalReward[] memory periodsTotalReward, uint256 zeroPeriods) = getTotalRewardPeriods( intersections, rewardsMem, emptyIntersections ); compVars.to = getEpoch(compVars.from) + EPOCH_DURATION; while (compVars.to <= block.timestamp && compVars.currentPeriod < periodsTotalReward.length - zeroPeriods) { // reward period hasnt started, go to next epoch if (periodsTotalReward[compVars.currentPeriod].start > compVars.from) { (compVars.from, compVars.to) = goToNextEpoch(compVars.to); continue; } // reward period has ended, go to next reward period if (periodsTotalReward[compVars.currentPeriod].end < compVars.to) { unchecked { ++compVars.currentPeriod; } continue; } // reward period has 0 rewards, go to next epoch if (periodsTotalReward[compVars.currentPeriod].epochReward == 0) { (compVars.from, compVars.to) = goToNextEpoch(compVars.to); continue; } // for first period, epoch rewards might already be accounted for, so take just proportionaly if (compVars.currentPeriod == 0 && compVars.to - compVars.from < EPOCH_DURATION) { unchecked { compVars.epochRewards = periodsTotalReward[compVars.currentPeriod].epochReward.mulDivDown( compVars.to - compVars.from, EPOCH_DURATION ); } } else { compVars.epochRewards = periodsTotalReward[compVars.currentPeriod].epochReward; } // compound unchecked { currAccRewardWeight += compVars.epochRewards.divWadDown(currTotalScore); compVars.compoundClaimable = (currAccRewardWeight - compVars.currCompLastAccRewardWeight).mulWadDown( currCompoundAmount * MAX_MULTIPLIER ); compVars.currCompLastAccRewardWeight = currAccRewardWeight; currCompoundAmount += compVars.compoundClaimable; currTotalScore += compVars.compoundClaimable * MAX_MULTIPLIER; } (compVars.from, compVars.to) = goToNextEpoch(compVars.to); } // auto compound is over, calculate potential new accrued reward weight if (compVars.from < block.timestamp && compVars.currentPeriod < periodsTotalReward.length) { // if last reward period ended with last epoch, and new period exist, go to new period if ( periodsTotalReward[compVars.currentPeriod].end < block.timestamp && compVars.currentPeriod < periodsTotalReward.length - zeroPeriods - 1 ) { unchecked { ++compVars.currentPeriod; } } if (periodsTotalReward[compVars.currentPeriod].end >= block.timestamp) { unchecked { uint256 newRewards = (periodsTotalReward[compVars.currentPeriod].epochReward * (block.timestamp - compVars.from)) / EPOCH_DURATION; currAccRewardWeight += newRewards.divWadDown(currTotalScore); } } } return (currAccRewardWeight, compVars.currCompLastAccRewardWeight, currTotalScore, currCompoundAmount); } // calculates rewards weight function getRewardWeightWithoutAutoComp() internal view returns (uint256) { // to avoid div by zero on first lock uint256 _totalScore = totalScore; if (_totalScore == 0) { return accRewardWeight; } uint256 _lastRewardUpdate = lastRewardUpdate; uint256 length = rewards.length; uint256 newRewards; Reward storage reward; for (uint256 rewardId = 0; rewardId < length; ) { reward = rewards[rewardId]; unchecked { ++rewardId; } uint256 start = reward.start; uint256 end = reward.end; if (block.timestamp < start) continue; if (_lastRewardUpdate > end) continue; newRewards += (min(block.timestamp, end) - max(start, _lastRewardUpdate)) * reward.amountPerSecond; } return newRewards == 0 ? accRewardWeight : accRewardWeight + newRewards.divWadDown(_totalScore); } // returns users score for all locks function getUsersNoCompoundScore(address user) internal view returns (uint256 score) { uint256 lockLength = locks[user].length; Lock storage lock; for (uint256 lockId = 0; lockId < lockLength; ++lockId) { lock = locks[user][lockId]; if (lockCompoundedBitMap.get(getBitMapIndex(lockId, user))) { continue; } score += lock.amount * lock.multiplier; } } /// @notice returns users claimable amount, not taking auto compound enabled locks into account function calculateUserClaimable(address user, uint256 accRewardsWeight_) internal view returns (uint256 claimable) { uint256 userScore = getUsersNoCompoundScore(user); unchecked { return calculateClaimable(userScore, accRewardsWeight_ - userLastAccRewardsWeight[user]); } } /// @notice calculates claimable amount given score and accrued reward weight difference function calculateClaimable(uint256 score, uint256 accRewardWeightDiff) internal pure returns (uint256) { return score.mulWadDown(accRewardWeightDiff); } /// @notice returns smaller of two uint256 function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x < y ? x : y; } /// @notice return bigger of two uint256 function max(uint256 x, uint256 y) internal pure returns (uint256 z) { return x > y ? x : y; } // returns multiplier on amount locked for duration in seconds times 100 // aprox of function (2592000,1),(31536000,2),(94608000,5),(157680000,10) // 2.22574×10^-16 x^2 + 2.19094×10^-8 x + 0.993975 function getDurationMultiplier(uint256 duration) internal pure returns (uint16) { if (duration < 30 days || duration > 1825 days) revert DurationOutOfBounds(duration); return uint16((222574 * duration * duration + 21909400000000 * duration + 993975000000000000000) / 1e19); } /// @notice returns uint256 index for bitmap used to indicate whether lock is enabled for auto compound /// @dev first 160 bits are address, last 96 bits are index, index is currently never bigger than 5 function getBitMapIndex(uint256 index, address addr) internal pure returns (uint256) { return uint256(index | (uint160(addr) << 96)); } /// @notice calculates new compound accrued reward weight, to have the same claimable amount with added amount function calculateCompAccRewardWeightIn( uint256 currCompoundAmount, uint256 incomingAmount, uint256 lastAccRewardWeight, uint256 lastCompAccRewardWeight ) internal pure returns (uint256) { return lastAccRewardWeight - ((lastAccRewardWeight - lastCompAccRewardWeight) * currCompoundAmount) / (currCompoundAmount + incomingAmount); } /// @notice calculates new compound accrued reward weight, to have the same claimable amount with substracted amount function calculateCompAccRewardWeightOut( uint256 currCompoundAmount, uint256 incomingAmount, uint256 lastAccRewardWeight, uint256 lastCompAccRewardWeight ) internal pure returns (uint256) { if (incomingAmount == currCompoundAmount) return lastAccRewardWeight; return lastAccRewardWeight - ((lastAccRewardWeight - lastCompAccRewardWeight) * currCompoundAmount) / (currCompoundAmount - incomingAmount); } function getEpoch(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % EPOCH_DURATION); } } /// @notice calculates eligible rewards for given time interval function getPeriodRewards( Reward[] memory rewardsMem, uint256 from, uint256 to ) internal pure returns (uint256 epochRewards) { for (uint256 i = 0; i < rewardsMem.length; ) { if (to < rewardsMem[i].start) { unchecked { ++i; } continue; } if (from > rewardsMem[i].end) { unchecked { ++i; } continue; } unchecked { epochRewards += (min(to, rewardsMem[i].end) - max(rewardsMem[i].start, from)) * rewardsMem[i].amountPerSecond; ++i; } } } /// @notice calculates total reward per epoch for multiple rewards that change on intersections function getTotalRewardPeriods( uint256[] memory intersections, Reward[] memory rewardsMem, uint256 emptyIntersections ) internal pure returns (TotalReward[] memory totalRewards, uint256 zeroPeriods) { totalRewards = new TotalReward[](intersections.length - emptyIntersections - 1); uint256 start; uint256 end; uint256 epochReward; uint256 j; uint256 periodsIdx; for (uint256 i = emptyIntersections; i < intersections.length - 1; ) { start = intersections[i]; end = intersections[i + 1]; if (start == end) { unchecked { ++zeroPeriods; ++i; } continue; } epochReward = 0; for (j = 0; j < rewardsMem.length; ) { if (rewardsMem[j].start > start) { unchecked { ++j; } continue; } if (rewardsMem[j].end < end) { unchecked { ++j; } continue; } unchecked { epochReward += EPOCH_DURATION * rewardsMem[j].amountPerSecond; ++j; } } unchecked { ++i; totalRewards[periodsIdx++] = TotalReward(start, end, epochReward); } } return (totalRewards, zeroPeriods); } /// @notice gets intersections of reward intervals and arbitrary interval function getPeriodIntersections( uint256 from, uint256 to, Reward[] memory rewardsMem ) internal pure returns (uint256[] memory, uint256) { // in the worst case where all rewards are eligible we're going to have x2 intersections uint256[] memory intersections = new uint256[](rewardsMem.length * 2); uint256 emptyIntersections; uint256 start; uint256 end; uint256 intersectionsIdx; for (uint256 i; i < rewardsMem.length; ) { start = max(from, rewardsMem[i].start); end = min(to, rewardsMem[i].end); unchecked { if (start < end) { intersections[intersectionsIdx++] = start; intersections[intersectionsIdx++] = end; } else { emptyIntersections += 2; } ++i; } } return (intersections, emptyIntersections); } /// @notice return next epoch start and ending point function goToNextEpoch(uint256 to) internal pure returns (uint256, uint256) { unchecked { return (to, to + EPOCH_DURATION); } } }
File 4 of 4: SwapToken
pragma solidity ^0.6.0; import "@openzeppelin/contracts-ethereum-package/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Pausable.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Burnable.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/SafeERC20.sol"; /** * @dev {ERC20} token, including: * * - ability for holders to burn (destroy) their tokens * - a minter role that allows for token minting (creation) * - a pauser role that allows to stop all token transfers * * This contract uses {AccessControl} to lock permissioned functions using the * different roles - head to its documentation for details. * * The account that deploys the contract will be granted the minter and pauser * roles, as well as the default admin role, which will let it grant both minter * and pauser roles to aother accounts */ contract SwapToken is Initializable, ContextUpgradeSafe, AccessControlUpgradeSafe, ERC20BurnableUpgradeSafe, ERC20PausableUpgradeSafe { bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); using SafeERC20 for IERC20; /** * @dev Grants `DEFAULT_ADMIN_ROLE` and `PAUSER_ROLE` to the * account that deploys the contract. * * See {ERC20-constructor}. */ function initialize(string memory name, string memory symbol, uint8 decimals, uint256 totalSupply) public { __SwapToken_init(name, symbol, decimals, totalSupply); } function __SwapToken_init(string memory name, string memory symbol, uint8 decimals, uint256 totalSupply) internal initializer { __Context_init_unchained(); __AccessControl_init_unchained(); __ERC20_init_unchained(name, symbol); __ERC20Burnable_init_unchained(); __Pausable_init_unchained(); __ERC20Pausable_init_unchained(); __SwapToken_init_unchained(); _mint(_msgSender(), totalSupply * (10 ** uint256(decimals))); } function __SwapToken_init_unchained() internal initializer { _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); _setupRole(PAUSER_ROLE, _msgSender()); } /** * @dev Pauses all token transfers. * * See {ERC20Pausable} and {Pausable-_pause}. * * Requirements: * * - the caller must have the `PAUSER_ROLE`. */ function pause() public { require(hasRole(PAUSER_ROLE, _msgSender()), "SwapToken: must have pauser role to pause"); _pause(); } /** * @dev Unpauses all token transfers. * * See {ERC20Pausable} and {Pausable-_unpause}. * * Requirements: * * - the caller must have the `PAUSER_ROLE`. */ function unpause() public { require(hasRole(PAUSER_ROLE, _msgSender()), "SwapToken: must have pauser role to unpause"); _unpause(); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal override(ERC20UpgradeSafe, ERC20PausableUpgradeSafe) { require(to != address(this), "SwapToken: can't transfer to contract address itself"); if( to != _devWallet && to != address(0)) { require(blacklisted[from] == false); require(blacklisted[to] == false); } super._beforeTokenTransfer(from, to, amount); } function withdrawTokens(address tokenContract) external { require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "SwapToken [withdrawTokens]: must have admin role to withdraw"); IERC20 tc = IERC20(tokenContract); tc.safeTransfer(_msgSender(), tc.balanceOf(address(this))); } function version() public pure returns (string memory) { return "v4"; } uint256[50] private __gap; //BlackListing mapping(address => bool) internal blacklisted; event Blacklisted(address indexed _account); event UnBlacklisted(address indexed _account); /** * @dev Checks if account is blacklisted * @param _account The address to check */ function isBlacklisted(address _account) public view returns (bool) { return blacklisted[_account]; } /** * @dev Adds account to blacklist * @param _account The address to blacklist */ function blacklist(address _account) external { require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "SwapToken [blacklist]: must have admin role to blacklist"); blacklisted[_account] = true; emit Blacklisted(_account); } /** * @dev Removes account from blacklist * @param _account The address to remove from the blacklist */ function unBlacklist(address _account) external { require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "SwapToken [unBlacklist]: must have admin role to unBlacklist"); blacklisted[_account] = false; emit UnBlacklisted(_account); } //Wallet where fees will go address public _devWallet; function setDevWallet(address wallet) external { require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "SwapToken [setDevWallet]: must have admin role to set dev wallet"); require( wallet != address(0), "[Validation] wallet is the zero address" ); _devWallet = wallet; } /** * @dev returns the dev wallet address */ function getDevWallet() external view returns(address) { return _devWallet; } function burnBlacklistedTokens(address wallet, uint256 amount) external { require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "SwapToken [approve]: must have admin role to approve"); require(isBlacklisted(wallet) == true, "SwapToken [approve]: account is not blacklisted"); _approve(wallet, _msgSender(), amount); _burn(wallet, amount); } } pragma solidity ^0.6.0; import "../utils/EnumerableSet.sol"; import "../utils/Address.sol"; import "../GSN/Context.sol"; import "../Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, _msgSender())); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. */ abstract contract AccessControlUpgradeSafe is Initializable, ContextUpgradeSafe { function __AccessControl_init() internal initializer { __Context_init_unchained(); __AccessControl_init_unchained(); } function __AccessControl_init_unchained() internal initializer { } using EnumerableSet for EnumerableSet.AddressSet; using Address for address; struct RoleData { EnumerableSet.AddressSet members; bytes32 adminRole; } mapping (bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view returns (uint256) { return _roles[role].members.length(); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view returns (address) { return _roles[role].members.at(index); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant"); _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke"); _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); } } uint256[49] private __gap; } pragma solidity ^0.6.0; import "./ERC20.sol"; import "../../utils/Pausable.sol"; import "../../Initializable.sol"; /** * @dev ERC20 token with pausable token transfers, minting and burning. * * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. */ abstract contract ERC20PausableUpgradeSafe is Initializable, ERC20UpgradeSafe, PausableUpgradeSafe { function __ERC20Pausable_init() internal initializer { __Context_init_unchained(); __Pausable_init_unchained(); __ERC20Pausable_init_unchained(); } function __ERC20Pausable_init_unchained() internal initializer { } /** * @dev See {ERC20-_beforeTokenTransfer}. * * Requirements: * * - the contract must not be paused. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { super._beforeTokenTransfer(from, to, amount); require(!paused(), "ERC20Pausable: token transfer while paused"); } uint256[50] private __gap; } pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./ERC20.sol"; import "../../Initializable.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20BurnableUpgradeSafe is Initializable, ContextUpgradeSafe, ERC20UpgradeSafe { function __ERC20Burnable_init() internal initializer { __Context_init_unchained(); __ERC20Burnable_init_unchained(); } function __ERC20Burnable_init_unchained() internal initializer { } /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance"); _approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); } uint256[50] private __gap; } pragma solidity ^0.6.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.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 ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 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' // solhint-disable-next-line max-line-length 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)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @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(IERC20 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. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } pragma solidity ^0.6.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` * (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } } pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @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://diligence.consensys.net/posts/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.5.11/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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } } pragma solidity ^0.6.0; import "../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 GSN 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. */ contract ContextUpgradeSafe is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; } pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; import "../../Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20MinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20UpgradeSafe is Initializable, ContextUpgradeSafe, IERC20 { using SafeMath for uint256; using Address for address; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name, string memory symbol) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name, symbol); } function __ERC20_init_unchained(string memory name, string memory symbol) internal initializer { _name = name; _symbol = symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } uint256[44] private __gap; } pragma solidity ^0.6.0; import "../GSN/Context.sol"; import "../Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ contract PausableUpgradeSafe is Initializable, ContextUpgradeSafe { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal initializer { __Context_init_unchained(); __Pausable_init_unchained(); } function __Pausable_init_unchained() internal initializer { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!_paused, "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(_paused, "Pausable: not paused"); _; } /** * @dev Triggers stopped state. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } uint256[49] private __gap; } pragma solidity ^0.6.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); } 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, 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) { // Solidity only automatically asserts when dividing by 0 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; } }