blockchain.lucas.zip

Day 3 — The ecosystem, and the adversary

Thursday 29 October, remote. The map of the Ethereum world — layers, tokens, DeFi, oracles, wallets, storage — and then security, which is the discipline of writing code that money will attack. · Updated 26 August 2026

Two weeks into the project, a day of lectures. The morning is the map: the layers, the standards, the protocols, the infrastructure, and the words for all of it — the material that lets you read a protocol’s documentation and understand what it is, and hold your own in a conversation with someone who has been in the field for years. The afternoon is the adversary: how contracts get broken, why, and the habits that prevent it. Both are lectures, both are recorded in these notes, and both end with something to apply to your project before the intermediate defence.

Each hour of the day has a short break; the schedule below marks the blocks.

TimeBlock
10:00Where you are: a check-in on the projects
10:15The history in thirty minutes, and the layers
10:45Tokens and standards
11:20DeFi: what the money legos are, and what they are made of
12:00Infrastructure: oracles, storage, indexing, wallets, MEV
12:40Reading a protocol on the explorer, live
13:00Lunch
14:00The mindset: immutable, public, adversarial, valuable
14:15The catalogue of failures
15:15The catalogue of defences
15:50Upgradeability, audits, and what “secure” means
16:15Live: breaking a contract, then fixing it
16:45The intermediate defence, and what to do before it

Morning, 10:00 – 13:00

The history in thirty minutes, and the layers

2008–2009. A paper and a piece of software, by someone using the name Satoshi Nakamoto, describing a peer-to-peer electronic cash system. Bitcoin’s contribution was not any single component — hash chains, digital signatures, and proof of work all existed — but the combination that made a ledger with no operator actually hold up against people trying to cheat it. Bitcoin’s script language is deliberately tiny. It moves one asset.

2013–2015. Vitalik Buterin, then nineteen, argued that the same machinery could run arbitrary programs, and Ethereum launched in 2015 with a virtual machine, a language, and the idea of a contract account. The first years produced the ERC-20 token standard, the first decentralised exchanges, and the first catastrophe — The DAO, a crowd-funded investment contract drained by reentrancy in 2016, whose aftermath split the chain into Ethereum and Ethereum Classic over whether to reverse the theft. Ethereum reversed it; Classic did not; the question of whether “code is law” had its first real answer, which was “mostly”.

2017–2018. The ICO wave — thousands of tokens sold on Ethereum, most of them worthless, some of them fraudulent, a few of them protocols that still run. The chain congested for the first time, famously because of a game about cats. Gas prices became a topic.

2020–2021. DeFi summer. Lending protocols, automated market makers, stablecoins, and yield strategies composed into each other and the total value locked in them went from under a billion dollars to over a hundred. NFTs followed. Gas prices reached the point where a simple swap cost more than most people’s lunch, and the scaling question became existential.

2022. The Merge: Ethereum switched from Proof of Work to Proof of Stake in a single live transition, cutting its energy use by more than ninety-nine percent. The same year, the collapse of Terra — an algorithmic stablecoin — and of FTX — a centralised exchange that was, it turned out, a fraud — took a great deal of money and most of the public’s goodwill. Neither was a failure of a blockchain; both were failures of trust in an operator, which is the thing blockchains were meant to remove.

2023–now. The rollup era. Ethereum’s roadmap settled on scaling through Layer 2 networks, and made it cheap for them to post data with an upgrade in 2024. Arbitrum, Optimism, Base, zkSync, Scroll, and others now carry most of the ecosystem’s transactions. Stablecoins became the one use case nobody argues about — hundreds of billions of dollars of them, used for payments and savings in places where the local currency or banking system is worse. Regulation arrived: MiCA in the European Union, and a shifting picture in the United States. Tokenised real-world assets — treasury bills, funds, eventually equities — began to be issued on chain by institutions that would have laughed at the idea five years earlier.

The layers, as they stand. Ethereum is Layer 1: the settlement layer, the court of final appeal, slow and expensive and maximally secure. Layer 2 networks execute transactions and post compressed data and proofs back to it. There are two families. Optimistic rollups — Arbitrum, Optimism, Base — assume the posted results are correct and allow a window, typically a week, in which anyone can prove a result wrong and have it reverted. ZK rollups — zkSync, Scroll, Linea, Starknet — post a cryptographic proof that the results are correct, so there is nothing to dispute; the maths is heavier and the tooling younger. From a developer’s chair the difference is mostly invisible: the same EVM, the same tools, a different chain id. From a user’s chair the difference is that withdrawing from an optimistic rollup to Ethereum takes a week unless a third party fronts the money.

