@bordrless/shared 0.8.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/README.md CHANGED
@@ -21,14 +21,19 @@ npm install @bordrless/shared
21
21
  ```ts
22
22
  import { PROGRAM_IDS, FIXED_ADDRESSES, TOKEN_HOOK_FLAGS, POOL_HOOK_FLAGS, RULE_BOUNDS } from '@bordrless/shared';
23
23
 
24
- PROGRAM_IDS.token; // the token program (devnet and localnet; mainnet gets its own keys at deploy time)
24
+ PROGRAM_IDS.token; // the token program (one set of ids on every cluster)
25
25
  TOKEN_HOOK_FLAGS.BEFORE_TRANSFER | TOKEN_HOOK_FLAGS.TRANSFER_RETURNS_DELTA;
26
26
  ```
27
27
 
28
+ A hook of your own launches from a config only when nobody outside Bordrless can upgrade it:
29
+ immutable, or held by one of `HOOK_UPGRADE_AUTHORITIES` (Bordrless Studio's key or the protocol's),
30
+ as the launch program checks. `hookFinalCommand(programId)` gives the `solana program
31
+ set-upgrade-authority --final` command that makes it immutable after deploying, and
32
+ `hookAuthorityAccepted` is the same check off chain.
33
+
28
34
  ## Where to read more
29
35
 
30
36
  - The SDK page: https://bordrless.app/sdk
31
37
  - The standard in full: https://bordrless.app/docs
32
38
 
33
- Status: the programs run on localnet and devnet until they are deployed to mainnet; they keep an
34
- upgrade authority until audited.
39
+ Status: the programs are live on mainnet; they keep an upgrade authority until audited.
package/dist/api.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  * (`Amount`), dollar figures as numbers, times as unix seconds. A figure the backend could not
4
4
  * read is null, never zero.
5
5
  */
6
+ import type { WorkshopReading } from './workshop.ts';
6
7
  export type Address = string;
7
8
  /** Base units, as a decimal string. */
8
9
  export type Amount = string;
