Security·7 min का पठन·Solingo द्वारा

Smart Contract Audit Checklist — Deployment से पहले 20 चीज़ें Check करें

Comprehensive pre-deployment checklist covering access control, reentrancy, overflow protection, input validation, gas optimization, events और upgradability।

# Smart Contract Audit Checklist — Deployment से पहले 20 चीज़ें Check करें

Smart contract को mainnet पर deploy करना permanent है। कोई "undo" button नहीं, कोई hotfixes नहीं, कोई patches नहीं। एक vulnerability millions drain कर सकती है।

यह checklist 20 critical security checks को cover करता है जो हर developer को deployment से पहले perform करने चाहिए। चाहे आप self-auditing कर रहे हों या professional audit के लिए prepare कर रहे हों, ये points आपको dangerous issues early catch करने में help करेंगे।

Access Control (1-3)

1. ✅ सभी Privileged Functions Protected हैं

Critical state modify करने वाले हर function में access control होना चाहिए।

Check:

// BAD: कोई भी withdraw कर सकता है

function withdraw(uint256 amount) external {

payable(msg.sender).transfer(amount);

}

// GOOD: केवल owner withdraw कर सकता है

function withdraw(uint256 amount) external onlyOwner {

payable(msg.sender).transfer(amount);

}

Tools: Slither --detect unprotected-upgrade के साथ unprotected functions detect करता है

2. ✅ Constructor में Owner Correctly Set है

Ownership properly initialize किया गया है ensure करें।

// BAD: Owner zero address पर default होता है

address public owner;

// GOOD: Constructor में owner set होता है

constructor() {

owner = msg.sender;

}

Test: Deployment के बाद verify करें कि owner correctly set है।

3. ✅ Two-Step Ownership Transfer

Accidental ownership loss prevent करें।

// BAD: Single-step, irreversible

function transferOwnership(address newOwner) external onlyOwner {

owner = newOwner; // Typo = permanent loss

}

// GOOD: Two-step process

address public pendingOwner;

function transferOwnership(address newOwner) external onlyOwner {

pendingOwner = newOwner;

}

function acceptOwnership() external {

require(msg.sender == pendingOwner);

owner = pendingOwner;

pendingOwner = address(0);

}

Use: OpenZeppelin का Ownable2Step

Reentrancy (4-5)

4. ✅ Checks-Effects-Interactions Pattern

External calls से पहले state updates।

// BAD: State update से पहले external call

function withdraw() external {

uint256 amount = balances[msg.sender];

(bool success,) = msg.sender.call{value: amount}("");

require(success);

balances[msg.sender] = 0; // बहुत LATE

}

// GOOD: पहले state update

function withdraw() external {

uint256 amount = balances[msg.sender];

balances[msg.sender] = 0; // Call से BEFORE update

(bool success,) = msg.sender.call{value: amount}("");

require(success);

}

5. ✅ External Calls पर ReentrancyGuard

Defense in depth।

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Safe is ReentrancyGuard {

function withdraw() external nonReentrant {

// Protected

}

}

Test: Protection verify करने के लिए reentrancy attack tests लिखें।

Integer Operations (6-7)

6. ✅ Unchecked Math नहीं (Unless Intentional)

Solidity 0.8+ में built-in overflow protection है। बिना reason के इसे disable न करें।

// BAD: बिना justification के unchecked

unchecked {

balance += amount; // Overflow हो सकता है

}

// GOOD: केवल safe होने पर unchecked उपयोग करें

unchecked {

// Loop counter realistically overflow नहीं होगा

for (uint256 i = 0; i < items.length; ++i) {

// ...

}

}

7. ✅ Multiplication से पहले Division

Rounding errors minimize करें।

// BAD: पहले division (precision खोता है)

uint256 result = (value / 100) * 25; // value का 0.25%

// GOOD: पहले multiplication

uint256 result = (value * 25) / 100;

Input Validation (8-10)

8. ✅ सभी Inputs Validated हैं

User input पर कभी trust न करें।

function setFee(uint256 _fee) external onlyOwner {

require(_fee <= 1000, "Fee too high"); // Max 10%

fee = _fee;

}

function transfer(address to, uint256 amount) external {

require(to != address(0), "Invalid address");

require(amount > 0, "Invalid amount");

// ...

}

9. ✅ Array Length Checks

Out-of-gas errors prevent करें।

function batchTransfer(address[] calldata recipients, uint256 amount) external {

require(recipients.length <= 100, "Too many recipients");

for (uint256 i = 0; i < recipients.length; i++) {

_transfer(msg.sender, recipients[i], amount);

}

}

10. ✅ Zero Address Checks

Accidentally tokens/ETH burn करना prevent करें।

function setTreasury(address _treasury) external onlyOwner {

require(_treasury != address(0), "Zero address");

treasury = _treasury;

}

Gas Optimization (11-13)

11. ✅ Storage Access Minimized है

Storage reads को memory में cache करें।

// BAD: Multiple storage reads

function calculateReward() external view returns (uint256) {

return userBalance[msg.sender] * rewardRate * stakingPeriod / 1e18;

// हर variable read storage से 2100 gas cost करता है

}

// GOOD: Memory में cache

function calculateReward() external view returns (uint256) {

uint256 balance = userBalance[msg.sender]; // One storage read

uint256 rate = rewardRate;

uint256 period = stakingPeriod;

return balance * rate * period / 1e18;

}

12. ✅ Loop Gas Limits Considered हैं

Unbounded loops gas से बाहर हो सकते हैं।

// BAD: Unbounded loop

function distributeRewards() external {

for (uint256 i = 0; i < users.length; i++) {

// अगर users.length = 10000, यह fail होगा

_transfer(users[i], rewardAmount);

}

}

// GOOD: Batch processing