Base, where you are deploying, is an optimistic rollup on the OP Stack — the open-source software Optimism built, which several chains share, and which is why “the Superchain” is a phrase you will hear.

Tokens and standards

A token is a contract that keeps a ledger of balances. That is all. The ETH balance is part of the protocol; a token balance is a mapping in a contract that anyone deployed. What makes tokens useful is that everyone agreed on the interface, so a wallet, an exchange, or another contract can handle any token without knowing which.

ERC-20 is the fungible token interface: balanceOf, transfer, totalSupply, and the two that matter most — approve and transferFrom. A holder cannot push tokens into a contract and have the contract react; the contract has to pull them. So the holder first approves the contract to spend up to an amount, and the contract then calls transferFrom. Every DeFi interaction begins with an approval transaction, every wallet drainer works by tricking users into an unlimited approval, and every frontend you build that takes ERC-20 payments has to handle the two-step. decimals says how many decimal places the display should show; the contract counts in integers. USDC has six; most tokens have eighteen; assuming either is a bug.

ERC-721 is the non-fungible token: each token has an id and one owner, and the standard adds ownerOf, tokenURI — a pointer to metadata, usually a JSON file on IPFS — and safe transfers that check the recipient can handle NFTs. It is the standard behind digital art, game items, domain names, and, more interestingly for the project, anything where a specific thing has a specific owner: a ticket, a membership, a position in a protocol.

ERC-1155 does both in one contract — many token types, each fungible or not — and is what games use.

Three more you will meet. ERC-2612, permit: an ERC-20 approval given by signature instead of by transaction, so a user can approve and spend in one step, and the gas can be paid by someone else. ERC-4626, tokenised vaults: a standard interface for “deposit an asset, get shares, shares grow”, which lets yield strategies be composed like tokens. ERC-5192 and the broader idea of soulbound tokens: NFTs that cannot be transferred, for credentials and memberships, which the credentials subject discusses.

The pattern to notice: a standard is a social achievement. The interface is trivial to write. The value is that everyone wrote the same one.

DeFi: what the money legos are, and what they are made of

Decentralised finance is the set of protocols that reimplement financial primitives as contracts. Four of them account for most of it, and each is worth understanding at the level of mechanism, because each is a design you can borrow.

Automated market makers. An exchange without an order book. A contract holds a pool of two tokens, say ETH and USDC, and lets anyone trade one for the other at a price set by a formula — the simplest, from Uniswap’s first version, keeps the product of the two reserves constant: x × y = k. Buy ETH from the pool and there is less ETH and more USDC, so the next ETH costs more. There is no counterparty and no price feed; the price is the ratio of the reserves, and it tracks the outside world because whenever it drifts, arbitrageurs trade it back for a profit. Liquidity providers deposit both tokens and earn a fee on every trade. The formula means large trades move the price a lot — slippage — and every swap interface asks you how much you will tolerate. Uniswap, on which this design was pioneered, has handled trillions of dollars of volume with a core contract a few hundred lines long.

Lending. A pool where depositors supply an asset and borrowers borrow it against collateral worth more than the loan. Interest rates are set by a formula of utilisation — the more of the pool is borrowed, the higher the rate — and if a borrower’s collateral falls in value below a threshold, anyone may liquidate the position: repay the debt and take the collateral at a discount. There is no credit check and no recourse, which is why every loan is overcollateralised. Aave and Compound are the names. The mechanism that keeps them solvent is the price of the collateral, which the contract cannot know by itself — hence oracles, below, and hence the largest category of DeFi exploits.

Stablecoins. A token meant to be worth one dollar. Three ways to do it. Fiat-backed: a company holds dollars in a bank and issues one token per dollar; USDC and USDT, most of the market, and a trust relationship with the issuer that no amount of on-chain machinery removes — they can and do freeze addresses. Crypto-backed: a lending protocol that mints the stablecoin as a loan against overcollateralised crypto, with liquidations keeping it backed; DAI is the original. Algorithmic: a token whose peg is maintained by an incentive mechanism with no reserve behind it; Terra’s UST was the largest, and its collapse in 2022 erased forty billion dollars in a week, in exactly the way the mechanism’s critics had described. Stablecoins are the one product of this ecosystem with unambiguous product-market fit, and the one most likely to touch your career whether or not you work in crypto.

