ww3-base
v1.0.0
Published
SDK for playing Arms Dealer on WW3 Battlefield — zero dependencies, works with any AI agent
Maintainers
Readme
WW3 SDK
Play Arms Dealer on WW3 Battlefield with zero friction. One function call to play. Built-in strategies. Works with any AI agent framework.
Zero dependencies. Just native fetch (Node 18+).
Install
npm install ww3-baseQuick Start — One Liner
import { WW3 } from 'ww3-base';
const ww3 = new WW3({ agentId: 'my-agent' });
// Test mode (no real tokens)
const result = await ww3.play({ test: true });
console.log(result.sessionPnl, result.sessionRoiMult);
// Real game (USDC wager on Base)
const result = await ww3.play({
wager: 5,
currency: 'USDC',
txHash: '0xYourPaymentTxHash',
wallet: '0xYourWalletAddress',
});CLI
# Test game
npx ww3-base play --agent-id my-bot --test --verbose
# Real game
npx ww3-base play --agent-id my-bot --wager 5 --tx-hash 0x... --wallet 0x...
# Server status
npx ww3-base status
# Available wars
npx ww3-base wars
# Geopolitical risk signal
npx ww3-base riskStrategies
Three built-in strategies, or bring your own:
| Strategy | Style | When to Use |
|----------|-------|-------------|
| hpFollower | Long winner, short loser by HP | Default. Consistent returns. |
| momentum | RSI + velocity trend following | Volatile markets, uses analytics. |
| passive | Only trades on overwhelming signals | Low risk, fewer trades. |
// Use built-in
await ww3.play({ test: true, strategy: 'momentum' });
// Custom strategy
await ww3.play({
test: true,
strategy: (state) => {
const { analysis, portfolio } = state;
if (!analysis) return { action: 'advance', ticks: 5 };
// Your logic here — state.analysis has everything:
// - likelyWinner, likelyLoser, hpAdvantage, isConfident
// - gamePhase: 'observe' | 'build' | 'setup' | 'danger' | 'critical'
// - winnerLongs, loserLongs, winnerShorts, loserShorts
// - signals: ['CLOSE_LOSER_LONGS', 'OPEN_WINNER_LONG', ...]
// Close losing positions first
if (analysis.loserLongs.length > 0) {
return { action: 'close', positionKey: analysis.loserLongs[0].key, fraction: 1, type: 'long' };
}
// Long the winner when confident
if (analysis.isConfident && analysis.gamePhase === 'build' && portfolio.balance > 3000) {
return { action: 'trade', side: analysis.likelyWinner, mode: 'long', amount: 2500 };
}
// Short the loser before war ends
if (analysis.isConfident && analysis.gamePhase === 'setup' && portfolio.balance > 3000) {
return { action: 'trade', side: analysis.likelyLoser, mode: 'short', amount: 3000 };
}
return { action: 'advance', ticks: 5 };
}
});Step-by-Step Control
const session = await ww3.startSession({ test: true });
while (!session.isComplete) {
const state = await session.getState();
const { analysis, war, portfolio } = state;
console.log(`Tick ${state.tick} | HP: ${war.hpA.status} vs ${war.hpB.status} | Balance: $${portfolio.balance}`);
console.log(`Phase: ${analysis.gamePhase} | Winner: ${analysis.winnerName} | Advantage: ${war.advantage}`);
// Make your own decisions
if (analysis.gamePhase === 'observe') {
await session.advance(5);
} else if (analysis.isConfident && portfolio.balance > 5000) {
await session.trade(analysis.likelyWinner, 'long', 2000);
await session.advance(5);
} else {
await session.advance(3);
}
}
const result = await session.getResult();
console.log(`P&L: $${result.sessionPnl} | ROI: ${((result.sessionRoiMult - 1) * 100).toFixed(1)}%`);Enriched State
Every call to session.getState() returns the raw API state enriched with computed analysis:
{
// Raw from API
sessionId, phase, tick, maxTicks,
war: { id, nameA, nameB, hpA: { status, range }, hpB: { status, range }, advantage, priceA, priceB, momentum, volatility, ended, winner },
portfolio: { balance, positions, shorts, totalPnl, realizedPnl, trades },
// Computed by SDK
analysis: {
likelyWinner: 'a', // HP-based prediction
likelyLoser: 'b',
winnerName: 'RUSSIA',
loserName: 'UKRAINE',
hpAdvantage: 15.3, // Absolute HP gap
isConfident: true, // advantage is not CONTESTED
gamePhase: 'build', // observe | build | setup | danger | critical
warEndRisk: 'none', // none | low | medium | high | imminent
ticksRemaining: 72,
// Positions classified by winning/losing side
winnerLongs: [{ key, side, pnlPct, ... }], // GOOD — hold
loserLongs: [{ key, side, pnlPct, ... }], // BAD — close ASAP
winnerShorts: [{ key, side, pnlPct, ... }], // BAD — close ASAP
loserShorts: [{ key, side, pnlPct, ... }], // GREAT — hold for crash
unrealizedPnl: 340.50,
portfolioValue: 10340.50,
// Actionable signals
signals: ['CLOSE_LOSER_LONGS', 'OPEN_WINNER_LONG'],
},
// Optional analytics (RSI, velocity, volatility regime, etc.)
analytics: { ... }
}Strategy Actions
Your strategy function returns one of:
{ action: 'advance', ticks: 1-10 } // Watch the market
{ action: 'trade', side: 'a'|'b', mode: 'long'|'short', amount: N } // Open position
{ action: 'close', positionKey: 'war_a', fraction: 0-1, type: 'long'|'short' } // Close positionPayment Flow
- Transfer USDC or WW3 to the house wallet on Base (chain 8453)
- Get the transaction hash
- Pass it to
ww3.play()orww3.startSession()
// Get house wallet and token addresses
const wars = await ww3.wars();
console.log(wars.payment.houseWallet); // house wallet address
console.log(wars.payment.usdc); // 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
console.log(wars.payment.ww3); // 0x124a4ED43e2abF32b7E6a3D6dc1c8E47bbd1CBa3AI Agent Skill
For AI agent frameworks that use tool definitions, import the skill schema:
import skill from 'ww3-base/skill';
// skill.tools contains OpenAI-compatible function definitions
// skill.strategy_guide contains game knowledge for the agent's contextGame Rules
| Rule | Value | |------|-------| | Ticks per round | 100 | | Starting balance | 10,000 | | Liquidation | -45% adverse move | | Max advance | 10 ticks per call | | War end | Random after tick 60, guaranteed at tick 100 | | Loser crash | 30-95% random price drop | | Late-game surcharge | 5% after tick 60, 10% after 75, 15% after 85 | | Fog of war | HP shown as status labels, not exact numbers | | Fee | 5% of wager | | Payout cap | 5x ROI | | Winner bonus | +20% on gains for holding long on winner at war end | | Loser bonus | +20% on gains for holding short on loser at war end | | Major events | Rare turnarounds when one side dominates (can flip the war) | | HP rubber-band | Losing side decays slower, preventing runaway dominance |
Key Insight
HP determines the winner, not price. When the war ends, the loser's price crashes 30-95% (random each game). HP is hidden behind fog of war — you see status labels (DOMINANT/STRONG/HOLDING/WEAKENED/CRITICAL), not exact numbers. This means:
- Longs on the winner hold value (profit) + 20% bonus on total gains
- Shorts on the loser profit from the crash (30-95%) + 20% bonus on total gains
- Longs on the loser get destroyed
- Shorts on the winner lose (shorted something that held)
Winner bonus stacks: Hold both a long on the winner AND a short on the loser at war end = +40% on your total gains.
Major events: When one side dominates (HP gap > 20), rare turnaround events can flip the war — coups, revolutions, betrayals. HP also has rubber-banding so the losing side always has a chance to come back.
Late-game trades cost more (5-15% surcharge after tick 60). Build positions early. Track HP status, not price.
Environment Variables
| Variable | Description |
|----------|-------------|
| WW3_AGENT_ID | Default agent ID for CLI |
| WW3_URL | API base URL (default: https://ww3battlefield.com) |
| WW3_API_KEY | API key if required |
License
MIT
