Ethereum Proxy Contract
微微介紹
(DELEGATECALL, Fallback Function, Contract Storage Model)
為什麼要用 proxy contract
- 減少 deployment 的 transaction fee
- 利用 proxy 的機制可以設計能夠 upgrade 的合約
Proxy
Contract
Logic
Contract
User
先來看一下合約
pragma solidity >=0.4.0 <=0.6.0;
contract ExampleDapp {
string dapp_name; // state variable
// Get Function
function read_name() public view returns(string) {
return dapp_name;
}
// Set Function
function update_name(string value) public {
dapp_name = value;
}
}
→ 會存在合約 storage 內
→ 改動合約 storage
→ 讀取合約 storage
- 合約有自己的 storage
- 合約內的 functions 會存取 storage
使用 proxy 的話
在 A 合約的 context,執行 B 合約的 function
這個主要是透過 EVM 的 DELEGATECALL 來達成
B 的 function 執行時 存取的是 A 的變數

EIP-1167 Minimal Proxy
把所有的 function call 都交給 logic contract 執行
它的 bytecode 只有這樣
其中 bebebebebebebebebebebebebebebebebebebebe 會是 logic contract 的地址
363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3
要怎麼看懂這個合約
不過有很讚的 OpenZeppelin 教大家看
因為他是直接寫 bytecode 所以不好懂
原理就是只寫一個 fallback function
把所有 message call 都用 DELEGATECALL 的方式
轉給寫死的 logic contract 來執行

(這個是 OpCode 的好讀版)
Fallback Function
收到的 call 沒有對應的 function
就會執行 fallback function
甚至是沒有帶 data,單純送錢的 call
也執行 fallback function
題外話 The DAO hack
大家知道現在的以太坊區塊鏈
其實有被硬改過
有些歷史被抹掉了 QQ
contract TheDao {
function refund() {
check(sender);
sender.send(value);
update(sender);
}
}
contract Hack {
function fallback() {
if (canRefund) {
TheDao.refund();
}
}
}
用 minimal proxy 的好處
bytecode 很短,部署合約很便宜
如果需要大量一模一樣邏輯
但又要不同地址、不同狀態的合約
用 proxy 就很省
如果想要合約可以 upgrade
就不能用 minimal proxy 的方式
因為它把 logic contract 的地址寫死在 bytecode 了
有點像是寫死在 web server 的程式碼裡面這樣
我們知道合約程式碼是不能修改的
那有可能可以把 logic contract 的地址
寫在 storage (db) 裡面 讓它可以被改嗎
可以啊 不過
可能會怎麼寫
這樣可以嗎
不行
contract Proxy {
address public logic;
function upgrade(address newLogic) {
logic = newLogic;
}
function () {
...
...delegatecall...
...
}
}
}
contract Logic {
uint256 public a;
uint256 public b;
function A() {
...
}
function B() {
...
}
}
合約的 storage model
storage 可以想成一個 sparse 的 array
solidity 的 compliler
會照 variable 宣告的順序
指定它們的 index (slot)

所以 slot 會衝到
proxy 自己保留的變數
要小心不要讓 logic contract 用到同一個 slot
所以要往後放
像這樣把 upgrade 的邏輯
保留在 proxy 合約這邊
其它交給 logic 合約的 pattern
非常常見
目前也很多不同作法
來看看 USDC 合約
另外補充
function 看起來不會衝到
(因為 proxy 優先 沒有才 fallback)
但是要注意一個問題
看起來不同的 function 可能會有一樣的 signature
(function clashing)
合約程式編譯完
function 會有一個 id (signature)
這個 id 是經過一個 hash 然後取前 4 個 bytes 來的
例如 →→→
大家都用 proxy,要怎麼看得出來這個合約在幹麻
(Minimal Proxy 可以直接看 bytecode 知道 implementation 合約地址)
參考資料
ethereum proxy contract
By luyunghsien
ethereum proxy contract
- 574