Protocol, L2, Oracle & ZK Engineering
A protocol is not a Solidity class hierarchy. It is asset accounting, market assumptions, external dependencies, and operations under adversarial inputs.
1. DeFi mechanics you must model
| Mechanism | Required model | Failure test |
|---|---|---|
| Lending | LTV, liquidation threshold, health factor, close factor, liquidation bonus, kinked utilization-rate curve | Price gap, stale oracle, bad debt, partial liquidation |
| AMM swap | Reserves, fees, slippage, minAmountOut, deadline, price impact and routing | Sandwich/revert on adverse price; zero-liquidity boundary |
| Vault | ERC-4626 conversions, share rounding, fees, donation resistance, strategy loss | First depositor, donation, loss, decimals mismatch |
| Stable/curve pool | StableSwap or weighted invariant, depeg scenario, oracle-free vs oracle-assisted price | One asset depegs; withdrawal queue/invariant remains safe |
Read and fork-test real interfaces rather than reimplementing a popular protocol from memory. Include Aave v3 isolation/e-mode and Uniswap periphery/router behavior in the investigation; an integration has more assumptions than its happy-path ABI call.
2. Oracle policy, not just an oracle call
function checkedPrice() internal view returns (uint256) {
(, int256 answer,, uint256 updatedAt,) = feed.latestRoundData();
if (answer <= 0 || updatedAt == 0 || block.timestamp - updatedAt > MAX_AGE) {
revert InvalidOraclePrice();
}
// Normalize feed decimals before combining with token decimals.
return uint256(answer);
}
- Document source, decimals, heartbeat, market-closure behavior, maximum age, fallback, and who can change configuration.
- Use a sequencer uptime feed where the L2 requires it. Define grace periods after recovery.
- For manipulable markets, combine independent sources, TWAP windows, liquidity floors, deviation bounds, and circuit breakers. Each control needs a test and operational owner.
- Do not use an oracle value to silently execute a large irreversible action without a bounded-risk policy.
3. L2 and cross-chain assumptions
A sidechain is not a rollup: Polygon PoS and an L2 have different trust and exit assumptions. For each target chain, document finality, reorg depth, sequencer failure/censorship behavior, data availability, precompile differences, native gas token, fee model, and canonical bridge. Learn the chain's message interfaces (for example OP Stack cross-domain messaging) rather than treating every EVM RPC as interchangeable.
| Message rule | Why |
|---|---|
| Authenticate transport and remote sender | Checking only a local endpoint permits forged payloads. |
| Persist message ID/nonce and consumed state | Prevents replay and gives an auditable recovery path. |
| Rate-limit mint/release and cap supply | Contains key compromise or implementation bugs. |
| Define ordering and retry semantics | Messages can delay, fail, arrive out of order, or be duplicated. |
| Monitor the full state machine | “Sent” is not “delivered” and “delivered” is not necessarily “executed”. |
4. MEV and transaction policy
- Every user swap needs bounded slippage, a deadline, and clear execution-price disclosure.
- Classify operations as public-mempool safe, private-submission preferred, or keeper-only. Test transaction replacement and nonce recovery.
- Use commit-reveal only when you have a credible reveal/liveness plan; it does not erase all information leakage.
- Model keeper incentives, liquidation races, and governance parameter changes as adversarial inputs.
5. ZK: circuit correctness is security
Learn the pipeline (circuit → witness → proof → verifier) and then add the production concerns that introductory examples omit: constrain every intended relationship, test malicious witnesses, version circuit/proving/verifying-key artifacts, pin verifier keys, decide upgrade governance, and measure proving CPU/GPU/memory and queue latency.
- Understand R1CS/PLONKish constraints, KZG commitments, recursion/aggregation, and why zkVMs trade circuit control for developer ergonomics.
- Use tooling such as Circomspect or equivalent review techniques to find underconstrained signals; unit-test negative cases that should be impossible.
- Keep public inputs minimal and explicit. A valid proof of the wrong statement is still a vulnerability.
6. Practical lab — guarded lending market
- Implement a collateralized borrowing prototype: deposit collateral, borrow a capped asset, repay, and partially liquidate. State formulas for health factor, liquidation threshold, close factor, and rounding direction in NatSpec.
- Use a mock Chainlink feed with stale, zero/negative, decimal-mismatch, and price-gap tests. Add an L2 sequencer-up check if deploying to an L2.
- Build Foundry handler invariants: debt/accounting conservation, no healthy account is liquidated, no borrower exceeds its cap, and liquidation improves health factor where mathematically possible.
- Fork-test token/oracle interactions; run a simulation of a 30–60% collateral drop and capture the resulting bad-debt behavior.
- Deploy to an L2 testnet. Make the UI submit slippage/deadline-bounded operations and expose pending, confirmed, reorged, and failed states.
7. Extension lab — proof-gated claim
labs/phase-24-zk/).