Skip to main content

Trading System

Titan implements secure peer-to-peer trading with real-time updates and atomic item swaps.

Trade Flow

Trade States

TradeSession Structure

interface TradeSession {
tradeId: string;
status: TradeStatus; // Pending, Completed, Cancelled, Expired
initiatorCharacterId: string;
targetCharacterId: string;
seasonId: string;
initiatorItems: string[]; // Item IDs offered by initiator
targetItems: string[]; // Item IDs offered by target
initiatorAccepted: boolean;
targetAccepted: boolean;
createdAt: string;
expiresAt: string;
}

Trade Rules

Trades are validated against a rule engine before execution:

RuleDescriptionError
SameSeasonRuleCharacters must be in the same season"Cannot trade across seasons"
SoloSelfFoundRuleSSF characters cannot trade"SSF characters cannot trade"

Starting a Trade

// Player 1 initiates trade with Player 2
const session = await connection.invoke(
"StartTrade",
myCharacterId,
targetCharacterId,
"season-1"
);

// Join the trade group for updates
await connection.invoke("JoinTradeSession", session.tradeId);

Adding/Removing Items

// Add item to your offer
await connection.invoke("AddItem", tradeId, itemId);

// Remove item from your offer
await connection.invoke("RemoveItem", tradeId, itemId);

Items are validated:

  • Must belong to your character's inventory
  • Cannot be equipped (must be in bag)
  • Cannot already be in another active trade

Accepting the Trade

// Accept current offer
const result = await connection.invoke("AcceptTrade", tradeId);

if (result.completed) {
console.log("Trade completed! Items swapped.");
} else {
console.log("Waiting for other party to accept...");
}

Acceptance is reset when items change - both parties must re-accept.

Cancelling

await connection.invoke("CancelTrade", tradeId);
// Both parties receive TradeCancelled event

Real-Time Events

Subscribe to trade updates:

connection.on("TradeUpdate", (update) => {
switch (update.eventType) {
case "TradeStarted":
showTradeWindow(update.data);
break;
case "ItemAdded":
addItemToDisplay(update.data.characterId, update.data.itemId);
break;
case "ItemRemoved":
removeItemFromDisplay(update.data.characterId, update.data.itemId);
break;
case "TradeAccepted":
markPartyAccepted(update.data.characterId);
break;
case "TradeCompleted":
refreshInventory();
closeTradeWindow();
break;
case "TradeCancelled":
showMessage("Trade cancelled");
closeTradeWindow();
break;
}
});

Atomic Execution

When both parties accept, items are swapped atomically:

  1. Remove items from initiator's inventory
  2. Remove items from target's inventory
  3. Add target's items to initiator's inventory
  4. Add initiator's items to target's inventory
  5. Record trade history for all items

If any step fails, the entire transaction rolls back.

Security

  • Ownership verification: Can only trade items you own
  • Character verification: Can only act as characters you own
  • Expiration: Trades timeout after 5 minutes
  • Single trade: Items can only be in one active trade