Smart Contract Audit: Protecting DeFi from Vulnerabilities

Before launching a DeFi protocol, a logic error costs more than any delay. We review smart contracts manually and with automated checks, eliminate entire classes of failures, and deliver a clear report with fix priorities to the team. We provide end-to-end service: from code review to a repeat audit policy.

Blockchain Development Services

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1375
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1349
  • B2B Advance company logo design
    B2B Advance company logo design
    794
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1087
  • AIDER company logo development
    AIDER company logo development
    1032
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1129

Smart contract audit: where logic breaks before the first exploit

A smart contract cannot be quietly patched: once published, its logic executes exactly as written, and an error in it becomes an open invitation.

A smart contract audit looks not for typos but for failure points where a single call withdraws more from the protocol than was deposited. We examine not only the code but also connections to price oracles, liquidity pools, and user wallets.

The first typical point is the withdrawal right held by a single role. If a single address can take all liquidity without delay, limits, or a second signature, the cost of a key error equals the value of the entire pool. We split such rights into roles, add an execution queue, and a per-withdrawal cap.

Second is settlement order. When the balance updates after an external call, the contract can respond to a repeated request with the previous state and pay out funds twice.

The same class enables rounding in favor of the caller — across a stream of transactions, this is a persistent risk of fund withdrawal.

Third is external calls without result validation: a returned failure, stale price, or empty response passes as success, and the protocol records a transaction based on incorrect data. DeFi exploit protection begins with validating every external response and limiting it by time.

We take basic primitives from proven libraries — OpenZeppelin — and do not write our own arithmetic where it has already passed public review. Next, we examine how these smart contract vulnerabilities are closed before release and what remains in the report.

What changes after an audit: eliminated failure classes and speed of fixes

After an audit, the list of open vulnerability classes drops to zero for critical and high severity: reentrancy through external calls, bypass of access control for privileged methods, oracle price manipulation on a thin pool, rounding errors when accruing fees, and dependence of the result on transaction ordering.

Each class is not merely named — it is confirmed by an exploit scenario and closed by a fix in a specific method.

The second effect is coverage.

A static analyzer such as Slither catches formal defects, but invariants run through fuzzing over thousands of call sequences are decisive: preservation of the sum of balances, monotonicity of the index, and unavailability of withdrawal above a share.

The share of paths covered by such checks becomes a measurable quantity rather than a declaration in a report.

The speed of releasing fixes changes qualitatively: a discovered attack scenario becomes a regression test, and the fixed version is verified by rerunning the entire suite rather than by manually reviewing changed lines.

The path from finding to a fixed version fits into one fix cycle instead of a series of iterations “found — rewrote — found again.”

Release predictability rests on a strict rule: deployment does not proceed with an open critical finding.

The verification checklist is embedded in the build pipeline, the report records the status for each vulnerability class, and the release decision is made based on risks actually being closed, not on the team’s feeling of readiness.

Smart contract audit: manual review and machine checks

A smart contract audit is not reduced to a single tool. Static contract analysis quickly goes through all the code and catches typical defects — external calls before state changes, unprotected fund withdrawal, overflows.

But an analyzer does not understand the protocol’s intent: it cannot distinguish intentional delegation of rights from an access error, so for every real defect there are dozens of analyzer false positives.

Manual code review closes this gap — economics, call order, and boundary states are checked against scenarios.

Verification formats differ in depth and in which class of errors they are capable of seeing at all:

Verification option When appropriate Limitations
Manual code review Protocol logic, economics, role rights, integrations with external contracts Requires time and expertise; coverage depends on selected paths
Static contract analysis First pass over the entire codebase, search for typical vulnerabilities, verification in the build pipeline Many false positives; does not see logic errors
Formal verification Critical invariants: preservation of balances, issuance limits, liquidation conditions Requires a formal specification; applicable to the core, not the entire system
Re-verification after fixes Any fix affecting state storage or external calls Checks changed areas; requires impact assessment on the rest of the system

In practice, the approaches are combined: a machine pass over the entire repository, manual review of critical paths, formal verification of the core, and re-verification after each fix. This closes both typical errors and logic defects that a tool cannot see in principle.

How implementation proceeds: from code review to report handover

The audit proceeds in sequential stages: first we establish what the contract must do, then how it may do something wrong. Without the first steps, the audit amounts to running a ready-made rule set, and some attack paths remain outside the review.

  1. Requirements and scope gathering. We clarify the logic, roles, places where funds are stored, and external calls; we write out invariants that must not be violated under any circumstances.
  2. Contract and role diagram. A map of calls, rights, and dependencies between modules shows where one participant can affect others’ funds.
  3. Line-by-line review. We follow the diagram through the code: arithmetic and rounding, access checks, state update order, and handling of external calls.
  4. Attack scenario execution. Nested call reentry, price manipulation, transaction front-running, withdrawal above balance — we confirm each hypothesis with a test, not with reasoning.
  5. Fix. Together with your team, we make fixes or provide targeted patches, noting where logic changes, not just protection.
  6. Control verification. We rerun the scenarios and make sure the patch did not open a new path or break the invariants from the first item.
  7. Report handover. Findings with risk level, reproduction path, and fix status; if the logic changes, re-verification after deployment to the network.

Each stage leaves a trail: it is clear what was checked, what remains, and what the conclusion is based on.

What remains in the project: configurations, diagrams, and policies

