@bordrless/shared 0.8.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.
@@ -34,6 +34,22 @@ export declare const PROGRAM_IDS: {
34
34
  * permissionless crank under the companion's buyback guards. Not deployed yet (2026-10-09).
35
35
  */
36
36
  readonly hookVault: "5cojoUStG7WFhHJiSncCUEwTqDuhDLKu4a9BqTbF8jzG";
37
+ /**
38
+ * The Loss cover hook (programs/loss_cover_hook, docs/loss-cover.md §2; the site says Lossback):
39
+ * a Lossback coin's token hook, which keeps each holding's average entry price, the cover it was
40
+ * paid and the round it was last recorded in. Keypair generated 2026-10-12.
41
+ */
42
+ readonly lossCoverHook: "6KMdXC3Fxovp3pnUsdQuUbderPzZtTA4t6R1jacYJWQr";
43
+ /**
44
+ * The Loss cover script (programs/loss_cover_script, docs/loss-cover.md §3): the companion script
45
+ * of a Lossback coin, which names the holders under water and what each gets; the companion pays.
46
+ */
47
+ readonly lossCoverScript: "9mRXU9gpWY3B13AyuCCtNjHnKt1pUFBQ6vJDLTwgakhm";
48
+ /**
49
+ * The router (programs/bordrless_router, docs/router.md, 2026-10-13): an app's integrator fee on
50
+ * any DEX swap, at most 1% of the quote side, 20% of it to the DEX treasury.
51
+ */
52
+ readonly router: "7M5GTuzhByzBbrJURzLtbBrFjcsC8aHu816qWTXAYD85";
37
53
  };
38
54
  /**
39
55
  * Bordrless Studio's attester (phase 3a, docs/phase3a.md §6): a hot key of Studio's build worker,
@@ -64,6 +80,67 @@ export declare const LOTTERY_HOOK: {
64
80
  };
65
81
  /** The creator fees (basis points) a lottery coin can launch with: those with a `LaunchConfig` in `LOTTERY_HOOK.launchConfigs`. */
66
82
  export declare const lotteryFeeChoices: () => number[];
83
+ /**
84
+ * The Loss cover hook's fixed facts (programs/loss_cover_hook, docs/loss-cover.md §2; the site
85
+ * says Lossback): the flags a `LaunchConfig` names for it (`BEFORE_TRANSFER | BEFORE_BURN |
86
+ * WRITES_HOOK_DATA`, the lottery hook's), the token program's signer of its callbacks
87
+ * (`["hook-authority", hook]` under the token program), its own `["hook-authority"]` (which signs
88
+ * the token program's `write_hook_data` in `record_payout`) with its bump, and the `LaunchConfig`s
89
+ * a Lossback coin launches from, one per creator fee, made by `pnpm admin loss-cover-configs`
90
+ * (which prints the lines to paste here); the backend lays
91
+ * `LOSS_COVER_LAUNCH_CONFIGS` over it.
92
+ */
93
+ export declare const LOSS_COVER_HOOK: {
94
+ readonly program: "6KMdXC3Fxovp3pnUsdQuUbderPzZtTA4t6R1jacYJWQr";
95
+ readonly flags: 145;
96
+ readonly tokenHookSigner: "A2WKjdKC4PurtabNwhvKJvWdxKXLvt79qrzre7GE8XTe";
97
+ readonly hookAuthority: "J7duBVXCMbN1BLp4mt7myzVvRsvXRPU3BAhFyksDSPAm";
98
+ readonly hookAuthorityBump: 252;
99
+ readonly readme: "https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/loss_cover_hook";
100
+ readonly launchConfigs: Readonly<Partial<Record<number, string>>>;
101
+ };
102
+ /**
103
+ * The rules engine's program id (`programs/rules_hook`, its keypair `keys/mainnet/rules_hook-keypair.json`):
104
+ * BUILT, NOT DEPLOYED YET (2026-10-12). The SDK builds `bind` and `prepare` for it; the lane opens
105
+ * only when `RULES_HOOK_PROGRAM` below is set to it, after the deploy lands.
106
+ */
107
+ export declare const RULES_HOOK_PROGRAM_ID_MAINNET = "AfDhsethmkoimbyoSWnRfLtjFXZteRNtbFMioR9qWMjD";
108
+ /**
109
+ * The rules engine (`programs/rules_hook`, docs/rules-lane.md): Bordrless's one token hook that
110
+ * runs a composed rule set bound to a launch config (`RuleSet` at `["rules", config]` under it).
111
+ * The lane's switch: a placeholder, the system program's id, until the engine is deployed, so
112
+ * nothing can name it as a hook (the launch program refuses the protocol's own programs), every
113
+ * check that compares a hook with it is false and the API answers `rules_closed`. Set to
114
+ * `RULES_HOOK_PROGRAM_ID_MAINNET` once the deploy lands; `RULES_HOOK.flags` are per rule set
115
+ * (`rulesFlagsOf`), never fixed.
116
+ */
117
+ export declare const RULES_HOOK_PROGRAM: string;
118
+ /** The engine's fixed facts, as the other hooks have them; `deployed` tells the site and the API whether the lane is live on chain (false while the id is the placeholder, the system program's). */
119
+ export declare const RULES_HOOK: {
120
+ readonly program: string;
121
+ readonly deployed: boolean;
122
+ /** `RuleSet` seed under the engine, with the launch config. */
123
+ readonly ruleSetSeed: "rules";
124
+ /** The per-mint state seed, the template's. */
125
+ readonly stateSeed: "state";
126
+ /** The engine's id once deployed (`RULES_HOOK_PROGRAM_ID_MAINNET`), and its PDAs: the token program's signer of its callbacks, and its `["hook-authority"]` (signs `write_hook_data` in `record_payout`). */
127
+ readonly programId: "AfDhsethmkoimbyoSWnRfLtjFXZteRNtbFMioR9qWMjD";
128
+ readonly tokenHookSigner: "FaU6drNBY2nayBkXiirtk5c29Hw3rqXMtv2K1La5V4cG";
129
+ readonly hookAuthority: "9SydDjwfgWaG8akwwsEpTpRpdoVZCtMYSeiqf6EkMdkK";
130
+ readonly hookAuthorityBump: 254;
131
+ /** The accounts' sizes: the `RuleSet` and the per-mint state. */
132
+ readonly ruleSetLen: 447;
133
+ readonly stateLen: 628;
134
+ readonly readme: "https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/rules_hook";
135
+ };
136
+ /** The Loss cover script's fixed facts (programs/loss_cover_script, docs/loss-cover.md §3): its program and the size of the state `create_script_v2` must ask for. */
137
+ export declare const LOSS_COVER_SCRIPT: {
138
+ readonly program: "9mRXU9gpWY3B13AyuCCtNjHnKt1pUFBQ6vJDLTwgakhm";
139
+ readonly stateLen: 128;
140
+ readonly readme: "https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/loss_cover_script";
141
+ };
142
+ /** The creator fees (basis points) a Lossback coin can launch with: those with a `LaunchConfig` in `LOSS_COVER_HOOK.launchConfigs` (the backend's env adds to them). */
143
+ export declare const lossCoverFeeChoices: () => number[];
67
144
  /**
68
145
  * Half-Life, Bordrless's own token hook (programs/half_life/README.md): the `LaunchConfig` the
69
146
  * launch form's Half-Life path launches from (no kit rules, creator fee 1%, the hook with
@@ -160,6 +237,8 @@ export declare const FIXED_ADDRESSES: {
160
237
  readonly kitHookAuthority: "2repKA1JgDkBo4AffscVee342dcBcH6c2yfpUTRrAiEN";
161
238
  /** `["__event_authority"]` under the companion program. */
