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.

Aller à l'installation

Informations de source

Dépôt
ccashwell/evm-cortex
Dernière activité de la source
10 avril 2026 à 16:31
Langue détectée de SKILL.md
anglais
Étoiles
129
Forks
18

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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
Voir sur GitHub