← All CCE Flashcard Decks

Smart Contracts and Ethereum Flashcards

6 cards from real CCE practice questions. Tap to flip, then mark Knew It or Still Learning — missed cards come back until you master them.

Read the first 6 Smart Contracts and Ethereum flashcards as text
  1. A DeFi contract has two functions: `withdraw()`, which sends ETH via `call()` and then zeroes the caller's balance, and `getBalance()`, which reads the balance mapping. A third function, `transfer()`, reads the balance mapping and moves funds to another address. An attacker exploits a cross-function reentrancy vulnerability by calling `transfer()` from their fallback during `withdraw()`. What intermediate state makes this attack possible?

    Answer: `withdraw()` has already sent ETH but has not yet zeroed the balance, so `transfer()` sees the original (inflated) balance

    Cross-function reentrancy exploits the window between an external call and the subsequent state update. When `withdraw()` sends ETH but hasn't yet zeroed the balance, any re-entrant call to `transfer()` reads the stale, non-zeroed balance. The fix is the checks-effects-interactions pattern: update state before making external calls.

  2. Under EIP-1559, Ethereum introduced a `baseFee` per gas unit. A miner/validator includes a transaction with `maxFeePerGas = 50 gwei` and `maxPriorityFeePerGas = 2 gwei` when the current `baseFee` is 30 gwei. What does the validator actually receive as a tip, and what happens to the base fee?

    Answer: Validator receives 2 gwei per gas as a priority fee; the 30 gwei base fee is burned

    Under EIP-1559, the baseFee is entirely burned (removed from circulation), acting as deflationary pressure. The validator only receives the `maxPriorityFeePerGas` (2 gwei here) as a tip. The user is refunded the unused headroom: `maxFeePerGas - baseFee - priorityFee = 50 - 30 - 2 = 18 gwei` per gas.

  3. In the UUPS (EIP-1822) upgradeable proxy pattern, where does the upgrade authorization logic reside, and why is this architecturally different from the Transparent Proxy Pattern (TPP)?

    Answer: In UUPS the upgrade logic lives in the implementation contract, reducing proxy bytecode size; in TPP the proxy itself checks caller identity via an admin slot

    In UUPS, the `upgradeTo()` function and its access control live inside the implementation contract. This keeps the proxy lightweight (cheaper deployment, less proxy bytecode). The risk is that a buggy implementation that omits the upgrade function will permanently brick upgradability. In the Transparent Proxy Pattern, the proxy itself contains admin-checking logic, calling either the implementation or the ProxyAdmin depending on the caller, making the proxy heavier but more resilient.

  4. After EIP-2929 (Berlin hard fork), Ethereum introduced 'cold' and 'warm' storage access costs. A Solidity function reads state variable `x` once, calls an external contract (which also reads `x` via `SLOAD` on the same slot), and then reads `x` again after the external call returns. Assuming no access list is used, what is the gas cost breakdown for the three `SLOAD` operations on that slot?

    Answer: 2100 + 100 + 100 = 2300 gas (slot is warm for the entire transaction after first access)

    EIP-2929 tracks accessed storage slots in a transaction-wide 'accessed_storage_keys' set. Once a slot is accessed anywhere in the transaction (including by an external call in a child frame), it is marked warm for the rest of that transaction. The first SLOAD costs 2100 (cold); all subsequent SLOADs on the same slot — even across call frames — cost only 100 (warm). Total: 2100 + 100 + 100 = 2300.

  5. A factory contract deploys a child contract to a deterministic address using `CREATE2` with a fixed salt. The child contract later calls `SELFDESTRUCT`. Under which precise condition can the factory redeploy a *different* implementation to the exact same address, and what security implication does this create?

    Answer: The factory can redeploy after SELFDESTRUCT using the same salt and any bytecode, because the nonce resets to zero; this enables a metamorphic contract attack where audited code is replaced post-deployment

    After `SELFDESTRUCT`, the address is cleared (nonce reset, code cleared, balance zeroed). `CREATE2` address derivation is `keccak256(0xff ++ deployerAddress ++ salt ++ keccak256(initcode))`. The deployer can change the `initcode` — e.g., by using a constructor that fetches bytecode from a mutable registry — and still produce the same address if the outer initcode hash is the same. This 'metamorphic contract' pattern lets an attacker pass an audit, self-destruct, then redeploy malicious logic to the same address.

  6. In Solidity, an `external` function declares its dynamic array parameter as `calldata` rather than `memory`. Beyond gas savings, what is a critical behavioral difference that `calldata` enforces compared to `memory`?

    Answer: `calldata` parameters are immutable within the function body; any attempt to assign to a `calldata` array element or slice produces a compile-time error, whereas `memory` parameters are mutable copies

    `calldata` is a read-only, non-persistent data location pointing directly at the raw transaction input. Solidity enforces immutability at compile time: assigning to a `calldata` variable or element is a compile error. This contrasts with `memory`, which allocates a mutable copy in the EVM's memory region. `calldata` avoids the copy cost and enforces immutability, but if the function logic needs to modify the parameter (e.g., sort an array), it must be copied to `memory` first.