162
239
  readonly companionEventAuthority: "7QuoYRuD9MHzX5EN7qqj62iwNPVqfy74RzmwJ524cgDt";
240
+ /** `["payout-authority"]` under the companion program (bump 251): the one signer of a hook's `record_payout` (docs/loss-cover.md §1); it signs nothing else. */
241
+ readonly companionPayoutAuthority: "8XJcBCYmYyggTQBNvK3RausfyRMpmtjJTjKd53W3StkG";
163
242
  };
164
243
  /**
165
244
  * The protocol lookup table (docs/hooks-v2.md §6; programs-summary §2.7): the 22 fixed addresses
package/dist/programs.js CHANGED
@@ -34,6 +34,22 @@ export const PROGRAM_IDS = {
34
34
  * permissionless crank under the companion's buyback guards. Not deployed yet (2026-10-09).
35
35
  */
36
36
  hookVault: '5cojoUStG7WFhHJiSncCUEwTqDuhDLKu4a9BqTbF8jzG',
37
+ /**
38
+ * The Loss cover hook (programs/loss_cover_hook, docs/loss-cover.md §2; the site says Lossback):
39
+ * a Lossback coin's token hook, which keeps each holding's average entry price, the cover it was
40
+ * paid and the round it was last recorded in. Keypair generated 2026-10-12.
41
+ */
42
+ lossCoverHook: '6KMdXC3Fxovp3pnUsdQuUbderPzZtTA4t6R1jacYJWQr',
43
+ /**
44
+ * The Loss cover script (programs/loss_cover_script, docs/loss-cover.md §3): the companion script
45
+ * of a Lossback coin, which names the holders under water and what each gets; the companion pays.
46
+ */
47
+ lossCoverScript: '9mRXU9gpWY3B13AyuCCtNjHnKt1pUFBQ6vJDLTwgakhm',
48
+ /**
49
+ * The router (programs/bordrless_router, docs/router.md, 2026-10-13): an app's integrator fee on
50
+ * any DEX swap, at most 1% of the quote side, 20% of it to the DEX treasury.
51
+ */
52
+ router: '7M5GTuzhByzBbrJURzLtbBrFjcsC8aHu816qWTXAYD85',
37
53
  };
