Skip to content

Arcuity/opensea-blur

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

70 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Base 721C Arbitrage Bot

A policy-aware, risk-bounded NFT arbitrage system that buys the lowest listing and sells into the best collection offer on OpenSea (Base), using private transactions and survival-weighted execution to minimize inventory risk.

Features

  • Risk-First Design: Multi-layered protection with survival probability gating, daily drawdown caps, and per-trade loss limits
  • Private Transactions: Uses Alchemy's private transaction endpoint to minimize MEV exposure
  • Adaptive Scanning: Scan frequency adjusts based on market volatility (survival λ)
  • Bounded Failover: Automatically tries alternative bids if primary sell fails
  • 721C Compliant: Respects creator royalties and uses approved conduits
  • Comprehensive Observability: Hourly Slack reports, persistent state tracking, detailed skip reasons

Architecture

src/
├── index.ts                 # Main entry point
├── worker.ts                # Main worker loop with adaptive scanning
├── config.ts                # Configuration validation
├── types.ts                 # TypeScript type definitions
├── feeds/
│   ├── opensea.ts          # OpenSea API client
│   └── reservoir.ts        # Reservoir API client (discovery + prices)
├── strategy/
│   ├── collectionOfferArb.ts  # Arbitrage strategy logic
│   ├── survival.ts         # Survival probability model (λ calculation)
│   └── risk.ts             # Drawdown tracking & risk management
├── execution/
│   ├── exec.ts             # Trade execution with failover
│   └── approval.ts         # ERC-721 approval management
├── state/
│   └── manager.ts          # Persistent state (trades, PnL, approvals)
├── report/
│   └── hourly.ts           # Slack reporting with blocks
└── utils/
    └── logger.ts           # Structured logging

Quick Start

Prerequisites

  • Node.js 20+
  • An Alchemy account (Base RPC + private transactions)
  • OpenSea API key
  • Slack webhook URL
  • A dedicated wallet with ETH on Base

Installation

# Clone the repository
git clone <repo-url>
cd base-721c-arbitrage-bot

# Install dependencies
npm install

# Copy and configure environment
cp .env.example .env
# Edit .env with your credentials

Configuration

Key environment variables (see .env.example for full list):

# Required
RPC_URL=https://base-mainnet.g.alchemy.com/v2/YOUR_KEY
PRIVATE_KEY=your_wallet_private_key
OPENSEA_API_KEY=your_opensea_key
SLACK_WEBHOOK_URL=your_slack_webhook
ALCHEMY_API_KEY=your_alchemy_key

# Risk parameters
MIN_PROFIT_USD=10                    # Minimum profit per trade
MAX_DAILY_DRAWDOWN_ETH=0.2          # Halt if daily loss exceeds this
MAX_SINGLE_TRADE_LOSS_ETH=0.05      # Max acceptable loss per trade

# Collection discovery
SLUGS=                               # Leave empty for auto-discovery
MIN_DAILY_VOLUME_USD=10000          # Minimum 24h volume filter
MAX_COLLECTIONS=20                   # Max collections to monitor

Running Locally

# Development mode
npm run dev

# Production build
npm run build
npm start

Deploying to Render

  1. Push code to GitHub
  2. Connect repository to Render
  3. Create a new Worker service
  4. Set environment variables in Render UI (secrets)
  5. Add persistent disk: /var/data/state (1GB)
  6. Deploy

The render.yaml file contains the full deployment configuration.

How It Works

Scan Loop

  1. Discovery: Auto-discover Base collections via Reservoir (or use manual slugs)
  2. Quote Ingestion: Fetch lowest listing + best collection offer from OpenSea
  3. Analysis: Calculate fees, royalties, gas, and net profit
  4. Survival Check: Gate trades with pSurvive ≥ 0.85 (configurable)
  5. Risk Check: Verify drawdown and single-trade loss limits
  6. Execution: Buy via private tx → Sell with failover to top-N bids
  7. Reporting: Log trade, update PnL, send hourly Slack summaries

Survival Model

The bot tracks bid vanish events in a 15-minute rolling window to calculate arrival rate λ:

pSurvive = exp(-λ × executionTime)
  • Cold start (first 30 min): Uses pessimistic prior λ = 0.08
  • Warm: Exponentially-weighted average of recent vanish events
  • Trades gated at pSurvive ≥ 0.85 (default)

Failover Logic

If primary sell fails:

  1. Fetch top N collection bids (default: 3)
  2. For each bid:
    • Rebuild fulfillment data
    • Estimate gas dynamically
    • Check if net profit ≥ -MAX_SINGLE_TRADE_LOSS_ETH
  3. Accept first successful sell within timeout (30s default)
  4. Alert operator if inventory stuck after exhausting all options

State Management

All state is persisted to disk for restart safety:

state/
├── trades.csv              # All executed trades
├── pnl-YYYY-MM-DD.json    # Daily PnL summaries
└── approvals.json         # ERC-721 approval cache

Monitoring & Alerts

Hourly Slack Reports

Automatically sent every hour (only if trades executed):

  • Total trades, wins, losses
  • Win rate %
  • Net PnL (ETH)
  • Top and bottom fills

Real-time Alerts

  • Drawdown breach: Trading halted
  • Inventory stuck: Failed to sell after buy
  • High λ: Survival rate deteriorating
  • API errors: >5 4xx errors in 5 minutes

Risk Management

Multi-Layer Protection

  1. Pre-trade: Survival probability, profit threshold, gas caps
  2. During trade: Balance checks, approval validation, expiry checks
  3. Post-trade: Drawdown tracking, single-trade loss limits
  4. Emergency: Auto-halt on breach, manual reset required

