655 lines
14 KiB
Markdown
655 lines
14 KiB
Markdown
# Steam Bot Setup Guide
|
|
|
|
## 🤖 Overview
|
|
|
|
The Steam bot system handles trade offers for buying items from users. When a user sells items, instead of immediately crediting funds, the system:
|
|
|
|
1. ✅ Creates a trade offer via Steam bot
|
|
2. ⏳ Tracks trade state (pending, accepted, declined, etc.)
|
|
3. 💰 Credits user balance ONLY after trade is accepted
|
|
4. 🔄 Handles failures, expirations, and retries
|
|
|
|
---
|
|
|
|
## 📋 Prerequisites
|
|
|
|
### 1. Steam Bot Account
|
|
|
|
You need a separate Steam account for the bot:
|
|
|
|
- ✅ Account with Steam Mobile Authenticator enabled
|
|
- ✅ Public inventory
|
|
- ✅ Valid trade URL
|
|
- ✅ API key from https://steamcommunity.com/dev/apikey
|
|
- ✅ Not limited (must have spent $5+ on Steam)
|
|
- ✅ Trade cooldown period expired (if newly set up)
|
|
|
|
### 2. Required Packages
|
|
|
|
Already installed in package.json:
|
|
```json
|
|
{
|
|
"steam-user": "^5.0.0",
|
|
"steamcommunity": "^3.47.0",
|
|
"steam-tradeoffer-manager": "^2.10.6",
|
|
"steam-totp": "^2.1.1"
|
|
}
|
|
```
|
|
|
|
Install if needed:
|
|
```bash
|
|
npm install steam-user steamcommunity steam-tradeoffer-manager steam-totp
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 Getting Steam Bot Credentials
|
|
|
|
### Step 1: Get Shared Secret & Identity Secret
|
|
|
|
1. **Enable Steam Mobile Authenticator** on bot account
|
|
2. Use one of these tools to extract secrets:
|
|
- **SDA (Steam Desktop Authenticator)**: https://github.com/Jessecar96/SteamDesktopAuthenticator
|
|
- **Android**: Use app like "Steam Guard Mobile Authenticator"
|
|
- **Manual extraction**: Follow guides online
|
|
|
|
3. You'll need:
|
|
- `shared_secret` - For generating 2FA codes
|
|
- `identity_secret` - For confirming trades
|
|
|
|
### Step 2: Get Steam API Key
|
|
|
|
1. Go to: https://steamcommunity.com/dev/apikey
|
|
2. Register domain: `turbotrades.com` (or your domain)
|
|
3. Copy the API key
|
|
|
|
### Step 3: Get Bot Trade URL
|
|
|
|
1. Login to bot account
|
|
2. Go to: https://steamcommunity.com/id/me/tradeoffers/privacy
|
|
3. Copy the trade URL (looks like: `https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=XXXXXXXX`)
|
|
|
|
---
|
|
|
|
## ⚙️ Configuration
|
|
|
|
### Environment Variables
|
|
|
|
Add to your `.env` file:
|
|
|
|
```env
|
|
# Steam Bot Credentials
|
|
STEAM_BOT_USERNAME=your_bot_username
|
|
STEAM_BOT_PASSWORD=your_bot_password
|
|
STEAM_BOT_SHARED_SECRET=your_shared_secret_here
|
|
STEAM_BOT_IDENTITY_SECRET=your_identity_secret_here
|
|
|
|
# Steam API
|
|
STEAM_API_KEY=your_steam_api_key
|
|
|
|
# Bot Trade URL
|
|
STEAM_BOT_TRADE_URL=https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=XXXXXXXX
|
|
|
|
# Optional: Bot Settings
|
|
STEAM_BOT_POLL_INTERVAL=30000
|
|
STEAM_BOT_AUTO_START=true
|
|
```
|
|
|
|
### Security Notes
|
|
|
|
- ⚠️ **NEVER commit `.env` to git**
|
|
- ⚠️ Keep secrets secure
|
|
- ⚠️ Use different account from your personal Steam
|
|
- ⚠️ Enable Steam Guard on bot account
|
|
- ⚠️ Use strong password
|
|
|
|
---
|
|
|
|
## 🚀 Starting the Bot
|
|
|
|
### Automatic Start (Recommended)
|
|
|
|
Bot starts automatically when backend launches if `STEAM_BOT_AUTO_START=true`
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
You'll see:
|
|
```
|
|
🔐 Logging into Steam...
|
|
✅ Steam bot logged in successfully
|
|
✅ Steam web session established
|
|
🤖 Steam bot ready for trades
|
|
```
|
|
|
|
### Manual Start
|
|
|
|
```javascript
|
|
import { getSteamBot } from './services/steamBot.js';
|
|
|
|
const bot = getSteamBot();
|
|
await bot.login();
|
|
|
|
console.log('Bot ready:', bot.isOnline());
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 How It Works
|
|
|
|
### User Sells Items Flow
|
|
|
|
```
|
|
1. User selects items on Sell page
|
|
2. User clicks "Sell Selected Items"
|
|
↓
|
|
3. Backend creates Trade record (state: pending)
|
|
- Does NOT credit balance yet
|
|
↓
|
|
4. Steam bot creates trade offer
|
|
- Requests items from user
|
|
- User sees trade offer in Steam
|
|
↓
|
|
5. User accepts trade in Steam app
|
|
↓
|
|
6. Bot receives "trade accepted" event
|
|
↓
|
|
7. Backend:
|
|
- Updates Trade state to "accepted"
|
|
- Creates Transaction record
|
|
- Credits user balance
|
|
- Updates WebSocket
|
|
↓
|
|
8. User sees balance update in UI
|
|
```
|
|
|
|
### Trade States
|
|
|
|
| State | Description | User Balance | Can Retry |
|
|
|-------|-------------|--------------|-----------|
|
|
| **pending** | Trade offer sent, waiting for user | ❌ Not credited | ✅ Yes |
|
|
| **accepted** | User accepted, items received | ✅ Credited | ❌ No |
|
|
| **declined** | User declined the offer | ❌ Not credited | ⚠️ Maybe |
|
|
| **expired** | Trade offer expired (10min timeout) | ❌ Not credited | ✅ Yes |
|
|
| **canceled** | Trade was canceled | ❌ Not credited | ✅ Yes |
|
|
| **failed** | Technical error occurred | ❌ Not credited | ✅ Yes |
|
|
| **escrow** | Trade in Steam escrow | ❌ Not credited | ⏳ Wait |
|
|
|
|
---
|
|
|
|
## 📊 Database Schema
|
|
|
|
### Trade Model
|
|
|
|
```javascript
|
|
{
|
|
offerId: String, // Steam trade offer ID
|
|
userId: ObjectId, // User who's selling
|
|
steamId: String, // User's Steam ID
|
|
state: String, // pending, accepted, declined, etc.
|
|
items: [{
|
|
assetId: String,
|
|
name: String,
|
|
price: Number,
|
|
image: String,
|
|
// ... item details
|
|
}],
|
|
totalValue: Number, // Total price of all items
|
|
fee: Number, // Platform fee (e.g., 5%)
|
|
feePercentage: Number, // Fee percentage
|
|
userReceives: Number, // Amount user gets (after fees)
|
|
tradeUrl: String, // User's trade URL
|
|
tradeOfferUrl: String, // Link to view offer on Steam
|
|
sentAt: Date, // When trade was sent
|
|
acceptedAt: Date, // When user accepted
|
|
completedAt: Date, // When balance was credited
|
|
expiresAt: Date, // When trade expires (10min)
|
|
transactionId: ObjectId, // Transaction created after acceptance
|
|
sessionId: ObjectId, // User's session
|
|
errorMessage: String, // If failed
|
|
retryCount: Number, // How many times retried
|
|
metadata: Mixed // Additional data
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎮 Bot Events
|
|
|
|
The bot emits events you can listen to:
|
|
|
|
```javascript
|
|
const bot = getSteamBot();
|
|
|
|
// Bot is ready
|
|
bot.on('ready', () => {
|
|
console.log('Bot is ready!');
|
|
});
|
|
|
|
// Trade accepted
|
|
bot.on('tradeAccepted', async (offer, tradeData) => {
|
|
console.log('Trade accepted:', offer.id);
|
|
// Credit user balance here
|
|
});
|
|
|
|
// Trade declined
|
|
bot.on('tradeDeclined', async (offer, tradeData) => {
|
|
console.log('Trade declined:', offer.id);
|
|
// Notify user
|
|
});
|
|
|
|
// Trade expired
|
|
bot.on('tradeExpired', async (offer, tradeData) => {
|
|
console.log('Trade expired:', offer.id);
|
|
// Can retry or cancel
|
|
});
|
|
|
|
// Bot error
|
|
bot.on('error', (err) => {
|
|
console.error('Bot error:', err);
|
|
});
|
|
|
|
// Bot disconnected
|
|
bot.on('disconnected', () => {
|
|
console.warn('Bot disconnected, will reconnect...');
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 🛠️ API Endpoints
|
|
|
|
### Create Trade Offer
|
|
|
|
```http
|
|
POST /api/trade/create
|
|
Authorization: Bearer <token>
|
|
|
|
{
|
|
"items": [
|
|
{
|
|
"assetId": "123456789",
|
|
"name": "AK-47 | Redline (Field-Tested)",
|
|
"price": 12.50,
|
|
"image": "https://...",
|
|
// ... other item data
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"trade": {
|
|
"id": "trade_id",
|
|
"offerId": "steam_offer_id",
|
|
"state": "pending",
|
|
"totalValue": 12.50,
|
|
"userReceives": 11.88,
|
|
"items": [...],
|
|
"tradeOfferUrl": "https://steamcommunity.com/tradeoffer/...",
|
|
"expiresAt": "2024-01-10T12:10:00Z"
|
|
},
|
|
"message": "Trade offer sent! Check your Steam app to accept."
|
|
}
|
|
```
|
|
|
|
### Get Trade Status
|
|
|
|
```http
|
|
GET /api/trade/:tradeId
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"trade": {
|
|
"id": "trade_id",
|
|
"offerId": "steam_offer_id",
|
|
"state": "accepted",
|
|
"totalValue": 12.50,
|
|
"userReceives": 11.88,
|
|
"acceptedAt": "2024-01-10T12:05:00Z",
|
|
"timeElapsed": "5m ago"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Cancel Trade
|
|
|
|
```http
|
|
POST /api/trade/:tradeId/cancel
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
### Retry Trade
|
|
|
|
```http
|
|
POST /api/trade/:tradeId/retry
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Bot Management
|
|
|
|
### Check Bot Status
|
|
|
|
```javascript
|
|
const bot = getSteamBot();
|
|
|
|
const health = bot.getHealth();
|
|
console.log(health);
|
|
// {
|
|
// isReady: true,
|
|
// isLoggedIn: true,
|
|
// activeTradesCount: 5,
|
|
// username: "bot_username"
|
|
// }
|
|
```
|
|
|
|
### Get Active Trades
|
|
|
|
```javascript
|
|
const activeTrades = bot.getActiveTrades();
|
|
console.log(`${activeTrades.length} trades active`);
|
|
```
|
|
|
|
### Cancel All Pending Trades
|
|
|
|
```javascript
|
|
const pendingTrades = await Trade.getPendingTrades();
|
|
|
|
for (const trade of pendingTrades) {
|
|
if (trade.isExpired) {
|
|
await bot.cancelTradeOffer(trade.offerId);
|
|
await trade.markAsExpired();
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing
|
|
|
|
### Test Bot Login
|
|
|
|
```bash
|
|
node -e "import('./services/steamBot.js').then(async m => {
|
|
const bot = m.getSteamBot();
|
|
await bot.login();
|
|
console.log('Bot logged in:', bot.isOnline());
|
|
bot.logout();
|
|
process.exit(0);
|
|
})"
|
|
```
|
|
|
|
### Test Trade Creation
|
|
|
|
```javascript
|
|
const bot = getSteamBot();
|
|
await bot.login();
|
|
|
|
const result = await bot.createTradeOffer({
|
|
tradeUrl: "https://steamcommunity.com/tradeoffer/new/?partner=XXX&token=XXX",
|
|
itemsToReceive: [
|
|
{ assetid: "123456789", appid: 730, contextid: 2 }
|
|
],
|
|
message: "Test trade offer"
|
|
});
|
|
|
|
console.log('Trade created:', result);
|
|
```
|
|
|
|
---
|
|
|
|
## 📈 Monitoring
|
|
|
|
### Database Queries
|
|
|
|
```javascript
|
|
// Get all pending trades
|
|
const pending = await Trade.find({ state: 'pending' });
|
|
|
|
// Get expired trades
|
|
const expired = await Trade.getExpiredTrades();
|
|
|
|
// Get trade stats
|
|
const stats = await Trade.getStats();
|
|
console.log(`
|
|
Total trades: ${stats.total}
|
|
Accepted: ${stats.accepted}
|
|
Pending: ${stats.pending}
|
|
Declined: ${stats.declined}
|
|
`);
|
|
|
|
// Get user's trades
|
|
const userTrades = await Trade.getUserTrades(userId);
|
|
```
|
|
|
|
### Admin Panel Integration
|
|
|
|
Add to admin panel:
|
|
- ✅ View pending trades
|
|
- ✅ Cancel stale trades
|
|
- ✅ Retry failed trades
|
|
- ✅ View trade statistics
|
|
- ✅ Bot health status
|
|
|
|
---
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
### Bot Won't Login
|
|
|
|
**Check:**
|
|
- ✅ Username and password correct
|
|
- ✅ Shared secret is valid
|
|
- ✅ Steam account not limited
|
|
- ✅ No active VAC ban
|
|
- ✅ No trade cooldown
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Test credentials
|
|
node -e "console.log('Username:', process.env.STEAM_BOT_USERNAME)"
|
|
node -e "console.log('Has password:', !!process.env.STEAM_BOT_PASSWORD)"
|
|
node -e "console.log('Has shared secret:', !!process.env.STEAM_BOT_SHARED_SECRET)"
|
|
```
|
|
|
|
### Trades Not Confirming
|
|
|
|
**Check:**
|
|
- ✅ Identity secret is correct
|
|
- ✅ Mobile authenticator is active
|
|
- ✅ Bot has trade URL
|
|
|
|
**Solution:**
|
|
- Manually confirm in Steam app first time
|
|
- Check if identity secret is correct
|
|
- Regenerate secrets if needed
|
|
|
|
### Trades Stuck in Pending
|
|
|
|
**Reasons:**
|
|
- User hasn't accepted yet
|
|
- Trade expired (10 minutes)
|
|
- Steam API issues
|
|
- User's inventory is private
|
|
|
|
**Solution:**
|
|
```javascript
|
|
// Cancel expired trades
|
|
const expired = await Trade.find({
|
|
state: 'pending',
|
|
expiresAt: { $lt: new Date() }
|
|
});
|
|
|
|
for (const trade of expired) {
|
|
await bot.cancelTradeOffer(trade.offerId);
|
|
await trade.markAsExpired();
|
|
}
|
|
```
|
|
|
|
### Bot Keeps Disconnecting
|
|
|
|
**Check:**
|
|
- ✅ Network connection stable
|
|
- ✅ Steam not under maintenance
|
|
- ✅ No rate limiting
|
|
|
|
**Solution:**
|
|
- Implement auto-reconnect (already built-in)
|
|
- Use connection pooling
|
|
- Monitor logs for error patterns
|
|
|
|
---
|
|
|
|
## 🔒 Security Best Practices
|
|
|
|
### 1. Secure Credentials
|
|
- ✅ Never hardcode credentials
|
|
- ✅ Use environment variables
|
|
- ✅ Keep .env out of git
|
|
- ✅ Rotate secrets regularly
|
|
|
|
### 2. Trade Validation
|
|
- ✅ Verify user owns items before creating trade
|
|
- ✅ Check item values match database
|
|
- ✅ Validate trade URLs
|
|
- ✅ Prevent duplicate trades
|
|
|
|
### 3. Rate Limiting
|
|
- ✅ Limit trades per user per hour
|
|
- ✅ Limit total trades per minute
|
|
- ✅ Queue trades during high load
|
|
|
|
### 4. Monitoring
|
|
- ✅ Log all trade events
|
|
- ✅ Alert on failed trades
|
|
- ✅ Track bot uptime
|
|
- ✅ Monitor Steam API status
|
|
|
|
---
|
|
|
|
## 📊 Performance Optimization
|
|
|
|
### Trade Queue System
|
|
|
|
For high volume, implement trade queue:
|
|
|
|
```javascript
|
|
// Redis-based queue
|
|
import Bull from 'bull';
|
|
|
|
const tradeQueue = new Bull('trades', {
|
|
redis: { host: 'localhost', port: 6379 }
|
|
});
|
|
|
|
tradeQueue.process(async (job) => {
|
|
const { userId, items } = job.data;
|
|
return await createTradeOffer(userId, items);
|
|
});
|
|
|
|
// Add to queue
|
|
await tradeQueue.add({ userId, items }, {
|
|
attempts: 3,
|
|
backoff: {
|
|
type: 'exponential',
|
|
delay: 2000
|
|
}
|
|
});
|
|
```
|
|
|
|
### Retry Strategy
|
|
|
|
```javascript
|
|
async function createTradeWithRetry(data, maxRetries = 3) {
|
|
let lastError;
|
|
|
|
for (let i = 0; i < maxRetries; i++) {
|
|
try {
|
|
return await bot.createTradeOffer(data);
|
|
} catch (error) {
|
|
lastError = error;
|
|
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
|
|
}
|
|
}
|
|
|
|
throw lastError;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Next Steps
|
|
|
|
### Phase 1: Basic Setup (You are here)
|
|
- [x] Install packages
|
|
- [x] Create bot service
|
|
- [x] Create Trade model
|
|
- [ ] Configure environment variables
|
|
- [ ] Test bot login
|
|
|
|
### Phase 2: Integration
|
|
- [ ] Update sell endpoint to create trades
|
|
- [ ] Add trade event handlers
|
|
- [ ] Credit balance on acceptance
|
|
- [ ] Add trade status polling
|
|
|
|
### Phase 3: Frontend
|
|
- [ ] Show trade status in UI
|
|
- [ ] Add "View Trade" button
|
|
- [ ] Show pending trades list
|
|
- [ ] Add trade notifications
|
|
|
|
### Phase 4: Admin Tools
|
|
- [ ] Bot health dashboard
|
|
- [ ] Trade management panel
|
|
- [ ] Retry/cancel controls
|
|
- [ ] Statistics and reports
|
|
|
|
### Phase 5: Advanced
|
|
- [ ] Trade queue system
|
|
- [ ] Multiple bot support
|
|
- [ ] Automatic retries
|
|
- [ ] Fraud detection
|
|
|
|
---
|
|
|
|
## 📚 Additional Resources
|
|
|
|
- **Steam Web API**: https://developer.valvesoftware.com/wiki/Steam_Web_API
|
|
- **Trade Offer Manager**: https://github.com/DoctorMcKay/node-steam-tradeoffer-manager
|
|
- **Steam User**: https://github.com/DoctorMcKay/node-steam-user
|
|
- **Steam TOTP**: https://github.com/DoctorMcKay/node-steam-totp
|
|
|
|
---
|
|
|
|
## ✅ Configuration Checklist
|
|
|
|
Before going live:
|
|
|
|
- [ ] Bot account created and funded ($5+ spent)
|
|
- [ ] Steam Mobile Authenticator enabled
|
|
- [ ] Shared secret and identity secret extracted
|
|
- [ ] API key obtained from Steam
|
|
- [ ] Environment variables configured
|
|
- [ ] Bot successfully logs in
|
|
- [ ] Test trade offer sent and accepted
|
|
- [ ] Trade events properly handled
|
|
- [ ] Balance credits on acceptance
|
|
- [ ] Error handling tested
|
|
- [ ] Monitoring set up
|
|
- [ ] Backup credentials stored securely
|
|
|
|
---
|
|
|
|
**Status**: Implementation Ready
|
|
**Next**: Configure bot credentials and test login
|
|
**Priority**: High - Required for production sell functionality |