@provable-games/metagame-sdk 0.1.1 → 0.1.2
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 +0 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -35
- package/dist/index.d.ts +24 -35
- package/dist/index.js +1 -66
- package/dist/index.js.map +1 -1
- package/dist/{prizeAggregation-CBHLCs6D.d.cts → prizeAggregation-CHwIJzXr.d.cts} +1 -7
- package/dist/{prizeAggregation-CBHLCs6D.d.ts → prizeAggregation-CHwIJzXr.d.ts} +1 -7
- package/dist/react.cjs +0 -67
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +3 -8
- package/dist/react.d.ts +3 -8
- package/dist/react.js +0 -67
- package/dist/react.js.map +1 -1
- package/package.json +10 -10
package/dist/react.cjs
CHANGED
|
@@ -494,45 +494,6 @@ function evaluateTokenQualification(input) {
|
|
|
494
494
|
totalEntriesLeft
|
|
495
495
|
};
|
|
496
496
|
}
|
|
497
|
-
function evaluateAllowlistQualification(input) {
|
|
498
|
-
const isInAllowlist = input.allowlist.some(
|
|
499
|
-
(addr) => addr.toLowerCase() === input.playerAddress.toLowerCase()
|
|
500
|
-
);
|
|
501
|
-
if (!isInAllowlist) {
|
|
502
|
-
return {
|
|
503
|
-
meetsRequirements: false,
|
|
504
|
-
bestProof: null,
|
|
505
|
-
qualifications: [],
|
|
506
|
-
totalEntriesLeft: 0
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
const remaining = input.entryLimit > 0 ? input.entryLimit - input.currentEntryCount : Infinity;
|
|
510
|
-
if (remaining <= 0) {
|
|
511
|
-
return {
|
|
512
|
-
meetsRequirements: false,
|
|
513
|
-
bestProof: null,
|
|
514
|
-
qualifications: [],
|
|
515
|
-
totalEntriesLeft: 0
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
const proof = {
|
|
519
|
-
type: "allowlist",
|
|
520
|
-
address: input.playerAddress
|
|
521
|
-
};
|
|
522
|
-
return {
|
|
523
|
-
meetsRequirements: true,
|
|
524
|
-
bestProof: proof,
|
|
525
|
-
qualifications: [
|
|
526
|
-
{
|
|
527
|
-
id: `allowlist-${input.playerAddress}`,
|
|
528
|
-
entriesLeft: remaining,
|
|
529
|
-
proof,
|
|
530
|
-
label: "Allowlist"
|
|
531
|
-
}
|
|
532
|
-
],
|
|
533
|
-
totalEntriesLeft: remaining === Infinity ? 1 : remaining
|
|
534
|
-
};
|
|
535
|
-
}
|
|
536
497
|
function evaluateExtensionQualification(input) {
|
|
537
498
|
const qualifications = input.checkedQualifications.filter((q) => q.entriesLeft > 0).map((q) => ({
|
|
538
499
|
id: q.id,
|
|
@@ -566,8 +527,6 @@ function useEntryQualification(options) {
|
|
|
566
527
|
ownedTokenIds = [],
|
|
567
528
|
tokenEntryCounts = {},
|
|
568
529
|
playerAddress,
|
|
569
|
-
allowlist = [],
|
|
570
|
-
addressEntryCount = 0,
|
|
571
530
|
extensionQualifications = [],
|
|
572
531
|
tournamentValidatorConfig,
|
|
573
532
|
extensionValidEntry = false,
|
|
@@ -598,30 +557,6 @@ function useEntryQualification(options) {
|
|
|
598
557
|
entriesLeftBySource: result.meetsRequirements ? [{ sourceType: "token", entriesLeft: result.totalEntriesLeft }] : []
|
|
599
558
|
};
|
|
600
559
|
}
|
|
601
|
-
if (variant === "allowlist") {
|
|
602
|
-
if (!playerAddress) {
|
|
603
|
-
return empty();
|
|
604
|
-
}
|
|
605
|
-
const result = evaluateAllowlistQualification({
|
|
606
|
-
playerAddress,
|
|
607
|
-
allowlist,
|
|
608
|
-
currentEntryCount: addressEntryCount,
|
|
609
|
-
entryLimit
|
|
610
|
-
});
|
|
611
|
-
return {
|
|
612
|
-
meetsRequirements: result.meetsRequirements,
|
|
613
|
-
bestProof: result.bestProof,
|
|
614
|
-
qualifications: result.qualifications,
|
|
615
|
-
totalEntriesLeft: result.totalEntriesLeft,
|
|
616
|
-
entriesLeftBySource: result.meetsRequirements ? [
|
|
617
|
-
{
|
|
618
|
-
sourceType: "allowlist",
|
|
619
|
-
sourceId: playerAddress,
|
|
620
|
-
entriesLeft: result.totalEntriesLeft === Infinity ? Infinity : result.totalEntriesLeft
|
|
621
|
-
}
|
|
622
|
-
] : []
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
560
|
if (variant === "extension") {
|
|
626
561
|
if (!playerAddress) {
|
|
627
562
|
return empty();
|
|
@@ -678,8 +613,6 @@ function useEntryQualification(options) {
|
|
|
678
613
|
ownedTokenIds,
|
|
679
614
|
tokenEntryCounts,
|
|
680
615
|
playerAddress,
|
|
681
|
-
allowlist,
|
|
682
|
-
addressEntryCount,
|
|
683
616
|
extensionQualifications,
|
|
684
617
|
tournamentValidatorConfig,
|
|
685
618
|
extensionValidEntry,
|
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/useDebounce.ts","../src/react/usePagination.ts","../src/react/useSearchFilter.ts","../src/react/useTokenSelector.ts","../src/utils/status.ts","../src/react/useStatusIndicator.ts","../src/react/useScoreTable.ts","../src/utils/prizeAggregation.ts","../src/react/usePrizeTable.ts","../src/utils/entryFee.ts","../src/utils/formatting.ts","../src/react/useEntryFeePreview.ts","../src/utils/qualification.ts","../src/react/useEntryQualification.ts","../src/rpc/extensions.ts","../src/react/useExtensionQualification.ts","../src/utils/opusTroves.ts","../src/react/useOpusTrovesBannableEntries.ts"],"names":["useState","useEffect","useMemo","useCallback","CallData","useRef"],"mappings":"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","file":"react.cjs","sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport function useDebounce<T>(value: T, delay: number): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n useEffect(() => {\n const handler = setTimeout(() => {\n setDebouncedValue(value);\n }, delay);\n\n return () => {\n clearTimeout(handler);\n };\n }, [value, delay]);\n\n return debouncedValue;\n}\n","import { useState, useMemo, useCallback } from \"react\";\n\nexport interface UsePaginationOptions {\n totalItems: number;\n pageSize?: number;\n}\n\nexport interface UsePaginationReturn {\n currentPage: number;\n totalPages: number;\n hasNext: boolean;\n hasPrev: boolean;\n next: () => void;\n prev: () => void;\n reset: () => void;\n startIndex: number;\n endIndex: number;\n}\n\nexport function usePagination({\n totalItems,\n pageSize = 10,\n}: UsePaginationOptions): UsePaginationReturn {\n const [currentPage, setCurrentPage] = useState(0);\n\n const totalPages = useMemo(\n () => Math.max(1, Math.ceil(totalItems / pageSize)),\n [totalItems, pageSize],\n );\n\n const hasNext = currentPage < totalPages - 1;\n const hasPrev = currentPage > 0;\n\n const next = useCallback(() => {\n setCurrentPage((p) => Math.min(p + 1, totalPages - 1));\n }, [totalPages]);\n\n const prev = useCallback(() => {\n setCurrentPage((p) => Math.max(p - 1, 0));\n }, []);\n\n const reset = useCallback(() => {\n setCurrentPage(0);\n }, []);\n\n const startIndex = currentPage * pageSize;\n const endIndex = Math.min(startIndex + pageSize, totalItems);\n\n return {\n currentPage,\n totalPages,\n hasNext,\n hasPrev,\n next,\n prev,\n reset,\n startIndex,\n endIndex,\n };\n}\n","import { useState, useMemo } from \"react\";\nimport { useDebounce } from \"./useDebounce\";\n\nexport interface UseSearchFilterOptions<T> {\n items: T[];\n searchFields: (keyof T)[];\n debounceMs?: number;\n}\n\nexport interface UseSearchFilterReturn<T> {\n search: string;\n setSearch: (q: string) => void;\n filteredItems: T[];\n resultCount: number;\n}\n\nexport function useSearchFilter<T>({\n items,\n searchFields,\n debounceMs = 300,\n}: UseSearchFilterOptions<T>): UseSearchFilterReturn<T> {\n const [search, setSearch] = useState(\"\");\n const debouncedSearch = useDebounce(search, debounceMs);\n\n const filteredItems = useMemo(() => {\n if (!debouncedSearch) return items;\n const lower = debouncedSearch.toLowerCase();\n return items.filter((item) =>\n searchFields.some((field) => {\n const value = item[field];\n if (typeof value === \"string\") {\n return value.toLowerCase().includes(lower);\n }\n if (typeof value === \"number\") {\n return String(value).includes(lower);\n }\n return false;\n }),\n );\n }, [items, debouncedSearch, searchFields]);\n\n return {\n search,\n setSearch,\n filteredItems,\n resultCount: filteredItems.length,\n };\n}\n","import { useState, useMemo, useCallback } from \"react\";\nimport type { Token } from \"../types/token\";\nimport { useDebounce } from \"./useDebounce\";\nimport { usePagination, type UsePaginationReturn } from \"./usePagination\";\n\nexport interface UseTokenSelectorOptions {\n tokens: Token[];\n tokenType?: \"erc20\" | \"erc721\";\n pageSize?: number;\n debounceMs?: number;\n}\n\nexport interface UseTokenSelectorReturn {\n search: string;\n setSearch: (q: string) => void;\n filteredTokens: Token[];\n selectedToken: Token | null;\n select: (token: Token) => void;\n clear: () => void;\n isSelected: (token: Token) => boolean;\n pagination: UsePaginationReturn;\n getTokenProps: (token: Token) => {\n onClick: () => void;\n \"data-selected\": boolean;\n role: \"option\";\n \"aria-selected\": boolean;\n };\n}\n\nexport function useTokenSelector({\n tokens,\n tokenType,\n pageSize = 10,\n debounceMs = 300,\n}: UseTokenSelectorOptions): UseTokenSelectorReturn {\n const [search, setSearchRaw] = useState(\"\");\n const [selectedToken, setSelectedToken] = useState<Token | null>(null);\n const debouncedSearch = useDebounce(search, debounceMs);\n\n const allFiltered = useMemo(() => {\n let result = tokens;\n if (tokenType) {\n result = result.filter((t) => t.tokenType === tokenType);\n }\n if (debouncedSearch) {\n const lower = debouncedSearch.toLowerCase();\n result = result.filter(\n (t) =>\n t.name.toLowerCase().includes(lower) ||\n t.symbol.toLowerCase().includes(lower) ||\n t.address.toLowerCase().includes(lower),\n );\n }\n return result;\n }, [tokens, tokenType, debouncedSearch]);\n\n const pagination = usePagination({\n totalItems: allFiltered.length,\n pageSize,\n });\n\n const filteredTokens = useMemo(\n () => allFiltered.slice(pagination.startIndex, pagination.endIndex),\n [allFiltered, pagination.startIndex, pagination.endIndex],\n );\n\n const setSearch = useCallback(\n (q: string) => {\n setSearchRaw(q);\n pagination.reset();\n },\n [pagination],\n );\n\n const select = useCallback((token: Token) => {\n setSelectedToken(token);\n }, []);\n\n const clear = useCallback(() => {\n setSelectedToken(null);\n }, []);\n\n const isSelected = useCallback(\n (token: Token) =>\n selectedToken?.address === token.address,\n [selectedToken],\n );\n\n const getTokenProps = useCallback(\n (token: Token) => ({\n onClick: () => select(token),\n \"data-selected\": isSelected(token),\n role: \"option\" as const,\n \"aria-selected\": isSelected(token),\n }),\n [select, isSelected],\n );\n\n return {\n search,\n setSearch,\n filteredTokens,\n selectedToken,\n select,\n clear,\n isSelected,\n pagination,\n getTokenProps,\n };\n}\n","import type { StatusTimestamps, StatusResult } from \"../types/status\";\n\nexport function computeStatus(\n timestamps: StatusTimestamps,\n now?: number,\n): StatusResult {\n const currentTimestamp = now ?? Math.floor(Date.now() / 1000);\n\n // Quest-specific: locked state\n if (timestamps.unlocked === false) {\n return {\n label: \"Locked\",\n variant: \"locked\",\n isActive: false,\n countdown: null,\n };\n }\n\n // Quest-specific: completed state\n if (timestamps.completed) {\n return {\n label: \"Completed\",\n variant: \"completed\",\n isActive: false,\n countdown: null,\n };\n }\n\n const { registrationStart, registrationEnd, start, end, submissionEnd } =\n timestamps;\n\n // Registration phase\n if (registrationStart && registrationEnd) {\n if (currentTimestamp < registrationStart) {\n return {\n label: \"Upcoming\",\n variant: \"upcoming\",\n isActive: false,\n countdown: {\n targetTimestamp: registrationStart,\n label: \"Registration\",\n },\n };\n }\n if (\n currentTimestamp >= registrationStart &&\n currentTimestamp < registrationEnd\n ) {\n return {\n label: \"Registration\",\n variant: \"registration\",\n isActive: true,\n countdown: { targetTimestamp: registrationEnd, label: \"Closes\" },\n };\n }\n }\n\n // Before start\n if (currentTimestamp < start) {\n return {\n label: \"Upcoming\",\n variant: \"upcoming\",\n isActive: false,\n countdown: { targetTimestamp: start, label: \"Starts\" },\n };\n }\n\n // Active / Live\n if (currentTimestamp >= start && currentTimestamp < end) {\n return {\n label: \"Live\",\n variant: \"active\",\n isActive: true,\n countdown: { targetTimestamp: end, label: \"Ends\" },\n };\n }\n\n // Submission phase\n if (submissionEnd && currentTimestamp >= end && currentTimestamp < submissionEnd) {\n return {\n label: \"Submission\",\n variant: \"submission\",\n isActive: true,\n countdown: { targetTimestamp: submissionEnd, label: \"Submit\" },\n };\n }\n\n // Ended\n return {\n label: \"Ended\",\n variant: \"ended\",\n isActive: false,\n countdown: null,\n };\n}\n","import { useState, useEffect } from \"react\";\nimport type { StatusTimestamps, StatusResult } from \"../types/status\";\nimport { computeStatus } from \"../utils/status\";\n\nexport function useStatusIndicator(\n timestamps: StatusTimestamps,\n refreshMs = 1000,\n): StatusResult {\n const [now, setNow] = useState(() => Math.floor(Date.now() / 1000));\n\n useEffect(() => {\n const interval = setInterval(() => {\n setNow(Math.floor(Date.now() / 1000));\n }, refreshMs);\n return () => clearInterval(interval);\n }, [refreshMs]);\n\n return computeStatus(timestamps, now);\n}\n","import { useState, useMemo, useCallback } from \"react\";\nimport type { Participant } from \"../types/participant\";\nimport { usePagination, type UsePaginationReturn } from \"./usePagination\";\nimport { useDebounce } from \"./useDebounce\";\n\ntype SortField = \"rank\" | \"score\" | \"name\";\ntype SortDirection = \"asc\" | \"desc\";\n\nexport interface UseScoreTableOptions {\n participants: Participant[];\n pageSize?: number;\n sortField?: SortField;\n sortDirection?: SortDirection;\n}\n\nexport interface UseScoreTableReturn {\n rows: Participant[];\n pagination: UsePaginationReturn;\n sort: { field: SortField; direction: SortDirection };\n setSort: (field: string) => void;\n search: string;\n setSearch: (q: string) => void;\n}\n\nexport function useScoreTable({\n participants,\n pageSize = 10,\n sortField = \"rank\",\n sortDirection = \"asc\",\n}: UseScoreTableOptions): UseScoreTableReturn {\n const [sort, setSortState] = useState<{\n field: SortField;\n direction: SortDirection;\n }>({ field: sortField, direction: sortDirection });\n\n const [search, setSearchRaw] = useState(\"\");\n const debouncedSearch = useDebounce(search, 300);\n\n const filtered = useMemo(() => {\n if (!debouncedSearch) return participants;\n const lower = debouncedSearch.toLowerCase();\n return participants.filter(\n (p) =>\n p.address.toLowerCase().includes(lower) ||\n (p.name && p.name.toLowerCase().includes(lower)),\n );\n }, [participants, debouncedSearch]);\n\n const sorted = useMemo(() => {\n const arr = [...filtered];\n const dir = sort.direction === \"asc\" ? 1 : -1;\n arr.sort((a, b) => {\n const aVal = a[sort.field] ?? 0;\n const bVal = b[sort.field] ?? 0;\n if (typeof aVal === \"string\" && typeof bVal === \"string\") {\n return dir * aVal.localeCompare(bVal);\n }\n return dir * (Number(aVal) - Number(bVal));\n });\n return arr;\n }, [filtered, sort]);\n\n const pagination = usePagination({\n totalItems: sorted.length,\n pageSize,\n });\n\n const rows = useMemo(\n () => sorted.slice(pagination.startIndex, pagination.endIndex),\n [sorted, pagination.startIndex, pagination.endIndex],\n );\n\n const setSort = useCallback(\n (field: string) => {\n const validField = field as SortField;\n setSortState((prev) => {\n if (prev.field === validField) {\n return {\n field: validField,\n direction: prev.direction === \"asc\" ? \"desc\" : \"asc\",\n };\n }\n return { field: validField, direction: \"asc\" };\n });\n },\n [],\n );\n\n const setSearch = useCallback(\n (q: string) => {\n setSearchRaw(q);\n pagination.reset();\n },\n [pagination],\n );\n\n return {\n rows,\n pagination,\n sort,\n setSort,\n search,\n setSearch,\n };\n}\n","import type { Prize } from \"../types/prize\";\n\n/**\n * Prize aggregation by position.\n *\n * Groups prizes by position, summing ERC20 amounts and collecting ERC721 IDs.\n * Works with Prize — metagame apps adapt their raw prize data to this\n * shape before calling these functions.\n */\n\nexport interface PositionPrizeGroup {\n position: number;\n erc20: Array<{ tokenAddress: string; totalAmount: bigint }>;\n erc721: Array<{ tokenAddress: string; tokenIds: string[] }>;\n}\n\n/**\n * Group prizes by leaderboard position, aggregating ERC20 amounts and\n * collecting ERC721 token IDs per position.\n */\nexport function aggregatePrizesByPosition(\n prizes: Prize[],\n): PositionPrizeGroup[] {\n const positionMap = new Map<number, {\n erc20Map: Map<string, bigint>;\n erc721Map: Map<string, string[]>;\n }>();\n\n for (const prize of prizes) {\n if (!positionMap.has(prize.position)) {\n positionMap.set(prize.position, {\n erc20Map: new Map(),\n erc721Map: new Map(),\n });\n }\n const group = positionMap.get(prize.position)!;\n\n if (prize.tokenType === \"erc20\") {\n const current = group.erc20Map.get(prize.tokenAddress) ?? 0n;\n group.erc20Map.set(prize.tokenAddress, current + BigInt(prize.amount));\n } else {\n const ids = group.erc721Map.get(prize.tokenAddress) ?? [];\n ids.push(prize.id);\n group.erc721Map.set(prize.tokenAddress, ids);\n }\n }\n\n return Array.from(positionMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([position, { erc20Map, erc721Map }]) => ({\n position,\n erc20: Array.from(erc20Map.entries()).map(([tokenAddress, totalAmount]) => ({\n tokenAddress,\n totalAmount,\n })),\n erc721: Array.from(erc721Map.entries()).map(([tokenAddress, tokenIds]) => ({\n tokenAddress,\n tokenIds,\n })),\n }));\n}\n\n/**\n * Sponsor contribution aggregated from prizes.\n */\nexport interface SponsorContribution {\n sponsorAddress: string;\n tokens: Array<{\n tokenAddress: string;\n totalAmount: bigint;\n prizeCount: number;\n }>;\n /** NFT collections grouped by token address, with individual token IDs */\n nftCollections: Array<{\n tokenAddress: string;\n tokenIds: string[];\n }>;\n nftCount: number;\n totalPrizeCount: number;\n}\n\n/**\n * Group prizes by sponsor address, aggregating ERC20 contributions and\n * grouping NFTs by collection. Filters out prizes with no sponsor\n * (address \"0x0\" or empty).\n *\n * For ERC721 prizes, `prize.amount` is expected to hold the token ID\n * (this is the convention set by the prize adapter).\n *\n * @param prizes - Array of Prize with sponsorAddress populated\n * @returns Sponsor contributions sorted by total prize count (descending)\n */\nexport function aggregatePrizesBySponsor(\n prizes: Prize[],\n): SponsorContribution[] {\n const sponsorMap = new Map<string, {\n erc20Map: Map<string, { amount: bigint; count: number }>;\n nftMap: Map<string, string[]>;\n nftCount: number;\n totalCount: number;\n }>();\n\n for (const prize of prizes) {\n if (!prize.sponsorAddress || prize.sponsorAddress === \"0x0\") continue;\n\n if (!sponsorMap.has(prize.sponsorAddress)) {\n sponsorMap.set(prize.sponsorAddress, {\n erc20Map: new Map(),\n nftMap: new Map(),\n nftCount: 0,\n totalCount: 0,\n });\n }\n const sponsor = sponsorMap.get(prize.sponsorAddress)!;\n sponsor.totalCount++;\n\n if (prize.tokenType === \"erc20\") {\n const current = sponsor.erc20Map.get(prize.tokenAddress) ?? {\n amount: 0n,\n count: 0,\n };\n sponsor.erc20Map.set(prize.tokenAddress, {\n amount: current.amount + BigInt(prize.amount),\n count: current.count + 1,\n });\n } else {\n sponsor.nftCount++;\n const ids = sponsor.nftMap.get(prize.tokenAddress) ?? [];\n ids.push(prize.amount); // For ERC721, amount holds the token ID\n sponsor.nftMap.set(prize.tokenAddress, ids);\n }\n }\n\n return Array.from(sponsorMap.entries())\n .map(([sponsorAddress, { erc20Map, nftMap, nftCount, totalCount }]) => ({\n sponsorAddress,\n tokens: Array.from(erc20Map.entries()).map(\n ([tokenAddress, { amount, count }]) => ({\n tokenAddress,\n totalAmount: amount,\n prizeCount: count,\n }),\n ),\n nftCollections: Array.from(nftMap.entries()).map(\n ([tokenAddress, tokenIds]) => ({\n tokenAddress,\n tokenIds,\n }),\n ),\n nftCount,\n totalPrizeCount: totalCount,\n }))\n .sort((a, b) => b.totalPrizeCount - a.totalPrizeCount);\n}\n\n/**\n * Filter prizes to only those not yet claimed.\n *\n * @param prizes - All prizes the user could potentially claim\n * @param claimedIds - Set of prize IDs already claimed\n * @returns Prizes not yet claimed\n */\nexport function filterClaimablePrizes(\n prizes: Prize[],\n claimedIds: Set<string>,\n): Prize[] {\n return prizes.filter((prize) => !claimedIds.has(prize.id));\n}\n\n/**\n * Filter out ERC20 prizes with zero amount.\n */\nexport function filterZeroPrizes(prizes: Prize[]): Prize[] {\n return prizes.filter((prize) => {\n if (prize.tokenType === \"erc20\") {\n return BigInt(prize.amount) > 0n;\n }\n return true; // Keep all NFTs\n });\n}\n","import { useMemo } from \"react\";\nimport { usePagination, type UsePaginationReturn } from \"./usePagination\";\nimport type { Prize } from \"../types/prize\";\nimport {\n aggregatePrizesByPosition,\n type PositionPrizeGroup,\n} from \"../utils/prizeAggregation\";\n\nexport interface UsePrizeTableOptions {\n prizes: Prize[];\n positionsPerPage?: number;\n}\n\nexport interface UsePrizeTableReturn {\n /** Prize groups for the current page, sorted by position */\n rows: PositionPrizeGroup[];\n /** Total number of positions across all prizes */\n totalPositions: number;\n /** Pagination state and controls */\n pagination: UsePaginationReturn;\n}\n\n/**\n * Headless hook for displaying a paginated prize table.\n *\n * Aggregates prizes by position (summing ERC20 amounts, grouping ERC721 IDs),\n * then paginates the position groups. Metagame UIs render each position group\n * however they like — the hook only manages data and pagination state.\n */\nexport function usePrizeTable({\n prizes,\n positionsPerPage = 5,\n}: UsePrizeTableOptions): UsePrizeTableReturn {\n const grouped = useMemo(() => aggregatePrizesByPosition(prizes), [prizes]);\n\n const pagination = usePagination({\n totalItems: grouped.length,\n pageSize: positionsPerPage,\n });\n\n const rows = useMemo(\n () => grouped.slice(pagination.startIndex, pagination.endIndex),\n [grouped, pagination.startIndex, pagination.endIndex],\n );\n\n return {\n rows,\n totalPositions: grouped.length,\n pagination,\n };\n}\n","/**\n * Entry fee breakdown calculation.\n *\n * Takes a total fee pool and share percentages (in basis points, where 10000 = 100%)\n * and returns the amount allocated to each bucket.\n *\n * This is the same math that on-chain metagame contracts use to split entry fees\n * between creator, game creator, refund pool, and prize pool.\n */\n\nexport interface EntryFeeBreakdown {\n /** Total fee collected from all entrants */\n totalCollected: bigint;\n /** Amount going to the metagame creator */\n creatorAmount: bigint;\n /** Amount going to the game creator */\n gameCreatorAmount: bigint;\n /** Amount reserved for refunds */\n refundAmount: bigint;\n /** Amount available for prize distribution */\n prizePoolAmount: bigint;\n}\n\nexport interface EntryFeeShares {\n /** Creator share in basis points (0-10000) */\n creatorShare: number;\n /** Game creator share in basis points (0-10000) */\n gameCreatorShare: number;\n /** Refund share in basis points (0-10000) */\n refundShare: number;\n}\n\n/**\n * Calculate how an entry fee pool is split between creator, game, refund, and prizes.\n *\n * @param feePerEntry - Fee amount per entry (in token units, as bigint)\n * @param entryCount - Number of entries\n * @param shares - Share percentages in basis points (10000 = 100%)\n * @returns Breakdown of amounts for each bucket\n */\nexport function calculateEntryFeeBreakdown(\n feePerEntry: bigint,\n entryCount: number,\n shares: EntryFeeShares,\n): EntryFeeBreakdown {\n const totalCollected = feePerEntry * BigInt(entryCount);\n\n if (totalCollected === 0n) {\n return {\n totalCollected: 0n,\n creatorAmount: 0n,\n gameCreatorAmount: 0n,\n refundAmount: 0n,\n prizePoolAmount: 0n,\n };\n }\n\n const creatorAmount =\n shares.creatorShare > 0\n ? (totalCollected * BigInt(shares.creatorShare)) / 10000n\n : 0n;\n\n const gameCreatorAmount =\n shares.gameCreatorShare > 0\n ? (totalCollected * BigInt(shares.gameCreatorShare)) / 10000n\n : 0n;\n\n const refundAmount =\n shares.refundShare > 0\n ? (totalCollected * BigInt(shares.refundShare)) / 10000n\n : 0n;\n\n const prizePoolBps =\n 10000 - shares.creatorShare - shares.gameCreatorShare - shares.refundShare;\n const prizePoolAmount =\n prizePoolBps > 0 ? (totalCollected * BigInt(prizePoolBps)) / 10000n : 0n;\n\n return {\n totalCollected,\n creatorAmount,\n gameCreatorAmount,\n refundAmount,\n prizePoolAmount,\n };\n}\n\n/**\n * Distribute a prize pool across positions using a distribution curve.\n *\n * Takes the prize pool amount and distribution percentages (from calculateDistribution),\n * and returns the actual token amount per position.\n *\n * @param prizePoolAmount - Total pool to distribute (bigint, in smallest token units)\n * @param percentages - Distribution percentages per position (from calculateDistribution)\n * @returns Array of { position, amount } where position is 1-indexed\n */\nexport function distributePool(\n prizePoolAmount: bigint,\n percentages: number[],\n): Array<{ position: number; amount: bigint }> {\n return percentages\n .map((pct, index) => ({\n position: index + 1,\n amount:\n (prizePoolAmount * BigInt(Math.floor(pct * 100))) / 10000n,\n }))\n .filter((entry) => entry.amount > 0n);\n}\n","export function formatNumber(num: number): string {\n if (Math.abs(num) >= 1000000) {\n return parseFloat((num / 1000000).toFixed(2)) + \"m\";\n } else if (Math.abs(num) >= 1000) {\n return parseFloat((num / 1000).toFixed(2)) + \"k\";\n } else if (Math.abs(num) >= 1) {\n return num.toFixed(0);\n } else if (Math.abs(num) >= 0.1) {\n return num.toFixed(1);\n } else if (Math.abs(num) >= 0.01) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 0.001) {\n return num.toFixed(3);\n } else if (num === 0) {\n return \"0\";\n } else {\n return num.toFixed(4);\n }\n}\n\nexport function formatPrizeAmount(num: number): string {\n if (Math.abs(num) >= 1000000) {\n return parseFloat((num / 1000000).toFixed(2)) + \"m\";\n } else if (Math.abs(num) >= 1000) {\n return parseFloat((num / 1000).toFixed(2)) + \"k\";\n } else if (Math.abs(num) >= 100) {\n return num.toFixed(1);\n } else if (Math.abs(num) >= 10) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 1) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 0.1) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 0.01) {\n return num.toFixed(3);\n } else if (Math.abs(num) >= 0.001) {\n return num.toFixed(4);\n } else if (num === 0) {\n return \"0\";\n } else {\n return num.toFixed(5);\n }\n}\n\nexport function formatUsdValue(value: number): string {\n if (value === 0) return \"0.00\";\n if (value < 0.01 && value > 0) return \"<0.01\";\n return value.toFixed(2);\n}\n\nexport function formatScore(num: number): string {\n if (Math.abs(num) >= 1000000) {\n return parseFloat((num / 1000000).toFixed(2)) + \"m\";\n } else if (Math.abs(num) >= 1000) {\n return parseFloat((num / 1000).toFixed(2)) + \"k\";\n } else if (Math.abs(num) >= 10) {\n return num.toFixed(0);\n } else if (Math.abs(num) > 0) {\n return num.toFixed(0);\n } else {\n return \"0\";\n }\n}\n\nexport function formatTime(seconds: number): string {\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days} Day${days > 1 ? \"s\" : \"\"}`;\n } else if (hours > 0) {\n return `${hours} Hour${hours > 1 ? \"s\" : \"\"}`;\n } else if (minutes > 0) {\n return `${minutes} Min${minutes > 1 ? \"s\" : \"\"}`;\n } else {\n return `${seconds.toFixed(0)} Sec${seconds > 1 ? \"s\" : \"\"}`;\n }\n}\n\nexport function getOrdinalSuffix(position: number): string {\n const formatPosition = isNaN(position) ? 0 : position;\n if (formatPosition % 10 === 1 && formatPosition !== 11) return \"st\";\n if (formatPosition % 10 === 2 && formatPosition !== 12) return \"nd\";\n if (position % 10 === 3 && position !== 13) return \"rd\";\n return \"th\";\n}\n\nexport type DistributionType = \"linear\" | \"exponential\" | \"uniform\";\n\nexport function calculatePayouts(\n totalPlaces: number,\n weightingFactor: number,\n): number[] {\n const weights: number[] = [];\n for (let i = 1; i <= totalPlaces; i++) {\n weights.push(1 / Math.pow(i, weightingFactor));\n }\n\n const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);\n\n const payouts: number[] = weights.map((weight) =>\n Math.floor((weight / totalWeight) * 100),\n );\n\n const totalPayout = payouts.reduce((sum, payout) => sum + payout, 0);\n\n let remaining = 100 - totalPayout;\n let index = 0;\n while (remaining > 0) {\n payouts[index] += 1;\n remaining -= 1;\n index = (index + 1) % totalPlaces;\n }\n\n return payouts;\n}\n\nexport function calculateDistribution(\n positions: number,\n weight: number,\n creatorFee?: number,\n gameFee?: number,\n refundShare?: number,\n distributionType: DistributionType = \"exponential\",\n): number[] {\n if (positions <= 0) {\n return [];\n }\n\n const safeCreatorFee = creatorFee ?? 0;\n const safeGameFee = gameFee ?? 0;\n const safeRefundShare = refundShare ?? 0;\n const prizePoolPercentage =\n 100 - safeCreatorFee - safeGameFee - safeRefundShare;\n\n if (prizePoolPercentage <= 0) {\n return Array(positions).fill(0);\n }\n\n let rawDistributions: number[] = [];\n\n if (distributionType === \"uniform\") {\n rawDistributions = Array(positions).fill(1);\n } else if (distributionType === \"linear\") {\n for (let i = 0; i < positions; i++) {\n const positionValue = positions - i;\n const share = 1 + (positionValue - 1) * (weight / 10);\n rawDistributions.push(share);\n }\n } else {\n for (let i = 0; i < positions; i++) {\n const share = Math.pow(1 - i / positions, weight);\n rawDistributions.push(share);\n }\n }\n\n const total = rawDistributions.reduce((a, b) => a + b, 0);\n\n if (total === 0) {\n return Array(positions).fill(0);\n }\n\n const basisPointShares = rawDistributions.map((d) => {\n const ratio = d / total;\n const basisPoints = ratio * 10000;\n return Math.floor(basisPoints);\n });\n\n const totalBasisPoints = basisPointShares.reduce((a, b) => a + b, 0);\n const remainingBasisPoints = 10000 - totalBasisPoints;\n\n if (remainingBasisPoints !== 0 && positions > 0) {\n basisPointShares[0] = basisPointShares[0] + remainingBasisPoints;\n }\n\n return basisPointShares.map((bp) => bp / 100);\n}\n","import { useMemo } from \"react\";\nimport {\n calculateEntryFeeBreakdown,\n distributePool,\n type EntryFeeBreakdown,\n type EntryFeeShares,\n} from \"../utils/entryFee\";\nimport {\n calculateDistribution,\n type DistributionType,\n} from \"../utils/formatting\";\n\nexport interface UseEntryFeePreviewOptions {\n /** Fee per entry in smallest token units (as bigint) */\n feePerEntry: bigint;\n /** Expected number of entries (for preview) */\n entryCount: number;\n /** Share percentages in basis points */\n shares: EntryFeeShares;\n /** Number of positions to distribute prizes across */\n distributionPositions: number;\n /** Distribution curve type */\n distributionType: DistributionType;\n /** Weight for linear/exponential curves */\n distributionWeight: number;\n}\n\nexport interface UseEntryFeePreviewReturn {\n /** Breakdown of total fees into creator/game/refund/pool buckets */\n breakdown: EntryFeeBreakdown;\n /** Per-position prize amounts from the pool */\n positionPrizes: Array<{ position: number; amount: bigint }>;\n /** Distribution percentages per position (0-100 scale) */\n percentages: number[];\n}\n\n/**\n * Headless hook for live entry fee breakdown preview.\n *\n * As form values change (fee amount, shares, distribution curve),\n * this hook recomputes the full breakdown and per-position prizes.\n * Useful for \"create tournament/quest\" forms where you want to show\n * the user a live preview of how entry fees will be distributed.\n */\nexport function useEntryFeePreview({\n feePerEntry,\n entryCount,\n shares,\n distributionPositions,\n distributionType,\n distributionWeight,\n}: UseEntryFeePreviewOptions): UseEntryFeePreviewReturn {\n const breakdown = useMemo(\n () => calculateEntryFeeBreakdown(feePerEntry, entryCount, shares),\n [feePerEntry, entryCount, shares.creatorShare, shares.gameCreatorShare, shares.refundShare],\n );\n\n const percentages = useMemo(\n () =>\n distributionPositions > 0\n ? calculateDistribution(\n distributionPositions,\n distributionWeight,\n 0,\n 0,\n 0,\n distributionType,\n )\n : [],\n [distributionPositions, distributionWeight, distributionType],\n );\n\n const positionPrizes = useMemo(\n () => distributePool(breakdown.prizePoolAmount, percentages),\n [breakdown.prizePoolAmount, percentages],\n );\n\n return { breakdown, positionPrizes, percentages };\n}\n","/**\n * Entry qualification evaluation.\n *\n * Pure functions that determine whether a user qualifies to enter a metagame\n * event based on pre-fetched data. Each metagame fetches the data through\n * their own SDK, then passes it here for evaluation.\n *\n * The evaluation logic is the same across metagames because the entry\n * requirement system (token gating, allowlists, extensions) is shared.\n */\n\nimport type {\n EntryRequirementVariant,\n QualificationResult,\n QualificationEntry,\n QualificationProof,\n} from \"../types/extensions\";\n\n// ---------------------------------------------------------------------------\n// Token-based qualification (NFT ownership)\n// ---------------------------------------------------------------------------\n\nexport interface TokenQualificationInput {\n /** NFT token IDs owned by the player */\n ownedTokenIds: string[];\n /** Number of times each token has been used to enter (tokenId → count) */\n usedEntryCounts: Record<string, number>;\n /** Max entries per token (0 = unlimited) */\n entryLimit: number;\n}\n\n/**\n * Evaluate token-based entry qualification.\n *\n * Checks if the player owns any qualifying NFTs and how many entries\n * remain for each. Selects the token with the most entries remaining\n * as the best proof.\n */\nexport function evaluateTokenQualification(\n input: TokenQualificationInput,\n): QualificationResult {\n if (input.ownedTokenIds.length === 0) {\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n };\n }\n\n const qualifications: QualificationEntry[] = [];\n\n for (const tokenId of input.ownedTokenIds) {\n const usedCount = input.usedEntryCounts[tokenId] ?? 0;\n const remaining =\n input.entryLimit > 0 ? input.entryLimit - usedCount : Infinity;\n\n if (remaining > 0) {\n qualifications.push({\n id: `token-${tokenId}`,\n entriesLeft: remaining,\n proof: { type: \"token\", tokenId },\n label: `Token #${tokenId}`,\n metadata: { tokenId },\n });\n }\n }\n\n const totalEntriesLeft = qualifications.reduce(\n (sum, q) => sum + (q.entriesLeft === Infinity ? 1 : q.entriesLeft),\n 0,\n );\n\n const best =\n qualifications.length > 0\n ? qualifications.reduce((a, b) =>\n b.entriesLeft > a.entriesLeft ? b : a,\n )\n : null;\n\n return {\n meetsRequirements: qualifications.length > 0,\n bestProof: best?.proof ?? null,\n qualifications,\n totalEntriesLeft,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Allowlist-based qualification\n// ---------------------------------------------------------------------------\n\nexport interface AllowlistQualificationInput {\n /** The player's address */\n playerAddress: string;\n /** Addresses on the allowlist */\n allowlist: string[];\n /** How many times this address has already entered */\n currentEntryCount: number;\n /** Max entries per address (0 = unlimited) */\n entryLimit: number;\n}\n\n/**\n * Evaluate allowlist-based entry qualification.\n */\nexport function evaluateAllowlistQualification(\n input: AllowlistQualificationInput,\n): QualificationResult {\n const isInAllowlist = input.allowlist.some(\n (addr) => addr.toLowerCase() === input.playerAddress.toLowerCase(),\n );\n\n if (!isInAllowlist) {\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n };\n }\n\n const remaining =\n input.entryLimit > 0\n ? input.entryLimit - input.currentEntryCount\n : Infinity;\n\n if (remaining <= 0) {\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n };\n }\n\n const proof: QualificationProof = {\n type: \"allowlist\",\n address: input.playerAddress,\n };\n\n return {\n meetsRequirements: true,\n bestProof: proof,\n qualifications: [\n {\n id: `allowlist-${input.playerAddress}`,\n entriesLeft: remaining,\n proof,\n label: \"Allowlist\",\n },\n ],\n totalEntriesLeft: remaining === Infinity ? 1 : remaining,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Extension-based qualification\n// ---------------------------------------------------------------------------\n\nexport interface ExtensionQualificationInput {\n /** Results from checking each qualification method against the extension contract */\n checkedQualifications: Array<{\n id: string;\n entriesLeft: number;\n proof: string[];\n label?: string;\n metadata?: Record<string, unknown>;\n }>;\n}\n\n/**\n * Evaluate extension-based entry qualification from pre-checked results.\n *\n * Each metagame calls the extension contract's `entries_left` function\n * for each potential qualification proof, then passes the results here.\n * This function aggregates and selects the best qualification.\n */\nexport function evaluateExtensionQualification(\n input: ExtensionQualificationInput,\n): QualificationResult {\n const qualifications: QualificationEntry[] = input.checkedQualifications\n .filter((q) => q.entriesLeft > 0)\n .map((q) => ({\n id: q.id,\n entriesLeft: q.entriesLeft,\n proof: {\n type: \"extension\" as const,\n extensionProof: q.proof,\n },\n label: q.label,\n metadata: q.metadata,\n }));\n\n const totalEntriesLeft = qualifications.reduce(\n (sum, q) => sum + q.entriesLeft,\n 0,\n );\n\n const best =\n qualifications.length > 0\n ? qualifications.reduce((a, b) =>\n b.entriesLeft > a.entriesLeft ? b : a,\n )\n : null;\n\n return {\n meetsRequirements: qualifications.length > 0,\n bestProof: best?.proof ?? null,\n qualifications,\n totalEntriesLeft,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Combined qualification\n// ---------------------------------------------------------------------------\n\n/**\n * Evaluate entry qualification based on requirement variant.\n *\n * This is the top-level function — pass in the requirement type and\n * the appropriate input, get back a unified QualificationResult.\n */\nexport function evaluateQualification(\n variant: EntryRequirementVariant,\n input:\n | { type: \"token\"; data: TokenQualificationInput }\n | { type: \"allowlist\"; data: AllowlistQualificationInput }\n | { type: \"extension\"; data: ExtensionQualificationInput }\n | { type: \"none\" },\n): QualificationResult {\n if (variant === \"none\" || input.type === \"none\") {\n return {\n meetsRequirements: true,\n bestProof: null,\n qualifications: [\n {\n id: \"no-requirement\",\n entriesLeft: Infinity,\n proof: { type: \"none\" },\n },\n ],\n totalEntriesLeft: Infinity,\n };\n }\n\n switch (input.type) {\n case \"token\":\n return evaluateTokenQualification(input.data);\n case \"allowlist\":\n return evaluateAllowlistQualification(input.data);\n case \"extension\":\n return evaluateExtensionQualification(input.data);\n default:\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n };\n }\n}\n","import { useMemo } from \"react\";\nimport type {\n EntryRequirementVariant,\n QualificationResult,\n QualificationProof,\n TournamentValidatorConfig,\n} from \"../types/extensions\";\nimport {\n evaluateTokenQualification,\n evaluateAllowlistQualification,\n evaluateExtensionQualification,\n} from \"../utils/qualification\";\n\n/**\n * A potential qualification the user has — e.g., an owned NFT, a tournament\n * they won, their address being on the allowlist.\n */\nexport interface QualificationMethod {\n /** Unique ID for deduplication */\n id: string;\n /** The proof to submit if this method is used */\n proof: QualificationProof;\n /** Human-readable label */\n label?: string;\n /** Additional display metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Pre-checked extension result from calling the extension contract.\n * Each metagame calls `entries_left` on-chain and passes results here.\n */\nexport interface CheckedExtensionQualification {\n id: string;\n entriesLeft: number;\n proof: string[];\n label?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UseEntryQualificationOptions {\n /** The type of entry requirement */\n variant: EntryRequirementVariant;\n\n // --- Token gating inputs ---\n /** NFT token IDs owned by the player */\n ownedTokenIds?: string[];\n /** How many times each token has been used (tokenId → count) */\n tokenEntryCounts?: Record<string, number>;\n\n // --- Allowlist inputs ---\n /** The player's address */\n playerAddress?: string;\n /** Addresses on the allowlist */\n allowlist?: string[];\n /** How many times this address has already entered */\n addressEntryCount?: number;\n\n // --- Extension inputs ---\n /** Pre-checked results from calling extension contract */\n extensionQualifications?: CheckedExtensionQualification[];\n /** For tournament validator: the parsed config */\n tournamentValidatorConfig?: TournamentValidatorConfig | null;\n /** For generic extensions: whether the contract says entry is valid */\n extensionValidEntry?: boolean;\n /** For generic extensions: entries left from contract */\n extensionEntriesLeft?: number | null;\n\n // --- Common ---\n /** Max entries allowed (0 = unlimited) */\n entryLimit?: number;\n}\n\nexport interface UseEntryQualificationReturn {\n /** Whether the user meets the entry requirements */\n meetsRequirements: boolean;\n /** The best proof to use for entering */\n bestProof: QualificationProof | null;\n /** All valid qualification methods */\n qualifications: QualificationResult[\"qualifications\"];\n /** Total entries remaining */\n totalEntriesLeft: number;\n /** Entries remaining grouped by source (tournament ID, token address, etc.) */\n entriesLeftBySource: Array<{\n sourceId?: string;\n sourceType?: string;\n entriesLeft: number;\n }>;\n}\n\n/**\n * Headless hook that evaluates whether a user qualifies to enter a\n * metagame event. Works for all requirement types (token, allowlist,\n * extension).\n *\n * Each metagame fetches the data through their own SDK (owned NFTs,\n * registrations, extension contract calls), then passes it here.\n * The evaluation logic is the same across all metagames.\n *\n * @example\n * ```tsx\n * const { meetsRequirements, bestProof, entriesLeftBySource } = useEntryQualification({\n * variant: \"token\",\n * ownedTokenIds: [\"123\", \"456\"],\n * tokenEntryCounts: { \"123\": 2, \"456\": 0 },\n * entryLimit: 3,\n * });\n *\n * // To enter, serialize the proof:\n * const onChainProof = buildQualificationProof(bestProof);\n * ```\n */\nexport function useEntryQualification(\n options: UseEntryQualificationOptions,\n): UseEntryQualificationReturn {\n const {\n variant,\n ownedTokenIds = [],\n tokenEntryCounts = {},\n playerAddress,\n allowlist = [],\n addressEntryCount = 0,\n extensionQualifications = [],\n tournamentValidatorConfig,\n extensionValidEntry = false,\n extensionEntriesLeft = null,\n entryLimit = 0,\n } = options;\n\n return useMemo(() => {\n // No requirement — always qualifies\n if (variant === \"none\") {\n return {\n meetsRequirements: true,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: Infinity,\n entriesLeftBySource: [{ entriesLeft: Infinity }],\n };\n }\n\n // Token-based (NFT ownership)\n if (variant === \"token\") {\n const result = evaluateTokenQualification({\n ownedTokenIds,\n usedEntryCounts: tokenEntryCounts,\n entryLimit,\n });\n\n return {\n meetsRequirements: result.meetsRequirements,\n bestProof: result.bestProof,\n qualifications: result.qualifications,\n totalEntriesLeft: result.totalEntriesLeft,\n entriesLeftBySource: result.meetsRequirements\n ? [{ sourceType: \"token\", entriesLeft: result.totalEntriesLeft }]\n : [],\n };\n }\n\n // Allowlist\n if (variant === \"allowlist\") {\n if (!playerAddress) {\n return empty();\n }\n\n const result = evaluateAllowlistQualification({\n playerAddress,\n allowlist,\n currentEntryCount: addressEntryCount,\n entryLimit,\n });\n\n return {\n meetsRequirements: result.meetsRequirements,\n bestProof: result.bestProof,\n qualifications: result.qualifications,\n totalEntriesLeft: result.totalEntriesLeft,\n entriesLeftBySource: result.meetsRequirements\n ? [\n {\n sourceType: \"allowlist\",\n sourceId: playerAddress,\n entriesLeft:\n result.totalEntriesLeft === Infinity\n ? Infinity\n : result.totalEntriesLeft,\n },\n ]\n : [],\n };\n }\n\n // Extension\n if (variant === \"extension\") {\n if (!playerAddress) {\n return empty();\n }\n\n // Tournament validator extension\n if (tournamentValidatorConfig && extensionQualifications.length > 0) {\n const result = evaluateExtensionQualification({\n checkedQualifications: extensionQualifications,\n });\n\n // Group entries by tournament/source\n const entriesBySource = new Map<string, number>();\n for (const qual of extensionQualifications) {\n if (qual.entriesLeft <= 0) continue;\n const sourceId =\n (qual.metadata?.tournamentId as string) ?? qual.id;\n const current = entriesBySource.get(sourceId) ?? 0;\n entriesBySource.set(sourceId, current + qual.entriesLeft);\n }\n\n // Check qualifying mode — modes 2, 4, 5 require ALL tournaments\n const qualifyingMode = tournamentValidatorConfig.qualifyingMode;\n let meetsRequirements: boolean;\n if (\n qualifyingMode === 0 ||\n qualifyingMode === 1 ||\n qualifyingMode === 3\n ) {\n meetsRequirements = result.meetsRequirements;\n } else {\n // Must have qualifications for every required tournament\n meetsRequirements =\n entriesBySource.size >=\n tournamentValidatorConfig.tournamentIds.length;\n }\n\n return {\n meetsRequirements,\n bestProof: result.bestProof,\n qualifications: result.qualifications,\n totalEntriesLeft: result.totalEntriesLeft,\n entriesLeftBySource: Array.from(entriesBySource.entries()).map(\n ([sourceId, entriesLeft]) => ({\n sourceId,\n sourceType: \"tournament\",\n entriesLeft,\n }),\n ),\n };\n }\n\n // Generic extension\n const remaining =\n extensionEntriesLeft !== null ? extensionEntriesLeft : Infinity;\n\n if (extensionValidEntry && remaining > 0) {\n return {\n meetsRequirements: true,\n bestProof: { type: \"extension\", extensionProof: [] },\n qualifications: [],\n totalEntriesLeft: remaining,\n entriesLeftBySource: [\n { sourceType: \"extension\", entriesLeft: remaining },\n ],\n };\n }\n\n return empty();\n }\n\n return empty();\n }, [\n variant,\n ownedTokenIds,\n tokenEntryCounts,\n playerAddress,\n allowlist,\n addressEntryCount,\n extensionQualifications,\n tournamentValidatorConfig,\n extensionValidEntry,\n extensionEntriesLeft,\n entryLimit,\n ]);\n}\n\nfunction empty(): UseEntryQualificationReturn {\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n entriesLeftBySource: [],\n };\n}\n","/**\n * RPC calls for EGS entry requirement extensions.\n *\n * These functions call the shared extension contracts on Starknet.\n * They take a starknet.js provider (or any object with callContract)\n * and return parsed results.\n *\n * Every metagame that uses the entry requirement system needs these\n * same calls — they're not app-specific, they call the same contracts.\n */\n\nimport { CallData, type BigNumberish } from \"starknet\";\n\n/** Minimal provider interface — anything with callContract works */\nexport interface StarknetCallProvider {\n callContract(call: {\n contractAddress: string;\n entrypoint: string;\n calldata: string[];\n }): Promise<string[]>;\n}\n\n// ---------------------------------------------------------------------------\n// Extension contract calls (IEntryRequirementExtension)\n// ---------------------------------------------------------------------------\n\n/**\n * Check if a player has a valid entry for an extension-gated event.\n *\n * Calls `valid_entry(context_id, player_address, qualification)` on the\n * extension contract.\n *\n * @param provider - Starknet RPC provider\n * @param extensionAddress - The extension contract address\n * @param contextId - The metagame event ID (tournament ID, quest ID, etc.)\n * @param playerAddress - The player's address\n * @param qualification - Proof data (felt252 array)\n * @returns Whether the entry is valid\n */\nexport async function checkExtensionValidEntry(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n playerAddress: string,\n qualification: string[],\n): Promise<boolean> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"valid_entry\",\n calldata: CallData.compile([contextId, playerAddress, qualification]),\n });\n return result[0] === \"0x1\" || BigInt(result[0]) === 1n;\n } catch (error) {\n console.error(\"Error checking extension valid_entry:\", error);\n return false;\n }\n}\n\n/**\n * Get the number of entries left for a player via an extension.\n *\n * Calls `entries_left(context_id, player_address, qualification)` on the\n * extension contract. Returns null if the extension has no entry limit\n * (Option::None).\n *\n * @returns Number of entries remaining, or null if unlimited\n */\nexport async function getExtensionEntriesLeft(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n playerAddress: string,\n qualification: string[],\n): Promise<number | null> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"entries_left\",\n calldata: CallData.compile([contextId, playerAddress, qualification]),\n });\n\n // Result is Option<u8>\n // Option::None: result[0] is 1\n // Option::Some: result[0] is 0, result[1] is the value\n if (result[0] === \"0x1\" || BigInt(result[0]) === 1n) {\n return null; // No limit\n }\n return Number(result[1]);\n } catch (error) {\n console.error(\"Error checking extension entries_left:\", error);\n return null;\n }\n}\n\n/**\n * Check if a player's entry should be banned via an extension.\n *\n * Calls `should_ban(context_id, game_token_id, current_owner, proof)`.\n *\n * @param gameTokenId - The game token ID to check (felt252)\n * @param currentOwner - Current owner of the game token\n * @param proof - Ban proof data (felt252 array)\n * @returns Whether the entry should be banned\n */\nexport async function checkExtensionShouldBan(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n gameTokenId: string,\n currentOwner: string,\n proof: string[],\n): Promise<boolean> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"should_ban\",\n calldata: CallData.compile([contextId, gameTokenId, currentOwner, proof]),\n });\n return result[0] === \"0x1\" || BigInt(result[0]) === 1n;\n } catch (error) {\n console.error(\"Error checking extension should_ban:\", error);\n return false;\n }\n}\n\n/**\n * Get the context owner for an entry requirement extension contract.\n *\n * Extensions are multi-tenant: each context_id has its own owner\n * (set by the first caller to configure that context via add_config).\n *\n * @param provider - Starknet RPC provider\n * @param extensionAddress - The extension contract address\n * @param contextId - The metagame event ID (tournament ID, quest ID, etc.)\n * @returns The owner address for that context, or empty string if unclaimed\n */\nexport async function getEntryRequirementContextOwner(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n): Promise<string> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"context_owner\",\n calldata: CallData.compile([contextId]),\n });\n return result[0] ?? \"\";\n } catch (error) {\n console.error(\"Error checking extension context_owner:\", error);\n return \"\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Opus Protocol calls (for Opus Troves extension)\n// ---------------------------------------------------------------------------\n\n/** Mainnet Opus Abbot contract address */\nconst OPUS_ABBOT_ADDRESS =\n \"0x04d0bb0a4c40012384e7c419e6eb3c637b28e8363fb66958b60d90505b9c072f\";\n\n/** Mainnet Opus Shrine contract address */\nconst OPUS_SHRINE_ADDRESS =\n \"0x0498edfaf50ca5855666a700c25dd629d577eb9afccdf3b5977aec79aee55ada\";\n\n/**\n * Get all trove IDs owned by a user from the Opus Abbot contract.\n *\n * @param provider - Starknet RPC provider\n * @param userAddress - The user's address\n * @param abbotAddress - Override Abbot address (defaults to mainnet)\n * @returns Array of trove IDs\n */\nexport async function getUserTroveIds(\n provider: StarknetCallProvider,\n userAddress: BigNumberish,\n abbotAddress: string = OPUS_ABBOT_ADDRESS,\n): Promise<bigint[]> {\n try {\n const result = await provider.callContract({\n contractAddress: abbotAddress,\n entrypoint: \"get_user_trove_ids\",\n calldata: CallData.compile([userAddress]),\n });\n\n // Result: [array_length, ...trove_ids]\n const arrayLength = Number(result[0] || 0);\n const troveIds: bigint[] = [];\n for (let i = 1; i <= arrayLength; i++) {\n troveIds.push(BigInt(result[i] || 0));\n }\n return troveIds;\n } catch (error) {\n console.error(\"Error getting user trove IDs:\", error);\n return [];\n }\n}\n\n/**\n * Get a trove's debt from the Opus Shrine contract.\n *\n * Calls `get_trove_health(trove_id)` which returns [value, threshold, ltv, debt].\n * We extract the debt (18 decimals, denominated in CASH which is 1:1 USD).\n *\n * @param provider - Starknet RPC provider\n * @param troveId - The trove ID\n * @param shrineAddress - Override Shrine address (defaults to mainnet)\n * @returns Debt amount in CASH (18 decimals), or null on error\n */\nexport async function getTroveDebt(\n provider: StarknetCallProvider,\n troveId: BigNumberish,\n shrineAddress: string = OPUS_SHRINE_ADDRESS,\n): Promise<bigint | null> {\n try {\n const result = await provider.callContract({\n contractAddress: shrineAddress,\n entrypoint: \"get_trove_health\",\n calldata: CallData.compile([troveId]),\n });\n return BigInt(result[3] || 0);\n } catch (error) {\n console.error(\"Error getting trove health:\", error);\n return null;\n }\n}\n\n/**\n * Get total debt across all of a user's troves.\n *\n * Convenience function that calls getUserTroveIds then getTroveDebt for each.\n *\n * @param provider - Starknet RPC provider\n * @param userAddress - The user's address\n * @returns Total debt in CASH (18 decimals)\n */\nexport async function getUserTotalTroveDebt(\n provider: StarknetCallProvider,\n userAddress: BigNumberish,\n abbotAddress?: string,\n shrineAddress?: string,\n): Promise<bigint> {\n const troveIds = await getUserTroveIds(provider, userAddress, abbotAddress);\n if (troveIds.length === 0) return 0n;\n\n let totalDebt = 0n;\n for (const troveId of troveIds) {\n const debt = await getTroveDebt(provider, troveId, shrineAddress);\n if (debt !== null) totalDebt += debt;\n }\n return totalDebt;\n}\n","/**\n * Hook to check extension qualification and entries left for multiple proofs.\n *\n * Ported from budokan — accepts a provider instead of relying on app-specific hooks.\n */\n\nimport { useState, useEffect, useMemo, useRef } from \"react\";\nimport { getExtensionEntriesLeft, type StarknetCallProvider } from \"../rpc/extensions\";\n\n/** A single qualification method for an extension */\nexport interface ExtensionQualification {\n id: string;\n proof: string[];\n entriesLeft: number;\n label?: string;\n metadata?: {\n tournamentId?: string;\n tournamentName?: string;\n tokenId?: string;\n position?: number;\n [key: string]: unknown;\n };\n}\n\n/** Result from extension qualification check */\nexport interface ExtensionQualificationResult {\n qualifications: ExtensionQualification[];\n totalEntriesLeft: number;\n bestQualification: ExtensionQualification | null;\n loading: boolean;\n error: Error | null;\n}\n\n/** Input for building qualifications — tournament validator specific */\nexport interface TournamentValidatorInput {\n tournamentId: string;\n tokenId: string;\n position: number;\n tournamentName?: string;\n}\n\n/**\n * Check extension qualification and entries left for multiple proofs.\n *\n * @param provider - Starknet RPC provider (or null to disable)\n * @param extensionAddress - The extension contract address\n * @param contextId - The metagame event ID (tournament ID, etc.)\n * @param playerAddress - The player's address\n * @param qualificationInputs - Potential qualifications to check\n * @param enabled - Whether to run the check (default: true)\n */\nexport const useExtensionQualification = (\n provider: StarknetCallProvider | null,\n extensionAddress: string | undefined,\n contextId: string | undefined,\n playerAddress: string | undefined,\n qualificationInputs: TournamentValidatorInput[],\n enabled: boolean = true,\n): ExtensionQualificationResult => {\n const [qualifications, setQualifications] = useState<ExtensionQualification[]>([]);\n const [loading, setLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n const inputsKey = useMemo(() => {\n if (!enabled || !provider || !extensionAddress || !contextId || !playerAddress) {\n return \"\";\n }\n return JSON.stringify({\n extensionAddress,\n contextId,\n playerAddress,\n inputs: qualificationInputs.map((i) => ({\n tid: i.tournamentId,\n token: i.tokenId,\n pos: i.position,\n })),\n });\n }, [enabled, provider, extensionAddress, contextId, playerAddress, qualificationInputs]);\n\n const lastFetchedKey = useRef<string>(\"\");\n\n useEffect(() => {\n if (!enabled) {\n lastFetchedKey.current = \"\";\n setQualifications([]);\n setLoading(false);\n setError(null);\n }\n }, [enabled]);\n\n useEffect(() => {\n if (!inputsKey) return;\n if (inputsKey === lastFetchedKey.current) return;\n\n const checkQualifications = async () => {\n lastFetchedKey.current = inputsKey;\n setLoading(true);\n setError(null);\n\n try {\n const results = await Promise.all(\n qualificationInputs.map(async (input) => {\n try {\n const proof = [\n input.tournamentId,\n input.tokenId,\n input.position.toString(),\n ];\n\n const entriesLeft = await getExtensionEntriesLeft(\n provider!,\n extensionAddress!,\n contextId!,\n playerAddress!,\n proof,\n );\n\n if (entriesLeft !== null && entriesLeft > 0) {\n return {\n id: `${input.tournamentId}-${input.tokenId}-${input.position}`,\n proof,\n entriesLeft,\n label: input.tournamentName,\n metadata: {\n tournamentId: input.tournamentId,\n tournamentName: input.tournamentName,\n tokenId: input.tokenId,\n position: input.position,\n },\n } as ExtensionQualification;\n }\n return null;\n } catch (err) {\n console.error(\n `Error checking qualification for ${input.tournamentId}:`,\n err,\n );\n return null;\n }\n }),\n );\n\n const validQualifications = results.filter(\n (q): q is ExtensionQualification => q !== null,\n );\n setQualifications(validQualifications);\n } catch (err) {\n console.error(\"Error checking extension qualifications:\", err);\n setError(err instanceof Error ? err : new Error(String(err)));\n setQualifications([]);\n } finally {\n setLoading(false);\n }\n };\n\n checkQualifications();\n }, [inputsKey, provider, extensionAddress, contextId, playerAddress, qualificationInputs]);\n\n const totalEntriesLeft = qualifications.reduce(\n (sum, q) => sum + q.entriesLeft,\n 0,\n );\n\n const bestQualification =\n qualifications.length > 0\n ? qualifications.reduce((best, current) =>\n current.entriesLeft > best.entriesLeft ? current : best,\n )\n : null;\n\n return {\n qualifications,\n totalEntriesLeft,\n bestQualification,\n loading,\n error,\n };\n};\n","/**\n * Opus Troves entry calculation.\n *\n * The Opus Troves extension gates entry based on the player's CASH debt\n * in the Opus Protocol. This module contains the pure math for determining\n * how many entries a given debt level allows, and which entries are bannable\n * if a player's debt drops below the threshold.\n *\n * The trove debt fetching (getUserTroveIds, getTroveHealth) is RPC-specific\n * and stays in each app. This module handles the calculation once you have\n * the debt value.\n */\n\nimport type { OpusTrovesValidatorConfig } from \"../types/extensions\";\n\n/**\n * Calculate how many entries a player's total debt allows.\n *\n * Two modes based on config:\n * - Proportional (valuePerEntry > 0): entries = (debt - threshold) / valuePerEntry\n * - Fixed (valuePerEntry == 0): if debt >= threshold → maxEntries\n *\n * @param debt - Player's total CASH debt across all troves (18 decimals)\n * @param config - Parsed Opus Troves validator config\n * @returns Number of entries allowed (0 if below threshold)\n */\nexport function calculateOpusTrovesEntries(\n debt: bigint,\n config: OpusTrovesValidatorConfig,\n): number {\n let allowed = 0;\n\n if (config.valuePerEntry > 0n) {\n // Proportional: entries scale with debt above threshold\n if (debt > config.threshold) {\n allowed = Number((debt - config.threshold) / config.valuePerEntry);\n }\n } else {\n // Fixed: meets threshold → gets maxEntries\n if (debt >= config.threshold && config.maxEntries > 0) {\n allowed = config.maxEntries;\n }\n }\n\n // Cap at maxEntries if specified\n if (config.maxEntries > 0) {\n allowed = Math.min(allowed, config.maxEntries);\n }\n\n return allowed;\n}\n\n/**\n * Determine which entries should be banned based on debt vs allowed entries.\n *\n * When a player's debt drops below what their entries require, the excess\n * entries (sorted by token ID ascending — oldest first) become bannable.\n *\n * @param registeredTokenIds - Token IDs the player registered with\n * @param entriesAllowed - From calculateOpusTrovesEntries()\n * @returns Set of token IDs that should be banned\n */\nexport function findBannableEntries(\n registeredTokenIds: string[],\n entriesAllowed: number,\n): Set<string> {\n const bannable = new Set<string>();\n const bannableCount = Math.max(0, registeredTokenIds.length - entriesAllowed);\n\n if (bannableCount > 0) {\n // Sort by token ID ascending (oldest entries first)\n const sorted = [...registeredTokenIds].sort((a, b) => {\n return Number(BigInt(a)) - Number(BigInt(b));\n });\n for (let i = 0; i < bannableCount; i++) {\n bannable.add(sorted[i]);\n }\n }\n\n return bannable;\n}\n\n/**\n * Batch calculate bannable entries for multiple players.\n *\n * Takes a map of player → { debt, registeredTokenIds } and returns\n * the set of all bannable token IDs across all players.\n *\n * @param players - Map of player address → their debt and registered entries\n * @param config - Parsed Opus Troves validator config\n * @returns Set of all bannable token IDs\n */\nexport function findAllBannableEntries(\n players: Map<string, { debt: bigint; registeredTokenIds: string[] }>,\n config: OpusTrovesValidatorConfig,\n): Set<string> {\n const allBannable = new Set<string>();\n\n for (const [, { debt, registeredTokenIds }] of players) {\n const allowed = calculateOpusTrovesEntries(debt, config);\n const bannable = findBannableEntries(registeredTokenIds, allowed);\n for (const id of bannable) {\n allBannable.add(id);\n }\n }\n\n return allBannable;\n}\n","/**\n * Hook to calculate bannable entries for Opus Troves extension.\n *\n * Ported from budokan — accepts a provider instead of relying on app-specific hooks.\n */\n\nimport { useState, useEffect, useMemo } from \"react\";\nimport type { OpusTrovesValidatorConfig } from \"../types/extensions\";\nimport { getUserTotalTroveDebt, type StarknetCallProvider } from \"../rpc/extensions\";\nimport { findAllBannableEntries } from \"../utils/opusTroves\";\n\ninterface Game {\n tokenId: number | bigint;\n owner?: string;\n}\n\nexport interface UseOpusTrovesBannableEntriesResult {\n bannableEntries: Set<string>;\n troveDebts: Map<string, bigint>;\n isLoading: boolean;\n playerGroups: Map<string, Game[]>;\n}\n\n/**\n * Calculate bannable entries for Opus Troves extension.\n *\n * @param provider - Starknet RPC provider (or null to disable)\n * @param games - Array of game entries with tokenId and owner\n * @param config - Opus Troves validator config (or undefined to disable)\n * @param enabled - Whether to run the check\n */\nexport const useOpusTrovesBannableEntries = (\n provider: StarknetCallProvider | null,\n games: Array<{ tokenId: number | bigint; owner?: string }>,\n config: OpusTrovesValidatorConfig | undefined,\n enabled: boolean,\n): UseOpusTrovesBannableEntriesResult => {\n const [troveDebts, setTroveDebts] = useState<Map<string, bigint>>(new Map());\n const [isLoading, setIsLoading] = useState(false);\n\n const playerGroups = useMemo(() => {\n const groups = new Map<string, Game[]>();\n games.forEach((game) => {\n const owner = game?.owner;\n if (!owner) return;\n if (!groups.has(owner)) groups.set(owner, []);\n groups.get(owner)!.push(game);\n });\n return groups;\n }, [games]);\n\n const playerAddresses = useMemo(\n () => Array.from(playerGroups.keys()),\n [playerGroups],\n );\n\n useEffect(() => {\n if (!enabled || !provider || !config || playerAddresses.length === 0) {\n setTroveDebts(new Map());\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n\n const fetchDebts = async () => {\n const debts = new Map<string, bigint>();\n await Promise.all(\n playerAddresses.map(async (addr) => {\n try {\n const debt = await getUserTotalTroveDebt(provider, addr);\n debts.set(addr, debt);\n } catch {\n debts.set(addr, 0n);\n }\n }),\n );\n if (!cancelled) {\n setTroveDebts(debts);\n setIsLoading(false);\n }\n };\n\n fetchDebts();\n return () => { cancelled = true; };\n }, [enabled, provider, config, playerAddresses]);\n\n const bannableEntries = useMemo(() => {\n if (!enabled || isLoading || !config) return new Set<string>();\n\n const players = new Map<string, { debt: bigint; registeredTokenIds: string[] }>();\n for (const [owner, ownerGames] of playerGroups.entries()) {\n players.set(owner, {\n debt: troveDebts.get(owner) ?? 0n,\n registeredTokenIds: ownerGames.map((g) => g.tokenId.toString()),\n });\n }\n\n return findAllBannableEntries(players, config);\n }, [enabled, isLoading, playerGroups, troveDebts, config]);\n\n return {\n bannableEntries,\n troveDebts,\n isLoading,\n playerGroups,\n };\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/useDebounce.ts","../src/react/usePagination.ts","../src/react/useSearchFilter.ts","../src/react/useTokenSelector.ts","../src/utils/status.ts","../src/react/useStatusIndicator.ts","../src/react/useScoreTable.ts","../src/utils/prizeAggregation.ts","../src/react/usePrizeTable.ts","../src/utils/entryFee.ts","../src/utils/formatting.ts","../src/react/useEntryFeePreview.ts","../src/utils/qualification.ts","../src/react/useEntryQualification.ts","../src/rpc/extensions.ts","../src/react/useExtensionQualification.ts","../src/utils/opusTroves.ts","../src/react/useOpusTrovesBannableEntries.ts"],"names":["useState","useEffect","useMemo","useCallback","CallData","useRef"],"mappings":"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","file":"react.cjs","sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport function useDebounce<T>(value: T, delay: number): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n useEffect(() => {\n const handler = setTimeout(() => {\n setDebouncedValue(value);\n }, delay);\n\n return () => {\n clearTimeout(handler);\n };\n }, [value, delay]);\n\n return debouncedValue;\n}\n","import { useState, useMemo, useCallback } from \"react\";\n\nexport interface UsePaginationOptions {\n totalItems: number;\n pageSize?: number;\n}\n\nexport interface UsePaginationReturn {\n currentPage: number;\n totalPages: number;\n hasNext: boolean;\n hasPrev: boolean;\n next: () => void;\n prev: () => void;\n reset: () => void;\n startIndex: number;\n endIndex: number;\n}\n\nexport function usePagination({\n totalItems,\n pageSize = 10,\n}: UsePaginationOptions): UsePaginationReturn {\n const [currentPage, setCurrentPage] = useState(0);\n\n const totalPages = useMemo(\n () => Math.max(1, Math.ceil(totalItems / pageSize)),\n [totalItems, pageSize],\n );\n\n const hasNext = currentPage < totalPages - 1;\n const hasPrev = currentPage > 0;\n\n const next = useCallback(() => {\n setCurrentPage((p) => Math.min(p + 1, totalPages - 1));\n }, [totalPages]);\n\n const prev = useCallback(() => {\n setCurrentPage((p) => Math.max(p - 1, 0));\n }, []);\n\n const reset = useCallback(() => {\n setCurrentPage(0);\n }, []);\n\n const startIndex = currentPage * pageSize;\n const endIndex = Math.min(startIndex + pageSize, totalItems);\n\n return {\n currentPage,\n totalPages,\n hasNext,\n hasPrev,\n next,\n prev,\n reset,\n startIndex,\n endIndex,\n };\n}\n","import { useState, useMemo } from \"react\";\nimport { useDebounce } from \"./useDebounce\";\n\nexport interface UseSearchFilterOptions<T> {\n items: T[];\n searchFields: (keyof T)[];\n debounceMs?: number;\n}\n\nexport interface UseSearchFilterReturn<T> {\n search: string;\n setSearch: (q: string) => void;\n filteredItems: T[];\n resultCount: number;\n}\n\nexport function useSearchFilter<T>({\n items,\n searchFields,\n debounceMs = 300,\n}: UseSearchFilterOptions<T>): UseSearchFilterReturn<T> {\n const [search, setSearch] = useState(\"\");\n const debouncedSearch = useDebounce(search, debounceMs);\n\n const filteredItems = useMemo(() => {\n if (!debouncedSearch) return items;\n const lower = debouncedSearch.toLowerCase();\n return items.filter((item) =>\n searchFields.some((field) => {\n const value = item[field];\n if (typeof value === \"string\") {\n return value.toLowerCase().includes(lower);\n }\n if (typeof value === \"number\") {\n return String(value).includes(lower);\n }\n return false;\n }),\n );\n }, [items, debouncedSearch, searchFields]);\n\n return {\n search,\n setSearch,\n filteredItems,\n resultCount: filteredItems.length,\n };\n}\n","import { useState, useMemo, useCallback } from \"react\";\nimport type { Token } from \"../types/token\";\nimport { useDebounce } from \"./useDebounce\";\nimport { usePagination, type UsePaginationReturn } from \"./usePagination\";\n\nexport interface UseTokenSelectorOptions {\n tokens: Token[];\n tokenType?: \"erc20\" | \"erc721\";\n pageSize?: number;\n debounceMs?: number;\n}\n\nexport interface UseTokenSelectorReturn {\n search: string;\n setSearch: (q: string) => void;\n filteredTokens: Token[];\n selectedToken: Token | null;\n select: (token: Token) => void;\n clear: () => void;\n isSelected: (token: Token) => boolean;\n pagination: UsePaginationReturn;\n getTokenProps: (token: Token) => {\n onClick: () => void;\n \"data-selected\": boolean;\n role: \"option\";\n \"aria-selected\": boolean;\n };\n}\n\nexport function useTokenSelector({\n tokens,\n tokenType,\n pageSize = 10,\n debounceMs = 300,\n}: UseTokenSelectorOptions): UseTokenSelectorReturn {\n const [search, setSearchRaw] = useState(\"\");\n const [selectedToken, setSelectedToken] = useState<Token | null>(null);\n const debouncedSearch = useDebounce(search, debounceMs);\n\n const allFiltered = useMemo(() => {\n let result = tokens;\n if (tokenType) {\n result = result.filter((t) => t.tokenType === tokenType);\n }\n if (debouncedSearch) {\n const lower = debouncedSearch.toLowerCase();\n result = result.filter(\n (t) =>\n t.name.toLowerCase().includes(lower) ||\n t.symbol.toLowerCase().includes(lower) ||\n t.address.toLowerCase().includes(lower),\n );\n }\n return result;\n }, [tokens, tokenType, debouncedSearch]);\n\n const pagination = usePagination({\n totalItems: allFiltered.length,\n pageSize,\n });\n\n const filteredTokens = useMemo(\n () => allFiltered.slice(pagination.startIndex, pagination.endIndex),\n [allFiltered, pagination.startIndex, pagination.endIndex],\n );\n\n const setSearch = useCallback(\n (q: string) => {\n setSearchRaw(q);\n pagination.reset();\n },\n [pagination],\n );\n\n const select = useCallback((token: Token) => {\n setSelectedToken(token);\n }, []);\n\n const clear = useCallback(() => {\n setSelectedToken(null);\n }, []);\n\n const isSelected = useCallback(\n (token: Token) =>\n selectedToken?.address === token.address,\n [selectedToken],\n );\n\n const getTokenProps = useCallback(\n (token: Token) => ({\n onClick: () => select(token),\n \"data-selected\": isSelected(token),\n role: \"option\" as const,\n \"aria-selected\": isSelected(token),\n }),\n [select, isSelected],\n );\n\n return {\n search,\n setSearch,\n filteredTokens,\n selectedToken,\n select,\n clear,\n isSelected,\n pagination,\n getTokenProps,\n };\n}\n","import type { StatusTimestamps, StatusResult } from \"../types/status\";\n\nexport function computeStatus(\n timestamps: StatusTimestamps,\n now?: number,\n): StatusResult {\n const currentTimestamp = now ?? Math.floor(Date.now() / 1000);\n\n // Quest-specific: locked state\n if (timestamps.unlocked === false) {\n return {\n label: \"Locked\",\n variant: \"locked\",\n isActive: false,\n countdown: null,\n };\n }\n\n // Quest-specific: completed state\n if (timestamps.completed) {\n return {\n label: \"Completed\",\n variant: \"completed\",\n isActive: false,\n countdown: null,\n };\n }\n\n const { registrationStart, registrationEnd, start, end, submissionEnd } =\n timestamps;\n\n // Registration phase\n if (registrationStart && registrationEnd) {\n if (currentTimestamp < registrationStart) {\n return {\n label: \"Upcoming\",\n variant: \"upcoming\",\n isActive: false,\n countdown: {\n targetTimestamp: registrationStart,\n label: \"Registration\",\n },\n };\n }\n if (\n currentTimestamp >= registrationStart &&\n currentTimestamp < registrationEnd\n ) {\n return {\n label: \"Registration\",\n variant: \"registration\",\n isActive: true,\n countdown: { targetTimestamp: registrationEnd, label: \"Closes\" },\n };\n }\n }\n\n // Before start\n if (currentTimestamp < start) {\n return {\n label: \"Upcoming\",\n variant: \"upcoming\",\n isActive: false,\n countdown: { targetTimestamp: start, label: \"Starts\" },\n };\n }\n\n // Active / Live\n if (currentTimestamp >= start && currentTimestamp < end) {\n return {\n label: \"Live\",\n variant: \"active\",\n isActive: true,\n countdown: { targetTimestamp: end, label: \"Ends\" },\n };\n }\n\n // Submission phase\n if (submissionEnd && currentTimestamp >= end && currentTimestamp < submissionEnd) {\n return {\n label: \"Submission\",\n variant: \"submission\",\n isActive: true,\n countdown: { targetTimestamp: submissionEnd, label: \"Submit\" },\n };\n }\n\n // Ended\n return {\n label: \"Ended\",\n variant: \"ended\",\n isActive: false,\n countdown: null,\n };\n}\n","import { useState, useEffect } from \"react\";\nimport type { StatusTimestamps, StatusResult } from \"../types/status\";\nimport { computeStatus } from \"../utils/status\";\n\nexport function useStatusIndicator(\n timestamps: StatusTimestamps,\n refreshMs = 1000,\n): StatusResult {\n const [now, setNow] = useState(() => Math.floor(Date.now() / 1000));\n\n useEffect(() => {\n const interval = setInterval(() => {\n setNow(Math.floor(Date.now() / 1000));\n }, refreshMs);\n return () => clearInterval(interval);\n }, [refreshMs]);\n\n return computeStatus(timestamps, now);\n}\n","import { useState, useMemo, useCallback } from \"react\";\nimport type { Participant } from \"../types/participant\";\nimport { usePagination, type UsePaginationReturn } from \"./usePagination\";\nimport { useDebounce } from \"./useDebounce\";\n\ntype SortField = \"rank\" | \"score\" | \"name\";\ntype SortDirection = \"asc\" | \"desc\";\n\nexport interface UseScoreTableOptions {\n participants: Participant[];\n pageSize?: number;\n sortField?: SortField;\n sortDirection?: SortDirection;\n}\n\nexport interface UseScoreTableReturn {\n rows: Participant[];\n pagination: UsePaginationReturn;\n sort: { field: SortField; direction: SortDirection };\n setSort: (field: string) => void;\n search: string;\n setSearch: (q: string) => void;\n}\n\nexport function useScoreTable({\n participants,\n pageSize = 10,\n sortField = \"rank\",\n sortDirection = \"asc\",\n}: UseScoreTableOptions): UseScoreTableReturn {\n const [sort, setSortState] = useState<{\n field: SortField;\n direction: SortDirection;\n }>({ field: sortField, direction: sortDirection });\n\n const [search, setSearchRaw] = useState(\"\");\n const debouncedSearch = useDebounce(search, 300);\n\n const filtered = useMemo(() => {\n if (!debouncedSearch) return participants;\n const lower = debouncedSearch.toLowerCase();\n return participants.filter(\n (p) =>\n p.address.toLowerCase().includes(lower) ||\n (p.name && p.name.toLowerCase().includes(lower)),\n );\n }, [participants, debouncedSearch]);\n\n const sorted = useMemo(() => {\n const arr = [...filtered];\n const dir = sort.direction === \"asc\" ? 1 : -1;\n arr.sort((a, b) => {\n const aVal = a[sort.field] ?? 0;\n const bVal = b[sort.field] ?? 0;\n if (typeof aVal === \"string\" && typeof bVal === \"string\") {\n return dir * aVal.localeCompare(bVal);\n }\n return dir * (Number(aVal) - Number(bVal));\n });\n return arr;\n }, [filtered, sort]);\n\n const pagination = usePagination({\n totalItems: sorted.length,\n pageSize,\n });\n\n const rows = useMemo(\n () => sorted.slice(pagination.startIndex, pagination.endIndex),\n [sorted, pagination.startIndex, pagination.endIndex],\n );\n\n const setSort = useCallback(\n (field: string) => {\n const validField = field as SortField;\n setSortState((prev) => {\n if (prev.field === validField) {\n return {\n field: validField,\n direction: prev.direction === \"asc\" ? \"desc\" : \"asc\",\n };\n }\n return { field: validField, direction: \"asc\" };\n });\n },\n [],\n );\n\n const setSearch = useCallback(\n (q: string) => {\n setSearchRaw(q);\n pagination.reset();\n },\n [pagination],\n );\n\n return {\n rows,\n pagination,\n sort,\n setSort,\n search,\n setSearch,\n };\n}\n","import type { Prize } from \"../types/prize\";\n\n/**\n * Prize aggregation by position.\n *\n * Groups prizes by position, summing ERC20 amounts and collecting ERC721 IDs.\n * Works with Prize — metagame apps adapt their raw prize data to this\n * shape before calling these functions.\n */\n\nexport interface PositionPrizeGroup {\n position: number;\n erc20: Array<{ tokenAddress: string; totalAmount: bigint }>;\n erc721: Array<{ tokenAddress: string; tokenIds: string[] }>;\n}\n\n/**\n * Group prizes by leaderboard position, aggregating ERC20 amounts and\n * collecting ERC721 token IDs per position.\n */\nexport function aggregatePrizesByPosition(\n prizes: Prize[],\n): PositionPrizeGroup[] {\n const positionMap = new Map<number, {\n erc20Map: Map<string, bigint>;\n erc721Map: Map<string, string[]>;\n }>();\n\n for (const prize of prizes) {\n if (!positionMap.has(prize.position)) {\n positionMap.set(prize.position, {\n erc20Map: new Map(),\n erc721Map: new Map(),\n });\n }\n const group = positionMap.get(prize.position)!;\n\n if (prize.tokenType === \"erc20\") {\n const current = group.erc20Map.get(prize.tokenAddress) ?? 0n;\n group.erc20Map.set(prize.tokenAddress, current + BigInt(prize.amount));\n } else {\n const ids = group.erc721Map.get(prize.tokenAddress) ?? [];\n ids.push(prize.id);\n group.erc721Map.set(prize.tokenAddress, ids);\n }\n }\n\n return Array.from(positionMap.entries())\n .sort(([a], [b]) => a - b)\n .map(([position, { erc20Map, erc721Map }]) => ({\n position,\n erc20: Array.from(erc20Map.entries()).map(([tokenAddress, totalAmount]) => ({\n tokenAddress,\n totalAmount,\n })),\n erc721: Array.from(erc721Map.entries()).map(([tokenAddress, tokenIds]) => ({\n tokenAddress,\n tokenIds,\n })),\n }));\n}\n\n/**\n * Sponsor contribution aggregated from prizes.\n */\nexport interface SponsorContribution {\n sponsorAddress: string;\n tokens: Array<{\n tokenAddress: string;\n totalAmount: bigint;\n prizeCount: number;\n }>;\n /** NFT collections grouped by token address, with individual token IDs */\n nftCollections: Array<{\n tokenAddress: string;\n tokenIds: string[];\n }>;\n nftCount: number;\n totalPrizeCount: number;\n}\n\n/**\n * Group prizes by sponsor address, aggregating ERC20 contributions and\n * grouping NFTs by collection. Filters out prizes with no sponsor\n * (address \"0x0\" or empty).\n *\n * For ERC721 prizes, `prize.amount` is expected to hold the token ID\n * (this is the convention set by the prize adapter).\n *\n * @param prizes - Array of Prize with sponsorAddress populated\n * @returns Sponsor contributions sorted by total prize count (descending)\n */\nexport function aggregatePrizesBySponsor(\n prizes: Prize[],\n): SponsorContribution[] {\n const sponsorMap = new Map<string, {\n erc20Map: Map<string, { amount: bigint; count: number }>;\n nftMap: Map<string, string[]>;\n nftCount: number;\n totalCount: number;\n }>();\n\n for (const prize of prizes) {\n if (!prize.sponsorAddress || prize.sponsorAddress === \"0x0\") continue;\n\n if (!sponsorMap.has(prize.sponsorAddress)) {\n sponsorMap.set(prize.sponsorAddress, {\n erc20Map: new Map(),\n nftMap: new Map(),\n nftCount: 0,\n totalCount: 0,\n });\n }\n const sponsor = sponsorMap.get(prize.sponsorAddress)!;\n sponsor.totalCount++;\n\n if (prize.tokenType === \"erc20\") {\n const current = sponsor.erc20Map.get(prize.tokenAddress) ?? {\n amount: 0n,\n count: 0,\n };\n sponsor.erc20Map.set(prize.tokenAddress, {\n amount: current.amount + BigInt(prize.amount),\n count: current.count + 1,\n });\n } else {\n sponsor.nftCount++;\n const ids = sponsor.nftMap.get(prize.tokenAddress) ?? [];\n ids.push(prize.amount); // For ERC721, amount holds the token ID\n sponsor.nftMap.set(prize.tokenAddress, ids);\n }\n }\n\n return Array.from(sponsorMap.entries())\n .map(([sponsorAddress, { erc20Map, nftMap, nftCount, totalCount }]) => ({\n sponsorAddress,\n tokens: Array.from(erc20Map.entries()).map(\n ([tokenAddress, { amount, count }]) => ({\n tokenAddress,\n totalAmount: amount,\n prizeCount: count,\n }),\n ),\n nftCollections: Array.from(nftMap.entries()).map(\n ([tokenAddress, tokenIds]) => ({\n tokenAddress,\n tokenIds,\n }),\n ),\n nftCount,\n totalPrizeCount: totalCount,\n }))\n .sort((a, b) => b.totalPrizeCount - a.totalPrizeCount);\n}\n\n/**\n * Filter prizes to only those not yet claimed.\n *\n * @param prizes - All prizes the user could potentially claim\n * @param claimedIds - Set of prize IDs already claimed\n * @returns Prizes not yet claimed\n */\nexport function filterClaimablePrizes(\n prizes: Prize[],\n claimedIds: Set<string>,\n): Prize[] {\n return prizes.filter((prize) => !claimedIds.has(prize.id));\n}\n\n/**\n * Filter out ERC20 prizes with zero amount.\n */\nexport function filterZeroPrizes(prizes: Prize[]): Prize[] {\n return prizes.filter((prize) => {\n if (prize.tokenType === \"erc20\") {\n return BigInt(prize.amount) > 0n;\n }\n return true; // Keep all NFTs\n });\n}\n","import { useMemo } from \"react\";\nimport { usePagination, type UsePaginationReturn } from \"./usePagination\";\nimport type { Prize } from \"../types/prize\";\nimport {\n aggregatePrizesByPosition,\n type PositionPrizeGroup,\n} from \"../utils/prizeAggregation\";\n\nexport interface UsePrizeTableOptions {\n prizes: Prize[];\n positionsPerPage?: number;\n}\n\nexport interface UsePrizeTableReturn {\n /** Prize groups for the current page, sorted by position */\n rows: PositionPrizeGroup[];\n /** Total number of positions across all prizes */\n totalPositions: number;\n /** Pagination state and controls */\n pagination: UsePaginationReturn;\n}\n\n/**\n * Headless hook for displaying a paginated prize table.\n *\n * Aggregates prizes by position (summing ERC20 amounts, grouping ERC721 IDs),\n * then paginates the position groups. Metagame UIs render each position group\n * however they like — the hook only manages data and pagination state.\n */\nexport function usePrizeTable({\n prizes,\n positionsPerPage = 5,\n}: UsePrizeTableOptions): UsePrizeTableReturn {\n const grouped = useMemo(() => aggregatePrizesByPosition(prizes), [prizes]);\n\n const pagination = usePagination({\n totalItems: grouped.length,\n pageSize: positionsPerPage,\n });\n\n const rows = useMemo(\n () => grouped.slice(pagination.startIndex, pagination.endIndex),\n [grouped, pagination.startIndex, pagination.endIndex],\n );\n\n return {\n rows,\n totalPositions: grouped.length,\n pagination,\n };\n}\n","/**\n * Entry fee breakdown calculation.\n *\n * Takes a total fee pool and share percentages (in basis points, where 10000 = 100%)\n * and returns the amount allocated to each bucket.\n *\n * This is the same math that on-chain metagame contracts use to split entry fees\n * between creator, game creator, refund pool, and prize pool.\n */\n\nexport interface EntryFeeBreakdown {\n /** Total fee collected from all entrants */\n totalCollected: bigint;\n /** Amount going to the metagame creator */\n creatorAmount: bigint;\n /** Amount going to the game creator */\n gameCreatorAmount: bigint;\n /** Amount reserved for refunds */\n refundAmount: bigint;\n /** Amount available for prize distribution */\n prizePoolAmount: bigint;\n}\n\nexport interface EntryFeeShares {\n /** Creator share in basis points (0-10000) */\n creatorShare: number;\n /** Game creator share in basis points (0-10000) */\n gameCreatorShare: number;\n /** Refund share in basis points (0-10000) */\n refundShare: number;\n}\n\n/**\n * Calculate how an entry fee pool is split between creator, game, refund, and prizes.\n *\n * @param feePerEntry - Fee amount per entry (in token units, as bigint)\n * @param entryCount - Number of entries\n * @param shares - Share percentages in basis points (10000 = 100%)\n * @returns Breakdown of amounts for each bucket\n */\nexport function calculateEntryFeeBreakdown(\n feePerEntry: bigint,\n entryCount: number,\n shares: EntryFeeShares,\n): EntryFeeBreakdown {\n const totalCollected = feePerEntry * BigInt(entryCount);\n\n if (totalCollected === 0n) {\n return {\n totalCollected: 0n,\n creatorAmount: 0n,\n gameCreatorAmount: 0n,\n refundAmount: 0n,\n prizePoolAmount: 0n,\n };\n }\n\n const creatorAmount =\n shares.creatorShare > 0\n ? (totalCollected * BigInt(shares.creatorShare)) / 10000n\n : 0n;\n\n const gameCreatorAmount =\n shares.gameCreatorShare > 0\n ? (totalCollected * BigInt(shares.gameCreatorShare)) / 10000n\n : 0n;\n\n const refundAmount =\n shares.refundShare > 0\n ? (totalCollected * BigInt(shares.refundShare)) / 10000n\n : 0n;\n\n const prizePoolBps =\n 10000 - shares.creatorShare - shares.gameCreatorShare - shares.refundShare;\n const prizePoolAmount =\n prizePoolBps > 0 ? (totalCollected * BigInt(prizePoolBps)) / 10000n : 0n;\n\n return {\n totalCollected,\n creatorAmount,\n gameCreatorAmount,\n refundAmount,\n prizePoolAmount,\n };\n}\n\n/**\n * Distribute a prize pool across positions using a distribution curve.\n *\n * Takes the prize pool amount and distribution percentages (from calculateDistribution),\n * and returns the actual token amount per position.\n *\n * @param prizePoolAmount - Total pool to distribute (bigint, in smallest token units)\n * @param percentages - Distribution percentages per position (from calculateDistribution)\n * @returns Array of { position, amount } where position is 1-indexed\n */\nexport function distributePool(\n prizePoolAmount: bigint,\n percentages: number[],\n): Array<{ position: number; amount: bigint }> {\n return percentages\n .map((pct, index) => ({\n position: index + 1,\n amount:\n (prizePoolAmount * BigInt(Math.floor(pct * 100))) / 10000n,\n }))\n .filter((entry) => entry.amount > 0n);\n}\n","export function formatNumber(num: number): string {\n if (Math.abs(num) >= 1000000) {\n return parseFloat((num / 1000000).toFixed(2)) + \"m\";\n } else if (Math.abs(num) >= 1000) {\n return parseFloat((num / 1000).toFixed(2)) + \"k\";\n } else if (Math.abs(num) >= 1) {\n return num.toFixed(0);\n } else if (Math.abs(num) >= 0.1) {\n return num.toFixed(1);\n } else if (Math.abs(num) >= 0.01) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 0.001) {\n return num.toFixed(3);\n } else if (num === 0) {\n return \"0\";\n } else {\n return num.toFixed(4);\n }\n}\n\nexport function formatPrizeAmount(num: number): string {\n if (Math.abs(num) >= 1000000) {\n return parseFloat((num / 1000000).toFixed(2)) + \"m\";\n } else if (Math.abs(num) >= 1000) {\n return parseFloat((num / 1000).toFixed(2)) + \"k\";\n } else if (Math.abs(num) >= 100) {\n return num.toFixed(1);\n } else if (Math.abs(num) >= 10) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 1) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 0.1) {\n return num.toFixed(2);\n } else if (Math.abs(num) >= 0.01) {\n return num.toFixed(3);\n } else if (Math.abs(num) >= 0.001) {\n return num.toFixed(4);\n } else if (num === 0) {\n return \"0\";\n } else {\n return num.toFixed(5);\n }\n}\n\nexport function formatUsdValue(value: number): string {\n if (value === 0) return \"0.00\";\n if (value < 0.01 && value > 0) return \"<0.01\";\n return value.toFixed(2);\n}\n\nexport function formatScore(num: number): string {\n if (Math.abs(num) >= 1000000) {\n return parseFloat((num / 1000000).toFixed(2)) + \"m\";\n } else if (Math.abs(num) >= 1000) {\n return parseFloat((num / 1000).toFixed(2)) + \"k\";\n } else if (Math.abs(num) >= 10) {\n return num.toFixed(0);\n } else if (Math.abs(num) > 0) {\n return num.toFixed(0);\n } else {\n return \"0\";\n }\n}\n\nexport function formatTime(seconds: number): string {\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days} Day${days > 1 ? \"s\" : \"\"}`;\n } else if (hours > 0) {\n return `${hours} Hour${hours > 1 ? \"s\" : \"\"}`;\n } else if (minutes > 0) {\n return `${minutes} Min${minutes > 1 ? \"s\" : \"\"}`;\n } else {\n return `${seconds.toFixed(0)} Sec${seconds > 1 ? \"s\" : \"\"}`;\n }\n}\n\nexport function getOrdinalSuffix(position: number): string {\n const formatPosition = isNaN(position) ? 0 : position;\n if (formatPosition % 10 === 1 && formatPosition !== 11) return \"st\";\n if (formatPosition % 10 === 2 && formatPosition !== 12) return \"nd\";\n if (position % 10 === 3 && position !== 13) return \"rd\";\n return \"th\";\n}\n\nexport type DistributionType = \"linear\" | \"exponential\" | \"uniform\";\n\nexport function calculatePayouts(\n totalPlaces: number,\n weightingFactor: number,\n): number[] {\n const weights: number[] = [];\n for (let i = 1; i <= totalPlaces; i++) {\n weights.push(1 / Math.pow(i, weightingFactor));\n }\n\n const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);\n\n const payouts: number[] = weights.map((weight) =>\n Math.floor((weight / totalWeight) * 100),\n );\n\n const totalPayout = payouts.reduce((sum, payout) => sum + payout, 0);\n\n let remaining = 100 - totalPayout;\n let index = 0;\n while (remaining > 0) {\n payouts[index] += 1;\n remaining -= 1;\n index = (index + 1) % totalPlaces;\n }\n\n return payouts;\n}\n\nexport function calculateDistribution(\n positions: number,\n weight: number,\n creatorFee?: number,\n gameFee?: number,\n refundShare?: number,\n distributionType: DistributionType = \"exponential\",\n): number[] {\n if (positions <= 0) {\n return [];\n }\n\n const safeCreatorFee = creatorFee ?? 0;\n const safeGameFee = gameFee ?? 0;\n const safeRefundShare = refundShare ?? 0;\n const prizePoolPercentage =\n 100 - safeCreatorFee - safeGameFee - safeRefundShare;\n\n if (prizePoolPercentage <= 0) {\n return Array(positions).fill(0);\n }\n\n let rawDistributions: number[] = [];\n\n if (distributionType === \"uniform\") {\n rawDistributions = Array(positions).fill(1);\n } else if (distributionType === \"linear\") {\n for (let i = 0; i < positions; i++) {\n const positionValue = positions - i;\n const share = 1 + (positionValue - 1) * (weight / 10);\n rawDistributions.push(share);\n }\n } else {\n for (let i = 0; i < positions; i++) {\n const share = Math.pow(1 - i / positions, weight);\n rawDistributions.push(share);\n }\n }\n\n const total = rawDistributions.reduce((a, b) => a + b, 0);\n\n if (total === 0) {\n return Array(positions).fill(0);\n }\n\n const basisPointShares = rawDistributions.map((d) => {\n const ratio = d / total;\n const basisPoints = ratio * 10000;\n return Math.floor(basisPoints);\n });\n\n const totalBasisPoints = basisPointShares.reduce((a, b) => a + b, 0);\n const remainingBasisPoints = 10000 - totalBasisPoints;\n\n if (remainingBasisPoints !== 0 && positions > 0) {\n basisPointShares[0] = basisPointShares[0] + remainingBasisPoints;\n }\n\n return basisPointShares.map((bp) => bp / 100);\n}\n","import { useMemo } from \"react\";\nimport {\n calculateEntryFeeBreakdown,\n distributePool,\n type EntryFeeBreakdown,\n type EntryFeeShares,\n} from \"../utils/entryFee\";\nimport {\n calculateDistribution,\n type DistributionType,\n} from \"../utils/formatting\";\n\nexport interface UseEntryFeePreviewOptions {\n /** Fee per entry in smallest token units (as bigint) */\n feePerEntry: bigint;\n /** Expected number of entries (for preview) */\n entryCount: number;\n /** Share percentages in basis points */\n shares: EntryFeeShares;\n /** Number of positions to distribute prizes across */\n distributionPositions: number;\n /** Distribution curve type */\n distributionType: DistributionType;\n /** Weight for linear/exponential curves */\n distributionWeight: number;\n}\n\nexport interface UseEntryFeePreviewReturn {\n /** Breakdown of total fees into creator/game/refund/pool buckets */\n breakdown: EntryFeeBreakdown;\n /** Per-position prize amounts from the pool */\n positionPrizes: Array<{ position: number; amount: bigint }>;\n /** Distribution percentages per position (0-100 scale) */\n percentages: number[];\n}\n\n/**\n * Headless hook for live entry fee breakdown preview.\n *\n * As form values change (fee amount, shares, distribution curve),\n * this hook recomputes the full breakdown and per-position prizes.\n * Useful for \"create tournament/quest\" forms where you want to show\n * the user a live preview of how entry fees will be distributed.\n */\nexport function useEntryFeePreview({\n feePerEntry,\n entryCount,\n shares,\n distributionPositions,\n distributionType,\n distributionWeight,\n}: UseEntryFeePreviewOptions): UseEntryFeePreviewReturn {\n const breakdown = useMemo(\n () => calculateEntryFeeBreakdown(feePerEntry, entryCount, shares),\n [feePerEntry, entryCount, shares.creatorShare, shares.gameCreatorShare, shares.refundShare],\n );\n\n const percentages = useMemo(\n () =>\n distributionPositions > 0\n ? calculateDistribution(\n distributionPositions,\n distributionWeight,\n 0,\n 0,\n 0,\n distributionType,\n )\n : [],\n [distributionPositions, distributionWeight, distributionType],\n );\n\n const positionPrizes = useMemo(\n () => distributePool(breakdown.prizePoolAmount, percentages),\n [breakdown.prizePoolAmount, percentages],\n );\n\n return { breakdown, positionPrizes, percentages };\n}\n","/**\n * Entry qualification evaluation.\n *\n * Pure functions that determine whether a user qualifies to enter a metagame\n * event based on pre-fetched data. Each metagame fetches the data through\n * their own SDK, then passes it here for evaluation.\n *\n * The evaluation logic is the same across metagames because the entry\n * requirement system (token gating, extensions) is shared.\n */\n\nimport type {\n EntryRequirementVariant,\n QualificationResult,\n QualificationEntry,\n} from \"../types/extensions\";\n\n// ---------------------------------------------------------------------------\n// Token-based qualification (NFT ownership)\n// ---------------------------------------------------------------------------\n\nexport interface TokenQualificationInput {\n /** NFT token IDs owned by the player */\n ownedTokenIds: string[];\n /** Number of times each token has been used to enter (tokenId → count) */\n usedEntryCounts: Record<string, number>;\n /** Max entries per token (0 = unlimited) */\n entryLimit: number;\n}\n\n/**\n * Evaluate token-based entry qualification.\n *\n * Checks if the player owns any qualifying NFTs and how many entries\n * remain for each. Selects the token with the most entries remaining\n * as the best proof.\n */\nexport function evaluateTokenQualification(\n input: TokenQualificationInput,\n): QualificationResult {\n if (input.ownedTokenIds.length === 0) {\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n };\n }\n\n const qualifications: QualificationEntry[] = [];\n\n for (const tokenId of input.ownedTokenIds) {\n const usedCount = input.usedEntryCounts[tokenId] ?? 0;\n const remaining =\n input.entryLimit > 0 ? input.entryLimit - usedCount : Infinity;\n\n if (remaining > 0) {\n qualifications.push({\n id: `token-${tokenId}`,\n entriesLeft: remaining,\n proof: { type: \"token\", tokenId },\n label: `Token #${tokenId}`,\n metadata: { tokenId },\n });\n }\n }\n\n const totalEntriesLeft = qualifications.reduce(\n (sum, q) => sum + (q.entriesLeft === Infinity ? 1 : q.entriesLeft),\n 0,\n );\n\n const best =\n qualifications.length > 0\n ? qualifications.reduce((a, b) =>\n b.entriesLeft > a.entriesLeft ? b : a,\n )\n : null;\n\n return {\n meetsRequirements: qualifications.length > 0,\n bestProof: best?.proof ?? null,\n qualifications,\n totalEntriesLeft,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Extension-based qualification\n// ---------------------------------------------------------------------------\n\nexport interface ExtensionQualificationInput {\n /** Results from checking each qualification method against the extension contract */\n checkedQualifications: Array<{\n id: string;\n entriesLeft: number;\n proof: string[];\n label?: string;\n metadata?: Record<string, unknown>;\n }>;\n}\n\n/**\n * Evaluate extension-based entry qualification from pre-checked results.\n *\n * Each metagame calls the extension contract's `entries_left` function\n * for each potential qualification proof, then passes the results here.\n * This function aggregates and selects the best qualification.\n */\nexport function evaluateExtensionQualification(\n input: ExtensionQualificationInput,\n): QualificationResult {\n const qualifications: QualificationEntry[] = input.checkedQualifications\n .filter((q) => q.entriesLeft > 0)\n .map((q) => ({\n id: q.id,\n entriesLeft: q.entriesLeft,\n proof: {\n type: \"extension\" as const,\n extensionProof: q.proof,\n },\n label: q.label,\n metadata: q.metadata,\n }));\n\n const totalEntriesLeft = qualifications.reduce(\n (sum, q) => sum + q.entriesLeft,\n 0,\n );\n\n const best =\n qualifications.length > 0\n ? qualifications.reduce((a, b) =>\n b.entriesLeft > a.entriesLeft ? b : a,\n )\n : null;\n\n return {\n meetsRequirements: qualifications.length > 0,\n bestProof: best?.proof ?? null,\n qualifications,\n totalEntriesLeft,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Combined qualification\n// ---------------------------------------------------------------------------\n\n/**\n * Evaluate entry qualification based on requirement variant.\n *\n * This is the top-level function — pass in the requirement type and\n * the appropriate input, get back a unified QualificationResult.\n */\nexport function evaluateQualification(\n variant: EntryRequirementVariant,\n input:\n | { type: \"token\"; data: TokenQualificationInput }\n | { type: \"extension\"; data: ExtensionQualificationInput }\n | { type: \"none\" },\n): QualificationResult {\n if (variant === \"none\" || input.type === \"none\") {\n return {\n meetsRequirements: true,\n bestProof: null,\n qualifications: [\n {\n id: \"no-requirement\",\n entriesLeft: Infinity,\n proof: { type: \"none\" },\n },\n ],\n totalEntriesLeft: Infinity,\n };\n }\n\n switch (input.type) {\n case \"token\":\n return evaluateTokenQualification(input.data);\n case \"extension\":\n return evaluateExtensionQualification(input.data);\n default:\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n };\n }\n}\n","import { useMemo } from \"react\";\nimport type {\n EntryRequirementVariant,\n QualificationResult,\n QualificationProof,\n TournamentValidatorConfig,\n} from \"../types/extensions\";\nimport {\n evaluateTokenQualification,\n evaluateExtensionQualification,\n} from \"../utils/qualification\";\n\n/**\n * A potential qualification the user has — e.g., an owned NFT, a tournament\n * they won.\n */\nexport interface QualificationMethod {\n /** Unique ID for deduplication */\n id: string;\n /** The proof to submit if this method is used */\n proof: QualificationProof;\n /** Human-readable label */\n label?: string;\n /** Additional display metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Pre-checked extension result from calling the extension contract.\n * Each metagame calls `entries_left` on-chain and passes results here.\n */\nexport interface CheckedExtensionQualification {\n id: string;\n entriesLeft: number;\n proof: string[];\n label?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UseEntryQualificationOptions {\n /** The type of entry requirement */\n variant: EntryRequirementVariant;\n\n // --- Token gating inputs ---\n /** NFT token IDs owned by the player */\n ownedTokenIds?: string[];\n /** How many times each token has been used (tokenId → count) */\n tokenEntryCounts?: Record<string, number>;\n\n /** The player's address */\n playerAddress?: string;\n\n // --- Extension inputs ---\n /** Pre-checked results from calling extension contract */\n extensionQualifications?: CheckedExtensionQualification[];\n /** For tournament validator: the parsed config */\n tournamentValidatorConfig?: TournamentValidatorConfig | null;\n /** For generic extensions: whether the contract says entry is valid */\n extensionValidEntry?: boolean;\n /** For generic extensions: entries left from contract */\n extensionEntriesLeft?: number | null;\n\n // --- Common ---\n /** Max entries allowed (0 = unlimited) */\n entryLimit?: number;\n}\n\nexport interface UseEntryQualificationReturn {\n /** Whether the user meets the entry requirements */\n meetsRequirements: boolean;\n /** The best proof to use for entering */\n bestProof: QualificationProof | null;\n /** All valid qualification methods */\n qualifications: QualificationResult[\"qualifications\"];\n /** Total entries remaining */\n totalEntriesLeft: number;\n /** Entries remaining grouped by source (tournament ID, token address, etc.) */\n entriesLeftBySource: Array<{\n sourceId?: string;\n sourceType?: string;\n entriesLeft: number;\n }>;\n}\n\n/**\n * Headless hook that evaluates whether a user qualifies to enter a\n * metagame event. Works for all requirement types (token, extension).\n *\n * Each metagame fetches the data through their own SDK (owned NFTs,\n * registrations, extension contract calls), then passes it here.\n * The evaluation logic is the same across all metagames.\n *\n * @example\n * ```tsx\n * const { meetsRequirements, bestProof, entriesLeftBySource } = useEntryQualification({\n * variant: \"token\",\n * ownedTokenIds: [\"123\", \"456\"],\n * tokenEntryCounts: { \"123\": 2, \"456\": 0 },\n * entryLimit: 3,\n * });\n *\n * // To enter, serialize the proof:\n * const onChainProof = buildQualificationProof(bestProof);\n * ```\n */\nexport function useEntryQualification(\n options: UseEntryQualificationOptions,\n): UseEntryQualificationReturn {\n const {\n variant,\n ownedTokenIds = [],\n tokenEntryCounts = {},\n playerAddress,\n extensionQualifications = [],\n tournamentValidatorConfig,\n extensionValidEntry = false,\n extensionEntriesLeft = null,\n entryLimit = 0,\n } = options;\n\n return useMemo(() => {\n // No requirement — always qualifies\n if (variant === \"none\") {\n return {\n meetsRequirements: true,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: Infinity,\n entriesLeftBySource: [{ entriesLeft: Infinity }],\n };\n }\n\n // Token-based (NFT ownership)\n if (variant === \"token\") {\n const result = evaluateTokenQualification({\n ownedTokenIds,\n usedEntryCounts: tokenEntryCounts,\n entryLimit,\n });\n\n return {\n meetsRequirements: result.meetsRequirements,\n bestProof: result.bestProof,\n qualifications: result.qualifications,\n totalEntriesLeft: result.totalEntriesLeft,\n entriesLeftBySource: result.meetsRequirements\n ? [{ sourceType: \"token\", entriesLeft: result.totalEntriesLeft }]\n : [],\n };\n }\n\n // Extension\n if (variant === \"extension\") {\n if (!playerAddress) {\n return empty();\n }\n\n // Tournament validator extension\n if (tournamentValidatorConfig && extensionQualifications.length > 0) {\n const result = evaluateExtensionQualification({\n checkedQualifications: extensionQualifications,\n });\n\n // Group entries by tournament/source\n const entriesBySource = new Map<string, number>();\n for (const qual of extensionQualifications) {\n if (qual.entriesLeft <= 0) continue;\n const sourceId =\n (qual.metadata?.tournamentId as string) ?? qual.id;\n const current = entriesBySource.get(sourceId) ?? 0;\n entriesBySource.set(sourceId, current + qual.entriesLeft);\n }\n\n // Check qualifying mode — modes 2, 4, 5 require ALL tournaments\n const qualifyingMode = tournamentValidatorConfig.qualifyingMode;\n let meetsRequirements: boolean;\n if (\n qualifyingMode === 0 ||\n qualifyingMode === 1 ||\n qualifyingMode === 3\n ) {\n meetsRequirements = result.meetsRequirements;\n } else {\n // Must have qualifications for every required tournament\n meetsRequirements =\n entriesBySource.size >=\n tournamentValidatorConfig.tournamentIds.length;\n }\n\n return {\n meetsRequirements,\n bestProof: result.bestProof,\n qualifications: result.qualifications,\n totalEntriesLeft: result.totalEntriesLeft,\n entriesLeftBySource: Array.from(entriesBySource.entries()).map(\n ([sourceId, entriesLeft]) => ({\n sourceId,\n sourceType: \"tournament\",\n entriesLeft,\n }),\n ),\n };\n }\n\n // Generic extension\n const remaining =\n extensionEntriesLeft !== null ? extensionEntriesLeft : Infinity;\n\n if (extensionValidEntry && remaining > 0) {\n return {\n meetsRequirements: true,\n bestProof: { type: \"extension\", extensionProof: [] },\n qualifications: [],\n totalEntriesLeft: remaining,\n entriesLeftBySource: [\n { sourceType: \"extension\", entriesLeft: remaining },\n ],\n };\n }\n\n return empty();\n }\n\n return empty();\n }, [\n variant,\n ownedTokenIds,\n tokenEntryCounts,\n playerAddress,\n extensionQualifications,\n tournamentValidatorConfig,\n extensionValidEntry,\n extensionEntriesLeft,\n entryLimit,\n ]);\n}\n\nfunction empty(): UseEntryQualificationReturn {\n return {\n meetsRequirements: false,\n bestProof: null,\n qualifications: [],\n totalEntriesLeft: 0,\n entriesLeftBySource: [],\n };\n}\n","/**\n * RPC calls for EGS entry requirement extensions.\n *\n * These functions call the shared extension contracts on Starknet.\n * They take a starknet.js provider (or any object with callContract)\n * and return parsed results.\n *\n * Every metagame that uses the entry requirement system needs these\n * same calls — they're not app-specific, they call the same contracts.\n */\n\nimport { CallData, type BigNumberish } from \"starknet\";\n\n/** Minimal provider interface — anything with callContract works */\nexport interface StarknetCallProvider {\n callContract(call: {\n contractAddress: string;\n entrypoint: string;\n calldata: string[];\n }): Promise<string[]>;\n}\n\n// ---------------------------------------------------------------------------\n// Extension contract calls (IEntryRequirementExtension)\n// ---------------------------------------------------------------------------\n\n/**\n * Check if a player has a valid entry for an extension-gated event.\n *\n * Calls `valid_entry(context_id, player_address, qualification)` on the\n * extension contract.\n *\n * @param provider - Starknet RPC provider\n * @param extensionAddress - The extension contract address\n * @param contextId - The metagame event ID (tournament ID, quest ID, etc.)\n * @param playerAddress - The player's address\n * @param qualification - Proof data (felt252 array)\n * @returns Whether the entry is valid\n */\nexport async function checkExtensionValidEntry(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n playerAddress: string,\n qualification: string[],\n): Promise<boolean> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"valid_entry\",\n calldata: CallData.compile([contextId, playerAddress, qualification]),\n });\n return result[0] === \"0x1\" || BigInt(result[0]) === 1n;\n } catch (error) {\n console.error(\"Error checking extension valid_entry:\", error);\n return false;\n }\n}\n\n/**\n * Get the number of entries left for a player via an extension.\n *\n * Calls `entries_left(context_id, player_address, qualification)` on the\n * extension contract. Returns null if the extension has no entry limit\n * (Option::None).\n *\n * @returns Number of entries remaining, or null if unlimited\n */\nexport async function getExtensionEntriesLeft(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n playerAddress: string,\n qualification: string[],\n): Promise<number | null> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"entries_left\",\n calldata: CallData.compile([contextId, playerAddress, qualification]),\n });\n\n // Result is Option<u8>\n // Option::None: result[0] is 1\n // Option::Some: result[0] is 0, result[1] is the value\n if (result[0] === \"0x1\" || BigInt(result[0]) === 1n) {\n return null; // No limit\n }\n return Number(result[1]);\n } catch (error) {\n console.error(\"Error checking extension entries_left:\", error);\n return null;\n }\n}\n\n/**\n * Check if a player's entry should be banned via an extension.\n *\n * Calls `should_ban(context_id, game_token_id, current_owner, proof)`.\n *\n * @param gameTokenId - The game token ID to check (felt252)\n * @param currentOwner - Current owner of the game token\n * @param proof - Ban proof data (felt252 array)\n * @returns Whether the entry should be banned\n */\nexport async function checkExtensionShouldBan(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n gameTokenId: string,\n currentOwner: string,\n proof: string[],\n): Promise<boolean> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"should_ban\",\n calldata: CallData.compile([contextId, gameTokenId, currentOwner, proof]),\n });\n return result[0] === \"0x1\" || BigInt(result[0]) === 1n;\n } catch (error) {\n console.error(\"Error checking extension should_ban:\", error);\n return false;\n }\n}\n\n/**\n * Get the context owner for an entry requirement extension contract.\n *\n * Extensions are multi-tenant: each context_id has its own owner\n * (set by the first caller to configure that context via add_config).\n *\n * @param provider - Starknet RPC provider\n * @param extensionAddress - The extension contract address\n * @param contextId - The metagame event ID (tournament ID, quest ID, etc.)\n * @returns The owner address for that context, or empty string if unclaimed\n */\nexport async function getEntryRequirementContextOwner(\n provider: StarknetCallProvider,\n extensionAddress: string,\n contextId: BigNumberish,\n): Promise<string> {\n try {\n const result = await provider.callContract({\n contractAddress: extensionAddress,\n entrypoint: \"context_owner\",\n calldata: CallData.compile([contextId]),\n });\n return result[0] ?? \"\";\n } catch (error) {\n console.error(\"Error checking extension context_owner:\", error);\n return \"\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Opus Protocol calls (for Opus Troves extension)\n// ---------------------------------------------------------------------------\n\n/** Mainnet Opus Abbot contract address */\nconst OPUS_ABBOT_ADDRESS =\n \"0x04d0bb0a4c40012384e7c419e6eb3c637b28e8363fb66958b60d90505b9c072f\";\n\n/** Mainnet Opus Shrine contract address */\nconst OPUS_SHRINE_ADDRESS =\n \"0x0498edfaf50ca5855666a700c25dd629d577eb9afccdf3b5977aec79aee55ada\";\n\n/**\n * Get all trove IDs owned by a user from the Opus Abbot contract.\n *\n * @param provider - Starknet RPC provider\n * @param userAddress - The user's address\n * @param abbotAddress - Override Abbot address (defaults to mainnet)\n * @returns Array of trove IDs\n */\nexport async function getUserTroveIds(\n provider: StarknetCallProvider,\n userAddress: BigNumberish,\n abbotAddress: string = OPUS_ABBOT_ADDRESS,\n): Promise<bigint[]> {\n try {\n const result = await provider.callContract({\n contractAddress: abbotAddress,\n entrypoint: \"get_user_trove_ids\",\n calldata: CallData.compile([userAddress]),\n });\n\n // Result: [array_length, ...trove_ids]\n const arrayLength = Number(result[0] || 0);\n const troveIds: bigint[] = [];\n for (let i = 1; i <= arrayLength; i++) {\n troveIds.push(BigInt(result[i] || 0));\n }\n return troveIds;\n } catch (error) {\n console.error(\"Error getting user trove IDs:\", error);\n return [];\n }\n}\n\n/**\n * Get a trove's debt from the Opus Shrine contract.\n *\n * Calls `get_trove_health(trove_id)` which returns [value, threshold, ltv, debt].\n * We extract the debt (18 decimals, denominated in CASH which is 1:1 USD).\n *\n * @param provider - Starknet RPC provider\n * @param troveId - The trove ID\n * @param shrineAddress - Override Shrine address (defaults to mainnet)\n * @returns Debt amount in CASH (18 decimals), or null on error\n */\nexport async function getTroveDebt(\n provider: StarknetCallProvider,\n troveId: BigNumberish,\n shrineAddress: string = OPUS_SHRINE_ADDRESS,\n): Promise<bigint | null> {\n try {\n const result = await provider.callContract({\n contractAddress: shrineAddress,\n entrypoint: \"get_trove_health\",\n calldata: CallData.compile([troveId]),\n });\n return BigInt(result[3] || 0);\n } catch (error) {\n console.error(\"Error getting trove health:\", error);\n return null;\n }\n}\n\n/**\n * Get total debt across all of a user's troves.\n *\n * Convenience function that calls getUserTroveIds then getTroveDebt for each.\n *\n * @param provider - Starknet RPC provider\n * @param userAddress - The user's address\n * @returns Total debt in CASH (18 decimals)\n */\nexport async function getUserTotalTroveDebt(\n provider: StarknetCallProvider,\n userAddress: BigNumberish,\n abbotAddress?: string,\n shrineAddress?: string,\n): Promise<bigint> {\n const troveIds = await getUserTroveIds(provider, userAddress, abbotAddress);\n if (troveIds.length === 0) return 0n;\n\n let totalDebt = 0n;\n for (const troveId of troveIds) {\n const debt = await getTroveDebt(provider, troveId, shrineAddress);\n if (debt !== null) totalDebt += debt;\n }\n return totalDebt;\n}\n","/**\n * Hook to check extension qualification and entries left for multiple proofs.\n *\n * Ported from budokan — accepts a provider instead of relying on app-specific hooks.\n */\n\nimport { useState, useEffect, useMemo, useRef } from \"react\";\nimport { getExtensionEntriesLeft, type StarknetCallProvider } from \"../rpc/extensions\";\n\n/** A single qualification method for an extension */\nexport interface ExtensionQualification {\n id: string;\n proof: string[];\n entriesLeft: number;\n label?: string;\n metadata?: {\n tournamentId?: string;\n tournamentName?: string;\n tokenId?: string;\n position?: number;\n [key: string]: unknown;\n };\n}\n\n/** Result from extension qualification check */\nexport interface ExtensionQualificationResult {\n qualifications: ExtensionQualification[];\n totalEntriesLeft: number;\n bestQualification: ExtensionQualification | null;\n loading: boolean;\n error: Error | null;\n}\n\n/** Input for building qualifications — tournament validator specific */\nexport interface TournamentValidatorInput {\n tournamentId: string;\n tokenId: string;\n position: number;\n tournamentName?: string;\n}\n\n/**\n * Check extension qualification and entries left for multiple proofs.\n *\n * @param provider - Starknet RPC provider (or null to disable)\n * @param extensionAddress - The extension contract address\n * @param contextId - The metagame event ID (tournament ID, etc.)\n * @param playerAddress - The player's address\n * @param qualificationInputs - Potential qualifications to check\n * @param enabled - Whether to run the check (default: true)\n */\nexport const useExtensionQualification = (\n provider: StarknetCallProvider | null,\n extensionAddress: string | undefined,\n contextId: string | undefined,\n playerAddress: string | undefined,\n qualificationInputs: TournamentValidatorInput[],\n enabled: boolean = true,\n): ExtensionQualificationResult => {\n const [qualifications, setQualifications] = useState<ExtensionQualification[]>([]);\n const [loading, setLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n const inputsKey = useMemo(() => {\n if (!enabled || !provider || !extensionAddress || !contextId || !playerAddress) {\n return \"\";\n }\n return JSON.stringify({\n extensionAddress,\n contextId,\n playerAddress,\n inputs: qualificationInputs.map((i) => ({\n tid: i.tournamentId,\n token: i.tokenId,\n pos: i.position,\n })),\n });\n }, [enabled, provider, extensionAddress, contextId, playerAddress, qualificationInputs]);\n\n const lastFetchedKey = useRef<string>(\"\");\n\n useEffect(() => {\n if (!enabled) {\n lastFetchedKey.current = \"\";\n setQualifications([]);\n setLoading(false);\n setError(null);\n }\n }, [enabled]);\n\n useEffect(() => {\n if (!inputsKey) return;\n if (inputsKey === lastFetchedKey.current) return;\n\n const checkQualifications = async () => {\n lastFetchedKey.current = inputsKey;\n setLoading(true);\n setError(null);\n\n try {\n const results = await Promise.all(\n qualificationInputs.map(async (input) => {\n try {\n const proof = [\n input.tournamentId,\n input.tokenId,\n input.position.toString(),\n ];\n\n const entriesLeft = await getExtensionEntriesLeft(\n provider!,\n extensionAddress!,\n contextId!,\n playerAddress!,\n proof,\n );\n\n if (entriesLeft !== null && entriesLeft > 0) {\n return {\n id: `${input.tournamentId}-${input.tokenId}-${input.position}`,\n proof,\n entriesLeft,\n label: input.tournamentName,\n metadata: {\n tournamentId: input.tournamentId,\n tournamentName: input.tournamentName,\n tokenId: input.tokenId,\n position: input.position,\n },\n } as ExtensionQualification;\n }\n return null;\n } catch (err) {\n console.error(\n `Error checking qualification for ${input.tournamentId}:`,\n err,\n );\n return null;\n }\n }),\n );\n\n const validQualifications = results.filter(\n (q): q is ExtensionQualification => q !== null,\n );\n setQualifications(validQualifications);\n } catch (err) {\n console.error(\"Error checking extension qualifications:\", err);\n setError(err instanceof Error ? err : new Error(String(err)));\n setQualifications([]);\n } finally {\n setLoading(false);\n }\n };\n\n checkQualifications();\n }, [inputsKey, provider, extensionAddress, contextId, playerAddress, qualificationInputs]);\n\n const totalEntriesLeft = qualifications.reduce(\n (sum, q) => sum + q.entriesLeft,\n 0,\n );\n\n const bestQualification =\n qualifications.length > 0\n ? qualifications.reduce((best, current) =>\n current.entriesLeft > best.entriesLeft ? current : best,\n )\n : null;\n\n return {\n qualifications,\n totalEntriesLeft,\n bestQualification,\n loading,\n error,\n };\n};\n","/**\n * Opus Troves entry calculation.\n *\n * The Opus Troves extension gates entry based on the player's CASH debt\n * in the Opus Protocol. This module contains the pure math for determining\n * how many entries a given debt level allows, and which entries are bannable\n * if a player's debt drops below the threshold.\n *\n * The trove debt fetching (getUserTroveIds, getTroveHealth) is RPC-specific\n * and stays in each app. This module handles the calculation once you have\n * the debt value.\n */\n\nimport type { OpusTrovesValidatorConfig } from \"../types/extensions\";\n\n/**\n * Calculate how many entries a player's total debt allows.\n *\n * Two modes based on config:\n * - Proportional (valuePerEntry > 0): entries = (debt - threshold) / valuePerEntry\n * - Fixed (valuePerEntry == 0): if debt >= threshold → maxEntries\n *\n * @param debt - Player's total CASH debt across all troves (18 decimals)\n * @param config - Parsed Opus Troves validator config\n * @returns Number of entries allowed (0 if below threshold)\n */\nexport function calculateOpusTrovesEntries(\n debt: bigint,\n config: OpusTrovesValidatorConfig,\n): number {\n let allowed = 0;\n\n if (config.valuePerEntry > 0n) {\n // Proportional: entries scale with debt above threshold\n if (debt > config.threshold) {\n allowed = Number((debt - config.threshold) / config.valuePerEntry);\n }\n } else {\n // Fixed: meets threshold → gets maxEntries\n if (debt >= config.threshold && config.maxEntries > 0) {\n allowed = config.maxEntries;\n }\n }\n\n // Cap at maxEntries if specified\n if (config.maxEntries > 0) {\n allowed = Math.min(allowed, config.maxEntries);\n }\n\n return allowed;\n}\n\n/**\n * Determine which entries should be banned based on debt vs allowed entries.\n *\n * When a player's debt drops below what their entries require, the excess\n * entries (sorted by token ID ascending — oldest first) become bannable.\n *\n * @param registeredTokenIds - Token IDs the player registered with\n * @param entriesAllowed - From calculateOpusTrovesEntries()\n * @returns Set of token IDs that should be banned\n */\nexport function findBannableEntries(\n registeredTokenIds: string[],\n entriesAllowed: number,\n): Set<string> {\n const bannable = new Set<string>();\n const bannableCount = Math.max(0, registeredTokenIds.length - entriesAllowed);\n\n if (bannableCount > 0) {\n // Sort by token ID ascending (oldest entries first)\n const sorted = [...registeredTokenIds].sort((a, b) => {\n return Number(BigInt(a)) - Number(BigInt(b));\n });\n for (let i = 0; i < bannableCount; i++) {\n bannable.add(sorted[i]);\n }\n }\n\n return bannable;\n}\n\n/**\n * Batch calculate bannable entries for multiple players.\n *\n * Takes a map of player → { debt, registeredTokenIds } and returns\n * the set of all bannable token IDs across all players.\n *\n * @param players - Map of player address → their debt and registered entries\n * @param config - Parsed Opus Troves validator config\n * @returns Set of all bannable token IDs\n */\nexport function findAllBannableEntries(\n players: Map<string, { debt: bigint; registeredTokenIds: string[] }>,\n config: OpusTrovesValidatorConfig,\n): Set<string> {\n const allBannable = new Set<string>();\n\n for (const [, { debt, registeredTokenIds }] of players) {\n const allowed = calculateOpusTrovesEntries(debt, config);\n const bannable = findBannableEntries(registeredTokenIds, allowed);\n for (const id of bannable) {\n allBannable.add(id);\n }\n }\n\n return allBannable;\n}\n","/**\n * Hook to calculate bannable entries for Opus Troves extension.\n *\n * Ported from budokan — accepts a provider instead of relying on app-specific hooks.\n */\n\nimport { useState, useEffect, useMemo } from \"react\";\nimport type { OpusTrovesValidatorConfig } from \"../types/extensions\";\nimport { getUserTotalTroveDebt, type StarknetCallProvider } from \"../rpc/extensions\";\nimport { findAllBannableEntries } from \"../utils/opusTroves\";\n\ninterface Game {\n tokenId: number | bigint;\n owner?: string;\n}\n\nexport interface UseOpusTrovesBannableEntriesResult {\n bannableEntries: Set<string>;\n troveDebts: Map<string, bigint>;\n isLoading: boolean;\n playerGroups: Map<string, Game[]>;\n}\n\n/**\n * Calculate bannable entries for Opus Troves extension.\n *\n * @param provider - Starknet RPC provider (or null to disable)\n * @param games - Array of game entries with tokenId and owner\n * @param config - Opus Troves validator config (or undefined to disable)\n * @param enabled - Whether to run the check\n */\nexport const useOpusTrovesBannableEntries = (\n provider: StarknetCallProvider | null,\n games: Array<{ tokenId: number | bigint; owner?: string }>,\n config: OpusTrovesValidatorConfig | undefined,\n enabled: boolean,\n): UseOpusTrovesBannableEntriesResult => {\n const [troveDebts, setTroveDebts] = useState<Map<string, bigint>>(new Map());\n const [isLoading, setIsLoading] = useState(false);\n\n const playerGroups = useMemo(() => {\n const groups = new Map<string, Game[]>();\n games.forEach((game) => {\n const owner = game?.owner;\n if (!owner) return;\n if (!groups.has(owner)) groups.set(owner, []);\n groups.get(owner)!.push(game);\n });\n return groups;\n }, [games]);\n\n const playerAddresses = useMemo(\n () => Array.from(playerGroups.keys()),\n [playerGroups],\n );\n\n useEffect(() => {\n if (!enabled || !provider || !config || playerAddresses.length === 0) {\n setTroveDebts(new Map());\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n\n const fetchDebts = async () => {\n const debts = new Map<string, bigint>();\n await Promise.all(\n playerAddresses.map(async (addr) => {\n try {\n const debt = await getUserTotalTroveDebt(provider, addr);\n debts.set(addr, debt);\n } catch {\n debts.set(addr, 0n);\n }\n }),\n );\n if (!cancelled) {\n setTroveDebts(debts);\n setIsLoading(false);\n }\n };\n\n fetchDebts();\n return () => { cancelled = true; };\n }, [enabled, provider, config, playerAddresses]);\n\n const bannableEntries = useMemo(() => {\n if (!enabled || isLoading || !config) return new Set<string>();\n\n const players = new Map<string, { debt: bigint; registeredTokenIds: string[] }>();\n for (const [owner, ownerGames] of playerGroups.entries()) {\n players.set(owner, {\n debt: troveDebts.get(owner) ?? 0n,\n registeredTokenIds: ownerGames.map((g) => g.tokenId.toString()),\n });\n }\n\n return findAllBannableEntries(players, config);\n }, [enabled, isLoading, playerGroups, troveDebts, config]);\n\n return {\n bannableEntries,\n troveDebts,\n isLoading,\n playerGroups,\n };\n};\n"]}
|
package/dist/react.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as Token, S as StatusTimestamps, a as StatusResult, l as Participant, P as Prize, m as PositionPrizeGroup, j as EntryFeeShares, D as DistributionType, h as EntryFeeBreakdown, g as QualificationProof, f as EntryRequirementVariant, T as TournamentValidatorConfig, e as QualificationResult, O as OpusTrovesValidatorConfig } from './prizeAggregation-
|
|
1
|
+
import { s as Token, S as StatusTimestamps, a as StatusResult, l as Participant, P as Prize, m as PositionPrizeGroup, j as EntryFeeShares, D as DistributionType, h as EntryFeeBreakdown, g as QualificationProof, f as EntryRequirementVariant, T as TournamentValidatorConfig, e as QualificationResult, O as OpusTrovesValidatorConfig } from './prizeAggregation-CHwIJzXr.cjs';
|
|
2
2
|
import { S as StarknetCallProvider } from './extensions-BskkhEHk.cjs';
|
|
3
3
|
import 'starknet';
|
|
4
4
|
|
|
@@ -139,7 +139,7 @@ declare function useEntryFeePreview({ feePerEntry, entryCount, shares, distribut
|
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
141
|
* A potential qualification the user has — e.g., an owned NFT, a tournament
|
|
142
|
-
* they won
|
|
142
|
+
* they won.
|
|
143
143
|
*/
|
|
144
144
|
interface QualificationMethod {
|
|
145
145
|
/** Unique ID for deduplication */
|
|
@@ -171,10 +171,6 @@ interface UseEntryQualificationOptions {
|
|
|
171
171
|
tokenEntryCounts?: Record<string, number>;
|
|
172
172
|
/** The player's address */
|
|
173
173
|
playerAddress?: string;
|
|
174
|
-
/** Addresses on the allowlist */
|
|
175
|
-
allowlist?: string[];
|
|
176
|
-
/** How many times this address has already entered */
|
|
177
|
-
addressEntryCount?: number;
|
|
178
174
|
/** Pre-checked results from calling extension contract */
|
|
179
175
|
extensionQualifications?: CheckedExtensionQualification[];
|
|
180
176
|
/** For tournament validator: the parsed config */
|
|
@@ -204,8 +200,7 @@ interface UseEntryQualificationReturn {
|
|
|
204
200
|
}
|
|
205
201
|
/**
|
|
206
202
|
* Headless hook that evaluates whether a user qualifies to enter a
|
|
207
|
-
* metagame event. Works for all requirement types (token,
|
|
208
|
-
* extension).
|
|
203
|
+
* metagame event. Works for all requirement types (token, extension).
|
|
209
204
|
*
|
|
210
205
|
* Each metagame fetches the data through their own SDK (owned NFTs,
|
|
211
206
|
* registrations, extension contract calls), then passes it here.
|