blockchain.lucas.zip

Day 4 — Building it properly, and the world beyond

Thursday 12 November, remote. The architecture and engineering of a dApp — on-chain and off-chain, testing that tries to break things, deployment and CI — then account abstraction, zero-knowledge, the real-world uses, the jobs, and the final defence. · Updated 26 August 2026

Five days after the intermediate defences and two weeks before the code freeze. The morning is engineering: how to structure a dApp so that the chain does only what it must, how to test a contract the way an attacker tests it, how to deploy reproducibly, and what came up across the intermediate defences. The afternoon widens the lens — the technologies that will change how users touch this, the uses that have nothing to do with speculation, the jobs that exist, and how to keep learning — and closes with the final defence, in detail, from the jury’s side.

TimeBlock
10:00What the intermediate defences showed
10:20The on-chain / off-chain split
10:50Contract design: minimal state, minimal trust, events as the API
11:20Testing like an adversary: fuzzing, invariants, forks — Foundry
12:00Deployment, configuration, and CI
12:30Gas: what to care about and what to ignore
13:00Lunch
14:00Account abstraction: what changes when the wallet is a contract
14:30Zero-knowledge in twenty minutes, without the maths
14:50What it is actually used for: stablecoins, tokenisation, and the accounting problem
15:30The jobs, and how to keep learning
16:00The final defence, from the jury’s side
16:30Open questions and project coaching

Morning, 10:00 – 13:00

What the intermediate defences showed

The first twenty minutes are the aggregate of what the jury saw across the groups — not group by group, but the patterns. This section of the notes is filled in after 7 November. In every cohort, a version of the following appears, and it is worth reading before your own defence whichever year you are in:

The on-chain / off-chain split

The most important architectural decision in a dApp is what is not on the chain. The chain is slow, expensive, public, and immutable, and it provides one of a handful of properties a database cannot. So the rule is:

On chain: the state whose integrity the guarantees are for, and the rules that govern it. Off chain: everything else.

Concretely, for the three subjects. The escrow’s chain holds: jobs, their states, their funds, the arbiter’s identity. Off chain: the job’s description (a hash on chain), the parties’ profiles, search, history views, notifications. The treasury’s chain holds: membership, proposals, votes, the funds, the parameters. Off chain: proposal text, discussion, participation dashboards. The credential registry’s chain holds: issuers, credentials as hashes with status. Off chain: the documents, the holder’s portfolio page, the verifier’s UI.

The off-chain parts have three homes. The frontend, for anything that is computed from public chain data on demand — most of it. Content storage — IPFS, Arweave — for documents and media, with the hash on chain. An indexer, for anything that needs history, aggregation, or search: it listens to events and writes a database that the frontend queries. An indexer is a server, and a server is a trust decision — but a small one, because everything it serves is verifiable against the chain, and if it lies, the lie is detectable. A backend that signs transactions is a different matter entirely, and is what the intermediate defences keep finding.

Contract design: minimal state, minimal trust, events as the API

Three principles that follow from the cost model and the threat model.

Minimal state. Every storage slot costs gas to write and lives forever. Store what the rules need to enforce themselves — balances, statuses, owners, deadlines — and nothing that only a display needs. If a value can be recomputed from other state, recompute it. If it is only ever read by the frontend, emit it as an event instead. Arrays that exist so the frontend can list things are the commonest form of state that should not exist; the events already contain the list.

Minimal trust. For every role in the table, ask whether it needs the power it has. An owner that can change the fee: does the fee need to change? If so, can it be bounded, and delayed? An admin that can add issuers: could the issuers add each other instead? A deployer that keeps any power at all after deployment: why? The best answer to “what can the deployer do” is “nothing”, and it is achievable more often than groups assume.

Events as the API. A contract’s events are its read interface for the world. Emit one for every state transition, with enough data that an indexer can rebuild the state from the events alone — that is the test. Index the fields that will be filtered on: addresses, ids. Events are cheap, and a contract that emits well needs far fewer view functions and far less storage.

A fourth, which is a habit more than a principle: write the state machine first. Enumerate the states; draw the transitions; label each with who may trigger it and under what conditions. Every function is then one transition, and every test is one transition attempted from every state by every role. Groups that do this write less code and more tests.

Testing like an adversary: fuzzing, invariants, forks — Foundry

Your Hardhat tests check that specific inputs produce specific outputs. An attacker does not choose your inputs. Three techniques close the gap, and Foundry — the other major toolchain, written in Rust, with tests in Solidity — is where they are most accessible. Hardhat 3 supports Foundry-style Solidity tests directly, so you can add them to your existing project.

Fuzzing. A test with parameters: the runner calls it hundreds of times with random values and reports the first that fails.

function testFuzz_ReleaseNeverExceedsFunded(uint96 amount) public {
    vm.assume(amount > 0);
    // fund a job with `amount`, deliver, release
    // assert the freelancer received exactly `amount` and the contract holds 0
}

Fuzzing finds the boundary you did not think of: the zero, the maximum, the value that makes a multiplication overflow, the amount that leaves one wei stranded.

