Hardhat

Optimize BlockSecOps for Hardhat projects. Hardhat is a popular Ethereum development environment with extensive plugin support. BlockSecOps fully supports...

Last updated: January 14, 2026

Hardhat Guide

Optimize BlockSecOps for Hardhat projects.

Overview

Hardhat is a popular Ethereum development environment with extensive plugin support. BlockSecOps fully supports Hardhat project configurations.


Project Structure

Standard Layout

project/
├── contracts/              # Contract sources
│   ├── Token.sol
│   └── Vault.sol
├── test/                   # Tests (JS/TS)
│   └── Token.test.js
├── scripts/                # Deployment scripts
│   └── deploy.js
├── node_modules/           # npm dependencies
│   └── @openzeppelin/
├── hardhat.config.js       # Configuration
└── package.json

What to Upload

Include:

  • contracts/ - All contract sources
  • node_modules/ - Required for dependencies
  • hardhat.config.js or hardhat.config.ts
  • package.json - For dependency versions

Optional:

  • test/ - Include for full analysis

Exclude:

  • artifacts/ - Build artifacts
  • cache/ - Hardhat cache
  • coverage/ - Coverage reports
  • typechain-types/ - Generated types

Configuration

hardhat.config.js

require("@nomicfoundation/hardhat-toolbox");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: {
    version: "0.8.20",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  },
  paths: {
    sources: "./contracts",
    tests: "./test",
    cache: "./cache",
    artifacts: "./artifacts"
  }
};

TypeScript Configuration

// hardhat.config.ts
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

const config: HardhatUserConfig = {
  solidity: {
    version: "0.8.20",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  }
};

export default config;

Multiple Compiler Versions

module.exports = {
  solidity: {
    compilers: [
      { version: "0.8.20" },
      { version: "0.7.6" },
      { version: "0.6.12" }
    ],
    overrides: {
      "contracts/legacy/OldContract.sol": {
        version: "0.6.12"
      }
    }
  }
};

Dependency Management

Installing Dependencies

# Install OpenZeppelin
npm install @openzeppelin/contracts

# Install specific version
npm install @openzeppelin/[email protected]

# Install Chainlink
npm install @chainlink/contracts

Common Dependencies

{
  "dependencies": {
    "@openzeppelin/contracts": "^4.9.0",
    "@openzeppelin/contracts-upgradeable": "^4.9.0",
    "@chainlink/contracts": "^0.6.0"
  },
  "devDependencies": {
    "hardhat": "^2.19.0",
    "@nomicfoundation/hardhat-toolbox": "^4.0.0"
  }
}

Import Resolution

Standard Imports

// npm package import
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

// Relative import
import "./interfaces/IToken.sol";

// Parent directory import
import "../libraries/SafeMath.sol";

Import Path Resolution

Hardhat resolves imports from:

  1. node_modules/ (npm packages)
  2. Relative to current file
  3. Custom paths in config

Creating Upload Archive

Including node_modules

node_modules must be included for dependency resolution:

# Create archive with dependencies
zip -r project.zip \
  contracts/ \
  node_modules/@openzeppelin/ \
  node_modules/@chainlink/ \
  hardhat.config.js \
  package.json

Selective node_modules

To reduce archive size, include only used packages:

# Include only specific packages
zip -r project.zip \
  contracts/ \
  node_modules/@openzeppelin/contracts/ \
  node_modules/@chainlink/contracts/ \
  hardhat.config.js

Using npx to Generate Flat Files

# Flatten a contract (removes import dependencies)
npx hardhat flatten contracts/Token.sol > Token.flat.sol

CI/CD Integration

GitHub Actions

name: Security Scan

on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Compile contracts
        run: npx hardhat compile

      - name: Create archive
        run: |
          zip -r project.zip \
            contracts/ \
            node_modules/@openzeppelin/ \
            hardhat.config.js \
            package.json

      - name: BlockSecOps Scan
        env:
          BLOCKSECOPS_API_KEY: ${{ secrets.BLOCKSECOPS_API_KEY }}
        run: |
          CONTRACT_ID=$(curl -s -X POST \
            "https://api.blocksecops.com/api/v1/contracts/upload" \
            -H "Authorization: Bearer $BLOCKSECOPS_API_KEY" \
            -F "[email protected]" | jq -r '.id')

          SCAN_ID=$(curl -s -X POST \
            "https://api.blocksecops.com/api/v1/scans" \
            -H "Authorization: Bearer $BLOCKSECOPS_API_KEY" \
            -H "Content-Type: application/json" \
            -d "{\"contract_id\": \"$CONTRACT_ID\", \"preset\": \"standard\"}" \
            | jq -r '.id')

          echo "Scan started: $SCAN_ID"

Hardhat Plugins

Supported Plugins

BlockSecOps works with common Hardhat plugins:

Plugin Support
@nomicfoundation/hardhat-toolbox Full
@openzeppelin/hardhat-upgrades Full
hardhat-deploy Full
hardhat-gas-reporter N/A (not needed for scanning)

Plugin Configuration

// hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");
require("@openzeppelin/hardhat-upgrades");

module.exports = {
  solidity: "0.8.20",
  // Plugins auto-configure
};

Upgradeable Contracts

OpenZeppelin Upgrades

// contracts/TokenV1.sol
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract TokenV1 is Initializable, ERC20Upgradeable {
    function initialize(string memory name, string memory symbol)
        public initializer
    {
        __ERC20_init(name, symbol);
    }
}

BlockSecOps detects and analyzes upgrade patterns for:

  • Storage layout issues
  • Initializer vulnerabilities
  • Proxy implementation issues

Troubleshooting

Compilation Errors

# Clean cache and recompile
npx hardhat clean
npx hardhat compile

# Check for errors
npx hardhat compile --force

Missing Dependencies

# Reinstall all dependencies
rm -rf node_modules
npm install

# Check specific package
npm ls @openzeppelin/contracts

Import Resolution Failures

  1. Verify package is installed:

    npm ls @openzeppelin/contracts
    
  2. Check import path matches package structure:

    ls node_modules/@openzeppelin/contracts/token/ERC20/
    
  3. Verify node_modules is included in upload

Version Conflicts

# Check for duplicate packages
npm ls

# Fix with specific version
npm install @openzeppelin/[email protected] --save-exact

Best Practices

Archive Creation Script

#!/bin/bash
# create-archive.sh

# Clean build
npx hardhat clean
npx hardhat compile

# Verify build succeeded
if [ $? -ne 0 ]; then
    echo "Compilation failed"
    exit 1
fi

# Create archive with minimal dependencies
zip -r project.zip \
  contracts/ \
  node_modules/@openzeppelin/contracts/ \
  node_modules/@chainlink/contracts/ \
  hardhat.config.js \
  package.json \
  package-lock.json

echo "Archive created: project.zip"
echo "Size: $(du -h project.zip | cut -f1)"

Reduce Archive Size

# Remove unnecessary files from node_modules
find node_modules -name "*.md" -delete
find node_modules -name "*.ts" -delete
find node_modules -name "test" -type d -exec rm -rf {} +

Example: Full Project Upload

#!/bin/bash

# 1. Install dependencies
npm ci

# 2. Compile to verify
npx hardhat compile

# 3. Create archive
zip -r project.zip \
  contracts/ \
  node_modules/@openzeppelin/ \
  hardhat.config.js \
  package.json

# 4. Upload
curl -X POST "https://api.blocksecops.com/api/v1/contracts/upload" \
  -H "Authorization: Bearer $BLOCKSECOPS_API_KEY" \
  -F "[email protected]"

Next Steps