@@ -100,6 +101,29 @@ export interface LaunchRulesInput {
100
101
  * token hook flags, and who can upgrade that program (null when it cannot be upgraded, or when it
101
102
  * has not been read). The site labels such a token "Custom hook, unverified" on every surface.
102
103
  */
104
+ /** A hook's code, upgrade authority and attestations read from the chain. checkedAt is Unix seconds. */
105
+ export interface HookRiskStatus {
106
+ status: 'available' | 'unavailable';
107
+ checkedAt: number;
108
+ class?: 'immutable' | 'timelocked' | 'managed' | 'author' | 'missing';
109
+ delaySecs?: number | null;
110
+ pending?: {
111
+ hash: string;
112
+ eta: number;
113
+ } | null;
114
+ audited?: 'current' | 'stale' | false;
115
+ blocked?: boolean;
116
+ provenance?: 'protocol' | 'studio' | 'unattested' | 'none';
117
+ studio?: {
118
+ buildHash: string;
119
+ simPass: boolean;
120
+ cutMaxBps: number;
121
+ current: boolean;
122
+ revoked?: boolean;
123
+ } | null;
124
+ severity: 'low' | 'medium' | 'high';
125
+ words: string;
126
+ }
103
127
  export interface CustomHookInfo {
104
128
  program: Address;
105
129
  flags: number;
@@ -109,6 +133,42 @@ export interface CustomHookInfo {
109
133
  upgradeable: boolean | null;
110
134
  /** What the hook does, for a hook Studio built (`HookAbout`); null (or absent) for any other, which the site describes from its flags. */
111
135
  about?: HookAbout | null;
136
+ /** Live code and attestation status, including hooks built outside Studio. */
137
+ risk?: HookRiskStatus | null;
138
+ /**
139
+ * Bordrless's own words for a Workshop hook (`HookReading`), filled on a launch's own page
140
+ * (`LaunchDetail`): null for a hook deployed outside the Workshop; absent from older servers and
141
+ * from lists.
142
+ */
143
+ workshop?: HookReading | null;
144
+ }
145
+ /**
146
+ * Bordrless's own words for a custom hook or companion that came through the Workshop, wherever a
147
+ * launcher or a buyer meets it (the owner, 2026-10-12: the site reads and puts official wording from
148
+ * Bordrless's checks, like "it takes 2% of every sell by a wallet over $1,000"): the item (its page
149
+ * is /workshop/<id>), the AI's reading of its source (what it does, the most it takes, what to
150
+ * watch), the largest cut of one transfer the trading test measured (a hook; null for a companion,
151
+ * which has no trading test) and the security review's verdict (`pass`: no finding above low;
152
+ * `warn`: passed with notes; `fail`: only in the reading lane, where the words are shown anyway).
153
+ * Served for an item that is approved and deployed (the Workshop lane), or matched (the reading
154
+ * lane, docs/workshop.md "The reading lane": the builder deployed the program themselves, and the
155
+ * words show while the code on chain stays the build Bordrless checked).
156
+ */
157
+ export interface HookReading {
158
+ workshopId: string;
159
+ name: string;
160
+ author: Address;
161
+ /** A hook on trades (a hook item, or a pair's hook half), or a companion on the creator fee (a companion item, or a pair's script half). */
162
+ kind: 'hook' | 'companion';
163
+ reading: WorkshopReading | null;
164
+ measuredCutBps: number | null;
165
+ verdict: 'pass' | 'warn' | 'fail' | null;
166
+ /** Who approved it: the checks ('auto', a clean pass) or the operator; null for items approved before that was kept, and for the reading lane (nothing is approved). */
167
+ approvedBy?: 'auto' | 'operator' | null;
168
+ /** `workshop`: Bordrless deployed it under its own key; `reading`: its builder deployed it, and Bordrless read the source that matches it. Absent from older servers: `workshop`. */
169
+ lane?: 'workshop' | 'reading';
170
+ /** With a `fail` verdict: the titles of the review's first findings (the most severe first), for the site to say what failed. Absent otherwise. */
171
+ findings?: string[];
112
172
  }
113
173
  /**
114
174
  * Bordrless's official summary of a hook Studio deployed: written once by the assistant from the
@@ -139,6 +199,7 @@ export interface HookMeasured {
139
199
  */
140
200
  export interface HookAbout {
141
201
  program: Address;
202
+ risk?: HookRiskStatus | null;
142
203
  /** The Studio project's name, as its author called it. */
143
204
  title: string;
144
205
  /** Bordrless's summary; null until it is written (the site then says what the flags allow). */
@@ -178,6 +239,7 @@ export interface LaunchConfigData {
178
239
  program: Address;
179
240
  flags: number; /** As `CustomHookInfo.about`. */
180
241
  about?: HookAbout | null;
242
+ risk?: HookRiskStatus | null;
181
243
  } | null;
182
244
  label: string;
183
245
  }
@@ -209,10 +271,49 @@ export interface ConfigInspection {
209
271
  /**
210
272
  * The hook is a game hook made in Studio (docs/games.md "Phase 2"): its kind and the constants
211
273
  * its source fixes. The config then launches a jackpot or streak coin through the companion
212
- * (`companion.game` of that kind); null or absent for any other hook.
274
+ * (`companion.game` of that kind); null or absent for any other hook, and for a Workshop pair's
275
+ * hook (its own script stands in for the game companion: `requiredCompanion`).
213
276
  */
214
277
  game?: import('./studio.ts').StudioGameSettings | null;
278
+ /**
279
+ * The companion a launch of this config must come with (the shape the on-chain `LaunchConfig`
280
+ * field will take, docs/HANDOFF-2026-10-12.md §4.5): `game` when the config's hook is a game hook
281
+ * (what `game` says), `script` when its hook belongs to a Workshop pair (docs/workshop.md
282
+ * "Pairs": the launch sends `companion.script` with that program, or is refused
283
+ * `companion_required`), else `none`. Absent from older servers.
284
+ */
285
+ requiredCompanion?: RequiredCompanion;
286
+ /**
287
+ * Bordrless's own words for the config's custom hook (`HookReading`) when it is a Workshop hook
288
+ * (or a pair's hook) that is approved and deployed; null for a hook deployed outside the
289
+ * Workshop, or one no longer approved. Absent from older servers.
290
+ */
291
+ hook?: HookReading | null;
215
292
  }
293
+ /** What a config's launch must come with: nothing in particular, a game of a kind, or a Workshop pair's script. */
294
+ export type RequiredCompanion = {
295
+ kind: 'none';
296
+ } | {
297
+ kind: 'game';
298
+ game: GameKindName;
299
+ } | {
300
+ kind: 'script';
301
+ /** The pair's companion script program: what `companion.script.program` must be (a preset's: the script its launch request names, `companion.lossCover` for Lossback). */
302
+ program: Address;
303
+ /** The pair's Workshop item (its page is /workshop/<id>), its name, its reading's title and its author. A Bordrless preset (`preset`) has no item and no author: both null. */
304
+ workshopId: string | null;
305
+ name: string;
306
+ title: string | null;
307
+ author: Address | null;
308
+ /** A Bordrless preset the config's hook belongs to: `lossCover` (docs/loss-cover.md; the site says Lossback), whose launch request is `companion.lossCover`, not `companion.script`. Absent for a pair and from older servers. */
309
+ preset?: 'lossCover';
310
+ /** Bordrless's reading of the pair (one for both halves), as `HookReading.reading`. Absent from older servers. */
311
+ reading?: WorkshopReading | null;
312
+ /** A companion script has no trading test: never a measured cut. */
313
+ measuredCutBps?: null;
314
+ /** The script half's security review verdict, as `HookReading.verdict`. Absent from older servers. */
315
+ verdict?: 'pass' | 'warn' | null;
316
+ };
216
317
  /** Live figures of a launch's token rules; each null when the launch lacks the rule or it is not tracked. */
217
318
  export interface RuleStats {
218
319
  /** Lamports distributed to holders as holder rewards, all time. */
@@ -257,6 +358,8 @@ export interface ProgramInfo {
257
358
  /** Phase 3a: present (true) when the upgrade authority is the program's own `hook_timelock` account. */
258
359
  timelocked?: boolean;
259
360
  }
361
+ /** Who a launch's creator fee goes to, read from the chain (docs/companions.md "Who may hold a launch's creator fee on the site"): a wallet, the companion program's pot, a program nobody can upgrade (shown, labelled), or a program someone can still upgrade (the launch is hidden). Null until read. */
362
+ export type CreatorKind = 'wallet' | 'companion' | 'program' | 'program-immutable';
260
363
  export interface LaunchSummary {
261
364
  mint: Address;
262
365
  name: string;
@@ -264,6 +367,8 @@ export interface LaunchSummary {
264
367
  image: string | null;
265
368
  description: string;
266
369
  creator: Address;
370
+ /** Who the creator fee goes to; absent from older servers. */
371
+ creatorKind?: CreatorKind | null;
267
372
  pool: Address;
268
373
  status: LaunchStatus;
269
374
  createdAt: number;
@@ -305,6 +410,8 @@ export interface LaunchSummary {
305
410
  config: Address | null;
306
411
  /** The creator's own token hook (§5.8); null when the mint's hook is the kit or none. */
307
412
  customHook: CustomHookInfo | null;
413
+ /** The program that is this launch's creator (docs/companions.md), as a list names it: null for a launch whose creator is a wallet; absent from an older backend. `LaunchDetail.companion` has its live figures. */
414
+ companionTag?: CompanionTag | null;
308
415
  /** How Bordrless is paid on this launch's pool: 'share' (a share of what the rules collect, `protocolShareBps`) or 'flat' (`protocolFeeBps` of the quote). */
309
416
  protocolModel: ProtocolModel;
310
417
  /** Under the share model, Bordrless's share of the cuts in basis points (2,500 = a quarter); null under the flat model. */
@@ -352,7 +459,8 @@ export interface LaunchDetail extends LaunchSummary {
352
459
  /** `GET /v1/launches?sort=`: newest first by default; `rewards24h` most paid to holders in 24 h first; `fees` lowest buy-then-sell fee first. */
353
460
  export type LaunchSort = 'new' | 'mcap' | 'volume' | 'trending' | 'graduated' | 'rewards24h' | 'fees';
354
461
  /** `GET /v1/launches?rules=a,b`: only launches that have every rule listed (`custom_hook`: launched with a creator's own hook). */
355
- export type RuleFilter = 'rewards' | 'burn' | 'max_wallet' | 'creator_lock' | 'early_lock' | 'custom_hook';
462
+ /** The board's filters: kit rules, and the pre-built hooks by name (2026-10-12: Snowball, the Jackpot draw, Half-Life, buy back & burn, the Workshop's last-buyer and streak games, Lossback as `loss_cover`). `custom_hook` stays for older links. */
463
+ export type RuleFilter = 'rewards' | 'burn' | 'max_wallet' | 'creator_lock' | 'early_lock' | 'custom_hook' | 'snowball' | 'jackpot' | 'last_buyer' | 'streak' | 'half_life' | 'buyback' | 'loss_cover';
356
464
  export interface LaunchList {
357
465
  launches: LaunchSummary[];
358
466
  total: number;
@@ -587,10 +695,238 @@ export type CompanionRequest = {
587
695
  split: CompanionSplitBps;
588
696
  vestDays?: number;
589
697
  game?: GameRequest;
698
+ snowball?: SnowballRequest;
699
+ script?: ScriptRequest;
700
+ lossCover?: LossCoverRequest;
590
701
  } | {
591
702
  template: CompanionTemplate;
592
703
  vestDays?: number;
593
704
  };
705
+ /**
706
+ * A Lossback coin as the launch request names it (docs/loss-cover.md; the programs and the policy
707
+ * say Loss cover): the companion's pot pays every holder under water the same share of what they
708
+ * are down, in rounds of `roundSecs`, once the pot holds `minPotLamports`; a holding counts from
709
+ * `minHolding` base units and gets `coverBps` of its loss covered when the pot can. The split's
710
+ * buyback and holders' parts are 0; the pot's part is what the split's launcher part leaves
711
+ * (10,000 with a launcher part of 0). Everything else (the step, the shares per step, holding and
712
+ * round, the least loss, the wait after a buy) is fixed by `LOSS_COVER_DEFAULTS`. Bounds:
713
+ * `lossCoverProblem`. Refused (`companion_rules`) beside a game, a Snowball or a script, and
714
+ * (`loss_cover_off`) while Lossback launches are closed or the creator fee has no config.
715
+ */
716
+ export interface LossCoverRequest {
717
+ roundSecs: number;
718
+ minPotLamports: Amount;
719
+ coverBps: number;
720
+ minHolding: Amount;
721
+ }
722
+ /**
723
+ * The terms a Lossback coin runs on, as the chain holds them: the script's six (`CoverState`:
724
+ * `coverBps`, `minHolding`, `minLossLamports`, `minAgeSecs`, `roundSecs`, `minPotLamports`), the
725
+ * companion's payout terms (`PayoutTerms`: `stepBps`, `holdingBps`, `roundBps` is `window_bps`,
726
+ * the window is the round) and the step (`Script.interval`).
727
+ */
728
+ export interface LossCoverTerms {
729
+ roundSecs: number;
730
+ stepSecs: number;
731
+ stepBps: number;
732
+ holdingBps: number;
733
+ roundBps: number;
734
+ coverBps: number;
735
+ minHolding: Amount;
736
+ minLossLamports: Amount;
737
+ minAgeSecs: number;
738
+ minPotLamports: Amount;
739
+ }
740
+ /** A Lossback coin's figures as its token page shows them (`CompanionSummary.lossCover`), read from the chain and the indexer's payouts. */
741
+ export interface LossCoverSummary {
742
+ /** The hook program, its state for the mint (`["state", mint]`), the script program, its state (`["script-state", mint]`) and the payout terms (`["payout-terms", mint]`). */
743
+ hook: Address;
744
+ hookState: Address;
745
+ script: Address;
746
+ scriptState: Address;
747
+ termsAddress: Address;
748
+ /** The pot (`Companion.pendingPot`), lamports. */
749
+ pot: Amount;
750
+ /** Lamports paid to holders all time, and entries recorded all time (touches included), the terms'. */
751
+ paidTotal: Amount;
752
+ payouts: number;
753
+ /** Distinct holdings paid above 0 so far (the indexer's `script_payouts`). */
754
+ holdersCovered: number;
755
+ /** The round the script last stepped in (0 before the first), and the round the clock is in now. */
756
+ round: number;
757
+ currentRound: number;
758
+ /** The share of its uncovered loss each holder is paid this round: `min(10,000, b / l_prev)` in basis points; 0 in a round that only measures. */
759
+ roundShareBps: number;
760
+ /** The round's budget (the pot at its first step), what it has paid and what is left. */
761
+ roundBudget: Amount;
762
+ roundPaid: Amount;
763
+ roundBudgetLeft: Amount;
764
+ /** The uncovered loss measured over the previous round (what this round's share is computed from) and so far this round. */
765
+ lossPrev: Amount;
766
+ lossCur: Amount;
767
+ /** Holdings measured this round, and rounds stepped so far. */
768
+ measured: number;
769
+ rounds: number;
770
+ /** When the round the script last stepped in began (0 before the first), when the current round ends, when a holder was last paid (0: never), when the next step may run. */
771
+ lastRoundAt: number;
772
+ nextRoundAt: number;
773
+ lastPaidAt: number;
774
+ nextStepAt: number;
775
+ /** Whether the pot holds the least a round starts with. */
776
+ minPotMet: boolean;
777
+ terms: LossCoverTerms;
778
+ }
779
+ /**
780
+ * `GET /v1/companion/:mint/cover/:owner`: one holder's own cover on a Lossback coin, from the
781
+ * holding's record (the hook data), the pool's price now and the script's round.
782
+ */
783
+ export interface LossCoverHoldingSummary {
784
+ owner: Address;
785
+ holding: Address;
786
+ /** Whether the owner holds the token (a holding with a record); every figure is 0 without one. */
787
+ holds: boolean;
788
+ /** Tokens held, base units; the tokens the record covers (the balance as of its last write). */
789
+ balance: Amount;
790
+ recorded: Amount;
791
+ /** The average entry price (lamports per base unit times 10^12) and in SOL per whole token; the pool's price now the same way. */
792
+ entry: Amount;
793
+ entrySolPerToken: number;
794
+ spot: Amount;
795
+ spotSolPerToken: number;
796
+ /** Lamports the holding is down (0 above water), the part the cover applies to, what it has been paid, and what it is still owed. */
797
+ loss: Amount;
798
+ covered: Amount;
799
+ paid: Amount;
800
+ owed: Amount;
801
+ /** What the current round would pay it at the round's share, lamports (0 in a measuring round, or when not eligible). */
802
+ payNow: Amount;
803
+ /** Whether a step would take it now, and why not in one sentence. */
804
+ eligible: boolean;
805
+ reason: string | null;
806
+ /** The round it was last measured or paid in (0: never), whether that is the current round, and when the holding's wait after its last buy ends. */
807
+ lastRound: number;
808
+ paidThisRound: boolean;
809
+ countsFrom: number;
810
+ /** The current round, and when it ends. */
811
+ round: number;
812
+ nextRoundAt: number;
813
+ }
814
+ /**
815
+ * A custom companion as the launch request names it (2026-10-12, docs/scripts.md): a Workshop
816
+ * script (`program`, a companion item that Bordrless approved, deployed and approved on chain)
817
+ * decides what the companion's pot does. The pot is `potBps` of every creator-fee claim (with the
818
+ * split's parts it adds up to 10,000); the companion calls the script's `companion_step` at most
819
+ * once every `interval` seconds (10 to a day), from a minute after the launch; `initData` is what
820
+ * the script's `companion_init` gets once (base64 or hex, at most 512 bytes; empty for none) and
821
+ * `stateLen` the size of the state the companion makes for it (0 to 10,240 bytes; the Workshop
822
+ * item's reading says what the script needs). Bounds: `scriptProblem`. Refused (`companion_rules`)
823
+ * beside a game or a Snowball, and (`script_not_approved`) when the program is not an approved,
824
+ * deployed Workshop companion whose on-chain approval holds.
825
+ */
826
+ export interface ScriptRequest {
827
+ potBps: number;
828
+ program: Address;
829
+ interval: number;
830
+ initData: string;
831
+ stateLen: number;
832
+ }
833
+ /** A custom companion's script as its token page shows it (`CompanionSummary.script`), read from the chain and the Workshop. */
834
+ export interface ScriptSummary {
835
+ /** Its account, `PDA(["script", mint])` under the companion program. */
836
+ address: Address;
837
+ /** The script program (a Workshop companion item's, deployed under Bordrless's key). */
838
+ program: Address;
839
+ /** Its author, paid half of what every fee claim takes from the launch; null when none (or the author launched it themselves: no extra share). */
840
+ author: Address | null;
841
+ /** The least time between steps, seconds. */
842
+ interval: number;
843
+ /** When it last stepped (unix seconds; 0: not yet). */
844
+ lastAt: number;
845
+ /** When the next step may run (a minute after the launch at the earliest). */
846
+ nextStepAt: number;
847
+ /** Steps run so far. */
848
+ steps: number;
849
+ /** SOL the script may spend (the companion's pot), lamports. */
850
+ pot: Amount;
851
+ /** The pot's part of every fee claim. */
852
+ potBps: number;
853
+ /** What the author has been paid so far, lamports. */
854
+ authorPaid: Amount;
855
+ /** The size of the script's state the companion made, bytes (0: none). */
856
+ stateLen: number;
857
+ /** The Workshop item it came from: its id (its page is /workshop/<id>), name and the AI reading's title; null for a script approved outside the Workshop. */
858
+ workshopId: string | null;
859
+ name: string | null;
860
+ title: string | null;
861
+ /**
862
+ * Whether Bordrless checked and approved the code: a Workshop script. False for an immutable
863
+ * program launched unreviewed (docs/scripts.md "Unreviewed scripts": no Workshop item, no author,
864
+ * no author's share), which the site names "Custom hook (unreviewed)". Absent from older servers.
865
+ */
866
+ reviewed?: boolean;
867
+ /** Bordrless's reading of the Workshop item it came from (`HookReading.reading`); null for a script outside the Workshop. Absent from older servers. */
868
+ reading?: WorkshopReading | null;
869
+ /** The security review's verdict of that item (`HookReading.verdict`; `fail` only in the reading lane); null for a script outside the Workshop. Absent from older servers. */
870
+ verdict?: 'pass' | 'warn' | 'fail' | null;
871
+ /**
872
+ * `reading` when the script was deployed by its builder (immutable, outside the Workshop) and a
873
+ * reading-lane item matches its code: Bordrless's words show with `reviewed` false. Absent for a
874
+ * Workshop script and from older servers.
875
+ */
876
+ lane?: 'workshop' | 'reading';
877
+ }
878
+ /**
879
+ * A Snowball companion as the launch request names it (2026-10-12): the companion's part of every
880
+ * creator fee claim (`potBps`; with the split's parts it adds up to 10,000) fills a pot that makes
881
+ * volume in the token on its own pool, once every `interval` seconds: a buy of `buyBps` of the pot
882
+ * when the price falls `buyStepBps` below its reference, a sell of `sellBps` of its tokens when it
883
+ * rises `sellStepBps` above, and with `flatTrades` a trade anyway when it hasn't moved (on the side
884
+ * that rebalances what it holds). One trade moves at most `poolBps` of the pool's SOL side. The
885
+ * presets are `SNOWBALL_PRESETS`; bounds `snowballProblem`.
886
+ */
887
+ export interface SnowballRequest {
888
+ potBps: number;
889
+ buyStepBps: number;
890
+ sellStepBps: number;
891
+ buyBps: number;
892
+ sellBps: number;
893
+ poolBps: number;
894
+ interval: number;
895
+ flatTrades: boolean;
896
+ }
897
+ /** A Snowball's terms without its part of the fee: what a preset sets and the custom controls change. */
898
+ export type SnowballTerms = Omit<SnowballRequest, 'potBps'>;
899
+ /** A Snowball's market maker as its token page shows it (`CompanionSummary.snowball`), read from the chain. */
900
+ export interface SnowballSummary {
901
+ /** Its account, `PDA(["snowball", mint])` under the companion program. */
902
+ address: Address;
903
+ buyStepBps: number;
904
+ sellStepBps: number;
905
+ buyBps: number;
906
+ sellBps: number;
907
+ /** The most one trade moves, as a share of the pool's SOL side. */
908
+ poolBps: number;
909
+ /** The least time between trades, seconds. */
910
+ interval: number;
911
+ /** It trades every interval even when the price hasn't moved. */
912
+ flatTrades: boolean;
913
+ /** SOL it holds to buy with (the companion's pot), lamports. */
914
+ pot: Amount;
915
+ /** Tokens it holds to sell, base units. */
916
+ tokensHeld: Amount;
917
+ /** The next buy waits for the price at or below `buyBelow`, the next sell at or above `sellAbove` (SOL per whole token). */
918
+ buyBelow: number;
919
+ sellAbove: number;
920
+ buys: number;
921
+ sells: number;
922
+ /** SOL spent on buys and received from sells, lamports; tokens bought and sold, base units. */
923
+ solSpent: Amount;
924
+ solReceived: Amount;
925
+ tokensBought: Amount;
926
+ tokensSold: Amount;
927
+ /** When it last traded or followed the price (unix seconds; 0: not yet). */
928
+ lastAt: number;
929
+ }
594
930
  /** The kinds of game a companion runs (the companion's `GameKind`): the lottery (phase 1), the last-buyer jackpot and the holding streak (phase 2). */
595
931
  export type GameKindName = 'lottery' | 'jackpot' | 'streak' | 'strategy';
596
932
  /**
@@ -864,6 +1200,24 @@ export interface CompanionSplitBps {
864
1200
  /** Paid to the launcher (the beneficiary), in SOL. */
865
1201
  beneficiaryBps: number;
866
1202
  }
1203
+ /**
1204
+ * A launch's companion as a list names it (2026-10-12): what takes its creator fee, fixed at launch, without
1205
+ * the live figures (`CompanionSummary` has those), so a card can say "Snowball 2%" without reading the chain.
1206
+ */
1207
+ export interface CompanionTag {
1208
+ split: CompanionSplitBps;
1209
+ /** The game it runs and the pot's part of every fee claim; null without a game. */
1210
+ game: {
1211
+ kind: GameKindName;
1212
+ potBps: number;
1213
+ } | null;
1214
+ /** A Snowball: its pot makes a market in the token (its part of the fee is what the split leaves). */
1215
+ snowball: boolean;
1216
+ /** A custom companion (2026-10-12): a Workshop script spends its pot. Absent from tags stored before scripts. */
1217
+ script?: boolean;
1218
+ /** A Lossback coin (docs/loss-cover.md): its script is the Loss cover script. Absent from tags stored before Lossback, and from every other tag. */
1219
+ lossCover?: boolean;
1220
+ }
867
1221
  /** A launch's companion as its token page shows it (`LaunchDetail.companion`): lamports and token base units as strings. */
868
1222
  export interface CompanionSummary {
869
1223
  /** The companion's account, `PDA(["companion", mint])` under the companion program. */
@@ -900,6 +1254,12 @@ export interface CompanionSummary {
900
1254
  nextBuybackAt: number | null;
901
1255
  /** The lottery this companion runs (docs/games.md): its settings and the hook's terms; null for a companion without a game. */
902
1256
  game: GameSummary | null;
1257
+ /** A Snowball's market maker (2026-10-12); null for any other companion. */
1258
+ snowball: SnowballSummary | null;
1259
+ /** A custom companion's script (2026-10-12, docs/scripts.md); null for any other companion; absent from older servers. */
1260
+ script?: ScriptSummary | null;
1261
+ /** A Lossback coin's figures (docs/loss-cover.md); null for any other companion (a Lossback coin's `script` is set too); absent from older servers. */
1262
+ lossCover?: LossCoverSummary | null;
903
1263
  }
904
1264
  /**
905
1265
  * `GET /v1/companion/:mint`: a mint's companion as a launch that may not have finished needs it.
@@ -915,6 +1275,10 @@ export interface CompanionStatus {
915
1275
  refundable: Amount | null;
916
1276
  /** 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). */
917
1277
  game?: GameStatus | null;
1278
+ /** A custom companion's script, once launched (docs/scripts.md); null for any other companion (absent from older servers, and before the launch). */
1279
+ script?: ScriptSummary | null;
1280
+ /** A Lossback coin's figures, once launched (docs/loss-cover.md); null for any other companion (absent from older servers, and before the launch). */
1281
+ lossCover?: LossCoverSummary | null;
918
1282
  }
919
1283
  /** `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. */
920
1284
  export interface CompanionRefundRequest {
@@ -1135,6 +1499,140 @@ export interface LiquidityPrepareResponse {
1135
1499
  transactions: PreparedTx[];
1136
1500
  quote: LiquidityQuote;
1137
1501
  }
1502
+ /** Which of a mint's four authorities (`set_authority`'s kinds). */
1503
+ export type MintAuthorityKind = 'mint' | 'freeze' | 'hook' | 'metadata';
1504
+ /** One fact of a mint's risk label (docs/dex.md §6.2), in the words every surface uses. */
1505
+ export interface MintRiskReason {
1506
+ kind: 'hook_missing' | 'hook_authority' | 'freeze_authority' | 'mint_authority' | 'hook' | 'metadata_authority' | 'fixed';
1507
+ severity: 'low' | 'medium' | 'high';
1508
+ words: string;
1509
+ }
1510
+ /** A mint's risk label: the highest severity, its first sentence, every reason, and the authorities still held (and by whom). */
1511
+ export interface MintRisk {
1512
+ severity: 'low' | 'medium' | 'high';
1513
+ words: string;
1514
+ reasons: MintRiskReason[];
1515
+ /** The authorities still set on the mint, each with its key. */
1516
+ held: {
1517
+ kind: MintAuthorityKind;
1518
+ authority: Address;
1519
+ }[];
1520
+ }
1521
+ /** The base token of a pool to be created, as the mint account has it. */
1522
+ export interface PoolCreateToken {
1523
+ mint: Address;
1524
+ symbol: string;
1525
+ name: string;
1526
+ decimals: number;
1527
+ image: string | null;
1528
+ supply: Amount;
1529
+ /** 0 when unlimited. */
1530
+ maxSupply: Amount;
1531
+ creator: Address;
1532
+ hookProgram: Address | null;
1533
+ /** How the site names it (from addresses, never from names): a launch of the launchpad, a bridged asset, or a free mint. */
1534
+ identity: 'launch' | 'bridged' | 'free';
1535
+ }
1536
+ /** A pool of the same pair that exists already: the depth, the price and the tier. */
1537
+ export interface ExistingPool {
1538
+ pool: Address;
1539
+ lpFeeBps: number;
1540
+ hookProgram: Address | null;
1541
+ /** The launchpad made it: its launch pool. */
1542
+ launch: boolean;
1543
+ curve: boolean;
1544
+ baseReserve: Amount;
1545
+ quoteReserve: Amount;
1546
+ /** Whole quote per whole token; null while the pool has no reserves. */
1547
+ priceQuote: number | null;
1548
+ tvlUsd: number | null;
1549
+ }
1550
+ export interface PoolCreateQuoteRequest {
1551
+ baseMint: Address;
1552
+ /** One of `POOL_FEE_TIERS_BPS`. */
1553
+ lpFeeBps: number;
1554
+ /** The wallet, for its balances; the quote stands without one. */
1555
+ owner?: Address;
1556
+ /** Base units of the token to deposit. */
1557
+ baseAmount?: Amount;
1558
+ /** Lamports of SOL (bridged in the same transaction) to deposit. */
1559
+ quoteAmount?: Amount;
1560
+ }
1561
+ /** The first deposit as quoted: the price it sets, the LP it mints and the FDV it implies. */
1562
+ export interface PoolCreateDeposit {
1563
+ baseAmount: Amount;
1564
+ quoteAmount: Amount;
1565
+ /** `isqrt(base · quote) − 1,000`, 9 decimals. */
1566
+ lpAmount: Amount;
1567
+ /** Whole SOL per whole token. */
1568
+ priceQuote: number;
1569
+ /** Fully diluted value in lamports (the price times `maxSupply`, or `supply` when unlimited), as a decimal string. */
1570
+ fdvLamports: Amount;
1571
+ fdvUsd: number | null;
1572
+ }
1573
+ export interface PoolCreateQuote {
1574
+ token: PoolCreateToken;
1575
+ quoteMint: Address;
1576
+ quoteSymbol: string;
1577
+ quoteDecimals: number;
1578
+ lpFeeBps: number;
1579
+ /** The DEX config's flat protocol rate of the quote side, which the new pool copies at creation. */
1580
+ protocolFeeBps: number;
1581
+ /** The pool this pair, tier and no hook would live at. */
1582
+ pool: Address;
1583
+ lpMint: Address;
1584
+ /** That pool, when it exists already (the form then offers to add liquidity instead). */
1585
+ exists: ExistingPool | null;
1586
+ /** Every other pool of the pair (the launch pool, other tiers, hooked ones), deepest first. */
1587
+ otherPools: ExistingPool[];
1588
+ /** The wallet's balances, with an owner. */
1589
+ balances: {
1590
+ lamports: Amount;
1591
+ base: Amount;
1592
+ bridgedSol: Amount;
1593
+ } | null;
1594
+ deposit: PoolCreateDeposit | null;
1595
+ risk: MintRisk;
1596
+ /** Rent the creator pays for the new accounts (the pool, the LP mint, two vaults, the LP holding, and the quote holding when missing). */
1597
+ rentLamports: Amount;
1598
+ solUsd: number | null;
1599
+ }
1600
+ export interface PoolCreatePrepareRequest {
1601
+ owner: Address;
1602
+ baseMint: Address;
1603
+ lpFeeBps: number;
1604
+ baseAmount: Amount;
1605
+ quoteAmount: Amount;
1606
+ /** Burn the LP in a second transaction, a permanent lock (docs/dex.md §5.1). */
1607
+ burnLp?: boolean;
1608
+ }
1609
+ export interface PoolCreatePrepareResponse {
1610
+ transactions: PreparedTx[];
1611
+ quote: PoolCreateQuote;
1612
+ pool: Address;
1613
+ lpMint: Address;
1614
+ }
1615
+ /** Burn LP of a pool the wallet holds: all of it, or `amount` (9 decimals). */
1616
+ export interface LpBurnPrepareRequest {
1617
+ owner: Address;
1618
+ pool: Address;
1619
+ amount?: Amount;
1620
+ }
1621
+ export interface LpBurnPrepareResponse {
1622
+ transactions: PreparedTx[];
1623
+ /** LP burned, 9 decimals. */
1624
+ amount: Amount;
1625
+ }
1626
+ /** Revoke authorities the wallet holds on a mint, for ever (`set_authority(kind, None)` for each). */
1627
+ export interface AuthorityPrepareRequest {
1628
+ owner: Address;
1629
+ mint: Address;
1630
+ kinds: MintAuthorityKind[];
1631
+ }
1632
+ export interface AuthorityPrepareResponse {
1633
+ transactions: PreparedTx[];
1634
+ kinds: MintAuthorityKind[];
1635
+ }
1138
1636
  export interface ApiErrorBody {
1139
1637
  error: string;
1140
1638
  code?: string;
package/dist/api.js CHANGED
@@ -1,8 +1,3 @@
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. */
@@ -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 {};