合約解析
資料儲存
本專案的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. 儲存設計優勢
- 模組化:每個模組儲存獨立,降低耦合
- 可升級性:支援Facet升級而不影響儲存結構
- 安全性:儲存隔離防止越權訪問
- 可維護性:儲存結構集中管理,方便維護
- 可擴充性:新增功能只需新增對應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項目,能夠有效管理日益增長的狀態資料。