智能合約開發

Yul / 內聯組合語言

Yul 與內聯組合語言是 Solidity 底下的一道暗門,讓你寫出非常接近原始 EVM 操作碼的東西。當你需要高階語言不肯給你的控制或 gas 節省時,你就落入一個 assembly 區塊——在代理中轉發 delegatecall、做緊湊的低階數學,或觸及 Solidity 未暴露的某個操作碼。

Yul 是一種低階中間語言,語法小巧而可讀;內聯組合語言透過一個 assembly { } 區塊把 Yul 嵌入 Solidity 函數中。它幾乎直接暴露操作碼:mload 與 mstore 操作記憶體、sload 與 sstore 操作儲存、call/delegatecall/staticcall 做跨合約呼叫、calldatacopy 與 returndatacopy 搬移資料、create2 做確定性部署,等等。你也要親手管理記憶體,遵守存於位址 0x40 的自由記憶體指標。這正是代理轉發呼叫、函式庫壓榨 gas 所在的那一層。

危險在於組合語言完全繞過 Solidity 的護欄:沒有溢位檢查、沒有陣列邊界檢查、沒有型別安全。單一個錯誤的偏移量就能默默覆寫記憶體或寫入錯誤的儲存槽,毫無錯誤地損毀狀態。編譯器對 assembly 區塊內已最佳化與會警告的行為也較少推理。應遵守的紀律是:讓組合語言保持精簡、大量註解,並盡量從經過審計的來源(OpenZeppelin、Solady)複製而非自行手寫——你省下的 gas 很少值得一個記憶體損毀的錯誤。

assembly {
  let ptr := mload(0x40)        // free memory pointer
  mstore(ptr, sload(slot))      // raw storage read into memory
  // no bounds, no overflow checks: you are on your own
}

最大的控制、零護欄。

在組合語言內沒有任何安全網。編譯器完全信任你,所以打錯的記憶體偏移或儲存槽不會報錯——它會默默損毀。少用它,並嚴格審計它。