@bordrless/shared 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -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 { RulesReadout } from './rules.ts';
6
7
  import type { WorkshopReading } from './workshop.ts';
7
8
  export type Address = string;
8
9
  /** Base units, as a decimal string. */
@@ -141,6 +142,32 @@ export interface CustomHookInfo {
141
142
  * from lists.
142
143
  */
143
144
  workshop?: HookReading | null;
145
+ /**
146
+ * A composed hook's rule set (docs/rules-lane.md §4): the hook is the rules engine and the set is
147
+ * the `RuleSet` bound to the launch's config, as the chain holds it (`RulesReadout`: its bytes and
148
+ * what they say). The one place the set travels: `workshop` beside it is the synthetic reading
149
+ * (`lane: 'rules'`, the words alone). Null for any other hook, or a set that could not be read;
150
+ * absent from older servers and from lists.
151
+ */
152
+ rules?: RulesReadout | null;
153
+ /**
154
+ * Its SOL cut (`QuoteCutInfo`), read live from the launch on a launch's own page (`LaunchDetail`):
155
+ * null when the launch takes none or could not be read; absent from older servers and from lists.
156
+ */
157
+ quoteCut?: QuoteCutInfo | null;
158
+ }
159
+ /**
160
+ * A custom hook's SOL cut (the launchpad of 13 Oct: a config made with `create_quote_cut_config`): on
161
+ * a trade the launchpad asks the hook for a rate, at most its side's cap, and takes it from the
162
+ * trade's SOL with the creator fee (a buy's SOL in, a sell's SOL out). It takes no tokens, and a send
163
+ * pays none of it.
164
+ */
165
+ export interface QuoteCutInfo {
166
+ /** The caps, basis points of the trade's SOL (each at most 1,000). */
167
+ maxBuyBps: number;
168
+ maxSellBps: number;
169
+ /** SOL the cut has taken so far, lamports (part of the creator fees); '0' for a config, which has taken nothing. */
170
+ takenLamports: Amount;
144
171
  }
145
172
  /**
146
173
  * Bordrless's own words for a custom hook or companion that came through the Workshop, wherever a
@@ -152,7 +179,10 @@ export interface CustomHookInfo {
152
179
  * `warn`: passed with notes; `fail`: only in the reading lane, where the words are shown anyway).
153
180
  * Served for an item that is approved and deployed (the Workshop lane), or matched (the reading
154
181
  * 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).
182
+ * words show while the code on chain stays the build Bordrless checked). A composed hook
183
+ * (docs/rules-lane.md §4) answers a synthetic one: `lane` and `verdict` `rules`, its words read
184
+ * from the rule set bound to the config (the set itself is `customHook.rules`), no measured cut,
185
+ * and `workshopId` '' while it is not listed.
156
186
  */
157
187
  export interface HookReading {
158
188
  workshopId: string;
@@ -162,11 +192,12 @@ export interface HookReading {
162
192
  kind: 'hook' | 'companion';
163
193
  reading: WorkshopReading | null;
164
194
  measuredCutBps: number | null;
165
- verdict: 'pass' | 'warn' | 'fail' | null;
195
+ /** `rules`: a composed hook's, read from its rules (no review, no build, no trading test). */
196
+ verdict: 'pass' | 'warn' | 'fail' | 'rules' | null;
166
197
  /** 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
198
  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';
199
+ /** `workshop`: Bordrless deployed it under its own key; `reading`: its builder deployed it, and Bordrless read the source that matches it; `rules`: composed from Bordrless rules and run by the rules engine. Absent from older servers: `workshop`. */
200
+ lane?: 'workshop' | 'reading' | 'rules';
170
201
  /** 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
202
  findings?: string[];
172
203
  }
@@ -237,9 +268,12 @@ export interface LaunchConfigData {
237
268
  creatorFeeBps: number;
238
269
  customHook: {
239
270
  program: Address;
240
- flags: number; /** As `CustomHookInfo.about`. */
271
+ flags: number;
272
+ /** As `CustomHookInfo.about`. */
241
273
  about?: HookAbout | null;
242
274
  risk?: HookRiskStatus | null;
275
+ /** As `CustomHookInfo.rules`: a composed hook's rule set, read from the `RuleSet` bound to this config; null for any other hook or an unbound one. Absent from older servers. */
276
+ rules?: RulesReadout | null;
243
277
  } | null;
244
278
  label: string;
245
279
  }