Invariants. Properties that must hold after any sequence of calls. The runner generates random sequences of your contract’s functions from random callers and checks the property after each. For the escrow: the contract’s balance equals the sum of funds in open jobs. For the treasury: the treasury’s balance never falls except through an executed proposal. For the registry: a revoked credential is never valid. Writing the invariants is the design exercise; the fuzzer running them is the adversary you could not afford to hire.

Fork tests. Run your tests against a copy of a real network’s state, pulled from an RPC at a block. If your project composes with an ERC-20 or a protocol on Base Sepolia, a fork test lets you test against the real one rather than a mock, and it is how you find out that USDC has six decimals before your users do.

forge test --fork-url $BASE_SEPOLIA_RPC_URL

The project’s “property-based and invariant testing” axis is this. Two or three well-chosen invariants, with the runner finding nothing, is a stronger statement about a contract than fifty example-based tests.

Deployment, configuration, and CI

Reproducible deployment means: one command, given a network name, deploys the system from configuration and records what it deployed. Hardhat Ignition does this — the module describes the contracts and their constructor arguments, the deployments/ directory records the result per chain, and running it again is a no-op. Parameters that differ per network — the arbiter’s address, the voting period, the initial issuers — come from configuration, not from edits to the module before each deployment. Secrets come from the keystore. Nothing sensitive is in the repository; the addresses of what was deployed are.

Verification is part of deployment, not an afterthought. A script that deploys and does not verify has done half the job.

Continuous integration. A GitHub Actions workflow that, on every push, installs, compiles, and runs the tests — Hardhat’s and, if you have them, Foundry’s. It costs fifteen lines of YAML and it means the jury can see, on the repository, that the tests pass on the commit being defended rather than on your laptop. It also means a teammate cannot push a change that breaks the suite without everyone knowing within minutes, which is the more important property with two weeks to the freeze.

The frontend’s deployment is ordinary web deployment — Vercel, Netlify, GitHub Pages — with the contract addresses and chain in configuration. A deployed frontend that the jury can open from a link is worth having; a demo run from localhost is acceptable.

Gas: what to care about and what to ignore

Gas optimisation is the topic beginners spend the most time on relative to its value. On Base, a transaction costs a fraction of a cent, and the difference between an optimised contract and a clean one is a rounding error. So, the short list of what actually matters:

Hardhat’s gas reporter gives you per-function costs from the tests; run it once, look for anything surprising, and then stop. The project’s “engineering quality” axis mentions gas reporting because knowing the cost of each function is professional; shaving it is not the assignment.

Afternoon, 14:00 – 17:00

Account abstraction: what changes when the wallet is a contract

Everything you built this module assumes a user with MetaMask, a recovery phrase, and ETH for gas. That user is a small fraction of humanity, and the ecosystem has spent years on the alternative: a user whose account is a contract, with whatever rules the contract enforces.

ERC-4337 achieves this without changing the protocol. A user’s smart account is a contract; the user signs user operations rather than transactions; a bundler collects them and submits them; a paymaster contract can pay the gas on the user’s behalf, sponsoring it or taking payment in a token. EIP-7702, live since 2025, lets an ordinary EOA temporarily act as a smart account, which brings the same capabilities to existing wallets.

What it enables, concretely: sign-in with a passkey — a fingerprint on a phone — instead of a recovery phrase; social recovery, where a lost key is replaced by the agreement of friends or devices; session keys, where a game or app is authorised to act within limits without a pop-up per action; gasless onboarding, where a new user’s first transactions are paid by the application; batching, where “approve and swap” is one signature instead of two.

For your project, the “gasless or sponsored transactions” axis is a paymaster: your frontend uses a smart-account SDK, and the application’s sponsor account pays the gas for a defined set of actions. It is also a trust decision — the sponsor can stop sponsoring — and belongs in the roles table. And it is the single most likely thing to make a dApp usable by someone who has never heard of gas.

Zero-knowledge in twenty minutes, without the maths

A zero-knowledge proof lets one party convince another that a statement is true without revealing why. “I know a value whose hash is this.” “This transaction is valid.” “I am over eighteen.” “This program, run on this input, produced this output.” The proof is small, checking it is fast, and it reveals nothing beyond the statement.

Two uses in the ecosystem, both already real. Scaling: a ZK rollup executes thousands of transactions off chain and posts one proof that they were all valid; Ethereum checks the proof rather than the transactions. This is why ZK rollups need no dispute window and why they are the long-term direction. Privacy: a proof that you hold a credential without revealing which one, that a payment is valid without revealing the amount, that you are on an allowlist without revealing your address. The credentials subject’s “selective disclosure” axis is the gentle version of this; the full version — proving a credential’s validity to a verifier who learns nothing else — is a field of its own, with its own languages and circuits, and a few months of study.

What to take from twenty minutes: proofs exist, they work, they are in production, they are what “privacy on a public chain” actually means, and when someone says “ZK” they mean one of the two uses above and you can ask which.

