@provable-games/metagame-sdk 0.1.0 → 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.
@@ -0,0 +1,325 @@
1
+ interface Token {
2
+ address: string;
3
+ name: string;
4
+ symbol: string;
5
+ tokenType: "erc20" | "erc721";
6
+ decimals?: number;
7
+ logoUrl?: string;
8
+ }
9
+
10
+ interface Prize {
11
+ id: string;
12
+ position: number;
13
+ tokenAddress: string;
14
+ tokenType: "erc20" | "erc721";
15
+ amount: string;
16
+ sponsorAddress: string;
17
+ }
18
+
19
+ interface Participant {
20
+ address: string;
21
+ rank?: number;
22
+ score?: number;
23
+ name?: string;
24
+ entryNumber?: number;
25
+ }
26
+
27
+ type StatusVariant = "upcoming" | "registration" | "active" | "submission" | "ended" | "completed" | "locked";
28
+ interface StatusTimestamps {
29
+ registrationStart?: number | null;
30
+ registrationEnd?: number | null;
31
+ start: number;
32
+ end: number;
33
+ submissionEnd?: number | null;
34
+ completed?: boolean;
35
+ unlocked?: boolean;
36
+ }
37
+ interface StatusResult {
38
+ label: string;
39
+ variant: StatusVariant;
40
+ isActive: boolean;
41
+ countdown: {
42
+ targetTimestamp: number;
43
+ label: string;
44
+ } | null;
45
+ }
46
+
47
+ /**
48
+ * Entry requirement and extension types.
49
+ *
50
+ * These types represent the shared entry requirement system used by
51
+ * EGS metagames. The on-chain extension contracts (tournament validator,
52
+ * ERC20 balance, Opus Troves, Snapshot) are deployed once and used by
53
+ * all metagames — the config parsing and qualification logic is the same.
54
+ */
55
+ /** The type of entry requirement on a metagame event */
56
+ type EntryRequirementVariant = "token" | "extension" | "none";
57
+ /** Known extension types (deployed as shared contracts) */
58
+ type ExtensionType = "tournament" | "erc20Balance" | "opusTroves" | "snapshot" | "zkPassport" | "governance" | "unknown";
59
+ /** Broad category of an extension */
60
+ type ExtensionCategory = "entryRequirement" | "entryFee" | "prize";
61
+ /** Deployed extension contract addresses per chain */
62
+ interface ExtensionAddresses {
63
+ tournamentValidator?: string;
64
+ erc20BalanceValidator?: string;
65
+ opusTrovesValidator?: string;
66
+ snapshotValidator?: string;
67
+ zkPassportValidator?: string;
68
+ governanceValidator?: string;
69
+ }
70
+ /** Parsed config for the tournament validator extension */
71
+ interface TournamentValidatorConfig {
72
+ /** "won" = must have placed in top N, "participated" = just entered */
73
+ requirementType: "won" | "participated";
74
+ /** How tournaments are combined for qualification */
75
+ qualifyingMode: QualifyingMode;
76
+ /** Number of top positions that count (0 = all positions) */
77
+ topPositions: number;
78
+ /** Tournament IDs that qualify */
79
+ tournamentIds: string[];
80
+ }
81
+ /** How multiple qualifying tournaments are evaluated */
82
+ declare enum QualifyingMode {
83
+ /** Qualify in at least one tournament */
84
+ AtLeastOne = 0,
85
+ /** Track entry limits separately per tournament */
86
+ CumulativePerTournament = 1,
87
+ /** Must qualify in all tournaments */
88
+ All = 2,
89
+ /** Track entries per qualifying token ID */
90
+ CumulativePerEntry = 3,
91
+ /** Must participate in all, win in any one */
92
+ AllParticipateAnyWin = 4,
93
+ /** Must participate in all, entries multiply by count */
94
+ AllWithCumulative = 5
95
+ }
96
+ /** Human-readable label and description for a qualifying mode */
97
+ interface QualifyingModeInfo {
98
+ label: string;
99
+ description: string;
100
+ }
101
+ /** Parsed config for the ERC20 balance validator extension */
102
+ interface ERC20BalanceValidatorConfig {
103
+ tokenAddress: string;
104
+ /** Minimum token balance required (raw, in smallest units) */
105
+ minThreshold: bigint;
106
+ /** Maximum token balance cap (raw, 0 = unlimited) */
107
+ maxThreshold: bigint;
108
+ /** Token amount per entry (raw, 0 = single entry regardless of balance) */
109
+ valuePerEntry: bigint;
110
+ /** Maximum entries allowed (0 = unlimited) */
111
+ maxEntries: number;
112
+ }
113
+ /** Parsed config for the Opus Troves validator extension */
114
+ interface OpusTrovesValidatorConfig {
115
+ /** Number of specific assets required (0 = wildcard, any asset) */
116
+ assetCount: number;
117
+ /** Specific collateral asset addresses (empty if wildcard) */
118
+ assetAddresses: string[];
119
+ /** Minimum debt threshold (raw, 18 decimals — CASH is 1:1 USD) */
120
+ threshold: bigint;
121
+ /** Debt value per entry (raw, 0 = single entry) */
122
+ valuePerEntry: bigint;
123
+ /** Maximum entries allowed (0 = unlimited) */
124
+ maxEntries: number;
125
+ }
126
+ /** Parsed config for the Snapshot validator extension */
127
+ interface SnapshotValidatorConfig {
128
+ snapshotId: string;
129
+ }
130
+ /** Result of checking whether a user qualifies to enter */
131
+ interface QualificationResult {
132
+ /** Whether the user meets the entry requirements */
133
+ meetsRequirements: boolean;
134
+ /** The best proof to submit (app-specific format) */
135
+ bestProof: QualificationProof | null;
136
+ /** All valid qualification methods with entries remaining */
137
+ qualifications: QualificationEntry[];
138
+ /** Total entries remaining across all qualification methods */
139
+ totalEntriesLeft: number;
140
+ }
141
+ /** A single way the user can qualify */
142
+ interface QualificationEntry {
143
+ /** Unique ID for this qualification method */
144
+ id: string;
145
+ /** Entries remaining via this method */
146
+ entriesLeft: number;
147
+ /** The proof data for this qualification */
148
+ proof: QualificationProof;
149
+ /** Human-readable label */
150
+ label?: string;
151
+ /** Additional metadata for display */
152
+ metadata?: Record<string, unknown>;
153
+ }
154
+ /** Parsed config for the ZK Passport validator extension */
155
+ interface ZkPassportValidatorConfig {
156
+ verifierAddress: string;
157
+ serviceScope: bigint;
158
+ subscope: bigint;
159
+ paramCommitment: bigint;
160
+ maxProofAge: number;
161
+ nullifierType: number;
162
+ }
163
+ /** Parsed config for the Governance validator extension */
164
+ interface GovernanceValidatorConfig {
165
+ governorAddress: string;
166
+ governanceTokenAddress: string;
167
+ balanceThreshold: bigint;
168
+ proposalId: bigint;
169
+ checkVoted: boolean;
170
+ votesThreshold: bigint;
171
+ votesPerEntry: bigint;
172
+ }
173
+ /** Generic config placeholder for entry fee extensions */
174
+ interface EntryFeeExtensionConfig {
175
+ tokenAddress: string;
176
+ amount: bigint;
177
+ /** Additional config fields (extension-specific) */
178
+ extra?: Record<string, unknown>;
179
+ }
180
+ /** Generic config placeholder for prize extensions */
181
+ interface PrizeExtensionConfig {
182
+ tokenAddress: string;
183
+ amount: bigint;
184
+ /** Additional config fields (extension-specific) */
185
+ extra?: Record<string, unknown>;
186
+ }
187
+ /** Proof data for entering — varies by requirement type */
188
+ interface QualificationProof {
189
+ type: EntryRequirementVariant;
190
+ /** For token requirements: the NFT token ID to use */
191
+ tokenId?: string;
192
+ /** Raw proof array to pass to the extension contract */
193
+ extensionProof?: string[];
194
+ }
195
+
196
+ declare function formatNumber(num: number): string;
197
+ declare function formatPrizeAmount(num: number): string;
198
+ declare function formatUsdValue(value: number): string;
199
+ declare function formatScore(num: number): string;
200
+ declare function formatTime(seconds: number): string;
201
+ declare function getOrdinalSuffix(position: number): string;
202
+ type DistributionType = "linear" | "exponential" | "uniform";
203
+ declare function calculatePayouts(totalPlaces: number, weightingFactor: number): number[];
204
+ declare function calculateDistribution(positions: number, weight: number, creatorFee?: number, gameFee?: number, refundShare?: number, distributionType?: DistributionType): number[];
205
+
206
+ /**
207
+ * Entry fee breakdown calculation.
208
+ *
209
+ * Takes a total fee pool and share percentages (in basis points, where 10000 = 100%)
210
+ * and returns the amount allocated to each bucket.
211
+ *
212
+ * This is the same math that on-chain metagame contracts use to split entry fees
213
+ * between creator, game creator, refund pool, and prize pool.
214
+ */
215
+ interface EntryFeeBreakdown {
216
+ /** Total fee collected from all entrants */
217
+ totalCollected: bigint;
218
+ /** Amount going to the metagame creator */
219
+ creatorAmount: bigint;
220
+ /** Amount going to the game creator */
221
+ gameCreatorAmount: bigint;
222
+ /** Amount reserved for refunds */
223
+ refundAmount: bigint;
224
+ /** Amount available for prize distribution */
225
+ prizePoolAmount: bigint;
226
+ }
227
+ interface EntryFeeShares {
228
+ /** Creator share in basis points (0-10000) */
229
+ creatorShare: number;
230
+ /** Game creator share in basis points (0-10000) */
231
+ gameCreatorShare: number;
232
+ /** Refund share in basis points (0-10000) */
233
+ refundShare: number;
234
+ }
235
+ /**
236
+ * Calculate how an entry fee pool is split between creator, game, refund, and prizes.
237
+ *
238
+ * @param feePerEntry - Fee amount per entry (in token units, as bigint)
239
+ * @param entryCount - Number of entries
240
+ * @param shares - Share percentages in basis points (10000 = 100%)
241
+ * @returns Breakdown of amounts for each bucket
242
+ */
243
+ declare function calculateEntryFeeBreakdown(feePerEntry: bigint, entryCount: number, shares: EntryFeeShares): EntryFeeBreakdown;
244
+ /**
245
+ * Distribute a prize pool across positions using a distribution curve.
246
+ *
247
+ * Takes the prize pool amount and distribution percentages (from calculateDistribution),
248
+ * and returns the actual token amount per position.
249
+ *
250
+ * @param prizePoolAmount - Total pool to distribute (bigint, in smallest token units)
251
+ * @param percentages - Distribution percentages per position (from calculateDistribution)
252
+ * @returns Array of { position, amount } where position is 1-indexed
253
+ */
254
+ declare function distributePool(prizePoolAmount: bigint, percentages: number[]): Array<{
255
+ position: number;
256
+ amount: bigint;
257
+ }>;
258
+
259
+ /**
260
+ * Prize aggregation by position.
261
+ *
262
+ * Groups prizes by position, summing ERC20 amounts and collecting ERC721 IDs.
263
+ * Works with Prize — metagame apps adapt their raw prize data to this
264
+ * shape before calling these functions.
265
+ */
266
+ interface PositionPrizeGroup {
267
+ position: number;
268
+ erc20: Array<{
269
+ tokenAddress: string;
270
+ totalAmount: bigint;
271
+ }>;
272
+ erc721: Array<{
273
+ tokenAddress: string;
274
+ tokenIds: string[];
275
+ }>;
276
+ }
277
+ /**
278
+ * Group prizes by leaderboard position, aggregating ERC20 amounts and
279
+ * collecting ERC721 token IDs per position.
280
+ */
281
+ declare function aggregatePrizesByPosition(prizes: Prize[]): PositionPrizeGroup[];
282
+ /**
283
+ * Sponsor contribution aggregated from prizes.
284
+ */
285
+ interface SponsorContribution {
286
+ sponsorAddress: string;
287
+ tokens: Array<{
288
+ tokenAddress: string;
289
+ totalAmount: bigint;
290
+ prizeCount: number;
291
+ }>;
292
+ /** NFT collections grouped by token address, with individual token IDs */
293
+ nftCollections: Array<{
294
+ tokenAddress: string;
295
+ tokenIds: string[];
296
+ }>;
297
+ nftCount: number;
298
+ totalPrizeCount: number;
299
+ }
300
+ /**
301
+ * Group prizes by sponsor address, aggregating ERC20 contributions and
302
+ * grouping NFTs by collection. Filters out prizes with no sponsor
303
+ * (address "0x0" or empty).
304
+ *
305
+ * For ERC721 prizes, `prize.amount` is expected to hold the token ID
306
+ * (this is the convention set by the prize adapter).
307
+ *
308
+ * @param prizes - Array of Prize with sponsorAddress populated
309
+ * @returns Sponsor contributions sorted by total prize count (descending)
310
+ */
311
+ declare function aggregatePrizesBySponsor(prizes: Prize[]): SponsorContribution[];
312
+ /**
313
+ * Filter prizes to only those not yet claimed.
314
+ *
315
+ * @param prizes - All prizes the user could potentially claim
316
+ * @param claimedIds - Set of prize IDs already claimed
317
+ * @returns Prizes not yet claimed
318
+ */
319
+ declare function filterClaimablePrizes(prizes: Prize[], claimedIds: Set<string>): Prize[];
320
+ /**
321
+ * Filter out ERC20 prizes with zero amount.
322
+ */
323
+ declare function filterZeroPrizes(prizes: Prize[]): Prize[];
324
+
325
+ export { filterZeroPrizes as A, formatNumber as B, formatPrizeAmount as C, type DistributionType as D, type ExtensionAddresses as E, formatScore as F, type GovernanceValidatorConfig as G, formatTime as H, formatUsdValue as I, getOrdinalSuffix as J, type OpusTrovesValidatorConfig as O, type Prize as P, type QualifyingModeInfo as Q, type StatusTimestamps as S, type TournamentValidatorConfig as T, type ZkPassportValidatorConfig as Z, type StatusResult as a, type ExtensionType as b, type ERC20BalanceValidatorConfig as c, type SnapshotValidatorConfig as d, type QualificationResult as e, type EntryRequirementVariant as f, type QualificationProof as g, type EntryFeeBreakdown as h, type EntryFeeExtensionConfig as i, type EntryFeeShares as j, type ExtensionCategory as k, type Participant as l, type PositionPrizeGroup as m, type PrizeExtensionConfig as n, type QualificationEntry as o, QualifyingMode as p, type SponsorContribution as q, type StatusVariant as r, type Token as s, aggregatePrizesByPosition as t, aggregatePrizesBySponsor as u, calculateDistribution as v, calculateEntryFeeBreakdown as w, calculatePayouts as x, distributePool as y, filterClaimablePrizes as z };