智能合約開發

透明代理

透明代理是對代理模式一個棘手角落的特定解答:萬一實作恰好有一個函數,其 4 位元組選擇器與代理自身的升級函數相同,怎麼辦?若沒有規則,一個使用者呼叫可能產生歧義。透明模式以「依誰在呼叫來決定」來化解它。

代理在每次呼叫時檢查 msg.sender。若呼叫者是管理員(慣例上是一個獨立的 ProxyAdmin 合約),呼叫就被路由到代理自身的管理函數,例如 upgradeTo 與 changeAdmin,絕不轉發給實作。其他每一個呼叫者都被直接 delegatecall 穿透到實作,即使某個選擇器原本會與管理函數碰撞也是如此。這乾淨地保證了一般使用者永遠無法不小心——或惡意地——觸發管理函數,而管理員也永遠不會不小心執行實作邏輯。

代價是 gas:每一個使用者呼叫,除了正常的 delegatecall,還要多付一次冷 SLOAD 來讀取管理員槽位,外加一次比較。由於這條「誰在呼叫」的規則,管理員必須是一個合約(ProxyAdmin)或多簽,而不能是同時想使用該 dapp 的外部帳戶——一個管理員 EOA 確實無法透過代理呼叫實作的使用者函數。OpenZeppelin 的 TransparentUpgradeableProxy 是經典實作;較精簡的 UUPS 模式部分正是為了避免這種每次呼叫的開銷而設計。

// inside the proxy, conceptually:
if (msg.sender == admin) {
  // run proxy admin functions (upgradeTo, changeAdmin)
} else {
  // delegatecall to the implementation
}

依呼叫者路由,避開管理員與實作的選擇器碰撞。

讓代理的管理員與任何使用該合約的帳戶分開。管理員 EOA 無法觸及實作的函數,所以來自管理員位址的 dapp 呼叫會默默地改路由進代理的管理邏輯。