Fatskills
Practice. Master. Repeat.
Study Guide: Blockchain and Web3 Development: DeFi and Tokenomics Liquid Staking and LSDs
Source: https://www.fatskills.com/cryptocurrency-bitcoin-blockchain-and-more/chapter/blockchain-and-web3-development-blockchain-and-web3-development-defi-and-tokenomics-liquid-staking-and-lsds

Blockchain and Web3 Development: DeFi and Tokenomics Liquid Staking and LSDs

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~6 min read

What This Is

Liquid staking lets users lock their native proof‑of‑stake tokens (e.g., ETH, DOT, SOL) in a validator and receive a tradable “Liquid Staking Derivative” (LSD) token that represents their stake plus accrued rewards. The derivative can be used instantly in DeFi—swapped on Uniswap, supplied to Aave, or staked in a DAO—while the underlying validator continues to earn consensus rewards.

Real‑world example: Alice deposits 10 ETH into Lido. Lido mints 10 stETH (the LSD) and sends it to Alice. Alice instantly swaps 5 stETH for USDC on Uniswap, uses the remaining 5 stETH as collateral on Aave, and still earns ETH staking rewards behind the scenes.


Key Terms & Code Snippets

  • Liquid Staking Derivative (LSD) – A token (usually ERC‑20) that tracks a user’s share of a pooled staking position and accrues rewards proportionally.
  • Staking Pool Contract – Holds the validator deposits and mints/burns LSDs.
    solidity contract LidoPool is ERC20 {
    uint256 public totalStaked; // ETH locked in validators
    function submit() external payable {
    totalStaked += msg.value;
    _mint(msg.sender, msg.value); // 1:1 mint of stETH
    } }
  • Reward Accrual (rebasing vs non‑rebasing)Rebasing LSDs automatically increase balance to reflect rewards; non‑rebasing keep a static balance and expose rewards via a separate exchangeRate.
    solidity // non‑rebasing example function exchangeRate() public view returns (uint256) {
    return totalStaked * 1e18 / totalSupply(); // 1e18 = 1.0 in 18‑decimals }
  • Validator Operator – An off‑chain service (or a set of contracts) that runs the actual validator nodes and reports rewards back to the pool.
  • ERC‑4626 Vault – Standardized “tokenized vault” interface; many LSDs implement it so they can be plugged into existing DeFi primitives.
  • Delegation – The act of assigning voting power or staking rights to another address (e.g., a DAO). In LSDs, delegation often works on the derivative token, not the underlying stake.
  • Slashing – Penalty when a validator misbehaves; LSD contracts must handle partial loss of the pooled stake and adjust balances accordingly.
  • Liquidity Provider (LP) Token – When an LSD is paired on an AMM, the LP token represents a share of the pool (e.g., stETH‑USDC LP).
  • EIP‑1559 Fee Model – Affects how much gas you pay when depositing/withdrawing from a staking pool; using maxFeePerGas can reduce front‑running risk.
  • receive() / fallback() – In the pool contract, receive() must be payable to accept ETH deposits; forgetting it will cause transactions to revert.
  • nonReentrant Modifier – Prevents re‑entrancy when users withdraw LSDs and the contract sends ETH back.
    solidity function withdraw(uint256 amount) external nonReentrant {
    uint256 ethAmount = amount * exchangeRate() / 1e18;
    _burn(msg.sender, amount);
    payable(msg.sender).transfer(ethAmount); }
  • delegatecall vs call – Some LSD implementations use a proxy pattern (delegatecall) to upgrade logic without moving funds; auditors check that storage layout is safe.


Step‑by‑Step / Process Flow

  1. Write the staking pool contract – Use the template above, add nonReentrant, receive(), and reward‑update logic.
  2. Compile & test – Run npx hardhat compile and write unit tests (deposit, withdraw, reward rebasing).
  3. Deploy to a testnet
    bash
    npx hardhat run scripts/deploy.js --network goerli


    (Make sure your Infura/Alchemy API key is set in .env).
  4. Add the LSD to an AMM – Create a Uniswap V3 pool via the UI or script, then provide liquidity:
    js
    const router = new ethers.Contract(UNISWAP_ROUTER, routerABI, signer);
    await router.addLiquidityETH(
    stETH.address,
    ethers.utils.parseUnits("5", 18),
    0,
    0,
    signer.address,
    Math.floor(Date.now()/1000)+60*10,
    { value: ethers.utils.parseEther("5") }
    );
  5. Integrate into a DeFi app – Use the LSD’s ERC‑20 address in your front‑end (Ethers.js Contract instance) to let users swap, lend, or vote.

