// // Liquid Lottery (LIQLO) is the first token from Read This Contract (RTC)! // If you don't know what RTC is, join the Telegram: // > https://t.me/ReadThisContract // // Nothing fancy in this token contract, but a play on the Uniswap pool! // The rules are simple: // // 0. LIQLO-ETH pool on Uniswap starts with 1 ETH and 10 LIQLO. // Supply is low because you will win the rest of LIQLO tokens! // // 1,000 LIQLO is reserved for prizes. 100 LIQLO is airdropped to RTC holders. // This means total & final supply is 1,110 LIQLO. Minting is locked for ever! // // 1. Add liquidity to RTC-ETH pool on Uniswap. // Every 1 ETH worth of RTC-ETH you add to the pool counts as 1 "ticket". // > https://uniswap.info/pair/0xfde42a9422cb0ee84ede728ab503487b382d135e // // 2. Once per day when RTC-ETH pool liquidity is above 32 ETH, a random "ticket" receives: // 1 ETH + 1 RTC + 1 LIQLO. // // 3. Once per day when RTC-ETH pool liquidity is above 32 ETH, the top liquidity provider receives: // 1 ETH + 2 RTC + 3 LIQLO. // // 4. The daily prize of 2 ETH comes from selling RTC reserve back to the pool, meaning once per day // there is a small chance to enter RTC at a discount. // // 5. Collect LIQLO tokens to use for staking in the next token contract! // // Good luck! // // Veronika // // //////////////////////////////////////////////////////////////////////////////// // // // // //// ////// ///// // // // // // // // // // ///// // // // // Never break the chain. // // // // //////////////////////////////////////////////////////////////////////////////// // pragma solidity ^0.6.0; contract Context { constructor () internal { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; return msg.data; } } pragma solidity ^0.6.0; library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } pragma solidity ^0.6.0; contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } function owner() public view returns (address) { return _owner; } modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } pragma solidity ^0.6.2; library Address { function isContract(address account) internal view returns (bool) { bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } 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"); } } pragma solidity ^0.6.0; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } pragma solidity ^0.6.0; contract ERC20 is Context, 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; constructor (string memory name, string memory symbol) public { _name = name; _symbol = symbol; _decimals = 18; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view returns (uint8) { return _decimals; } function totalSupply() public view override returns (uint256) { return _totalSupply; } function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } 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; } function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } 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; } 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); } 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); } 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); } 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); } function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } pragma solidity ^0.6.0; abstract contract ERC20Capped is ERC20 { uint256 private _cap; constructor (uint256 cap) public { require(cap > 0, "ERC20Capped: cap is 0"); _cap = cap; } function cap() public view returns (uint256) { return _cap; } function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { super._beforeTokenTransfer(from, to, amount); if (from == address(0)) { require(totalSupply().add(amount) <= _cap, "ERC20Capped: cap exceeded"); } } } pragma solidity ^0.6.0; abstract contract ERC20Burnable is Context, ERC20 { function burn(uint256 amount) public virtual { _burn(_msgSender(), 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); } } pragma solidity ^0.6.0; interface IERC165 { function supportsInterface(bytes4 interfaceId) external view returns (bool); } pragma solidity ^0.6.2; library ERC165Checker { bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; function supportsERC165(address account) internal view returns (bool) { return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) && !_supportsERC165Interface(account, _INTERFACE_ID_INVALID); } function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { return supportsERC165(account) && _supportsERC165Interface(account, interfaceId); } function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { if (!supportsERC165(account)) { return false; } for (uint256 i = 0; i < interfaceIds.length; i++) { if (!_supportsERC165Interface(account, interfaceIds[i])) { return false; } } return true; } function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) { (bool success, bool result) = _callERC165SupportsInterface(account, interfaceId); return (success && result); } function _callERC165SupportsInterface(address account, bytes4 interfaceId) private view returns (bool, bool) { bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId); (bool success, bytes memory result) = account.staticcall{ gas: 30000 }(encodedParams); if (result.length < 32) return (false, false); return (success, abi.decode(result, (bool))); } } pragma solidity ^0.6.0; contract ERC165 is IERC165 { bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { _registerInterface(_INTERFACE_ID_ERC165); } function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return _supportedInterfaces[interfaceId]; } function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } pragma solidity ^0.6.0; contract TokenRecover is Ownable { function recoverERC20(address tokenAddress, uint256 tokenAmount) public onlyOwner { IERC20(tokenAddress).transfer(owner(), tokenAmount); } } pragma solidity ^0.6.0; library EnumerableSet { struct Set { bytes32[] _values; mapping (bytes32 => uint256) _indexes; } function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); set._indexes[value] = set._values.length; return true; } else { return false; } } function _remove(Set storage set, bytes32 value) private returns (bool) { uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; bytes32 lastvalue = set._values[lastIndex]; set._values[toDeleteIndex] = lastvalue; set._indexes[lastvalue] = toDeleteIndex + 1; set._values.pop(); delete set._indexes[value]; return true; } else { return false; } } function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } function _length(Set storage set) private view returns (uint256) { return set._values.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]; } struct AddressSet { Set _inner; } function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); } struct UintSet { Set _inner; } function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } } pragma solidity ^0.6.0; abstract contract AccessControl is Context { 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; event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); } function getRoleMemberCount(bytes32 role) public view returns (uint256) { return _roles[role].members.length(); } function getRoleMember(bytes32 role, uint256 index) public view returns (address) { return _roles[role].members.at(index); } function getRoleAdmin(bytes32 role) public view returns (bytes32) { return _roles[role].adminRole; } 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); } 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); } function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } 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()); } } } pragma solidity ^0.6.0; contract Roles is AccessControl { bytes32 public constant MINTER_ROLE = keccak256("MINTER"); bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR"); constructor () public { _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); _setupRole(MINTER_ROLE, _msgSender()); _setupRole(OPERATOR_ROLE, _msgSender()); } modifier onlyMinter() { require(hasRole(MINTER_ROLE, _msgSender()), "Roles: caller does not have the MINTER role"); _; } modifier onlyOperator() { require(hasRole(OPERATOR_ROLE, _msgSender()), "Roles: caller does not have the OPERATOR role"); _; } } pragma solidity ^0.6.0; contract LiquidLottery is ERC20Capped, ERC20Burnable, Roles, TokenRecover { bool private _mintingFinished = false; bool private _transferEnabled = false; event MintFinished(); event TransferEnabled(); modifier canMint() { require(!_mintingFinished, "LiquidLottery: minting is finished"); _; } modifier canTransfer(address from) { require( _transferEnabled || hasRole(OPERATOR_ROLE, from), "LiquidLottery: transfer is not enabled or from does not have the OPERATOR role" ); _; } constructor( string memory name, string memory symbol, uint8 decimals, uint256 cap, uint256 initialSupply, bool transferEnabled, bool mintingFinished ) public ERC20Capped(cap) ERC20(name, symbol) { require( mintingFinished == false || cap == initialSupply, "LiquidLottery: if finish minting, cap must be equal to initialSupply" ); _setupDecimals(decimals); if (initialSupply > 0) { _mint(owner(), initialSupply); } if (mintingFinished) { finishMinting(); } if (transferEnabled) { enableTransfer(); } } function mintingFinished() public view returns (bool) { return _mintingFinished; } function transferEnabled() public view returns (bool) { return _transferEnabled; } function mint(address to, uint256 value) public canMint onlyMinter { _mint(to, value); } function transfer(address to, uint256 value) public virtual override(ERC20) canTransfer(_msgSender()) returns (bool) { return super.transfer(to, value); } function transferFrom(address from, address to, uint256 value) public virtual override(ERC20) canTransfer(from) returns (bool) { return super.transferFrom(from, to, value); } function finishMinting() public canMint onlyOwner { _mintingFinished = true; emit MintFinished(); } function enableTransfer() public onlyOwner { _transferEnabled = true; emit TransferEnabled(); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override(ERC20, ERC20Capped) { super._beforeTokenTransfer(from, to, amount); } }