Introduction

Project Leviathan is a deterministic, production-grade code migration tool for Web3 projects. It transforms legacy codebases from Brownie, Ethers v5, and Web3.js v1 to modern frameworks in seconds—not hours.

Philosophy: Zero false positives. We trace declarations back to the source and only transform what we can verify.

Why Leviathan?

Architecture

Leviathan consists of three core modules orchestrated by a workflow engine:

  1. Web3.js v4 Evolution — JavaScript/TypeScript migrations
  2. Ethers v6 Bridge — BigNumber to BigInt transformations
  3. Brownie to Ape — Python smart contract migrations

Quick Start

Get up and running with Leviathan in minutes.

Prerequisites

Installation

# Clone the repository
git clone https://github.com/your-org/project-leviathan.git
cd project-leviathan

# Install dependencies
npm install

# Install the codemod CLI globally
npm install -g codemod

Run a Migration

# Run the smoke test on a sample project
npm run smoke-test

# Validate JavaScript files
npm run validate:js

# Validate Python files
npm run validate:py

Codemod CLI

The Codemod CLI is the core engine behind Leviathan. It uses AST-grep for deterministic pattern matching and transformation.

Commands

# Run a single codemod
codemod run <module-path>

# Run a workflow
codemod workflow run -w workflow.yaml

# Publish a module to the registry
codemod publish .

Options

Module Structure

modules/
├── web3js-v4-evolution/
│   ├── codemod.yaml        # Module manifest
│   ├── workflow.yaml       # Local workflow
│   ├── scripts/
│   │   └── codemod.ts      # Transformation script
│   ├── rules/
│   │   └── config.yml      # AST-grep rules
│   └── tests/
│       ├── test.ts
│       └── fixtures/
│           ├── input.js
│           └── expected.js

Writing a Codemod

Codemods are written in TypeScript and use the AST-grep API:

import { Codemod, File } from '@codemod/core';

export const codemod: Codemod = {
  name: 'web3-migration',
  description: 'Migrate Web3.js v1 to v4',
  
  run(files: File[]) {
    return files.map(file => {
      return file.ast.update((node: any) => {
        // Transform: require('web3') -> import { Web3 } from 'web3'
        if (node.type === 'CallExpression' &&
            node.callee.name === 'require' &&
            node.arguments[0]?.value === 'web3') {
          return {
            type: 'ImportDeclaration',
            specifiers: [{
              type: 'ImportSpecifier',
              imported: { type: 'Identifier', name: 'Web3' }
            }],
            source: { type: 'Literal', value: 'web3' }
          };
        }
        return node;
      });
    });
  }
};

Pro Tip: Always include test fixtures (input and expected output) to verify your codemod works correctly.

Workflow Engine

The workflow engine orchestrates multiple codemods in sequence with dependency resolution.

Workflow YAML

version: "1"
name: "Leviathan Migration"

nodes:
  # Phase 1: Web3.js Migration
  - id: web3js-migration
    name: Web3.js v4 Evolution
    type: automatic
    steps:
      - js-ast-grep:
          js_file: "modules/web3js-v4-evolution/scripts/codemod.ts"
          language: "javascript"

  # Validation after each phase
  - id: validate-web3
    name: Validate Web3 Migration
    type: automatic
    depends_on: [web3js-migration]
    steps:
      - run: "npm run validate:js"

  # Phase 2: Ethers v6 (runs after validation)
  - id: ethers-v6-migration
    name: Ethers.js v6 Bridge
    type: automatic
    depends_on: [validate-web3]
    steps:
      - js-ast-grep:
          js_file: "modules/ethers-v6-bridge/scripts/codemod.ts"

Node Types

Core Modules

1. Web3.js v4 Evolution

Migrates legacy Web3.js v1 patterns to modern v4 syntax.

2. Ethers v6 Bridge

Transforms Ethers.js v5 BigNumber methods to native BigInt operators.

3. Brownie to Ape

Converts Python smart contract projects from Brownie to Ape Framework.

Configuration

codemod.yaml

schema_version: "1.0"
name: "web3js-v4-evolution"
version: "0.1.0"
description: "Migrate Web3.js v1 legacy patterns to v4"
author: "Skywalkingzulu1"
license: "Apache-2.0"
workflow: "workflow.yaml"

targets:
  languages: ["typescript", "javascript"]
  keywords: ["web3", "blockchain", "ethereum"]

AST-grep Rules (Python)

rules:
  - id: brownie-imports
    pattern: from brownie import $IMPORTS
    message: "Migrate Brownie imports to Ape"
    transform:
      - from: brownie
        to: ape
      - map:
          accounts: accounts
          network: network
          project: project

Validation

Every transformation is validated to ensure syntax integrity.

JavaScript Validation

// validate.js
function validateJs() {
  const { execSync } = require('child_process');
  try {
    execSync('node --check ' + file, { stdio: 'pipe' });
    return true;
  } catch (e) {
    console.error('Syntax error in:', file);
    return false;
  }
}

Python Validation

# validate.py
import py_compile
import sys

def validate_python(file):
    try:
        py_compile.compile(file, doraise=True)
        return True
    except py_compile.PyCompileError as e:
        print(f"Syntax error in {file}: {e}")
        return False

Important: The workflow stops if validation fails, ensuring no broken code reaches your repository.

Troubleshooting

Common Issues

1. "Cannot find module"

Ensure all dependencies are installed:

npm install
cd modules/<module-name> && npm install

