Skip to content

Commit 5969c4c

Browse files
committed
Add study notes for 2025-08-16
1 parent 584061a commit 5969c4c

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

KKisacat.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,106 @@ timezone: UTC+8
1515
## Notes
1616

1717
<!-- Content_START -->
18+
# 2025-08-16
19+
20+
### 存取控制(Access Control)
21+
```solidity=
22+
contract BadVault {
23+
mapping(address => uint256) public balance;
24+
25+
// 使用者存錢,沒問題
26+
function deposit() external payable {
27+
balance[msg.sender] += msg.value;
28+
}
29+
30+
// 沒有存取控制的提款函數
31+
function withdraw() public {
32+
payable(msg.sender).transfer(address(this).balance);
33+
}
34+
}
35+
```
36+
37+
#### 如何防範
38+
```solidity=
39+
// SPDX-License-Identifier: MIT // (1)
40+
pragma solidity ^0.8.20;
41+
42+
contract SafeUserVault {
43+
address public immutable owner; // 部署者 // (2)
44+
mapping(address => uint256) public balance; // 每個使用者的存款紀錄
45+
46+
constructor() {
47+
owner = msg.sender; // 部署者
48+
}
49+
50+
// 存錢:任何人都能存
51+
function deposit() external payable {
52+
balance[msg.sender] += msg.value;
53+
}
54+
55+
// 使用者自己提款 (CEI模式)
56+
function withdraw(uint256 amount) external {
57+
// Check
58+
require(balance[msg.sender] >= amount, "Not enough balance");
59+
60+
// Effects (先改狀態)
61+
balance[msg.sender] -= amount;
62+
63+
// Interactions (再轉錢)
64+
(bool ok, ) = msg.sender.call{value: amount}("");
65+
require(ok, "Transfer failed");
66+
}
67+
68+
// 部署者提取「整個金庫」
69+
function withdrawAll() external {
70+
require(msg.sender == owner, "Not owner");
71+
72+
uint256 amount = address(this).balance;
73+
require(amount > 0, "Vault empty");
74+
75+
(bool ok, ) = owner.call{value: amount}("");
76+
require(ok, "Transfer failed");
77+
}
78+
}
79+
```
80+
1. MIT授權是任何人都可以自由使用、修改、散佈你的程式碼,甚至可以用在商業用途。但必須保留原始的授權聲明(像上面這一行)。
81+
2. immutable 表示這個變數只能在 建構子(constructor)裡設定一次,之後不可更改,避免被惡意修改。
82+
3. call 跟 transfer 差異:
83+
* **transfer:**
84+
```solidity
85+
payable(to).transfer(amount);
86+
```
87+
* Gas 限制:
88+
最多只會給接收方 2300 gas。2300 gas 幾乎只能觸發 event 或寫個簡單的 log。接收方的 fallback 或 receive 函數裡,不能做複雜操作(例如寫入 storage、呼叫其他合約)。
89+
90+
* 錯誤處理:
91+
如果轉帳失敗(例如接收方的 fallback revert),整個交易會自動 revert。不需要手動檢查。
92+
93+
* 安全性:
94+
因為 gas 很低,幾乎無法被重入攻擊。
95+
96+
* 缺點:在 EIP-1884(以太坊升級) 之後,某些操作 gas 變貴,2300 gas 有時不足,會造成正常的轉帳失敗。
97+
98+
99+
* **call:**
100+
```solidity
101+
(bool ok, ) = to.call{value: amount}("");
102+
require(ok, "Transfer failed");
103+
104+
// 如果想限制 gas,可以寫
105+
to.call{value: amount, gas: 2300}("");
106+
```
107+
108+
* Gas 控制:
109+
預設會把「所有剩餘 gas」都交給接收方。接收方可以在 fallback/receive 裡執行很複雜的邏輯(甚至再呼叫回來 → 可能重入)。
110+
111+
* 錯誤處理:
112+
call 會回傳 (success, data)。不會自動 revert,要自己檢查 success。這讓開發者可以決定是否忽略錯誤或 revert。
113+
114+
* 安全性:
115+
因為可能給太多 gas,所以如果沒做好防護(例如重入鎖),可能被重入攻擊。
116+
但 call 比 transfer 彈性大,也比較不會因為 gas 限制而失敗。現在建議用call+檢查。
117+
18118
# 2025-08-15
19119

20120
## 安全實踐 -- 常見攻擊手段

0 commit comments

Comments
 (0)