Smart Contract Security Audit

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Smart Contract Security Audit
Complex
~5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Smart Contract Security Audit

A smart contract is immutable code managing real money. One error in logic, incorrect access check, or unexpected call sequence can result in loss of user funds with no possibility of rollback. In 2023-2024, cumulative losses from smart contract exploits exceeded $2 billion. An audit is not a formality or insurance: it is the only systematic way to discover vulnerabilities before attackers do.

What Happens During an Audit

An audit is not just running automatic tools. It is a combination of manual analysis, automation, and threat modeling specific to the protocol. Blind trust in tool reports creates false sense of security.

Manual Code Analysis

An auditor reads code like an attacker. Key questions for each function: can the caller get funds that are not theirs? can repeated invocation yield a larger result? will system invariants change?

Access control verification: every write-function should have explicit access control. onlyOwner, onlyRole, msg.sender checks. Common mistake — forgotten check in initialize function of upgradeable contract.

Invariant verification: for each contract, invariants are formulated — properties that must always remain true. For example: "sum of all user balances ≤ totalSupply". Auditor checks if each invariant can be violated.

Automated Analysis

Slither (Trail of Bits) — static analyzer for Solidity. Runs quickly, catches typical vulnerability patterns:

slither . --config-file slither.config.json \
  --exclude naming-convention,solc-version \
  --print human-summary

Slither detects: reentrancy through various patterns, uninitialized variables in proxy contracts, unsafe delegatecall calls, arithmetic overflows (though Solidity 0.8.x added built-in checks), shadowed variables.

Mythril — symbolic execution. Analyzes all possible execution paths. Slower than Slither, but catches more complex patterns:

myth analyze --solc-json mythril.json contracts/Protocol.sol \
  --execution-timeout 120 \
  --max-depth 22

Echidna — fuzzer for property-based testing. You describe invariants as Solidity functions, Echidna generates millions of random transactions attempting to violate them:

// Echidna invariant: totalSupply never exceeds MAX_SUPPLY
function echidna_total_supply_bound() public view returns (bool) {
    return token.totalSupply() <= token.MAX_SUPPLY();
}

Foundry invariant testing — integrated into Foundry, similar approach:

// test/invariants/InvariantTest.sol
contract InvariantTest is Test {
    function invariant_solvency() public {
        assertLe(
            vault.totalDebt(),
            vault.totalAssets(),
            "Vault insolvent"
        );
    }
}

Fork Testing

For protocols interacting with existing DeFi primitives (Uniswap, Aave, Compound), audit includes fork testing on mainnet snapshot. This allows testing real interactions with real protocol states.

# Foundry fork test
forge test --fork-url https://eth-mainnet.g.alchemy.com/v2/KEY \
  --fork-block-number 19000000 \
  -vvv --match-contract AttackSimulation

Vulnerability Classification

Critical: Direct Loss of Funds

Reentrancy: classic attack. Contract calls external address before updating state. Attacker contract, on receiving ETH, re-calls vulnerable function.

// Vulnerable code
function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount);
    (bool success,) = msg.sender.call{value: amount}(""); // external call
    require(success);
    balances[msg.sender] -= amount; // state update AFTER call
}

// Correct: Checks-Effects-Interactions pattern
function withdraw(uint256 amount) external nonReentrant {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount; // update state first
    (bool success,) = msg.sender.call{value: amount}("");
    require(success);
}

The DAO hack (2016, $60M), Lendf.Me (2020, $25M), many others — reentrancy. nonReentrant modifier from OpenZeppelin and CEI pattern are standard. No excuses not to use them.

Price oracle manipulation: protocol uses spot price from AMM pool as oracle. Attacker through flash loan manipulates pool price, borrows or liquidates at artificial price.

Protection: TWAP (Time-Weighted Average Price) instead of spot price. Uniswap v3 TWAP, Chainlink — acceptable oracles. Spot price from pool — no.

Logic errors in financial calculations: incorrect operation order with integer division, incorrect decimal accounting across different tokens, rounding in user's favor (not protocol's) — accumulated errors.

High: Significant Damage Under Certain Conditions

Access control bypass: bypass checks through non-obvious paths. Example: initialize() in upgradeable contract called without initializer modifier — can reinitialize with different owner.

Front-running: attacker sees transaction in mempool and inserts theirs before it. Classic: DEX slippage attacks, bypassing deadline checks.

Flash loan price manipulation: described above, but broader category — any manipulations through temporary capital.

Unchecked return values: token.transfer() for non-standard ERC20 (USDT) returns bool. If not checked — silent failure.

// Dangerous
token.transfer(recipient, amount);

// Correct
require(token.transfer(recipient, amount), "Transfer failed");
// or use SafeERC20:
token.safeTransfer(recipient, amount);

Medium: Limited Damage or Requiring Specific Conditions

Denial of Service: gas griefing through large arrays, blocking through revert in callback, unbounded loops.

Timestamp dependence: using block.timestamp for critical logic. Validator can manipulate timestamp within ~15 seconds.

Integer overflow/underflow: in Solidity < 0.8.0 without SafeMath. In 0.8.x built-in checks, but unchecked {} blocks can create problems again.

Low and Informational

Stylistic issues, potential optimizations, documentation-to-code mismatch, missing events for important operations.

Specifics of Upgradeable Contract Audits

Proxy patterns (TransparentProxy, UUPS, Beacon) add additional attack surface:

Storage collision: proxy and implementation share one storage space. If layout doesn't match — variables get overwritten.

// OpenZeppelin recommends ERC-7201 namespace pattern:
// keccak256(abi.encode(uint256(keccak256("myprotocol.main")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant MAIN_STORAGE_LOCATION = 0x...;

struct MainStorage {
    uint256 totalSupply;
    mapping(address => uint256) balances;
}

function _getMainStorage() private pure returns (MainStorage storage $) {
    assembly { $.slot := MAIN_STORAGE_LOCATION }
}

Uninitialized implementation: direct call to initialize() on implementation contract (not through proxy) can compromise system. Solution: _disableInitializers() in implementation constructor.

UUPS: missing upgrade function in new implementation: if deploying implementation without upgradeTo — contract forever loses upgrade capability.

Typical Audit Program

Preparation: final code version (feature freeze), architecture documentation, threat model description, test cases. Without final code, audit is meaningless — changes after audit are not covered.

Automated analysis (days 1-2): Slither, Mythril, Echidna — collect automated findings, exclude false positives.

Manual analysis (days 3-12): systematic code review, attack modeling, invariant checking, business logic.

Testing (days 8-14, parallel): PoC exploits for found vulnerabilities, fork testing of interactions.

Report and remediation (days 14-20): detailed report with severity, PoC, recommendations. Team fixes, auditor verifies fixes.

Fix Review (3-5 days): verification that fixes don't introduce new vulnerabilities.

Protocol Type Code Volume Audit Timeline
Simple ERC-20 + vesting < 500 lines 1-2 weeks
DeFi protocol (lending/AMM) 1000-3000 lines 3-5 weeks
Complex protocol with proxy 3000-10000 lines 5-8 weeks
Cross-chain bridges any volume 6-12 weeks

What Audit Does Not Guarantee

Audit reduces risk but does not eliminate it completely. Auditors are people; they miss bugs. Most famous exploits: Euler Finance ($197M, 2023), Nomad Bridge ($190M, 2022), Wormhole ($320M, 2022) — all underwent audits.

Correct strategy: audit + bug bounty (Immunefi, HackerOne) + gradual rollout with TVL limits + monitoring (Forta, OpenZeppelin Defender).

Audit is necessary but not sufficient for security.