合約解析

資料儲存

本專案的storage設計採用了模組化、隔離式的儲存模式,結合了EIP-2535 Diamond模式的特性,具體解析如下:

1. 儲存設計核心模式

專案採用庫儲存模式(Library Storage Pattern),透過獨立的Storage庫合約管理不同模組的存儲,實現了儲存與邏輯的分離,具體特點:

  • 每個功能模組(Facet或應用程式)擁有獨立的Storage庫
  • 使用bytes32常數定義唯一儲存槽位(透過keccak256產生)
  • 提供load()函數透過內聯彙編存取特定插槽的存儲
  • 儲存結構封裝在struct中,確保資料組織的清晰性

2. 儲存層次結構

(1)通用Facet存儲

  • 位置/contracts/facets下各Facet目錄
  • 範例
  • DiamondLoupeStorage:管理鑽石切面元數據
  • AccessControlStorage:儲存使用者角色和權限資訊
  • ERC1155Storage:管理NFT資產數據
  • 特點:獨立於具體應用,可被多個項目重複使用
  • 存取方式:透過[StorageName].load()函數,如/contracts/facets/DiamondLoupe/Storage.sol

(2)應用程式級存儲

  • 位置/contracts/apps下各應用目錄
  • 範例
  • /contracts/apps/TokenUnlocker/AppStorage.sol
  • /contracts/apps/TuringMarket/AppStorage.sol
  • 特點
  • 包含應用專用的業務資料結構
  • 透過繼承AppStorage合約存取(內部s變數)
  • 儲存應用特定的狀態變數和映射

3. 關鍵技術實現

(1)儲存槽位隔離

每個Storage庫使用唯一的儲存槽位,避免儲存衝突:

bytes32 internal constant POSITION = keccak256("DiamondLoupeStorage");

(2)儲存存取機制

透過內嵌彙編實現高效率的儲存存取:

function load() internal pure returns (Storage storage $) {
 bytes32 position = POSITION;
 assembly {
 $.slot := position
 }
}

(3)應用儲存封裝

應用程式儲存透過合約繼承方式提供存取:

contract AppStorage {
 struct Storage {
 // 業務資料結構
 }
 Storage internal s;
}

(4)型別哈希定義

儲存庫中定義TYPEHASH_*常數用於EIP-712簽章驗證:

bytes32 constant TYPEHASH_ORDER = keccak256("Order(uint256 salt,address maker,...)");

4. 儲存設計優勢

  1. 模組化:每個模組儲存獨立,降低耦合
  2. 可升級性:支援Facet升級而不影響儲存結構
  3. 安全性:儲存隔離防止越權訪問
  4. 可維護性:儲存結構集中管理,方便維護
  5. 可擴充性:新增功能只需新增對應Storage庫

5. 典型儲存結構範例

(1)通用Facet儲存(DiamondLoupeStorage)

struct Storage {
 mapping(bytes4 interfaceId => bool isSupported) supportedInterfaces;
}

(2)應用程式儲存(TokenUnlocker AppStorage)

struct Storage {
 uint256 vaultsCount;
 mapping(uint256 => Vault) vaultsMap;
 uint256 unlockedSchedulesCount;
 mapping(uint256 => UnlockedSchedule) unlockedSchedulesMap;
 // 更多業務相關儲存...
}

總結

本專案的storage設計充分利用了Solidity的庫功能和EIP-2535的特性,實現了儲存的模組化、隔離化和高效存取。透過將儲存邏輯與業務邏輯分離,提高了程式碼的可維護性和可升級性,同時確保了資料的安全性和完整性。這種設計模式特別適合大型、複雜的DApp項目,能夠有效管理日益增長的狀態資料。