@bordrless/shared 0.6.0 → 0.7.0

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/api.d.ts CHANGED
@@ -570,14 +570,136 @@ export interface LaunchPrepareRequest {
570
570
  */
571
571
  companion?: CompanionRequest;
572
572
  }
573
- /** A launch's companion as the launch request names it: a split of the creator fee, or one of the preset splits by name. */
573
+ /**
574
+ * A launch's companion as the launch request names it: a split of the creator fee, or one of the
575
+ * preset splits by name; with `game`, a lottery coin (docs/games.md): the split's holders' share is
576
+ * then 0 and the pot's part (`game.potBps`) makes the four add up to 10,000.
577
+ */
574
578
  export type CompanionRequest = {
575
579
  split: CompanionSplitBps;
576
580
  vestDays?: number;
581
+ game?: LotteryRequest;
577
582
  } | {
578
583
  template: CompanionTemplate;
579
584
  vestDays?: number;
580
585
  };
586
+ /**
587
+ * A lottery coin's game as the launch request names it (docs/games.md "The companion's game"):
588
+ * every setting `create_game` fixes before the launch. Bounds: `LOTTERY_LIMITS` (`lotteryProblem`).
589
+ */
590
+ export interface LotteryRequest {
591
+ kind: 'lottery';
592
+ /** A round's length, seconds: an hour to 30 days. Every holder's tokens held since a round began are their tickets in it. */
593
+ roundSecs: number;
594
+ /** The pot's part of every creator fee claim, basis points: with the split's buyback and launcher parts it adds up to 10,000. */
595
+ potBps: number;
596
+ /** No draw while the pot holds less, lamports: 0.1 to 1,000 SOL. */
597
+ minPotLamports: Amount;
598
+ /** The part of the pot one draw pays, basis points: 10% to 100%. */
599
+ prizeBps: number;
600
+ /** How long each claim attempt stays open, seconds: 5 minutes to a day. */
601
+ claimWindowSecs: number;
602
+ /** Attempts a draw makes before it rolls over, 1 to 16; all of them within half a round. */
603
+ maxAttempts: number;
604
+ }
605
+ /** A lottery coin's settings as its token page shows them (`CompanionSummary.game`): fixed at the launch, and the hook's terms. */
606
+ export interface GameSummary {
607
+ kind: 'lottery';
608
+ /** The game's account, `PDA(["game", mint])` under the companion program. */
609
+ address: Address;
610
+ /** The coin's token hook, which keeps the tickets (the lottery hook). */
611
+ hook: Address;
612
+ roundSecs: number;
613
+ potBps: number;
614
+ minPot: Amount;
615
+ prizeBps: number;
616
+ claimWindowSecs: number;
617
+ maxAttempts: number;
618
+ /** The most the pot may hold while the hook is not audited (lamports); null for an audited hook. */
619
+ potCap: Amount | null;
620
+ audited: boolean;
621
+ /** Bordrless stopped this hook's games: the pot and its share go to the buyback and are burned. */
622
+ blocked: boolean;
623
+ /** Prizes paid so far, lamports, and how many. */
624
+ prizesTotal: Amount;
625
+ prizesPaid: number;
626
+ }
627
+ /** Why a round paid no prize (the companion's `RolloverReason`). */
628
+ export type GameRolloverReason = 'noTickets' | 'roundForgotten' | 'noClaim' | 'oracleSilent' | 'blocked' | 'late' | 'oracleUnreadable' | 'oracleUnpaid';
629
+ /** One round's draw as the indexer saw it (`GameStatus.draws`), newest first. */
630
+ export interface GameDraw {
631
+ round: number;
632
+ /** When the round ended (its tickets final), unix seconds. */
633
+ roundEndsAt: number;
634
+ /** `requested`: ORAO asked; `revealed`: its answer stored, claims open; `paid`: the prize paid; `rolledOver`: no prize. */
635
+ status: 'requested' | 'revealed' | 'paid' | 'rolledOver';
636
+ /** The round's ticket total, base units. */
637
+ total: Amount;
638
+ /** ORAO's request account for the round's seed; null when no seed was committed. */
639
+ request: Address | null;
640
+ winner: Address | null;
641
+ /** Lamports paid; null unless paid. */
642
+ prize: Amount | null;
643
+ /** The ticket attempt that paid, 0-based; null unless paid. */
644
+ attempt: number | null;
645
+ reason: GameRolloverReason | null;
646
+ /** The transaction of the draw's last step, and when it landed. */
647
+ signature: string;
648
+ at: number | null;
649
+ }
650
+ /** The caller's place in the current round (`GameStatus.you`, with `?wallet=`). */
651
+ export interface GameYou {
652
+ wallet: Address;
653
+ /** Tokens the wallet holds, base units. */
654
+ balance: Amount;
655
+ /** Its tickets in the current round, base units (its range's weight); 0 until it is written this round. */
656
+ tickets: Amount;
657
+ /** The wallet's holding has been written this round (it traded, or was entered): its tickets are registered. */
658
+ entered: boolean;
659
+ /** Its share of the round's tickets so far, 0 to 1; null without tickets. */
660
+ odds: number | null;
661
+ /** Its tickets in the round before (the one a draw may be for now). */
662
+ previousTickets: Amount;
663
+ }
664
+ /** A lottery coin's live state (`CompanionStatus.game`, docs/games.md): the pot, the round, the draw, the caller's tickets and the draw history. */
665
+ export interface GameStatus extends GameSummary {
666
+ /** Bridged SOL the pot holds, lamports. */
667
+ pot: Amount;
668
+ /** Chain time the status was read at, unix seconds. */
669
+ now: number;
670
+ /** The current round (`floor(now / roundSecs)`) and when it ends. */
671
+ round: number;
672
+ roundEndsAt: number;
673
+ /** Tickets registered in the current round so far, base units (the hook's header). */
674
+ tickets: Amount;
675
+ /** The round before, and its tickets: what the next draw is for once the round ends. */
676
+ previousRound: number;
677
+ previousTickets: Amount;
678
+ /** The least the pot must hold for a round to be drawn (the minimum, or the cap when lower; 0.1 SOL once dormant). */
679
+ drawThreshold: Amount;
680
+ /** The draw in progress, when one is. */
681
+ draw: {
682
+ round: number;
683
+ status: 'requested' | 'revealed';
684
+ request: Address;
685
+ prize: Amount;
686
+ revealedAt: number | null;
687
+ claimsEndAt: number;
688
+ } | null;
689
+ lastWinner: Address | null;
690
+ you: GameYou | null;
691
+ draws: GameDraw[];
692
+ }
693
+ /** `POST /v1/game/enter/prepare`: a holder's own `enter` (docs/games.md): their whole balance registered as tickets for the current round, when the holding was not written this round yet. */
694
+ export interface GameEnterRequest {
695
+ wallet: Address;
696
+ mint: Address;
697
+ }
698
+ export interface GameEnterResponse {
699
+ transactions: PreparedTx[];
700
+ /** The round the tickets count in. */
701
+ round: number;
702
+ }
581
703
  /** The companion templates (`COMPANION_SPLITS`; `COMPANION_TEMPLATES` in the SDK). */
