Created
October 15, 2021 17:11
-
-
Save z0r0z/b9c7f05d6c1cc47a2529a1b60a3b64ee to your computer and use it in GitHub Desktop.
ross screwed up modules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-3.0-or-later | |
pragma solidity >=0.8.0; | |
/// @notice Single owner function access control module. | |
abstract contract LexOwnable { | |
event TransferOwner(address indexed from, address indexed to); | |
event TransferOwnerClaim(address indexed from, address indexed to); | |
address public owner; | |
address public pendingOwner; | |
/// @notice Initialize ownership module for function access control. | |
/// @param _owner Account to grant ownership. | |
constructor(address _owner) { | |
owner = _owner; | |
emit TransferOwner(address(0), _owner); | |
} | |
/// @notice Access control modifier that conditions function to be restricted to `owner` account. | |
modifier onlyOwner() { | |
require(msg.sender == owner, "NOT_OWNER"); | |
_; | |
} | |
/// @notice `pendingOwner` can claim `owner` account. | |
function claimOwner() external { | |
require(msg.sender == pendingOwner, "NOT_PENDING_OWNER"); | |
emit TransferOwner(owner, msg.sender); | |
owner = msg.sender; | |
pendingOwner = address(0); | |
} | |
/// @notice Transfer `owner` account. | |
/// @param to Account granted `owner` access control. | |
/// @param direct If 'true', ownership is directly transferred. | |
function transferOwner(address to, bool direct) external onlyOwner { | |
require(to != address(0), "ZERO_ADDRESS"); | |
if (direct) { | |
owner = to; | |
emit TransferOwner(msg.sender, to); | |
} else { | |
pendingOwner = to; | |
emit TransferOwnerClaim(msg.sender, to); | |
} | |
} | |
} | |
/// @notice Ownable function pausing module. | |
abstract contract LexPausable is LexOwnable { | |
event TogglePause(bool indexed paused); | |
bool public paused; | |
/// @notice Initialize pausing module. | |
/// @param _paused If 'true', modified functions are paused. | |
/// @param _owner Account to grant ownership of this module. | |
constructor(bool _paused, address _owner) LexOwnable(_owner) { | |
paused = _paused; | |
emit TogglePause(_paused); | |
} | |
/// @notice Function pausing modifier that conditions functions to be called when `paused` is not enabled. | |
modifier notPaused() { | |
require(!paused, "PAUSED"); | |
_; | |
} | |
/// @notice Toggle `paused` conditions on/off. | |
/// @param _paused If 'true', modified functions are paused. | |
function togglePause(bool _paused) external onlyOwner { | |
paused = _paused; | |
emit TogglePause(_paused); | |
} | |
} | |
/// @notice Ownable function time restriction module. | |
abstract contract LexTimeRestricted is LexOwnable { | |
event ToggleTimeRestriction(bool indexed timeRestrictionEnabled); | |
event UpdateTimeRestriction(uint256 indexed timeRestriction); | |
uint256 public timeRestriction; | |
bool public timeRestrictionEnabled; | |
/// @notice Initialize time restriction module. | |
/// @param _timeRestriction Point when restriction ends in Unix time. | |
/// @param _timeRestrictionEnabled If 'true', modified functions are restricted. | |
/// @param _owner Account to grant ownership of this module. | |
constructor(uint256 _timeRestriction, bool _timeRestrictionEnabled, address _owner) LexOwnable(_owner) { | |
timeRestriction = _timeRestriction; | |
timeRestrictionEnabled = _timeRestrictionEnabled; | |
emit ToggleTimeRestriction(_timeRestrictionEnabled); | |
} | |
/// @notice Time restriction modifier that conditions function to be called at `timeRestriction` or after. | |
modifier timeRestricted { | |
if (timeRestrictionEnabled) | |
require(block.timestamp >= timeRestriction, "TIME_RESTRICTED"); | |
_; | |
} | |
/// @notice Toggle `timeRestriction` conditions on/off. | |
/// @param _timeRestrictionEnabled If 'true', `timeRestriction` conditions are on. | |
function toggleTimeRestriction(bool _timeRestrictionEnabled) external onlyOwner { | |
timeRestrictionEnabled = _timeRestrictionEnabled; | |
emit ToggleTimeRestriction(_timeRestrictionEnabled); | |
} | |
/// @notice Update `timeRestriction` in Unix time. | |
/// @param _timeRestriction Point when restriction ends in Unix time. | |
function updateTimeRestriction(uint256 _timeRestriction) external onlyOwner { | |
timeRestriction = _timeRestriction; | |
emit UpdateTimeRestriction(_timeRestriction); | |
} | |
} | |
/// @notice Ownable function whitelisting module. | |
abstract contract LexWhitelistable is LexOwnable { | |
event ToggleWhiteList(bool indexed whitelistEnabled); | |
event UpdateWhitelist(address indexed account, bool indexed whitelisted); | |
bool public whitelistEnabled; | |
mapping(address => bool) public whitelisted; | |
/// @notice Initialize contract with `whitelistEnabled` status. | |
/// @param _whitelistEnabled If 'true', `whitelisted` conditions are on. | |
/// @param _owner Account to grant ownership of this module. | |
constructor(bool _whitelistEnabled, address _owner) LexOwnable(_owner) { | |
whitelistEnabled = _whitelistEnabled; | |
emit ToggleWhiteList(_whitelistEnabled); | |
} | |
/// @notice Whitelisting modifier that conditions function to be called between `whitelisted` accounts. | |
modifier onlyWhitelisted(address from, address to) { | |
if (whitelistEnabled) | |
require(whitelisted[from] && whitelisted[to], "NOT_WHITELISTED"); | |
_; | |
} | |
/// @notice Toggle `whitelisted` conditions on/off. | |
/// @param _whitelistEnabled If 'true', `whitelisted` conditions are on. | |
function toggleWhitelist(bool _whitelistEnabled) external onlyOwner { | |
whitelistEnabled = _whitelistEnabled; | |
emit ToggleWhiteList(_whitelistEnabled); | |
} | |
/// @notice Update account `whitelisted` status. | |
/// @param account Account to update. | |
/// @param _whitelisted If 'true', `account` is `whitelisted`. | |
function updateWhitelist(address account, bool _whitelisted) external onlyOwner { | |
whitelisted[account] = _whitelisted; | |
emit UpdateWhitelist(account, _whitelisted); | |
} | |
} | |
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. | |
/// @author Adapted from RariCapital, https://github.com/Rari-Capital/solmate/blob/main/src/erc20/ERC20.sol, | |
// License-Identifier: AGPL-3.0-only. | |
abstract contract LexToken { | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval(address indexed owner, address indexed spender, uint256 value); | |
string public name; | |
string public symbol; | |
uint8 public immutable decimals; | |
uint256 public totalSupply; | |
mapping(address => uint256) public balanceOf; | |
mapping(address => mapping(address => uint256)) public allowance; | |
bytes32 public constant PERMIT_TYPEHASH = | |
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); | |
uint256 internal immutable INITIAL_CHAIN_ID; | |
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; | |
mapping(address => uint256) public nonces; | |
constructor( | |
string memory _name, | |
string memory _symbol, | |
uint8 _decimals | |
) { | |
name = _name; | |
symbol = _symbol; | |
decimals = _decimals; | |
INITIAL_CHAIN_ID = block.chainid; | |
INITIAL_DOMAIN_SEPARATOR = _calculateDomainSeparator(); | |
} | |
function _calculateDomainSeparator() internal view returns (bytes32 domainSeperator) { | |
domainSeperator = keccak256( | |
abi.encode( | |
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), | |
keccak256(bytes(name)), | |
keccak256(bytes("1")), | |
block.chainid, | |
address(this) | |
) | |
); | |
} | |
function DOMAIN_SEPARATOR() public view returns (bytes32 domainSeperator) { | |
domainSeperator = block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _calculateDomainSeparator(); | |
} | |
function approve(address spender, uint256 value) public virtual returns (bool) { | |
allowance[msg.sender][spender] = value; | |
emit Approval(msg.sender, spender, value); | |
return true; | |
} | |
function transfer(address to, uint256 value) public virtual returns (bool) { | |
balanceOf[msg.sender] -= value; | |
/// @dev This is safe because the sum of all user | |
// balances can't exceed 'type(uint256).max'. | |
unchecked { | |
balanceOf[to] += value; | |
} | |
emit Transfer(msg.sender, to, value); | |
return true; | |
} | |
function transferFrom( | |
address from, | |
address to, | |
uint256 value | |
) public virtual returns (bool) { | |
if (allowance[from][msg.sender] != type(uint256).max) { | |
allowance[from][msg.sender] -= value; | |
} | |
balanceOf[from] -= value; | |
/// @dev This is safe because the sum of all user | |
// balances can't exceed 'type(uint256).max'. | |
unchecked { | |
balanceOf[to] += value; | |
} | |
emit Transfer(from, to, value); | |
return true; | |
} | |
function permit( | |
address owner, | |
address spender, | |
uint256 value, | |
uint256 deadline, | |
uint8 v, | |
bytes32 r, | |
bytes32 s | |
) public virtual { | |
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); | |
/// @dev This is reasonably safe from overflow because incrementing `nonces` beyond | |
// 'type(uint256).max' is exceedingly unlikely compared to optimization benefits. | |
unchecked { | |
bytes32 digest = keccak256( | |
abi.encodePacked( | |
"\x19\x01", | |
DOMAIN_SEPARATOR(), | |
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) | |
) | |
); | |
address recoveredAddress = ecrecover(digest, v, r, s); | |
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_PERMIT_SIGNATURE"); | |
allowance[recoveredAddress][spender] = value; | |
} | |
emit Approval(owner, spender, value); | |
} | |
function _mint(address to, uint256 value) internal { | |
totalSupply += value; | |
/// @dev This is safe because the sum of all user | |
// balances can't exceed 'type(uint256).max'. | |
unchecked { | |
balanceOf[to] += value; | |
} | |
emit Transfer(address(0), to, value); | |
} | |
function _burn(address from, uint256 value) internal { | |
balanceOf[from] -= value; | |
/// @dev This is safe because a user won't ever | |
// have a balance larger than `totalSupply`. | |
unchecked { | |
totalSupply -= value; | |
} | |
emit Transfer(from, address(0), value); | |
} | |
} | |
contract LexTokenRestricted is LexOwnable, LexPausable, LexTimeRestricted, LexWhitelistable { | |
constructor(address _owner, uint256 _timeRestriction) | |
LexOwnable(_owner) | |
LexPausable(_owner, true) | |
LexTimeRestricted(_timeRestriction, true, _owner) | |
LexWhitelistable(true, _owner) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment