-sender address (CREATE2 Factory is the sender in this context to execute the CREATE2 opcode)-salt-byteCode [creationCode since constructor input arguments can change the byteCode value]
Create a contract with SELFDESTRUCT in a function only the owner can access to keep the contract secure.
:::danger WARNING
Calling SELFDESTRUCT will delete all data in a contract! Be very careful using it.
Goerli supports SELFDESTRUCT while Shardeum currently does not. SELFDESTRUCT might
also be deprecated with EIP-4758: https://eips.ethereum.org/EIPS/eip-4758.
:::
Deploy a contract using a CREATE2 Factory.
:::caution Caution
Remember this CREATE2 Factory address and the salt you used for the contract byteCode deployed.
:::
Once the contract is deployed from the CREATE2 Factory, call SELFDESTRUCT.
:::danger WARNING
If you skip this step 3, you will see the following error on the Shardeum explorer:
create collision
since there is a contract at that address that hasn't been destroyed yet.
:::
Use the same CREATE2 Factory contract at the same address to deploy the contract with the same byteCode and salt.
Doing this will kill a contract at an address, then bring it back to life at the same address.
-saving gas: -factory can be used for other contracts since it takes raw creationCode -constructors cannot be payable (callvalue() [msg.value in assembly] set to 0, saves gas) -constructors cannot have arguments (memory variables not used saves gas)-creationCode == runtimeCode, since there are no constructor arguments changing the byteCode
// SPDX-License-Identifier: MITpragma solidity 0.8.17;error notOwner();contract ContractToDeployMetamask { //Bytecode matches creation code with no constructor input arguments. Bytecode with tutorial address 0xc1202e7d42655F23097476f6D48006fE56d38d4f: //0x60a060405234801561001057600080fd5b5073c1202e7d42655f23097476f6d48006fe56d38d4f73ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250506080516102c96100806000396000818160bb0152818160df015261016401526102c96000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806321cf146c14610051578063b4a99a4e1461006f578063f81bfa3f1461008d578063f965e32e14610097575b600080fd5b6100596100b3565b60405161006691906101be565b60405180910390f35b6100776100b9565b604051610084919061021a565b60405180910390f35b6100956100dd565b005b6100b160048036038101906100ac9190610266565b61019b565b005b60005481565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610162576040517f251c9d6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16ff5b8060008190555050565b6000819050919050565b6101b8816101a5565b82525050565b60006020820190506101d360008301846101af565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610204826101d9565b9050919050565b610214816101f9565b82525050565b600060208201905061022f600083018461020b565b92915050565b600080fd5b610243816101a5565b811461024e57600080fd5b50565b6000813590506102608161023a565b92915050565b60006020828403121561027c5761027b610235565b5b600061028a84828501610251565b9150509291505056fea2646970667358221220f13ed2f135ac0e33e3f372e325eaa526fa74eefc16e73495164e7b2549f0974464736f6c63430008110033 uint public storageSlot0; address public immutable Owner; constructor() { // Put your address as Owner instead of msg.sender because msg.sender will be another contract with CREATE2 salt deploy. Owner = 0xc1202e7d42655F23097476f6D48006fE56d38d4f; // Metamask address for tutorial. } // Do not do tx.origin because someone can front run you during contract creation! function changeValue(uint updateStorageSlot) public { storageSlot0 = updateStorageSlot; } function killThisContract() public { //After a contract is killed at an address, you can deploy another contract at that address. if(msg.sender != Owner) { revert notOwner(); } selfdestruct(payable(Owner)); //Deletes all data from this contract address. Address inside selfdestruct call gets all ether in the contract self destructing. } }contract Create2Factory { event create2Event(address deployedAddressEvent); function generalDeployCreate2(uint _salt, bytes memory creationCode) public { // BYTECODE NEEDS TO HAVE "0X" PREFIX TO BUILD RLP! address deployedAddress; // Salt example: 0x0000000000000000000000000000000000000000000000000000000000000000 assembly { // Another salt example: 0x123456789abcdef0000000000000000000000000000000000000000000000000 deployedAddress := create2(0, add(creationCode, 0x20), mload(creationCode), _salt) //callvalue() is the same as msg.value in assembly. callvalue() == 0 to save gas since the constructor and this create2 function are not payable. if iszero(extcodesize(deployedAddress)) { //Note: constructor is not payable and takes no input variables (hardcoded in) to keep the creation code simple for this example. revert(0, 0) } } emit create2Event(deployedAddress); } function generalPrecomputeAddress(uint _salt, bytes memory creationCode) public view returns (address) { // BYTECODE NEEDS TO HAVE "0X" PREFIX TO BUILD RLP! bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(creationCode))); return address(uint160(uint(hash))); }}
-building creationCode directly inside CREATE2 Factory functions with constructor argument values-keeping contract deployment simple without needing to deploy other contracts with general byteCode
// SPDX-License-Identifier: MITpragma solidity 0.8.17;error notOwner();contract ContractToDeploy { uint public storageSlot0; address public immutable Owner; constructor(address inputAddress) payable { Owner = inputAddress; //Need to put address as input instead of msg.sender because msg.sender will be another contract with CREATE2 salt deploy. } function changeValue(uint updateStorageSlot) public { storageSlot0 = updateStorageSlot; } function killThisContract() public { //After a contract is killed at an address, you can deploy another contract at that address. if(msg.sender != Owner) { revert notOwner(); } selfdestruct(payable(Owner)); //Deletes all data from this contract. }}contract Create2Factory { //Modified from: "Create2 | Solidity 0.8" by Smart Contract Programmer https://www.youtube.com/watch?v=883-koWrsO4&ab_channel=SmartContractProgrammer event create2Event(address deployedAddressEvent); function create2DeployContract(bytes32 _salt, address ownerAddress) public payable { // Salt example: 0x0000000000000000000000000000000000000000000000000000000000000000 ContractToDeploy deployedAddress = new ContractToDeploy {value: msg.value, salt: _salt}(ownerAddress); // Another salt example: 0x123456789abcdef0000000000000000000000000000000000000000000000000 emit create2Event(address(deployedAddress)); } function precomputeAddress(uint _salt, address ownerAddress) public view returns (address) { bytes memory creationCodeValue = abi.encodePacked(type(ContractToDeploy).creationCode, abi.encode(ownerAddress)); bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(creationCodeValue))); return address(uint160(uint(hash))); }}