This page is a placeholder. All examples on this page are currently AI-generated and are not correct. This documentation will be completed in the future with accurate, tested examples.
Overview
Opcode: 0xf0
Introduced: Frontier (EVM genesis)
CREATE deploys a new contract by executing initialization code and storing the resulting runtime bytecode. The new contract’s address is deterministically computed from the creator’s address and nonce.
Specification
Stack Input:
value (wei to send)
offset (memory offset of init code)
length (size of init code)
Stack Output:
address (deployed contract address, or 0 if failed)
Gas Cost: 32,000 + init_code_cost + memory_expansion + deployment_cost
Operation:
address = keccak256(rlp([sender_address, sender_nonce]))[12:]
success = deploy(address, init_code, value, gas * 63/64)
push(success ? address : 0)
Behavior
CREATE executes a multi-step deployment process:
- Pop stack arguments: value, memory offset, length
- Charge gas: Base 32,000 + init code cost + memory expansion
- Read init code from memory at offset:length
- Compute address:
keccak256(rlp([sender, nonce]))[12:]
- Forward gas: Up to 63/64 of remaining gas (EIP-150)
- Execute init code in new context with forwarded gas
- Store runtime code returned by init code (charged 200 gas/byte)
- Push address to stack (0 if deployment failed)
- Refund unused gas from child execution
- Clear return_data on success, set to child output on failure
Key rules:
- Cannot be called in static context (EIP-214)
- Init code executes with empty storage/code
- Nonce incremented before address computation
- Init code size limited to 49,152 bytes (EIP-3860)
- Runtime code size limited to 24,576 bytes (EIP-170)
Examples
Basic Contract Creation
import { CREATE } from '@tevm/voltaire/evm/system';
import { createFrame } from '@tevm/voltaire/evm/Frame';
const frame = createFrame({
gasRemaining: 1000000n,
address: Address("0x1234..."),
nonce: 5n
});
// Init code: PUSH1 0x42 PUSH1 0x00 MSTORE PUSH1 0x01 PUSH1 0x1f RETURN
// Returns single byte: 0x42
const initCode = Bytecode([
0x60, 0x42, // PUSH1 0x42
0x60, 0x00, // PUSH1 0x00
0x52, // MSTORE
0x60, 0x01, // PUSH1 0x01 (length)
0x60, 0x1f, // PUSH1 0x1f (offset)
0xf3 // RETURN
]);
// Write init code to memory
for (let i = 0; i < initCode.length; i++) {
frame.memory.set(i, initCode[i]);
}
// Stack: [value=0, offset=0, length=9]
frame.stack.push(9n); // length
frame.stack.push(0n); // offset
frame.stack.push(0n); // value
const err = CREATE(frame);
console.log(err); // null (success)
console.log(frame.stack[0]); // address (non-zero if successful)
console.log(frame.return_data); // empty on success
Address Prediction
import { Address } from '@tevm/voltaire/primitives';
import { keccak256 } from '@tevm/voltaire/crypto';
import { RLP } from '@tevm/voltaire/primitives';
function predictAddress(creator: Address, nonce: bigint): Address {
// CREATE address = keccak256(rlp([sender, nonce]))[12:]
const encoded = RLP.encode([
creator,
nonce
]);
const hash = keccak256(encoded);
return Address(hash.slice(12));
}
const creator = Address("0x742d35Cc6634C0532925a3b844Bc454e4438f44e");
const nonce = 5n;
const predictedAddr = predictAddress(creator, nonce);
console.log(predictedAddr); // Address where contract will be deployed
Factory Contract
contract Factory {
event Deployed(address indexed contractAddress, address indexed creator);
// Deploy new contract and return address
function deployContract(bytes memory initCode) external returns (address) {
address contractAddr;
assembly {
// CREATE(value, offset, length)
contractAddr := create(
0, // No ETH sent
add(initCode, 0x20), // Skip length prefix
mload(initCode) // Init code length
)
// Revert if deployment failed
if iszero(contractAddr) {
revert(0, 0)
}
}
emit Deployed(contractAddr, msg.sender);
return contractAddr;
}
// Predict next deployment address
function predictNextAddress() external view returns (address) {
// Address of this contract
address factory = address(this);
// Next nonce will be current nonce + 1
uint256 nonce = vm.getNonce(factory) + 1;
// Compute CREATE address
return address(uint160(uint256(keccak256(abi.encodePacked(
bytes1(0xd6), // RLP prefix for [address, nonce] with nonce < 128
bytes1(0x94), // RLP prefix for 20-byte address
factory,
bytes1(uint8(nonce))
)))));
}
}
Constructor with Arguments
contract Example {
uint256 public value;
address public owner;
constructor(uint256 _value) {
value = _value;
owner = msg.sender;
}
}
contract Deployer {
function deploy(uint256 constructorArg) external returns (address) {
// Get creation bytecode with encoded constructor args
bytes memory bytecode = abi.encodePacked(
type(Example).creationCode,
abi.encode(constructorArg)
);
address deployed;
assembly {
deployed := create(0, add(bytecode, 32), mload(bytecode))
}
return deployed;
}
}
Gas Cost
Total cost: 32,000 + init_code_cost + memory_expansion + deployment_cost
Base Cost: 32,000 gas
Fixed cost for CREATE operation.
Init Code Cost (EIP-3860)
Shanghai+: 2 gas per word (32 bytes)
init_code_cost = 2 * ceil(init_code_length / 32)
Pre-Shanghai: No init code cost.
Memory Expansion
Dynamic cost for reading init code from memory:
words_needed = ceil((offset + length) / 32)
expansion_cost = (words_needed)² / 512 + 3 * (words_needed - current_words)
Deployment Cost
Runtime code storage: 200 gas per byte of returned code
deployment_cost = 200 * runtime_code_length
Gas Forwarding (EIP-150)
Tangerine Whistle+: Forward up to 63/64 of remaining gas:
gas_after_charge = remaining_gas - total_cost
max_forwarded = gas_after_charge - (gas_after_charge / 64)
Pre-Tangerine Whistle: Forward all remaining gas after charging.
Example Calculation
// Deploy contract with 100-byte init code, returns 50-byte runtime code
const initCodeLength = 100;
const runtimeCodeLength = 50;
// Base cost
const baseCost = 32000;
// Init code cost (Shanghai+): 2 gas/word
const initCodeWords = Math.ceil(initCodeLength / 32); // 4 words
const initCodeCost = 2 * initCodeWords; // 8 gas
// Memory expansion (assume clean memory)
const memWords = Math.ceil(initCodeLength / 32); // 4 words
const memCost = Math.floor(memWords ** 2 / 512) + 3 * memWords; // 12 gas
// Deployment cost: 200 gas/byte
const deploymentCost = 200 * runtimeCodeLength; // 10,000 gas
// Total charged to caller
const totalCost = baseCost + initCodeCost + memCost; // 32,020 gas
// Gas forwarded to init code (assume 100,000 remaining after charge)
const remainingAfterCharge = 100000 - totalCost; // 67,980 gas
const forwardedGas = remainingAfterCharge - Math.floor(remainingAfterCharge / 64); // 66,918 gas
// Total gas consumed (if init code uses all forwarded gas)
const totalConsumed = totalCost + forwardedGas + deploymentCost; // 108,938 gas
Common Usage
Contract Factory
contract TokenFactory {
Token[] public deployedTokens;
function createToken(
string memory name,
string memory symbol,
uint256 initialSupply
) external returns (address) {
Token token = new Token(name, symbol, initialSupply, msg.sender);
deployedTokens.push(token);
return address(token);
}
function getDeployedTokens() external view returns (Token[] memory) {
return deployedTokens;
}
}
contract Token {
string public name;
string public symbol;
uint256 public totalSupply;
address public creator;
constructor(
string memory _name,
string memory _symbol,
uint256 _initialSupply,
address _creator
) {
name = _name;
symbol = _symbol;
totalSupply = _initialSupply;
creator = _creator;
}
}
Clone Pattern (Minimal Proxy)
contract Cloner {
// Minimal proxy bytecode (EIP-1167)
function clone(address implementation) external returns (address instance) {
bytes20 targetBytes = bytes20(implementation);
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), targetBytes)
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create(0, ptr, 0x37)
}
require(instance != address(0), "Clone failed");
}
}
Upgradeable Contract
contract UpgradeableContract {
address public implementation;
function upgrade(bytes memory newCode) external {
// Deploy new implementation
address newImpl;
assembly {
newImpl := create(0, add(newCode, 32), mload(newCode))
}
require(newImpl != address(0), "Deployment failed");
implementation = newImpl;
}
}
Security
Nonce Prediction
CREATE addresses are predictable - can pre-compute future deployment addresses:
// VULNERABLE: Relying on address unpredictability
function deploy() external returns (address) {
Contract c = new Contract();
// Assuming address(c) is unpredictable - WRONG!
return address(c);
}
Risk: Attacker can pre-compute addresses and exploit race conditions.
Mitigation: Use CREATE2 if address unpredictability is required.
Deployment Failure
CREATE returns 0 on failure - must check result:
// VULNERABLE: Not checking deployment result
function deployUnchecked() external {
address deployed;
assembly {
deployed := create(0, 0, 0)
}
// deployed might be 0!
Contract(deployed).initialize(); // Will revert with confusing error
}
// SAFE: Check deployment result
function deploySafe() external {
address deployed;
assembly {
deployed := create(0, add(bytecode, 32), mload(bytecode))
}
require(deployed != address(0), "Deployment failed");
Contract(deployed).initialize();
}
Constructor Reentrancy
Init code can make external calls - reentrancy risk during construction:
contract Victim {
mapping(address => bool) public initialized;
function register() external {
// Deploy new contract
address deployed = address(new Malicious());
// VULNERABLE: Malicious constructor could re-enter here
initialized[deployed] = true;
}
}
contract Malicious {
constructor() {
// Re-enter during construction!
Victim(msg.sender).register(); // Reentrancy attack
}
}
Mitigation: Use reentrancy guards, check-effects-interactions.
Gas Griefing
Init code controls gas consumption - griefing risk:
// VULNERABLE: Unbounded gas consumption
function deployUserContract(bytes memory code) external {
address deployed;
assembly {
deployed := create(0, add(code, 32), mload(code))
}
// User can provide gas-heavy init code
}
// BETTER: Limit gas forwarded
function deployUserContractSafe(bytes memory code) external {
address deployed;
assembly {
// Forward limited gas
deployed := create(0, add(code, 32), mload(code))
}
// Gas limit naturally bounds init code execution
}
Code Size Limits
Init code: Max 49,152 bytes (EIP-3860, Shanghai+)
Runtime code: Max 24,576 bytes (EIP-170, Spurious Dragon+)
// Pre-deploy check
require(initCode.length <= 49152, "Init code too large");
// Runtime code check happens during deployment
// Will fail if init code returns >24,576 bytes
Implementation
References