Solidity
如何確定是否存在帶有 create2 地址的合約?
假設我有一個工廠契約,它使用
create2
子契約可能從未存在或可能已經存在但不再存在但通過例如自毀而不再存在的工廠契約,我如何檢查(在契約的createChild
方法內)是否具有create2 地址x
的契約目前存在以便不嘗試重新實例化它,或者我應該允許它嘗試重新實例化並讓呼叫恢復,因為您無法實例化已經存在的契約。
我在 Remix 中創建了一個簡單的測試範例,它展示了:
- 無法重新實例化目前存在的 create2 合約
- 在創建後變得不存在的 create2 合約可以像最初實例化一樣正常重新實例化。
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; contract Factory { mapping(uint => address) children; function createChild(uint id) public returns(address child) { bytes32 salt = keccak256(abi.encodePacked(id)); child = address(new Child{salt: salt}(id)); children[id] = child; } function destruct(uint childId) public { address _child = children[childId]; Child child = Child(_child); child.selfDestruct(); } } contract Child { uint immutable public id; constructor(uint _id) { id = _id; } function selfDestruct() public { selfdestruct(payable(address(this))); } }
您可以使用以下
getAddress
功能查看孩子的地址,而無需嘗試部署。當您擁有時,address child
您可以使用child.code.length
該地址獲取合約的執行時字節碼長度:如果它不為零,則意味著那裡已經部署了合約。contract Factory { ... function createChild(uint256 id) public returns(address child) { child = getAddress(id); if (child.code.length != 0) return child; // do nothing, already deployed bytes32 salt = keccak256(abi.encodePacked(id)); new Child{salt: salt}(id); children[id] = child; } function getAddress(uint256 id) public view returns(address) { bytes32 salt = keccak256(abi.encodePacked(id)); bytes32 bytecodeHash = keccak256(abi.encodePacked(type(Child).creationCode, id)); bytes32 _data = keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, bytecodeHash)); return address(uint160(uint256(_data))); } } contract Child { ... constructor(uint256 _id) { id = _id; } }