582
704
  export type CompanionTemplate = 'buysItself' | 'rugProofDev' | 'buybackAndReward';
583
705
  /** What a companion does with every creator fee it claims, in basis points summing to 10,000. */
@@ -623,6 +745,8 @@ export interface CompanionSummary {
623
745
  } | null;
624
746
  /** When the next buyback may run while SOL waits for one (it also waits while the price runs above its reference); null otherwise. */
625
747
  nextBuybackAt: number | null;
748
+ /** The lottery this companion runs (docs/games.md): its settings and the hook's terms; null for a companion without a game. */
749
+ game: GameSummary | null;
626
750
  }
627
751
  /**
628
752
  * `GET /v1/companion/:mint`: a mint's companion as a launch that may not have finished needs it.
@@ -636,6 +760,8 @@ export interface CompanionStatus {
636
760
  beneficiary: Address | null;
637
761
  /** Lamports a refund returns now; null unless `set-up`. */
638
762
  refundable: Amount | null;
763
+ /** The lottery this companion runs, live (docs/games.md), the caller's tickets with `?wallet=`; null for a companion without a game (absent from older servers). */
764
+ game?: GameStatus | null;
639
765
  }
640
766
  /** `POST /v1/companion/refund/prepare`: a companion's funding back to the wallet that set it up, for a launch that never happened. The mint's key signs it after the wallet. */
