@provable-games/budokan-sdk 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as Tournament, P as PrizeAggregation, a as Prize, b as PaginatedResult, Q as QualificationEntry, R as Registration, c as RewardClaim, d as RewardClaimSummary, e as TournamentListParams, f as PlatformStats, g as PrizeStats, W as WSSubscribeOptions, h as WSEventHandler } from './client-DlXvzneQ.cjs';
2
- export { B as BudokanClient, i as BudokanClientConfig, C as ConnectionMode, j as ConnectionStatus, k as ConnectionStatusState, D as DataSource, G as GameConfig, L as LeaderboardConfig, l as LeaderboardEntry, m as Phase, S as Schedule, n as WSChannel, o as WSEventMessage, p as WSMessage, q as WSSubscribeMessage, r as WSUnsubscribeMessage, s as createBudokanClient } from './client-DlXvzneQ.cjs';
1
+ import { T as Tournament, P as PrizeAggregation, a as Prize, b as PaginatedResult, Q as QualificationEntry, R as Registration, c as RewardClaim, d as RewardClaimSummary, e as TournamentListParams, f as PlatformStats, g as PrizeStats, W as WSSubscribeOptions, h as WSEventHandler } from './player-C2GE9Lop.cjs';
2
+ export { B as BudokanClient, i as BudokanClientConfig, C as ConnectionMode, j as ConnectionStatus, k as ConnectionStatusState, D as DataSource, G as GameConfig, L as LeaderboardConfig, l as LeaderboardEntry, m as Phase, n as PlayerPlacement, o as PlayerRewards, S as Schedule, p as WSChannel, q as WSEventMessage, r as WSMessage, s as WSSubscribeMessage, t as WSUnsubscribeMessage, u as createBudokanClient } from './player-C2GE9Lop.cjs';
3
3
  export { EntryFee } from '@provable-games/metagame-sdk';
4
4
  import 'starknet';
5
5
 
@@ -189,5 +189,540 @@ interface ChainConfig {
189
189
  }
190
190
  declare const CHAINS: Record<string, ChainConfig>;
191
191
  declare function getChainConfig(chain: string): ChainConfig | undefined;
