Live prices are currently unavailable — the exchange feed could not be reached and no recent cached reading is held.

Research · Ethereum

Smart contracts

A contract is bytecode at an address, with storage it can write and a balance it can hold. Its code cannot be changed once deployed, which is why the upgradeable pattern exists — and why that pattern moves the trust from the code to whoever controls the upgrade.

Last reviewed 2026-09-21Source: ethereum.org smart contract documentation and the Solidity documentationPattern descriptions only; no security audit or guarantee is implied.

Deployment and the creation transaction

A contract is deployed by a transaction whose recipient field is empty and whose data field carries the compiled bytecode. The protocol creates a new account at an address derived from the sender's address and nonce, runs the bytecode as a constructor, and stores whatever the constructor returns as the contract's runtime code. The constructor runs once, and its return value is the only thing that persists as code; everything else it did is state.

The address derivation is deterministic, which is what makes counterfactual deployment possible. Because the address depends only on the creator and its nonce, anyone can compute where a contract will live before it is deployed and send funds there. A second creation method, using a salt supplied by the creator, produces an address that depends on the salt and the init code rather than on the nonce, which lets a deployer choose an address and redeploy the same code to the same address on a different chain.

Deployment is not free and not reversible. The gas cost of a creation transaction includes a per-byte charge for the code that ends up in state, which is why contract authors work to keep runtime bytecode small and why libraries and proxies are common. Once deployed, the code at an address cannot be replaced: the account's code hash is part of the state commitment, and changing it would change the state root. Every upgrade pattern in use is a way of working around that fact rather than a way of changing it.

Storage layout

A contract's storage is a mapping from 256-bit slots to 256-bit values, and the compiler decides which slot each declared variable occupies. The rules are simple enough to state: state variables are assigned slots in declaration order, starting at slot zero, and variables that fit together are packed into a single slot. A mapping or a dynamic array does not occupy a slot for its contents; it occupies one slot for a seed, and the location of each element is computed by hashing the key with that seed.

The layout matters because it is part of a contract's external interface in every case where another contract reads its storage directly. A proxy reads the implementation's storage, a library writes the caller's storage, and an upgrade replaces the code while keeping the layout. If a new implementation declares its variables in a different order, or inserts one in the middle, every variable after the insertion point reads the wrong slot. That is why upgradeable contracts append new variables at the end and reserve gaps for future use, and why a storage-layout collision is one of the classic ways an upgrade goes wrong.

The cost of storage is what makes the layout a design decision rather than a detail. Writing a slot that was zero costs substantially more than overwriting a slot that already held a value, and clearing a slot back to zero refunds part of the cost. Packing several small variables into one slot therefore saves gas on every write, and deleting data that is no longer needed recovers some of what it cost to store. A contract that accumulates state without ever clearing it pays the full price for every entry it keeps.

Calls, delegatecalls and proxies

How the EVM's call opcodes differ in whose code runs and whose storage is written.
OpcodeCode executedStorage and address context
CALLThe callee's codeThe callee's storage; the callee sees its own address and the value sent
STATICCALLThe callee's codeThe callee's storage, read-only; any state write reverts
DELEGATECALLThe callee's codeThe caller's storage; the callee sees the caller's address and value
CALLCODEThe callee's codeThe caller's storage; deprecated and superseded by DELEGATECALL

Last reviewed 2026-09-21Source: Ethereum Yellow Paper, Appendix HOpcode semantics as specified; the security implications are the author's analysis.

The proxy pattern is built on delegatecall. A proxy contract holds the storage and the address that users interact with, and it delegatecalls to an implementation contract that holds the code. The implementation's logic runs, but every read and write lands in the proxy's storage. Upgrading means pointing the proxy at a different implementation address, which changes the behaviour without changing the address users hold or the state they have accumulated.

The pattern solves a real problem and creates a real one. The problem it solves is that code is immutable and bugs are permanent; a proxy lets a team fix a bug without asking every user to migrate. The problem it creates is that the upgrade authority becomes the trust anchor: whoever can change the implementation can change what the contract does, including redirecting funds. A proxy therefore trades the guarantee that the code will not change for the guarantee that the address will not change, and a user has to decide which of those they value more.

The delegatecall primitive is also the source of a recurring class of vulnerability. Because a delegatecall executes the callee's code in the caller's storage, a delegatecall to an address the caller does not control hands that address the ability to write the caller's state. The standard defences are to restrict which addresses may be delegated to, to initialise the implementation contract so it cannot be taken over, and to verify the storage layout of every implementation before an upgrade. None of those is enforced by the protocol; all of them are the contract author's responsibility.

Sources and references

The deployment path, storage layout rules and call semantics described above are taken from Ethereum's documentation and the Solidity language reference.

  • Smart contracts and deployment. ethereum.org, Introduction to smart contracts: what a contract is, how it is deployed, and what it can do.
  • Storage layout rules. Solidity Documentation, Layout of State Variables in Storage: slot assignment, packing, and how mappings and dynamic arrays are addressed.
  • Call semantics. Solidity Documentation, Address — Members of Address Types: the difference between call, delegatecall and staticcall as exposed to contract authors.
  • Proxy patterns and their risks. OpenZeppelin Docs, Proxy Upgrade Pattern: how a proxy delegates to an implementation and what the pattern requires of the storage layout.