# @pump-fun/shared-contracts

Shared contracts and type definitions for the Pump.fun notification system microservices.

## Installation

```bash
bun add @pump-fun/shared-contracts
```

## NATS Subjects

The package exports NATS subject constants organized by service domain:

### Trade Subjects
```typescript
import { TRADE_SUBJECTS } from "@pump-fun/shared-contracts/events";

// Subscribe to all unified trades
nats.subscribe(TRADE_SUBJECTS.UNIFIED_TRADE);
```

### Watcher Service Subjects
```typescript
import {
  TRENDING_SUBJECTS,
  WATCHLIST_SUBJECTS,
  PORTFOLIO_SUBJECTS,
  MILESTONE_SUBJECTS
} from "@pump-fun/shared-contracts/events";

// Subscribe to trending events
nats.subscribe(TRENDING_SUBJECTS.EVENT);

// Subscribe to watchlist alerts
nats.subscribe(WATCHLIST_SUBJECTS.ALERT);

// Subscribe to portfolio alerts
nats.subscribe(PORTFOLIO_SUBJECTS.ALERT);

// Subscribe to milestone events
nats.subscribe(MILESTONE_SUBJECTS.EVENT);
```

### Notification Processor Subjects
```typescript
import { NOTIFICATION_SUBJECTS } from "@pump-fun/shared-contracts/events";

// Subscribe to all notification events
nats.subscribe(NOTIFICATION_SUBJECTS.ALL);

// Publish processed notification
nats.publish(NOTIFICATION_SUBJECTS.PROCESSED, notification);
```

### Gateway Subjects
```typescript
import {
  EMAIL_GATEWAY_SUBJECTS,
  FCM_GATEWAY_SUBJECTS
} from "@pump-fun/shared-contracts/events";

// Send email command
nats.publish(EMAIL_GATEWAY_SUBJECTS.SEND, emailCommand);

// Send push notification
nats.publish(FCM_GATEWAY_SUBJECTS.SEND, pushCommand);
```

## Message Types

All message types are defined using Zod schemas for runtime validation:

### Trade Messages
```typescript
import { UnifiedTradeSchema, type UnifiedTrade } from "@pump-fun/shared-contracts/events";

// Validate incoming trade
const trade = UnifiedTradeSchema.parse(message.data);

// Type-safe trade object
const processTrade = (trade: UnifiedTrade) => {
  console.log(`${trade.type} trade: ${trade.amountUsd} USD for ${trade.mintAddress}`);
};
```

### Alert Messages
```typescript
import {
  TrendingEventSchema,
  WatchlistAlertSchema,
  PortfolioAlertSchema,
  MilestoneEventSchema
} from "@pump-fun/shared-contracts/events";

// Parse and validate alerts
const trendingEvent = TrendingEventSchema.parse(data);
const watchlistAlert = WatchlistAlertSchema.parse(data);
const portfolioAlert = PortfolioAlertSchema.parse(data);
const milestoneEvent = MilestoneEventSchema.parse(data);
```

### Notification Messages
```typescript
import {
  ProcessedNotificationSchema,
  NotificationDeliveryStatusSchema
} from "@pump-fun/shared-contracts/events";

// Create a processed notification
const notification = ProcessedNotificationSchema.parse({
  notificationId: "123",
  userId: "user-456",
  type: "watchlist_alert",
  title: "Price Alert",
  body: "BONK reached your target price",
  channels: ["push", "email"],
  priority: "high",
  data: { tokenMint: "...", price: 0.001 },
  createdAt: Date.now()
});
```

## Utility Functions

### Message Envelopes
```typescript
import { createMessageEnvelope } from "@pump-fun/shared-contracts/events";

// Wrap data in a message envelope with headers
const envelope = createMessageEnvelope(
  { type: "buy", amount: 1000 },
  {
    correlationId: "req-123",
    userId: "user-456",
    source: "watchlist-watcher"
  }
);
```

### Subject Matching
```typescript
import { subjectMatches } from "@pump-fun/shared-contracts/events";

// Check if a subject matches a pattern
subjectMatches("trade.unified", "trade.*"); // true
subjectMatches("notification.push", "notification.>"); // true
subjectMatches("trending.event", "watchlist.*"); // false
```

### Subject Builder
```typescript
import { SubjectBuilder } from "@pump-fun/shared-contracts/events";

// Build subjects dynamically
const subject = SubjectBuilder
  .create("notification")
  .add("user")
  .add(userId)
  .add("push")
  .build(); // "notification.user.123.push"
```

### Error Handling
```typescript
import { NatsError } from "@pump-fun/shared-contracts/events";

try {
  await nats.publish(subject, data);
} catch (error) {
  throw new NatsError(
    "PUBLISH_FAILED",
    `Failed to publish to ${subject}`,
    error
  );
}
```

## Core NATS Usage

This system uses core NATS (not JetStream), so subscriptions are simple:

```typescript
import { UNIFIED_TRADE_SUBJECTS } from "@pump-fun/shared-contracts/events";
import { connect } from "nats";

// Connect to NATS
const nc = await connect({ servers: ["nats://localhost:4222"] });

// Simple subscription
const sub = nc.subscribe(UNIFIED_TRADE_SUBJECTS.ALL);

// Process messages
(async () => {
  for await (const msg of sub) {
    try {
      const tradeData = JSON.parse(msg.data.toString());
      // Validate with schema
      const trade = UnifiedTradeSchema.parse(tradeData);

      console.log(`Processing ${trade.type} trade:`, {
        mintAddress: trade.mintAddress,
        amountUsd: trade.amountUsd,
        tx: trade.tx
      });

      await processTrade(trade);
    } catch (error) {
      console.error("Failed to process trade:", error);
    }
  }
})();
```

