@bordrless/shared 0.0.0-stage → 0.1.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.
@@ -0,0 +1,622 @@
1
+ /**
2
+ * The launch policy and the pool math, mirroring `crates/bordrless-core` bit for bit (integer
3
+ * math in bigint), and the kit's reward accounting with its off-chain mirror, mirroring
4
+ * `bordrless_kit::math` and `bordrless_kit::mirror`. The numbers the site shows and the numbers
5
+ * the backend builds transactions from come from here. `vectors.test.ts` runs every case of
6
+ * `programs/tests/vectors/launch-fees.json`, which the Rust tests render from the reference the
7
+ * programs are held to, and requires exact equality.
8
+ */
9
+ import type { LaunchRules, LaunchRulesInput, Side } from './api.ts';
10
+ export declare const BPS = 10000n;
11
+ export declare const WAD: bigint;
12
+ /** The largest u64, where the programs' checked arithmetic stops. */
13
+ export declare const U64_MAX: bigint;
14
+ /** The largest u128 (the kit's `acc_per_share` and `rem`). */
15
+ export declare const U128_MAX: bigint;
16
+ /** Decimals of a launched token. */
17
+ export declare const TOKEN_DECIMALS = 6;
18
+ /** Supply of a launched token, base units: one billion whole tokens. */
19
+ export declare const TOKEN_SUPPLY: bigint;
20
+ /** Share of the supply sold on the curve; the rest is reserved for graduation. */
21
+ export declare const CURVE_BPS = 7500n;
22
+ /** LP fee of a launch pool, which stays in the pool for ever. */
23
+ export declare const LP_FEE_BPS = 30;
24
+ /** Protocol fee of an ordinary DEX pool (anyone's pool), in basis points of the quote side: the flat model (§3.1). */
25
+ export declare const PROTOCOL_FEE_BPS = 100;
26
+ /**
27
+ * Bordrless's take on a launch pool (its curve and the same pool after graduation), the share
28
+ * model of §3.1 (2026-10-07: "we earn 25% of their total fees, not 0.25%"): a quarter of what the
29
+ * launch's rules collect on each swap (the creator fee, holder rewards and any cut a creator's own
30
+ * hook takes), in SOL, rounded up, never more than the cuts. Burns and the pool's LP fee are not
31
+ * collected by anyone and are not shared. A launch whose rules collect nothing pays Bordrless
32
+ * nothing. Every launch-side figure uses this one; the flat rate above is for ordinary pools.
33
+ */
34
+ export declare const LAUNCH_PROTOCOL_SHARE_BPS = 2500;
35
+ /** The largest share the DEX config may set (`MAX_PROTOCOL_SHARE_BPS`): all of the cuts. */
36
+ export declare const MAX_PROTOCOL_SHARE_BPS = 10000;
37
+ /** Largest creator fee a launch may choose. */
38
+ export declare const MAX_CREATOR_FEE_BPS = 200;
39
+ /** The creator fee choices offered on the launch form. */
40
+ export declare const CREATOR_FEE_CHOICES_BPS: readonly [0, 50, 100, 200];
41
+ /** Seconds after creation during which the LP fee is elevated against snipers. */
42
+ export declare const SNIPER_WINDOW_SECS = 30;
43
+ /** LP fee at the first second of the sniper window, falling linearly to LP_FEE_BPS. */
44
+ export declare const SNIPER_START_BPS = 8000;
45
+ /** Paid by the creator to the treasury at launch. */
46
+ export declare const LAUNCH_FEE_LAMPORTS = 10000000n;
47
+ /** Bounds of the virtual quote reserve a launch may open with (bridged SOL, 9 decimals). */
48
+ export declare const MIN_VIRTUAL_QUOTE = 1000000000n;
49
+ export declare const MAX_VIRTUAL_QUOTE = 10000000000000n;
50
+ /** LP units the pool keeps on the first deposit. */
51
+ export declare const MINIMUM_LIQUIDITY = 1000n;
52
+ /** Decimals of an LP mint. */
53
+ export declare const LP_DECIMALS = 9;
54
+ /** Decimals of bridged SOL. */
55
+ export declare const SOL_DECIMALS = 9;
56
+ /** The dollar market cap a launch opens at; the backend sets the virtual quote to hit it. */
57
+ export declare const OPENING_MCAP_USD = 5000;
58
+ /** Candle resolutions the API serves, in seconds. */
59
+ export declare const CANDLE_RESOLUTIONS: {
60
+ readonly '1m': 60;
61
+ readonly '5m': 300;
62
+ readonly '15m': 900;
63
+ readonly '1h': 3600;
64
+ readonly '4h': 14400;
65
+ readonly '1d': 86400;
66
+ };
67
+ export type CandleResolution = keyof typeof CANDLE_RESOLUTIONS;
68
+ export declare function mulDivFloor(a: bigint, b: bigint, d: bigint): bigint;
69
+ export declare function mulDivCeil(a: bigint, b: bigint, d: bigint): bigint;
70
+ /** A fee of `bps` on `amount`, rounded up. */
71
+ export declare function feeAmount(amount: bigint, bps: number | bigint): bigint;
72
+ /**
73
+ * Bordrless's share of `value`, the quote value of what a launch pool's hooks cut from one side of
74
+ * a swap (`bordrless_core::protocol_share`): `shareBps` of it, rounded up, never more than `value`
75
+ * (a share is at most 10,000). Pure: 0 in gives 0 out, so a launch whose rules collect nothing pays
76
+ * nothing.
77
+ */
78
+ export declare function protocolShare(value: bigint, shareBps: number): bigint;
79
+ /**
80
+ * The quote value of a base-side cut at the swap's own price (`bordrless_core::quote_value`):
81
+ * `ceil(cut * quoteLeg / baseLeg)` over the quote and base the curve exchanged; 0 for no cut.
82
+ * Only a creator's own token hook makes base-side cuts (the kit takes none); the launch quote math
83
+ * here does not model them.
84
+ */
85
+ export declare function quoteValue(base: bigint, quoteLeg: bigint, baseLeg: bigint): bigint;
86
+ export declare function isqrt(n: bigint): bigint;
87
+ /** The reserves of a pool as the math sees them. */
88
+ export interface Reserves {
89
+ baseReserve: bigint;
90
+ quoteReserve: bigint;
91
+ virtualBase: bigint;
92
+ virtualQuote: bigint;
93
+ }
94
+ /** Constant-product output of `amountIn` (after fees), or null when nothing comes out or the output would exceed the real reserve. */
95
+ export declare function swapOut(amountIn: bigint, reserveIn: bigint, virtualIn: bigint, reserveOut: bigint, virtualOut: bigint): bigint | null;
96
+ /**
97
+ * The input (after fees) that buys exactly `amountOut`, rounded up; null when `amountOut` is above
98
+ * the real reserve, when the curve can never give it (no virtual output reserve left beyond it), or
99
+ * when the input would not fit a u64 (`bordrless_core::swap_in_for_out`).
100
+ */
101
+ export declare function swapInForOut(amountOut: bigint, reserveIn: bigint, virtualIn: bigint, reserveOut: bigint, virtualOut: bigint): bigint | null;
102
+ /** The largest input (after fees) before the real output reserve is exhausted. */
103
+ export declare function maxSwapIn(reserveIn: bigint, virtualIn: bigint, reserveOut: bigint, virtualOut: bigint): bigint | null;
104
+ /** Spot price in quote base units per base base unit, times WAD. */
105
+ export declare function spotPriceWad(r: Reserves): bigint;
106
+ /** Spot price as a number: quote whole units per base whole unit. */
107
+ export declare function spotPrice(r: Reserves, baseDecimals: number, quoteDecimals: number): number;
108
+ /**
109
+ * The fees and the curve of one swap in the order of the v2 DEX (docs/hooks-v2.md §3.1),
110
+ * `bordrless_core::SwapAmounts`. The LP fee is on the input in both directions and stays in the
111
+ * pool; the protocol fee is always in the quote token, kept apart from the reserves: a buy's from
112
+ * what reached the vault, before the curve, a sell's from the curve's output.
113
+ */
114
+ export interface SwapAmounts {
115
+ /** In the input token: `feeAmount(received, lpFeeBps)`. */
116
+ lpFee: bigint;
117
+ /** In the quote token: `feeAmount(received, protocolFeeBps)` on a buy, `feeAmount(outGross, protocolFeeBps)` on a sell. */
118
+ protocolFee: bigint;
119
+ /** What goes into the curve: what reached the vault less the LP fee and, on a buy, the protocol fee. */
120
+ netIn: bigint;
121
+ /** What the curve gives: it leaves the output reserve. */
122
+ outGross: bigint;
123
+ /** What the output side hands on: `outGross`, less a sell's protocol fee. A pool hook's `after_swap` is told this; without a hook it is delivered. */
124
+ amountOut: bigint;
125
+ /** What enters the input reserve: what reached the vault, less a buy's protocol fee. */
126
+ toReserveIn: bigint;
127
+ }
128
+ /** Why the DEX refuses a swap (`bordrless_core::SwapFailure`): `FeeExceedsInput`, `InsufficientLiquidity`, `FeeExceedsOutput`. */
129
+ export type SwapFailure = 'fees_exceed_input' | 'insufficient_liquidity' | 'fee_exceeds_output';
130
+ /**
131
+ * `bordrless_core::swap_amounts`: the amounts of a swap whose input vault received `received`
132
+ * (after any `before_swap` cut), or why the DEX refuses it. A fee that does not fit a u64 is larger
133
+ * than the amount it is taken from.
134
+ */
135
+ export declare function swapAmounts(side: Side, received: bigint, lpFeeBps: number, protocolFeeBps: number, r: Reserves): (SwapAmounts & {
136
+ failure: null;
137
+ }) | {
138
+ failure: SwapFailure;
139
+ };
140
+ /**
141
+ * A swap on a pool as the v2 DEX runs it (§3.1), `received` being what reached the input vault
142
+ * (the caller applies a hook's `before_swap` cut first, and its `after_swap` cut to `amountOut`).
143
+ * The protocol fee is in the quote token on both sides: a buy's from what reached the vault, a
144
+ * sell's from the curve's output, so a sell's `amountOut` is the curve's output less it. On a
145
+ * failure the fields are those computed up to it and `amountOut` is null.
146
+ */
147
+ export declare function quoteSwap(r: Reserves, direction: Side, amountIn: bigint, lpFeeBps: number, protocolFeeBps: number): {
148
+ lpFee: bigint;
149
+ protocolFee: bigint;
150
+ netIn: bigint;
151
+ amountOut: bigint | null;
152
+ outGross: bigint | null;
153
+ toReserveIn: bigint;
154
+ failure: SwapFailure | null;
155
+ };
156
+ /** First LP: sqrt(base · quote), of which MINIMUM_LIQUIDITY stays with the pool. */
157
+ export declare function initialLp(base: bigint, quote: bigint): {
158
+ toDepositor: bigint;
159
+ total: bigint;
160
+ } | null;
161
+ /** A later deposit: what is taken at the pool's ratio and the LP minted. */
162
+ export declare function lpForDeposit(baseDesired: bigint, quoteDesired: bigint, baseReserve: bigint, quoteReserve: bigint, lpSupply: bigint): {
163
+ baseUsed: bigint;
164
+ quoteUsed: bigint;
165
+ lp: bigint;
166
+ } | null;
167
+ /** What `lp` shares withdraw. */
168
+ export declare function withdrawForLp(lp: bigint, baseReserve: bigint, quoteReserve: bigint, lpSupply: bigint): {
169
+ base: bigint;
170
+ quote: bigint;
171
+ } | null;
172
+ export interface CurveParams {
173
+ curveTokens: bigint;
174
+ reserveTokens: bigint;
175
+ virtualQuote: bigint;
176
+ virtualBase: bigint;
177
+ graduationQuote: bigint;
178
+ }
179
+ /** The curve of a launch from the supply, the curve share and the virtual quote it opens with. */
180
+ export declare function curveParams(supply: bigint, curveBps: bigint, virtualQuote: bigint): CurveParams | null;
181
+ /** The market cap a curve opens at, in quote base units. */
182
+ export declare function openingMcap(supply: bigint, p: CurveParams): bigint;
183
+ /** The virtual quote that opens a curve at `mcap` quote base units (the inverse of openingMcap, rounded up). */
184
+ export declare function virtualQuoteForMcap(supply: bigint, curveBps: bigint, mcap: bigint): bigint | null;
185
+ /** Base to add at graduation so the price is continuous without the virtual offsets. */
186
+ export declare function graduationTopup(r: Reserves): bigint;
187
+ /** The LP fee during the sniper window. */
188
+ export declare function sniperLpFee(now: number, createdAt: number, windowSecs: number, startBps: number, baseBps: number): number;
189
+ /** The virtual quote for a launch opening at OPENING_MCAP_USD given the quote's dollar price, clamped to the bounds. */
190
+ export declare function virtualQuoteForUsd(quoteUsd: number, quoteDecimals?: number, mcapUsd?: number): bigint;
191
+ /** Bounds of token rules as the launch `Config` keeps them (§5.2); `create_launch` refuses anything outside them. */
192
+ export interface RuleBounds {
193
+ maxHolderFeeBps: number;
194
+ maxBurnBps: number;
195
+ /** Creator + holders + burn on one side. */
196
+ maxRulesFeeBps: number;
197
+ minMaxWalletBps: number;
198
+ maxMaxWalletBps: number;
199
+ maxCreatorLockSecs: number;
200
+ maxEarlyWindowSecs: number;
201
+ maxEarlyLockSecs: number;
202
+ }
203
+ /** The policy every launch config is set to. */
204
+ export declare const RULE_BOUNDS: Readonly<RuleBounds>;
205
+ /** Ceilings `init_config` and `set_config` enforce, which no config can raise (max wallet stays below 10,000; 1 is the kit's own floor). */
206
+ export declare const RULE_CEILINGS: Readonly<RuleBounds>;
207
+ /** The smallest launch supply a config may set (a ceiling of §5.2), so `min_eligible` is at least 1. */
208
+ export declare const MIN_LAUNCH_SUPPLY = 1000n;
209
+ /** The largest launch supply a config may set: the kit installs on no larger supply (§4.11). */
210
+ export declare const MAX_LAUNCH_SUPPLY = 10000000000000000n;
211
+ /** Holder rewards offered on the launch form, per side (§7.1). */
212
+ export declare const HOLDER_FEE_CHOICES_BPS: readonly [0, 50, 100, 200];
213
+ /** Burn offered on the launch form, per side. */
214
+ export declare const BURN_CHOICES_BPS: readonly [0, 25, 50, 100];
215
+ /** Max wallet offered on the launch form, as a share of supply until graduation. */
216
+ export declare const MAX_WALLET_CHOICES_BPS: readonly [0, 100, 200, 300, 500];
217
+ /** Creator wallet lock offered on the launch form, in days. */
218
+ export declare const CREATOR_LOCK_CHOICES_DAYS: readonly [0, 7, 30, 90];
219
+ /** Early-buyer lock: buys this many seconds after the launch or sooner are locked. */
220
+ export declare const EARLY_WINDOW_CHOICES_SECS: readonly [0, 30, 60, 300];
221
+ /** Early-buyer lock: seconds after the launch when those tokens unlock (15 min, 1 h, 24 h). */
222
+ export declare const EARLY_LOCK_CHOICES_SECS: readonly [900, 3600, 86400];
223
+ /** No token rules. */
224
+ export declare const NO_RULES: Readonly<LaunchRulesInput>;
225
+ /** The §7.1 per-rule defaults the Custom path starts from when a rule is switched on: holder rewards 1% both sides, max wallet 2%, creator wallet lock 30 days, no burn, no early-buyer lock. (The preset the form starts on is Plain.) */
226
+ export declare const DEFAULT_RULES: Readonly<LaunchRulesInput>;
227
+ /** Holder rewards are on when either side takes a holder fee. */
228
+ export declare const rewardsOn: (r: Pick<LaunchRulesInput, "holderFeeBuyBps" | "holderFeeSellBps">) => boolean;
229
+ /** The default creator fee: 0.5% with holder rewards on, else 1%. */
230
+ export declare const defaultCreatorFeeBps: (r: LaunchRulesInput) => number;
231
+ /** The four presets of §7.1 (2026-10-07: Holders first, Fair start, Scorched and Community are gone). */
232
+ export type RulePresetName = 'Plain' | 'Diamond hands' | 'Burn' | 'Paid to hold';
233
+ /** The two ways beside the presets (§7.1): Custom mixes the rules by hand with the form's controls; Build your own launches from a `LaunchConfig` a creator made with the SDK (§5.7). */
234
+ export type RulePathName = 'Custom' | 'Build your own';
235
+ /** What the launch form's rules row can be set to: a preset, or one of the two paths. */
236
+ export type RuleModeName = RulePresetName | RulePathName;
237
+ export interface RulePreset {
238
+ name: RulePresetName;
239
+ /** How links name it: `/launch?preset=<slug>`. */
240
+ slug: string;
241
+ /** One line: what it sets. */
242
+ description: string;
243
+ /** The creator fee it sets. */
244
+ creatorFeeBps: number;
245
+ /** The rules it sets. */
246
+ rules: Readonly<LaunchRulesInput>;
247
+ }
248
+ export interface RulePath {
249
+ name: RulePathName;
250
+ /** How links name it: `/launch?preset=<slug>`. */
251
+ slug: string;
252
+ /** One line: what it is. */
253
+ description: string;
254
+ }
255
+ /**
256
+ * The presets of the launch form, in order (§7.1), the one list the launch page, the home page and
257
+ * the docs read; `bordrless_core::policy::presets::ALL` is the same list, and the fee vectors pin
258
+ * this one to it. Each stays within the §5.2 bounds and the 3%-per-side cap (the policy test checks
259
+ * every one). Holder rewards set "both sides" take the same rate on buys and sells.
260
+ */
261
+ export declare const RULE_PRESETS: readonly RulePreset[];
262
+ /** The two paths beside the presets, in order, with the words the home console and the launch form print. */
263
+ export declare const RULE_PATHS: readonly RulePath[];
264
+ /** The preset the launch form starts on. */
265
+ export declare const DEFAULT_RULE_PRESET: RulePresetName;
266
+ /** The preset of this name. */
267
+ export declare function presetNamed(name: RulePresetName): RulePreset;
268
+ /** Kit module bits (§4.2). */
269
+ export declare const KIT_MODULES: {
270
+ readonly HOLDER_REWARDS: 1;
271
+ readonly MAX_WALLET: 2;
272
+ readonly CREATOR_LOCK: 4;
273
+ readonly EARLY_LOCK: 8;
274
+ };
275
+ /** The kit modules a launch with these rules installs (§5.1); 0 means no hook at all (a burn alone runs in the pool hook). */
276
+ export declare function kitModules(r: LaunchRulesInput): number;
277
+ /**
278
+ * The token hook flags a kit mint carries for `modules` (§4.2, `bordrless_kit::mint_flags`):
279
+ * `BEFORE_TRANSFER`, plus `BEFORE_BURN | WRITES_HOOK_DATA` with holder rewards or the early-buyer
280
+ * lock; 0 (no hook at all) without modules. So 1 for modules 2, 4 or 6, and 145 whenever 1 or 8 is
281
+ * among them. A mint naming the kit with other flags is not a kit token (§4.15).
282
+ */
283
+ export declare function kitMintFlags(modules: number): number;
284
+ /** The rules a launch made at `launchedAt` (unix seconds) carries, as the API shows them. */
285
+ export declare function launchRulesAt(r: LaunchRulesInput, launchedAt: number): LaunchRules;
286
+ /**
287
+ * Why `create_launch` would refuse these rules with this creator fee under `bounds`, as the sentence
288
+ * the launch form shows; null when it would take them. An early-buyer lock needs its window, and its
289
+ * tokens must unlock after the window ends.
290
+ */
291
+ export declare function checkLaunchRules(r: LaunchRulesInput, creatorFeeBps: number, bounds?: Readonly<RuleBounds>): string | null;
292
+ /**
293
+ * §8.1 `preset`: the §7.1 preset whose rules and creator fee a launch matches exactly, 'custom' for
294
+ * other rules (and for a config without a custom hook), 'custom-hook' for a launch made from a
295
+ * config with a creator's own hook, null for a launch without rules and without a hook.
296
+ */
297
+ export declare function presetOf(r: LaunchRulesInput, creatorFeeBps: number, customHook?: boolean): string | null;
298
+ /** §4.9: a buy from the launch pool landing at `now` inside the early window is locked until the early unlock; null when it is not. */
299
+ export declare function buyLockedUntil(rules: Pick<LaunchRules, 'earlyWindowEndsAt' | 'earlyUnlockAt'>, now: number): number | null;
300
+ /** A launch's fee rates and the holder-fee threshold, as its pool hook reads them. */
301
+ export interface LaunchFeeParams {
302
+ creatorFeeBps: number;
303
+ holderFeeBuyBps: number;
304
+ holderFeeSellBps: number;
305
+ burnBuyBps: number;
306
+ burnSellBps: number;
307
+ /** `KitConfig.eligible` before the trade; 0 without holder rewards. */
308
+ eligible: bigint;
309
+ /** `KitConfig.min_eligible` (the supply / 1,000); 0 without holder rewards. */
310
+ minEligible: bigint;
311
+ }
312
+ /** What the launch hook takes in one callback: creator and holder fees in bridged SOL, the burn in tokens. */
313
+ export interface HookCut {
314
+ creatorFee: bigint;
315
+ holderFee: bigint;
316
+ burn: bigint;
317
+ }
318
+ /**
319
+ * The creator and holder fees from `amount` of bridged SOL (a buy's input, a sell's output): each
320
+ * rounded up, the holder fee only while `eligible >= minEligible`, and neither when together they are
321
+ * not below the amount.
322
+ */
323
+ export declare function creatorAndHolderFees(amount: bigint, creatorFeeBps: number, holderFeeBps: number, eligible: bigint, minEligible: bigint): {
324
+ creatorFee: bigint;
325
+ holderFee: bigint;
326
+ };
327
+ /** The burn from `amount` of tokens (a buy's output, a sell's input): rounded down, and none when it is not below the amount. */
328
+ export declare function tradeBurn(amount: bigint, burnBps: number): bigint;
329
+ /** The hook's `before_swap` cut from the input: a buy's creator and holder fees, a sell's burn. `p.eligible` is the count before the trade. */
330
+ export declare function launchBeforeSwap(side: Side, amountIn: bigint, p: LaunchFeeParams): HookCut;
331
+ /** The hook's `after_swap` cut from the output: a buy's burn, a sell's creator and holder fees. For a sell, `p.eligible` is the count once the input has left the seller. */
332
+ export declare function launchAfterSwap(side: Side, amountOut: bigint, p: LaunchFeeParams): HookCut;
333
+ /** A swap on a launch pool, step by step. */
334
+ export interface LaunchSwap {
335
+ /** Bridged SOL to the creator: from a buy's input, or from a sell's output after the protocol fee. */
336
+ creatorFee: bigint;
337
+ /** Bridged SOL to holders, likewise. */
338
+ holderFee: bigint;
339
+ /** Tokens burned: from a buy's output, or a sell's input. */
340
+ burn: bigint;
341
+ /** The holder-fee threshold was met when the hook took this side's fees. */
342
+ holderFeeOn: boolean;
343
+ /** What reached the input vault. */
344
+ received: bigint;
345
+ /** The LP fee, in the input token, on what reached the vault. */
346
+ lpFee: bigint;
347
+ /** Bordrless's share of the creator and holder fees (`LAUNCH_PROTOCOL_SHARE_BPS` of them, rounded up; 0 when they are 0), always in bridged SOL: on a buy from what reached the vault, before the curve; on a sell held back from the delivery. */
348
+ protocolFee: bigint;
349
+ /** What went into the curve: `received` less the LP fee (and, on a buy, the protocol fee); negative when the fees take more than arrived. */
350
+ netIn: bigint;
351
+ /** What the curve gave (on a sell, before the protocol fee and the creator and holder fees); null when the swap fails. */
352
+ amountOut: bigint | null;
353
+ /** What reaches the recipient; null when the swap fails. */
354
+ delivered: bigint | null;
355
+ /** Why the swap fails: the fees take the whole input, nothing would reach the wallet, or the pool cannot fill it; null when it lands. */
356
+ failure: 'fees_exceed_input' | 'no_output' | 'insufficient_liquidity' | null;
357
+ }
358
+ /** The constant-product output for `netIn` going into the curve, rounded down, before the check against the real reserve. */
359
+ export declare function curveOutput(r: Reserves, side: Side, netIn: bigint): bigint;
360
+ /**
361
+ * A swap on a launch pool as the v2 DEX runs it with the launch hook under the share model (§3.1,
362
+ * §5.4; the Rust reference is `bordrless_program_tests::launch::quote_launch_swap`): Bordrless
363
+ * takes `protocolShareBps` of the creator and holder fees (the hooks' cuts; the kit takes none of
364
+ * its own, so the cuts are exactly those fees), in bridged SOL, and nothing when they are nothing.
365
+ * A buy: the creator and holder fees from the input, Bordrless's share of them and the LP fee on
366
+ * what reached the vault, the curve, the burn from the output. A sell: the burn from the input, the
367
+ * LP fee on what reached the vault, the curve, then the creator and holder fees from the output and
368
+ * Bordrless's share of them held back from the delivery. A sell takes its input out of the kit's
369
+ * eligible count before `after_swap` reads it (every seller is a holder: the pool and the launch
370
+ * never sell). An ordinary pool's flat rate is `quoteSwap`.
371
+ */
372
+ export declare function quoteLaunchSwap(r: Reserves, side: Side, amountIn: bigint, lpFeeBps: number, protocolShareBps: number, p: LaunchFeeParams): LaunchSwap;
373
+ /** What a launch-pool swap adds to its input reserve (the Rust reference's `to_reserve_in`): what reached the vault, less a buy's protocol fee. */
374
+ export declare const launchSwapToReserve: (side: Side, q: Pick<LaunchSwap, "received" | "protocolFee">) => bigint;
375
+ /**
376
+ * Whether a buy that lands leaves the pool's quote reserve at or above the graduation threshold, so
377
+ * `graduate` can follow it in the same transaction (§8.2: the input after the creator and holder
378
+ * fees, less the protocol fee, joins the reserve; the launch graduates once `quote_reserve >=
379
+ * graduation_quote`).
380
+ */
381
+ export declare function buyGraduates(r: Reserves, q: LaunchSwap, graduationQuote: bigint): boolean;
382
+ /**
383
+ * §8.2 `maxAmountIn` on a curve pool: the largest buy the curve can still fill with these fees (one
384
+ * lamport more and the DEX refuses it, `InsufficientLiquidity`), found with the quote itself rather
385
+ * than by dividing out the fees, so the rounding is the programs'. Only meaningful on a curve: a pool
386
+ * without virtual reserves can always fill a buy.
387
+ */
388
+ export declare function curveMaxBuyIn(r: Reserves, lpFeeBps: number, protocolShareBps: number, p: LaunchFeeParams): bigint;
389
+ /** `1 - Π(1 - fee_i)` in basis points, rounded up so the figure never understates. */
390
+ export declare function compoundFeeBps(feesBps: readonly number[]): number;
391
+ /**
392
+ * One side's fee rates. `holderFeeBps` is 0 while nobody is eligible; `lpFeeBps` is the current LP
393
+ * fee (the sniper fee while elevated), or the base rate for a launch's standing figure. How
394
+ * Bordrless is paid follows the pool's model (§3.1): `protocolShareBps` of the creator and holder
395
+ * fees on a launch pool (the share model; `LAUNCH_PROTOCOL_SHARE_BPS`), or a flat `protocolFeeBps`
396
+ * of the quote on an ordinary pool. Either left out counts as 0.
397
+ */
398
+ export interface SideFees {
399
+ lpFeeBps: number;
400
+ creatorFeeBps: number;
401
+ holderFeeBps: number;
402
+ burnBps: number;
403
+ /** The share model: Bordrless's share of the cuts, in basis points. */
404
+ protocolShareBps?: number;
405
+ /** The flat model: a rate of the quote, in basis points. */
406
+ protocolFeeBps?: number;
407
+ }
408
+ /** What Bordrless's share comes to as a rate of the trade, in basis points (may be fractional: 150 bps of cuts at a quarter is 37.5). 0 when the rules collect nothing. */
409
+ export declare function protocolShareBps(cutsBps: number, shareBps?: number): number;
410
+ /**
411
+ * The total fee of one side as one figure (§7.3), in the order the v2 DEX charges it, rounded up to
412
+ * a basis point so the figure never understates. With `s` Bordrless's share of the cuts and `flat`
413
+ * an ordinary pool's rate (one of them 0):
414
+ * a buy `1 - (1 - (creator + holders)(1 + s))(1 - lp - flat)(1 - burn)`,
415
+ * a sell `1 - (1 - burn)(1 - lp)(1 - flat)(1 - (creator + holders)(1 + s))`.
416
+ * Plain on a launch pool (creator 1%, LP 0.3%, s = 0.25): 1 - 0.9875 · 0.997 = 1.5437%, 155 bps;
417
+ * Diamond hands (holders 1%, creator 0.5%): 1 - 0.98125 · 0.997 = 2.1694%, 217 bps a side.
418
+ */
419
+ export declare function sideFeeBps(side: Side, f: SideFees): number;
420
+ /** How far a swap's price on the curve (fees excluded) is from the spot price before it, in basis points, rounded to nearest. */
421
+ export declare function curveImpactBps(r: Reserves, side: Side, netIn: bigint, amountOut: bigint): number;
422
+ /** The max-wallet cap, fixed at launch (`bordrless_core::max_wallet_cap`): the launch supply times the bps, rounded down; 0 when off. */
423
+ export declare function maxWalletCap(supplyAtLaunch: bigint, maxWalletBps: number): bigint;
424
+ /** What a wallet holding `balance` can still receive: the kit refuses a transfer that would take it above `cap`. */
425
+ export declare function maxWalletLeft(cap: bigint, balance: bigint): bigint;
426
+ /**
427
+ * The largest buy the pool can fill whose delivery stays within `allowance` tokens; 0 when no buy
428
+ * does. Fees rounding up make the boundary ragged by a few base units, so this bisects on the exact
429
+ * quote and then looks a little past the boundary.
430
+ */
431
+ export declare function maxBuyWithin(r: Reserves, lpFeeBps: number, protocolShareBps: number, p: LaunchFeeParams, allowance: bigint): bigint;
432
+ /**
433
+ * §8.2 `devBuyMaxLamports`: the largest first buy, in lamports, whose tokens after the buy burn stay
434
+ * within max wallet at the opening reserves, with the fees of the creator's own first buy (the normal
435
+ * LP fee, the creator fee and Bordrless's share of it; no holder fee, as nobody is eligible yet).
436
+ * Null without max wallet. A bot that buys first only makes the creator receive less.
437
+ */
438
+ export declare function devBuyMaxLamports(curve: CurveParams, supply: bigint, rules: LaunchRulesInput, creatorFeeBps: number, lpFeeBps: number, protocolShareBps: number): bigint | null;
439
+ /** Scale of the reward accounting: `acc_per_share` is lamports per eligible base unit times SCALE. */
440
+ export declare const SCALE: bigint;
441
+ /** `min_eligible` is the supply / 1,000, set at init: holder fees wait until holders hold that much. */
442
+ export declare const MIN_ELIGIBLE_DIVISOR = 1000n;
443
+ export declare const minEligibleFor: (supply: bigint) => bigint;
444
+ /** `min_eligible` at the policy supply: 1,000,000 whole tokens. */
445
+ export declare const MIN_ELIGIBLE: bigint;
446
+ /** The least "Share with holders" takes: 0.001 SOL. */
447
+ export declare const MIN_SHARE_LAMPORTS = 1000000n;
448
+ /** A share streams to holders over this many seconds of eligible holding: from when it is made, or from when the share streaming then ends (§4.10, the review fixes). */
449
+ export declare const SHARE_STREAM_SECS = 3600;
450
+ /** Claims below 0.0005 SOL (about 100 times a claim's network fee) are hidden by default (§7.3). */
451
+ export declare const CLAIM_DUST_LAMPORTS = 500000n;
452
+ /**
453
+ * The reward accounting `KitConfig` keeps (§4.3, with the review fixes); times are unix seconds.
454
+ * The SDK's `kitRewardsOf` reads it from a decoded `KitConfig`.
455
+ */
456
+ export interface KitRewards {
457
+ /** Balances of every holding whose owner is not excluded (the pool and the launch are). */
458
+ eligible: bigint;
459
+ minEligible: bigint;
460
+ /** Lamports per eligible base unit, times SCALE. */
461
+ accPerShare: bigint;
462
+ /** Scaled remainder of the last division, below the eligible supply it was divided by. */
463
+ rem: bigint;
464
+ /** Lamports waiting while nobody or too little is eligible (direct donations only: the stream pauses then). */
465
+ held: bigint;
466
+ /** `reward_vault.amount + total_claimed` at the last sync, counting shares as seen when they arrive. */
467
+ seen: bigint;
468
+ /** The running stream's lamports not yet released to holders. */
469
+ streamRemaining: bigint;
470
+ /** The running stream's last release. */
471
+ streamLast: number;
472
+ /** The running stream's end. While nobody is eligible it moves on with the clock. */
473
+ streamEnd: number;
474
+ /** Lamports shared while the stream runs, waiting for it: they stream over the hour after `streamEnd`. */
475
+ streamNext: bigint;
476
+ totalDistributed: bigint;
477
+ totalClaimed: bigint;
478
+ totalShared: bigint;
479
+ /** `KitConfig.modules`: without holder rewards (bit 1) nothing is ever claimable. Absent counts as holder rewards on. */
480
+ modules?: number;
481
+ }
482
+ /** A holding's hook data under the kit (§4.4). */
483
+ export interface KitHookData {
484
+ /** `acc_per_share` at the holder's last settle. */
485
+ snapshot: bigint;
486
+ /** Rewards earned and not claimed, lamports. */
487
+ owed: bigint;
488
+ /** Tokens bought in the early window. */
489
+ earlyLocked: bigint;
490
+ }
491
+ /** 64 bytes of hook data: snapshot u128, owed u64, early_locked u64, little-endian, then 32 reserved bytes. */
492
+ export declare function decodeKitHookData(data: Uint8Array): KitHookData;
493
+ /** The inverse of decodeKitHookData, reserved bytes zero. */
494
+ export declare function encodeKitHookData(d: KitHookData): Uint8Array;
495
+ /** Whether a sync divides among holders: `eligible > 0` and `eligible >= min_eligible` (`KitConfig::divides`). */
496
+ export declare const kitDivides: (k: Pick<KitRewards, "eligible" | "minEligible">) => boolean;
497
+ /**
498
+ * What a linear stream of `amount` over `[from, to]` releases at `now`, rounded down: all of it at or
499
+ * after `to`, nothing at or before `from` (`bordrless_kit::math::stream_release`, `mirror::linear`).
500
+ */
501
+ export declare function linearRelease(amount: bigint, from: number, to: number, now: number): bigint;
502
+ /** The stream at a moment: what it releases, and what is left running and waiting after it. */
503
+ export interface KitStream {
504
+ released: bigint;
505
+ streamRemaining: bigint;
506
+ streamNext: bigint;
507
+ }
508
+ /**
509
+ * The shared stream at `now` (`bordrless_kit::mirror::stream_at`): the running stream's linear
510
+ * release; once it is out (`now >= streamEnd`), the waiting shares' release over the hour after its
511
+ * end. Nothing while holders hold less than `minEligible`. Null on an overflow.
512
+ */
513
+ export declare function streamAt(k: Pick<KitRewards, 'eligible' | 'minEligible' | 'streamRemaining' | 'streamLast' | 'streamEnd' | 'streamNext'>, now: number): KitStream | null;
514
+ /** What the shared stream releases at `now`, rounded down (`mirror::released_at`): 0 while nobody is eligible. */
515
+ export declare function streamReleased(k: Pick<KitRewards, 'eligible' | 'minEligible' | 'streamRemaining' | 'streamLast' | 'streamEnd' | 'streamNext'>, now: number): bigint | null;
516
+ /** The state a sync at `now` would leave, without writing anything (`bordrless_kit::mirror::Synced`). */
517
+ export interface KitSynced {
518
+ /** What the shared stream releases at `now`. */
519
+ released: bigint;
520
+ /** What arrived since the last sync (`vault + total_claimed - seen`), plus `released`. */
521
+ pending: bigint;
522
+ /** Whether this sync divides: holders hold at least `minEligible`, and there is something to divide. */
523
+ divides: boolean;
524
+ accPerShare: bigint;
525
+ held: bigint;
526
+ /** The running stream's lamports not yet released, after the sync. */
527
+ streamRemaining: bigint;
528
+ /** Shares waiting for the running stream, after the sync. */
529
+ streamNext: bigint;
530
+ /** `total_distributed` after the sync. */
531
+ distributed: bigint;
532
+ /** Shared lamports not yet released: `streamRemaining + streamNext` (saturating), i.e. `stream_remaining + stream_next - released`. */
533
+ streaming: bigint;
534
+ }
535
+ /** The mirror's sync at `now` with the reward vault holding `vaultAmount` (`bordrless_kit::mirror::synced`). Null when the state is impossible. */
536
+ export declare function kitSynced(k: KitRewards, vaultAmount: bigint, now: number): KitSynced | null;
537
+ /**
538
+ * The off-chain mirror (§4.13) at `now` (`bordrless_kit::mirror::claimable`): what a holder could
539
+ * claim, from `KitConfig`, the reward vault's balance, the holding's balance and its hook data, and
540
+ * what a claim would pay (no more than the vault holds). 0 for the pool and the launch (`excluded`)
541
+ * and for a token without holder rewards. Null when the kit's state cannot be synced.
542
+ */
543
+ export declare function rewardsClaimable(k: KitRewards, vaultAmount: bigint, now: number, balance: bigint, data: KitHookData, excluded?: boolean): {
544
+ claimable: bigint;
545
+ payable: bigint;
546
+ } | null;
547
+ /**
548
+ * §4.13 totals at `now`, lamports: distributed (with what the next sync would distribute), claimed,
549
+ * shared, and shared but still streaming (`rewardsStreaming`: `stream_remaining + stream_next -
550
+ * released`); also what the stream releases now and what waits in `held`. Null when the state
551
+ * cannot be synced.
552
+ */
553
+ export declare function rewardTotals(k: KitRewards, vaultAmount: bigint, now: number): {
554
+ distributed: bigint;
555
+ claimed: bigint;
556
+ shared: bigint;
557
+ streaming: bigint;
558
+ released: bigint;
559
+ held: bigint;
560
+ } | null;
561
+ /**
562
+ * `KitConfig::release` at `now`, as the program runs it: the running stream releases linearly; once
563
+ * it is out the waiting shares become the running stream over the hour after its end, and the part
564
+ * of that hour already past is released with it. While nobody is eligible nothing is released and
565
+ * the end moves on by the time that passed. Null on an overflow.
566
+ */
567
+ export declare function kitRelease(k: KitRewards, now: number): {
568
+ state: KitRewards;
569
+ released: bigint;
570
+ } | null;
571
+ /**
572
+ * The kit's sync at `now` as the program runs it (`KitConfig::sync`, §4.7 with the review fixes):
573
+ * the stream releases (`kitRelease`), then what reached the reward vault since the last sync plus
574
+ * what was released is spread over the eligible supply with the exact scaled remainder kept, or held
575
+ * while nobody or too little is eligible. Null when the vault and the claims fall short of what the
576
+ * accounting has seen, or on an overflow, which the program reverts on.
577
+ */
578
+ export declare function kitSync(k: KitRewards, vaultAmount: bigint, now: number): KitRewards | null;
579
+ /**
580
+ * `KitConfig::add_share`: a share of `received` lamports made at `now`, right after the sync at
581
+ * `now`, counted as seen and streamed over one hour at its own rate: at once when nothing streams or
582
+ * waits; joining the running stream when that stream's whole hour is still ahead; otherwise waiting
583
+ * with any shares already waiting, for the hour after the running stream. Null (the program's
584
+ * `MathOverflow`, a bug) when the stream was not synced at `now`, or on an overflow.
585
+ */
586
+ export declare function kitAddShare(k: KitRewards, received: bigint, now: number): KitRewards | null;
587
+ /**
588
+ * The kit's settle (§4.8, `bordrless_kit::math::settle`) of a holder at its balance before the
589
+ * operation: `owed += balance * (accPerShare - snapshot) / SCALE` (floor), then `snapshot =
590
+ * accPerShare`, or 0 when the balance after the operation is 0. Null when the snapshot is above the
591
+ * accumulator or on an overflow (the program's `MathOverflow`).
592
+ */
593
+ export declare function kitSettle(d: KitHookData, balance: bigint, balanceAfter: bigint, accPerShare: bigint): KitHookData | null;
594
+ /**
595
+ * The kit's `share(amount)` at `now` with the reward vault holding `vaultAmount`: refused (null) below
596
+ * MIN_SHARE_LAMPORTS, while nobody is eligible or without holder rewards; else the sync, the
597
+ * transfer into the vault (bridged SOL has no hook, so all of it arrives) and `kitAddShare`.
598
+ */
599
+ export declare function kitShare(k: KitRewards, vaultAmount: bigint, amount: bigint, now: number): {
600
+ state: KitRewards;
601
+ vault: bigint;
602
+ } | null;
603
+ /**
604
+ * The kit's `claim` at `now` by a holder with `balance` and hook data `data`: the sync, the settle at
605
+ * the balance, then `min(owed, vault)` paid. Null when the kit refuses it: the pool or the launch
606
+ * (`excluded`), no holder rewards, nothing to pay, or a state it cannot sync. The early-buyer bytes
607
+ * of the hook data are kept as they are.
608
+ */
609
+ export declare function kitClaim(k: KitRewards, vaultAmount: bigint, now: number, balance: bigint, data: KitHookData, excluded?: boolean): {
610
+ state: KitRewards;
611
+ vault: bigint;
612
+ data: KitHookData;
613
+ pay: bigint;
614
+ } | null;
615
+ /**
616
+ * When a share made at `now` starts streaming, unix seconds (§7.3's share copy, as the second round
617
+ * of review fixes words it): `now` when nothing streams or waits, or when the running stream's whole
618
+ * hour is still ahead (the share joins it); otherwise when the running stream ends, after the sync
619
+ * the share makes first. Null while nobody is eligible (the kit refuses a share then) or when the
620
+ * state cannot be synced.
621
+ */
622
+ export declare function shareStartsAt(k: KitRewards, vaultAmount: bigint, now: number): number | null;