Yield and composition. Because every one of these is a contract with a standard interface, they compose. Deposit into a lending pool, receive a token representing your deposit, use that token as collateral elsewhere, provide the borrowed asset to an AMM, stake the liquidity token in a rewards contract. This is the “money legos” phrase, and it is genuinely new — no other financial system lets a stranger assemble products from other people’s infrastructure without permission. It also means that a failure anywhere propagates everywhere, and that the phrase “yield” often describes a chain of risks nobody has fully mapped.

Bridges move assets between chains, and are the most exploited category in the ecosystem’s history — several individual incidents over half a billion dollars — because a bridge is a contract on one chain that has to trust a report about another chain, and that trust is exactly the kind of thing this module keeps telling you to write down.

Infrastructure: oracles, storage, indexing, wallets, MEV

Oracles. A contract cannot make an HTTP request. It cannot know the price of ETH, the weather, the result of a match, or whether a package arrived. Anything from outside has to be brought in by a transaction, and whoever sends that transaction is trusted for its contents. An oracle is a service that does this at scale: Chainlink runs networks of nodes that agree on a price and post it, and most of DeFi reads those feeds. The design problem is that the oracle is now the trusted party, and an oracle that can be manipulated — by feeding it a price from an AMM pool that a flash loan just distorted — is how lending protocols get drained. The lesson for your project: every piece of data that enters your contract from the world has a source, and that source is a row in your roles table.

Storage. A chain is the most expensive place in the world to keep a kilobyte. Anything larger than a hash goes elsewhere, and the elsewhere of the ecosystem is IPFS: content-addressed storage, where a file is identified by the hash of its contents, so that anyone holding the hash can verify what they fetched, and anyone can host it. The chain holds the hash; the frontend fetches the content from an IPFS gateway and checks it. IPFS does not guarantee persistence — someone has to keep the file pinned — and Arweave is the alternative that does, for a one-time fee. NFT metadata, credential documents, governance proposals: all of them belong off chain with a hash on it.

Indexing. A node can tell you the current state and can give you the events in a block range. It cannot answer “all the jobs this address ever created, sorted by amount” without you scanning every block. That is what an indexer does: it watches events, writes them into a database, and serves queries. The Graph is the decentralised version — you write a subgraph describing how events map to entities, and a network of indexers serves it over GraphQL. Ponder and a hand-written viem watcher are the lighter versions. Every dApp with a history page has one, and it is one of the axes of the project.

Wallets. Everything so far assumes an EOA with a key in a browser extension. The industry is moving away from that, because recovery phrases lose people money and pop-ups lose products users. Account abstraction — ERC-4337, and the protocol-level EIP-7702 that landed in 2025 — lets an account be a contract: with a passkey instead of a recovery phrase, with spending limits, with a way to recover it through friends, with gas paid by a third party so that a new user needs no ETH to start. It is the most important change in how users will touch this technology, and the project’s “gasless transactions” axis is about it.

MEV. Every pending transaction is visible before it is included, and whoever produces a block chooses the order. That means a bot can see your swap, buy before you, and sell after you — a sandwich — and it means that block producers can extract value from ordering. Maximal extractable value is a research field and an industry; for you it is a design constraint: anything in your contract that rewards being first — a first-come auction, a claim, a liquidation — will be won by a bot, and anything that reveals a secret in a transaction is not a secret.

Reading a protocol on the explorer, live

The last twenty minutes of the morning are a walk through a real protocol on Basescan, screen shared: a Uniswap pool contract on Base Sepolia. The verified source, the read functions — reserves, fee, token addresses — the events a swap emits, and a recent swap transaction decoded: which function was called, with what arguments, what it emitted, what tokens moved. Then the same for the USDC contract: balanceOf, allowance, and the Approval and Transfer events from an address that just used the pool.

The purpose is to show that everything above is readable. There is no documentation more accurate than the verified source and the event log, and learning to read them is the skill that makes the rest of the ecosystem legible. Do it for your own contract when it is deployed, and do it for any protocol you consider composing with.

Afternoon, 14:00 – 17:00

The mindset: immutable, public, adversarial, valuable

Four things are true of a deployed contract at once, and no other kind of software has all four.

It is immutable: what you deployed is what runs, forever, unless you built a way to change it, and building that way is itself a trust decision. There is no patch Tuesday.

