Proxy-Contracts
了解 ERC1967Proxy 內部
我有一個可以儲存/檢索值的邏輯合約(Box.sol),我想通過 ERC1967Proxy 與之互動
問題: 直接更新一次盒子值後,通過代理檢索值返回預設值,而不是因為它是一個不同的盒子實例
行為:呼叫 proxy.retrieve 返回 0(預設框值)
預期:呼叫 proxy.retrieve 返回 5(之前手動更新的值)
這就是我所做的
- 部署邏輯合約 (Box.sol) => 儲存值為 0
- 直接與邏輯合約互動 => 儲存值被更新(例如:5)
- 在建構子中使用邏輯合約地址部署代理合約(MyProxy.sol)
- 通過 remix,我使用 Box ABI 檢索具有代理合約地址的值(從文件資源管理器選項卡中選擇 Box.sol,從事務選項卡中選擇“地址”按鈕,但使用代理的地址而不是部署的地址盒子)
最終部署狀態
盒子.sol
// contracts/Box.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Box { uint256 private _value; // Emitted when the stored value changes event ValueChanged(uint256 value); // Stores a new value in the contract function store(uint256 value) public { _value = value; emit ValueChanged(value); } // Reads the last stored value function retrieve() public view returns (uint256) { return _value; } }
MyProxy.sol
// contracts/Box.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract MyProxy is ERC1967Proxy { constructor(address _logic, bytes memory _data) ERC1967Proxy(_logic, _data) {} // debug method to expose the address function getImplementationAddress() public view returns(address) { return ERC1967Upgrade._getImplementation(); } }
Mikko Ohtamaa是對的。他的回答為我指明了正確的方向:
有幫助的文件是關於代理升級的 OpenZeppelin 文件
需要注意的一個非常重要的事情是程式碼使用了 EVM 的委託呼叫操作碼,該操作碼在呼叫者狀態的上下文中執行被呼叫者的程式碼。
所以這裡發生的是,執行的程式碼是由邏輯合約的字節碼創建的,但它是在代理儲存狀態下執行的,這也是為什麼你需要一個初始化程序而不是使用建構子的原因(參見建構子警告)
您誤解瞭如何使用代理合約處理狀態儲存。
部署邏輯合約 (Box.sol) => 儲存值為 0
直接與邏輯合約互動 => 儲存值被更新(例如:5)
這兩個動作都需要通過代理合約發生。永遠不要直接與實現合約互動。這樣狀態處理就得到了正確的管理。