Development

Development Environment Setup

Prerequisites

  • Node.js 18+ and npm
  • Git
  • SQLite3
  • Text editor (VSCode recommended)
  • Telegram account for testing

Initial Setup

# Clone repository
git clone https://github.com/your-repo/somnia-validator-bot.git
cd somnia-validator-bot

# Install dependencies
npm install

# Copy environment template
cp .env.example .env

# Configure environment variables
nano .env

Environment Configuration

# Bot Configuration
BOT_TOKEN=your_bot_token_from_botfather
TELEGRAM_ADMIN_IDS=your_telegram_id

# Blockchain Configuration
SOMNIA_RPC_URL=https://dream.somnia.network
NODE_COMMITTEE_CONTRACT_ADDRESS=0x...
SOMNIA_STAKING_CONTRACT_ADDRESS=0x...

# Development Settings
NODE_ENV=development
LOG_LEVEL=debug

Development Workflow

Code Structure

src/
├── bot.ts              # Main bot entry point
├── config/             # Configuration management
├── commands/           # Command handlers
├── services/           # Business logic
├── utils/              # Utility functions
├── types/              # TypeScript types
└── locales/            # Translations

Running in Development

# Run with hot reload
npm run dev

# Run with debugger
npm run debug

# Check types
npm run type-check

# Lint code
npm run lint

# Format code
npm run format

VSCode Configuration

.vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Bot",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/src/bot.ts",
      "preLaunchTask": "tsc: build - tsconfig.json",
      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
      "env": {
        "NODE_ENV": "development"
      }
    }
  ]
}

Adding Features

Creating a New Command

  1. Create command handler:
// src/commands/mycommand.ts
import { Context } from 'telegraf';

export async function myCommandHandler(ctx: Context) {
  const userId = ctx.from?.id;
  const userLang = await getUserLanguage(userId);
  
  await ctx.reply(t('mycommand.response', userLang));
}
  1. Register in bot:
// src/bot.ts
import { myCommandHandler } from './commands/mycommand';

bot.command('mycommand', myCommandHandler);
  1. Add translations:
// locales/en.json
{
  "mycommand": {
    "response": "This is my new command!"
  }
}

Adding Database Tables

  1. Create migration:
// src/migrations/add_my_table.ts
export async function up(db: Database) {
  await db.run(`
    CREATE TABLE my_table (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      data TEXT NOT NULL,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    )
  `);
}
  1. Update types:
// src/types/database.ts
export interface MyTableRow {
  id: number;
  data: string;
  created_at: Date;
}
  1. Add database functions:
// src/database.ts
export async function insertMyData(data: string): Promise<void> {
  return new Promise((resolve, reject) => {
    db.run(
      'INSERT INTO my_table (data) VALUES (?)',
      [data],
      (err) => err ? reject(err) : resolve()
    );
  });
}

Testing During Development

Manual Testing

  1. Create test bot:
    • Talk to @BotFather
    • Create new bot for testing
    • Get test token
  2. Test database:
# Create test database
cp somnia_validator_bot.db test.db

# Use test database
DATABASE_PATH=./test.db npm run dev
  1. Test commands:
# Use test admin ID
TELEGRAM_ADMIN_IDS=your_test_id npm run dev

Automated Testing

# Run all tests
npm test

# Run specific test
npm test -- database.test.ts

# Run with coverage
npm run test:coverage

# Watch mode
npm run test:watch

Debugging

Debug Logging

import { logger } from './utils/logger';

// Add debug logs
logger.debug('Processing validator', { 
  address: validatorAddress,
  state: currentState 
});

// Conditional debug
if (config.app.debug) {
  console.log('Detailed debug info:', data);
}

Common Issues

  1. Bot not responding:
    • Check BOT_TOKEN is correct
    • Verify bot is not running elsewhere
    • Check network connectivity
  2. Database locked:
    • Ensure only one instance running
    • Check file permissions
    • Use WAL mode
  3. RPC errors:
    • Verify RPC URL is accessible
    • Check rate limits
    • Monitor network latency

Code Style

TypeScript Guidelines

// Use explicit types
function processData(data: ValidatorData): ProcessedResult {
  // ...
}

// Use interfaces for objects
interface UserPreferences {
  language: string;
  notifications: boolean;
}

// Use enums for constants
enum CommandType {
  User = 'user',
  Admin = 'admin'
}

Error Handling

// Always handle errors
try {
  const result = await riskyOperation();
  return result;
} catch (error) {
  logger.error('Operation failed', error);
  throw new CustomError('Operation failed', error);
}

// Use custom errors
class ValidationError extends Error {
  constructor(message: string, public field: string) {
    super(message);
    this.name = 'ValidationError';
  }
}

Performance Considerations

Development Profiling

// Time operations
console.time('fetchValidatorData');
const data = await fetchValidatorData(address);
console.timeEnd('fetchValidatorData');

// Memory profiling
if (process.env.NODE_ENV === 'development') {
  setInterval(() => {
    const usage = process.memoryUsage();
    console.log('Memory:', usage);
  }, 10000);
}

Development Tools

  • nodemon: Auto-restart on changes
  • ts-node: Run TypeScript directly
  • source-map-support: Better stack traces
  • dotenv: Environment management

Git Workflow

Branch Strategy

# Feature branch
git checkout -b feature/new-command

# Bug fix
git checkout -b fix/subscription-error

# Hotfix
git checkout -b hotfix/critical-bug

Commit Messages

# Format: type(scope): description

git commit -m "feat(commands): add validator stats command"
git commit -m "fix(database): resolve connection timeout"
git commit -m "docs(readme): update installation instructions"
git commit -m "refactor(monitoring): optimize batch processing"

Pre-commit Hooks

.husky/pre-commit:

#!/bin/sh
npm run lint
npm run type-check
npm test