Skip to content

Commit 8739bd8

Browse files
committed
Add study notes for 2025-08-19
1 parent 63e6d67 commit 8739bd8

1 file changed

Lines changed: 281 additions & 0 deletions

File tree

3956ray.md

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)