38
54
  /**
39
55
  * Bordrless Studio's attester (phase 3a, docs/phase3a.md §6): a hot key of Studio's build worker,
@@ -68,6 +84,72 @@ export const LOTTERY_HOOK = {
68
84
  };
69
85
  /** The creator fees (basis points) a lottery coin can launch with: those with a `LaunchConfig` in `LOTTERY_HOOK.launchConfigs`. */
70
86
  export const lotteryFeeChoices = () => Object.keys(LOTTERY_HOOK.launchConfigs).map(Number).filter((bps) => bps > 0);
87
+ /**
88
+ * The Loss cover hook's fixed facts (programs/loss_cover_hook, docs/loss-cover.md §2; the site
89
+ * says Lossback): the flags a `LaunchConfig` names for it (`BEFORE_TRANSFER | BEFORE_BURN |
90
+ * WRITES_HOOK_DATA`, the lottery hook's), the token program's signer of its callbacks
91
+ * (`["hook-authority", hook]` under the token program), its own `["hook-authority"]` (which signs
92
+ * the token program's `write_hook_data` in `record_payout`) with its bump, and the `LaunchConfig`s
93
+ * a Lossback coin launches from, one per creator fee, made by `pnpm admin loss-cover-configs`
94
+ * (which prints the lines to paste here); the backend lays
95
+ * `LOSS_COVER_LAUNCH_CONFIGS` over it.
96
+ */
97
+ export const LOSS_COVER_HOOK = {
98
+ program: PROGRAM_IDS.lossCoverHook,
99
+ flags: 145,
100
+ tokenHookSigner: 'A2WKjdKC4PurtabNwhvKJvWdxKXLvt79qrzre7GE8XTe',
101
+ hookAuthority: 'J7duBVXCMbN1BLp4mt7myzVvRsvXRPU3BAhFyksDSPAm',
102
+ hookAuthorityBump: 252,
103
+ readme: 'https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/loss_cover_hook',
104
+ // Made 2026-10-12 22:26 UTC by `pnpm admin loss-cover-configs --send` (5xsib), no token rules, the Loss cover hook with flags 145.
105
+ launchConfigs: {
106
+ 50: 'DCNLF3jvZvo6SMTa9dG8y2E7CgB7VZr2C5tQrs83HR84',
107
+ 100: '8E1UWZ8PXYrWvfBNRxVSzceR4ywLmHQYAXvWZ4JkUhQZ',
108
+ 200: '8PLEsXW4hbEfYXgtRWxZhe7nTvjeYR1XdY5ehKj8z3Xr',
109
+ },
110
+ };
111
+ /**
112
+ * The rules engine's program id (`programs/rules_hook`, its keypair `keys/mainnet/rules_hook-keypair.json`):
113
+ * BUILT, NOT DEPLOYED YET (2026-10-12). The SDK builds `bind` and `prepare` for it; the lane opens
114
+ * only when `RULES_HOOK_PROGRAM` below is set to it, after the deploy lands.
115
+ */
116
+ export const RULES_HOOK_PROGRAM_ID_MAINNET = 'AfDhsethmkoimbyoSWnRfLtjFXZteRNtbFMioR9qWMjD';
117
+ /**
118
+ * The rules engine (`programs/rules_hook`, docs/rules-lane.md): Bordrless's one token hook that
119
+ * runs a composed rule set bound to a launch config (`RuleSet` at `["rules", config]` under it).
120
+ * The lane's switch: a placeholder, the system program's id, until the engine is deployed, so
121
+ * nothing can name it as a hook (the launch program refuses the protocol's own programs), every
122
+ * check that compares a hook with it is false and the API answers `rules_closed`. Set to
123
+ * `RULES_HOOK_PROGRAM_ID_MAINNET` once the deploy lands; `RULES_HOOK.flags` are per rule set
124
+ * (`rulesFlagsOf`), never fixed.
125
+ */
126
+ export const RULES_HOOK_PROGRAM = RULES_HOOK_PROGRAM_ID_MAINNET;
127
+ /** The engine's fixed facts, as the other hooks have them; `deployed` tells the site and the API whether the lane is live on chain (false while the id is the placeholder, the system program's). */
128
+ export const RULES_HOOK = {
129
+ program: RULES_HOOK_PROGRAM,
130
+ deployed: RULES_HOOK_PROGRAM !== '11111111111111111111111111111111',
131
+ /** `RuleSet` seed under the engine, with the launch config. */
132
+ ruleSetSeed: 'rules',
133
+ /** The per-mint state seed, the template's. */
134
+ stateSeed: 'state',
135
+ /** The engine's id once deployed (`RULES_HOOK_PROGRAM_ID_MAINNET`), and its PDAs: the token program's signer of its callbacks, and its `["hook-authority"]` (signs `write_hook_data` in `record_payout`). */
136
+ programId: RULES_HOOK_PROGRAM_ID_MAINNET,
137
+ tokenHookSigner: 'FaU6drNBY2nayBkXiirtk5c29Hw3rqXMtv2K1La5V4cG',
138
+ hookAuthority: '9SydDjwfgWaG8akwwsEpTpRpdoVZCtMYSeiqf6EkMdkK',
139
+ hookAuthorityBump: 254,
140
+ /** The accounts' sizes: the `RuleSet` and the per-mint state. */
141
+ ruleSetLen: 447,
142
+ stateLen: 628,
143
+ readme: 'https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/rules_hook',
144
+ };
145
+ /** The Loss cover script's fixed facts (programs/loss_cover_script, docs/loss-cover.md §3): its program and the size of the state `create_script_v2` must ask for. */
146
+ export const LOSS_COVER_SCRIPT = {
147
+ program: PROGRAM_IDS.lossCoverScript,
148
+ stateLen: 128,
149
+ readme: 'https://github.com/BordrlessDex/bordrless-programs/tree/main/programs/loss_cover_script',
150
+ };
151
+ /** The creator fees (basis points) a Lossback coin can launch with: those with a `LaunchConfig` in `LOSS_COVER_HOOK.launchConfigs` (the backend's env adds to them). */
152
+ export const lossCoverFeeChoices = () => Object.keys(LOSS_COVER_HOOK.launchConfigs).map(Number).filter((bps) => bps > 0);
71
153
  /**
72
154
  * Half-Life, Bordrless's own token hook (programs/half_life/README.md): the `LaunchConfig` the
73
155
  * launch form's Half-Life path launches from (no kit rules, creator fee 1%, the hook with
@@ -176,6 +258,8 @@ export const FIXED_ADDRESSES = {
176
258
  kitHookAuthority: '2repKA1JgDkBo4AffscVee342dcBcH6c2yfpUTRrAiEN',
177
259
  /** `["__event_authority"]` under the companion program. */
