將合約部署到您想要的特定地址有多難?
讓我們考慮兩種情況:
- 地址 X 將 Uniswap 程式碼部署到 ETH 主網,
Create2
操作碼指向地址 Y- 地址 X 將 Uniswap 程式碼部署到 ETH 主網,
Create
操作碼指向地址 Z我是地址 A 的一個無關錢包,我想將 Uniswap 部署到 EVM 鏈 E(尚未部署 Uniswap 程式碼)。
知道create和create2是如何工作的,地址 A 上的無關參與者將 Uniswap 合約部署到 EVM 鏈 E 並確定性地選擇地址 Y 或地址 Z 即使他們不是原始發送者(即地址 X)是多麼容易? 是否可以在 EVM 鏈 E 上使用 uniswap 程式碼在 Uniswap 地址上“蹲”?
讓我看看我是否理解你的需要…
所以,你想知道任何人(除了合約所有者)在另一個與 EVM 兼容的鏈中部署一個與另一個鏈中的現有合約地址相同的合約有多難?
簡短的回答:
平均需要 2**256 次嘗試
salt
為 EVM 創建具有所需地址的合約,因為create2
使用創建者合約的地址將其與creationCode
鹽混合以生成新的合約地址。這意味著該人將需要在另一條鏈中擁有一個私鑰,該私鑰會生成一個公鑰,該公鑰會生成一個與原始鏈中完全相同的地址/帳戶,從而進行交易,直到將隨機數設置為原始使用者在創建他的智能合約時擁有的隨機數,並且該智能合約本身確保具有正確的隨機數,就像原始使用者創建其智能合約時一樣,或者如果它使用create2
然後使用與原始合約相同的設置並加鹽。所以,實際上,應該是同一個人,因為我們都知道猜測私鑰是不可行的。長答案:
create2
操作碼不接受任意地址作為輸入,即使在創建它時也不new TestDeployContract{salt: hash}()
接受. 它獲取創建合約的地址,我們無法強制它獲取我們想要的任意地址。
create2
因此,對我們擁有的操作碼的唯一控制是bytecode
合約的 和salt
,在您的情況下,我們希望部署與原始鏈中完全相同的字節碼,因此無法更改此選項。我們知道
keccak256
散列從給定的數據中產生一個 256 位的數字。EVMcreate2
使用keccak256
將其與合約字節碼、創建者合約的地址和鹽混合來派生新的合約地址。如果我們可以通過某種方式傳遞一個salt
隨機數,這可以使生成的雜湊與原始鏈keccak256
中create2
生成的雜湊相同。我們都知道這將是蠻力。嘗試在
keccak256
給定不同輸入的情況下創建相同的輸出是不可行的。因此,平均而言,它需要2**256
嘗試,生成隨機鹽,並嘗試手動計算地址以查看它是否與我們想要的相同。所以,回答你的問題,是的,這很難,真的很難,
2**256
很難,或者至少2**160
,因為算法複製了最後 20 個字節keccak256
以將其用作地址。所以,理論上,我們需要嘗試,蠻力,直到雜湊的最後 20 個字節是我們所期望的。一些帶有一些範例和註釋的程式碼:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; contract TestDeployContract { uint256 public id = 50; } contract Contract { // Using keccak256 hash of the contract name to use it as the salt bytes32 hash = keccak256("TestDeployContract"); uint256 hashValue = uint(keccak256("TestDeployContract")); address public testDeployContractAddress; // Function to derive the address of a smart contract. function getAddress() public view returns (address) { // Passing address(this) manually here. But we have no option to provide any address we want when actually deploying the contract with create2 bytes32 hash32 = keccak256( abi.encodePacked(bytes1(0xff), address(this), hashValue, keccak256(type(TestDeployContract).creationCode)) ); return address(uint160(uint(hash32))); } function createContract() public { // No option provide any creator address we want when actually deploying the contract // So it uses the address of the contract that is executing this code, // mix it with the bytecode of the TestDeployContract and the salt to produce a // keccak256 hash and derive the new contract address from it TestDeployContract testDeployContract = new TestDeployContract{salt: hash}(); testDeployContractAddress = address(testDeployContract); } }