@provable-games/budokan-sdk 0.1.22 → 0.1.23

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/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as Tournament, P as PrizeAggregation, a as Prize, b as PaginatedResult, Q as QualificationEntry, R as Registration, c as RewardClaim, d as RewardClaimSummary, e as TournamentListParams, f as PlatformStats, g as PrizeStats, W as WSSubscribeOptions, h as WSEventHandler } from './client-DlXvzneQ.cjs';
2
- export { B as BudokanClient, i as BudokanClientConfig, C as ConnectionMode, j as ConnectionStatus, k as ConnectionStatusState, D as DataSource, G as GameConfig, L as LeaderboardConfig, l as LeaderboardEntry, m as Phase, S as Schedule, n as WSChannel, o as WSEventMessage, p as WSMessage, q as WSSubscribeMessage, r as WSUnsubscribeMessage, s as createBudokanClient } from './client-DlXvzneQ.cjs';
1
+ import { T as Tournament, P as PrizeAggregation, a as Prize, b as PaginatedResult, Q as QualificationEntry, R as Registration, c as RewardClaim, d as RewardClaimSummary, e as TournamentListParams, f as PlatformStats, g as PrizeStats, W as WSSubscribeOptions, h as WSEventHandler } from './player-BUynfv7D.cjs';
2
+ export { B as BudokanClient, i as BudokanClientConfig, C as ConnectionMode, j as ConnectionStatus, k as ConnectionStatusState, D as DataSource, G as GameConfig, L as LeaderboardConfig, l as LeaderboardEntry, m as Phase, n as PlayerPlacement, o as PlayerRewards, S as Schedule, p as WSChannel, q as WSEventMessage, r as WSMessage, s as WSSubscribeMessage, t as WSUnsubscribeMessage, u as createBudokanClient } from './player-BUynfv7D.cjs';
3
3
  export { EntryFee } from '@provable-games/metagame-sdk';
4
4
  import 'starknet';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as Tournament, P as PrizeAggregation, a as Prize, b as PaginatedResult, Q as QualificationEntry, R as Registration, c as RewardClaim, d as RewardClaimSummary, e as TournamentListParams, f as PlatformStats, g as PrizeStats, W as WSSubscribeOptions, h as WSEventHandler } from './client-DlXvzneQ.js';
2
- export { B as BudokanClient, i as BudokanClientConfig, C as ConnectionMode, j as ConnectionStatus, k as ConnectionStatusState, D as DataSource, G as GameConfig, L as LeaderboardConfig, l as LeaderboardEntry, m as Phase, S as Schedule, n as WSChannel, o as WSEventMessage, p as WSMessage, q as WSSubscribeMessage, r as WSUnsubscribeMessage, s as createBudokanClient } from './client-DlXvzneQ.js';
1
+ import { T as Tournament, P as PrizeAggregation, a as Prize, b as PaginatedResult, Q as QualificationEntry, R as Registration, c as RewardClaim, d as RewardClaimSummary, e as TournamentListParams, f as PlatformStats, g as PrizeStats, W as WSSubscribeOptions, h as WSEventHandler } from './player-BUynfv7D.js';
2
+ export { B as BudokanClient, i as BudokanClientConfig, C as ConnectionMode, j as ConnectionStatus, k as ConnectionStatusState, D as DataSource, G as GameConfig, L as LeaderboardConfig, l as LeaderboardEntry, m as Phase, n as PlayerPlacement, o as PlayerRewards, S as Schedule, p as WSChannel, q as WSEventMessage, r as WSMessage, s as WSSubscribeMessage, t as WSUnsubscribeMessage, u as createBudokanClient } from './player-BUynfv7D.js';
3
3
  export { EntryFee } from '@provable-games/metagame-sdk';
4
4
  import 'starknet';
5
5
 