@@ -285,8 +319,9 @@ export interface ConfigInspection {
285
319
  requiredCompanion?: RequiredCompanion;
286
320
  /**
287
321
  * 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.
322
+ * (or a pair's hook) that is approved and deployed, or a composed hook's synthetic reading
323
+ * (`lane: 'rules'`; its set is `config.customHook.rules`); null for a hook deployed outside the
324
+ * Workshop, one no longer approved, or the rules engine with no set bound. Absent from older servers.
290
325
  */
291
326
  hook?: HookReading | null;
292
327
  }
@@ -691,7 +726,7 @@ export interface LaunchPrepareRequest {
691
726
  * preset splits by name; with `game`, a lottery coin (docs/games.md): the split's holders' share is
692
727
  * then 0 and the pot's part (`game.potBps`) makes the four add up to 10,000.
693
728
  */
694
- export type CompanionRequest = {
729
+ export type CompanionRequest = ({
695
730
  split: CompanionSplitBps;
696
731
  vestDays?: number;
697
732
  game?: GameRequest;
@@ -701,7 +736,35 @@ export type CompanionRequest = {
701
736
  } | {
702
737
  template: CompanionTemplate;
703
738
  vestDays?: number;
704
- };
739
+ }) & CompanionExtras;
740
+ /**
741
+ * What any companion request may add (2026-10-13, docs/payees-and-wallet-payouts.md), each set once
742
+ * before the launch, the mint signing:
743
+ * - `payees`: up to 10 wallets that share the launcher's part of the creator fee (the split's
744
+ * `beneficiaryBps`), each a fixed share of that part (1 to 10,000 basis points, 10,000 in all at
745
+ * most); the launcher keeps the rest. Not the launcher, the companion or its creator address, each
746
+ * named once. Bounds: `payeesProblem`. The setup carries `set_payees`, in its own transaction when
747
+ * the setup leaves no room (a Lossback or custom hook's setup).
748
+ * - `allowWalletPayouts`: a custom hook's script with payout terms (`script.payout`, made with
749
+ * `create_script_v2`) may also pay any wallet SOL from the pot, within those terms. Refused
750
+ * (`companion_rules`) on any other companion: `walletPayoutsProblem`.
751
+ */
752
+ export interface CompanionExtras {
753
+ payees?: PayeeRequest[];
754
+ allowWalletPayouts?: boolean;
755
+ }
756
+ /** A wallet that shares the launcher's part of the creator fee (`set_payees`): its share of that part, basis points. */
757
+ export interface PayeeRequest {
758
+ wallet: Address;
759
+ bps: number;
760
+ }
761
+ /** A payee as the token page shows it (`CompanionSummary.payees`): its share of the launcher's part, what it was paid and what it is owed (its account could not take it yet), lamports. */
762
+ export interface PayeeSummary {
763
+ wallet: Address;
764
+ bps: number;
765
+ paid: Amount;
766
+ owed: Amount;
767
+ }
705
768
  /**
706
769
  * A Lossback coin as the launch request names it (docs/loss-cover.md; the programs and the policy
707
770
  * say Loss cover): the companion's pot pays every holder under water the same share of what they
@@ -744,7 +807,7 @@ export interface LossCoverSummary {
744
807
  hookState: Address;
745
808
  script: Address;
746
809
  scriptState: Address;
747
- termsAddress: Address;
810
+ payoutTerms: Address;
748
811
  /** The pot (`Companion.pendingPot`), lamports. */
749
812
  pot: Amount;
750
813
  /** Lamports paid to holders all time, and entries recorded all time (touches included), the terms'. */
@@ -829,6 +892,20 @@ export interface ScriptRequest {
829
892
  interval: number;
830
893
  initData: string;
831
894
  stateLen: number;
895
+ /** Payout terms (2026-10-13): the script is made with `create_script_v2`, its payouts bound by them; absent, `create_script` (no payouts). Bounds: `scriptProblem`. */
896
+ payout?: PayoutTermsRequest;
897
+ }
898
+ /**
899
+ * A script's payout terms as a launch request names them (the companion's `PayoutTerms`, made by
900
+ * `create_script_v2`): the most one step pays (`stepBps` of the pot at the step's start), the most
901
+ * one holding or wallet gets of a step's budget (`holdingBps`), and the most a window pays
902
+ * (`windowBps` of the pot at the window's first step), the window `windowSecs` long (10 s to a day).
903
+ */
904
+ export interface PayoutTermsRequest {
905
+ stepBps: number;
906
+ holdingBps: number;
907
+ windowBps: number;
908
+ windowSecs: number;
832
909
  }
833
910
  /** A custom companion's script as its token page shows it (`CompanionSummary.script`), read from the chain and the Workshop. */
834
911
  export interface ScriptSummary {
@@ -874,6 +951,8 @@ export interface ScriptSummary {
874
951
  * Workshop script and from older servers.
875
952
  */
876
953
  lane?: 'workshop' | 'reading';
954
+ /** Its payout terms let it pay any wallet SOL from the pot (`allow_wallet_payouts`, `PayoutTerms.reserved[0]`, 2026-10-13); absent otherwise and from older servers. */
955
+ walletPayouts?: true;
877
956
  }
878
957
  /**
879
958
  * A Snowball companion as the launch request names it (2026-10-12): the companion's part of every
@@ -1260,6 +1339,8 @@ export interface CompanionSummary {
1260
1339
  script?: ScriptSummary | null;
1261
1340
  /** 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
1341
  lossCover?: LossCoverSummary | null;
1342
+ /** The wallets that share the launcher's part (`set_payees`, 2026-10-13); null for a companion without payees (or whose payees can't be read); absent from older servers. */
1343
+ payees?: PayeeSummary[] | null;
1263
1344
  }
1264
1345
  /**
1265
1346
  * `GET /v1/companion/:mint`: a mint's companion as a launch that may not have finished needs it.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from './api.ts';
2
2
  export * from './explorer.ts';
3
+ export * from './keeper.ts';
3
4
  export * from './policy.ts';
4
5
  export * from './programs.ts';
6
+ export * from './rules.ts';
5
7
  export * from './studio.ts';
6
8
  export * from './workshop.ts';
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from "./api.js";
2
2
  export * from "./explorer.js";
3
+ export * from "./keeper.js";
3
4
  export * from "./policy.js";
4
5
  export * from "./programs.js";
6
+ export * from "./rules.js";
5
7
  export * from "./studio.js";
6
8
  export * from "./workshop.js";
@@ -0,0 +1,139 @@
1
+ /** The file, at the root of the submitted source (beside `src/`): a companion script's, or a pair's companion half's. */
2
+ export declare const KEEPER_FILE = "keeper.json";
3
+ /** The schema's version: the only one there is. */
4
+ export declare const KEEPER_VERSION = 1;
5
+ /** The bounds a declaration is held to. */
6
+ export declare const KEEPER_LIMITS: {
7
+ /** The file's bytes (UTF-8). */
8
+ readonly bytes: 4096;
9
+ /** Holdings one step may bring (the keeper brings fewer when a step would not fit one transaction). */
10
+ readonly perStep: 16;
11
+ /** A round or an epoch, seconds: from the shortest step interval to a year. */
12
+ readonly minSecs: 10;
13
+ readonly maxSecs: 31536000;
14
+ /** The unit a hook-data field counts time in, seconds (an epoch's stamp: 300 for five minutes). */
15
+ readonly maxUnitSecs: 31536000;
16
+ /** Wallets a step may bring (about 12 fit one transaction beside the protocol's lookup table on a plain coin; the keeper brings fewer when they do not). */
17
+ readonly wallets: 12;
18
+ };
19
+ /** Bytes of an unsigned little-endian field. */
20
+ export type KeeperWidth = 1 | 2 | 4 | 8;
21
+ /** An unsigned little-endian field of the script's own state account (`PDA(["script-state", mint])` under the companion), read fresh at each step. */
22
+ export interface KeeperStateField {
23
+ offset: number;
24
+ width: KeeperWidth;
25
+ }
26
+ /** A balance or a constant in base units: a string of digits, or a field of the script's state. */
27
+ export type KeeperAmount = string | {
28
+ state: KeeperStateField;
29
+ };
30
+ /** A length of time in seconds: a whole number, or a field of the script's state. */
31
+ export type KeeperSeconds = number | {
32
+ state: KeeperStateField;
33
+ };
34
+ export type KeeperCompare = 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte';
35
+ export declare const KEEPER_COMPARES: readonly KeeperCompare[];
36
+ /**
37
+ * What a hook-data field is compared with: the pool's price now (the companion's scale, 10^12 per
38
+ * token unit, as `companionSpotPrice` reads it), a constant, or the current epoch, floor(now / secs).
39
+ * With `fieldUnitSecs`, the field counts units of that many seconds (a hook that stamps
40
+ * floor(now / 300)) and is compared in the epoch's own units: floor(field × fieldUnitSecs / secs).
41
+ */
42
+ export type KeeperAgainst = 'poolPrice' | {
43
+ const: string;
44
+ } | {
45
+ epoch: {
46
+ secs: KeeperSeconds;
47
+ fieldUnitSecs: number | null;
48
+ };
49
+ };
50
+ /** A filter on each holding's hook data: the unsigned little-endian field of `width` bytes at `offset`, compared with `against`. A holding passes when `field <compare> against` holds. */
51
+ export interface KeeperHookDataFilter {
52
+ offset: number;
53
+ width: KeeperWidth;
54
+ compare: KeeperCompare;
55
+ against: KeeperAgainst;
56
+ }
57
+ /**
58
+ * Where each holding a step brings is paid: `owner` (its owner's wallet, writable, after the
59
+ * holding), `ownerQuoteHolding` (its owner's bridged-SOL holding under the Bordrless token program,
60
+ * `holdingAddress(BRIDGED_SOL_MINT, owner)`, writable, after the holding; a holder without one is
61
+ * passed over), or `none` (the holding alone).
62
+ */
63
+ export type KeeperPayTo = 'none' | 'owner' | 'ownerQuoteHolding';
64
+ export declare const KEEPER_PAY_TO: readonly KeeperPayTo[];
65
+ export interface KeeperHoldings {
66
+ /** The least balance that counts, base units (at least 1). */
67
+ minBalance: KeeperAmount;
68
+ /** The most balance that counts, base units, inclusive; null: no most. */
69
+ maxBalance: KeeperAmount | null;
70
+ hookData: KeeperHookDataFilter | null;
71
+ payTo: KeeperPayTo;
72
+ /** Holdings a step brings when it carries the swap accounts, and when it does not (the one `swapAccounts` names is required; null: not said). */
73
+ perStep: {
74
+ withSwapAccounts: number | null;
75
+ withoutSwapAccounts: number | null;
76
+ };
77
+ }
78
+ /**
79
+ * A wallet a step brings for the script's wallet answers: a fixed address (base58), or the public key
80
+ * in the 32 bytes at `offset` of the script's state, read fresh at each step (all zeros: none that step).
81
+ */
82
+ export type KeeperWallet = string | {
83
+ state: {
84
+ offset: number;
85
+ };
86
+ };
87
+ /** A declaration in its normal form: what `parseKeeperDeclaration` answers, what the Workshop stores and hashes, what the keeper reads. */
88
+ export interface KeeperDeclaration {
89
+ version: 1;
90
+ /** Which holdings a step brings; null: none (only beside `wallets`: a script that pays wallets alone). */
91
+ holdings: KeeperHoldings | null;
92
+ /** Each step carries the launch pool's swap accounts (what trading the pot needs; they hold the token's hook accounts too). */
93
+ swapAccounts: boolean;
94
+ /** A step without the swap accounts carries the token's custom hook accounts (its program, the token program's signer for it, its registry's extras): what moving the token inside a step needs. */
95
+ hookAccounts: boolean;
96
+ /** Each step carries the companion's payout accounts (`companion.payoutAccounts`): a script whose answers the companion pays and its hook records. */
97
+ payouts: boolean;
98
+ /** The round the keeper's cursor rotates by; null: none (the cursor never starts over). */
99
+ roundSecs: KeeperSeconds | null;
100
+ /**
101
+ * The wallets each step brings (writable, with the payout terms) while the script's terms allow
102
+ * wallet payouts (`allowWalletPayouts`), at most `KEEPER_LIMITS.wallets`. Absent when none: left out
103
+ * of the normal form, so a declaration approved before wallets existed hashes as it did.
104
+ */
105
+ wallets?: KeeperWallet[];
106
+ }
107
+ export type KeeperParse = {
108
+ ok: true;
109
+ declaration: KeeperDeclaration;
110
+ } | {
111
+ ok: false;
112
+ problem: string;
113
+ };
114
+ /** Whether a text is a public key in base58: exactly 32 bytes, as `new PublicKey` reads it (each leading "1" a zero byte). */
115
+ export declare function isBase58Key(text: string): boolean;
116
+ /** The declaration in a parsed JSON value, held to the schema and its bounds: its normal form, or why not, in one sentence. */
117
+ export declare function keeperDeclarationOf(value: unknown): KeeperParse;
118
+ /** Bytes of a text in UTF-8 (a lone surrogate counts as its replacement character, 3). */
119
+ export declare function utf8Length(text: string): number;
120
+ /** A `keeper.json` as submitted: within its size, JSON, then the schema (`keeperDeclarationOf`). */
121
+ export declare function parseKeeperDeclaration(text: string): KeeperParse;
122
+ /** The declaration in a canonical text (keys sorted, no spaces): what its hash is taken of, so the same declaration hashes the same however it was written. */
123
+ export declare function canonicalKeeperJson(d: KeeperDeclaration): string;
124
+ /** Whether a file of a submission is the declaration. */
125
+ export declare const isKeeperFile: (path: string) => boolean;
126
+ /** How many holdings a step brings as declared: with the swap accounts when it carries them, else without; 0 without holdings (a script that pays wallets alone). */
127
+ export declare const keeperPerStep: (d: KeeperDeclaration) => number;
128
+ /**
129
+ * The declaration in one plain sentence, for the item's page, the reading and the operator: "Each
130
+ * step brings up to 3 holders with under 20M tokens not yet paid this 5-minute epoch, paid to their
131
+ * SOL holding." An epoch whose length the script's state sets is "this epoch". The wallets a step
132
+ * brings follow in a sentence of their own.
133
+ */
134
+ export declare function keeperWords(d: KeeperDeclaration, decimals?: number): string;
135
+ /**
136
+ * The rest of the declaration, a sentence each, for the review and the operator: what else each
137
+ * step carries, and where a round's or an epoch's length comes from.
138
+ */
139
+ export declare function keeperDetails(d: KeeperDeclaration): string[];