@provable-games/budokan-sdk 0.1.21 → 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.cjs +80 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +80 -3
- package/dist/index.js.map +1 -1
- package/dist/{client-0HDPKrdw.d.cts → player-BUynfv7D.d.cts} +66 -21
- package/dist/{client-0HDPKrdw.d.ts → player-BUynfv7D.d.ts} +66 -21
- package/dist/react.cjs +280 -5
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +45 -2
- package/dist/react.d.ts +45 -2
- package/dist/react.js +281 -7
- package/dist/react.js.map +1 -1
- package/package.json +3 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RpcProvider } from 'starknet';
|
|
2
|
-
import { EntryFee, EntryRequirement
|
|
2
|
+
import { EntryFee, EntryRequirement } from '@provable-games/metagame-sdk';
|
|
3
3
|
|
|
4
4
|
type DataSource = "api" | "rpc";
|
|
5
5
|
interface BudokanClientConfig {
|
|
@@ -111,9 +111,20 @@ interface TournamentListParams {
|
|
|
111
111
|
whitelistedExtensions?: string[];
|
|
112
112
|
includePrizeSummary?: "summary" | boolean;
|
|
113
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Discriminator for `QualificationEntry.qualificationKind`. Picks one of
|
|
116
|
+
* the two terminal variants of the on-chain `QualificationProof` enum
|
|
117
|
+
* (NFT, Extension). `nftTokenId` is populated only for `nft`;
|
|
118
|
+
* `extensionConfig` only for `extension`.
|
|
119
|
+
*/
|
|
120
|
+
type QualificationKind = "nft" | "extension";
|
|
114
121
|
interface QualificationEntry {
|
|
115
122
|
tournamentId: string;
|
|
116
|
-
|
|
123
|
+
qualificationKind: QualificationKind;
|
|
124
|
+
/** Populated when `qualificationKind === "nft"`. u256 token id, decimal string. */
|
|
125
|
+
nftTokenId: string | null;
|
|
126
|
+
/** Populated when `qualificationKind === "extension"`. List of felt252 hex strings. */
|
|
127
|
+
extensionConfig: string[] | null;
|
|
117
128
|
entryCount: number;
|
|
118
129
|
}
|
|
119
130
|
|
|
@@ -141,23 +152,6 @@ interface Registration {
|
|
|
141
152
|
isBanned: boolean;
|
|
142
153
|
}
|
|
143
154
|
|
|
144
|
-
type RewardType = {
|
|
145
|
-
Prize: {
|
|
146
|
-
tokenAddress: string;
|
|
147
|
-
tokenType: string;
|
|
148
|
-
};
|
|
149
|
-
} | {
|
|
150
|
-
EntryFee: EntryFeeRewardType;
|
|
151
|
-
};
|
|
152
|
-
type EntryFeeRewardType = {
|
|
153
|
-
Position: number;
|
|
154
|
-
} | {
|
|
155
|
-
TournamentCreator: Record<string, never>;
|
|
156
|
-
} | {
|
|
157
|
-
GameCreator: Record<string, never>;
|
|
158
|
-
} | {
|
|
159
|
-
Refund: string;
|
|
160
|
-
};
|
|
161
155
|
interface Prize {
|
|
162
156
|
prizeId: string;
|
|
163
157
|
tournamentId: string;
|
|
@@ -174,9 +168,25 @@ interface Prize {
|
|
|
174
168
|
distributionCount: number | null;
|
|
175
169
|
sponsorAddress: string;
|
|
176
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Discriminator for `RewardClaim.claimKind`. Picks one of the six terminal
|
|
173
|
+
* variants of the on-chain `RewardType` enum (Prize::Single, Prize::Distributed,
|
|
174
|
+
* EntryFee::Position / TournamentCreator / GameCreator / Refund). The
|
|
175
|
+
* variant-specific fields below are populated only for the kinds that carry
|
|
176
|
+
* them; the two pure-marker creator kinds leave all four nullable fields null.
|
|
177
|
+
*/
|
|
178
|
+
type RewardClaimKind = "prize_single" | "prize_distributed" | "entry_fee_position" | "entry_fee_tournament_creator" | "entry_fee_game_creator" | "entry_fee_refund";
|
|
177
179
|
interface RewardClaim {
|
|
178
180
|
tournamentId: string;
|
|
179
|
-
|
|
181
|
+
claimKind: RewardClaimKind;
|
|
182
|
+
/** Populated for `prize_single` and `prize_distributed`. Stringified u64. */
|
|
183
|
+
prizeId: string | null;
|
|
184
|
+
/** Populated for `prize_distributed`. */
|
|
185
|
+
payoutIndex: number | null;
|
|
186
|
+
/** Populated for `entry_fee_position`. */
|
|
187
|
+
position: number | null;
|
|
188
|
+
/** Populated for `entry_fee_refund`. felt252 hex string of the game token. */
|
|
189
|
+
refundTokenId: string | null;
|
|
180
190
|
claimed: boolean;
|
|
181
191
|
}
|
|
182
192
|
interface PrizeAggregation {
|
|
@@ -472,4 +482,39 @@ declare class BudokanClient {
|
|
|
472
482
|
*/
|
|
473
483
|
declare function createBudokanClient(config: BudokanClientConfig): BudokanClient;
|
|
474
484
|
|
|
475
|
-
|
|
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 };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RpcProvider } from 'starknet';
|
|
2
|
-
import { EntryFee, EntryRequirement
|
|
2
|
+
import { EntryFee, EntryRequirement } from '@provable-games/metagame-sdk';
|
|
3
3
|
|
|
4
4
|
type DataSource = "api" | "rpc";
|
|
5
5
|
interface BudokanClientConfig {
|
|
@@ -111,9 +111,20 @@ interface TournamentListParams {
|
|
|
111
111
|
whitelistedExtensions?: string[];
|
|
112
112
|
includePrizeSummary?: "summary" | boolean;
|
|
113
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Discriminator for `QualificationEntry.qualificationKind`. Picks one of
|
|
116
|
+
* the two terminal variants of the on-chain `QualificationProof` enum
|
|
117
|
+
* (NFT, Extension). `nftTokenId` is populated only for `nft`;
|
|
118
|
+
* `extensionConfig` only for `extension`.
|
|
119
|
+
*/
|
|
120
|
+
type QualificationKind = "nft" | "extension";
|
|
114
121
|
interface QualificationEntry {
|
|
115
122
|
tournamentId: string;
|
|
116
|
-
|
|
123
|
+
qualificationKind: QualificationKind;
|
|
124
|
+
/** Populated when `qualificationKind === "nft"`. u256 token id, decimal string. */
|
|
125
|
+
nftTokenId: string | null;
|
|
126
|
+
/** Populated when `qualificationKind === "extension"`. List of felt252 hex strings. */
|
|
127
|
+
extensionConfig: string[] | null;
|
|
117
128
|
entryCount: number;
|
|
118
129
|
}
|
|
119
130
|
|
|
@@ -141,23 +152,6 @@ interface Registration {
|
|
|
141
152
|
isBanned: boolean;
|
|
142
153
|
}
|
|
143
154
|
|
|
144
|
-
type RewardType = {
|
|
145
|
-
Prize: {
|
|
146
|
-
tokenAddress: string;
|
|
147
|
-
tokenType: string;
|
|
148
|
-
};
|
|
149
|
-
} | {
|
|
150
|
-
EntryFee: EntryFeeRewardType;
|
|
151
|
-
};
|
|
152
|
-
type EntryFeeRewardType = {
|
|
153
|
-
Position: number;
|
|
154
|
-
} | {
|
|
155
|
-
TournamentCreator: Record<string, never>;
|
|
156
|
-
} | {
|
|
157
|
-
GameCreator: Record<string, never>;
|
|
158
|
-
} | {
|
|
159
|
-
Refund: string;
|
|
160
|
-
};
|
|
161
155
|
interface Prize {
|
|
162
156
|
prizeId: string;
|
|
163
157
|
tournamentId: string;
|
|
@@ -174,9 +168,25 @@ interface Prize {
|
|
|
174
168
|
distributionCount: number | null;
|
|
175
169
|
sponsorAddress: string;
|
|
176
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Discriminator for `RewardClaim.claimKind`. Picks one of the six terminal
|
|
173
|
+
* variants of the on-chain `RewardType` enum (Prize::Single, Prize::Distributed,
|
|
174
|
+
* EntryFee::Position / TournamentCreator / GameCreator / Refund). The
|
|
175
|
+
* variant-specific fields below are populated only for the kinds that carry
|
|
176
|
+
* them; the two pure-marker creator kinds leave all four nullable fields null.
|
|
177
|
+
*/
|
|
178
|
+
type RewardClaimKind = "prize_single" | "prize_distributed" | "entry_fee_position" | "entry_fee_tournament_creator" | "entry_fee_game_creator" | "entry_fee_refund";
|
|
177
179
|
interface RewardClaim {
|
|
178
180
|
tournamentId: string;
|
|
179
|
-
|
|
181
|
+
claimKind: RewardClaimKind;
|
|
182
|
+
/** Populated for `prize_single` and `prize_distributed`. Stringified u64. */
|
|
183
|
+
prizeId: string | null;
|
|
184
|
+
/** Populated for `prize_distributed`. */
|
|
185
|
+
payoutIndex: number | null;
|
|
186
|
+
/** Populated for `entry_fee_position`. */
|
|
187
|
+
position: number | null;
|
|
188
|
+
/** Populated for `entry_fee_refund`. felt252 hex string of the game token. */
|
|
189
|
+
refundTokenId: string | null;
|
|
180
190
|
claimed: boolean;
|
|
181
191
|
}
|
|
182
192
|
interface PrizeAggregation {
|
|
@@ -472,4 +482,39 @@ declare class BudokanClient {
|
|
|
472
482
|
*/
|
|
473
483
|
declare function createBudokanClient(config: BudokanClientConfig): BudokanClient;
|
|
474
484
|
|
|
475
|
-
|
|
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
|
@@ -1114,6 +1114,84 @@ async function viewerPrizes(contract, tournamentId) {
|
|
|
1114
1114
|
return result.map(parsePrize);
|
|
1115
1115
|
}, contract.address);
|
|
1116
1116
|
}
|
|
1117
|
+
function translateCairoRewardType(rewardType) {
|
|
1118
|
+
if (!rewardType || typeof rewardType !== "object") {
|
|
1119
|
+
throw new Error(`Unexpected RewardType payload: ${JSON.stringify(rewardType)}`);
|
|
1120
|
+
}
|
|
1121
|
+
const rt = rewardType;
|
|
1122
|
+
const outer = typeof rt.activeVariant === "function" ? rt.activeVariant() : null;
|
|
1123
|
+
const innerBag = typeof rt.activeVariant === "function" ? rt.variant : rt;
|
|
1124
|
+
if (outer === "Prize" || innerBag.Prize !== void 0) {
|
|
1125
|
+
const prize = innerBag.Prize;
|
|
1126
|
+
const subVariant = typeof prize?.activeVariant === "function" ? prize.activeVariant() : null;
|
|
1127
|
+
const subBag = typeof prize?.activeVariant === "function" ? prize.variant : prize;
|
|
1128
|
+
if (subVariant === "Single" || subBag?.Single !== void 0) {
|
|
1129
|
+
return {
|
|
1130
|
+
claimKind: "prize_single",
|
|
1131
|
+
prizeId: BigInt(subBag.Single).toString(),
|
|
1132
|
+
payoutIndex: null,
|
|
1133
|
+
position: null,
|
|
1134
|
+
refundTokenId: null
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
if (subVariant === "Distributed" || subBag?.Distributed !== void 0) {
|
|
1138
|
+
const distributed = subBag.Distributed;
|
|
1139
|
+
const prizeId = distributed?.["0"] ?? distributed?.[0];
|
|
1140
|
+
const payoutIndex = distributed?.["1"] ?? distributed?.[1];
|
|
1141
|
+
return {
|
|
1142
|
+
claimKind: "prize_distributed",
|
|
1143
|
+
prizeId: BigInt(prizeId).toString(),
|
|
1144
|
+
payoutIndex: Number(payoutIndex),
|
|
1145
|
+
position: null,
|
|
1146
|
+
refundTokenId: null
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
if (outer === "EntryFee" || innerBag.EntryFee !== void 0) {
|
|
1151
|
+
const entryFee = innerBag.EntryFee;
|
|
1152
|
+
const subVariant = typeof entryFee?.activeVariant === "function" ? entryFee.activeVariant() : null;
|
|
1153
|
+
const subBag = typeof entryFee?.activeVariant === "function" ? entryFee.variant : entryFee;
|
|
1154
|
+
if (subVariant === "Position" || subBag?.Position !== void 0) {
|
|
1155
|
+
return {
|
|
1156
|
+
claimKind: "entry_fee_position",
|
|
1157
|
+
prizeId: null,
|
|
1158
|
+
payoutIndex: null,
|
|
1159
|
+
position: Number(subBag.Position),
|
|
1160
|
+
refundTokenId: null
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
if (subVariant === "TournamentCreator" || subBag?.TournamentCreator !== void 0) {
|
|
1164
|
+
return {
|
|
1165
|
+
claimKind: "entry_fee_tournament_creator",
|
|
1166
|
+
prizeId: null,
|
|
1167
|
+
payoutIndex: null,
|
|
1168
|
+
position: null,
|
|
1169
|
+
refundTokenId: null
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
if (subVariant === "GameCreator" || subBag?.GameCreator !== void 0) {
|
|
1173
|
+
return {
|
|
1174
|
+
claimKind: "entry_fee_game_creator",
|
|
1175
|
+
prizeId: null,
|
|
1176
|
+
payoutIndex: null,
|
|
1177
|
+
position: null,
|
|
1178
|
+
refundTokenId: null
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
if (subVariant === "Refund" || subBag?.Refund !== void 0) {
|
|
1182
|
+
return {
|
|
1183
|
+
claimKind: "entry_fee_refund",
|
|
1184
|
+
prizeId: null,
|
|
1185
|
+
payoutIndex: null,
|
|
1186
|
+
position: null,
|
|
1187
|
+
refundTokenId: `0x${BigInt(subBag.Refund).toString(16)}`
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
throw new Error(
|
|
1192
|
+
`Unrecognised on-chain RewardType variant: ${JSON.stringify(rewardType)}`
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1117
1195
|
async function viewerRewardClaims(contract, tournamentId, offset, limit) {
|
|
1118
1196
|
return wrapRpcCall(async () => {
|
|
1119
1197
|
const result = await contract.call("tournament_reward_claims", [tournamentId, offset, limit]);
|
|
@@ -1121,7 +1199,7 @@ async function viewerRewardClaims(contract, tournamentId, offset, limit) {
|
|
|
1121
1199
|
const claims = obj.claims?.map((raw) => {
|
|
1122
1200
|
const claim = raw;
|
|
1123
1201
|
return {
|
|
1124
|
-
|
|
1202
|
+
...translateCairoRewardType(claim.reward_type),
|
|
1125
1203
|
claimed: Boolean(claim.claimed)
|
|
1126
1204
|
};
|
|
1127
1205
|
}) ?? [];
|
|
@@ -4518,8 +4596,7 @@ var BudokanClient = class {
|
|
|
4518
4596
|
const result = await viewerRewardClaims(contract, tournamentId, offset, limit);
|
|
4519
4597
|
const data = result.claims.map((c) => ({
|
|
4520
4598
|
tournamentId,
|
|
4521
|
-
|
|
4522
|
-
claimed: c.claimed
|
|
4599
|
+
...c
|
|
4523
4600
|
}));
|
|
4524
4601
|
return { data, total: result.total, limit, offset };
|
|
4525
4602
|
};
|
|
@@ -4794,7 +4871,6 @@ function useOwnedTournamentIds(owner, contextId) {
|
|
|
4794
4871
|
enabled ? {
|
|
4795
4872
|
owner,
|
|
4796
4873
|
minterAddress: budokanAddress,
|
|
4797
|
-
hasContext: true,
|
|
4798
4874
|
...{},
|
|
4799
4875
|
limit: MAX_OWNED_TOKENS
|
|
4800
4876
|
} : void 0
|
|
@@ -4910,7 +4986,11 @@ function useRegistrationsByOwner(tournamentId, owner, params) {
|
|
|
4910
4986
|
}, [enabled, tokensResult]);
|
|
4911
4987
|
const inner = useRegistrations(
|
|
4912
4988
|
ownedGameTokenIds && ownedGameTokenIds.length > 0 ? tournamentId : void 0,
|
|
4913
|
-
ownedGameTokenIds && ownedGameTokenIds.length > 0 ? {
|
|
4989
|
+
ownedGameTokenIds && ownedGameTokenIds.length > 0 ? {
|
|
4990
|
+
limit: Math.min(ownedGameTokenIds.length, MAX_OWNED_TOKENS),
|
|
4991
|
+
...params,
|
|
4992
|
+
gameTokenIds: ownedGameTokenIds
|
|
4993
|
+
} : void 0
|
|
4914
4994
|
);
|
|
4915
4995
|
if (ownedGameTokenIds !== null && ownedGameTokenIds.length === 0) {
|
|
4916
4996
|
return {
|
|
@@ -5099,6 +5179,200 @@ function useActivityStats() {
|
|
|
5099
5179
|
}, [fetch2]);
|
|
5100
5180
|
return { stats, loading, error, refetch: fetch2 };
|
|
5101
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
|
+
}
|
|
5102
5376
|
function useSubscription(channels, tournamentIds) {
|
|
5103
5377
|
const client = useBudokanClient();
|
|
5104
5378
|
const [lastMessage, setLastMessage] = react.useState(null);
|
|
@@ -5149,6 +5423,7 @@ exports.useActivityStats = useActivityStats;
|
|
|
5149
5423
|
exports.useBudokanClient = useBudokanClient;
|
|
5150
5424
|
exports.useConnectionStatus = useConnectionStatus;
|
|
5151
5425
|
exports.useLeaderboard = useLeaderboard;
|
|
5426
|
+
exports.usePlayerRewards = usePlayerRewards;
|
|
5152
5427
|
exports.usePrizeAggregation = usePrizeAggregation;
|
|
5153
5428
|
exports.usePrizeStats = usePrizeStats;
|
|
5154
5429
|
exports.usePrizes = usePrizes;
|