@bordrless/shared 0.7.0 → 0.9.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.js CHANGED
@@ -1,9 +1,27 @@
1
- /**
2
- * The HTTP API between the site and the backend. Amounts in base units travel as decimal strings
3
- * (`Amount`), dollar figures as numbers, times as unix seconds. A figure the backend could not
4
- * read is null, never zero.
5
- */
6
1
  /** "What your hook does": the most an author writes, in characters (the Studio field and what is served). */
7
2
  export const HOOK_ABOUT_CHARS = 280;
8
3
  /** The official summary's limits, in characters. */
9
4
  export const HOOK_SUMMARY_LIMITS = { title: 40, text: 320 };
5
+ // ---- accounts and trading wallets --------------------------------------------------------------------
6
+ // POST /v1/account/session -> AccountSessionResponse the signup wallet signs `accountSignInMessage`
7
+ // GET /v1/account/wallets -> AccountWallets the session's trading wallets (public keys only)
8
+ // POST /v1/account/wallets -> AccountWallets register one; the trading wallet co-signs `tradingWalletMessage`
9
+ // POST /v1/account/wallets/:pubkey/revoke -> AccountWallets
10
+ // POST /v1/account/withdraw/prepare -> AccountWithdrawPrepareResponse a plain SOL transfer from a registered trading wallet
11
+ // POST /v1/account/withdraw/send -> AccountWithdrawSendResponse the signed transfer, sent and followed
12
+ //
13
+ // An account is a wallet: the one a visitor connected (their signup wallet), or, without one, a
14
+ // trading wallet generated in their browser. Trading wallets are keypairs made and kept in the
15
+ // browser; Bordrless stores their public keys and labels under the account, never a secret.
16
+ /** Trading wallets an account may have registered at once. */
17
+ export const MAX_TRADING_WALLETS = 5;
18
+ /** The header the account session travels in, browser → site proxy → backend. The same token serves Studio (`STUDIO_SESSION_HEADER`). */
19
+ export const ACCOUNT_SESSION_HEADER = 'x-studio-session';
20
+ /** The message a wallet signs to sign in to Bordrless: no transaction, nothing moves. */
21
+ export function accountSignInMessage(wallet, nonce, issuedAt) {
22
+ return ['Sign in to Bordrless', '', 'This signature proves you own this wallet. It does not move funds or approve any transaction.', '', `Wallet: ${wallet}`, `Nonce: ${nonce}`, `Issued: ${issuedAt}`].join('\n');
23
+ }
24
+ /** The message a trading wallet signs to be registered under an account: proof the key exists and is held by whoever holds the account. */
25
+ export function tradingWalletMessage(account, publicKey) {
26
+ return ['Bordrless trading wallet', '', 'This wallet was generated in your browser for trading on Bordrless and belongs to the account below.', '', `Account: ${account}`, `Wallet: ${publicKey}`].join('\n');
27
+ }
@@ -0,0 +1,21 @@
1
+ import type { ExplorerProgram } from './api.ts';
2
+ /** Which group a program id belongs to: the five of Bordrless, or any other program the indexer follows (a token hook). */
3
+ export declare function explorerProgramOf(programId: string): ExplorerProgram;
4
+ /** The groups' names, as the explorer's filter and its chips print them. */
5
+ export declare const EXPLORER_PROGRAM_NAMES: Readonly<Record<ExplorerProgram, string>>;
6
+ /** A program's name: one of the five, a hook Bordrless wrote, or "Hook" for any other. */
7
+ export declare function programLabel(programId: string): string;
8
+ /** The IDL's PascalCase name from whatever case the coder stored (`transferred` -> `Transferred`). */
9
+ export declare const eventName: (raw: string) => string;
10
+ interface EventWords {
11
+ label: string;
12
+ /** The payload key naming the account the event is mostly about; null when it has none worth linking. */
13
+ subject: string | null;
14
+ }
15
+ /** Every event of the IDLs, by its PascalCase name (`ConfigSet` is three programs' and reads the same). */
16
+ export declare const EVENT_WORDS: Readonly<Record<string, EventWords>>;
17
+ /** An event's label in plain words; an unknown event's name with its words spaced (`SomethingNew` -> "Something new"). */
18
+ export declare function eventLabel(name: string): string;
19
+ /** The account an event is mostly about, read from its payload; null when the table names none or the payload lacks it. */
20
+ export declare function eventSubject(name: string, payload: Record<string, unknown>): string | null;
21
+ export {};
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The explorer's words for the chain: each program's name, each IDL event's label in plain words
3
+ * and the account it is mostly about, in one table the backend and the site both read (the backend
4
+ * picks an event's subject with it; the site prints its label with the raw name as a title).
5
+ *
6
+ * Event names are the IDLs' (`packages/sdk/idl/*.json`), PascalCase; the SDK's coder gives them
7
+ * camelCase, which `eventName` undoes. An event the table does not know keeps its raw name, spaced.
8
+ */
9
+ import { PROGRAM_IDS } from "./programs.js";
10
+ /** Which group a program id belongs to: the five of Bordrless, or any other program the indexer follows (a token hook). */
11
+ export function explorerProgramOf(programId) {
12
+ switch (programId) {
13
+ case PROGRAM_IDS.token:
14
+ return 'token';
15
+ case PROGRAM_IDS.swap:
16
+ return 'swap';
17
+ case PROGRAM_IDS.bridge:
18
+ return 'bridge';
19
+ case PROGRAM_IDS.launch:
20
+ return 'launch';
21
+ case PROGRAM_IDS.kit:
22
+ return 'kit';
23
+ default:
24
+ return 'hook';
25
+ }
26
+ }
27
+ /** The groups' names, as the explorer's filter and its chips print them. */
28
+ export const EXPLORER_PROGRAM_NAMES = { token: 'Token', swap: 'DEX', bridge: 'Bridge', launch: 'Launchpad', kit: 'Kit', hook: 'Hook' };
29
+ /** A program's name: one of the five, a hook Bordrless wrote, or "Hook" for any other. */
30
+ export function programLabel(programId) {
31
+ if (programId === PROGRAM_IDS.taxHook)
32
+ return 'Tax hook';
33
+ if (programId === PROGRAM_IDS.halfLife)
34
+ return 'Half-Life';
35
+ return EXPLORER_PROGRAM_NAMES[explorerProgramOf(programId)];
36
+ }
37
+ /** The IDL's PascalCase name from whatever case the coder stored (`transferred` -> `Transferred`). */
38
+ export const eventName = (raw) => (raw ? `${raw.charAt(0).toUpperCase()}${raw.slice(1)}` : raw);
39
+ /** Every event of the IDLs, by its PascalCase name (`ConfigSet` is three programs' and reads the same). */
40
+ export const EVENT_WORDS = {
41
+ // token
42
+ MintCreated: { label: 'Mint created', subject: 'mint' },
43
+ HoldingCreated: { label: 'Holding opened', subject: 'holding' },
44
+ Transferred: { label: 'Transfer', subject: 'mint' },
45
+ Minted: { label: 'Mint', subject: 'mint' },
46
+ Burned: { label: 'Burn', subject: 'mint' },
47
+ HookSet: { label: 'Hook set', subject: 'mint' },
48
+ AuthoritySet: { label: 'Authority set', subject: 'mint' },
49
+ MetadataUpdated: { label: 'Metadata updated', subject: 'mint' },
50
+ HoldingClosed: { label: 'Holding closed', subject: 'holding' },
51
+ DelegateSet: { label: 'Delegate set', subject: 'holding' },
52
+ FrozenSet: { label: 'Freeze changed', subject: 'holding' },
53
+ HookDataWritten: { label: 'Hook data written', subject: 'holding' },
54
+ // swap
55
+ PoolCreated: { label: 'Pool created', subject: 'pool' },
56
+ Swapped: { label: 'Swap', subject: 'pool' },
57
+ LiquidityAdded: { label: 'Liquidity added', subject: 'pool' },
58
+ LiquidityRemoved: { label: 'Liquidity removed', subject: 'pool' },
59
+ CurveFinalized: { label: 'Curve finalized', subject: 'pool' },
60
+ ProtocolFeesCollected: { label: 'Protocol fees collected', subject: 'pool' },
61
+ ConfigSet: { label: 'Config set', subject: 'admin' },
62
+ // launch
63
+ LaunchCreated: { label: 'Launch created', subject: 'mint' },
64
+ Graduated: { label: 'Graduated', subject: 'mint' },
65
+ CreatorFeesClaimed: { label: 'Creator fees claimed', subject: 'mint' },
66
+ LaunchConfigCreated: { label: 'Launch config created', subject: 'config' },
67
+ // kit
68
+ KitInstalled: { label: 'Rules installed', subject: 'mint' },
69
+ KitGraduated: { label: 'Rules graduated', subject: 'mint' },
70
+ RewardsClaimed: { label: 'Rewards claimed', subject: 'mint' },
71
+ RewardsShared: { label: 'Rewards shared', subject: 'mint' },
72
+ // bridge
73
+ WrapperRegistered: { label: 'Wrapper registered', subject: 'wrappedMint' },
74
+ Wrapped: { label: 'Bridged in', subject: 'wrappedMint' },
75
+ Unwrapped: { label: 'Bridged out', subject: 'wrappedMint' },
76
+ // half_life
77
+ Stoked: { label: 'Exit fee burned', subject: 'mint' },
78
+ };
79
+ /** An event's label in plain words; an unknown event's name with its words spaced (`SomethingNew` -> "Something new"). */
80
+ export function eventLabel(name) {
81
+ const known = EVENT_WORDS[eventName(name)];
82
+ if (known)
83
+ return known.label;
84
+ const spaced = eventName(name).replace(/([a-z0-9])([A-Z])/g, '$1 $2');
85
+ return `${spaced.charAt(0)}${spaced.slice(1).toLowerCase()}`;
86
+ }
87
+ /** The account an event is mostly about, read from its payload; null when the table names none or the payload lacks it. */
88
+ export function eventSubject(name, payload) {
89
+ const key = EVENT_WORDS[eventName(name)]?.subject;
90
+ if (!key)
91
+ return null;
92
+ const value = payload[key];
93
+ return typeof value === 'string' && value.length > 0 ? value : null;
94
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './api.ts';
2
+ export * from './explorer.ts';
2
3
  export * from './policy.ts';
3
4
  export * from './programs.ts';
4
5
  export * from './studio.ts';
6
+ export * from './workshop.ts';
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./api.js";
2
+ export * from "./explorer.js";
2
3
  export * from "./policy.js";
3
4
  export * from "./programs.js";
4
5
  export * from "./studio.js";
6
+ export * from "./workshop.js";
package/dist/policy.d.ts CHANGED
@@ -6,7 +6,8 @@
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, GameRolloverReason, LaunchRules, LaunchRulesInput, LotteryRequest, Side } from './api.ts';
9
+ import type { CompanionSplitBps, CompanionTemplate, GameKindName, GameRequest, GameRolloverReason, JackpotRequest, LaunchRules, LaunchRulesInput, LotteryRequest, ScriptRequest, Side, SnowballRequest, SnowballTerms, StreakRequest } from './api.ts';
10
+ import type { StudioGameSettings } from './studio.ts';
10
11
  export declare const BPS = 10000n;
11
12
  export declare const WAD: bigint;
12
13
  /** The largest u64, where the programs' checked arithmetic stops. */
@@ -23,6 +24,15 @@ export declare const CURVE_BPS = 7500n;
23
24
  export declare const LP_FEE_BPS = 30;
24
25
  /** Protocol fee of an ordinary DEX pool (anyone's pool), in basis points of the quote side: the flat model (§3.1). */
25
26
  export declare const PROTOCOL_FEE_BPS = 100;
27
+ /**
28
+ * The LP fee tiers the create-pool form offers for an ordinary pool (docs/dex.md decision 2): 0.25%
29
+ * (the default, for bridged pairs), 1% and 2% (memecoins). The program takes any value from 0 to 90%;
30
+ * three tiers keep the number of duplicate pools per pair down (§3.5).
31
+ */
32
+ export declare const POOL_FEE_TIERS_BPS: readonly [25, 100, 200];
33
+ export declare const POOL_FEE_TIER_DEFAULT_BPS = 25;
34
+ export type PoolFeeTierBps = (typeof POOL_FEE_TIERS_BPS)[number];
35
+ export declare const isPoolFeeTier: (bps: unknown) => bps is PoolFeeTierBps;
26
36
  /**
27
37
  * Bordrless's take on a launch pool (its curve and the same pool after graduation), the share
28
38
  * model of §3.1 (2026-10-07: "we earn 25% of their total fees, not 0.25%"): a quarter of what the
@@ -34,6 +44,8 @@ export declare const PROTOCOL_FEE_BPS = 100;
34
44
  export declare const LAUNCH_PROTOCOL_SHARE_BPS = 2500;
35
45
  /** The largest share the DEX config may set (`MAX_PROTOCOL_SHARE_BPS`): all of the cuts. */
36
46
  export declare const MAX_PROTOCOL_SHARE_BPS = 10000;
47
+ /** The largest flat protocol fee the DEX config may set (`bordrless_swap::constants::MAX_PROTOCOL_FEE_BPS`): 10% of the quote side. */
48
+ export declare const MAX_PROTOCOL_FEE_BPS = 1000;
37
49
  /** Largest creator fee a launch may choose. */
38
50
  export declare const MAX_CREATOR_FEE_BPS = 200;
39
51
  /** The creator fee choices offered on the launch form. */
@@ -285,27 +297,32 @@ export declare const COMPANION_MAX_VEST_DAYS = 365;
285
297
  /** The whole creator fee to the launcher: an ordinary launch, with no companion. */
286
298
  export declare const LAUNCHER_SPLIT: Readonly<CompanionSplitBps>;
287
299
  /**
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`).
300
+ * The Jackpot's limits as the site offers them: the round's length (the programs take rounds from 5
301
+ * minutes since the five-minute rounds upgrade of 2026-10-12; the owner set the site's floor at 15
302
+ * minutes, which is also its default), the minimum pot, the prize's least share, a claim window's
303
+ * bounds (`MIN_CLAIM_WINDOW` in the companion, a minute), the most attempts, and the half of a round
304
+ * the attempts may take. The launch form holds its choices to them and the backend refuses anything
305
+ * outside them (`lotteryProblem`). `GAME_LIMITS` in the SDK is the programs' own.
292
306
  */
293
307
  export declare const LOTTERY_LIMITS: {
294
- readonly minRoundSecs: 3600;
308
+ readonly minRoundSecs: 900;
295
309
  readonly maxRoundSecs: number;
296
310
  readonly minMinPotLamports: 100000000n;
297
311
  readonly maxMinPotLamports: 1000000000000n;
298
312
  readonly minPrizeBps: 1000;
299
- readonly minClaimWindowSecs: 300;
313
+ readonly minClaimWindowSecs: 60;
300
314
  readonly maxClaimWindowSecs: 86400;
301
315
  readonly maxAttempts: 16;
302
316
  readonly claimsPerRound: 2;
317
+ /** A streak's epoch and its claim window keep the programs' older floors (`MIN_EPOCH_SECS`, `MIN_EPOCH_CLAIM_WINDOW`). */
318
+ readonly minEpochSecs: 3600;
319
+ readonly minEpochClaimWindowSecs: 300;
303
320
  /** The most a pot holds while its hook is not audited: 10 SOL, the rest of the pot's share bought back. */
304
321
  readonly potCapLamports: 10000000000n;
305
322
  /** Lamports the setup pays for the hook's state and registry and the game's account (mainnet rent, 2026-10-08). */
306
323
  readonly rentLamports: bigint;
307
324
  };
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. */
325
+ /** The lottery the launch form starts with (the owner, 2026-10-12): 15-minute rounds, 70% of the fee to the pot, 30% bought back, draws from 0.5 SOL paying the whole pot, 3 claim attempts of 2 minutes (`lotteryClaimsFor`). */
309
326
  export declare const LOTTERY_DEFAULTS: Readonly<LotteryRequest>;
310
327
  /** The round lengths the form offers (seconds), each with its label. */
311
328
  export declare const LOTTERY_ROUND_CHOICES: readonly {
@@ -322,8 +339,10 @@ export declare const LOTTERY_PRIZE_CHOICES_BPS: readonly [10000, 5000, 2500];
322
339
  /** The pot's share moves in steps of 10%, like the Split control's. */
323
340
  export declare const LOTTERY_POT_STEP_BPS = 1000;
324
341
  /**
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).
342
+ * The claim windows and attempts the form fixes for a round length (the attempts must fit in half a
343
+ * round, `claimsPerRound`): 8 attempts of 10 minutes from 6 hours, 6 of 5 minutes from an hour, 3 of
344
+ * 2 minutes from 15 minutes, and 2 of a minute under that (the programs' 5-minute rounds, which the
345
+ * site does not offer).
327
346
  */
328
347
  export declare function lotteryClaimsFor(roundSecs: number): {
329
348
  claimWindowSecs: number;
@@ -341,11 +360,61 @@ export declare function lotteryRequestOf(raw: unknown): LotteryRequest | null;
341
360
  export declare function lotteryProblem(game: LotteryRequest, split: CompanionSplitBps, rules: LaunchRulesInput, creatorFeeBps: number): string | null;
342
361
  /** 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
362
  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.";
363
+ readonly held: "The pot is held by code, not by a person. Each round, one holder is picked at random and paid in SOL.";
364
+ readonly odds: "Your odds are your share of the tokens held through the round. Tokens you buy count from the next round, and selling during a round takes you out of it.";
365
+ readonly stop: "Bordrless can stop the game. If it does, the pot buys back and burns the token and no one is paid.";
366
+ readonly cap: "The pot holds at most 10 SOL for now. Anything above that buys back and burns the token.";
367
+ readonly oracle: "The random numbers come from ORAO, an outside service. Neither Bordrless nor the launcher can pick the winner.";
368
+ };
369
+ /** The jackpot's timer and the streak's minimum streak: the companion's bounds (`GAME_LIMITS` in the SDK). */
370
+ export declare const GAME_KIND_LIMITS: {
371
+ readonly minTimerSecs: 300;
372
+ readonly maxTimerSecs: number;
373
+ readonly maxMinStreakSecs: number;
374
+ };
375
+ /** A jackpot as the launch form starts it (spec example 2, `JACKPOT_DEFAULTS` in the SDK): 70% of the fee to the pot, 30% bought back, half the pot to the last buyer from 0.5 SOL. */
376
+ export declare const JACKPOT_REQUEST_DEFAULTS: Readonly<JackpotRequest>;
377
+ /** A streak as the launch form starts it (spec example 3, `STREAK_DEFAULTS` in the SDK): 70% of the fee to the pot, 30% bought back, the whole pot shared each epoch from 0.1 SOL, an hour at least for claims. */
378
+ export declare const STREAK_REQUEST_DEFAULTS: Readonly<StreakRequest>;
379
+ /** The least a streak's close leaves for claims, as the form offers it (seconds); each must fit half the hook's epoch. */
380
+ export declare const STREAK_CLAIM_WINDOW_CHOICES: readonly {
381
+ secs: number;
382
+ label: string;
383
+ }[];
384
+ /** The game a launch request's `companion.game` names, of any kind, each field a whole number; null when malformed (bounds are `gameProblem`'s). */
385
+ export declare function gameRequestOf(raw: unknown): GameRequest | null;
386
+ /**
387
+ * Why `create_game_v2` (or the launch) would refuse this game with this split on these rules at
388
+ * this fee, with `hook` the Studio game hook the config names (`ConfigInspection.game`; null: the
389
+ * config names none), in one sentence; null when it would not. A lottery is `lotteryProblem`'s.
390
+ * The program's own checks (`gameArgsProblem` in the SDK, the same sentences) and what a game
391
+ * coin's launch needs besides: a creator fee, no token rules, no holders' share, and a hook of the
392
+ * game's kind.
393
+ */
394
+ export declare function gameProblem(game: GameRequest, split: CompanionSplitBps, rules: LaunchRulesInput, creatorFeeBps: number, hook?: StudioGameSettings | null): string | null;
395
+ /** Each game kind in a word: "jackpot". */
396
+ export declare const GAME_KIND_NAMES: Readonly<Record<GameKindName, string>>;
397
+ /**
398
+ * The copy rules of a jackpot and a streak coin (docs/games.md "Phase 2", "Site"): said on the
399
+ * launch form, the review step and the token page. The pot is held by the companion and paid by
400
+ * code (no randomness in either kind), the 10 SOL cap until the hook is audited, "Bordrless can
401
+ * stop this game"; never "provably fair", "guaranteed" or "audited".
402
+ */
403
+ export declare const JACKPOT_COPY: {
404
+ readonly held: "The pot is held by code, not by a person. No luck involved: the last buyer wins.";
405
+ readonly rule: "The last buyer wins when the timer runs out, as long as they still hold what they bought. Selling or sending any of it forfeits.";
406
+ readonly unfunded: "If the pot is under its minimum when the timer runs out, no prize is paid and the pot keeps growing.";
407
+ readonly curve: "The game runs while the coin is on its curve and ends at graduation. A round under way is still paid.";
408
+ readonly cap: "The pot holds at most 10 SOL for now. Anything above that buys back and burns the token.";
409
+ readonly stop: "Bordrless can stop the game. If it does, the pot buys back and burns the token and no one is paid.";
410
+ };
411
+ export declare const STREAK_COPY: {
412
+ readonly held: "The pot is held by code, not by a person. No luck involved: holders share it in proportion to what they held.";
413
+ readonly rule: "Hold through the epoch without sending anything. Any sale or transfer drops you out of this epoch and the last one.";
414
+ readonly weight: "Your share is based on what you held when the epoch began. Tokens you buy during an epoch count from the next one.";
415
+ readonly claims: "Shares are paid out during the next epoch. Most are paid automatically; small ones are claimed here. Unclaimed shares stay in the pot.";
416
+ readonly cap: "The pot holds at most 10 SOL for now. Anything above that buys back and burns the token.";
417
+ readonly stop: "Bordrless can stop the game. If it does, the pot buys back and burns the token and no one is paid.";
349
418
  };
350
419
  /** Why a round paid no prize, in a few words each (`GameRolloverReason`). */
351
420
  export declare const ROLLOVER_WORDS: Readonly<Record<GameRolloverReason, string>>;
@@ -371,6 +440,61 @@ export declare function companionRequestSplit(raw: unknown): CompanionSplitBps |
371
440
  * `CreatorLockUnsupported`, `HolderRewardsOff`), and a creator fee for it to run.
372
441
  */
373
442
  export declare function companionSplitProblem(split: CompanionSplitBps, rules: Pick<LaunchRulesInput, 'holderFeeBuyBps' | 'holderFeeSellBps' | 'creatorLockDays'>, creatorFeeBps: number): string | null;
443
+ /** The presets the launch form offers. Every one spends the pot on volume and trades even when the price is flat; they differ in how fast and how big. */
444
+ export type SnowballPreset = 'conservative' | 'normal' | 'aggressive';
445
+ export declare const SNOWBALL_PRESETS: Readonly<Record<SnowballPreset, Readonly<SnowballTerms>>>;
446
+ export declare const SNOWBALL_PRESET_LIST: readonly SnowballPreset[];
447
+ export declare const SNOWBALL_DEFAULT_PRESET: SnowballPreset;
448
+ /** The custom controls' choices. The program takes anything within `SNOWBALL_BOUNDS`. */
449
+ export declare const SNOWBALL_STEP_CHOICES_BPS: readonly [50, 100, 200, 300, 500, 1000];
450
+ export declare const SNOWBALL_SIZE_CHOICES_BPS: readonly [1000, 2500, 5000, 7500, 10000];
451
+ export declare const SNOWBALL_POOL_CHOICES_BPS: readonly [100, 200, 500, 1000];
452
+ export declare const SNOWBALL_INTERVAL_CHOICES_SECS: readonly [10, 30, 60, 300];
453
+ /** The program's bounds (`create_snowball`). */
454
+ export declare const SNOWBALL_BOUNDS: {
455
+ readonly minStepBps: 50;
456
+ readonly maxStepBps: 2000;
457
+ readonly minSizeBps: 100;
458
+ readonly maxSizeBps: 10000;
459
+ readonly minPoolBps: 25;
460
+ readonly maxPoolBps: 1000;
461
+ readonly minInterval: 10;
462
+ readonly maxInterval: 86400;
463
+ };
464
+ /** The Snowball a launch request's `companion` names; null without one; `'malformed'` when it is there and not whole numbers and a flag. */
465
+ export declare function snowballRequestOf(companion: unknown): SnowballRequest | null | 'malformed';
466
+ /**
467
+ * Why a Snowball with this split can't run these rules at this fee, in the words the launch form and
468
+ * the backend use (`companion_rules`); null when it can: the market maker's part with the split adds up
469
+ * to 10,000, its terms are within the program's bounds, and what any companion needs
470
+ * (`companionSplitProblem`'s rules).
471
+ */
472
+ export declare function snowballProblem(s: SnowballRequest, split: CompanionSplitBps, rules: Pick<LaunchRulesInput, 'holderFeeBuyBps' | 'holderFeeSellBps' | 'creatorLockDays'>, creatorFeeBps: number): string | null;
473
+ /** The companion program's script bounds (`create_script`): steps 10 seconds to a day apart, at most 512 bytes of init data, at most 10,240 bytes of state. */
474
+ export declare const SCRIPT_BOUNDS: {
475
+ readonly minInterval: 10;
476
+ readonly maxInterval: 86400;
477
+ readonly maxInitLen: 512;
478
+ readonly maxStateLen: 10240;
479
+ };
480
+ /** The interval choices the launch form offers (seconds): a minute, five, fifteen, an hour, a day. */
481
+ export declare const SCRIPT_INTERVAL_CHOICES_SECS: readonly [60, 300, 900, 3600, 86400];
482
+ /**
483
+ * How many bytes a script's init data holds, as the request writes it: hex (an even number of hex
484
+ * digits, `0x` or not) or base64; the empty string is no data. Null when it is neither. Hex is tried
485
+ * first: a text that reads as both (`abcd`) is read as hex.
486
+ */
487
+ export declare function scriptInitDataLength(raw: string): number | null;
488
+ /** The custom companion's script a launch request's `companion` names; null without one; `'malformed'` when it is there and not the fields `ScriptRequest` takes. */
489
+ export declare function scriptRequestOf(companion: unknown): ScriptRequest | null | 'malformed';
490
+ /**
491
+ * Why a custom companion with this split can't run these rules at this fee, in the words the launch
492
+ * form and the backend use (`companion_rules`); null when it can: the pot's part with the split adds
493
+ * up to 10,000, the interval, the init data and the state are within the program's bounds, and what
494
+ * any companion needs (`companionSplitProblem`'s rules). Whether the script is approved is the
495
+ * backend's to check (`script_not_approved`).
496
+ */
497
+ export declare function scriptProblem(s: ScriptRequest, split: CompanionSplitBps, rules: Pick<LaunchRulesInput, 'holderFeeBuyBps' | 'holderFeeSellBps' | 'creatorLockDays'>, creatorFeeBps: number): string | null;
374
498
  /** The template whose split this is, or null for any other split. */
375
499
  export declare function companionTemplateOf(split: CompanionSplitBps): CompanionTemplate | null;
376
500
  /** Kit module bits (§4.2). */