--- title: 'Solidity WTF 102 25 ~ 26 單元' lang: zh-tw --- Solidity WTF 102 25 ~ 26 單元 === :::info :date: 2024/10/07 ::: [TOC] # 課程學習 ## CREATE2 ### 簡介 其實與合約中創建新合約相關,只是創建方式不同。 #### CREATE 先來說說`CREATE`是如何計算地址 > 通常是創建者地址 + 該地址發送交易的總數,如果是合約帳戶則是創建合約的總數,每創建一次都會 nonce + 1 ```javascript= 新地址 = hash(创建者地址, nonce) ``` #### CREATE2 目的是為了讓合約地址獨立於未來的事件,也就是預測地址,他由以下四種方法去計算: - 0XFF: 一個長數,避免和CREATE衝突。 - CreatorAddress: 調用CREATE2的當前合約地址。 - salt: 一個創建者指定的bytes32類型的值,主要目的用來影響創建出來的合約地址。 - initcode: 新合約的初始字節。 ```javascript= 新地址 = hash("0xFF",创建者地址, salt, initcode) ``` ### 如何使用 與CREATE類似都是new一個合約出來,但是傳入的參數並不同: ```javascript= Contract x = new Contract{salt: _salt, value: _value}(params) ``` ### 如何提前計算Address 用來預測的方法,其實都是這四個參數帶入後取唯一值,就是我創建的新合約的地址。 ```javascript! predictedAddress = address(uint160(uint(keccak256(abi.encodePacked( bytes1(0xff), // 固定的前綴 address(this), // 部署該合約的創建者地址(工廠合約地址) salt, // 用於區分不同合約部署的隨機值 keccak256(type(Pair).creationCode) // 合約的創建碼的哈希值 ))))); ``` 如果在創建新合約中有值帶入,那就會是 ```javascript! predictedAddress = address(uint160(uint(keccak256(abi.encodePacked( bytes1(0xff), // 固定前綴,表明使用CREATE2 address(this), // 工廠合約地址 salt, // 隨機值 salt keccak256( abi.encodePacked( type(Pair).creationCode, // 合約創建碼 abi.encode(address(this) // 構造函數參數 ))) ))))); ``` :::success 這邊重點我認為應該是在怎麼去更改合約創建碼的內容,因為其餘都是複製貼上,並且清出了解與CREATE的差別。 ::: ## 刪除合約 ### 簡介 selfdestruct命令用來刪除合約,並將被刪除的該合約剩餘ETH轉到指定的地址。 > 如果想使用 SELFDESTRUCT 銷毀合約並釋放合約中的資源,那麼這必須是在同一筆交易內完成的,否則已經部署且在多筆交易中運行的合約不容易再通過 SELFDESTRUCT 來執行相同的功能。 :::info 早期被命名為suicide(自殺),後來改掉。 ::: :::warning 在V0.8.18版本中,selfdestruct關鍵字被標記為「不再建議使用」,目前還沒有替代方案,所以只是編譯階段的警告。[詳細看這裡 EIP-6049](https://eips.ethereum.org/EIPS/eip-6049) ::: ### 使用方式 `value`初始設置為10,並且有兩個函數`deleteContract() and getBalance()`,合約部屬後可以透過`msg.value`傳入`ETH`,並且這時呼叫`getBalance()`會返回傳入的ETH數量,`Value`仍然是`10`。當我們調用`deleteContract()`,會把合約中的`ETH`返回於`msg.sender`。 ```javascript! // _addr是接收合約中剩餘的ETH地址。不需有receive() or fallback()也能接收。 selfdestruct(_addr); // 下列是範例 contract DeleteContract { uint public value = 10; constructor() payable {} receive() external payable {} function deleteContract() external { // 调用selfdestruct销毁合约,并把剩余的ETH转给msg.sender selfdestruct(payable(msg.sender)); } function getBalance() external view returns(uint balance){ balance = address(this).balance; } } ``` :::warning 這邊有個重點,**在坎昆升級前,合約是會被自毀的,升級後,合約會依然存在,只是將合約包含的ETH轉移到指定地址中,而合約依然可以調用**。所以在調用`deleteContract()`後,`value`仍然是`10`。 :::