@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 +91 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/keeper.d.ts +139 -0
- package/dist/keeper.js +399 -0
- package/dist/policy.d.ts +108 -1
- package/dist/policy.js +235 -1
- package/dist/programs.d.ts +79 -0
- package/dist/programs.js +84 -0
- package/dist/rules.d.ts +353 -0
- package/dist/rules.js +949 -0
- package/dist/studio.d.ts +3 -1
- package/dist/studio.js +3 -1
- package/dist/workshop.d.ts +34 -6
- package/dist/workshop.js +8 -1
- package/package.json +1 -1
package/dist/policy.js
CHANGED
|
@@ -757,7 +757,28 @@ export function scriptRequestOf(companion) {
|
|
|
757
757
|
const initData = r.initData === undefined || r.initData === null ? '' : r.initData;
|
|
758
758
|
if (typeof initData !== 'string' || scriptInitDataLength(initData) === null)
|
|
759
759
|
return 'malformed';
|
|
760
|
-
|
|
760
|
+
const payout = payoutTermsRequestOf(r.payout);
|
|
761
|
+
if (payout === 'malformed')
|
|
762
|
+
return 'malformed';
|
|
763
|
+
return { potBps: r.potBps, program: r.program, interval: r.interval, initData, stateLen: r.stateLen, ...(payout ? { payout } : {}) };
|
|
764
|
+
}
|
|
765
|
+
/** The companion program's bounds on payout terms (`PayoutTermsArgs::valid`): each share 1 to 10,000 basis points, the window 10 seconds to a day. */
|
|
766
|
+
export const PAYOUT_TERMS_BOUNDS = { minWindowSecs: 10, maxWindowSecs: 86_400 };
|
|
767
|
+
/** A script's payout terms as a request names them (`script.payout`); null without them; `'malformed'` when they are there and not four whole numbers. */
|
|
768
|
+
function payoutTermsRequestOf(raw) {
|
|
769
|
+
if (raw === undefined || raw === null)
|
|
770
|
+
return null;
|
|
771
|
+
if (typeof raw !== 'object')
|
|
772
|
+
return 'malformed';
|
|
773
|
+
const r = raw;
|
|
774
|
+
if (![r.stepBps, r.holdingBps, r.windowBps].every(isShare) || typeof r.windowSecs !== 'number' || !Number.isInteger(r.windowSecs))
|
|
775
|
+
return 'malformed';
|
|
776
|
+
return { stepBps: r.stepBps, holdingBps: r.holdingBps, windowBps: r.windowBps, windowSecs: r.windowSecs };
|
|
777
|
+
}
|
|
778
|
+
/** Whether payout terms are within the companion program's bounds (`create_script_v2` refuses them otherwise, `BadPayoutTerms`). */
|
|
779
|
+
export function payoutTermsWithin(t) {
|
|
780
|
+
const share = (v) => Number.isInteger(v) && v >= 1 && v <= 10_000;
|
|
781
|
+
return share(t.stepBps) && share(t.holdingBps) && share(t.windowBps) && Number.isInteger(t.windowSecs) && t.windowSecs >= PAYOUT_TERMS_BOUNDS.minWindowSecs && t.windowSecs <= PAYOUT_TERMS_BOUNDS.maxWindowSecs;
|
|
761
782
|
}
|
|
762
783
|
/**
|
|
763
784
|
* Why a custom companion with this split can't run these rules at this fee, in the words the launch
|
|
@@ -779,6 +800,8 @@ export function scriptProblem(s, split, rules, creatorFeeBps) {
|
|
|
779
800
|
return `The script’s init data is at most ${B.maxInitLen} bytes.`;
|
|
780
801
|
if (!Number.isInteger(s.stateLen) || s.stateLen < 0 || s.stateLen > B.maxStateLen)
|
|
781
802
|
return `The script’s state is 0 to ${B.maxStateLen.toLocaleString('en-US')} bytes.`;
|
|
803
|
+
if (s.payout && !payoutTermsWithin(s.payout))
|
|
804
|
+
return 'The script’s payout limits are each 0.01% to 100%, over a window of 10 seconds to a day.';
|
|
782
805
|
if (rules.creatorLockDays > 0)
|
|
783
806
|
return 'A creator fee run by a program can’t come with the creator wallet lock: the program vests your first buy instead.';
|
|
784
807
|
if (creatorFeeBps === 0)
|
|
@@ -787,6 +810,217 @@ export function scriptProblem(s, split, rules, creatorFeeBps) {
|
|
|
787
810
|
return 'A share of the creator fee for holders needs holder rewards on.';
|
|
788
811
|
return null;
|
|
789
812
|
}
|
|
813
|
+
// ---- Payees and wallet payouts (2026-10-13, docs/payees-and-wallet-payouts.md) ---------------------
|
|
814
|
+
/** The most wallets that share a launcher's part (`set_payees`; the SDK's `MAX_PAYEES`). */
|
|
815
|
+
export const MAX_PAYEES = 10;
|
|
816
|
+
/** The system program's id, the default key: never a payee. */
|
|
817
|
+
const DEFAULT_KEY = '11111111111111111111111111111111';
|
|
818
|
+
/** The payees a launch request's `companion` names (`companion.payees`); null without any (absent, null or empty); `'malformed'` when they are there and not a list of `{ wallet, bps }` with an address and a whole number. */
|
|
819
|
+
export function payeesRequestOf(companion) {
|
|
820
|
+
if (typeof companion !== 'object' || companion === null)
|
|
821
|
+
return null;
|
|
822
|
+
const raw = companion.payees;
|
|
823
|
+
if (raw === undefined || raw === null)
|
|
824
|
+
return null;
|
|
825
|
+
if (!Array.isArray(raw))
|
|
826
|
+
return 'malformed';
|
|
827
|
+
if (raw.length === 0)
|
|
828
|
+
return null;
|
|
829
|
+
const out = [];
|
|
830
|
+
for (const entry of raw) {
|
|
831
|
+
if (typeof entry !== 'object' || entry === null)
|
|
832
|
+
return 'malformed';
|
|
833
|
+
const e = entry;
|
|
834
|
+
if (typeof e.wallet !== 'string' || !BASE58_ADDRESS.test(e.wallet) || typeof e.bps !== 'number' || !Number.isInteger(e.bps))
|
|
835
|
+
return 'malformed';
|
|
836
|
+
out.push({ wallet: e.wallet, bps: e.bps });
|
|
837
|
+
}
|
|
838
|
+
return out;
|
|
839
|
+
}
|
|
840
|
+
/** What the payees leave the launcher of their part, basis points of it (10,000 with none). */
|
|
841
|
+
export const payeesLeaveBps = (payees) => 10_000 - payees.reduce((sum, p) => sum + p.bps, 0);
|
|
842
|
+
/**
|
|
843
|
+
* Why `set_payees` would refuse these payees (`BadPayees`), in the words the launch form and the
|
|
844
|
+
* backend use (`companion_rules`); null when it would take them: 1 to 10 wallets, each named once,
|
|
845
|
+
* each 0.01% to 100% of the launcher's part and 100% in all at most; none the default key, the
|
|
846
|
+
* launcher (`beneficiary`) or one of `reserved` (the companion and its creator address, which the
|
|
847
|
+
* backend derives for the mint). A split with no part for the launcher has nothing to share.
|
|
848
|
+
*/
|
|
849
|
+
export function payeesProblem(payees, split, beneficiary, reserved = []) {
|
|
850
|
+
if (payees.length === 0 || payees.length > MAX_PAYEES)
|
|
851
|
+
return `Up to ${MAX_PAYEES} wallets can share your part.`;
|
|
852
|
+
if (split.beneficiaryBps <= 0)
|
|
853
|
+
return 'The wallets share your part of the creator fee, and this split leaves you none.';
|
|
854
|
+
if (payees.some((p) => !Number.isInteger(p.bps) || p.bps < 1 || p.bps > 10_000))
|
|
855
|
+
return 'Each wallet gets 0.01% to 100% of your part.';
|
|
856
|
+
if (payeesLeaveBps(payees) < 0)
|
|
857
|
+
return 'The wallets’ shares add up to more than 100% of your part.';
|
|
858
|
+
const seen = new Set();
|
|
859
|
+
for (const p of payees) {
|
|
860
|
+
if (!BASE58_ADDRESS.test(p.wallet) || p.wallet === DEFAULT_KEY)
|
|
861
|
+
return `${p.wallet} is not a wallet.`;
|
|
862
|
+
if (seen.has(p.wallet))
|
|
863
|
+
return 'Name each wallet once.';
|
|
864
|
+
seen.add(p.wallet);
|
|
865
|
+
if (p.wallet === beneficiary)
|
|
866
|
+
return 'You keep what the wallets don’t take: name wallets other than your own.';
|
|
867
|
+
if (reserved.includes(p.wallet))
|
|
868
|
+
return 'A wallet can’t be the hook’s own account.';
|
|
869
|
+
}
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Why a request's `allowWalletPayouts` can't be taken (`companion_rules`); null when it can, or it
|
|
874
|
+
* is off: only a custom hook's script with payout terms (`script.payout`, `create_script_v2`) may
|
|
875
|
+
* pay wallets, never Lossback's (its script pays holders under water, and nothing else).
|
|
876
|
+
*/
|
|
877
|
+
export function walletPayoutsProblem(allow, script) {
|
|
878
|
+
if (!allow)
|
|
879
|
+
return null;
|
|
880
|
+
if (!script)
|
|
881
|
+
return 'Only a custom hook’s script can pay wallets.';
|
|
882
|
+
if (!script.payout)
|
|
883
|
+
return 'A script pays wallets only within payout limits: set them.';
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
// ---- Loss cover (2026-10-12; the site says Lossback): the pot pays holders who are under water (docs/loss-cover.md) ----
|
|
887
|
+
/**
|
|
888
|
+
* The bounds a Lossback coin's terms keep within, as the site offers them: the programs' own
|
|
889
|
+
* (`loss_cover_script::CoverTerms::valid`, the companion's `PayoutTermsArgs::valid`) and the
|
|
890
|
+
* policy's tighter ones (the step at least 10 s and at most a quarter of the round, a holding of
|
|
891
|
+
* at most 1% of the supply, a loss of at least 0.0001 SOL, a wait of at most a day). The keeper's
|
|
892
|
+
* batches (`batchPaying`, `batchMeasuring`) are what one step carries within the runtime's
|
|
893
|
+
* instruction trace, measured by the programs' `loss_cover_vectors` (a measuring step carries one
|
|
894
|
+
* fewer on a coin's first step, when the creator's holding is made on the way).
|
|
895
|
+
*/
|
|
896
|
+
export const LOSS_COVER_LIMITS = {
|
|
897
|
+
minRoundSecs: 60,
|
|
898
|
+
maxRoundSecs: DAY_SECS,
|
|
899
|
+
minStepSecs: 10,
|
|
900
|
+
maxStepSecs: 3_600,
|
|
901
|
+
/** The step is at most this part of the round: a round has at least four steps. */
|
|
902
|
+
stepsPerRoundMin: 4,
|
|
903
|
+
minBps: 100,
|
|
904
|
+
maxBps: 10_000,
|
|
905
|
+
minCoverBps: 1_000,
|
|
906
|
+
maxCoverBps: 10_000,
|
|
907
|
+
/** The least holding that counts, at most this part of the supply (basis points). */
|
|
908
|
+
maxMinHoldingBps: 100,
|
|
909
|
+
minMinLossLamports: 100000n,
|
|
910
|
+
maxMinAgeSecs: DAY_SECS,
|
|
911
|
+
maxMinPotLamports: 100000000000n,
|
|
912
|
+
batchPaying: 7,
|
|
913
|
+
batchMeasuring: 13,
|
|
914
|
+
};
|
|
915
|
+
/**
|
|
916
|
+
* The terms the site launches a Lossback coin with: rounds of 5 minutes stepped every 15 seconds,
|
|
917
|
+
* the whole pot available to each step, each holding and each round, the whole loss covered when
|
|
918
|
+
* the pot can, a holding of 100,000 tokens (6 decimals: base units) and a loss of 0.001 SOL at
|
|
919
|
+
* least, a minute after its last buy (the owner, 2026-10-12; the first coin, LIFEVEST, was made with
|
|
920
|
+
* half an hour, fixed in its script state), a round only once the pot holds 1 SOL, the hook's whole
|
|
921
|
+
* fee row to the pot (the launcher's row 0: `potBps` is 10,000 less the launcher's part). The
|
|
922
|
+
* launcher sets `roundSecs`, `minPotLamports`, `coverBps` and `minHolding` (`LossCoverRequest`);
|
|
923
|
+
* the rest is fixed here. There is no cooldown: a holding is measured or paid once a round.
|
|
924
|
+
*/
|
|
925
|
+
/** A holding's wait in words: "45 seconds", "1 minute", "30 minutes". */
|
|
926
|
+
export function ageWords(secs) {
|
|
927
|
+
if (secs % 60 !== 0 || secs < 60)
|
|
928
|
+
return `${secs} second${secs === 1 ? '' : 's'}`;
|
|
929
|
+
const m = secs / 60;
|
|
930
|
+
return `${m} minute${m === 1 ? '' : 's'}`;
|
|
931
|
+
}
|
|
932
|
+
export const LOSS_COVER_DEFAULTS = {
|
|
933
|
+
potBps: 10_000,
|
|
934
|
+
roundSecs: 300,
|
|
935
|
+
stepSecs: 15,
|
|
936
|
+
roundBps: 10_000,
|
|
937
|
+
stepBps: 10_000,
|
|
938
|
+
holdingBps: 10_000,
|
|
939
|
+
coverBps: 10_000,
|
|
940
|
+
minHolding: '100000000000',
|
|
941
|
+
minLossLamports: '1000000',
|
|
942
|
+
minAgeSecs: 60,
|
|
943
|
+
minPotLamports: '1000000000',
|
|
944
|
+
};
|
|
945
|
+
/** The round lengths the launch form offers (seconds): 5, 10, 30 and 60 minutes. */
|
|
946
|
+
export const LOSS_COVER_ROUND_CHOICES_SECS = [300, 600, 1_800, 3_600];
|
|
947
|
+
/** The cover shares the launch form offers: the whole loss, half, a quarter. */
|
|
948
|
+
export const LOSS_COVER_COVER_CHOICES_BPS = [10_000, 5_000, 2_500];
|
|
949
|
+
/** The minimum pots the launch form offers, lamports: none, 0.5, 1, 5 SOL. */
|
|
950
|
+
export const LOSS_COVER_MIN_POT_CHOICES_LAMPORTS = ['0', '500000000', '1000000000', '5000000000'];
|
|
951
|
+
const LAMPORTS = /^\d{1,20}$/;
|
|
952
|
+
/** The Lossback terms a launch request's `companion` names (`companion.lossCover`); null without them; `'malformed'` when they are there and not whole numbers and lamport strings. */
|
|
953
|
+
export function lossCoverRequestOf(companion) {
|
|
954
|
+
if (typeof companion !== 'object' || companion === null)
|
|
955
|
+
return null;
|
|
956
|
+
const raw = companion.lossCover;
|
|
957
|
+
if (raw === undefined || raw === null)
|
|
958
|
+
return null;
|
|
959
|
+
if (typeof raw !== 'object')
|
|
960
|
+
return 'malformed';
|
|
961
|
+
const r = raw;
|
|
962
|
+
if (typeof r.roundSecs !== 'number' || !Number.isInteger(r.roundSecs) || !isShare(r.coverBps))
|
|
963
|
+
return 'malformed';
|
|
964
|
+
if (typeof r.minPotLamports !== 'string' || !LAMPORTS.test(r.minPotLamports) || typeof r.minHolding !== 'string' || !LAMPORTS.test(r.minHolding))
|
|
965
|
+
return 'malformed';
|
|
966
|
+
return { roundSecs: r.roundSecs, minPotLamports: r.minPotLamports, coverBps: r.coverBps, minHolding: r.minHolding };
|
|
967
|
+
}
|
|
968
|
+
/** The full terms a request launches with: what it names, the rest from `LOSS_COVER_DEFAULTS`. */
|
|
969
|
+
export function lossCoverTermsOf(s) {
|
|
970
|
+
const D = LOSS_COVER_DEFAULTS;
|
|
971
|
+
return { roundSecs: s.roundSecs, stepSecs: D.stepSecs, stepBps: D.stepBps, holdingBps: D.holdingBps, roundBps: D.roundBps, coverBps: s.coverBps, minHolding: s.minHolding, minLossLamports: D.minLossLamports, minAgeSecs: D.minAgeSecs, minPotLamports: s.minPotLamports };
|
|
972
|
+
}
|
|
973
|
+
/** The pot's part of every fee claim for a Lossback coin: what the launcher's part of the split leaves (the hook's whole fee row). */
|
|
974
|
+
export const lossCoverPotBps = (split) => 10_000 - split.buybackBps - split.holdersBps - split.beneficiaryBps;
|
|
975
|
+
/**
|
|
976
|
+
* Why a Lossback coin with these terms can't launch with this split on these rules at this fee, in
|
|
977
|
+
* the words the launch form and the backend use (`companion_rules`); null when it can: a creator
|
|
978
|
+
* fee to fill the pot, no other token rules (it launches from Bordrless's Loss cover config, which
|
|
979
|
+
* has none, and runs its own hook in the kit's place), nothing bought back and no holders' part (the
|
|
980
|
+
* pot and the launcher only), a part for the pot, and the terms within `LOSS_COVER_LIMITS` (the
|
|
981
|
+
* programs refuse anything outside their own bounds at the setup's dry run). `supply` is the
|
|
982
|
+
* launch's, for the least holding's cap.
|
|
983
|
+
*/
|
|
984
|
+
export function lossCoverProblem(s, split, rules, creatorFeeBps, supply = TOKEN_SUPPLY) {
|
|
985
|
+
const L = LOSS_COVER_LIMITS;
|
|
986
|
+
const D = LOSS_COVER_DEFAULTS;
|
|
987
|
+
if (creatorFeeBps === 0)
|
|
988
|
+
return 'There is no creator fee to fill the pot with: set one.';
|
|
989
|
+
if (Object.keys(NO_RULES).some((k) => rules[k] !== 0))
|
|
990
|
+
return 'A Lossback coin has no other token rules: its hook keeps each holding’s entry price.';
|
|
991
|
+
if (split.buybackBps !== 0 || split.holdersBps !== 0)
|
|
992
|
+
return 'A Lossback coin’s creator fee goes to its pot and to the launcher: nothing bought back, no holders’ part.';
|
|
993
|
+
const potBps = lossCoverPotBps(split);
|
|
994
|
+
if (!(potBps > 0) || !isShare(split.beneficiaryBps))
|
|
995
|
+
return 'The pot’s part and the launcher’s must add up to 100%, with a part for the pot.';
|
|
996
|
+
if (!Number.isInteger(s.roundSecs) || s.roundSecs < L.minRoundSecs || s.roundSecs > L.maxRoundSecs)
|
|
997
|
+
return 'A round lasts a minute to a day.';
|
|
998
|
+
if (s.roundSecs < D.stepSecs * L.stepsPerRoundMin)
|
|
999
|
+
return `A round holds at least ${L.stepsPerRoundMin} steps of ${D.stepSecs} seconds.`;
|
|
1000
|
+
if (!Number.isInteger(s.coverBps) || s.coverBps < L.minCoverBps || s.coverBps > L.maxCoverBps)
|
|
1001
|
+
return 'The pot covers 10% to 100% of a loss.';
|
|
1002
|
+
const minHolding = BigInt(s.minHolding);
|
|
1003
|
+
if (minHolding < 1n || minHolding > (supply * BigInt(L.maxMinHoldingBps)) / BPS)
|
|
1004
|
+
return 'The least holding that counts is at least one base unit and at most 1% of the supply.';
|
|
1005
|
+
const minPot = BigInt(s.minPotLamports);
|
|
1006
|
+
if (minPot > L.maxMinPotLamports)
|
|
1007
|
+
return 'The minimum pot is at most 100 SOL.';
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* The review step's sentence for a Lossback coin, in numbers: what it does, never that it protects
|
|
1012
|
+
* anyone (docs/loss-cover.md §5).
|
|
1013
|
+
*/
|
|
1014
|
+
export function lossCoverSentence(s, decimals = TOKEN_DECIMALS) {
|
|
1015
|
+
const D = LOSS_COVER_DEFAULTS;
|
|
1016
|
+
const minutes = Math.round(s.roundSecs / 60);
|
|
1017
|
+
const pot = Number(BigInt(s.minPotLamports)) / 1e9;
|
|
1018
|
+
const holding = Number(BigInt(s.minHolding)) / 10 ** decimals;
|
|
1019
|
+
const loss = Number(BigInt(D.minLossLamports)) / 1e9;
|
|
1020
|
+
const share = s.coverBps === 10_000 ? 'the same share of what they are down' : `the same share of ${s.coverBps / 100}% of what they are down`;
|
|
1021
|
+
const once = pot > 0 ? `, once the pot holds ${pot} SOL,` : '';
|
|
1022
|
+
return `Every ${minutes} minutes${once} it pays every holder under water ${share}, as much as the pot allows, in steps of ${D.stepSecs} seconds; a holding counts from ${holding.toLocaleString('en-US')} tokens and ${loss} SOL of loss, ${ageWords(D.minAgeSecs)} after it bought.`;
|
|
1023
|
+
}
|
|
790
1024
|
/** The template whose split this is, or null for any other split. */
|
|
791
1025
|
export function companionTemplateOf(split) {
|
|
792
1026
|
return COMPANION_TEMPLATE_LIST.find((t) => {
|
package/dist/programs.d.ts
CHANGED
|
@@ -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
|