192
+ /**
193
+ * Voyager block-explorer base URL for the chain. Used to build
194
+ * shareable links for tx hashes and contracts in chat / Discord / CLI
195
+ * surfaces. Unknown chains fall back to mainnet — Voyager 404s
196
+ * gracefully and the caller can still click the link.
197
+ */
198
+ declare function explorerBaseUrl(chain: string): string;
199
+ /** Voyager URL for a transaction hash. */
200
+ declare function explorerTxUrl(chain: string, txHash: string): string;
201
+ /** Voyager URL for a contract / account address. */
202
+ declare function explorerAddressUrl(chain: string, address: string): string;
203
+ /**
204
+ * Canonical budokan.gg URL for a tournament. The `network` query param
205
+ * tells the client which chain to load — important when sharing sepolia
206
+ * tournaments since the site defaults to mainnet.
207
+ */
208
+ declare function tournamentPageUrl(chain: string, tournamentId: string | number | bigint): string;
209
+
210
+ /** Subset of chain identifiers the whitelist covers. */
211
+ type WhitelistChain = "mainnet" | "sepolia";
212
+ interface WhitelistedGame {
213
+ /** Canonical 0x-prefixed, 66-char lowercase contract address. */
214
+ contractAddress: string;
215
+ /** Display name. */
216
+ name: string;
217
+ /** Optional remote logo URL. The SDK never bundles binary assets — host externally. */
218
+ imageUrl?: string;
219
+ /** Game's homepage / landing URL. */
220
+ url?: string;
221
+ /** Direct-play URL template. May include `{tokenId}`. */
222
+ playUrl?: string;
223
+ /** Optional spectator URLs. */
224
+ watchLink?: string;
225
+ replayLink?: string;
226
+ /** True if the game requires a Cartridge Controller to play. */
227
+ controllerOnly?: boolean;
228
+ /** Hide from default listings while keeping the metadata around. */
229
+ disabled?: boolean;
230
+ /** Minimum entry fee floor in USD, used as a UX hint at tournament-create time. */
231
+ minEntryFeeUsd?: number;
232
+ /** Recommended ERC-20 token for entry fee on this chain. */
233
+ defaultEntryFeeToken?: string;
234
+ /** Game-creator share of entry fee (basis-points-style — `5` means 5%). */
235
+ defaultGameFeePercentage?: number;
236
+ /** Approximate gas cost per entry, in USD — UX hint only. */
237
+ averageGasCostUsd?: number;
238
+ /** Some game tokens use animated SVG that needs `<object>` rather than `<img>`. */
239
+ objectImage?: boolean;
240
+ /**
241
+ * Score ordering. `true` = lower-is-better (golf-style), `false` = higher-
242
+ * is-better (points-style). Defaults to false when omitted — most games
243
+ * are points-based.
244
+ */
245
+ leaderboardAscending?: boolean;
246
+ /**
247
+ * Whether the game's score is only valid once the game is in a completed
248
+ * (e.g. dead, finished) state. Tournament-creation UIs hide this question
249
+ * when the property of the game is known. Defaults to false.
250
+ */
251
+ leaderboardGameMustBeOver?: boolean;
252
+ }
253
+ /**
254
+ * Whitelisted games for a chain, sorted by name with disabled entries last.
255
+ *
256
+ * Returns a frozen copy — mutations don't bleed back into the module state.
257
+ */
258
+ declare function getWhitelistedGames(chain: WhitelistChain): WhitelistedGame[];
259
+ /**
260
+ * Look up a single whitelisted game by contract address. Address is normalized
261
+ * before comparison so callers can pass any padding.
262
+ */
263
+ declare function findWhitelistedGame(chain: WhitelistChain, contractAddress: string): WhitelistedGame | undefined;
264
+ /** True if the given game is on the whitelist. */
265
+ declare function isGameWhitelisted(chain: WhitelistChain, contractAddress: string): boolean;
266
+ /**
267
+ * Defaults block — what UI surfaces should pre-fill when the user picks this
268
+ * game. Falls back to per-chain sensible defaults (STRK as fee token, 1% fee,
269
+ * $0.25 minimum) when the game isn't whitelisted, so callers don't have to
270
+ * special-case missing entries.
271
+ */
272
+ interface GameDefaults {
273
+ minEntryFeeUsd: number;
274
+ defaultEntryFeeToken: string;
275
+ defaultGameFeePercentage: number;
276
+ averageGasCostUsd: number | undefined;
277
+ /** Inherited leaderboard ordering (true = lower wins, false = higher wins). */
278
+ leaderboardAscending: boolean;
279
+ /** Inherited "must finish game before submitting" flag. */
280
+ leaderboardGameMustBeOver: boolean;
281
+ }
282
+ declare function getGameDefaults(chain: WhitelistChain, contractAddress: string): GameDefaults;
283
+
284
+ /**
285
+ * Calldata builders for Budokan's on-chain entrypoints.
286
+ *
287
+ * Each builder is a pure function that returns a starknet.js `Call` —
288
+ * `{ contractAddress, entrypoint, calldata }` — without signing or
289
+ * executing anything. Callers pass the returned Call to
290
+ * `account.execute([...])` themselves so this module is decoupled from
291
+ * how an integrator obtains an account (controller, sessions, agent
292
+ * wallets, signing servers).
293
+ *
294
+ * Cairo encoding gotchas this module hides from callers:
295
+ * - Option<T> and custom enums must be wrapped in `CairoOption` /
296
+ * `CairoCustomEnum`. Plain `{ type, variant }` objects look right but
297
+ * CallData.compile treats them as generic structs and serializes the
298
+ * type-name string as a ByteArray — i.e. produces garbage calldata.
299
+ * - `Metadata.description` is a ByteArray (3+ felts). A plain JS
300
+ * string becomes a single felt and the deserializer reverts with
301
+ * "Failed to deserialize param".
302
+ * - Cairo enum variant tags are 0-indexed in declaration order; the
303
+ * manually-built calldata in enter/claim/submit follows this order
304
+ * exactly. References:
305
+ * contracts/packages/interfaces/src/budokan.cairo (RewardType,
306
+ * EntryFeeRewardType, EntryRequirementType, Distribution)
307
+ * game-components/.../prize.cairo (PrizeType)
308
+ *
309
+ * Used today by the Telegram bot in
310
+ * `examples/telegram-controller-bot/`. Any other integration that needs
311
+ * to drive the same contract (a Discord bot, a CLI, agent code) should
312
+ * import from here so we don't fork the encoding logic again.
313
+ */
314
+ interface Call {
315
+ contractAddress: string;
316
+ entrypoint: string;
317
+ calldata: string[];
318
+ }
319
+ /**
320
+ * Shape of the entry-fee distribution. Mirrors the Cairo `Distribution`
321
+ * enum (Linear / Exponential / Uniform / Custom). The integer `weight`
322
+ * is in client units — the encoder scales it ×10 to match the on-chain
323
+ * convention the budokan client uses, so distributions created via this
324
+ * SDK and via budokan.gg render identically.
325
+ */
326
+ type DistributionSpec = {
327
+ kind: "linear";
328
+ weight: number;
329
+ } | {
330
+ kind: "exponential";
331
+ weight: number;
332
+ } | {
333
+ kind: "uniform";
334
+ };
335
+ interface EntryFeeArgs {
336
+ tokenAddress: string;
337
+ /** Raw u128 amount in smallest token units (decimal string). */
338
+ amount: string;
339
+ /** All shares are basis points (0–10000). Sum + leaderboard pool = 10000. */
340
+ tournamentCreatorShare: number;
341
+ gameCreatorShare: number;
342
+ refundShare: number;
343
+ distribution: DistributionSpec;
344
+ /** Number of top placements that share the leaderboard pool. */
345
+ distributionCount: number;
346
+ }
347
+ /**
348
+ * Entry-requirement gating. Two variants on the chain's
349
+ * EntryRequirementType enum:
350
+ * - token: ContractAddress — must own a token from this contract
351
+ * - extension: ExtensionConfig — validator contract + config Span
352
+ *
353
+ * For "extension" callers build the `config` Span<felt252> in the exact
354
+ * felt order the target validator's `add_config` expects (see
355
+ * `src/extensions` for preset builders that produce this for the
356
+ * shared deployed validators).
357
+ */
358
+ type EntryRequirementSpec = {
359
+ kind: "token";
360
+ tokenAddress: string;
361
+ } | {
362
+ kind: "extension";
363
+ address: string;
364
+ config: string[];
365
+ };
366
+ interface EntryRequirementArgs {
367
+ /** Max entries per qualifying token / extension match. */
368
+ entryLimit: number;
369
+ type: EntryRequirementSpec;
370
+ }
371
+ interface EnterTournamentArgs {
372
+ tournamentId: string;
373
+ /**
374
+ * Mint recipient. Encoded as `Option<ContractAddress>` — omit for
375
+ * `None` (the contract defaults the mint to the caller).
376
+ */
377
+ playerAddress?: string;
378
+ /** Optional felt252 short string (≤31 ASCII bytes). Omit → Option::None. */
379
+ playerName?: string;
380
+ /**
381
+ * Third-party qualifier to claim, as `Option<ContractAddress>`. Omit for
382
+ * `None` (caller is the qualifier — the common path). Only needed for
383
+ * sponsor flows against gated tournaments.
384
+ */
385
+ qualifier?: string;
386
+ /**
387
+ * `entry_fee_pay_params` (`Option<Span<felt252>>`). Required only for
388
+ * tournaments with an `EntryFeeKind::Extension` fee — the felts the fee
389
+ * extension expects. Omit for the built-in fee flow (Option::None).
390
+ */
391
+ entryFeePayParams?: string[];
392
+ salt?: number;
393
+ metadataValue?: number;
394
+ }
395
+ interface CreateTournamentArgs {
396
+ creatorRewardsAddress: string;
397
+ /** ≤31 ASCII bytes (felt252 short string). */
398
+ name: string;
399
+ description: string;
400
+ gameAddress: string;
401
+ settingsId: number;
402
+ schedule: {
403
+ registrationStartDelay: number;
404
+ registrationEndDelay: number;
405
+ gameStartDelay: number;
406
+ gameEndDelay: number;
407
+ submissionDuration: number;
408
+ };
409
+ leaderboard: {
410
+ ascending: boolean;
411
+ gameMustBeOver: boolean;
412
+ };
413
+ /** Encoded as Option::Some(EntryFeeKind::BuiltIn(EntryFee)) when set. */
414
+ entryFee?: EntryFeeArgs;
415
+ /** Encoded as Option::Some(EntryRequirement) on chain when set. */
416
+ entryRequirement?: EntryRequirementArgs;
417
+ salt?: number;
418
+ metadataValue?: number;
419
+ }
420
+ /**
421
+ * Token prize payload. Mirrors the Cairo `TokenTypeData` enum.
422
+ *
423
+ * - `erc20` — fungible. `amount` is required; `distribution` optional
424
+ * (undefined → single winner-takes-all payout). When `distribution`
425
+ * is set, `distributionCount` is required (number of paid positions).
426
+ * - `erc721` — single NFT. `tokenId` is the u128 id of the token the
427
+ * sponsor is escrowing.
428
+ */
429
+ type TokenTypeSpec = {
430
+ kind: "erc20";
431
+ /** Raw u128 amount (decimal string). */
432
+ amount: string;
433
+ distribution?: DistributionSpec;
434
+ distributionCount?: number;
435
+ } | {
436
+ kind: "erc721";
437
+ tokenId: string;
438
+ };
439
+ /**
440
+ * Tagged union mirroring the on-chain `Prize` enum.
441
+ *
442
+ * - `config` — built-in path: sponsor escrows an ERC20/ERC721 prize via
443
+ * the budokan PrizeComponent; `position` selects a leaderboard slot
444
+ * for non-distributed prizes (ignored for distributed ERC20).
445
+ * - `extension` — external `IPrizeExtension`: budokan forwards the
446
+ * `config` blob to `IPrizeExtension.add_prize`. `position` is ignored
447
+ * (the extension owns position semantics).
448
+ */
449
+ type PrizeSpec = {
450
+ kind: "token";
451
+ tokenAddress: string;
452
+ tokenType: TokenTypeSpec;
453
+ /** Leaderboard slot for single (non-distributed) prizes. Omit for distributed. */
454
+ position?: number;
455
+ } | {
456
+ kind: "extension";
457
+ /** Address of the contract implementing `IPrizeExtension`. */
458
+ address: string;
459
+ /** Opaque payload forwarded to `IPrizeExtension.add_prize`. */
460
+ config: string[];
461
+ };
462
+ interface AddPrizeArgs {
463
+ tournamentId: string;
464
+ prize: PrizeSpec;
465
+ }
466
+ /**
467
+ * Tagged union mirroring the Cairo `RewardType` enum hierarchy:
468
+ *
469
+ * variant 0: Prize(PrizeClaim)
470
+ * PrizeClaim variant 0: Token(PrizeType)
471
+ * PrizeType variant 0: Single(u64)
472
+ * PrizeType variant 1: Distributed((u64, u8))
473
+ * PrizeClaim variant 1: Extension({prize_id, position, payout_params})
474
+ * variant 1: EntryFee(EntryFeeClaim)
475
+ * EntryFeeClaim variant 0: Token(EntryFeeRewardType)
476
+ * EntryFeeRewardType variant 0: Position(u32)
477
+ * EntryFeeRewardType variant 1: TournamentCreator
478
+ * EntryFeeRewardType variant 2: GameCreator
479
+ * EntryFeeRewardType variant 3: Refund(felt252)
480
+ * EntryFeeClaim variant 1: Extension(ExtensionEntryFeeClaim)
481
+ *
482
+ * Extension claims are pure pass-through on the host: budokan forwards
483
+ * `(token_id, payout_params)` to the extension and lets it resolve
484
+ * recipient + eligibility from its own state. Callers don't supply
485
+ * recipient or position — the extension derives them.
486
+ *
487
+ * Conventions:
488
+ * - `tokenId` is the game token claiming. Positional extensions
489
+ * (NFTPrize, NFTEntryFee) use it to look up the leaderboard
490
+ * position; ownership-based extensions use it to derive the
491
+ * recipient via `owner_of`.
492
+ * - `tokenId: undefined` signals a non-claim flow (sponsor refund,
493
+ * dao distribution, raffle draw). The extension extracts whatever
494
+ * it needs from `payoutParams` / `claimParams` — e.g. NFTPrize
495
+ * reads `payoutParams[0]` as the slot index to refund.
496
+ */
497
+ type RewardType = {
498
+ kind: "prize_single";
499
+ prizeId: string;
500
+ } | {
501
+ kind: "prize_distributed";
502
+ prizeId: string;
503
+ payoutPosition: number;
504
+ } | {
505
+ kind: "prize_extension";
506
+ prizeId: string;
507
+ /**
508
+ * Game token claiming the prize, or undefined for non-claim flows
509
+ * (sponsor refunds, raffle draws, etc.).
510
+ */
511
+ tokenId?: string;
512
+ payoutParams: string[];
513
+ } | {
514
+ kind: "entry_fee_position";
515
+ position: number;
516
+ } | {
517
+ kind: "entry_fee_tournament_creator";
518
+ } | {
519
+ kind: "entry_fee_game_creator";
520
+ } | {
521
+ kind: "entry_fee_refund";
522
+ tokenId: string;
523
+ } | {
524
+ kind: "entry_fee_extension";
525
+ /**
526
+ * Game token claiming the fee-pool share, or undefined for
527
+ * non-claim flows (sponsor refunds, creator shares, etc.).
528
+ */
529
+ tokenId?: string;
530
+ claimParams: string[];
531
+ };
532
+ /** Standard ERC20 `approve(spender, amount)` call. */
533
+ declare function buildErc20ApproveCall(tokenAddress: string, spender: string, amount: string): Call;
534
+ /**
535
+ * `enter_tournament(tournament_id: u64, player_name: Option<felt252>,
536
+ * player_address: Option<ContractAddress>,
537
+ * qualifier: Option<ContractAddress>,
538
+ * qualification: Option<QualificationProof>,
539
+ * entry_fee_pay_params: Option<Span<felt252>>,
540
+ * salt: u16, metadata_value: u16)`
541
+ *
542
+ * Targets the current budokan contract (#264/#269). `qualification` and
543
+ * `entry_fee_pay_params` are always `None` here — gated/extension-fee
544
+ * tournaments need a real proof / pay-params payload, which depend on the
545
+ * validator and the caller's runtime state.
546
+ *
547
+ * Returns `(felt252, u32)` on-chain — game_token_id and entry_number — but
548
+ * `execute()` surfaces only the tx hash. Callers can fetch the receipt
549
+ * and parse events if they need the values.
550
+ *
551
+ * Tournaments with a non-trivial entry_requirement (NFT-gated or
552
+ * extension-validator) need a real `QualificationProof` and shouldn't go
553
+ * through this entrypoint — route those via the budokan client UI or
554
+ * implement a qualification-proof builder.
555
+ */
556
+ declare function buildEnterTournamentCall(budokanAddress: string, args: EnterTournamentArgs): Call;
557
+ /** `submit_score(tournament_id: u64, token_id: felt252, position: u32)` */
558
+ declare function buildSubmitScoreCall(budokanAddress: string, args: {
559
+ tournamentId: string;
560
+ tokenId: string;
561
+ position: number;
562
+ }): Call;
563
+ /** `claim_reward(tournament_id: u64, reward_type: RewardType)` */
564
+ declare function buildClaimRewardCall(budokanAddress: string, args: {
565
+ tournamentId: string;
566
+ reward: RewardType;
567
+ }): Call;
568
+ /**
569
+ * `create_tournament(creator_rewards_address, metadata, schedule,
570
+ * game_config, entry_fee, entry_requirement,
571
+ * leaderboard_config, salt, metadata_value)`
572
+ *
573
+ * Schedule fields are durations (`registration_end_delay`,
574
+ * `game_end_delay` measured from their respective starts) — *not*
575
+ * absolute offsets from creation. Callers are responsible for the
576
+ * arithmetic; the contract validates min/max bounds itself.
577
+ *
578
+ * Pass `entryFee` / `entryRequirement` as `undefined` for free / open
579
+ * tournaments. Both fields are wrapped in `CairoOption` so
580
+ * `CallData.compile` emits the correct variant tag.
581
+ */
582
+ declare function buildCreateTournamentCall(budokanAddress: string, args: CreateTournamentArgs): Call;
583
+ /**
584
+ * `add_prize(tournament_id: u64, prize: Prize, position: Option<u32>) -> u64`
585
+ *
586
+ * The `Prize` sum type discriminates between the built-in
587
+ * (ERC20/ERC721) flow and an external `IPrizeExtension` integration —
588
+ * see `PrizeSpec` for the variants.
589
+ *
590
+ * The on-chain entrypoint returns the minted `prize_id` (u64); callers
591
+ * wanting the full payload should subscribe to the `PrizeAdded` event.
592
+ */
593
+ declare function buildAddPrizeCall(budokanAddress: string, args: AddPrizeArgs): Call;
594
+ /**
595
+ * Minimal receipt shape — `events: Array<{ from_address, keys, ... }>`
596
+ * is all `parseTournamentIdFromReceipt` needs and matches what every
597
+ * Starknet RPC / starknet.js `waitForTransaction` returns.
598
+ */
599
+ interface ReceiptWithEvents {
600
+ events?: Array<{
601
+ from_address?: string;
602
+ keys?: string[];
603
+ }>;
604
+ }
605
+ /**
606
+ * Extract the new tournament's id from a `create_tournament` tx receipt
607
+ * by scanning for the `TournamentCreated` event emitted by the budokan
608
+ * contract. The event has the tournament id in its first indexed key
609
+ * (`keys[1]` — `keys[0]` is the selector).
610
+ *
611
+ * Returns the id as a `bigint` (the on-chain type is `u64`, which exceeds
612
+ * JS `Number.MAX_SAFE_INTEGER`, so a lossless type is required — callers
613
+ * deep-linking to a tournament page should `.toString()` it). Returns
614
+ * `undefined` if no matching event is found (e.g. the receipt came from a
615
+ * different call, or the budokan address didn't match).
616
+ *
617
+ * Caller is responsible for fetching the receipt — typically via
618
+ * `account.waitForTransaction(hash)` or `provider.waitForTransaction(hash)`.
619
+ */
620
+ declare function parseTournamentIdFromReceipt(receipt: ReceiptWithEvents, budokanAddress: string): bigint | undefined;
621
+
622
+ /**
623
+ * Entry-requirement validator extensions.
624
+ *
625
+ * Thin wrappers on top of @provable-games/metagame-sdk for the four
626
+ * validator presets we recommend for chat / bot integrations:
627
+ *
628
+ * - merkle — Allowlist of addresses via a pre-built merkle tree
629
+ * - erc20Balance — Player must hold ≥ X of some ERC-20
630
+ * - opusTroves — Player must have borrowed ≥ $X CASH on Opus
631
+ * - tournament — Player must have entered / placed in a prior tournament
632
+ *
633
+ * Each `buildXxxConfig` function emits the `Span<felt252>` config array
634
+ * the on-chain validator's `add_config` expects. Pair the array with the
635
+ * validator address (via `extensionAddressFor`) when building an
636
+ * `EntryRequirementArgs` of kind `"extension"`.
637
+ *
638
+ * Authoritative on-chain layouts:
639
+ * metagame-extensions/packages/presets/src/entry_requirement/*.cairo
640
+ *
641
+ * u256 values (ERC-20 balance thresholds) are split into low/high felt
642
+ * pairs to match those layouts. CASH amounts for Opus are passed as
643
+ * single felts because they're u128-range in practice.
644
+ */
645
+
646
+ type ExtensionPresetKind = "merkle" | "erc20Balance" | "opusTroves" | "tournament";
647
+ /**
648
+ * Lookup the deployed validator address for a given preset on a given
649
+ * chain. Throws if the metagame-sdk address table doesn't have one — the
650
+ * preset isn't usable on that chain.
651
+ */
652
+ declare function extensionAddressFor(chain: WhitelistChain, kind: ExtensionPresetKind): string;
653
+ /** Split a u256 (as bigint) into [low_128, high_128] felt strings. */
654
+ declare function u256ToLowHigh(value: bigint): [string, string];
655
+ interface Erc20BalanceConfig {
656
+ tokenAddress: string;
657
+ /** Raw u256, smallest units. */
658
+ minThreshold: bigint;
659
+ /** Raw u256, smallest units; 0 = no max. */
660
+ maxThreshold: bigint;
661
+ /** Raw u256, smallest units; 0 = single entry, regardless of balance. */
662
+ valuePerEntry: bigint;
663
+ /** 0 = unlimited (only meaningful when valuePerEntry > 0). */
664
+ maxEntries: number;
665
+ bannable: boolean;
666
+ }
667
+ /**
668
+ * Build the felt-string config array.
669
+ *
670
+ * Layout (from erc20_balance_validator.cairo):
671
+ * [token, min_low, min_high, max_low, max_high, vpe_low, vpe_high,
672
+ * max_entries, bannable]
673
+ */
674
+ declare function buildErc20BalanceConfig(cfg: Erc20BalanceConfig): string[];
675
+ interface OpusTrovesConfig {
676
+ /** Specific collateral filters; empty = wildcard (any trove qualifies). */
677
+ assetAddresses: string[];
678
+ /** Min CASH borrowed (raw, 18 decimals). CASH is 1:1 USD. */
679
+ threshold: bigint;
680
+ /** CASH per additional entry; 0 = single entry per qualifying trove. */
681
+ valuePerEntry: bigint;
682
+ /** 0 = unlimited (only meaningful with proportional valuePerEntry > 0). */
683
+ maxEntries: number;
684
+ bannable: boolean;
685
+ }
686
+ /**
687
+ * Layout (from opus_troves_validator):
688
+ * [asset_count, ...asset_addresses, threshold, value_per_entry,
689
+ * max_entries, bannable]
690
+ *
691
+ * threshold / value_per_entry are CASH amounts (18 decimals, ≤ u128 range
692
+ * for any reasonable USD value) — passed as single felts, not low/high
693
+ * pairs. This matches the validator's parse (parseOpusTrovesValidatorConfig
694
+ * in metagame-sdk reads them as bigints directly).
695
+ */
696
+ declare function buildOpusTrovesConfig(cfg: OpusTrovesConfig): string[];
697
+ interface MerkleConfig {
698
+ /** On-chain tree ID from the merkle-validator's create_tree. */
699
+ treeId: number;
700
+ }
701
+ /** Layout: [tree_id]. */
702
+ declare function buildMerkleConfig(cfg: MerkleConfig): string[];
703
+ /** 0 = participated (any entry counts), 1 = won (placed in top N). */
704
+ type TournamentRequirementType = "participated" | "won";
705
+ /**
706
+ * How to combine multiple qualifying tournaments. Matches QualifyingMode
707
+ * in metagame-sdk: 0=AtLeastOne, 1=CumulativePerTournament, 2=All,
708
+ * 3=CumulativePerEntry, 4=AllParticipateAnyWin, 5=AllWithCumulative.
709
+ */
710
+ interface TournamentValidatorConfig {
711
+ requirement: TournamentRequirementType;
712
+ /** Tournament IDs whose history qualifies. */
713
+ tournamentIds: string[];
714
+ /** Top N positions that count (only used when requirement = "won"). */
715
+ topPositions: number;
716
+ /** Default 0 (= AtLeastOne). */
717
+ qualifyingMode?: number;
718
+ }
719
+ /**
720
+ * Layout (from tournament_validator):
721
+ * [qualifier_type, qualifying_mode, top_positions, ...tournament_ids]
722
+ * - qualifier_type: 0 = participated, 1 = won
723
+ * - qualifying_mode: 0–5 enum
724
+ * - top_positions: 0 for "all positions" (used with participated)
725
+ */
726
+ declare function buildTournamentValidatorConfig(cfg: TournamentValidatorConfig): string[];
192
727
 
