Chapter 33 Quiz: dApp Development
Multiple Choice
1. In the dApp architecture stack, which layer is responsible for user identity and transaction authorization?
A) The RPC provider B) The smart contract C) The wallet (e.g., MetaMask) D) The frontend JavaScript application
Answer: C. The wallet manages the user's private key and signs transactions on their behalf. The frontend can request signatures, but the wallet is the authorization layer. The user must explicitly approve every transaction in the wallet interface.
2. In ethers.js v6, what is the difference between a Provider and a Signer?
A) A Provider can read and write; a Signer can only read. B) A Provider can only read blockchain state; a Signer can also sign and send transactions. C) A Provider connects to MetaMask; a Signer connects to an RPC endpoint. D) There is no difference; they are aliases for the same object.
Answer: B. A Provider is a read-only connection to the blockchain (e.g., querying balances, reading contract state). A Signer extends a Provider with the ability to sign transactions using a private key. This separation is a core design principle of ethers.js.
3. Why is IPFS used for proposal metadata instead of on-chain storage?
A) IPFS is faster than the blockchain for data retrieval. B) On-chain storage is too expensive for large text data, while IPFS storage costs are minimal and only the CID (a 32-byte hash) needs to be stored on-chain. C) The Ethereum Virtual Machine cannot process text strings. D) IPFS provides encryption that the blockchain does not.
Answer: B. Storing 1 KB of data on Ethereum costs approximately $5-20 at typical gas prices. A detailed proposal might be 10+ KB. IPFS stores the data off-chain for minimal cost, and only the content-addressed CID (32 bytes) is stored on-chain. IPFS does not provide encryption (option D is incorrect), and Solidity does handle strings (option C is incorrect).
4. What is a CID in the context of IPFS?
A) A unique identifier assigned sequentially to uploaded files. B) A content-addressed identifier that is a cryptographic hash of the file's contents. C) A certificate of identity issued by the IPFS network. D) A chain identifier that specifies which blockchain the file is associated with.
Answer: B. CID stands for Content Identifier. It is derived from the cryptographic hash of the file's contents. This means that the same content always produces the same CID, and any modification to the content produces a different CID. This provides integrity verification without trusting the server.
5. What problem does The Graph solve for dApp frontends?
A) It provides a faster blockchain consensus mechanism. B) It allows efficient querying of historical blockchain data that would otherwise require scanning millions of blocks. C) It replaces the need for smart contracts by storing state off-chain. D) It provides a decentralized hosting solution for frontend files.
Answer: B. The blockchain stores state but does not index it for efficient querying. To answer a question like "What are all proposals sorted by vote count?" you would need to scan every block since contract deployment. The Graph indexes blockchain events into a queryable database and exposes a GraphQL API.
6. In the deployment script, why is it critical to call timelock.revokeRole(ADMIN_ROLE, deployer.address) after configuring the governor's roles?
A) To reduce gas costs for future transactions. B) To prevent the deployer from retaining the ability to bypass the timelock and execute arbitrary actions. C) To enable the governor contract to function. D) To comply with ERC-20 token standards.
Answer: B. If the deployer retains the admin role on the TimelockController, they can grant themselves the executor role and execute any action without going through the governance process. This completely undermines the purpose of decentralized governance. Revoking the admin role is the most important step in the deployment process.
7. In the ERC20Votes extension, why must a token holder call delegate() before their tokens count toward voting power?
A) Delegation is required by the ERC-20 standard. B) The checkpoint system only tracks voting power for addresses that have an active delegation, allowing gas-efficient historical lookups. C) Tokens are locked during delegation, preventing double-voting. D) Delegation transfers token ownership to the delegate.
Answer: B. The ERC20Votes extension uses a checkpoint system that records voting power at specific block numbers. This system only activates when a holder delegates (to themselves or another address). Without delegation, the holder's tokens exist but are not tracked in the checkpoint history, so they have zero voting weight. Delegation does not lock tokens (C is incorrect) or transfer ownership (D is incorrect).
8. What does loadFixture() do in Hardhat tests?
A) It loads test data from a JSON file. B) It deploys contracts once, takes a blockchain snapshot, and reverts to that snapshot before each test, providing clean state without redeployment overhead. C) It loads the contract ABI from the artifacts directory. D) It connects to a running testnet to load existing contract state.
Answer: B. loadFixture() is a Hardhat Network Helper that optimizes test performance. It runs the setup function once, snapshots the blockchain state, and reverts to that snapshot before each test. This gives every test a clean starting state while avoiding the gas and time cost of redeploying contracts for each test.
9. Which of the following is a centralization risk in a typical dApp?
A) The smart contracts on the blockchain B) The frontend hosted on Vercel or Netlify C) The blockchain consensus mechanism D) The ERC-20 token standard
Answer: B. The frontend is typically hosted on a centralized server. If the hosting provider takes it down (as happened when Uniswap's frontend delisted certain tokens), users lose access to the web interface. The smart contracts continue to operate on the blockchain, but most users cannot interact with them without a frontend. This is the "decentralized frontend problem."
10. What is the purpose of a timelock in a governance system?
A) To prevent proposals from being created too quickly. B) To impose a mandatory delay between when a proposal passes and when it can be executed, giving stakeholders time to react. C) To encrypt the proposal contents until the voting period ends. D) To limit the number of tokens that can be transferred per block.
Answer: B. The timelock creates a window between passage and execution. If a malicious proposal passes (e.g., during low participation), token holders have time to sell their tokens, move funds from affected contracts, or coordinate a defense. Without a timelock, a passed proposal executes immediately, leaving no opportunity for recourse.
Short Answer
11. Explain the difference between content addressing (IPFS) and location addressing (HTTP). Give one advantage and one disadvantage of each approach.
Model Answer: Location addressing (HTTP) identifies data by where it is stored: "go to server X, path Y, and retrieve the file." The advantage is simplicity and familiarity; the URL can change content without changing the address. The disadvantage is that if the server moves or goes down, the link breaks, and there is no built-in way to verify content integrity.
Content addressing (IPFS) identifies data by what it is: the address is a cryptographic hash of the content itself. The advantage is immutability and integrity verification — the same CID always refers to the same content, and any tampering produces a different CID. The disadvantage is that content availability depends on at least one node pinning the content; if no node has it, the CID resolves to nothing.
12. A dApp developer deploys a governance system but forgets to revoke the deployer's admin role on the TimelockController. Describe a specific attack that becomes possible and explain how revoking the admin role prevents it.
Model Answer: With the admin role, the deployer can call grantRole(EXECUTOR_ROLE, attackerAddress) on the TimelockController, granting any address the ability to execute operations directly through the timelock — bypassing the governor's proposal/vote/queue process entirely. The attacker (or compromised deployer) could then schedule and execute arbitrary transactions: draining the treasury, minting unlimited tokens, or modifying critical protocol parameters. Revoking the admin role means no single address can modify the timelock's access control after deployment. Only the governance process (propose, vote, queue, execute) can grant or revoke roles, ensuring collective decision-making.
13. Why does ethers.js v6 use native JavaScript BigInt instead of the custom BigNumber class used in ethers.js v5? What practical difference does this make for developers?
Model Answer: ethers.js v6 uses native JavaScript BigInt because modern JavaScript engines (V8, SpiderMonkey, JavaScriptCore) all support it natively, eliminating the need for a library-specific implementation. The practical difference is that developers use standard JavaScript syntax (100n, a + b, a * b) instead of method calls (BigNumber.from(100), a.add(b), a.mul(b)). This makes code more readable, reduces bundle size (no BigNumber library needed), and allows interoperability with other libraries that also use native BigInt. The main caveat is that BigInt and Number cannot be mixed in arithmetic expressions; developers must be careful to use BigInt consistently when working with blockchain values (which are almost always 256-bit integers).
14. Describe the complete lifecycle of a governance proposal from creation to execution. Include the state transitions and the role of each component (Governor, Token, Timelock).
Model Answer: The lifecycle has seven states:
- Pending: A token holder calls
governor.propose(). The Governor records the proposal and emits aProposalCreatedevent. The proposal is pending during the voting delay. - Active: After the voting delay (measured in blocks), the proposal becomes active. The Governor queries the Token's checkpoint at the proposal's snapshot block to determine each voter's weight. Token holders call
governor.castVote()to vote For, Against, or Abstain. - Succeeded/Defeated: After the voting period ends, the Governor evaluates whether the proposal met quorum (minimum total votes) and passed (more For than Against). It transitions to Succeeded or Defeated accordingly.
- Queued: If Succeeded, anyone can call
governor.queue(), which schedules the proposal's operations in the TimelockController with the configured delay. - Waiting: The Timelock enforces a mandatory delay. During this period, stakeholders can react.
- Executed: After the timelock delay, anyone can call
governor.execute(). The Timelock executes the proposal's operations (contract calls, transfers, etc.). - Canceled: At any point before execution, the proposer can cancel the proposal (in most implementations).
The Token provides voting weight, the Governor manages the proposal process and vote counting, and the Timelock enforces a delay before execution.
15. A developer uses governor.on('VoteCast', callback) to listen for real-time vote events on their frontend, but the events never fire. What are two possible causes and how would you fix each?
Model Answer:
Cause 1: The RPC connection uses HTTP instead of WebSocket. Event listeners require a persistent WebSocket connection to receive push notifications from the node. HTTP connections are request-response only and cannot receive unsolicited event notifications. Fix: Switch to a WebSocket RPC endpoint (e.g., wss://eth-sepolia.g.alchemy.com/v2/your-key instead of https://...) or use polling with governor.queryFilter('VoteCast', fromBlock, toBlock) on a timer.
Cause 2: The contract address or ABI is incorrect. If the ethers.js Contract object is pointed at the wrong address, it will listen for events that are never emitted at that address. Similarly, if the ABI does not include the VoteCast event, ethers.js cannot decode the event logs. Fix: Verify that the contract address matches the deployed Governor address and that the ABI includes the complete VoteCast event definition with all parameters.