rain-sdk-v2 2.1.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1237,6 +1237,64 @@ const priceData = await rain.getTokenPrice('0x...'); // token contract address
1237
1237
  // priceData.data = { price: 0.05 } — USD price per token
1238
1238
  ```
1239
1239
 
1240
+ ### Leaderboard
1241
+
1242
+ Public endpoints — no access token required. Boards are served from a materialized document rebuilt by a cron (~20 min), so changes appear after the next tick rather than on the next request.
1243
+
1244
+ ```typescript
1245
+ // Get a ranked leaderboard — one board per (board, window, category)
1246
+ const board = await rain.getLeaderboard({
1247
+ board: 'profit', // 'profit' (net realized PnL) or 'correct_calls' (sum of 1 − entryPrice over winning positions)
1248
+ window: 'all_time', // 'all_time' (default) or 'monthly' (current UTC calendar month)
1249
+ category: 'Crypto', // optional, case-insensitive; omit for the global board
1250
+ limit: 10, // up to the stored cap of 100 (default 10)
1251
+ });
1252
+ // board.data = { board, window, category, categoryLabel, period, limit, totalRanked, priceBasis, entries, lastUpdatedAt }
1253
+ // Each entry carries all four table columns — profit, correctCalls, winRate, trades —
1254
+ // whichever board is sorting, so switching the sorted column needs no second request.
1255
+
1256
+ // Search traders on a board — the leaderboard's trader search box
1257
+ const found = await rain.searchLeaderboard({
1258
+ q: '0x742d', // wallet address, address fragment (with/without 0x, prefix/middle/tail), or user id
1259
+ board: 'profit', // required — searches the stored board for this (board, window, category)
1260
+ window: 'all_time', // optional, default 'all_time'
1261
+ category: 'Crypto', // optional; omit for the global board
1262
+ limit: 10, // up to 50 (default 10)
1263
+ });
1264
+ // found.data = { board, window, category, period, query, matched, searchedTop, totalRanked, lastUpdatedAt, results }
1265
+ // `results` are the same entry objects getLeaderboard returns, in rank order.
1266
+ // Scoped to the stored board — a trader outside the top N is simply not found.
1267
+ // Empty `results` means "not on this board"; `searchedTop` + `totalRanked` let you
1268
+ // say "not in the top 100" precisely. Queries under 2 characters return empty, not a 400.
1269
+
1270
+ // Get a trader's most recent trades — the rows inside an expanded leaderboard row
1271
+ const recent = await rain.getTraderRecentTrades({
1272
+ userId: '...', // from a leaderboard entry's `userId`
1273
+ limit: 5, // rendered rows (a multi-side trade flattens into more lines), up to 25 (default 5)
1274
+ });
1275
+ // recent.data = { userId, limit, trades }
1276
+ // Each trade: { action ('Buy'|'Sell'), origin, transactionHash, tradedAt, poolId, question,
1277
+ // poolImage, subPoolId, subQuestion, side (1=YES, 2=NO), optionName, shares,
1278
+ // amountUSD, pricePerShare, priceCents, status ('open'|'pending'|'settled'),
1279
+ // pnlScope, pnlUSD }
1280
+ // Directional trades only (origin ∈ {enter, orderFill}), newest first — and unlike the
1281
+ // track-record endpoint, OPEN positions are included (status 'open').
1282
+ // `pnlUSD` is POSITION-level, not per-fill: several trades in the same market report the
1283
+ // same number. Null until settled; `amountUSD`/`pnlUSD` are dollars × 1e6.
1284
+
1285
+ // Get categories that currently have a ranked board (feeds the category filter)
1286
+ const categories = await rain.getLeaderboardCategories();
1287
+ // categories.data = [{ category: 'CRYPTO', label: 'Crypto' }, ...]
1288
+ // Pass `category` back as the `category` param of getLeaderboard.
1289
+ ```
1290
+
1291
+ **Notes:**
1292
+ - **Units:** every `*USD` number (including `profit` and `score` on the profit board) is **dollars × 1e6** — divide by 1,000,000 to display. E.g. `profit: 887505347` is **$887.51**.
1293
+ - **Monthly window** buckets on when PnL *settled*, not when the position was opened; `window: 'monthly'` always means the current UTC month (`period` reports it as `YYYY-MM`).
1294
+ - **Only positive scores are ranked.** An unknown `category` returns an empty board, not a 400.
1295
+ - **Top-N only** — there is no rank-of-user lookup. Empty `entries` with `lastUpdatedAt: null` means the cron hasn't built the board yet; empty with a timestamp means nobody qualifies.
1296
+ - The client can highlight the viewer's own row by matching `userId` in `entries`.
1297
+
1240
1298
  ---
1241
1299
 
1242
1300
  ## WebSocket Events (Socket.IO)
package/dist/Rain.d.ts CHANGED
@@ -5,7 +5,7 @@ import { RainCoreConfig, RainEnvironment } from './types.js';
5
5
  import { LoginParams, LoginResult } from './auth/types.js';
6
6
  import { SellProceedsResult } from './markets/getSellProceeds.js';
7
7
  import { EntrySharesResult } from './markets/getEntryShares.js';
8
- import type { UserProfileUpdateParams, UserHistoryParams, CreateCommentParams, CommentsListingParams, UpdateCommentParams, CommentCountParams, PublicPoolsParams, PrivatePoolsParams, PoolListingByCreatorParams, VerifyAccessCodeParams, PoolTotalParticipantsParams, SearchPoolParams, RelatedPoolsParams, UpdateStreamingParams, UpdatePoolResolutionTimeParams, FindPoolFallbackParams, SignOraclesExtendTimeParams, TrendingTagsParams, UserTotalInvestmentParams, OptionsTotalVolumeParams, PoolActivityParams, TopHoldersParams, UserInvestedPoolsParams, InvestmentVolumeGraphParams, UserPnlGraphParams, TopWinnersLosersParams, PnlByPoolIdParams, UserPositionsParams, OpenPositionsParams, UserSharePositionsParams, SearchInvestedPoolsParams, PriceDataParams, AddReviewParams, GetUserOrdersParams, OrderBookParams, GetUserOrderByPoolIdParams, OrdersListingByPoolParams, AddUserPointsParams, UserOnboardingParams, PointsGraphParams, GetNotificationsParams, MarkNotificationAsReadParams, CreateDisputeMessageParams, GetPoolDisputeConvoParams, FollowToggleParams, FollowCheckParams, FollowListParams, FollowStatsParams, RainBurnPerPoolParams, ToggleBookmarkParams, GetBookmarksParams, CheckBookmarkParams } from './api/types.js';
8
+ import type { UserProfileUpdateParams, UserHistoryParams, CreateCommentParams, CommentsListingParams, UpdateCommentParams, CommentCountParams, PublicPoolsParams, PrivatePoolsParams, PoolListingByCreatorParams, VerifyAccessCodeParams, PoolTotalParticipantsParams, SearchPoolParams, RelatedPoolsParams, UpdateStreamingParams, UpdatePoolResolutionTimeParams, FindPoolFallbackParams, SignOraclesExtendTimeParams, TrendingTagsParams, UserTotalInvestmentParams, OptionsTotalVolumeParams, PoolActivityParams, TopHoldersParams, UserInvestedPoolsParams, InvestmentVolumeGraphParams, UserPnlGraphParams, TopWinnersLosersParams, PnlByPoolIdParams, UserPositionsParams, OpenPositionsParams, UserSharePositionsParams, SearchInvestedPoolsParams, PriceDataParams, AddReviewParams, GetUserOrdersParams, OrderBookParams, GetUserOrderByPoolIdParams, OrdersListingByPoolParams, AddUserPointsParams, UserOnboardingParams, PointsGraphParams, GetNotificationsParams, MarkNotificationAsReadParams, CreateDisputeMessageParams, GetPoolDisputeConvoParams, FollowToggleParams, FollowCheckParams, FollowListParams, FollowStatsParams, RainBurnPerPoolParams, ToggleBookmarkParams, GetBookmarksParams, CheckBookmarkParams, LeaderboardParams, LeaderboardSearchParams, TraderRecentTradesParams } from './api/types.js';
9
9
  export declare class Rain {
10
10
  readonly environment: RainEnvironment;
11
11
  private readonly marketFactory;
@@ -235,7 +235,7 @@ export declare class Rain {
235
235
  checkTokenExpiration(accessToken: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
236
236
  updatePoolResolutionTime(params: UpdatePoolResolutionTimeParams, accessToken: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
237
237
  findPoolFallback(params: FindPoolFallbackParams, accessToken: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
238
- getTrendingTags(params: TrendingTagsParams, accessToken?: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
238
+ getTrendingTags(params: TrendingTagsParams): Promise<import("./api/types.js").ApiResponse<unknown>>;
239
239
  getFeaturedPools(accessToken?: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
240
240
  getUserTotalInvestment(params: UserTotalInvestmentParams, accessToken: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
241
241
  getOptionsTotalVolume(params: OptionsTotalVolumeParams, accessToken?: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
@@ -292,4 +292,8 @@ export declare class Rain {
292
292
  toggleBookmark(params: ToggleBookmarkParams, accessToken: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
293
293
  getBookmarks(params: GetBookmarksParams, accessToken: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
294
294
  checkBookmark(params: CheckBookmarkParams, accessToken: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
295
+ getLeaderboard(params: LeaderboardParams): Promise<import("./api/types.js").ApiResponse<import("./api/types.js").LeaderboardData>>;
296
+ searchLeaderboard(params: LeaderboardSearchParams): Promise<import("./api/types.js").ApiResponse<import("./api/types.js").LeaderboardSearchData>>;
297
+ getTraderRecentTrades(params: TraderRecentTradesParams): Promise<import("./api/types.js").ApiResponse<import("./api/types.js").TraderRecentTradesData>>;
298
+ getLeaderboardCategories(): Promise<import("./api/types.js").ApiResponse<import("./api/types.js").LeaderboardCategory[]>>;
295
299
  }
package/dist/Rain.js CHANGED
@@ -41,6 +41,7 @@ import * as disputeApi from './api/dispute.js';
41
41
  import * as followApi from './api/follow.js';
42
42
  import * as whitelistedTokensApi from './api/whitelistedTokens.js';
43
43
  import * as bookmarksApi from './api/bookmarks.js';
44
+ import * as leaderboardApi from './api/leaderboard.js';
44
45
  const erc20AllowanceAbi = parseAbi(['function allowance(address owner, address spender) view returns (uint256)']);
45
46
  const factoryViewAbi = parseAbi([
46
47
  'function oracleFixedFee() view returns (uint256)',
@@ -333,8 +334,8 @@ export class Rain {
333
334
  async findPoolFallback(params, accessToken) {
334
335
  return poolsApi.findPoolFallback(params, this.cfg(accessToken));
335
336
  }
336
- async getTrendingTags(params, accessToken) {
337
- return poolsApi.getTrendingTags(params, this.cfg(accessToken));
337
+ async getTrendingTags(params) {
338
+ return poolsApi.getTrendingTags(params, this.cfg());
338
339
  }
339
340
  async getFeaturedPools(accessToken) {
340
341
  return poolsApi.getFeaturedPools(this.cfg(accessToken));
@@ -503,4 +504,17 @@ export class Rain {
503
504
  async checkBookmark(params, accessToken) {
504
505
  return bookmarksApi.checkBookmark(params, this.cfg(accessToken));
505
506
  }
507
+ // ─── Leaderboard ────────────────────────────────────────────────────────────
508
+ async getLeaderboard(params) {
509
+ return leaderboardApi.getLeaderboard(params, this.cfg());
510
+ }
511
+ async searchLeaderboard(params) {
512
+ return leaderboardApi.searchLeaderboard(params, this.cfg());
513
+ }
514
+ async getTraderRecentTrades(params) {
515
+ return leaderboardApi.getTraderRecentTrades(params, this.cfg());
516
+ }
517
+ async getLeaderboardCategories() {
518
+ return leaderboardApi.getLeaderboardCategories(this.cfg());
519
+ }
506
520
  }
@@ -14,3 +14,4 @@ export * from './dispute.js';
14
14
  export * from './follow.js';
15
15
  export * from './whitelistedTokens.js';
16
16
  export * from './bookmarks.js';
17
+ export * from './leaderboard.js';
package/dist/api/index.js CHANGED
@@ -14,3 +14,4 @@ export * from './dispute.js';
14
14
  export * from './follow.js';
15
15
  export * from './whitelistedTokens.js';
16
16
  export * from './bookmarks.js';
17
+ export * from './leaderboard.js';
@@ -0,0 +1,5 @@
1
+ import { ApiConfig, ApiResponse, LeaderboardParams, LeaderboardData, LeaderboardCategory, LeaderboardSearchParams, LeaderboardSearchData, TraderRecentTradesParams, TraderRecentTradesData } from './types.js';
2
+ export declare function getLeaderboard(params: LeaderboardParams, config: ApiConfig): Promise<ApiResponse<LeaderboardData>>;
3
+ export declare function searchLeaderboard(params: LeaderboardSearchParams, config: ApiConfig): Promise<ApiResponse<LeaderboardSearchData>>;
4
+ export declare function getTraderRecentTrades(params: TraderRecentTradesParams, config: ApiConfig): Promise<ApiResponse<TraderRecentTradesData>>;
5
+ export declare function getLeaderboardCategories(config: ApiConfig): Promise<ApiResponse<LeaderboardCategory[]>>;
@@ -0,0 +1,32 @@
1
+ import { buildHeaders, buildQuery, handleResponse } from './helpers.js';
2
+ export async function getLeaderboard(params, config) {
3
+ const qs = buildQuery({ board: params.board, window: params.window, category: params.category, limit: params.limit });
4
+ const res = await fetch(`${config.apiUrl}/leaderboard${qs}`, {
5
+ method: 'GET',
6
+ headers: buildHeaders(config),
7
+ });
8
+ return handleResponse(res);
9
+ }
10
+ export async function searchLeaderboard(params, config) {
11
+ const qs = buildQuery({ q: params.q, board: params.board, window: params.window, category: params.category, limit: params.limit });
12
+ const res = await fetch(`${config.apiUrl}/leaderboard/search${qs}`, {
13
+ method: 'GET',
14
+ headers: buildHeaders(config),
15
+ });
16
+ return handleResponse(res);
17
+ }
18
+ export async function getTraderRecentTrades(params, config) {
19
+ const qs = buildQuery({ limit: params.limit });
20
+ const res = await fetch(`${config.apiUrl}/leaderboard/traders/${encodeURIComponent(params.userId)}/recent-trades${qs}`, {
21
+ method: 'GET',
22
+ headers: buildHeaders(config),
23
+ });
24
+ return handleResponse(res);
25
+ }
26
+ export async function getLeaderboardCategories(config) {
27
+ const res = await fetch(`${config.apiUrl}/leaderboard/categories`, {
28
+ method: 'GET',
29
+ headers: buildHeaders(config),
30
+ });
31
+ return handleResponse(res);
32
+ }
@@ -322,3 +322,141 @@ export interface GetBookmarksParams {
322
322
  export interface CheckBookmarkParams {
323
323
  poolId: string;
324
324
  }
325
+ export type LeaderboardBoard = 'profit' | 'correct_calls';
326
+ export type LeaderboardWindow = 'all_time' | 'monthly';
327
+ export interface LeaderboardParams {
328
+ /** Ranking to serve: net realized PnL, or the weighted correct-calls score. */
329
+ board: LeaderboardBoard;
330
+ /** `all_time` (default) or the current UTC calendar month. */
331
+ window?: LeaderboardWindow;
332
+ /** Market category (case-insensitive). Omit for the global board. Unknown categories return an empty board. */
333
+ category?: string;
334
+ /** Entries to return, up to the stored cap of 100. Default 10. */
335
+ limit?: number;
336
+ }
337
+ export interface LeaderboardEntry {
338
+ rank: number;
339
+ userId: string;
340
+ walletAddress: string | null;
341
+ eoaWalletAddress: string | null;
342
+ /** The ranking key. On `profit`, dollars × 1e6 (divide by 1,000,000 to display); on `correct_calls`, an unscaled weight. */
343
+ score: number;
344
+ positions: number;
345
+ /** Net realized PnL in dollars × 1e6. Present on both boards. */
346
+ profit: number;
347
+ /** Sum of `1 − entryPrice` over winning positions — a weight, not a count. Present on both boards. */
348
+ correctCalls: number;
349
+ /** Resolved directional positions — the denominator of `winRate`. */
350
+ trades: number;
351
+ wins: number;
352
+ /** `wins / trades`, a fraction in [0,1]. */
353
+ winRate: number;
354
+ badge: 'none' | 'blue' | 'gold';
355
+ /** Crowns held on this board and category — the row's crown indicator. */
356
+ categoryCrowns: number;
357
+ /** Newest crowned month in this bucket, `YYYY-MM` (UTC), or null. */
358
+ lastCrownPeriod: string | null;
359
+ /** Crowns held across all boards and categories. */
360
+ crownCount: number;
361
+ marketScore: number;
362
+ costScore: number;
363
+ }
364
+ export interface LeaderboardData {
365
+ board: LeaderboardBoard;
366
+ window: LeaderboardWindow;
367
+ /** Upper-cased matched key, or null for the global board. */
368
+ category: string | null;
369
+ /** Display spelling of the matched category, or null. */
370
+ categoryLabel: string | null;
371
+ /** `YYYY-MM` (UTC) on the monthly window; null on all-time. */
372
+ period: string | null;
373
+ limit: number;
374
+ /** Users ranked in total (before the stored cap). */
375
+ totalRanked: number;
376
+ /** Entry-price basis the correct-calls board was ranked on: `market` or `cost`. */
377
+ priceBasis: 'market' | 'cost';
378
+ entries: LeaderboardEntry[];
379
+ /** When the cron last rebuilt this board; null means never. */
380
+ lastUpdatedAt: string | null;
381
+ }
382
+ export interface LeaderboardCategory {
383
+ /** Upper-cased key — pass this back as `category`. */
384
+ category: string;
385
+ /** First-seen spelling, for display. */
386
+ label: string;
387
+ }
388
+ export interface LeaderboardSearchParams {
389
+ /** Wallet address, address fragment (with or without 0x, prefix/middle/tail), or user id. Case-insensitive substring match. */
390
+ q: string;
391
+ /** Board to search: `profit` or `correct_calls`. */
392
+ board: LeaderboardBoard;
393
+ /** `all_time` (default) or the current UTC calendar month. */
394
+ window?: LeaderboardWindow;
395
+ /** Market category (case-insensitive). Omit for the global board. */
396
+ category?: string;
397
+ /** Results to return, up to 50. Default 10. */
398
+ limit?: number;
399
+ }
400
+ export interface TraderRecentTradesParams {
401
+ /** The trader's user id, as returned in leaderboard entries. */
402
+ userId: string;
403
+ /** Rendered rows to return (a trade carrying more than one side flattens into more than one line), up to 25. Default 5. */
404
+ limit?: number;
405
+ }
406
+ export interface TraderRecentTrade {
407
+ /** Rendered form of `transactionType`: `Buy` or `Sell`. */
408
+ action: 'Buy' | 'Sell';
409
+ transactionType: string;
410
+ origin: 'enter' | 'orderFill';
411
+ transactionHash: string;
412
+ tradedAt: string;
413
+ poolId: string;
414
+ question: string | null;
415
+ poolImage: string | null;
416
+ subPoolId: string | null;
417
+ /** The sub-market — e.g. "Match winner". */
418
+ subQuestion: string | null;
419
+ /** 1 = YES, 2 = NO */
420
+ side: number;
421
+ optionName: string;
422
+ shares: number;
423
+ /** Collateral paid, in dollars × 1e6 (divide by 1,000,000 to display). */
424
+ amountUSD: number;
425
+ /** Collateral paid per share, in (0,1). Null when the recorded ratio is not a price (e.g. a 1:1 AMM entry). */
426
+ pricePerShare: number | null;
427
+ /** `pricePerShare` in cents, for the "9c" label. */
428
+ priceCents: number | null;
429
+ /** `open` = market not resolved; `pending` = won but unclaimed (no PnL yet, never booked as a loss); `settled` = realized. */
430
+ status: 'open' | 'pending' | 'settled';
431
+ /** Always `position` — PnL is per (pool, subPool), not per fill. */
432
+ pnlScope: string;
433
+ /** Realized PnL of the POSITION this trade belongs to, in dollars × 1e6. Null until settled. */
434
+ pnlUSD: number | null;
435
+ /** Resolved-but-unclaimed winnings of the position, in dollars × 1e6. */
436
+ pendingUSD?: number;
437
+ /** Whether the position won, once resolved. */
438
+ won?: boolean;
439
+ }
440
+ export interface TraderRecentTradesData {
441
+ userId: string;
442
+ limit: number;
443
+ /** Most recent directional trades, newest first. */
444
+ trades: TraderRecentTrade[];
445
+ }
446
+ export interface LeaderboardSearchData {
447
+ board: LeaderboardBoard;
448
+ window: LeaderboardWindow;
449
+ category: string | null;
450
+ /** `YYYY-MM` (UTC) on the monthly window; null on all-time. */
451
+ period: string | null;
452
+ query: string;
453
+ /** Board entries the term matched, before `limit`. */
454
+ matched: number;
455
+ /** Board rows searched — the stored depth. With `matched: 0`, lets a client say "not in the top N" rather than "no such trader". */
456
+ searchedTop: number;
457
+ /** Users ranked on this board in total. */
458
+ totalRanked: number;
459
+ lastUpdatedAt: string | null;
460
+ /** Matching board entries — the same objects `getLeaderboard` returns, in rank order. */
461
+ results: LeaderboardEntry[];
462
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rain-sdk-v2",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "type": "module",
5
5
  "description": "Rain SDK V2 — TypeScript SDK for Rain prediction markets on Arbitrum. Market creation, trading, liquidity, order book, split/merge, dispute, and smart account support.",
6
6
  "main": "dist/index.js",