2. Validation failures

Check that your code compiles before running migrations. Leviathan assumes syntactically valid input.

3. Partial transformations

If some patterns aren't transformed, check the AST-grep rules match your code structure. Use --dry-run to preview.

4. Python module not found

Ensure Python 3.10+ is installed and the Ape Framework:

pip install ape-framework

Getting Help

Command Reference

Global Options

-v, --verbose               Verbose output
    --disable-analytics         Disable telemetry
-h, --help                    Print help

codemod run

codemod run <PACKAGE> [OPTIONS]

Arguments:
  <PACKAGE>        Package name with optional version (e.g., @org/package@1.0.0)

Options:
  -t, --target <TARGET_PATH>    Target path to run the codemod on
      --dry-run                  Preview without applying changes
      --no-interactive           Run without prompts
      --allow-dirty              Allow uncommitted changes
      --param <KEY=VALUE>        Pass parameters to the codemod
      --registry <URL>           Custom registry URL
      --force                    Force re-download even if cached

codemod jssg run

codemod jssg run <JS_FILE> [OPTIONS]

Arguments:
  <JS_FILE>       Path to the JavaScript transformation file

Options:
  -t, --target <TARGET_PATH>    Target directory to process
      --language <LANG>          Language: javascript, typescript, tsx
      --dry-run                  Preview without applying
      --no-interactive           Run without prompts
      --allow-dirty              Allow uncommitted changes
      --semantic-workspace <PATH> Enable cross-file analysis
      --max-threads <N>          Max concurrent threads (default: CPU cores)

codemod workflow

codemod workflow run -w <WORKFLOW_FILE> [OPTIONS]

Options:
  -w, --workflow <FILE>    Path to workflow.yaml
      --no-interactive      Run all steps without prompts
      --allow-dirty         Allow uncommitted changes
      --dry-run             Preview entire workflow

Tip: Use --dry-run with --verbose to see exactly what will be changed before applying.

Environment Variables

Required for Ethers/BigInt Migrations

ETHEREUM_RPC_URL=
  Ethereum JSON-RPC endpoint (e.g., https://eth-mainnet.alchemyapi.io)
ETHEREUM_CHAIN_ID=1    Chain ID for type inference (1=mainnet, 5=goerli, etc.)

Required for Alchemy Web3

REACT_APP_ALCHEMY_KEY=
  Alchemy API key for Web3.js migrations
ALCHEMY_API_KEY=           Alternative env var for Alchemy SDK

Optional Configuration

LOG_LEVEL=info             Logging verbosity: debug, info, warn, error
CODEMOD_REGISTRY=https://registry.npmjs.org
NODE_ENV=production         Enables stricter validation

Python (Brownie to Ape)

APE_ETHEREUM_RPC=          Ethereum RPC URL for Ape test networks
APE_ETHEREUM_CHAIN_ID=     Chain ID for network configuration
WEB3_INFURA_PROJECT_ID=    Infura project ID (alternative to Alchemy)

Security: Never commit API keys to version control. Use .env.example files and .gitignore.

Safety & Limitations

What Leviathan CAN Transform

What Leviathan CANNOT Transform

Known Edge Cases

Zero False Positives: If Leviathan cannot verify the transformation is safe, it skips the change and logs a warning. Review logs carefully.

CI/CD Integration

Automate Leviathan migrations in your continuous integration pipeline.

GitHub Actions

name: Leviathan Migration

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          
      - name: Install dependencies
        run: npm install
        
      - name: Run Leviathan Migration
        run: npm run smoke-test
        env:
          ALCHEMY_API_KEY: ${{ secrets.ALCHEMY_API_KEY }}
          
      - name: Validate JS
        run: npm run validate:js
        
      - name: Commit Changes
        uses: stefanzweifel/git-auto-commit-action@v5
        with:
          commit_message: "chore: Leviathan migration"
          file_pattern: "*.js *.ts"

GitLab CI

leviathan-migration:
  image: node:20
  script:
    - npm install
    - npm run smoke-test
    - npm run validate:js
  only:
    - main
  artifacts:
    paths:
      - modified/
    when: always

Jenkins Pipeline

pipeline {
    agent any
    environment {
        ALCHEMY_API_KEY = credentials('alchemy-api-key')
    }
    stages {
        stage('Install') {
            steps {
                sh 'npm install'
            }
        }
        stage('Migrate') {
            steps {
                sh 'npm run smoke-test'
            }
        }
        stage('Validate') {
            steps {
                sh 'npm run validate:js'
            }
        }
        stage('Commit') {
            steps {
                sh 'git add -A && git commit -m "chore: Leviathan migration"'
            }
        }
    }
}

Pre-commit Hooks

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/your-org/project-leviathan
    rev: v1.0.0
    hooks:
      - id: leviathan-migration
        args: ['--target', '.']
        stages: [pre-commit]
        language: system

Environment-Specific Migrations

# Run only Web3.js migration
npx codemod jssg run modules/web3js-v4-evolution/scripts/codemod.ts \
  --language javascript --target ./src --no-interactive

# Run only Ethers migration  
npx codemod jssg run modules/ethers-v6-bridge/scripts/codemod.ts \
  --language javascript --target ./src --no-interactive

# Run with environment awareness
CODEMOD_TARGET=production npx codemod workflow run -w workflow.yaml \
  --no-interactive --allow-dirty

Best Practice: Always run with --dry-run first in CI to preview changes before applying.