Common Mistakes

  • Mistake: Minting LSDs 1:1 without tracking total ETH locked.
    Correction: Keep a totalStaked variable and update it on every deposit/withdrawal; otherwise the exchange rate drifts and rewards are mis‑represented.

  • Mistake: Using tx.origin for access control (e.g., only the pool owner can call withdraw).
    Correction: Use msg.sender and OpenZeppelin’s Ownable/AccessControl. tx.origin can be spoofed through a malicious contract, leading to unauthorized withdrawals.

  • Mistake: Forgetting to make receive() payable, causing deposits to revert.
    Correction: Declare receive() external payable {}; this is the fallback that captures plain ETH transfers.

  • Mistake: Neglecting slashing handling – balances stay unchanged after a validator penalty.
    Correction: Implement a handleSlashing(uint256 loss) function that reduces totalStaked and proportionally burns LSDs or adjusts the exchange rate.

  • Mistake: Deploying the pool with an outdated Solidity compiler (e.g., <0.8.0) and missing built‑in overflow checks.
    Correction: Use pragma solidity ^0.8.20; (or latest stable) to get automatic overflow protection and newer optimizer flags.


Blockchain Developer Interview / Practical Insights

  1. “Explain the difference between a rebasing and a non‑rebasing LSD.” – Interviewers expect you to discuss balance changes vs. exchange‑rate calculations and the impact on downstream contracts (e.g., LP tokens).
  2. “How would you safeguard against a validator slashing event in your pool contract?” – Mention a handleSlashing hook, proportional balance adjustments, and the need for an off‑chain oracle or validator‑reporting mechanism.
  3. “Why might you choose a proxy (delegatecall) pattern for an LSD implementation?” – To upgrade reward‑distribution logic without moving user funds; but you must keep storage layout identical and protect against delegatecall injection attacks.
  4. “What gas‑optimizations are typical for high‑frequency deposit/withdraw functions?” – Use unchecked for loops where safe, pack variables into a single storage slot, and emit events only when necessary.

Quick Check Questions

  1. Scenario: A contract uses tx.origin to verify that only the original user can withdraw their LSD.
    Answer: Dangerous – a malicious contract can call the vulnerable contract on behalf of the user, making tx.origin the user’s address and bypassing the check.

  2. Scenario: Your LSD pool’s withdraw function sends ETH before burning the user’s LSD balance.
    Answer: This opens a re‑entrancy attack; the attacker could re‑enter withdraw and drain more ETH before the balance is reduced.

  3. Scenario: You see an LSD that reports a constant 1:1 exchange rate even after months of staking rewards.
    Answer: It’s a non‑rebasing token; rewards are reflected via an off‑chain exchangeRate() call, not by increasing the token balance.


Last‑Minute Cram Sheet (10 one‑liners)

  1. ⚠️ Never use tx.origin for auth – it can be spoofed through a contract call chain.
  2. Rebasing LSDs automatically increase holder balances; non‑rebasing keep a static balance and expose an exchangeRate.
  3. ERC‑4626 is the “tokenized vault” standard – most modern LSDs implement it for composability.
  4. nonReentrant (OpenZeppelin) protects withdraw functions from classic re‑entrancy attacks.
  5. Always store totalStaked and update it on every deposit/withdraw to keep the pool’s accounting sound.
  6. When using a proxy, keep the storage layout identical across upgrades; otherwise you’ll corrupt user balances.
  7. Gas tip: Pack multiple uint128 variables into a single uint256 slot to save ~20 k gas per write.
  8. EIP‑1559 tip: Set maxFeePerGas a few gwei above the current base fee to avoid being out‑bid by front‑runners.
  9. Slashing handling: Reduce totalStaked and proportionally burn LSDs or adjust the exchange rate; never ignore it.
  10. Common compiler version: pragma solidity ^0.8.20; – includes built‑in overflow checks and the latest optimizer.


ADVERTISEMENT