A small story about my auditing journey
First Step: Line-by-Line Auditing
When I first started auditing, my approach was extremely standardized. I audited each contract line by line, understanding the business logic, function by function.
At this stage, I was focused on grasping what each function did and how it fit into the larger functionality. However, this line-by-line approach, while thorough, had limitations:
Missed Vulnerabilities: Some bugs, especially complex ones involving cross-functional or state-based logic, can simply not be found by using this approach only.
Difficulty Seeing the Big Picture: Focusing so closely on individual lines of code made it challenging to understand the contract’s broader design or how different parts interacted.
At this stage, I was building foundational skills, understanding syntax, structure, and the logic behind various functions, but I hadn’t yet developed a method to catch some of the more complex or nuanced vulnerabilities.
It was an extreme hard process during this phase because the resources how to learn solidity (let alone auditing) were extremely limited (I bought some courses on Udemy back then)
Second Step: Introducing Function Jumping and State Differentiation
In my second step, I adapted my process to address the limitations of pure line-by-line auditing. I began to jump between functions, tracking how different functions connected and interacted with each other. This shift helped me get a better grasp on state management within contracts:
Better Contextual Awareness: By understanding the interconnections between functions, I was able to identify vulnerabilities in the transitions between contract states.
Functionality-Based Auditing: Instead of focusing on individual lines in isolation, I started viewing functions as part of a broader context. This enabled me to uncover logic issues that occur when functions are used together or in specific sequences.
This approach helped me catch more bugs and improved my ability to analyze complex function interactions. At this point, I had developed a more holistic view of the code but the ability to efficiently spot game-theoretical issues or vulnerabilities in contract states was still not perfect.
Third Step: Initial Assessment Through State Separation
During the third step, I began my audits with an initial assessment based on contract states. With more experience, I found that I could identify potential weaknesses simply by mapping out the different states and interactions:
Preliminary Bug Identification: During this initial assessment, I could already find bugs simply by categorizing and understanding contract states. The process of separating and analyzing these states made many vulnerabilities clear right from the start.
Pattern Recognition and Sensitivity: Experience had taught me to recognize patterns and identify areas that were likely to contain vulnerabilities. Certain coding patterns or state transitions became red flags, and I intuitively knew where to look. This must not be mixed up with pattern matching which most auditors do these days.
This shift in focus allowed me to understand the contract’s dynamics more deeply, making it easier to uncover vulnerabilities in the broader logic rather than just in isolated functions. At this stage, I started uncovering more sophisticated bugs and edge cases, especially those related to state transitions and variable sensitivity.
Fourth Step: Freestyle Auditing and Intuition-Driven Leads
During the fourth step, my approach had become highly intuition-driven. I no longer felt the need to start at the beginning of a contract or follow a strict line-by-line order. Instead, I started randomly within the architecture and spent the first few days exploring the codebase freestyle:
Lead-Based Auditing: Instead of systematically working through functions, I would list potential leads, following my intuition to areas that I suspected might have vulnerabilities. Interestingly, the intuition was by that time already so great that I can find multiple leads / potential leads within the first few minutes.
Deep Architectural Understanding: This freestyle approach gave me a great understanding of the contract’s architecture. I began to uncover game-theoretical scenarios and complex vulnerabilities that might have been hidden in conventional audits.
High Success Rate of Intuition: At this point, my intuition had become a critical tool. Years of experience meant that I could sense which areas of the code were likely to contain vulnerabilities. I would often uncover significant issues based purely on this intuition.
This evolution of my approach meant that I could assess not only the security of individual functions but the security of the entire protocol’s structure and intent, including very sophisticated issues which were hard to explain “how I found them”.
I reached a point where I was confident enough to say that with sufficient carefulness and time, I am able to uncover around 95% of all issues. This has proven itself again and again when participating in team audits.
This does not mean that my auditing approach these days is purely based on intuition and freestyle auditing. It's only one part of many parts of my methodology for a full audit.
Reflection: How Experience Shapes Auditing Approaches
Over the years, my auditing approach transformed from a detailed, line-by-line process to one driven by intuition and architectural understanding. As I gained experience, I learned that while foundational skills and systematic approaches are crucial in the beginning, intuition and a deep understanding of contract dynamics become invaluable tools for discovering the most sophisticated vulnerabilities.
As knowledge and experience grow, an auditor’s intuition becomes one of the most reliable resources. This intuition enables us to see beyond the syntax and dive into the underlying logic and strategy of the code, revealing vulnerabilities that are nearly invisible in standard audit. There are some really great issues which other team members couldnt even reproduce when I told them exactly where to look for and what to look for, simply because reproducing the bug needed a few different, consecutive state transitions before it became visible.
For over 6 months, we've been writing a large body of work that explains the Uniswap V3 codebase.
As you can imagine, this is no small piece of literature!
Instead of waiting until everything is done before publishing, we decided to start releasing the portions that are finished now, rather than keep the useful alpha in the dark
We will compile all the blogs into a single resource, but right now this collection of articles has no name (Uniswap V3 Book is already taken — do you have suggestions?).
The first article we are publishing today is “How Concentrated Liquidity Works in Uniswap V3."
This article is rich in animations and even includes an interactive widget.
Of course, the bulk of the investment went into making sure we explained everything as clearly as possible.
We'd like to thank @andrewcmonte and @deadrosesxyz for their helpful reviews that contributed to this.
More will be published in the following weeks.
This is one of our biggest content investments to date.
Making such an intimidating codebase digestible is a huge task, and we're excited to be at the stage where we can release some highly polished articles about it.
🎆 New Year's Resolutions are shit.
1. The action items are what matter
2. Goal setting in public is bad
3. 1 year is too long a reflection period
Here's why 👇
@0xaleko@dethSCA@code4rena No you're not
Don't follow the hype of people saying they found many.
Keep working and trying to improve
You'll get better at your craft
@GiuseppeDeLaZa Just today i called up my fiancee telling her i saw some little bugs and gas optimisation..
Was happy i was making progress only to later see the bot race have found all that..
Got a soft pat on the back.
We try again..😊
I have been working in smart contract security for the past 10 months:
If starting over again, I'd do these from day 1:
- start contests immediately
- read exploits/hacks instead of audit reports
- avoid studying stuff I don't need at the moment
- write a POC for all my findings
- build a knowledge base with findings I found
- no CTF's (or just 1)
- spend less time caring about salty folks
When the findings aren't coming, auditing is very hard for me.
So I developed a plan for exactly these situations, and it has rewarded me with 51 Critical/High findings so far this year.
The 3️⃣ pillars of my momentum-based auditing framework, so you can use superstar mode too🧵
Little knowledge and high effort can land you in the top 10% of any contest.
Low effort and some more knowledge will land you in the top 50% (if you're lucky).
In the short term, effort is the best leverage you have.
Been asked quite a few times recently how I approach large and complex codebases without getting overwhelmed.
My answer - break it down into smaller components and tackle them one by one.
⏬⏬
@MartinAtanasovv You just understand the project before reading reports.
Awesome.
By any chance have you been doing CTFs?
About POCs you don't write them?