It is public: the bytecode, the storage, every transaction, every event, and — if you verified it, as you should — the source. Your attacker reads your code with more attention than your reviewer did.

It is adversarial: it will be called by people whose intent is to make it misbehave, using contracts written for the purpose, with transactions constructed by hand, at a moment of their choosing, from anywhere. There is no rate limiting, no IP ban, no terms of service.

It is valuable: it holds money, or controls money, or controls something that can be turned into money. A bug is not a crash report. It is a transfer.

The consequence is that smart contract security is not a phase of the project. It is the way the code is written. The rest of the afternoon is the specific knowledge that discipline is made of.

The catalogue of failures

Each of these has cost real money, most of them many times. Know them by name; you will be asked.

Access control. A function that should be restricted and is not. The Parity multisig wallet in 2017 had an initialisation function that anyone could call; someone called it, became the owner, and then, apparently by accident, destroyed the library that every wallet depended on, freezing three hundred million dollars permanently. Every function that changes state should have an answer to “who may call this”, and the answer should be enforced in the function, not in the frontend.

Reentrancy. Covered on Day 2 and worth repeating because it keeps happening. A call to an external address hands it control; if your state is not yet updated, it can call you back and act on stale state. The DAO, 2016; and a steady stream of protocols since, including some that used a reentrancy guard on one function and forgot it on another that shared the same state. Checks-effects-interactions, guards, and a test that performs the attack.

Arithmetic. Before 0.8, overflow wrapped silently, and a balance of zero minus one became the largest number representable. Since 0.8 it reverts — but division truncation, precision loss in ratios computed in the wrong order, and rounding that consistently favours one party are still with us. Multiply before dividing; know which way a rounding error should go, and make it go against the caller.

Oracle manipulation. A contract that reads a price from an AMM pool’s reserves is reading a number that anyone with enough capital can move, and a flash loan — borrowing any amount with no collateral, provided it is repaid in the same transaction — gives everyone enough capital. Borrow, distort the pool, take out a loan against the inflated collateral, restore the pool, repay the flash loan, keep the difference. Dozens of protocols, hundreds of millions. Use a time-weighted price or a proper oracle, and understand that the oracle is now trusted.

Front-running and sandwiching. Discussed under MEV. A design where the first transaction to do something wins is a design where a bot wins. A commit-reveal scheme — submit a hash now, reveal the value later — is the usual mitigation when order matters.

Signature replay. A signed message that authorises something can be submitted again, or on another chain, or to another contract, unless the signature covers a nonce, a deadline, the chain id, and the contract address. EIP-712 exists to make this systematic; use it, and never verify a bare signature over user-supplied data.

Denial of service. An unbounded loop that grows with users until it exceeds the block gas limit, after which the function can never run again. A push payment to a list of recipients where one recipient’s receive reverts and blocks everyone. A refund mechanism that a single malicious address can wedge. The fix is structural: bound everything, pull rather than push, and never let one party’s failure block another’s.

Randomness. There is none. block.timestamp and blockhash are chosen or influenced by the block producer, and anything derived from them can be predicted or gamed by whoever produces the block — and on a rollup, that is one party. A lottery drawn from a block hash is a lottery the sequencer can win. Use a verifiable random function from an oracle, or a commit-reveal among participants, and know the trust each implies.

Delegatecall and proxies. delegatecall runs another contract’s code in your storage context; it is how upgradeable proxies work and how libraries are shared. A delegatecall to an address the caller controls is a complete takeover. A proxy whose storage layout does not match its implementation corrupts itself silently. Use OpenZeppelin’s proxies if you must, and read the section on upgradeability below before you decide you must.

The user’s side. Phishing sites that ask for a signature that turns out to be an unlimited approval. Approvals granted years ago to a protocol that has since been compromised. Wallet drainers that work entirely through legitimate wallet UI. Your frontend is part of the attack surface: ask for the minimum approval, explain every signature, and never ask for a signature you cannot explain.

The catalogue of defences

Checks-effects-interactions. Every function: validate, then mutate, then call out. Make it a habit that a reviewer can verify by reading the function top to bottom.

Pull over push. Record what is owed; let the owed party withdraw.

Reentrancy guards on every function that transfers value or calls an external contract, and — crucially — on every function that shares state with one that does.