An audit ends not with a verdict “no vulnerabilities found” but with a set of artifacts that the team can continue working with without us: below is what remains in the repository after the audit is delivered.

  • Audit report — for each finding, risk class, execution path, function reference, and minimal reproduction scenario. There are no formulations like “we recommend checking”: either a specific call or the item did not make it into the report.
  • Audit artifacts — static analysis configurations, fuzzing scenarios, invariant tests, and coverage snapshots. The set is rerun with a single command, so the result is reproducible.
  • Access diagrams — a role map: who issues assets, changes parameters, freezes operations, and updates logic; roles with execution delay and candidates for multisig are marked separately.
  • Change policy — which fixes require re-verification and which follow a simplified procedure; rules for updating logic through a proxy and a prohibition on changing the order of fields in storage.
  • Re-verification policy — triggers: changes to calculations, changes to economic parameters, expansion of administrator rights, connection of an external data source.
  • Contract documentation — invariants, event model for monitoring, list of external calls, and assumptions on which the logic rests.
  • Accepted risk log — findings consciously left without fixes, with justification and impact assessment: a new team will not have to figure this out again.

The set removes dependence on the contractor: the next audit can be performed in-house or handed over to another team — there is a single entry point.

Case study: before and after fixing a critical vulnerability

What it was before the fix

The contract audit case began with two audits by previous contractors: the contract compiled, and static analyzers gave a clean report. A reentrant call remained in the withdrawal logic — an external contract was able to return control before the internal balance was updated.

The class is described in SWC Registry as interaction before state change — no scanner flagged it here because the vulnerability manifested only in a combination of calls, not within a single function.

What was found and what was changed

Engineers traced the call flow from deposit to withdrawal and consolidated it into a balance change diagram — on it, the window between debit and recording became visible.

The liquidity incident scenario was reproduced on a local copy of the network: a series of calls pulled more from the pool than had been deposited, and did so without a single error in the logs.

The fix was reduced to the “check — write — external call” order, protection against reentrancy was added, and a regression test that fails if the old operation order returns.

Metric Before After
Response to pool anomaly hours minutes
Share of withdrawal paths under tests 40% 95%
Detection of reentrancy class not detected closed by test

After fixing the critical vulnerability, re-verification found no new outflow paths, and pool monitoring was switched to threshold alerts based on reserve volume.

Rollback to the previous contract version remained available — the fixes were made so that the pool state did not require migration.

How does a pre-launch audit differ from a post-incident review?

A pre-launch audit is work with the source code before money has appeared in the contract. Engineers go through all execution branches: administrator rights, external calls, state update order, and dependencies on external data sources.

Economic scenarios are modeled separately — price manipulation, liquidity withdrawal, and token price pumping.

A post-incident review solves a different task: stop losses and understand the vector. The order is reversed — first transaction traces on the network, then reconstruction of the call sequence, and only then the cause in the code.

If the source code is unavailable or the deployed code differs from it, analysis has to be done using bytecode.

The difference in approaches is in goals, not tools. Before launch, completeness is needed: cover all execution paths, describe risk classes and the conditions for their realization.

After an incident, speed is needed: two or three nodes through which the withdrawal passed, urgent measures — pause, migration, contract update — and only then a full review of what happened.

Re-verification is mandatory in both modes. A patch often closes one vector and opens an adjacent one, so the fixed code goes through the same scenarios again rather than being eyeballed.

After an incident, the discovered rules are transferred into preventive checks for subsequent releases.

Common technical doubts before starting work

Doubts before an audit rarely concern methodology — more often people ask about the scope of work: what is actually checked in already deployed code, where automation ends and manual review begins, and who is responsible for findings after handover. Below are answers to what comes up in the first review.

The contract is already deployed — is it too late to audit?

No, although fixes are more expensive. We compare the on-chain code with the source, check whether the logic is updated through a proxy and who has rights to change it. If the hole can be closed by an update, we prepare a patch; if not, we calculate state migration.

Are automated analyzers sufficient?

No. They catch template errors: bypass of access checks, overflows, uninitialized variables. Protocol logic cannot be seen that way — we review it manually and run scenarios on a copy of the network.

Do you check economic logic?

Yes, as a separate track: price manipulations, liquidation order, timing of reward accrual, dependence on an external price source. Correct code with flawed economics loses funds just as confidently.

What happens after fixes based on your report?

Re-verification of the changed areas, not the entire code from scratch: we confirm that the specific discovered paths are closed and no new ones have appeared. The regression test suite remains with the team.

What about responsibility after handover?

We hand over a report with risk levels, tests, and call diagrams; we do not hold keys or control the protocol. We are responsible for methodology and reproducibility of conclusions, so we plan re-verification after every significant update in advance.

Let’s discuss the task: what to clarify before the audit begins

To come back with a timeline estimate and work plan rather than clarifying questions, we need just a few inputs. The more precisely the system boundaries and role model are described, the fewer assumptions in the estimate and the higher the chance of meeting the launch date.

What helps discuss the task concretely:

  • Audit scope: which contracts are in scope and which external calls — oracles, bridges, liquidity pools — we consider trusted and do not review.
  • Role and access diagram: who has admin functions, whether there is multisig and a delay for critical operations such as fund withdrawal.
  • Change history and source code: how to match the repository with the contract deployed on the network so that the logic matches the build.
  • Known incidents and assumptions: what you have already found yourselves, what was consciously left as is, and which places the team considers risky.
  • Regulatory and platform requirements: the format of the conclusion that partners or a trading platform will accept, and the required report sections.
  • Launch or next release deadlines: the order of work depends on the date — critical paths first, then the rest of the logic.
  • Protocol economics: how shares, fees, and liquidations are calculated — discrepancies in formulas most often open the path to fund loss.

After that, scope agreement takes one conversation: we establish what is included in the audit, what remains outside the scope, and in what order we deliver results — critical paths before the periphery.