Skip to main content

create2-patterns

Use when deploying contracts to deterministic addresses with CREATE2. Covers address prediction, salt selection, factory patterns, cross-chain same-address deployment, CREATE3, vanity addresses, and replay protection.

Ir para a instalação

Informações da origem

Repositório
ccashwell/evm-cortex
Última atividade na origem
10 de abril de 2026 às 16:31
Idioma detectado do SKILL.md
inglês
Estrelas
129
Forks
18

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
create2-patterns
description
Use when deploying contracts to deterministic addresses with CREATE2. Covers address prediction, salt selection, factory patterns, cross-chain same-address deployment, CREATE3, vanity addresses, and replay protection.
# CREATE2 Deterministic Deployment Patterns ## Address Calculation CREATE2 address is determined by four inputs: ``` address = keccak256(0xff ++ deployer ++ salt ++ keccak256(initCode))[12:] ``` ```solidity function computeAddress(bytes32 salt, bytes32 initCodeHash, address deployer) internal pure returns (address) { return address(uint160(uint256(keccak256(abi.encodePacked( bytes1(0xff), deployer, salt, initCodeHash ))))); } ``` ## Basic CREATE2 Factory ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; contract Create2Factory { event Deployed(address indexed addr, bytes32 indexed salt); function deploy(bytes32 salt, bytes memory creationCode) external payable returns (address deployed) { assembly { deployed := create2(callvalue(), add(creationCode, 0x20), mload(creationCode), salt) } require(deployed != address(0), "CREATE2: deployment failed"); emit Deployed(deployed, salt); } function computeAddress(bytes32 salt, bytes memory creationCode) external view returns (address) { bytes32 hash = keccak256(abi.encodePacked( bytes1(0xff), address(this), salt, keccak256(creationCode) )); return address(uint160(uint256(hash))); } } ``` ## Salt Selection Strategies ```solidity // Simple: use deployer address + nonce bytes32 salt = keccak256(abi.encode(msg.sender, nonce)); // Access-controlled: only specific deployer can use this salt bytes32 salt = keccak256(abi.encode(msg.sender, "MyContract-v1")); // Include constructor args in salt for uniqueness bytes32 salt = keccak256(abi.encode(msg.sender, name, symbol, initialSupply)); ``` ## Cross-Chain Same-Address Deployment To deploy at the same address on multiple chains: 1. Use the same factory contract address on all chains (deploy factory with CREATE2 from an EOA at same nonce, or use a known factory like Arachnid's) 2. Use the same salt 3. Use the same creation code (including constructor arguments) ```solidity // Arachnid's deterministic deployment proxy (deployed on most chains): // 0x4e59b44847b379578588920cA78FbF26c0B4956C // Deploy to same address on any chain: bytes memory initCode = abi.encodePacked(type(MyContract).creationCode, abi.encode(arg1, arg2)); bytes32 salt = keccak256("my-protocol-v1"); // Submit identical tx to factory on each chain ``` ## CREATE3 Pattern (Address Independent of Init Code) CREATE3 makes the deployed address independent of constructor arguments. Useful when constructor args differ per chain but you want the same address: ```solidity library CREATE3 { bytes internal constant PROXY_BYTECODE = hex"67363d3d37363d34f03d5260086018f3"; bytes32 internal constant PROXY_BYTECODE_HASH = keccak256(PROXY_BYTECODE); function deploy(bytes32 salt, bytes memory creationCode, uint256 value) internal returns (address deployed) { // Step 1: deploy a minimal proxy via CREATE2 (deterministic) address proxy; assembly { proxy := create2(0, add(PROXY_BYTECODE, 0x20), mload(PROXY_BYTECODE), salt) } require(proxy != address(0), "CREATE3: proxy deploy failed"); // Step 2: proxy deploys the real contract via CREATE (nonce-based) // The real contract address = f(proxy address, nonce=1) (bool ok,) = proxy.call{value: value}(creationCode); require(ok, "CREATE3: deploy failed"); deployed = addressOf(salt); } function addressOf(bytes32 salt) internal view returns (address) { address proxy = address(uint160(uint256(keccak256(abi.encodePacked( bytes1(0xff), address(this), salt, PROXY_BYTECODE_HASH ))))); return address(uint160(uint256(keccak256(abi.encodePacked( bytes2(0xd694), proxy, bytes1(0x01) ))))); } } ``` ## Replay Protection Prevent the same contract from being deployed twice to the same address: ```solidity contract SafeCreate2Factory { mapping(address => bool) public isDeployed; function deploy(bytes32 salt, bytes memory creationCode) external payable returns (address deployed) { deployed = _computeAddress(salt, creationCode); require(!isDeployed[deployed], "Already deployed"); assembly { deployed := create2(callvalue(), add(creationCode, 0x20), mload(creationCode), salt) } require(deployed != address(0), "Deploy failed"); isDeployed[deployed] = true; } } ``` ## Vanity Addresses Mine salts for addresses with desirable prefixes: ```solidity // Off-chain salt mining (pseudocode) // for salt in 0..2^256: // addr = computeCreate2Address(factory, salt, initCodeHash) // if addr starts with 0x0000: // return salt // Use create2crunch or similar GPU miner for efficient vanity search ``` ```bash # create2crunch: GPU-accelerated vanity address mining create2crunch --factory 0xFactory... --caller 0xCaller... \ --init-code-hash 0xHash... --leading 4 --total 6 ``` ## Foundry Testing ```solidity function test_create2_deterministic() public { bytes32 salt = keccak256("test-salt"); bytes memory initCode = abi.encodePacked( type(MyContract).creationCode, abi.encode("arg1", 42) ); address predicted = factory.computeAddress(salt, initCode); address deployed = factory.deploy(salt, initCode); assertEq(deployed, predicted, "Address mismatch"); assertGt(deployed.code.length, 0, "No code at address"); } function test_create2_sameAddressDifferentChains() public { bytes32 salt = keccak256("cross-chain"); bytes memory initCode = type(MyContract).creationCode; // Same factory + salt + initCode = same address regardless of chain address addr = factory.computeAddress(salt, initCode); assertTrue(addr != address(0)); } ``` ## Key Considerations - CREATE2 address depends on init code, so different constructor args = different address - CREATE3 removes init code dependency (address depends only on factory + salt) - If a contract is `selfdestruct`ed, a new contract CAN be deployed at the same CREATE2 address - `selfdestruct` is deprecated post-Dencun (EIP-6780) — only works in same tx as creation - Always verify the deployed bytecode matches expectations after cross-chain deployment
Ver no GitHub