@@ -15,6 +15,287 @@ timezone: UTC+8
1515## Notes
1616
1717<!-- Content_START -->
18+ # 2025-08-19
19+
20+ # 1. EIP-20
21+
22+ ** 强制接口**
23+
24+ - ` totalSupply() → uint256 `
25+
26+ - ` balanceOf(address) → uint256 `
27+
28+ - ` transfer(address to, uint256 value) → bool `
29+
30+ - ` allowance(address owner, address spender) → uint256 `
31+
32+ - ` approve(address spender, uint256 value) → bool `
33+
34+ - ` transferFrom(address from, address to, uint256 value) → bool `
35+
36+ - 事件:` Transfer(address indexed from, address indexed to, uint256 value) ` ;` Approval(address indexed owner, address indexed spender, uint256 value) `
37+
38+
39+ ** 可选元数据(主流实现都提供)**
40+
41+ - ` name() ` , ` symbol() ` , ` decimals() ` (通常 18)
42+
43+
44+ ** 语义与细节**
45+
46+ - ** 返回值必须是 ` bool true ` ** (历史上一些老合约不返回值,DeFi 里需用 SafeERC20 适配)。
47+
48+ - ** Mint/Burn 的事件:**
49+
50+ - 铸造:` from = address(0) ` 的 ` Transfer(0, to, value) `
51+
52+ - 销毁:` to = address(0) ` 的 ` Transfer(from, 0, value) `
53+
54+ - ** Approve 竞态(Allowance Race)** :如果 spender 已有额度 A,你把额度改为 B,在 Mempool 可被“夹击”(先花光 A 再把 B 生效)。
55+
56+ - 缓解:先 ` approve(spender, 0) ` 再设置新额度;或直接用 ** EIP-2612 permit** /** Permit2** 。
57+
58+
59+ # 2. DeFi 里最容易“踩雷”的行为与对策
60+
61+ - ** 前置授权两步流(approve→transferFrom)** :用户体验差、Gas 多、且有前述竞态。
62+ ✅ ** 对策** :优先支持 ** EIP-2612 Permit** (或引导用户/前端使用 Uniswap ** Permit2** )。
63+
64+ - ** “税费/通缩”代币(transfer 会扣税)** :金额不守恒,许多协议(AMM、金库、桥)若没对接好会出错。
65+ ✅ ** 对策** :处理** 到帐值与发送值可能不相等** ;或显式拒绝非标准代币。
66+
67+ - ** 不返回 bool 的老 ERC-20** :会在严格调用下 revert。
68+ ✅ ** 对策** :与外部代币交互一律用 ** SafeERC20** (包容不规范合约)。
69+
70+ - ** 重入假设** :ERC-20 本身无回调,但与 ** ERC-777** 或自定义 Hook 共用时需保持可重入安全(比如转账前后外部交互)。
71+ ✅ ** 对策** :** Checks-Effects-Interactions** 、必要时 ` ReentrancyGuard ` 、尽量“先记账再外调”。
72+
73+
74+ # 3. 技术栈
75+
76+ - ** 语言/编译器** :Solidity ^0.8.x(内置溢出检查;性能敏感处可 ` unchecked ` )
77+
78+ - ** 合约库** :OpenZeppelin Contracts(建议 v5 及以上)
79+
80+ - ` ERC20 ` / ` ERC20Permit ` / ` SafeERC20 ` / ` AccessControl ` / ` Ownable ` / ` Pausable ` / ` Snapshot ` / ` Votes ` 等
81+
82+ - ** 工具链**
83+
84+ - 开发:** Foundry** (forge + cast)或 ** Hardhat** (ethers、typechain)
85+
86+ - 安全:** Slither** 、** Mythril** 、** Echidna** (模糊测试)、** Foundry fuzz**
87+
88+ - 形式化/审计:Certora、Scribble(规范注释 + 静态仪表)
89+
90+ - ** 前端交互** :ethers.js / viem;钱包支持 EIP-712(MetaMask、Safe)
91+
92+ - ** 签名授权** :EIP-712(Typed Data) + EIP-2612 或 Permit2
93+
94+
95+ # 4. OpenZeppelin v5
96+
97+ ### 4.1 最小安全基线(含增减额度 API)
98+
99+ ``` solidity
100+ // SPDX-License-Identifier: MIT
101+ pragma solidity ^0.8.20;
102+
103+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
104+
105+ contract MyToken is ERC20 {
106+ constructor(string memory n, string memory s, uint256 initial)
107+ ERC20(n, s)
108+ {
109+ _mint(msg.sender, initial);
110+ }
111+
112+ // OZ v5 已内置 increaseAllowance / decreaseAllowance(通过 ERC20 扩展)
113+ // 使用前端引导:优先使用 permit,fallback 到 increase/decrease
114+ }
115+ ```
116+
117+ ** 重点**
118+
119+ - ** Solidity 0.8+** 内置溢出检查,耗气场景可在不影响安全的自增/自减里用 ` unchecked ` 。
120+
121+ - ** OpenZeppelin v5** 对内部结构做了清理与优化(见 6 节),默认实现已包含 best-practice。
122+
123+
124+ ### 4.2 加入 Permit(EIP-2612)
125+
126+ ``` solidity
127+ pragma solidity ^0.8.20;
128+
129+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
130+ import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
131+
132+ contract MyPermitToken is ERC20, ERC20Permit {
133+ constructor(uint256 initial)
134+ ERC20("MyPermitToken", "MPT")
135+ ERC20Permit("MyPermitToken") // EIP-712 Domain(name, version, chainId, verifyingContract)
136+ {
137+ _mint(msg.sender, initial);
138+ }
139+ }
140+ ```
141+
142+ ** 重点**
143+
144+ - 用钱包弹窗签名(EIP-712 typed data),合约侧 ` permit(owner, spender, value, deadline, v, r, s) ` 写入 ` nonces ` 与 ` allowance ` 。
145+
146+ - 前端** 一笔交易** 即可完成授权+业务;显著改善 UX 与 Gas。
147+
148+
149+ ### 4.3 金库/治理/黑天鹅控制(可选扩展)
150+
151+ - ** 可暂停(Pausable)** :黑天鹅或审计发现漏洞时快速止血
152+
153+ - ** 快照(Snapshot)** :治理/分红场景的历史余额证明
154+
155+ - ** 访问控制(Ownable/AccessControl)** :铸造、回收、白名单管控
156+
157+ - ** 投票(Votes)** :余额 → 治理权重(与快照语义一致)
158+
159+
160+ ``` solidity
161+ pragma solidity ^0.8.20;
162+
163+ import {ERC20, ERC20Burnable, ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
164+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
165+
166+ contract GovToken is ERC20, ERC20Burnable, ERC20Pausable, Ownable {
167+ constructor() ERC20("GovToken", "GOV") Ownable(msg.sender) {
168+ _mint(msg.sender, 1_000_000e18);
169+ }
170+
171+ function pause() external onlyOwner { _pause(); }
172+ function unpause() external onlyOwner { _unpause(); }
173+
174+ // 钩子在 v5 中通过内部 _update 统一调用(见第 6 节)
175+ function _update(address from, address to, uint256 value)
176+ internal
177+ override(ERC20, ERC20Pausable)
178+ {
179+ super._update(from, to, value);
180+ }
181+ }
182+ ```
183+
184+ # 5. ERC-20 交互的“协议侧”
185+
186+ - ** 使用 ` SafeERC20 ` ** (可兼容不返回 bool 的“古董币”)
187+ - 留心** 到帐量** 与** 发送量** 不一致的“税费代币”
188+ - 对接 ** Permit/Permit2** ,减少一次 ` approve ` 交易
189+
190+ ``` solidity
191+ pragma solidity ^0.8.20;
192+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
193+ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
194+
195+ contract Vault {
196+ using SafeERC20 for IERC20;
197+ IERC20 public immutable asset;
198+
199+ constructor(IERC20 _asset) { asset = _asset; }
200+
201+ function deposit(uint256 amt) external {
202+ uint256 beforeBal = asset.balanceOf(address(this));
203+ asset.safeTransferFrom(msg.sender, address(this), amt);
204+ uint256 received = asset.balanceOf(address(this)) - beforeBal; // 税费代币差额
205+ // 按 received 记账,避免金额错配
206+ }
207+ }
208+ ```
209+
210+ # 6. OpenZeppelin v5 “代码层面的变化/优化”
211+ - ** Hooks 重构为 ` _update ` 统一入口** :
212+ 以前常见 ` _beforeTokenTransfer/_afterTokenTransfer ` 已在 v5 中被** 统一为** ` ERC20._update(from, to, value) ` 。
213+
214+ - 你如果需要在转账/铸造/销毁时插入控制逻辑,** 重写 ` _update ` ** (就像上面 ` Pausable ` 的 override)。
215+
216+ - ** 更一致的自定义错误与 Gas 优化** :
217+
218+ - v5 广泛使用 ** custom errors** 、去除历史包袱(不再需要 SafeMath)。
219+
220+ - 一些内部函数布局更利于内联与 ` unchecked ` 性能优化。
221+
222+ - ** 扩展模块解耦更清晰** :
223+
224+ - ` ERC20Permit ` 、` ERC20Votes ` 、` Snapshot ` 等各司其职,组合更直观。
225+
226+ - ** 默认实现更“安全保守”** :
227+
228+ - 例如 ` increaseAllowance ` /` decreaseAllowance ` 早已内建,官方推荐替代直接改写 ` approve ` 的模式。
229+
230+
231+ # 7. Gas/存储优化清单
232+
233+ - ** ` immutable ` ** :代币的不可变参数(如金库的底层资产地址)用 ` immutable ` ,读成本低。
234+
235+ - ** ` unchecked ` ** :仅在你** 绝对确认** 不溢出的地方使用(如 ` totalSupply += amount ` 紧跟 ` require ` )。
236+
237+ - ** 事件索引** :` Transfer/Approval ` 的 indexed 字段已固定;自定义事件控制 ` indexed ` 数量(过多索引会加日志成本)。
238+
239+ - ** Slot 打包** :` mapping ` 无法与其它状态变量打包;但常量/少量 config 可放一个 struct 里一起布局(收益有限,别过度优化)。
240+
241+ - ** 外部调用最小化** :批量转账尽量在调用方循环而不是被调用方多次回调(协议设计层面优化)。
242+
243+
244+ # 8. 与“更上一层”的标准/组件协同
245+
246+ - ** EIP-2612(Permit)** :签名授权,提升 UX;强烈建议你的代币和协议** 同时支持** 。
247+
248+ - ** Permit2(Uniswap 工具合约)** :一个合约集中管理授权与签名核销,** 跨代币/跨合约** 统一;协议方集成最省心。
249+
250+ - ** EIP-4626(金库/Vault)** :如果你的 ERC-20 是** 收益凭证** 或** 份额代币** ,用 4626 统一“资产↔份额”换算,DeFi 可组合性大增。
251+
252+ - ** EIP-712(Typed Data)** :所有签名(Permit / off-chain order / meta-tx)底层都用它;前端与钱包交互标准化。
253+
254+
255+ # 9. ERC-20 + Permit + Ownable + Pausable
256+
257+ ``` solidity
258+ // SPDX-License-Identifier: MIT
259+ pragma solidity ^0.8.20;
260+
261+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
262+ import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
263+ import {ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
264+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
265+
266+ contract AppToken is ERC20, ERC20Permit, ERC20Pausable, Ownable {
267+ constructor(uint256 init)
268+ ERC20("AppToken", "APP")
269+ ERC20Permit("AppToken")
270+ Ownable(msg.sender)
271+ {
272+ _mint(msg.sender, init);
273+ }
274+
275+ function pause() external onlyOwner { _pause(); }
276+ function unpause() external onlyOwner { _unpause(); }
277+
278+ // v5:统一从这里拦截所有转账/铸销逻辑(Pausable 已在 super 里处理)
279+ function _update(address from, address to, uint256 value)
280+ internal
281+ override(ERC20, ERC20Pausable)
282+ {
283+ // 风控/黑名单/限频等也可写在这里(注意 gas & 误触发)
284+ super._update(from, to, value);
285+ }
286+ }
287+ ```
288+
289+ # 10. 测试与审计清单(理解成软测)
290+
291+ - ** 单元测试** :正/反路径、边界(0 值、极大值)、授权 race、税费代币模拟、Permit 非法签名/过期
292+
293+ - ** 模糊测试** (Foundry ` forge test --fuzz ` / Echidna):针对 ` transfer/transferFrom ` 不变量(守恒)、总供给不变(除非铸销)
294+
295+ - ** 静态分析** :Slither(未用返回值、可重入、可见性、不必要存储写)
296+
297+ - ** Gas 对比** :Foundry ` --gas-report ` ;对 ` _update ` 里自定义逻辑做 A/B
298+
18299# 2025-08-18
19300
20301# 🔑 1. ERC-20(EIP-20)
0 commit comments