An automated Twitter bot that monitors and tweets about Ethereum Name Service (ENS) domain sales, registrations, bids, and renewals with AI-generated market analysis.
- Real-time ENS Monitoring: Tracks sales, registrations, bids, and renewals for ENS domains
- AI-Powered Insights: Generates contextual market analysis using OpenAI GPT-5
- Twitter Integration: Automatically posts formatted tweets with generated images
- Web Dashboard: SIWE-authenticated admin interface for bot management
- Multi-Source Data: Aggregates data from Grails, OpenSea, Alchemy, and QuickNode
- Portfolio Analysis: Enriches transactions with buyer/seller portfolio data and trading patterns
- Club Detection: Identifies membership in ENS clubs (999 Club, 10k Club, etc.)
- Bidding Intelligence: Tracks bidding patterns and conviction signals
- Renewal Tracking: Monitors bulk renewals with per-tx aggregation and dynamic image generation
- GrailsApiService: Primary data source for ENS marketplace activity (aggregator)
- OpenAIService: Generates AI-powered market commentary
- TwitterService: Handles tweet posting and formatting
- AlchemyService: Provides portfolio and token balance data
- OpenSeaService: Fetches ENS holdings and metadata
- ENSSubgraphService: ENS subgraph powered by ENSNode for fast name resolution
- DatabaseService: PostgreSQL integration for state management
- QuickNodeSales/Registration/RenewalService: Webhook handlers for real-time events
- BidsProcessingService: Monitors and processes new bids
- AIReplyService: Generates contextual replies for transactions (sales, registrations, bids, renewals)
- Webhook Reception: QuickNode sends real-time ENS transaction events
- Event Processing: Services enrich data with portfolio, history, and metadata
- AI Analysis: OpenAI generates market insights from enriched context
- Tweet Generation: Formatted tweets with images are created
- Publishing: Automated posting to Twitter with rate limiting
- Node.js 18+
- PostgreSQL database
- Twitter API credentials (Premium+ for 1200 char replies)
- OpenAI API key (GPT-5-mini)
- QuickNode account with streaminging API
- Alchemy API key
- Ethereum RPC provider
# Clone repository
git clone <repository-url>
cd ens-market-bot
# Install dependencies
npm install
# Copy environment template
cp env.production.example .env
# Configure environment variables (see Configuration section)
nano .env
# Build TypeScript
npm run build
# Start application
npm startCreate a .env file with the following variables:
# Database (Required)
POSTGRES_URL=postgresql://user:password@host:5432/database
# Twitter API (Required)
TWITTER_API_KEY=your_twitter_api_key
TWITTER_API_SECRET=your_twitter_api_secret
TWITTER_ACCESS_TOKEN=your_twitter_access_token
TWITTER_ACCESS_TOKEN_SECRET=your_twitter_access_token_secret
TWITTER_CALLBACK_URL=https://your-domain.com/auth/twitter/callback
# OpenAI (Required)
OPENAI_API_KEY=your_openai_api_key
# QuickNode Webhooks (Required)
QUICKNODE_SECRET_SALES=your_quicknode_sales_secret
QUICKNODE_SECRET_REGISTRATIONS=your_quicknode_registration_secret
QUICKNODE_SECRET_RENEWALS=your_quicknode_renewals_secret
# Alchemy (Required - for portfolio data and price lookups)
ALCHEMY_API_KEY=your_alchemy_api_key
# SIWE Authentication (Required for dashboard)
ADMIN_WHITELIST=0xYourAddress1,0xYourAddress2
SESSION_SECRET=your_secure_random_session_secret
SIWE_DOMAIN=your-domain.com
# In-house ENS Subgraph (Optional - falls back to public endpoint)
ENS_SUBGRAPH_PRIMARY_URL=https://your-subgraph-endpoint.com/subgraph
# Grails API (Optional - aggregator for ENS bid ingestion across marketplaces)
# Defaults to https://api.grails.app/api/v1/activity if unset.
# Set to empty string to explicitly disable bid ingestion entirely.
GRAILS_API_URL=https://api.grails.app/api/v1/activity
# Timezone (Recommended)
TZ=UTCThe bot ingests ENS bids from the Grails API, which aggregates offers across OpenSea, Blur, and other marketplaces. By default, GRAILS_API_URL defaults to the production endpoint (https://api.grails.app/api/v1/activity) so bid ingestion works out of the box. To disable bid ingestion entirely (e.g., for sales/registrations-only deployments), explicitly set GRAILS_API_URL= (empty string). The startup log will warn loudly when this is the case.
The bot requires PostgreSQL with the following tables (auto-created on first run):
sales: ENS sales transactionsregistrations: ENS registrationsbids: ENS bid eventsrenewals: ENS renewal events (one row per name, aggregated per-tx for tweets)ai_replies: AI-generated contextual replies (sales, registrations, bids, renewals)rate_limits: Twitter API rate limiting statescheduler_state: Cron job state managementapi_toggle: Feature flag controlsessions: Web dashboard sessions
# Production
npm run build && npm start
# Development with auto-reload
npm run devAccess the admin dashboard at http://localhost:3000 (or your deployed URL):
- Connect wallet (MetaMask)
- Sign SIWE message
- Manage bot settings:
- Enable/disable automated tweeting
- Configure scheduler
- Monitor recent transactions
- View API health status
POST /webhook/salesv2: QuickNode sales webhookPOST /webhook/quicknode-registrations: QuickNode registrations webhookPOST /webhook/quicknode-renewals: QuickNode renewals webhookGET /health: System health checkGET /api/database/sales: Recent sales (authenticated)GET /api/database/registrations: Recent registrations (authenticated)GET /api/database/bids: Recent bids (authenticated)GET /api/database/renewals: Recent renewals grouped by tx (authenticated)GET /api/renewal/tweet/generate/:txHash: Preview renewal tweet (authenticated)POST /api/renewal/tweet/send/:txHash: Post renewal tweet (authenticated)
# Lint code
npm run lint
# Format code
npm run format
# Build TypeScript
npm run build
# Run in development mode
npm run devThe bot uses a sophisticated AI pipeline to generate insights:
- Name Research: Web search for context about the ENS name
- Data Enrichment: Fetch buyer/seller portfolio, trading history, holdings
- Pattern Detection: Identify collecting patterns, bidding behavior, market signals
- Context Building: Assemble ~200k token LLM context with all relevant data
- Generation: OpenAI GPT-5-mini generates 800-1000 character analysis
- Monitors bids across ENS Registry and Name Wrapper contracts
- Detects bidding patterns (spray and pray, targeted collecting, etc.)
- Analyzes wallet commitment and conviction signals
- Limits bid history to last 500 per user to prevent token overflow
- Fetches multi-chain portfolio data via Alchemy
- Tracks total portfolio value, major holdings, and cross-chain presence
- Handles portfolio timing correctly (pre-bid vs post-purchase)
- Uses portfolio context for wash trading detection and conviction signals
Additional technical documentation is available in the docs/ folder:
- QuickNode Sales Stream Filter - Seaport OrderFulfilled event filter for ENS sales
- QuickNode Registration Stream Filter - NameRegistered event filter for ENS registrations
- QuickNode Renewal Stream Filter - NameRenewed event filter for ENS renewals (bulk-renewal aware)
The bot implements intelligent rate limiting:
- Twitter API: Respects Twitter's rate limits with exponential backoff
- External APIs: Rate-limited to prevent quota exhaustion
- Webhook processing: Queue-based with throttling
The bot includes comprehensive logging:
- Transaction processing events
- API call success/failure
- Tweet posting status
- AI generation metrics
- Portfolio fetch timing
- Error tracking with context
- SIWE Authentication: Sign-In with Ethereum for dashboard access
- Webhook Verification: HMAC signature validation for QuickNode webhooks
- Admin Whitelist: Address-based access control
- Rate Limiting: Request throttling on all endpoints
- Environment Secrets: All credentials stored in environment variables
- Helmet.js: HTTP security headers
- CORS Protection: Configurable origin restrictions
Contributions are welcome! Please ensure:
- Code follows existing style (ESLint + Prettier)
- TypeScript types are properly defined
- Environment variables are documented
- Error handling is comprehensive
MIT License - see LICENSE file for details
For issues, questions, or feature requests, please open a GitHub issue.
- Built with TypeScript, Express, and OpenAI
- Uses Grails, OpenSea, Alchemy, and QuickNode APIs
- ENS infrastructure by ENS Labs
- Web3 libraries by viem and ethers