Your First Contract & Deployment
Never paste a real private key on the command line; use cast wallet import (encrypted keystore) with --account, or a hardware wallet (--ledger).
5.1 Hello World
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title A simple greeting contract
/// @notice Stores a greeting that anyone can read and the owner can update
contract HelloWorld {
string public greeting; // `public` auto-generates a getter greeting()
address public immutable owner;
event GreetingChanged(address indexed by, string newGreeting);
error NotOwner();
constructor(string memory initialGreeting) {
greeting = initialGreeting;
owner = msg.sender; // the deployer
}
function setGreeting(string calldata newGreeting) external {
if (msg.sender != owner) revert NotOwner();
greeting = newGreeting;
emit GreetingChanged(msg.sender, newGreeting);
}
}5.2 Deploy in Remix
Create HelloWorld.sol, paste the code.
Solidity Compiler tab → choose 0.8.x → Compile.
Deploy & Run tab → Environment "Remix VM" → enter "Hello" next to Deploy → click Deploy.
Expand the deployed contract: click greeting (free call), call setGreeting (a transaction — note the gas used in the console).
Switch Environment to "Injected Provider - MetaMask" with Sepolia selected to deploy to a real testnet.
5.3 Deploy with Foundry
Never paste a real private key on the command line; use cast wallet import (encrypted keystore) with --account, or a hardware wallet (--ledger).
anvil & # local node
forge create src/HelloWorld.sol:HelloWorld \
--rpc-url http://127.0.0.1:8545 \
--private-key $ANVIL_KEY \
--broadcast \
--constructor-args "Hello"
cast call $ADDR "greeting()(string)" --rpc-url http://127.0.0.1:8545
cast send $ADDR "setGreeting(string)" "Hi!" --private-key $ANVIL_KEY --rpc-url http://127.0.0.1:85455.4 What the compiler produces
Creation (init) bytecode runs once at deployment: executes the constructor and returns the runtime code stored on-chain at the contract address describes functions, events, errors — used by wallets, frontends, other tools compiler version, settings, source hashes (used for verification) slots and offsets of state variables
5.5 How a function call works
Calldata = 4-byte selector (first 4 bytes of keccak256("setGreeting(string)")) + ABI-encoded arguments. The compiled contract's dispatcher compares the selector against each external function and jumps to the matching code; if none matches it runs fallback (or reverts).