Drawdown Tracking

Daily PnL = Σ(realized net from receipts)

If Daily PnL < -MAX_DAILY_DRAWDOWN_ETH:
   Halt trading
   Send Slack alert
   Require manual intervention

Testing

Unit Tests

npm test

Test coverage includes:

  • Profit calculations
  • Survival model math
  • Gas estimation
  • Pagination logic

Staging (Dry Run)

Set --dry-run flag or mock sendPrivateTransaction to test without executing real trades:

// In exec.ts
if (process.env.DRY_RUN === 'true') {
  return mockExecutionResult();
}

Production Canary

Start with minimal configuration:

MIN_PROFIT_USD=15              # High threshold
MAX_DAILY_DRAWDOWN_ETH=0.05   # Low exposure

Monitor for 24h before scaling up.

Operational Runbook

Health Checks

Healthy indicators:

  • Hourly Slack reports arriving
  • state/trades.csv updating
  • No 4xx/5xx error loops in logs
  • Survival λ < 0.1

⚠️ Warning signs:

  • No reports for 2+ hours
  • Repeated sell failures (>3 consecutive)
  • λ > 0.1 for 10+ minutes
  • Gas price consistently at MAX_GAS_GWEI

Common Issues

Issue: No trades executing

Possible causes:

  • Profit threshold too high for current market
  • Gas prices above MAX_GAS_GWEI
  • Survival threshold too strict
  • No collections meeting volume filter

Actions:

  1. Check logs for skip reasons
  2. Lower MIN_PROFIT_USD or increase MAX_GAS_GWEI
  3. Reduce SURVIVAL_MIN_PSURVE to 0.80
  4. Lower MIN_DAILY_VOLUME_USD

Issue: Drawdown breach

Actions:

  1. Review state/pnl-*.json to identify losing patterns
  2. Adjust MIN_PROFIT_USD upward
  3. Reduce MAX_SINGLE_TRADE_LOSS_ETH
  4. Increase SURVIVAL_MIN_PSURVE
  5. Manually reset halt after adjustments: worker.risk.resetHalt()

Issue: Inventory stuck

Causes:

  • All failover bids vanished
  • Collection offers dried up
  • Gas estimation failures

Actions:

  1. Check OpenSea UI for stuck NFT
  2. Manually list at floor - 2% via OpenSea
  3. Consider adding relist fallback (P2 feature)

Issue: API rate limits (429 errors)

Actions:

  1. Reduce MAX_COLLECTIONS
  2. Increase scan interval (adjust survival λ threshold)
  3. Enable request caching
  4. Contact API provider for limit increase

Performance Tuning

For more aggressive trading:

MIN_PROFIT_USD=5
SURVIVAL_MIN_PSURVE=0.80
FAILOVER_MAX_BIDS=5

For conservative, high-quality fills:

MIN_PROFIT_USD=15
SURVIVAL_MIN_PSURVE=0.90
FAILOVER_MAX_BIDS=2
ENABLE_CROSS_VALIDATION_HARD_GATE=true

Security Considerations

Wallet Safety

  • Use a dedicated hot wallet with minimal balances
  • Never commit PRIVATE_KEY to version control
  • Rotate keys periodically
  • Monitor wallet address for unexpected activity

API Keys

  • Store all secrets in Render environment (not in code)
  • Use read-only keys where possible
  • Enable IP whitelisting if supported

721C Compliance

  • Bot respects OpenSea conduit addresses
  • No fee circumvention attempts
  • Royalties calculated and paid per collection metadata
  • No blocked operators used

Roadmap

P0 (Completed)

✅ Single collection support
✅ Survival gating
✅ Failover logic
✅ Slack reporting
✅ Risk management

P1 (Next)

  • Multi-collection with pagination
  • Per-collection fee/royalty overrides
  • Enhanced alerting (Lambda threshold breach)
  • Cross-validation hard gate toggle

P2 (Future)

  • Relist fallback (floor - ε for 15 min)
  • Per-collection survival tracking
  • Concurrent trade execution
  • Daily summary reports

P3 (Advanced)

  • Backtesting module
  • Dynamic sizing based on confidence
  • Cross-chain support (Optimism, Arbitrum)
  • ML-based survival prediction

Troubleshooting

Logs

All logs are JSON-formatted for easy parsing:

# View recent errors
grep '"level":"ERROR"' logs.txt | tail -20

# Track specific collection
grep '"slug":"milady"' logs.txt

# Monitor survival lambda
grep 'pSurvive' logs.txt

State Inspection

# View today's trades
cat state/trades.csv | grep "$(date +%Y-%m-%d)"

# Check current PnL
cat state/pnl-$(date +%Y-%m-%d).json | jq '.realized'

# List approved collections
cat state/approvals.json | jq 'keys'

Emergency Stop

# Via environment
kill -SIGTERM <process_id>

# Via Render UI
Click "Restart Service"

# Manual halt reset (in code)
worker.risk.resetHalt()

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for new functionality
  4. Ensure all tests pass: npm test
  5. Submit pull request with detailed description

License

MIT

Disclaimer

This software is provided for educational purposes. Use at your own risk. The authors are not responsible for any financial losses incurred through the use of this bot. Always test thoroughly with small amounts before scaling up.

Support

For issues, questions, or feature requests:

  • Open a GitHub issue
  • Check existing documentation
  • Review logs for error messages

Acknowledgments

Built according to the PRD specifications with:

  • OpenSea Seaport 1.6 protocol
  • Alchemy private transactions
  • Reservoir market data
  • Risk-first design principles

About

asdf

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 99.2%
  • Dockerfile 0.8%