# OpenZeppelin 學習 ## 學習前預備 ### 為什麼要學習 1. 可以看懂,和看到套件就知道這個合約的功能是什麼 2. 能夠增進自己合約的閱讀能力 3. 觀摩怎麼樣才是好的合約 ### 學習後打算怎麼實用 1. 在閱讀開源合約時可以透過回想,不用每次都重新翻,增加閱讀理解和效率 2. 寫文章介紹OpenZepplin功能和用法 ### 計劃如何學習 粗略瀏覽過一次,先有大概的構想 詳細精讀重要的部分,略讀較不重要或自己會了的部分 ### 粗略學習,邊做邊獲得反饋 ## 內容 ### 大綱 - Contracts - 用於安全智能合約開發的庫。建立在經過社區審查的代碼的堅實基礎之上。 - Upgrades - OpenZeppelin 提供了用於部署和保護可升級智能合約的工具。 - 升級插件以部署具有自動安全檢查的可升級合約。 - 可升級合約,使用 Solidity 組件構建合約。 - Defender Admin用於管理生產升級和自動化操作。 - Defender - OpenZeppelin Defender 為以太坊提供了一個具有內置最佳實踐的安全操作 (SecOps) 平台。開發團隊實施 Defender 以加快交付速度並將安全風險降至最低 - Subgraphs - 用於輕鬆索引 OpenZeppelin Contracts 活動的模塊 - Test Helpers - 用於以太坊智能合約測試的斷言庫。確保您的合約按預期運行! - solidity-docgen - 智能合約庫的文檔生成器。使用 Solidity 代碼中的內聯文檔來生成網站或任何類型的文檔。 - 輸出可通過 Handlebars 模板完全自定義,這些模板提供對智能合約所有元數據的輕鬆訪問。 ## 筆記 ### Extending Contracts - Overriding - Calling super #### Using Hooks Hook 某些操作發生之前或之後調用的函數。它們提供了一個集中點來連接和擴展原始行為。 使用鉤子會導致代碼更乾淨、更安全,而不必依賴對父級內部結構的深入理解。 ##### Rules of Hooks virtual每當您覆蓋父掛鉤時,將屬性重新應用於掛鉤。這將允許子合約向鉤子添加更多功能。 始終使用super. 這將確保調用繼承樹中的所有鉤子:像這樣的合約ERC20Pausable依賴於這種行為。 ### Using with Upgrades oz 的可升級合約套件:https://docs.openzeppelin.com/upgrades-plugins/1.x/ UUPS 看敘述還是不太明白,可能要看合約 token合約(ERC): - 20 - 721 - 777 - 1155 Governance Utilities ### New Releases and API Stability #### Access Control Note that a contract can also be the owner of another one! This opens the door to using, for example, a Gnosis Multisig or Gnosis Safe, an Aragon DAO, an ERC725/uPort identity contract, or a totally custom contract that you create. - Ownership and Ownable - AccessControl - Granting and Revoking Roles - Querying Privileged Accounts #### TimelockController TimelockController is a proxy that is governed by proposers and executors. ### Token - ERC20 - ERC721 - ERC777 - ERC20升級版 - receive hooks - 可以拒絕被支付 - ERC1155 - 20+721+777 - batch transform ### Governance 工具 - Tally - Ethers.js 兼容性(與基於Compound 的GovernorAlpha 和GovernorBravo): - ERC20Votes & ERC20VotesComp - OpenZeppelin Governance & GovernorAlpha - GovernorTimelockControl & GovernorTimelockCompound Tally是一個成熟的應用程序,用於用戶擁有的鏈上治理。它包括投票儀表板、提案創建嚮導、實時研究和分析以及教育內容。 對於所有這些選項,Governor 將與 Tally 兼容:用戶將能夠創建提案、可視化投票權和擁護者、瀏覽提案並投票。特別是對於提案創建,項目還可以使用 Defender Admin 作為替代界面。 ### Utility 其他oz的套件包: - Cryptography - Checking Signatures On-Chain - Verifying Merkle Proofs - Introspection - whether or not a contract supports an interface you’d like to use - Detection: ERC165 - interface detection - 檢查是否支援介面 - Math(還有用嗎?) - Payment - PaymentSplitter(ex.抽成70趴) - PullPayment(讓使用者自己使用withdrawPayments() 來取平台回饋) - Escrow, ConditionalEscrow( 託管?) - Collections - EnumerableSet - EnumerableMap - Misc - Address.isContract() - Counters - Base64 - transform bytes32 data into its Base64 string - Multicall - bundles together multiple calls in a single external call - to let external accounts perform **atomic** operations comprising several function calls - 用法: - 繼承Multicall合約 - 調用multicall function(可以使用hardhat 或 truffle) ### Access Control - AccessControl - RBAC function - Ownable - simple owner can do something #### Contract ##### IAccessControl External interface of AccessControl declared to support ERC165 detection FUNCTIONS ``` { hasRole(role, account) getRoleAdmin(role) grantRole(role, account) revokeRole(role, account) renounceRole(role, account) } ``` ##### AccessControl Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn’t allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see [AccessControlEnumerable](https://docs.openzeppelin.com/contracts/4.x/api/access#AccessControlEnumerable). FUNCTIONS ``` { supportsInterface(interfaceId) hasRole(role, account) _checkRole(role, account) getRoleAdmin(role) grantRole(role, account) revokeRole(role, account) renounceRole(role, account) _setupRole(role, account) _setRoleAdmin(role, adminRole) _grantRole(role, account) _revokeRole(role, account) } ``` ##### IAccessControlEnumerable IAccessControl + ``` { getRoleMember(role, index) getRoleMemberCount(role) } ``` ### Common (Tokens) ERC2981:與 ERC721 和 ERC1155 兼容的 NFT 版稅 ### ERC 20 #### Draft EIPs(還沒有被定下來的EIP) ERC20Permit #### Presets 這些合約是上述功能的預配置組合。它們可以通過繼承或作為模型來複製和粘貼其源代碼。 #### Utilities SafeERC20 ##### TokenTimelock 一個代幣持有者合約,允許受益人在給定的發佈時間後提取代幣。 對於簡單的歸屬時間表很有用,例如“顧問在 1 年後獲得所有代幣”。 ### ERC721 ### ERC777 ERC20進化版 operator ->代替別人傳送或銷毀代幣 ### ERC 1155 ### Finance - PaymentSplitter - 抽版稅 - VestingWallet ### Interface 標準化接口 #### IERC1271 ERC-1271中定義的合約的 ERC1271 標準簽名驗證方法的接口。 isValidSignature(hash, signature) #### IERC1363 ERC20加強版 #### IERC1363Receiver onTransferReceived(operator, from, value, data) Any ERC1363 smart contract calls this function on the recipient after a transfer or a transferFrom. This function MAY throw to revert and reject the transfer. Return of other than the magic value MUST result in the transaction being reverted. Note: the token contract address is always the message sender. ->拒絕傳送 #### IERC2612 IERC20PERMIT #### IERC2981 NFT 版稅標準的接口。 一種檢索不可替代代幣 (NFT) 版稅支付信息的標準化方法,以實現對所有 NFT 市場和生態系統參與者的版稅支付的普遍支持。 ``` royaltyInfo(uint256 tokenId, uint256 salePrice) → address receiver, uint256 royaltyAmount ``` 根據可能以任何交換單位計價的銷售價格,返回應支付的特許權使用費以及向誰支付。特許權使用費金額以相同的交換單位計價並應支付。 #### 閃電貸 IERC3156FlashLender IERC3156FlashBorrower ### Meta Transactions ERC2771Context Context variant with ERC2771 support. ### Proxies 為了避免與代理背後的實現合約的存儲變量發生衝突,我們使用EIP1967存儲槽。 ERC1967Upgrade:獲取和設置 EIP1967 中定義的存儲槽的內部函數。 ERC1967Proxy:使用 EIP1967 存儲槽的代理。默認不可升級。 有兩種方法可以為 ERC1967 代理添加可升級性。 - TransparentUpgradeableProxy:具有內置管理和升級界面的代理。 - UUPSUpgradeable:要包含在實施合同中的可升級機制。 正確安全地使用可升級代理是一項艱鉅的任務,需要深入了解代理模式、Solidity 和 EVM。除非您想要大量低級控制,否則我們建議使用OpenZeppelin Upgrades Plugins for Truffle 和 Hardhat。 Hardhat: https://www.npmjs.com/package/@openzeppelin/hardhat-upgrades #### Beacon Proxy A different family of proxies are beacon proxies. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. - BeaconProxy: A proxy that retreives its implementation from a beacon contract. - UpgradeableBeacon: A beacon contract with a built in admin that can upgrade the BeaconProxy pointing to it. 在這種模式下,代理合約不像 ERC1967 代理那樣將實現地址保存在存儲中,而是將地址存儲在單獨的信標合約中。發送到信標而不是代理合約的upgrade操作,以及遵循該信標的所有代理都會自動升級。 #### Transparent vs UUPS Proxies OpenZeppelin 中包含的原始代理遵循Transparent代理模式。雖然仍然提供這種模式,但我們的建議現在轉向 UUPS 代理,它既輕量級又多功能。UUPS 的名稱來自EIP1822,它首先記錄了該模式。 雖然這兩者共享相同的升級接口,但在 UUPS 代理中,升級由實現處理,並且最終**可以被刪除**。另一方面,透明代理在代理本身中包含升級和管理邏輯。這意味著TransparentUpgradeableProxy部署比使用 UUPS 代理更昂貴。 --- UUPS 代理使用ERC1967Proxy. 代理本身不可升級。除了合約的邏輯之外,實現的作用是包含更新存儲在代理存儲空間中特定插槽中的實現地址所需的所有代碼。這就是UUPSUpgradeable合約的用武之地。從它繼承(並_authorizeUpgrade使用相關的訪問控制機制覆蓋該功能)會將您的合約變成符合 UUPS 的實現。 請注意,由於兩個代理使用相同的存儲槽作為實現地址,因此使用符合 UUPS 的實現和 aTransparentUpgradeableProxy可能允許非管理員執行升級操作。 默認情況下,其中包含的升級功能UUPSUpgradeable包含一個安全機制,該機制將阻止對不符合 UUPS 的實施進行任何升級。這可以防止升級到不包含必要升級機制的實現合約,因為它會永遠鎖定代理的可升級性。此安全機制可以通過以下任一方式繞過: 在實現中添加一個標誌機制,在觸發時將禁用升級功能。 在沒有額外安全檢查的情況下升級到具有升級機制的實現,然後再次升級到沒有升級機制的另一個實現。 這種安全機制的當前實現使用EIP1822來檢測實現使用的存儲槽。以前的實現,現在已棄用,依賴於回滾檢查。可以從使用舊機制的合約升級到新機制。然而,反過來是不可能的,因為舊的實現(4.5 版之前)不包括該ERC1822接口。 --- #### Core ##### Proxy 這個抽象合約提供了一個回退函數,它使用 EVM 指令將所有調用委託給另一個合約delegatecall。我們將第二個合約稱為代理背後的實現,它必須通過覆蓋虛擬_implementation函數來指定。 此外,可以通過該函數手動觸發對實現的委託,也可以通過該函數觸發_fallback不同的合約_delegate。 委託調用的成功和返回數據將返回給代理的調用者。 FUNCTIONS * _delegate(implementation) * _implementation() * _fallback() * fallback() * receive() * _beforeFallback() ##### ERC1967 ERC1967Proxy 該合約實現了一個可升級的代理。它是可升級的,因為調用被委託給可以更改的實現地址。此地址存儲在 EIP1967指定位置的 storage 中,因此它不會與代理後面的實現的存儲佈局衝突。 ERC1967PROXY ERC1967UPGRADE ##### Transparent Proxy 管理員無法使用代理功能,所以應使用專用帳戶 輔助合約 ###### ProxyAdmin 這是一份輔助合同,旨在被指定為TransparentUpgradeableProxy. 有關為什麼要使用它的說明,請參閱TransparentUpgradeableProxy. ##### BeaconProxy 該合約實現了一個代理,該代理從UpgradeableBeacon. 信標地址存儲在 storage slotuint256(keccak256('eip1967.proxy.beacon')) - 1中,因此它不會與代理背後的實現的存儲佈局衝突。 ###### 輔助合約 UpgradeableBeacon ## 進度 讀到升級 https://docs.openzeppelin.com/contracts/4.x/api/proxy#:~:text=beacon%20is%20changed.-,Minimal%20Clones,-Clones