function distributeRewards(uint256 start, uint256 end) external {

require(end <= users.length);

require(end - start <= 100, "Batch too large");

for (uint256 i = start; i < end; i++) {

_transfer(users[i], rewardAmount);

}

}

13. ✅ Efficient Data Types

Appropriate sizes उपयोग करें।

// BAD: Wasteful storage

struct User {

uint256 id; // uint32 हो सकता है

uint256 timestamp; // uint32 हो सकता है

bool active; // 1 byte लेकिन full slot लेता है

}

// GOOD: Packed storage

struct User {

uint32 id; // 4 bytes

uint32 timestamp; // 4 bytes

bool active; // 1 byte

// सभी एक 32-byte slot में fit

}

Events (14-15)

14. ✅ Critical Actions Events Emit करते हैं

Off-chain tracking के लिए essential।

event Transfer(address indexed from, address indexed to, uint256 amount);

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

event Paused(address account);

function transfer(address to, uint256 amount) external {

// ...

emit Transfer(msg.sender, to, amount);

}

15. ✅ Filtering के लिए Indexed Parameters

हर event में up to 3 indexed parameters।

// GOOD: Key fields indexed

event Deposit(

address indexed user,

address indexed token,

uint256 amount,

uint256 timestamp

);

External Interactions (16-17)

16. ✅ External Calls Safely Handled हैं

हमेशा return values check करें।

// BAD: Return value ignore करना

token.transfer(recipient, amount);

// GOOD: Return value check करें

bool success = token.transfer(recipient, amount);

require(success, "Transfer failed");

// BETTER: SafeERC20 उपयोग करें

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

using SafeERC20 for IERC20;

token.safeTransfer(recipient, amount); // Failure पर reverts

17. ✅ msg.sender Used है (tx.origin नहीं)

इस पर हमारा dedicated article देखें।

// BAD: Phishing vulnerable

require(tx.origin == owner);

// GOOD: Secure

require(msg.sender == owner);

Upgradability (18-19)

18. ✅ Storage Layout Preserved है (Upgradeable Contracts)

Upgrades में variables rearrange न करें।

// V1

contract TokenV1 {

address public owner;

uint256 public totalSupply;

}

// BAD V2: Inserted variable storage break करता है

contract TokenV2 {

address public owner;

uint256 public newVariable; // totalSupply location BREAKS करता है

uint256 public totalSupply;

}

// GOOD V2: केवल append

contract TokenV2 {

address public owner;

uint256 public totalSupply;

uint256 public newVariable; // End पर appended

}

19. ✅ Proxies के लिए Initialization (Constructor नहीं)

Proxies constructors execute नहीं करते।

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract TokenUpgradeable is Initializable {

address public owner;

// BAD: Constructor run नहीं होगा

constructor() {

owner = msg.sender;

}

// GOOD: Initialize function

function initialize() public initializer {

owner = msg.sender;

}

}

Testing (20)

20. ✅ Comprehensive Test Coverage

100% line coverage का aim करें, लेकिन साथ ही test करें:

Unit Tests:

function testOwnerCanWithdraw() public {

vm.prank(owner);

contract.withdraw(100);

assertEq(owner.balance, 100);

}

Negative Tests:

function testNonOwnerCannotWithdraw() public {

vm.prank(user);

vm.expectRevert("Not owner");

contract.withdraw(100);

}

Edge Cases:

function testWithdrawZero() public {

vm.prank(owner);

vm.expectRevert("Amount must be > 0");

contract.withdraw(0);

}

Fuzzing:

function testWithdrawFuzz(uint256 amount) public {

vm.assume(amount > 0 && amount <= address(contract).balance);

vm.prank(owner);

contract.withdraw(amount);

}

Tools to Run

Deployment से पहले, ये automated tools run करें:

# Static analysis

slither .

# Formal verification (अगर applicable हो)

certora-cli

# Test coverage

forge coverage

# Gas optimization

forge test --gas-report

Professional Audit

यह checklist common issues catch करता है, लेकिन professional audits high-value contracts के लिए irreplaceable हैं

कब audit कराएँ:

  • >$100k TVL manage कर रहे हों
  • Complex DeFi logic (DEX, lending, derivatives)
  • Upgradeable contracts
  • Multi-signature या DAO governance
  • किसी भी public protocol की mainnet launch से पहले

Top audit firms:

  • Trail of Bits
  • OpenZeppelin
  • ConsenSys Diligence
  • Certora
  • ChainSecurity

Final Checklist

Mainnet पर deploy करने से पहले:

✅ इस article के सभी 20 points addressed

✅ कोई high/medium issues नहीं के साथ Slither run

✅ 100% test coverage achieved

✅ Fuzzing tests passed

✅ Gas optimizations applied

✅ Professional audit completed (अगर high-value)

✅ Testnet पर deployment tested

✅ Emergency pause mechanism in place

✅ Bug bounty program prepared

✅ Documentation complete

Conclusion

Security एक checkbox नहीं है — यह एक mindset है। यह checklist एक solid foundation provide करता है, लेकिन secure रहने के लिए चाहिए:

  • Continuous learning (attacks evolve करते हैं)
  • Conservative coding (simplicity > cleverness)
  • Defense in depth (multiple protections)
  • Humility (assume करें कि आपने कुछ miss किया)

Stakes real हैं। एक single vulnerability millions cost कर सकती है। Thoroughly audit करने के लिए time लें।

Solingo पर secure development practice करें — हमारे platform में automated security checks, real-world vulnerability simulations, और इस checklist की सभी items के लिए step-by-step remediation guides शामिल हैं।

Practice में लगाने के लिए तैयार हैं?

Solingo पर interactive exercises के साथ इन concepts को apply करें।

मुफ्त में शुरू करें