641
767
  export interface CompanionRefundRequest {
package/dist/policy.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * `programs/tests/vectors/launch-fees.json`, which the Rust tests render from the reference the
7
7
  * programs are held to, and requires exact equality.
8
8
  */
9
- import type { CompanionSplitBps, CompanionTemplate, LaunchRules, LaunchRulesInput, Side } from './api.ts';
9
+ import type { CompanionSplitBps, CompanionTemplate, GameRolloverReason, LaunchRules, LaunchRulesInput, LotteryRequest, Side } from './api.ts';
10
10
  export declare const BPS = 10000n;
11
11
  export declare const WAD: bigint;
12
12
  /** The largest u64, where the programs' checked arithmetic stops. */
@@ -284,6 +284,71 @@ export declare const COMPANION_DEFAULT_VEST_DAYS = 30;
284
284
  export declare const COMPANION_MAX_VEST_DAYS = 365;
285
285
  /** The whole creator fee to the launcher: an ordinary launch, with no companion. */
286
286
  export declare const LAUNCHER_SPLIT: Readonly<CompanionSplitBps>;
287
+ /**
288
+ * The companion program's game limits (`constants.rs`; `GAME_LIMITS` in the SDK, the same numbers):
289
+ * a round's length, the minimum pot, the prize's least share, a claim window's bounds, the most
290
+ * attempts, and the half of a round the attempts may take. The launch form holds its choices to
291
+ * them and the backend refuses anything outside them (`lotteryProblem`).
292
+ */
293
+ export declare const LOTTERY_LIMITS: {
294
+ readonly minRoundSecs: 3600;
295
+ readonly maxRoundSecs: number;
296
+ readonly minMinPotLamports: 100000000n;
297
+ readonly maxMinPotLamports: 1000000000000n;
298
+ readonly minPrizeBps: 1000;
299
+ readonly minClaimWindowSecs: 300;
300
+ readonly maxClaimWindowSecs: 86400;
301
+ readonly maxAttempts: 16;
302
+ readonly claimsPerRound: 2;
303
+ /** The most a pot holds while its hook is not audited: 10 SOL, the rest of the pot's share bought back. */
304
+ readonly potCapLamports: 10000000000n;
305
+ /** Lamports the setup pays for the hook's state and registry and the game's account (mainnet rent, 2026-10-08). */
306
+ readonly rentLamports: bigint;
307
+ };
308
+ /** The lottery the launch form starts with (docs/games.md, spec example 1): 6-hour rounds, 70% of the fee to the pot, 30% bought back, draws from 0.5 SOL paying the whole pot, 8 claim attempts of 10 minutes. */
309
+ export declare const LOTTERY_DEFAULTS: Readonly<LotteryRequest>;
310
+ /** The round lengths the form offers (seconds), each with its label. */
311
+ export declare const LOTTERY_ROUND_CHOICES: readonly {
312
+ secs: number;
313
+ label: string;
314
+ }[];
315
+ /** The least a pot holds before a round is drawn, as the form offers it (lamports). */
316
+ export declare const LOTTERY_MIN_POT_CHOICES: readonly {
317
+ lamports: string;
318
+ label: string;
319
+ }[];
320
+ /** What one draw pays of the pot, as the form offers it. */
321
+ export declare const LOTTERY_PRIZE_CHOICES_BPS: readonly [10000, 5000, 2500];
322
+ /** The pot's share moves in steps of 10%, like the Split control's. */
323
+ export declare const LOTTERY_POT_STEP_BPS = 1000;
324
+ /**
325
+ * The claim windows and attempts the form fixes for a round length: 8 attempts of 10 minutes for a
326
+ * round of 6 hours or more, 6 of 5 minutes for an hour (the attempts must fit in half a round).
327
+ */
328
+ export declare function lotteryClaimsFor(roundSecs: number): {
329
+ claimWindowSecs: number;
330
+ maxAttempts: number;
331
+ };
332
+ /** The lottery a launch request's `companion.game` names, each field a whole number; null when it is malformed (bounds are `lotteryProblem`'s). */
333
+ export declare function lotteryRequestOf(raw: unknown): LotteryRequest | null;
334
+ /**
335
+ * Why `create_game` would refuse this lottery with this split on these rules, in the words the
336
+ * launch form and the backend use (`companion_rules`); null when it would not. The program's own
337
+ * checks (`gameArgsProblem` in the SDK, the same sentences), and what a lottery coin's launch
338
+ * needs besides: a creator fee, no token rules (it launches from Bordrless's lottery config, which
339
+ * has none, and runs its own hook in the kit's place), and no holders' share.
340
+ */
341
+ export declare function lotteryProblem(game: LotteryRequest, split: CompanionSplitBps, rules: LaunchRulesInput, creatorFeeBps: number): string | null;
342
+ /** The copy rules of a lottery coin (docs/games.md): said on the launch form, the review step and the token page, never "provably fair", "guaranteed" or "audited". */
343
+ export declare const LOTTERY_COPY: {
344
+ readonly held: "The pot is held by the companion program and paid out by code. Randomness by ORAO VRF.";
345
+ readonly odds: "Your odds = your tokens in the round. Sell before the payout and you forfeit.";
346
+ readonly stop: "Bordrless can stop this game: its pot would be bought back and burned. Nobody is paid.";
347
+ readonly cap: "Pot capped at 10 SOL until the game’s hook is audited.";
348
+ readonly oracle: "Randomness by ORAO VRF: ORAO’s three signers produce it. They could withhold or bias a draw; Bordrless can’t.";
349
+ };
350
+ /** Why a round paid no prize, in a few words each (`GameRolloverReason`). */
351
+ export declare const ROLLOVER_WORDS: Readonly<Record<GameRolloverReason, string>>;
287
352
  /** Whether a split is the whole fee to the launcher (no companion needed). */
288
353
  export declare const isLauncherSplit: (s: CompanionSplitBps) => boolean;
289
354
  /** A split with a share for holders needs holder rewards on. */
package/dist/policy.js CHANGED
@@ -368,6 +368,120 @@ export const COMPANION_DEFAULT_VEST_DAYS = 30;
368
368
  export const COMPANION_MAX_VEST_DAYS = 365;
369
369
  /** The whole creator fee to the launcher: an ordinary launch, with no companion. */
370
370
  export const LAUNCHER_SPLIT = { buybackBps: 0, holdersBps: 0, beneficiaryBps: 10_000 };
371
+ // ---- lottery coins (docs/games.md) -----------------------------------------------------------------
372
+ /**
373
+ * The companion program's game limits (`constants.rs`; `GAME_LIMITS` in the SDK, the same numbers):
374
+ * a round's length, the minimum pot, the prize's least share, a claim window's bounds, the most
375
+ * attempts, and the half of a round the attempts may take. The launch form holds its choices to
376
+ * them and the backend refuses anything outside them (`lotteryProblem`).
377
+ */
378
+ export const LOTTERY_LIMITS = {
379
+ minRoundSecs: 3_600,
380
+ maxRoundSecs: 30 * DAY_SECS,
381
+ minMinPotLamports: 100000000n,
382
+ maxMinPotLamports: 1000000000000n,
383
+ minPrizeBps: 1_000,
384
+ minClaimWindowSecs: 300,
385
+ maxClaimWindowSecs: DAY_SECS,
386
+ maxAttempts: 16,
387
+ claimsPerRound: 2,
388
+ /** The most a pot holds while its hook is not audited: 10 SOL, the rest of the pot's share bought back. */
389
+ potCapLamports: 10000000000n,
390
+ /** Lamports the setup pays for the hook's state and registry and the game's account (mainnet rent, 2026-10-08). */
391
+ rentLamports: 3515360n + 3119120n,
392
+ };
393
+ /** The lottery the launch form starts with (docs/games.md, spec example 1): 6-hour rounds, 70% of the fee to the pot, 30% bought back, draws from 0.5 SOL paying the whole pot, 8 claim attempts of 10 minutes. */
394
+ export const LOTTERY_DEFAULTS = { kind: 'lottery', roundSecs: 21_600, potBps: 7_000, minPotLamports: '500000000', prizeBps: 10_000, claimWindowSecs: 600, maxAttempts: 8 };
395
+ /** The round lengths the form offers (seconds), each with its label. */
396
+ export const LOTTERY_ROUND_CHOICES = [
397
+ { secs: 3_600, label: '1 hour' },
398
+ { secs: 21_600, label: '6 hours' },
399
+ { secs: DAY_SECS, label: '1 day' },
400
+ { secs: 7 * DAY_SECS, label: '7 days' },
401
+ ];
402
+ /** The least a pot holds before a round is drawn, as the form offers it (lamports). */
403
+ export const LOTTERY_MIN_POT_CHOICES = [
404
+ { lamports: '100000000', label: '0.1 SOL' },
405
+ { lamports: '500000000', label: '0.5 SOL' },
406
+ { lamports: '1000000000', label: '1 SOL' },
407
+ { lamports: '5000000000', label: '5 SOL' },
408
+ ];
409
+ /** What one draw pays of the pot, as the form offers it. */
410
+ export const LOTTERY_PRIZE_CHOICES_BPS = [10_000, 5_000, 2_500];
411
+ /** The pot's share moves in steps of 10%, like the Split control's. */
412
+ export const LOTTERY_POT_STEP_BPS = 1_000;
413
+ /**
414
+ * The claim windows and attempts the form fixes for a round length: 8 attempts of 10 minutes for a
415
+ * round of 6 hours or more, 6 of 5 minutes for an hour (the attempts must fit in half a round).
416
+ */
417
+ export function lotteryClaimsFor(roundSecs) {
418
+ return roundSecs >= 21_600 ? { claimWindowSecs: 600, maxAttempts: 8 } : { claimWindowSecs: 300, maxAttempts: 6 };
419
+ }
420
+ const isWhole = (v, min, max) => typeof v === 'number' && Number.isInteger(v) && v >= min && v <= max;
421
+ /** The lottery a launch request's `companion.game` names, each field a whole number; null when it is malformed (bounds are `lotteryProblem`'s). */
422
+ export function lotteryRequestOf(raw) {
423
+ if (typeof raw !== 'object' || raw === null)
424
+ return null;
425
+ const r = raw;
426
+ if (r.kind !== 'lottery')
427
+ return null;
428
+ if (!isWhole(r.roundSecs, 0, 2 ** 32 - 1) || !isWhole(r.potBps, 0, 10_000) || !isWhole(r.prizeBps, 0, 10_000) || !isWhole(r.claimWindowSecs, 0, 2 ** 32 - 1) || !isWhole(r.maxAttempts, 0, 255))
429
+ return null;
430
+ if (typeof r.minPotLamports !== 'string' || !/^\d{1,20}$/.test(r.minPotLamports))
431
+ return null;
432
+ return { kind: 'lottery', roundSecs: r.roundSecs, potBps: r.potBps, minPotLamports: r.minPotLamports, prizeBps: r.prizeBps, claimWindowSecs: r.claimWindowSecs, maxAttempts: r.maxAttempts };
433
+ }
434
+ /**
435
+ * Why `create_game` would refuse this lottery with this split on these rules, in the words the
436
+ * launch form and the backend use (`companion_rules`); null when it would not. The program's own
437
+ * checks (`gameArgsProblem` in the SDK, the same sentences), and what a lottery coin's launch
438
+ * needs besides: a creator fee, no token rules (it launches from Bordrless's lottery config, which
439
+ * has none, and runs its own hook in the kit's place), and no holders' share.
440
+ */
441
+ export function lotteryProblem(game, split, rules, creatorFeeBps) {
442
+ const L = LOTTERY_LIMITS;
443
+ if (creatorFeeBps === 0)
444
+ return 'There is no creator fee to fill the pot with: set one.';
445
+ if (Object.keys(NO_RULES).some((k) => rules[k] !== 0))
446
+ return 'A lottery coin has no other token rules: its hook keeps the tickets.';
447
+ if (split.holdersBps !== 0)
448
+ return 'A game coin runs its own hook, so it has no holder rewards: no holders’ part.';
449
+ if (!(game.potBps > 0) || split.buybackBps + split.holdersBps + split.beneficiaryBps + game.potBps !== 10_000)
450
+ return 'The pot’s part and the split must add up to 10,000 basis points, with a pot.';
451
+ if (game.roundSecs < L.minRoundSecs || game.roundSecs > L.maxRoundSecs)
452
+ return 'A round lasts an hour to 30 days.';
453
+ const minPot = BigInt(game.minPotLamports);
454
+ if (minPot < L.minMinPotLamports || minPot > L.maxMinPotLamports)
455
+ return 'The minimum pot is 0.1 to 1,000 SOL.';
456
+ if (game.prizeBps < L.minPrizeBps || game.prizeBps > 10_000)
457
+ return 'A draw pays 10% to 100% of the pot.';
458
+ if (game.claimWindowSecs < L.minClaimWindowSecs || game.claimWindowSecs > L.maxClaimWindowSecs)
459
+ return 'A claim window lasts 5 minutes to a day.';
460
+ if (!(game.maxAttempts >= 1 && game.maxAttempts <= L.maxAttempts))
461
+ return 'A draw makes 1 to 16 attempts.';
462
+ if (game.claimWindowSecs * game.maxAttempts * L.claimsPerRound > game.roundSecs)
463
+ return 'A draw’s attempts must fit in half a round.';
464
+ return null;
465
+ }
466
+ /** The copy rules of a lottery coin (docs/games.md): said on the launch form, the review step and the token page, never "provably fair", "guaranteed" or "audited". */
467
+ export const LOTTERY_COPY = {
468
+ held: 'The pot is held by the companion program and paid out by code. Randomness by ORAO VRF.',
469
+ odds: 'Your odds = your tokens in the round. Sell before the payout and you forfeit.',
470
+ stop: 'Bordrless can stop this game: its pot would be bought back and burned. Nobody is paid.',
471
+ cap: 'Pot capped at 10 SOL until the game’s hook is audited.',
472
+ oracle: 'Randomness by ORAO VRF: ORAO’s three signers produce it. They could withhold or bias a draw; Bordrless can’t.',
473
+ };
474
+ /** Why a round paid no prize, in a few words each (`GameRolloverReason`). */
475
+ export const ROLLOVER_WORDS = {
476
+ noTickets: 'Nobody held tickets',
477
+ roundForgotten: 'The round was forgotten',
478
+ noClaim: 'No winner claimed in time',
479
+ oracleSilent: 'ORAO never answered',
480
+ blocked: 'Stopped by Bordrless',
481
+ late: 'Drawn too late',
482
+ oracleUnreadable: 'ORAO’s answer unreadable',
483
+ oracleUnpaid: 'The pot could not pay ORAO',
484
+ };
371
485
  /** Whether a split is the whole fee to the launcher (no companion needed). */
372
486
  export const isLauncherSplit = (s) => s.buybackBps === 0 && s.holdersBps === 0 && s.beneficiaryBps === 10_000;
373
487
  /** A split with a share for holders needs holder rewards on. */
@@ -35,7 +35,17 @@ export declare const LOTTERY_HOOK: {
35
35
  readonly tokenHookSigner: "CFyuaxvKmpgnSMCoNqDKCcwxnTUeW8Mm1go1t3UMsvLH";
36
36
  readonly hookAuthority: "6oZ9LkAfgmhmPYjXj3okjYK5sderddEo8fp8MR4H6Gx1";
37
37
  readonly readme: "https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/lottery_hook";
38
+ /**
39
+ * The `LaunchConfig`s a lottery coin launches from, one per creator fee (basis points): each
40
+ * names this hook with `flags`, no token rules and that creator fee, made by the protocol with
41
+ * `pnpm admin lottery-configs` (which prints the lines to paste here). A creator fee without a
42
+ * config can't launch a lottery coin yet: the launch form says so, the backend refuses it
43
+ * (`lottery_off`). Created on mainnet 2026-10-09 by `pnpm admin lottery-configs`.
44
+ */
45
+ readonly launchConfigs: Readonly<Partial<Record<number, string>>>;
38
46
  };
47
+ /** The creator fees (basis points) a lottery coin can launch with: those with a `LaunchConfig` in `LOTTERY_HOOK.launchConfigs`. */
48
+ export declare const lotteryFeeChoices: () => number[];
39
49
  /**
40
50
  * Half-Life, Bordrless's own token hook (programs/half_life/README.md): the `LaunchConfig` the
41
51
  * launch form's Half-Life path launches from (no kit rules, creator fee 1%, the hook with
package/dist/programs.js CHANGED
@@ -35,7 +35,21 @@ export const LOTTERY_HOOK = {
35
35
  tokenHookSigner: 'CFyuaxvKmpgnSMCoNqDKCcwxnTUeW8Mm1go1t3UMsvLH',
36
36
  hookAuthority: '6oZ9LkAfgmhmPYjXj3okjYK5sderddEo8fp8MR4H6Gx1',
37
37
  readme: 'https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/lottery_hook',
38
+ /**
39
+ * The `LaunchConfig`s a lottery coin launches from, one per creator fee (basis points): each
40
+ * names this hook with `flags`, no token rules and that creator fee, made by the protocol with
41
+ * `pnpm admin lottery-configs` (which prints the lines to paste here). A creator fee without a
42
+ * config can't launch a lottery coin yet: the launch form says so, the backend refuses it
43
+ * (`lottery_off`). Created on mainnet 2026-10-09 by `pnpm admin lottery-configs`.
44
+ */
45
+ launchConfigs: {
46
+ 50: 'CYm9FNY49gV7wjukpYFqkm9u7FQLrjp2GexeHwbncf1L',
47
+ 100: 'GViQSt6znkGdiCrUYNTo3dJKMgfGS8eBHPSBjxfN2VS9',
48
+ 200: 'Ejo4Ehg4x16MeBKn3Y2f1NU31CoBjnby4kv75azUD8hU',
49
+ },
38
50
  };
51
+ /** The creator fees (basis points) a lottery coin can launch with: those with a `LaunchConfig` in `LOTTERY_HOOK.launchConfigs`. */
52
+ export const lotteryFeeChoices = () => Object.keys(LOTTERY_HOOK.launchConfigs).map(Number).filter((bps) => bps > 0);
39
53
  /**
40
54
  * Half-Life, Bordrless's own token hook (programs/half_life/README.md): the `LaunchConfig` the
41
55
  * launch form's Half-Life path launches from (no kit rules, creator fee 1%, the hook with
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bordrless/shared",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "description": "Bordrless policy (the same math as crates/bordrless-core), program addresses and the API types shared by the server and the site. No Solana dependencies.",
6
6
  "license": "Apache-2.0",