About StarkDiff
Inspiration
The idea for StarkDiff came from a frustrating debugging session. I was working on a Starknet smart contract and a transaction had failed in an unexpected way. I knew something had changed in the contract's storage, but figuring out what changed felt like archaeology. Block explorers showed me the transaction happened, but gave me cryptic hex values. Reading raw RPC responses meant parsing through nested JSON structures. Setting up a local devnet to reproduce the issue required manual contract redeployment and hoping I could recreate the exact state.
I thought: "There has to be a better way."
That's when I realized there was a fundamental gap in the Starknet developer experience. Ethereum developers have tools like Tenderly and Etherscan's state diff features. Starknet developers had... nothing comparable. We were flying blind, spending 10+ hours a week just trying to understand what our transactions actually did.
StarkDiff was born from this pain point. I wanted to build something that would save developers time, reduce debugging frustration, and make Starknet development more transparent and accessible.
What it does
StarkDiff is a comprehensive state-diff explorer and security analyzer for Starknet that makes blockchain state changes visible, understandable, and actionable.
Core Features:
Transaction Inspection - Paste any transaction hash and see exactly what changed in contract storage, with before/after values presented in human-readable format.
Block Analysis - Inspect entire blocks to understand all state changes across multiple transactions.
Security Analysis - Automatic detection of risky patterns including:
- Ownership and admin changes (Critical severity)
- Role and permission modifications (High severity)
- Nonce anomalies (Medium severity)
- Critical storage slot changes
- Large value transfers
OpenZeppelin Integration - Recognizes and analyzes 9+ OpenZeppelin Cairo components (Ownable, AccessControl, ERC20, ERC721, Pausable, etc.) with component-specific security rules.
Multiple Interfaces:
- CLI Tool - Fast command-line inspection with beautiful terminal output
- REST API - Full-featured API for integration with other tools
- Web UI - Beautiful React-based dashboard for visual exploration
Export Capabilities:
- JSON reports for documentation and sharing
- Auto-generated Cairo test cases from real transactions
- Git-style diff format for code reviews
Multi-Network Support - Works on Starknet Mainnet and Sepolia testnet.
Example Usage:
# CLI
starkdiff inspect 0xYOUR_TX_HASH --network mainnet --audit
# API
curl -X POST https://api.starkdiff.com/api/inspect \
-d '{"hash":"0xYOUR_TX_HASH","network":"mainnet","audit":true}'
StarkDiff transforms cryptic hex values into actionable insights, helping developers debug faster, catch security issues before deployment, and understand contract behavior at a glance.
How we built it
Technical Deep Dives
State Diff RPC Internals: I learned how
starknet_getStateUpdateworks under the hood, including how Starknet organizes storage changes, nonce updates, and class declarations. Understanding the difference between storage diffs, deployed contracts, and declared classes became crucial.Security Pattern Recognition: While implementing the security analyzer, I discovered common patterns in ownership changes, role mutations, and access control. I learned that storage slot
0x0is often used for ownership in many contracts, and how OpenZeppelin Cairo components structure their storage.OpenZeppelin Cairo Components: Integrating OpenZeppelin pattern detection taught me how different components (Ownable, AccessControl, ERC20, ERC721) organize their storage and what security implications each has. The component model in Cairo is fundamentally different from Solidity's inheritance model.
TypeScript Type Safety: Working with Starknet.js and strict TypeScript types forced me to handle edge cases I wouldn't have considered otherwise—like pending transactions, missing blocks, and malformed RPC responses.
Developer Experience Insights
The Power of Good DX: I learned that developers will tolerate a lot of complexity if you give them a clean interface. Making the CLI output beautiful with chalk, providing multiple output formats, and adding security analysis transformed a utility tool into something people actually want to use.
Documentation Matters: Writing comprehensive documentation (900+ lines across guides) taught me how to think from a user's perspective. Every "obvious" feature needed explanation, every error message needed a troubleshooting guide.
Unexpected Challenges
RPC Provider Reliability: I learned that public RPC endpoints have limitations—rate limits, occasional downtime, inconsistent responses. This taught me defensive programming and the importance of comprehensive error handling.
Node.js Ecosystem Complexity: Navigating Vite versions, TypeScript configurations, Next.js API routes, and managing three separate services (CLI, API, Web UI) taught me project architecture at scale.
How I Built It
Architecture Decision: Three Interfaces, One Core
I designed StarkDiff with a shared TypeScript core library that powers three different interfaces:
Core Library (src/)
├── CLI Tool (commander.js)
├── REST API (Next.js)
└── Web UI (React + Vite)
This architecture meant I could:
- Write business logic once, use it everywhere
- Test core functionality in isolation
- Add new interfaces without duplicating code
- Maintain consistency across all user experiences
Architecture: Three Interfaces, One Core
We designed StarkDiff with a shared TypeScript core library that powers three different interfaces:
Core Library (TypeScript)
├── CLI Tool (Commander.js)
├── REST API (Next.js)
└── Web UI (React + Vite)
This architecture meant writing business logic once and deploying it everywhere—CLI for developers, API for integrations, and Web UI for non-technical users.
Technology Stack:
- Core: TypeScript 5.5, Starknet.js 6.11, Node.js 18+
- Backend: Next.js 14 with serverless API routes
- Frontend: React 18, Vite 6, Tailwind CSS, shadcn/ui components
- CLI: Commander.js, Chalk for beautiful terminal output, cli-table3
- Security: Custom pattern detection engine, OpenZeppelin component analyzer
Development Process:
Week 1: Proof of Concept
- Built basic CLI that could fetch state diffs using
starknet_getStateUpdate - Implemented table formatting with cli-table3
- Created network configuration for Mainnet/Sepolia
Week 1: Making It Human-Readable
- Added before/after value fetching for storage slots
- Implemented the decoder for common storage patterns
- Created multiple output formats (table, JSON, compact)
Week 2: Security Analysis
- Researched common Starknet security patterns
- Implemented five detection categories (ownership, roles, nonces, critical storage, large values)
- Added colored, severity-based reporting
Week 3: Production Ready
- Built Next.js API backend
- Created React web interface with shadcn/ui components
- Implemented export functionality (JSON, Cairo tests, diff format)
- Fixed all linting errors, security vulnerabilities
- Wrote comprehensive documentation
Week 4: OpenZeppelin Integration
- Studied OpenZeppelin Cairo contracts on GitHub
- Implemented component detection (9+ components recognized)
- Added component-specific security rules
- Enhanced audit reporting with OZ context
Week 4: Polish & Production
- Created production deployment guides
- Wrote RPC troubleshooting documentation (600+ lines)
- Removed emojis from code output for terminal compatibility
- Added real transaction examples throughout docs
- Prepared for public release
Key Technical Implementations:
1. Transaction vs Block Identification
// Had to detect if input is transaction hash (66 chars) vs block number
if (hash.startsWith('0x') && hash.length === 66) {
result = await fetcher.fetchByTransactionHash(hash);
} else if (hash.startsWith('0x')) {
result = await fetcher.fetchByBlockHash(hash);
} else {
result = await fetcher.fetchByBlockNumber(parseInt(hash));
}
2. Nonce Parsing Inconsistency
// Starknet returns nonces in different formats depending on the query
private static parseNonce(value: string | Record<string, unknown>): number | null {
if (typeof value === 'object' && value.nonce) {
return parseInt(value.nonce as string, 16);
}
if (typeof value === 'string') {
return parseInt(value, 16);
}
return null;
}
3. Security Pattern Detection Without ABIs
// Without ABIs, detect patterns by storage slot positions and value changes
private static isOwnershipKey(key: string): boolean {
const ownerPatterns = ['0x0', '0x1', '0x2']; // Common owner slots
return ownerPatterns.includes(key.toLowerCase());
}
Production Ready:
- Zero npm security vulnerabilities
- Comprehensive test coverage (9/9 API tests passing)
- Full documentation (900+ lines across guides)
- Production deployment ready (Vercel, Railway, Docker)
Challenges we ran into
1. RPC Response Inconsistency
The Problem: Different RPC providers returned state updates in slightly different formats. Some included pending transactions, others didn't. Block hashes were sometimes strings, sometimes objects.
The Solution: Built defensive type checking everywhere, used TypeScript's union types, and created helper functions to normalize responses:
const blockHash = 'block_hash' in block ? block.block_hash : 'pending';
2. Node.js Version Compatibility
The Problem: Vite 7 required Node.js 20.19+, but many developers use 20.11.1. VitePress 2.0 (alpha) had the same issue. This would've blocked adoption.
The Solution:
- Downgraded to Vite 6 (still fixes security issues, broader compatibility)
- Used VitePress 1.6.4 (stable) instead of 2.0-alpha
- Documented the decision in ARCHITECTURE.md
3. Making Security Analysis Useful
The Problem: Early versions flagged everything as suspicious. Every storage change was a "potential security issue." This created alert fatigue and made the tool useless.
The Solution:
- Researched actual Starknet exploits and vulnerabilities
- Focused on high-signal patterns (ownership changes, role mutations)
- Implemented severity levels (critical, high, medium, low)
- Added actionable recommendations to every issue
- Made it opt-in with
--auditflag
4. Three Codebases, One Developer
The Problem: Managing CLI, API, and Web UI simultaneously meant context switching constantly. A bug fix in the core library could break all three interfaces.
The Solution:
- Created shared types in a central
types.tsfile - Wrote the core library first, then wrappers
- Used TypeScript's type system to catch integration issues at compile time
- Built comprehensive test suite for the core library
5. Documentation Completeness
The Problem: I knew how to use StarkDiff, but users didn't. Questions like "What RPC provider should I use?" and "Why is my transaction not found?" needed answers.
The Solution:
- Wrote RPC_TROUBLESHOOTING.md (600+ lines) covering every error
- Created PRODUCTION_READINESS.md explaining what's ready vs what's not
- Added real transaction examples (not just placeholders)
- Created multiple quick-start paths (5 min, 30 min, full day)
6. Terminal Compatibility
The Problem: Emojis looked great in my terminal but broke in CI/CD logs, some SSH sessions, and enterprise terminals.
The Solution:
- Removed emojis from all code output
- Replaced with bracketed labels:
[CRITICAL],[HIGH],[OK] - Kept chalk colors for visual distinction
- Preserved emojis in documentation (where they enhance readability)
7. Feature Scope Management
The Problem: Built a transaction replay feature using starknet-devnet, but it required external dependencies, wasn't fully tested, and the devnet state loading API was "simplified."
The Solution:
- Marked it as "experimental"
- Documented the limitations clearly
- Decided not to promote it as a core feature
- Planning to improve or remove for v1.0
Accomplishments that we're proud of
Zero Security Vulnerabilities - Achieved and maintained 0 npm vulnerabilities through careful dependency management and regular audits.
Production-Ready in 4 Weeks - Built a complete, deployable product with three interfaces, comprehensive documentation, and full test coverage.
OpenZeppelin Integration - First tool to recognize and analyze OpenZeppelin Cairo component patterns automatically.
Beautiful Developer Experience - Created a CLI tool that developers actually want to use, with colored output, clear error messages, and multiple output formats.
Comprehensive Documentation - Wrote 900+ lines of documentation covering every use case, error scenario, and deployment option. Created a 600-line RPC troubleshooting guide that covers every possible error.
Real-World Testing - Used real Sepolia transactions for examples and testing, ensuring everything works with actual blockchain data.
Open Source Done Right - MIT licensed, well-documented, easy to contribute to, with clear architecture and comprehensive guides.
Multi-Interface Architecture - Designed a shared core library that powers CLI, API, and Web UI without code duplication.
Security-First Approach - Built-in security analysis that detects ownership changes, role mutations, and suspicious patterns automatically.
Production Deployment Ready - Can be deployed to Vercel in 10 minutes with full setup guides and configuration examples.
What we learned
Technical Insights:
State Diff RPC Internals - Deep understanding of how
starknet_getStateUpdateworks, including storage diffs, deployed contracts, and declared classes.Security Pattern Recognition - Learned how ownership changes, role mutations, and access control work in Starknet. Discovered that storage slot
0x0is often used for ownership.OpenZeppelin Cairo Architecture - Understanding how Cairo components differ from Solidity's inheritance model and how different components (Ownable, AccessControl, ERC20, ERC721) organize their storage.
TypeScript Type Safety - The value of strict typing when handling complex external APIs. Type safety caught bugs that would have been nightmare to debug in production.
RPC Provider Ecosystem - Public RPC endpoints have limitations (rate limits, occasional downtime). Learned defensive programming and comprehensive error handling.
Developer Experience Lessons:
Documentation is a Product Feature - Good documentation can make or break adoption. Users need examples, troubleshooting guides, and clear error messages.
Backwards Compatibility Matters - Chose Vite 6 over Vite 7 for broader Node.js compatibility. Better to support more users than have cutting-edge features.
Security Tools Need Precision - Early versions flagged everything as suspicious, creating alert fatigue. Learned that false positives kill trust faster than false negatives.
Architecture Decisions Pay Off - The shared core library made everything easier. Writing logic once for CLI, API, and Web UI saved countless hours.
Simplicity Scales - Kept it simple with REST instead of GraphQL, monolithic instead of microservices, TypeScript instead of multiple languages. Simple works.
Project Management:
Ship What Works - Marked the replay feature as "experimental" instead of rushing it to completion. It's better to have 3 great features than 4 mediocre ones.
Real Examples Matter - Used actual Sepolia transaction (
0x0316f67cc3f24b6118c3c4faaf4abbe34b34c78e38b383b6b58f1692909562ae) throughout docs instead of placeholders.Professional Tools Work Everywhere - Removed emojis from terminal output for better compatibility with CI/CD, SSH sessions, and enterprise environments.
What's next for StarkDiff
Immediate Priorities (v0.2.0):
ABI Decoding - Decode storage values using contract ABIs to show human-readable token amounts, addresses, and structured data instead of raw hex.
Caching Layer - Implement Redis caching for frequently accessed transactions to reduce RPC load and improve response times.
Batch Processing - Allow analyzing multiple transactions at once for comprehensive audits and bulk operations.
Enhanced OZ Detection - Improve OpenZeppelin component detection accuracy with more comprehensive pattern matching.
Near-term Goals (v0.5.0):
GitHub Action - Create a GitHub Action for CI/CD pipelines to automatically analyze transactions before deployment and fail builds on critical security issues.
Custom Security Rules - Build a rule engine that lets users define their own security patterns based on their specific contract architecture.
VS Code Extension - Bring StarkDiff directly into the IDE with inline transaction inspection and security warnings.
Transaction Comparison - Side-by-side diff comparison of two transactions to understand behavior changes across contract upgrades.
Future Vision (v1.0.0 and beyond):
ML-Based Anomaly Detection - Train models on historical Starknet transactions to detect unusual patterns that might indicate exploits or bugs.
Time-Series Analysis - Track contract behavior over time with historical charts and trend analysis to identify degradation or suspicious changes.
Tool Integration - Native integration with Scarb, Starknet Foundry, and other popular Starknet development tools.
Multi-Language SDKs - Build Python, Rust, and Go SDKs for programmatic access to StarkDiff's analysis capabilities.
Smart Contract Monitoring - Real-time monitoring service that alerts protocol teams when critical state changes occur in their contracts.
Educational Platform - Create interactive tutorials using real transactions to teach developers about Starknet state management and security best practices.
Mission: Make every Starknet transaction transparent and secure, empowering developers at all skill levels to build with confidence.
Project Status: Production-ready v0.1.0
GitHub: https://github.com/daveylupes/starkdiff
Author: @daveylupes
License: MIT
Built with: TypeScript, Starknet.js, Next.js, and React
"Making Starknet development transparent, one transaction at a time."
Built With
- next
- starknet
- typescript
Log in or sign up for Devpost to join the conversation.