@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 +8 -3
- package/dist/api.d.ts +500 -2
- package/dist/api.js +0 -5
- package/dist/explorer.d.ts +21 -0
- package/dist/explorer.js +94 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/policy.d.ts +100 -27
- package/dist/policy.js +185 -34
- package/dist/studio.d.ts +63 -1
- package/dist/studio.js +1 -1
- package/dist/workshop.d.ts +352 -0
- package/dist/workshop.js +21 -0
- package/package.json +1 -1
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 (
|
|
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
|
|
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
|
-
|
|
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 {};
|