## Complete Example

```typescript
import {
  WATCHLIST_SUBJECTS,
  WatchlistAlertSchema,
  createMessageEnvelope,
  NatsError
} from "@pump-fun/shared-contracts/events";
import { connect } from "nats";

// Connect to NATS
const nc = await connect({ servers: ["nats://localhost:4222"] });

// Subscribe to watchlist alerts
const sub = nc.subscribe(WATCHLIST_SUBJECTS.ALERT);

(async () => {
  for await (const msg of sub) {
    try {
      // Parse and validate the alert
      const alert = WatchlistAlertSchema.parse(
        JSON.parse(msg.data.toString())
      );

      console.log(`Alert for ${alert.userId}: ${alert.message}`);

      // Process the message (no ack needed in core NATS)
      console.log(`Processed alert for ${alert.userId}: ${alert.message}`);
    } catch (error) {
      console.error("Failed to process alert:", error);
    }
  }
})();

// Publish a watchlist alert
const alert = {
  userId: "user-123",
  tokenMint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
  symbol: "BONK",
  alertType: "price_above" as const,
  threshold: 0.001,
  currentValue: 0.0012,
  message: "BONK price exceeded $0.001",
  timestamp: Date.now()
};

try {
  const envelope = createMessageEnvelope(alert, {
    source: "watchlist-watcher",
    userId: alert.userId
  });

  await nc.publish(
    WATCHLIST_SUBJECTS.ALERT,
    JSON.stringify(envelope)
  );
} catch (error) {
  throw new NatsError(
    "PUBLISH_FAILED",
    "Failed to publish watchlist alert",
    error as Error
  );
}
```

## Type Exports

The package exports all TypeScript types for the schemas:

```typescript
export type UnifiedTrade = z.infer<typeof UnifiedTradeSchema>;
export type TrendingEvent = z.infer<typeof TrendingEventSchema>;
export type WatchlistAlert = z.infer<typeof WatchlistAlertSchema>;
export type PortfolioAlert = z.infer<typeof PortfolioAlertSchema>;
export type MilestoneEvent = z.infer<typeof MilestoneEventSchema>;
export type ProcessedNotification = z.infer<typeof ProcessedNotificationSchema>;
export type NotificationDeliveryStatus = z.infer<typeof NotificationDeliveryStatusSchema>;
export type EmailSendCommand = z.infer<typeof EmailSendCommandSchema>;
export type PushSendCommand = z.infer<typeof PushSendCommandSchema>;
export type HealthCheckRequest = z.infer<typeof HealthCheckRequestSchema>;
export type HealthCheckResponse = z.infer<typeof HealthCheckResponseSchema>;
export type SystemError = z.infer<typeof SystemErrorSchema>;
export type UserPreferences = z.infer<typeof UserPreferencesSchema>;
export type DeviceRegistration = z.infer<typeof DeviceRegistrationSchema>;
```

# Shared Contracts

This package contains shared API contracts and types for Pump.fun services.

## For Mobile App Developers

### What to Import

The notification API exports its router type which you can use to create a fully typed client:

```typescript
import type { Router } from "@pump-fun/notification-api";
```

### Setting Up the Client

You have two options for consuming the notification API:

#### Option 1: Using RPC Endpoint (Recommended for oRPC clients)

```typescript
import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/fetch";
import type { RouterClient } from "@orpc/server";
import type { Router } from "@pump-fun/notification-api";

function createNotificationApiClient(config: {
  baseUrl: string;
  getAuthToken: () => string | null;
}): RouterClient<Router> {
  return createORPCClient(
    new RPCLink({
      url: `${config.baseUrl}/rpc`,
      headers: () => {
        const token = config.getAuthToken();
        return token ? { Authorization: `Bearer ${token}` } : {};
      },
    }),
  );
}
```

#### Option 2: Using OpenAPI/REST Endpoints

If you prefer REST semantics or are not using oRPC:

```typescript
// Direct REST calls
const response = await fetch("https://api.pump.fun/api/mobile/users/me/pnl-tracking", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`,
  },
  body: JSON.stringify({
    deviceInfo: {
      appVersion: "1.0.0",
      deviceId: "device-123",
      platform: "ios",
    },
  }),
});
```

### Available Endpoints

The notification API provides:

- **Mobile User P&L Tracking**
  - `POST /api/mobile/users/me/pnl-tracking` - Setup 7-day P&L tracking
  - `GET /api/mobile/users/me/pnl-tracking-status` - Check tracking status

- **Authentication Demo** (for testing)
  - `POST /api/auth/generate-token` - Generate test JWT tokens
  - `GET /api/auth/profile` - Get authenticated user profile
  - `GET /api/public/info` - Public endpoint (no auth required)

- **Health Check**
  - `GET /api/health` - Check API health status

- **Notification Settings**
  - Various endpoints for managing notification preferences

### Authentication

All endpoints except `/api/health` and `/api/public/*` require JWT authentication:

```typescript
headers: {
  Authorization: `Bearer ${yourJwtToken}`,
}
```

### OpenAPI Documentation

The full OpenAPI specification is available at:
- JSON: `https://api.pump.fun/api/openapi.json`
- Interactive UI: `https://api.pump.fun/api/reference`

## Contract-First Development

This package also contains contract definitions that can be imported for type safety:

```typescript
import { mobileUserContract } from "@pump-fun/shared-contracts/api-contracts";
```

These contracts define the API specification and can be used to ensure client-server compatibility.