What it is actually used for: stablecoins, tokenisation, and the accounting problem

A decade in, the uses that have survived contact with reality are fewer and less glamorous than the pitch decks, and more durable.

Stablecoins as payment rails. Hundreds of billions of dollars of dollar-denominated tokens, moving across borders in seconds for cents, held as savings where the local currency is unreliable, settling between businesses without a correspondent bank. This is the product. It works because the chain provides exactly the property it needs — a neutral ledger nobody’s bank can block — and it is regulated now, in Europe under MiCA, which is why the issuers are companies with compliance departments. Whether or not you work in crypto, you are likely to touch a stablecoin payment flow in your career.

Tokenised assets. Treasury bills, money-market funds, private credit, and increasingly ordinary securities, issued as tokens by institutions that hold the underlying. The chain provides settlement — instant, final, twenty-four hours a day — and composability, so that a tokenised fund can be collateral in a lending protocol. The trust model is entirely the issuer’s; the chain is plumbing. It is plumbing that a great deal of money is being moved onto.

Governance and treasuries. Open-source projects, protocols, and communities that hold and allocate funds through exactly the mechanism the treasury subject builds — with the same problems of participation, capture, and rule-changing, played out in public with real money.

Credentials, provenance, and registries, where the property needed is “anyone can check without asking” — ticketing, certificates, supply-chain attestations where the data entry problem has been solved by other means, domain names.

And the accounting problem, which is where the teacher’s own work lives. Every company that touches any of the above has a ledger on the chain and a ledger in its books, and the two do not speak the same language. A transaction on Base is a transfer of a token at a timestamp between addresses; an accountant needs a cost basis, a counterparty, a classification, a fiat value at the time, and a reconciliation against the bank. A treasury with a hundred thousand transactions across five chains needs software to make it auditable, and the auditors need evidence they can trust. This is unglamorous, it is where much of the industry’s actual engineering happens, and it is a good example of the kind of job this module prepares you for: not building the next protocol, but building the systems that let ordinary organisations use the existing ones. The reading-the-explorer skill from Day 3 is the beginning of it.

The jobs, and how to keep learning

What a “blockchain developer” does, in practice, is one of the following, and it is worth knowing which you would want.

Protocol engineering — writing and auditing the contracts at the core of a protocol. Small teams, high stakes, deep Solidity and security, often Rust as well. The audit firms are the other half of this world, and security research is a career on its own, with bug bounties as a way in.

Application engineering — the frontends, indexers, and integrations that put protocols in front of users. Ordinary web engineering plus what this module taught: wallets, transactions, events, the cost model. The largest number of jobs, and the most transferable.

Infrastructure — nodes, RPC providers, indexers, bridges, the tooling itself. Distributed systems engineering with a chain at the bottom.

Data and integration — the accounting problem above, analytics, compliance, exchanges. The chain is one data source among several, and the work is making it legible to systems that predate it.

And a great many jobs that are not “blockchain jobs” but touch one of these — a payments team adding stablecoin settlement, a fintech integrating a custody provider, a bank tokenising a fund. Those are the ones where holding a conversation without bluffing is the whole requirement, and they are the reason the module spends a morning on vocabulary.

To keep learning: read verified contracts on explorers, because the best protocols are their own documentation; read the post-mortems of exploits, which are the field’s best security teaching; follow the Ethereum Foundation’s blog and the EIP repository for where the platform is going; and build something small on a testnet every few months, because the tooling changes faster than any course can track.

The final defence, from the jury’s side

The final defence page has the format. This is the jury’s view of it, which is the useful one.

Before the day, the jury has read your README, your roles table, your justification, your contracts, your tests, your deployment record, and DEMO.md. It arrives with a list of questions per member, chosen to cover the parts that member did not present. It has looked at your verified contract on Basescan and at your commit history.

During the demo, it is checking DEMO.md against what happens, watching the explorer alongside your screen, and noting whether the failure paths are shown or skipped. It will ask for a failure of its own choosing.

During the walkthrough, it is checking the roles table against the code. Every claim in the table has a line in a contract that enforces it, or it is a finding.

During the questions, it is finding out whether three people built this or one did. The questions are not tricks. They are the questions a colleague would ask on the first day of maintaining your code.

Two weeks remain. The single best use of them, in this order: make the demo work from DEMO.md on the testnet without improvisation; make the roles table and the code agree; and teach each other the parts you did not write.

Vocabulary from today

On-chain / off-chain split, indexer, content storage; minimal state, minimal trust, events as API, state machine; fuzzing, invariant, fork test, Foundry, forge; Ignition module, deployments record, configuration variable, keystore, continuous integration; SSTORE, struct packing, gas reporter; smart account, ERC-4337, EIP-7702, user operation, bundler, paymaster, passkey, social recovery, session key; zero-knowledge proof, ZK rollup, selective disclosure; stablecoin rail, MiCA, tokenised asset, settlement, reconciliation, cost basis; protocol engineering, audit firm, application engineering, infrastructure.