178
260
  companionEventAuthority: '7QuoYRuD9MHzX5EN7qqj62iwNPVqfy74RzmwJ524cgDt',
261
+ /** `["payout-authority"]` under the companion program (bump 251): the one signer of a hook's `record_payout` (docs/loss-cover.md §1); it signs nothing else. */
262
+ companionPayoutAuthority: '8XJcBCYmYyggTQBNvK3RausfyRMpmtjJTjKd53W3StkG',
179
263
  };
180
264
  /**
181
265
  * The protocol lookup table (docs/hooks-v2.md §6; programs-summary §2.7): the 22 fixed addresses
@@ -0,0 +1,353 @@
1
+ /**
2
+ * The rules lane (docs/rules-lane.md): a custom hook composed as data and run by Bordrless's one
3
+ * rules engine (`rules_hook`). A rule set is a header and 1 to 6 rules of 48 bytes, little-endian,
4
+ * every field fixed-width (§1). This module is the lane's one reading of the bytes, shared by the
5
+ * SDK, the site, the API and the engine's own tests (`vectors/rules.json`):
6
+ *
7
+ * - the types and the enums as the doc numbers them (`RULE_VALUE_IDS`, `RULE_OP_IDS`, ...);
8
+ * - `encodeRules` / `decodeRules`, the exact byte layout of §1.2;
9
+ * - `validateRules`, every bound of §1 and §2.6 as a code and a plain sentence: the same codes the
10
+ * engine's `bind` refuses with (`RULES_ERROR_TEXT` lists them);
11
+ * - `renderRules`, the pure reading of §3: the sentences, "the most it takes" per side (summed from
12
+ * the rules, never measured), the flags and the generated watch lines;
13
+ * - `rulesFlagsOf`, the token hook flags a set needs; `rulesHookReading`, the synthetic reading in
14
+ * the shape of `HookReading` (`lane: 'rules'`, `verdict: 'rules'`) every surface already shows.
15
+ *
16
+ * Wording follows the site's: numbers only, the site's units, no reassurance. Nothing here touches
17
+ * a chain: the SDK builds the instructions, the API reads the accounts.
18
+ */
19
+ import type { HookReading } from './api.ts';
20
+ import type { WorkshopReading } from './workshop.ts';
21
+ export declare const RULES_VERSION = 1;
22
+ /** The header, then each rule, then each atom slot (§1.2). */
23
+ export declare const RULES_HEADER_BYTES = 8;
24
+ export declare const RULE_BYTES = 48;
25
+ export declare const ATOM_BYTES = 10;
26
+ export declare const RULE_ATOM_SLOTS = 4;
27
+ export declare const RULES_LIMITS: {
28
+ /** Rules in a set. */
29
+ readonly rules: 6;
30
+ /** `when` atoms a rule may have; `unless` atoms. */
31
+ readonly when: 3;
32
+ readonly unless: 1;
33
+ /** A cut, basis points of the amount; the cuts of one side summed. */
34
+ readonly cutBps: 1500;
35
+ readonly sideCutBps: 1500;
36
+ /** `entry_cap_bps` (§1.2): checked by `bind`, applied nowhere (a buy's entry is what it paid). */
37
+ readonly entryCapBps: 5000;
38
+ /** A set's bytes: `8 + 48 * 6`. */
39
+ readonly bytes: 296;
40
+ /** Composed hooks one wallet may list in a day (the Workshop's allowance). */
41
+ readonly perDay: 6;
42
+ /** Literals, by unit (§1.2). A price is any u64. */
43
+ readonly literal: {
44
+ readonly bps: 10000n;
45
+ readonly seconds: 31536000n;
46
+ readonly lamports: 10000000000000n;
47
+ readonly baseUnits: bigint;
48
+ readonly count: 65535n;
49
+ readonly flag: 1n;
50
+ readonly price: bigint;
51
+ };
52
+ };
53
+ export type RuleSide = 'sell' | 'buy' | 'send' | 'receive' | 'burn';
54
+ export declare const RULE_SIDES: readonly RuleSide[];
55
+ /** `on`'s bits. */
56
+ export declare const RULE_SIDE_BITS: Record<RuleSide, number>;
57
+ export type RuleValueName = 'amount' | 'amountShare' | 'balanceBefore' | 'balanceAfter' | 'shareAfter' | 'tradePrice' | 'spotPrice' | 'gain' | 'loss' | 'valueBefore' | 'valueAfter' | 'sinceReceived' | 'sinceSent' | 'age' | 'firstAfterLaunch' | 'sinceLaunch' | 'counter' | 'graduated' | 'hasEntry' | 'flag0' | 'flag1' | 'flag2' | 'flag3';
58
+ /** The values a rule can see (§1.1), by id. */
59
+ export declare const RULE_VALUE_IDS: Record<RuleValueName, number>;
60
+ export type RuleUnit = 'baseUnits' | 'bps' | 'price' | 'lamports' | 'seconds' | 'count' | 'flag';
61
+ /** Each value's unit, which bounds its literal. */
62
+ export declare const RULE_VALUE_UNITS: Record<RuleValueName, RuleUnit>;
63
+ export type RuleKeep = 'entry' | 'times' | 'count';
64
+ /** The header's `keeps` bits. */
65
+ export declare const RULE_KEEP_BITS: Record<RuleKeep, number>;
66
+ /** What each value needs the engine to keep (§2.3); null for one computed from the operation, the pool or the clock alone. */
67
+ export declare const RULE_VALUE_KEEPS: Record<RuleValueName, RuleKeep | null>;
68
+ export type RuleOpName = 'lt' | 'le' | 'gt' | 'ge' | 'eq' | 'ne';
69
+ export declare const RULE_OP_IDS: Record<RuleOpName, number>;
70
+ export type RuleActionKind = 'cut' | 'refuse' | 'count' | 'flag';
71
+ export declare const RULE_ACTION_IDS: Record<RuleActionKind, number>;
72
+ export type RefuseReason = 'cooling' | 'cap' | 'locked' | 'rule';
73
+ export declare const REFUSE_REASON_IDS: Record<RefuseReason, number>;
74
+ export type CountWhat = 'add' | 'reset';
75
+ export declare const COUNT_ARG_IDS: Record<CountWhat, number>;
76
+ /** A FLAG's `arg`: bits 0..1 which flag, bit 4 set (1) or clear (0). */
77
+ export declare const FLAG_SET_BIT = 16;
78
+ export type RuleDestination = 'none' | 'burn' | 'creator' | 'named';
79
+ export declare const RULE_DESTINATION_IDS: Record<RuleDestination, number>;
80
+ export interface Atom {
81
+ value: RuleValueName;
82
+ op: RuleOpName;
83
+ /** Unsigned 64-bit, in the value's unit. */
84
+ literal: bigint;
85
+ }
86
+ export type Action = {
87
+ kind: 'cut';
88
+ bps: number;
89
+ } | {
90
+ kind: 'refuse';
91
+ reason: RefuseReason;
92
+ } | {
93
+ kind: 'count';
94
+ what: CountWhat;
95
+ } | {
96
+ kind: 'flag';
97
+ flag: 0 | 1 | 2 | 3;
98
+ set: boolean;
99
+ };
100
+ export interface Rule {
101
+ on: RuleSide[];
102
+ when: Atom[];
103
+ unless: Atom | null;
104
+ then: Action;
105
+ /** Ends the walk when this rule fires. */
106
+ stop: boolean;
107
+ }
108
+ export interface RuleKeeps {
109
+ entry: boolean;
110
+ times: boolean;
111
+ count: boolean;
112
+ }
113
+ export interface RuleSet {
114
+ version: number;
115
+ keeps: RuleKeeps;
116
+ /** 0, or 1 to 5,000 with an entry kept: checked by `bind` and kept in the bytes, applied nowhere (the engine records a buy's entry at the trade's own price, uncapped). */
117
+ entryCapBps: number;
118
+ destination: RuleDestination;
119
+ rules: Rule[];
120
+ }
121
+ /** Every refusal of the engine's `bind` (§2.6), by code; `RULES_ERROR_TEXT` says each in a sentence. */
122
+ export type RulesErrorCode = 'length' | 'version' | 'rule_count' | 'keeps' | 'destination' | 'side' | 'value' | 'op' | 'action' | 'arg' | 'when_count' | 'unless_count' | 'slot' | 'literal' | 'cut_bps' | 'cut_on_burn' | 'cut_destination' | 'side_total' | 'keeps_entry' | 'keeps_times' | 'keeps_count' | 'entry_cap' | 'refuse_when' | 'refuse_marks' | 'destination_wallet' | 'config_hook' | 'config_flags' | 'config_kit_rules' | 'config_creator';
123
+ export declare const RULES_ERROR_TEXT: Record<RulesErrorCode, string>;
124
+ export declare const RULES_ERROR_CODES: readonly RulesErrorCode[];
125
+ /** One refusal: its code, the rule it is about (0-based; null for the set), and the sentence. */
126
+ export interface RulesProblem {
127
+ code: RulesErrorCode;
128
+ rule: number | null;
129
+ text: string;
130
+ }
131
+ export declare class RulesError extends Error {
132
+ readonly code: RulesErrorCode;
133
+ readonly rule: number | null;
134
+ constructor(code: RulesErrorCode, rule?: number | null);
135
+ }
136
+ export declare const rulesBytesLength: (ruleCount: number) => number;
137
+ /** `on` as its mask. */
138
+ export declare const sideMask: (on: readonly RuleSide[]) => number;
139
+ /** A mask as its sides, in the doc's order; unknown bits are dropped (the validator refuses them). */
140
+ export declare const sidesOf: (mask: number) => RuleSide[];
141
+ export declare const keepsMask: (k: RuleKeeps) => number;
142
+ /** An action's `(action, arg, bps)` bytes. */
143
+ export declare function actionBytes(a: Action): {
144
+ action: number;
145
+ arg: number;
146
+ bps: number;
147
+ };
148
+ /**
149
+ * The set's bytes (§1.2): the header, then each rule, its `when` atoms in the first slots and its
150
+ * `unless` in the next, the rest zero. Encodes what it is given; `validateRules` says whether the
151
+ * engine will take it. Throws `RulesError` only for what has no encoding (more atoms than slots, a
152
+ * literal past u64, more than 255 rules).
153
+ */
154
+ export declare function encodeRules(set: RuleSet): Uint8Array;
155
+ /**
156
+ * A set from its bytes, refusing with the engine's own code what the layout cannot hold: the
157
+ * length, the version, the count, unknown keeps bits, an unknown destination, side, value, op,
158
+ * action or arg, counts past 3 and 1, a filled slot beyond them, a `bps` on an action that is not a
159
+ * cut. The bounds that need the whole set (`validateRules`) are checked after; `checkRulesBytes`
160
+ * does both.
161
+ */
162
+ export declare function decodeRules(bytes: Uint8Array): RuleSet;
163
+ export declare const rulesToHex: (bytes: Uint8Array) => string;
164
+ export declare function rulesFromHex(hex: string): Uint8Array;
165
+ /** The bound a value's literal keeps to. */
166
+ export declare const literalBound: (value: RuleValueName) => bigint;
167
+ /** Whether a value turns on a holding's own marks (a flag or the counter): never enough for a refusal of a sell, a send or a burn (§2.6). */
168
+ export declare const isMarkValue: (value: RuleValueName) => boolean;
169
+ /**
170
+ * Every refusal of §2.6 that the bytes alone do not catch, in order, each once per rule: the codes
171
+ * the engine's `bind` answers with. Empty when the engine will take the set. `validateRules` reads
172
+ * a typed set; `checkRulesBytes` decodes first.
173
+ */
174
+ export declare function validateRules(set: RuleSet): RulesProblem[];
175
+ /** Decodes and validates: the problems, or the set. */
176
+ export declare function checkRulesBytes(bytes: Uint8Array): {
177
+ set: RuleSet;
178
+ problems: RulesProblem[];
179
+ } | {
180
+ set: null;
181
+ problems: RulesProblem[];
182
+ };
183
+ /** The set, or the first refusal thrown (the builder's `build`). */
184
+ export declare function assertRules(set: RuleSet): RuleSet;
185
+ /**
186
+ * The token hook flags a set needs (`flags_for`, §2): `BEFORE_TRANSFER` always;
187
+ * `TRANSFER_RETURNS_DELTA` with any cut; `BEFORE_BURN` with any rule on burns (so a burn rule runs
188
+ * even in a set that keeps nothing); `BEFORE_BURN | WRITES_HOOK_DATA` with any keeps bit, a count
189
+ * or a mark. The config must name exactly these (`config_flags`).
190
+ */
191
+ export declare function rulesFlagsOf(set: RuleSet): number;
192
+ /** A fixed-point value with `decimals`, rounded half up to `places`, trailing zeros trimmed, the whole part grouped. */
193
+ export declare function decimalWords(value: bigint, decimals: number, places: number): string;
194
+ /** Basis points as a percent: 500 -> 5%, 25 -> 0.25%, 1,500 -> 15%. */
195
+ export declare const pctWords: (bps: bigint | number) => string;
196
+ /** Lamports as SOL, to three places: 6,500,000,000 -> 6.5. */
197
+ export declare const solWords: (lamports: bigint) => string;
198
+ /** Base units as whole tokens (to six places when not whole), with the ticker, or "tokens". */
199
+ export declare const tokenWords: (base: bigint, symbol: string | null | undefined) => string;
200
+ /** A price (lamports per base unit times 10^12) as SOL per whole token: `p * 10^decimals / 10^21`. */
201
+ export declare const priceWords: (price: bigint) => string;
202
+ /** A length of time in a sentence: a minute, 10 minutes, an hour, 6 hours, a day, 30 days, 30 seconds. With `article` false, the noun alone for one unit: "the first minute", "the first day". */
203
+ export declare function durationWords(secs: bigint | number, article?: boolean): string;
204
+ /** A wallet address shortened for a sentence. */
205
+ export declare const shortWallet: (wallet: string) => string;
206
+ /** The words of a rule's sides: one ("sell or transfer"), many ("sells or transfers"), the verbs of a refusal ("sell or send"). */
207
+ export interface SideWords {
208
+ one: string;
209
+ many: string;
210
+ verbs: string;
211
+ }
212
+ export declare function sideWords(on: readonly RuleSide[]): SideWords;
213
+ interface Phrase {
214
+ /** After "every sell": "by a holder in profit". */
215
+ when: string;
216
+ /** After "A wallet": "that received tokens less than an hour ago". */
217
+ relative: string;
218
+ /** After "cannot sell or send": "until an hour after launch" (the launch clock alone); null otherwise. */
219
+ trailing: string | null;
220
+ /** As an unless clause: "unless in profit", "until graduation". */
221
+ unless: string;
222
+ /** The second sentence of a cut with this one condition; null when there is none to say. */
223
+ complement: ((w: SideWords) => string) | null;
224
+ }
225
+ /** The phrases of one atom (the table of §3, every value and op given a reading so the function is total). */
226
+ export declare function phraseOf(atom: Atom, symbol: string | null | undefined): Phrase;
227
+ export interface RenderOptions {
228
+ /** The named destination's wallet, for the sentence; absent: "a named wallet". */
229
+ destinationWallet?: string | null;
230
+ /** The ticker, for amounts; absent: "tokens". */
231
+ symbol?: string | null;
232
+ }
233
+ /** The most a set takes per side, basis points of the amount, summed over every cut rule on the side, conditions and `stop` ignored (§3). */
234
+ export interface MostTakes {
235
+ sell: number;
236
+ buy: number;
237
+ /** A transfer's sender and receiver cuts together (both sides answer in one return). */
238
+ transfer: number;
239
+ /** The largest of the three. */
240
+ bps: number;
241
+ /** "5% of a sell; nothing from buys or transfers", or "Takes nothing." */
242
+ text: string;
243
+ }
244
+ /** What `renderRules` gives: the sentences in rule order (one or two per rule), the worst case, the flags, the generated notes and what the set keeps. */
245
+ export interface RulesWords {
246
+ sentences: string[];
247
+ mostTakes: MostTakes;
248
+ flags: number;
249
+ watch: WorkshopReading['watch'];
250
+ /** What the engine keeps per holding for this set, in words; empty when nothing. */
251
+ keeps: string[];
252
+ }
253
+ /** One rule's sentences (one or two), per §3's templates. */
254
+ export declare function renderRule(r: Rule, set: RuleSet, opts?: RenderOptions): string[];
255
+ /** The most a set takes per side (§3): summed, never measured. */
256
+ export declare function mostTakesOf(set: RuleSet): MostTakes;
257
+ /** What the engine keeps for a set, in words. */
258
+ export declare function keepsWords(set: RuleSet): string[];
259
+ /**
260
+ * The reading of a set (§3): the sentences in rule order, the most it takes, the flags and the
261
+ * generated notes. Total and deterministic: the same bytes give the same words in the SDK, on the
262
+ * site, in the API and in the engine's tests.
263
+ */
264
+ export declare function renderRules(set: RuleSet, opts?: RenderOptions): RulesWords;
265
+ /** The lane's own words on the site: the lane, its verdict word and the line over a composed hook's sentences. */
266
+ export declare const RULES_LANE = "rules";
267
+ export declare const RULES_VERDICT_WORD = "Read from its rules";
268
+ export declare const RULES_COMPOSED_LINE = "Composed from Bordrless rules";
269
+ /** What the inspection says of a config that names the engine with no rules bound (§4). */
270
+ export declare const RULES_UNBOUND_PROBLEM = "This config names the rules engine but has no rules bound: it cannot launch.";
271
+ /** The set as the API carries it beside the sentences (`RulesReadout`): the bytes (hex) and what they say. */
272
+ export interface RulesReadout {
273
+ version: number;
274
+ bytes: string;
275
+ sentences: string[];
276
+ mostTakes: MostTakes;
277
+ flags: number;
278
+ destination: RuleDestination;
279
+ destinationWallet: string | null;
280
+ keeps: RuleKeep[];
281
+ entryCapBps: number;
282
+ }
283
+ /**
284
+ * The reading of a composed hook in the shape every surface already shows (`HookReading`), with the
285
+ * lane's own lane and verdict words: `reading.does` the sentences, `total` the computed figure (never
286
+ * measured: `measuredCutBps` null), `watch` the generated notes, and `rules` the set itself. The API
287
+ * serves the words alone (`rulesReadingWords`) and the set once, as `customHook.rules`.
288
+ */
289
+ export interface RulesHookReading extends Omit<HookReading, 'verdict' | 'lane' | 'measuredCutBps' | 'kind' | 'reading'> {
290
+ kind: 'hook';
291
+ /** Always present: the words are the bytes. */
292
+ reading: WorkshopReading;
293
+ verdict: 'rules';
294
+ lane: 'rules';
295
+ measuredCutBps: null;
296
+ rules: RulesReadout;
297
+ }
298
+ export interface RulesReadingOptions extends RenderOptions {
299
+ /** The config's label, else "Composed hook". */
300
+ name?: string | null;
301
+ /** Who bound the set. */
302
+ author?: string | null;
303
+ /** The Workshop item it is listed as, when it is; '' otherwise. */
304
+ workshopId?: string | null;
305
+ /** When it was bound, unix seconds. */
306
+ at?: number | null;
307
+ }
308
+ export declare function rulesReadout(set: RuleSet, opts?: RenderOptions): RulesReadout;
309
+ export declare function rulesHookReading(set: RuleSet, opts?: RulesReadingOptions): RulesHookReading;
310
+ /** Whether a reading the API answered is the lane's synthetic one (served without the set: `rulesReadingWords`). */
311
+ export declare const isRulesReading: (r: unknown) => r is HookReading & {
312
+ lane: "rules";
313
+ verdict: "rules";
314
+ };
315
+ /** The reading as the API serves it (`ConfigInspection.hook`, `CustomHookInfo.workshop`): the words alone; the set itself travels once, as `customHook.rules`. */
316
+ export declare function rulesReadingWords(r: RulesHookReading): HookReading;
317
+ /**
318
+ * A `REFUSE` rule fails the operation with its reason's error (`1 cooling, 2 cap, 3 locked, 4 rule`).
319
+ * `RULES_REFUSAL_ERRORS` are the engine's error names, the ones the starter's `HookError` spells too
320
+ * (held to the engine's IDL by the SDK's tests); the API names a trade or a send the engine refused
321
+ * by `RULES_REFUSAL_CODES`, with `RULES_REFUSAL_TEXT`; the site's trade panel says its own line from
322
+ * the token's own rules (`rulesRefusalLine`).
323
+ */
324
+ export declare const RULES_REFUSAL_ERRORS: Readonly<Record<RefuseReason, string>>;
325
+ export declare const RULES_REFUSAL_CODES: Readonly<Record<RefuseReason, string>>;
326
+ export declare const RULES_REFUSAL_TEXT: Readonly<Record<RefuseReason, string>>;
327
+ /** The reason of an engine error by its name (`CoolingDown`); null for any other error. */
328
+ export declare const refuseReasonOfError: (name: string | null | undefined) => RefuseReason | null;
329
+ /** The reason of an API error code (`rules_cooling`); null for any other code. */
330
+ export declare const refuseReasonOfCode: (code: string | null | undefined) => RefuseReason | null;
331
+ /**
332
+ * The engine's errors by number, as its IDL lists them: `bind`'s refusals first, 6000 plus their
333
+ * place in `RULES_ERROR_CODES` (`length` 6000 ... `config_creator` 6028), then the four reasons
334
+ * (`CoolingDown` 6029, `OverCap` 6030, `Locked` 6031, `Refused` 6032), then its own. A log names
335
+ * the error too (`Error Code: CoolingDown`), which `refuseReasonOfError` reads.
336
+ */
337
+ export declare const RULES_ENGINE_ERRORS: Readonly<Record<number, string>>;
338
+ /** The engine's error number of a refusal of `bind` (`config_flags` -> 6026). */
339
+ export declare const rulesErrorNumber: (code: RulesErrorCode) => number;
340
+ /** The refusal of `bind` an engine error number stands for; null for any other number. */
341
+ export declare function rulesErrorCodeOfNumber(n: number): RulesErrorCode | null;
342
+ /** The engine's error numbers of the four reasons. */
343
+ export declare const RULES_REFUSAL_NUMBERS: Readonly<Record<RefuseReason, number>>;
344
+ /** The reason of an engine error number (6029 -> `cooling`); null for any other number. */
345
+ export declare const refuseReasonOfNumber: (n: number) => RefuseReason | null;
346
+ /**
347
+ * What a refused operation says, from the set that refused it: the first `REFUSE` rule with that
348
+ * reason on that side (else on any side). A cooldown on the time since tokens arrived says it the
349
+ * trade panel's way ("Tokens that arrived less than an hour ago can’t be sold yet."); any other is
350
+ * the rule's own sentence. Null when the set has no such rule.
351
+ */
352
+ export declare function rulesRefusalLine(set: RuleSet, reason: RefuseReason, side: RuleSide, opts?: RenderOptions): string | null;
353
+ export {};