Back to Contract Registry
LOCKIT Token
Governance token with fixed supply and voting power.
0x309456d4F1e321dCdf9a8f9245bC660bBA3f30A0
ERC-20 Base Mainnet Verified on Basescan
Source Viewer
1 // SPDX-License-Identifier: MIT
2 pragma solidity ^0.8.20;
3
4 import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5 import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
6 import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
7 import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol";
8
9 /**
10 * @title LOCKIT Token
11 * @author LockItIn Protocol DAO
12 * @notice Governance token for the LockItIn Protocol
13 * @dev ERC20 with EIP-2612 permit and EIP-5805 votes (timestamp mode)
14 *
15 * Key Properties:
16 * - Fixed supply: 1,000,000,000 (1 billion) tokens, 18 decimals
17 * - No mint/burn functions after deployment (immutable supply)
18 * - Timestamp-based voting snapshots (L2/Base compatible)
19 * - Auto-self-delegation on first token receipt (UX optimization)
20 *
21 * Auto-Delegation Logic:
22 * When tokens are transferred to an address that has never held voting
23 * power, that address is automatically self-delegated. This ensures
24 * recipients have immediate voting power without requiring a separate
25 * delegation transaction.
26 *
27 * Security Considerations:
28 * - Zero-value transfers do not trigger auto-delegation (prevents griefing)
29 * - Only first-time recipients are auto-delegated (respects user agency)
30 * - No admin functions, no pause, no upgrade mechanism
31 */
32 contract LOCKITToken is ERC20, ERC20Permit, ERC20Votes {
33
34 /// @notice Total supply: 1 billion tokens with 18 decimals
35 uint256 public constant TOTAL_SUPPLY = 1_000_000_000e18;
36
37 /**
38 * @notice Deploy token with entire supply minted to deployer
39 * @dev Deployer is responsible for distributing to vault/vesting contracts
40 */
41 constructor() ERC20("LockItIn", "LOCKIT") ERC20Permit("LockItIn") {
42 _mint(msg.sender, TOTAL_SUPPLY);
43 }
44
45 /**
46 * @notice Clock used for voting snapshots (EIP-6372)
47 * @dev Uses timestamp instead of block number for L2 compatibility.
48 * Block numbers on L2s like Base don't map predictably to time,
49 * making timestamp-based voting periods more reliable.
50 * @return Current block timestamp as uint48
51 */
52 function clock() public view override returns (uint48) {
53 return uint48(block.timestamp);
54 }
55
56 /**
57 * @notice Machine-readable clock mode descriptor (EIP-6372)
58 * @return Mode string indicating timestamp-based snapshots
59 */
60 function CLOCK_MODE() public pure override returns (string memory) {
61 return "mode=timestamp";
62 }
63
64 /**
65 * @dev Handle voting power transfers with auto-self-delegation
66 *
67 * Auto-delegation triggers only when ALL conditions are met:
68 * 1. value > 0 - Prevents zero-transfer griefing attacks
69 * 2. to != address(0) - Not a burn operation
70 * 3. delegates(to) == address(0) - Recipient hasn't chosen a delegate
71 * 4. numCheckpoints(to) == 0 - Recipient has never held voting power
72 *
73 * This "first meaningful receipt" pattern:
74 * - Gives new holders immediate voting power (no extra tx needed)
75 * - Respects user agency (doesn't override existing delegation choices)
76 * - Prevents state-bloat attacks via zero-value transfers
77 *
78 * Note: Contracts receiving tokens will be self-delegated but cannot
79 * vote unless they implement voting logic. This affects quorum math
80 * for governance - plan Governor parameters accordingly.
81 */
82 function _update(
83 address from,
84 address to,
85 uint256 value
86 ) internal virtual override(ERC20, ERC20Votes) {
87 super._update(from, to, value);
88
89 // Auto-self-delegate on first meaningful receipt only
90 if (
91 value > 0 &&
92 to != address(0) &&
93 delegates(to) == address(0) &&
94 numCheckpoints(to) == 0
95 ) {
96 _delegate(to, to);
97 }
98 }
99
100 /**
101 * @dev Required override for ERC20Permit + Nonces diamond inheritance
102 * @param owner Address to query nonce for
103 * @return Current permit nonce for owner
104 */
105 function nonces(
106 address owner
107 ) public view virtual override(ERC20Permit, Nonces) returns (uint256) {
108 return super.nonces(owner);
109 }
110 }