@@ -482,4 +482,39 @@ declare class BudokanClient {
482
482
  */
483
483
  declare function createBudokanClient(config: BudokanClientConfig): BudokanClient;
484
484
 
485
- export { BudokanClient as B, type ConnectionMode as C, type DataSource as D, type GameConfig as G, type LeaderboardConfig as L, type PrizeAggregation as P, type QualificationEntry as Q, type Registration as R, type Schedule as S, type Tournament as T, type WSSubscribeOptions as W, type Prize as a, type PaginatedResult as b, type RewardClaim as c, type RewardClaimSummary as d, type TournamentListParams as e, type PlatformStats as f, type PrizeStats as g, type WSEventHandler as h, type BudokanClientConfig as i, ConnectionStatus as j, type ConnectionStatusState as k, type LeaderboardEntry as l, type Phase as m, type WSChannel as n, type WSEventMessage as o, type WSMessage as p, type WSSubscribeMessage as q, type WSUnsubscribeMessage as r, createBudokanClient as s };
485
+ /**
486
+ * One row per (player token, tournament) where the token's final rank fell
487
+ * inside a paid position. Multiple placements per tournament are possible
488
+ * when the player owns several tokens entered into the same tournament.
489
+ */
490
+ interface PlayerPlacement {
491
+ tournamentId: string;
492
+ tokenId: string;
493
+ /** 1-indexed rank in the tournament's final leaderboard. */
494
+ position: number;
495
+ /** Token's final score as a decimal string (preserves felt252 precision). */
496
+ score: string;
497
+ }
498
+ /**
499
+ * Aggregate rewards summary for a player address. Computed against current
500
+ * NFT ownership (denshokan), not historical attribution — see PR #243.
501
+ *
502
+ * `tournaments`, `prizes`, and `rewardClaims` are restricted to tournaments
503
+ * where the player has at least one placement. Consumers compute USD values
504
+ * by walking placements + prize/entry-fee data + token prices client-side.
505
+ */
506
+ interface PlayerRewards {
507
+ /** Count of placements that landed on a paid position. */
508
+ wins: number;
509
+ /** Lowest position number across all placements; null when no wins. */
510
+ bestPlacement: number | null;
511
+ placements: PlayerPlacement[];
512
+ /** Tournaments where the player placed (subset of currently-held entries). */
513
+ tournaments: Tournament[];
514
+ /** All sponsored prizes for those tournaments. */
515
+ prizes: Prize[];
516
+ /** All reward claims for those tournaments. */
517
+ rewardClaims: RewardClaim[];
518
+ }
519
+
520
+ export { BudokanClient as B, type ConnectionMode as C, type DataSource as D, type GameConfig as G, type LeaderboardConfig as L, type PrizeAggregation as P, type QualificationEntry as Q, type Registration as R, type Schedule as S, type Tournament as T, type WSSubscribeOptions as W, type Prize as a, type PaginatedResult as b, type RewardClaim as c, type RewardClaimSummary as d, type TournamentListParams as e, type PlatformStats as f, type PrizeStats as g, type WSEventHandler as h, type BudokanClientConfig as i, ConnectionStatus as j, type ConnectionStatusState as k, type LeaderboardEntry as l, type Phase as m, type PlayerPlacement as n, type PlayerRewards as o, type WSChannel as p, type WSEventMessage as q, type WSMessage as r, type WSSubscribeMessage as s, type WSUnsubscribeMessage as t, createBudokanClient as u };
@@ -482,4 +482,39 @@ declare class BudokanClient {
482
482
  */
483
483
  declare function createBudokanClient(config: BudokanClientConfig): BudokanClient;
484
484
 
485
- export { BudokanClient as B, type ConnectionMode as C, type DataSource as D, type GameConfig as G, type LeaderboardConfig as L, type PrizeAggregation as P, type QualificationEntry as Q, type Registration as R, type Schedule as S, type Tournament as T, type WSSubscribeOptions as W, type Prize as a, type PaginatedResult as b, type RewardClaim as c, type RewardClaimSummary as d, type TournamentListParams as e, type PlatformStats as f, type PrizeStats as g, type WSEventHandler as h, type BudokanClientConfig as i, ConnectionStatus as j, type ConnectionStatusState as k, type LeaderboardEntry as l, type Phase as m, type WSChannel as n, type WSEventMessage as o, type WSMessage as p, type WSSubscribeMessage as q, type WSUnsubscribeMessage as r, createBudokanClient as s };
485
+ /**
486
+ * One row per (player token, tournament) where the token's final rank fell
487
+ * inside a paid position. Multiple placements per tournament are possible
488
+ * when the player owns several tokens entered into the same tournament.
489
+ */
490
+ interface PlayerPlacement {
491
+ tournamentId: string;
492
+ tokenId: string;
493
+ /** 1-indexed rank in the tournament's final leaderboard. */
494
+ position: number;
495
+ /** Token's final score as a decimal string (preserves felt252 precision). */
496
+ score: string;
497
+ }
498
+ /**
499
+ * Aggregate rewards summary for a player address. Computed against current
500
+ * NFT ownership (denshokan), not historical attribution — see PR #243.
501
+ *
502
+ * `tournaments`, `prizes`, and `rewardClaims` are restricted to tournaments
503
+ * where the player has at least one placement. Consumers compute USD values
504
+ * by walking placements + prize/entry-fee data + token prices client-side.
505
+ */
506
+ interface PlayerRewards {
507
+ /** Count of placements that landed on a paid position. */
508
+ wins: number;
509
+ /** Lowest position number across all placements; null when no wins. */
510
+ bestPlacement: number | null;
511
+ placements: PlayerPlacement[];
512
+ /** Tournaments where the player placed (subset of currently-held entries). */
513
+ tournaments: Tournament[];
514
+ /** All sponsored prizes for those tournaments. */
515
+ prizes: Prize[];
516
+ /** All reward claims for those tournaments. */
517
+ rewardClaims: RewardClaim[];
518
+ }
519
+
520
+ export { BudokanClient as B, type ConnectionMode as C, type DataSource as D, type GameConfig as G, type LeaderboardConfig as L, type PrizeAggregation as P, type QualificationEntry as Q, type Registration as R, type Schedule as S, type Tournament as T, type WSSubscribeOptions as W, type Prize as a, type PaginatedResult as b, type RewardClaim as c, type RewardClaimSummary as d, type TournamentListParams as e, type PlatformStats as f, type PrizeStats as g, type WSEventHandler as h, type BudokanClientConfig as i, ConnectionStatus as j, type ConnectionStatusState as k, type LeaderboardEntry as l, type Phase as m, type PlayerPlacement as n, type PlayerRewards as o, type WSChannel as p, type WSEventMessage as q, type WSMessage as r, type WSSubscribeMessage as s, type WSUnsubscribeMessage as t, createBudokanClient as u };
package/dist/react.cjs CHANGED
@@ -4871,7 +4871,6 @@ function useOwnedTournamentIds(owner, contextId) {
4871
4871
  enabled ? {
4872
4872
  owner,
4873
4873
  minterAddress: budokanAddress,
4874
- hasContext: true,
4875
4874
  ...{},
4876
4875
  limit: MAX_OWNED_TOKENS
4877
4876
  } : void 0
@@ -4987,7 +4986,11 @@ function useRegistrationsByOwner(tournamentId, owner, params) {
4987
4986
  }, [enabled, tokensResult]);
4988
4987
  const inner = useRegistrations(
4989
4988
  ownedGameTokenIds && ownedGameTokenIds.length > 0 ? tournamentId : void 0,
4990
- ownedGameTokenIds && ownedGameTokenIds.length > 0 ? { ...params, gameTokenIds: ownedGameTokenIds } : void 0
4989
+ ownedGameTokenIds && ownedGameTokenIds.length > 0 ? {
4990
+ limit: Math.min(ownedGameTokenIds.length, MAX_OWNED_TOKENS),
4991
+ ...params,
4992
+ gameTokenIds: ownedGameTokenIds
4993
+ } : void 0
4991
4994
  );
4992
4995
  if (ownedGameTokenIds !== null && ownedGameTokenIds.length === 0) {
4993
4996
  return {
@@ -5176,6 +5179,200 @@ function useActivityStats() {
5176
5179
  }, [fetch2]);
5177
5180
  return { stats, loading, error, refetch: fetch2 };
5178
5181
  }
5182
+ function usePlayerRewards(address) {
5183
+ const budokan = useBudokanClient();
5184
+ const denshokan = react$1.useDenshokanClient();
5185
+ const budokanAddress = budokan.clientConfig.budokanAddress;
5186
+ const [rewards, setRewards] = react.useState(null);
5187
+ const [aggregating, setAggregating] = react.useState(false);
5188
+ const [error, setError] = react.useState(null);
5189
+ useResetOnClient(budokan, setRewards, setError);
5190
+ const tokensEnabled = !!address && !!budokanAddress;
5191
+ const { data: tokensResult, isLoading: tokensLoading } = react$1.useTokens(
5192
+ tokensEnabled ? {
5193
+ owner: address,
5194
+ minterAddress: budokanAddress,
5195
+ limit: 1e3
5196
+ } : void 0
5197
+ );
5198
+ const tokensByTournament = react.useMemo(() => {
5199
+ if (!tokensResult?.data) return null;
5200
+ const map = /* @__PURE__ */ new Map();
5201
+ for (const t of tokensResult.data) {
5202
+ if (t.contextId == null || !t.tokenId) continue;
5203
+ const tid = String(t.contextId);
5204
+ let list = map.get(tid);
5205
+ if (!list) {
5206
+ list = [];
5207
+ map.set(tid, list);
5208
+ }
5209
+ list.push(t.tokenId);
5210
+ }
5211
+ return map;
5212
+ }, [tokensResult]);
5213
+ const tournamentIds = react.useMemo(
5214
+ () => tokensByTournament ? Array.from(tokensByTournament.keys()) : [],
5215
+ [tokensByTournament]
5216
+ );
5217
+ const { tournaments: tournamentsPage, loading: tournamentsLoading } = useTournaments(
5218
+ tournamentIds.length > 0 ? { tournamentIds, limit: 1e3 } : void 0
5219
+ );
5220
+ const tournamentIdsKey = tournamentIds.join(",");
5221
+ const fetch2 = react.useCallback(async () => {
5222
+ if (!tokensEnabled) {
5223
+ setRewards(null);
5224
+ return;
5225
+ }
5226
+ if (!tokensByTournament) return;
5227
+ if (tokensByTournament.size === 0) {
5228
+ setRewards(emptyRewards());
5229
+ return;
5230
+ }
5231
+ if (!tournamentsPage?.data) return;
5232
+ const now = Math.floor(Date.now() / 1e3);
5233
+ const finalized = tournamentsPage.data.filter((t) => {
5234
+ const sub = Number(t.submissionEndTime ?? 0);
5235
+ return sub > 0 && sub <= now;
5236
+ });
5237
+ if (finalized.length === 0) {
5238
+ setRewards(emptyRewards());
5239
+ return;
5240
+ }
5241
+ setAggregating(true);
5242
+ setError(null);
5243
+ try {
5244
+ const settled = await Promise.allSettled(
5245
+ finalized.map(async (t) => {
5246
+ const tid = t.id;
5247
+ const tokenIds = tokensByTournament.get(tid) ?? [];
5248
+ if (tokenIds.length === 0) return null;
5249
+ const [prizes, allClaims, ranksResult] = await Promise.all([
5250
+ budokan.getTournamentPrizes(tid),
5251
+ fetchAllRewardClaims(budokan, tid),
5252
+ denshokan.getTokenRanks(tokenIds, {
5253
+ contextId: Number(tid),
5254
+ minterAddress: budokanAddress
5255
+ })
5256
+ ]);
5257
+ let maxPaid = 0;
5258
+ for (const p of prizes) {
5259
+ if ((p.payoutPosition ?? 0) > 0) {
5260
+ maxPaid = Math.max(maxPaid, p.payoutPosition);
5261
+ }
5262
+ if ((p.distributionCount ?? 0) > 0) {
5263
+ maxPaid = Math.max(maxPaid, p.distributionCount);
5264
+ }
5265
+ }
5266
+ const efDistCount = Number(t.entryFee?.distributionCount ?? 0);
5267
+ if (efDistCount > 0) maxPaid = Math.max(maxPaid, efDistCount);
5268
+ if (maxPaid === 0) return null;
5269
+ const placements = ranksResult.data.filter((r) => r.rank > 0 && r.rank <= maxPaid).map((r) => ({
5270
+ tournamentId: tid,
5271
+ tokenId: r.tokenId,
5272
+ position: r.rank,
5273
+ score: String(r.score ?? "0")
5274
+ }));
5275
+ if (placements.length === 0) return null;
5276
+ return {
5277
+ tournament: t,
5278
+ prizes,
5279
+ rewardClaims: allClaims,
5280
+ placements
5281
+ };
5282
+ })
5283
+ );
5284
+ const valid = settled.map((s, i) => {
5285
+ if (s.status === "fulfilled") return s.value;
5286
+ console.warn(
5287
+ `usePlayerRewards: tournament ${finalized[i].id} fetch failed; skipping`,
5288
+ s.reason
5289
+ );
5290
+ return null;
5291
+ }).filter((r) => r !== null);
5292
+ const allPlacements = valid.flatMap(
5293
+ (r) => r.placements
5294
+ );
5295
+ const wins = allPlacements.length;
5296
+ const bestPlacement = wins > 0 ? Math.min(...allPlacements.map((p) => p.position)) : null;
5297
+ const tournamentsList = valid.map((r) => r.tournament);
5298
+ const prizesList = valid.flatMap((r) => r.prizes);
5299
+ const rewardClaimsList = valid.flatMap(
5300
+ (r) => r.rewardClaims
5301
+ );
5302
+ setRewards({
5303
+ wins,
5304
+ bestPlacement,
5305
+ placements: allPlacements,
5306
+ tournaments: tournamentsList,
5307
+ prizes: prizesList,
5308
+ rewardClaims: rewardClaimsList
5309
+ });
5310
+ } catch (e) {
5311
+ setError(e);
5312
+ } finally {
5313
+ setAggregating(false);
5314
+ }
5315
+ }, [
5316
+ tokensEnabled,
5317
+ tokensByTournament,
5318
+ tournamentsPage,
5319
+ tournamentIdsKey,
5320
+ budokan,
5321
+ denshokan,
5322
+ budokanAddress
5323
+ ]);
5324
+ const lastRunRef = react.useRef("");
5325
+ react.useEffect(() => {
5326
+ if (!tokensEnabled) {
5327
+ setRewards(null);
5328
+ return;
5329
+ }
5330
+ if (!tokensByTournament || !tournamentsPage?.data) return;
5331
+ const fingerprint = `${address}|${tournamentIdsKey}|${tournamentsPage.data.length}`;
5332
+ if (fingerprint === lastRunRef.current) return;
5333
+ lastRunRef.current = fingerprint;
5334
+ fetch2();
5335
+ }, [
5336
+ address,
5337
+ tokensEnabled,
5338
+ tokensByTournament,
5339
+ tournamentsPage,
5340
+ tournamentIdsKey,
5341
+ fetch2
5342
+ ]);
5343
+ const loading = tokensEnabled && (tokensLoading || tournamentsLoading) || aggregating;
5344
+ return { rewards, loading, error, refetch: fetch2 };
5345
+ }
5346
+ function emptyRewards() {
5347
+ return {
5348
+ wins: 0,
5349
+ bestPlacement: null,
5350
+ placements: [],
5351
+ tournaments: [],
5352
+ prizes: [],
5353
+ rewardClaims: []
5354
+ };
5355
+ }
5356
+ async function fetchAllRewardClaims(client, tournamentId) {
5357
+ const first = await client.getTournamentRewardClaims(tournamentId, {
5358
+ limit: 100
5359
+ });
5360
+ const accumulated = [...first.data];
5361
+ const total = first.total ?? accumulated.length;
5362
+ if (accumulated.length >= total) return accumulated;
5363
+ const pageSize = Math.max(first.data.length, 1);
5364
+ let offset = accumulated.length;
5365
+ while (offset < total) {
5366
+ const next = await client.getTournamentRewardClaims(tournamentId, {
5367
+ limit: pageSize,
5368
+ offset
5369
+ });
5370
+ if (next.data.length === 0) break;
5371
+ accumulated.push(...next.data);
5372
+ offset += next.data.length;
5373
+ }
5374
+ return accumulated;
5375
+ }
5179
5376
  function useSubscription(channels, tournamentIds) {
5180
5377
  const client = useBudokanClient();
5181
5378
  const [lastMessage, setLastMessage] = react.useState(null);
@@ -5226,6 +5423,7 @@ exports.useActivityStats = useActivityStats;
5226
5423
  exports.useBudokanClient = useBudokanClient;
5227
5424
  exports.useConnectionStatus = useConnectionStatus;
5228
5425
  exports.useLeaderboard = useLeaderboard;
5426
+ exports.usePlayerRewards = usePlayerRewards;
5229
5427
  exports.usePrizeAggregation = usePrizeAggregation;
5230
5428
  exports.usePrizeStats = usePrizeStats;
5231
5429
  exports.usePrizes = usePrizes;