Explicit access control. Ownable for a single admin; AccessControl for roles. A roles table in the README, and a modifier enforcing each line of it in the code. If the table says the arbiter may only touch disputed jobs, the modifier checks the job is disputed.

Fail closed. Default to reverting. An if with no else that lets a transaction succeed in an unexpected state is where money leaves.

Bound everything. Arrays users can grow; loops over them; amounts; durations. If a parameter has no ceiling, a caller will find the number that breaks you.

Pausable, with a written justification. An emergency stop that a guardian can pull is a trust decision — it gives someone the power to freeze the system — and it has saved several protocols. If you include one, it goes in the roles table, and a timelock on un-pausing keeps the guardian from using it selectively.

Timelocks on anything administrative. A change to a fee, a quorum, an implementation, or a list of issuers that takes effect in two days rather than now gives users a window to react, and turns “the admin can do anything” into “the admin can do anything, visibly, with notice”.

Minimal trust, written down. The roles table is the defence that makes the others checkable. If you cannot write who can do what, you cannot know whether the code enforces it.

Use the library. OpenZeppelin’s implementations of tokens, access control, guards, and proxies have been audited many times and attacked many more. Your own ERC-20 has been neither.

Upgradeability, audits, and what “secure” means

Upgradeability. A contract can be made changeable by putting a proxy in front of it: users call the proxy, the proxy delegatecalls the current implementation, and an admin can point it at a new one. It is widely used, and it is a trust decision of the largest possible kind — an upgradeable contract is one whose rules can be changed by whoever controls the upgrade, which returns you to trusting an operator. Some protocols accept this with a governance vote and a timelock on upgrades; some deploy immutable contracts and migrate users when they must; some lie about which they are. For the project: an upgradeable contract is acceptable only with a written answer to “who controls the upgrade, with what delay, and why should a user accept that”, and a design that does not need it is usually better.

Audits. A security review by people who do this for a living, over weeks, producing a report of findings by severity. Serious protocols get several before launch and more after each change. Audits are expensive — tens to hundreds of thousands of dollars — and they are not guarantees: audited protocols are exploited regularly, through code the audit did not cover or assumptions the audit did not question. What an audit is, is evidence of care, and a second pair of adversarial eyes. Bug bounties — a standing offer to pay whoever reports a vulnerability rather than exploiting it — are the ongoing version, and the largest have paid out millions. Static analysis tools like Slither find the mechanical classes of bug cheaply and are the project’s “security self-review” axis.

What “secure” means. Not “has no bugs”. It means: the trust assumptions are explicit; the code enforces them; the known classes of failure have been considered and addressed or consciously accepted; and the amount at risk is bounded by design. A contract with a documented admin who can pause it is more secure than one with an undocumented admin who can do anything, even if the second has fewer lines of code.

Live: breaking a contract, then fixing it

Thirty minutes, screen shared. A version of Day 2’s escrow with the guard removed and the state update after the transfer. An Attacker contract that accepts a job, gets it delivered, and in its receive function calls release again. The escrow, deployed on a local node with a second job funded by someone else, pays the attacker twice, and the second victim’s money is gone. Then the fix — the state update moved above the call, the guard added — and the same attack reverting. Then the test that would have caught it, and a look at what Slither says about the vulnerable version.

The code for both versions is in the Day 3 material. Run the attack yourself; there is no substitute for watching it work.

The intermediate defence, and what to do before it

The intermediate defence is Saturday 7 November, thirty minutes per group, not graded. Before it, in the light of today:

Vocabulary from today

Layer 1, Layer 2, optimistic rollup, ZK rollup, OP Stack, Superchain, finality window; ERC-20, approve, transferFrom, decimals, ERC-721, tokenURI, ERC-1155, permit, ERC-4626, soulbound; AMM, constant product, liquidity provider, slippage, arbitrage; lending pool, collateral, liquidation, utilisation; stablecoin, fiat-backed, crypto-backed, algorithmic, peg; composability, TVL, bridge; oracle, price feed, flash loan; IPFS, content addressing, CID, pinning, Arweave; indexer, subgraph, The Graph; account abstraction, ERC-4337, EIP-7702, paymaster; MEV, sandwich, front-running, commit-reveal; access control, reentrancy, overflow, oracle manipulation, signature replay, EIP-712, denial of service, randomness, delegatecall, proxy; checks-effects-interactions, pull payment, reentrancy guard, fail closed, pausable, timelock; upgradeability, audit, bug bounty, static analysis, Slither.