193
- export { BudokanApiError, BudokanConnectionError, BudokanError, BudokanTimeoutError, CHAINS, type ChainConfig, DataSourceError, PaginatedResult, PlatformStats, Prize, PrizeAggregation, PrizeStats, QualificationEntry, Registration, RewardClaim, RewardClaimSummary, RpcError, Tournament, TournamentListParams, TournamentNotFoundError, WSEventHandler, WSManager, WSSubscribeOptions, camelToSnake, getActivityStats, getChainConfig, getGameStats, getGameTournaments, getPrizeStats, getTournament, getTournamentPrizeAggregation, getTournamentPrizes, getTournamentQualifications, getTournamentRegistrations, getTournamentRewardClaims, getTournamentRewardClaimsSummary, getTournaments, normalizeAddress, snakeToCamel, withRetry };
728
+ export { type AddPrizeArgs, BudokanApiError, BudokanConnectionError, BudokanError, BudokanTimeoutError, CHAINS, type Call, type ChainConfig, type CreateTournamentArgs, DataSourceError, type DistributionSpec, type EnterTournamentArgs, type EntryFeeArgs, type EntryRequirementArgs, type EntryRequirementSpec, type Erc20BalanceConfig, type ExtensionPresetKind, type GameDefaults, type MerkleConfig, type OpusTrovesConfig, PaginatedResult, PlatformStats, Prize, PrizeAggregation, type PrizeSpec, PrizeStats, QualificationEntry, type ReceiptWithEvents, Registration, RewardClaim, RewardClaimSummary, type RewardType, RpcError, type TokenTypeSpec, Tournament, TournamentListParams, TournamentNotFoundError, type TournamentRequirementType, type TournamentValidatorConfig, WSEventHandler, WSManager, WSSubscribeOptions, type WhitelistChain, type WhitelistedGame, buildAddPrizeCall, buildClaimRewardCall, buildCreateTournamentCall, buildEnterTournamentCall, buildErc20ApproveCall, buildErc20BalanceConfig, buildMerkleConfig, buildOpusTrovesConfig, buildSubmitScoreCall, buildTournamentValidatorConfig, camelToSnake, explorerAddressUrl, explorerBaseUrl, explorerTxUrl, extensionAddressFor, findWhitelistedGame, getActivityStats, getChainConfig, getGameDefaults, getGameStats, getGameTournaments, getPrizeStats, getTournament, getTournamentPrizeAggregation, getTournamentPrizes, getTournamentQualifications, getTournamentRegistrations, getTournamentRewardClaims, getTournamentRewardClaimsSummary, getTournaments, getWhitelistedGames, isGameWhitelisted, normalizeAddress, parseTournamentIdFromReceipt, snakeToCamel, tournamentPageUrl, u256ToLowHigh, withRetry };