Skip to main content

Trading System

The trading system enables secure player-to-player item exchange using OSRS-style mechanics with a two-screen confirmation flow and comprehensive anti-scam features.
Trading code lives in:
  • packages/server/src/systems/TradingSystem/ - Server-side trade management
  • packages/client/src/game/panels/TradePanel/ - Client-side UI components
  • packages/client/src/hooks/useModalPanels.ts - Trade event handlers

Overview

The trading system implements OSRS-accurate player-to-player trading with:
  • Two-screen confirmation flow (Offer → Confirm)
  • Anti-scam features (value warnings, modification tracking)
  • Server-authoritative state management
  • Proximity validation (2-tile range)
  • Interface blocking during active trades

Trade Flow

1. Trade Request

Players initiate trades by right-clicking another player and selecting “Trade with”:
Request Validation:
  • Both players must be within 2 tiles (Chebyshev distance)
  • Neither player can be in another trade
  • Neither player can be in combat
  • 30-second timeout for acceptance
Acceptance:
  • Target receives TradeRequestModal with accept/decline buttons
  • Clicking accept opens trade panel for both players
  • Declining or timeout cancels the request

Screen 1: Offer Screen

Players add/remove items and accept the offer.

Adding Items

Left-click: Offer 1 item Right-click: Open quantity menu (Offer-1, Offer-5, Offer-10, Offer-All, Offer-X)

Removing Items

Left-click trade slot: Remove 1 item Right-click trade slot: Open quantity menu (Remove-1, Remove-5, Remove-All, Remove-X)

Acceptance

Both players must click “Accept” to proceed to Screen 2:
Acceptance Reset:
  • Acceptance is cleared when either player modifies their offer
  • Both players must re-accept after any change
  • Prevents “bait and switch” scams

Screen 2: Confirm Screen

Final read-only review before trade completion.

Confirmation Display

Shows both players’ final offers with total values:

Final Acceptance

Both players must click “Accept” on Screen 2 to complete the trade:
Trade Completion:
  • Server validates both players accepted on Screen 2
  • Items transferred atomically in database transaction
  • Trade panel closes for both players
  • Success message displayed

Anti-Scam Features

Value Imbalance Warnings

The trade panel shows warnings when offer values are significantly different:

Removed Item Tracking

The useRemovedItemTracking hook highlights items that the opponent removed from their offer:
Visual Indicator:
  • Removed items flash red in the trade offer grid
  • Helps players notice when opponent removes valuable items
  • Clears when player modifies their own offer

Modification Warnings

Screen 2 shows a warning if the opponent modified their offer after you accepted Screen 1:

Network Protocol

Trade Events

UI_UPDATE Components

The server sends trade updates via UI_UPDATE events with different component types: Trade Open:
Trade Update (Screen 1):
Trade Confirm (Screen 2):
Trade Close:

Server Architecture

TradingSystem

Location: packages/server/src/systems/TradingSystem/index.ts Server-authoritative system managing all trade state:
Key Methods:
  • createTradeRequest() - Initiate trade with proximity check
  • acceptTradeRequest() - Accept incoming request
  • addItemToOffer() - Add item with validation
  • removeItemFromOffer() - Remove item and reset acceptance
  • acceptOffer() - Accept current screen
  • completeTrade() - Execute atomic item transfer
  • cancelTrade() - Cancel trade and cleanup

Trade Handlers

Location: packages/server/src/systems/ServerNetwork/handlers/trade/ Modular handlers for trade operations: Security Features:
  • Proximity validation (2-tile range)
  • Inventory validation (item exists, sufficient quantity)
  • Duplicate prevention (can’t offer same item twice)
  • Atomic transfers (database transaction)
  • Audit logging for all trades

Client Architecture

TradePanel Component

Location: packages/client/src/game/panels/TradePanel/ Modular React components for trade UI:

useModalPanels Hook

Location: packages/client/src/hooks/useModalPanels.ts Centralized hook for all modal panel events including trade:

Trade Constants


Database Integration

Trade History

Completed trades are logged to the trades table for audit purposes:
Query Methods:
  • insertTradeAsync() - Log completed trade
  • queryTradesAsync() - Query trade history with filters
  • countTradesAsync() - Get trade count
  • cleanupOldTradesAsync() - Remove old records (90-day retention)

Security Features

Proximity Validation

Trades are cancelled if players move too far apart:

Atomic Transfers

Item transfers use database transactions to prevent duplication:

Interface Blocking

Players cannot open other interfaces during an active trade:

UI Components

TradePanel

Main trade window with two screens:

TradeRequestModal

Modal for incoming trade requests:

Error Handling

Trade Errors

The server emits duelError network events for trade failures:
Common Error Messages:
  • “Trade request timed out”
  • “Player is too far away”
  • “Player is already in a trade”
  • “Insufficient inventory space”
  • “Item no longer in inventory”

Testing

Integration Tests

Location: packages/server/tests/integration/trade/ Comprehensive tests covering:
  • Trade request flow
  • Item addition/removal
  • Acceptance logic
  • Screen transitions
  • Proximity validation
  • Atomic transfers
  • Error handling