brainblast 0.7.3 → 0.7.4
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/{chunk-UWE6HAGS.js → chunk-F7QOW3IM.js} +1 -1
- package/dist/{chunk-SVSVVW6U.js → chunk-GF37ANSW.js} +46 -0
- package/dist/{chunk-2UZGWXIX.js → chunk-QMJEZ6NO.js} +14 -4
- package/dist/chunk-WQFLKWBY.js +110 -0
- package/dist/cli.js +50 -4
- package/dist/index.d.ts +43 -1
- package/dist/index.js +21 -3
- package/dist/oracle-DVZLFJ43.js +15 -0
- package/dist/{score-VLKER37D.js → score-YXFXD6QG.js} +2 -2
- package/dist/{trustGraph-4SSJOQKT.js → trustGraph-K5PWNEL4.js} +10 -2
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
getAccountInfo,
|
|
2
3
|
probeUpgradeAuthority
|
|
3
4
|
} from "./chunk-XSVQSK53.js";
|
|
4
5
|
|
|
@@ -39,6 +40,41 @@ function loadDirectory(path = bundledPath()) {
|
|
|
39
40
|
return m;
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
// src/trustGraph/classifyAuthority.ts
|
|
44
|
+
var SYSTEM_PROGRAM = "11111111111111111111111111111111";
|
|
45
|
+
var KNOWN_AUTHORITY_OWNERS = {
|
|
46
|
+
// Squads — the dominant Solana multisig. v3 ("SMPL") and v4 program ids.
|
|
47
|
+
// https://docs.squads.so/main/development/sdk/program-ids
|
|
48
|
+
SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu: { kind: "multisig", label: "Squads v3" },
|
|
49
|
+
SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf: { kind: "multisig", label: "Squads v4" },
|
|
50
|
+
// SPL Governance (Realms) — the standard on-chain governance program.
|
|
51
|
+
// https://github.com/solana-labs/solana-program-library/tree/master/governance
|
|
52
|
+
GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw: { kind: "dao", label: "SPL Governance (Realms)" }
|
|
53
|
+
};
|
|
54
|
+
async function classifyUpgradeAuthority(address, opts = {}) {
|
|
55
|
+
const acct = await getAccountInfo(address, opts);
|
|
56
|
+
if (!acct) {
|
|
57
|
+
return { kind: "unknown" };
|
|
58
|
+
}
|
|
59
|
+
if (acct.owner === SYSTEM_PROGRAM) {
|
|
60
|
+
return { kind: "single-key", ownerProgram: SYSTEM_PROGRAM };
|
|
61
|
+
}
|
|
62
|
+
const known = KNOWN_AUTHORITY_OWNERS[acct.owner];
|
|
63
|
+
if (known) {
|
|
64
|
+
return { kind: known.kind, ownerProgram: acct.owner, ownerLabel: known.label };
|
|
65
|
+
}
|
|
66
|
+
return { kind: "unknown", ownerProgram: acct.owner };
|
|
67
|
+
}
|
|
68
|
+
async function enrichAuthorityClassification(authority, opts = {}) {
|
|
69
|
+
if (authority.kind !== "unknown" || !authority.address) return authority;
|
|
70
|
+
const c = await classifyUpgradeAuthority(authority.address, opts);
|
|
71
|
+
return {
|
|
72
|
+
...authority,
|
|
73
|
+
kind: c.kind,
|
|
74
|
+
...c.ownerProgram ? { ownerProgram: c.ownerProgram } : {}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
42
78
|
// src/trustGraph/programCache.ts
|
|
43
79
|
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync as existsSync2 } from "fs";
|
|
44
80
|
import { join as join2, dirname } from "path";
|
|
@@ -146,6 +182,12 @@ async function buildTrustGraph(programIds, opts = {}) {
|
|
|
146
182
|
let authority;
|
|
147
183
|
try {
|
|
148
184
|
authority = await probeUpgradeAuthority(id, opts);
|
|
185
|
+
if (opts.classifyAuthority !== false) {
|
|
186
|
+
try {
|
|
187
|
+
authority = await enrichAuthorityClassification(authority, opts);
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
}
|
|
149
191
|
} catch (e) {
|
|
150
192
|
unresolved.push({ programId: id, reason: `rpc_error: ${e?.message ?? String(e)}` });
|
|
151
193
|
continue;
|
|
@@ -174,6 +216,10 @@ async function buildTrustGraph(programIds, opts = {}) {
|
|
|
174
216
|
|
|
175
217
|
export {
|
|
176
218
|
loadDirectory,
|
|
219
|
+
SYSTEM_PROGRAM,
|
|
220
|
+
KNOWN_AUTHORITY_OWNERS,
|
|
221
|
+
classifyUpgradeAuthority,
|
|
222
|
+
enrichAuthorityClassification,
|
|
177
223
|
DEFAULT_TTL_HOURS,
|
|
178
224
|
defaultCachePath,
|
|
179
225
|
loadProgramCache,
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
// src/trustGraph/render.ts
|
|
2
2
|
function renderAuthority(p) {
|
|
3
3
|
const a = p.upgradeAuthority;
|
|
4
|
+
const owner = a.ownerProgram ? ` _(owner: \`${a.ownerProgram}\`)_` : "";
|
|
4
5
|
switch (a.kind) {
|
|
5
6
|
case "renounced":
|
|
6
7
|
return "\u{1F512} **Renounced** \u2014 program is frozen; no key can upgrade it.";
|
|
7
8
|
case "single-key":
|
|
8
|
-
return `\u26A0\uFE0F **Single key** \`${a.address}\` \u2014 one private key can replace this program at any time
|
|
9
|
+
return `\u26A0\uFE0F **Single key** \`${a.address}\` \u2014 one private key can replace this program at any time.${owner}`;
|
|
9
10
|
case "multisig":
|
|
10
|
-
return `\u{1F510} **Multisig** \`${a.address}\` \u2014 a threshold of signers can upgrade
|
|
11
|
+
return `\u{1F510} **Multisig** \`${a.address}\` \u2014 a threshold of signers can upgrade.${owner}`;
|
|
11
12
|
case "dao":
|
|
12
|
-
return `\u{1F3DB} **DAO** \`${a.address}\` \u2014 governance program controls upgrades
|
|
13
|
+
return `\u{1F3DB} **DAO** \`${a.address}\` \u2014 governance program controls upgrades.${owner}`;
|
|
13
14
|
case "unknown":
|
|
14
|
-
return a.address ? `\u2753 **Unclassified authority** \`${a.address}
|
|
15
|
+
return a.address ? `\u2753 **Unclassified authority** \`${a.address}\`${owner} \u2014 needs research to confirm single-key vs multisig/DAO.` : "\u2753 **Unknown** \u2014 could not determine upgrade authority.";
|
|
15
16
|
}
|
|
16
17
|
}
|
|
18
|
+
function renderTrustSummary(p) {
|
|
19
|
+
const a = p.upgradeAuthority;
|
|
20
|
+
const authBit = a.kind === "renounced" ? "\u{1F512} immutable" : a.kind === "multisig" ? "\u{1F510} multisig" : a.kind === "dao" ? "\u{1F3DB} DAO-governed" : a.kind === "single-key" ? "\u26A0\uFE0F single-key upgradeable" : "\u2753 authority unclassified";
|
|
21
|
+
const verifiedBit = p.verifiedBuild.state === "verified" ? "\u2705 verified build" : p.verifiedBuild.state === "unverified" ? "\u274C unverified" : "\u2753 build unchecked";
|
|
22
|
+
const auditBit = p.audits.length ? `\u2705 audited (${p.audits.map((x) => x.firm).join(", ")})` : "\u274C no audits on file";
|
|
23
|
+
return `${authBit} \xB7 ${verifiedBit} \xB7 ${auditBit}`;
|
|
24
|
+
}
|
|
17
25
|
function renderVerified(p) {
|
|
18
26
|
const v = p.verifiedBuild;
|
|
19
27
|
switch (v.state) {
|
|
@@ -42,6 +50,8 @@ function renderProgram(p) {
|
|
|
42
50
|
"",
|
|
43
51
|
`\`${p.programId}\`${p.kind ? ` \xB7 kind: \`${p.kind}\`` : ""}`,
|
|
44
52
|
"",
|
|
53
|
+
`**Trust:** ${renderTrustSummary(p)}`,
|
|
54
|
+
"",
|
|
45
55
|
`- **Upgrade authority:** ${renderAuthority(p)}`,
|
|
46
56
|
`- **Verified build:** ${renderVerified(p)}`,
|
|
47
57
|
`- **Parity:** ${renderParity(p)}`,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_RPC
|
|
3
|
+
} from "./chunk-XSVQSK53.js";
|
|
4
|
+
import {
|
|
5
|
+
isValidSolanaAddress
|
|
6
|
+
} from "./chunk-VG5FMOLW.js";
|
|
7
|
+
|
|
8
|
+
// src/oracle.ts
|
|
9
|
+
var SLOT_MS = 400;
|
|
10
|
+
var DEFAULT_STALENESS_SLOTS = 150;
|
|
11
|
+
async function rpc(method, params, opts) {
|
|
12
|
+
const url = opts.rpcUrl ?? DEFAULT_RPC;
|
|
13
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
14
|
+
const ac = new AbortController();
|
|
15
|
+
const t = setTimeout(() => ac.abort(), opts.timeoutMs ?? 1e4);
|
|
16
|
+
try {
|
|
17
|
+
const res = await fetchImpl(url, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: { "content-type": "application/json" },
|
|
20
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
|
|
21
|
+
signal: ac.signal
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) throw new Error(`rpc ${method}: HTTP ${res.status}`);
|
|
24
|
+
const body = await res.json();
|
|
25
|
+
if (body.error) throw new Error(`rpc ${method}: ${body.error.message}`);
|
|
26
|
+
if (body.result === void 0) throw new Error(`rpc ${method}: empty result`);
|
|
27
|
+
return body.result;
|
|
28
|
+
} finally {
|
|
29
|
+
clearTimeout(t);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function checkOracleFreshness(account, opts = {}) {
|
|
33
|
+
if (!isValidSolanaAddress(account)) throw new Error(`invalid Solana address: ${account}`);
|
|
34
|
+
const thresholdSlots = opts.maxStalenessSlots ?? (opts.maxStalenessSeconds != null ? Math.max(1, Math.round(opts.maxStalenessSeconds * 1e3 / SLOT_MS)) : DEFAULT_STALENESS_SLOTS);
|
|
35
|
+
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
36
|
+
const currentSlot = await rpc("getSlot", [{ commitment: "confirmed" }], opts);
|
|
37
|
+
const sigs = await rpc(
|
|
38
|
+
"getSignaturesForAddress",
|
|
39
|
+
[account, { limit: 1 }],
|
|
40
|
+
opts
|
|
41
|
+
);
|
|
42
|
+
if (!sigs || sigs.length === 0) {
|
|
43
|
+
return {
|
|
44
|
+
account,
|
|
45
|
+
currentSlot,
|
|
46
|
+
lastSlot: null,
|
|
47
|
+
lastBlockTime: null,
|
|
48
|
+
slotsBehind: null,
|
|
49
|
+
secondsBehind: null,
|
|
50
|
+
thresholdSlots,
|
|
51
|
+
fresh: false,
|
|
52
|
+
verdict: "NO_HISTORY",
|
|
53
|
+
checkedAt
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const last = sigs[0];
|
|
57
|
+
const lastSlot = last.slot;
|
|
58
|
+
const lastBlockTime = last.blockTime ?? null;
|
|
59
|
+
const slotsBehind = Math.max(0, currentSlot - lastSlot);
|
|
60
|
+
const secondsBehind = lastBlockTime != null ? Math.max(0, Math.floor(Date.now() / 1e3) - lastBlockTime) : Math.round(slotsBehind * SLOT_MS / 1e3);
|
|
61
|
+
const fresh = slotsBehind <= thresholdSlots;
|
|
62
|
+
return {
|
|
63
|
+
account,
|
|
64
|
+
currentSlot,
|
|
65
|
+
lastSlot,
|
|
66
|
+
lastBlockTime,
|
|
67
|
+
slotsBehind,
|
|
68
|
+
secondsBehind,
|
|
69
|
+
thresholdSlots,
|
|
70
|
+
fresh,
|
|
71
|
+
verdict: fresh ? "FRESH" : "STALE",
|
|
72
|
+
checkedAt
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function renderOracleText(f) {
|
|
76
|
+
const L = [];
|
|
77
|
+
L.push("\u2500\u2500 Oracle Freshness \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
78
|
+
L.push(` account: ${f.account}`);
|
|
79
|
+
L.push(` current slot: ${f.currentSlot.toLocaleString()}`);
|
|
80
|
+
if (f.verdict === "NO_HISTORY") {
|
|
81
|
+
L.push(" last write: (no transactions found touching this account)");
|
|
82
|
+
L.push(" verdict: \u2753 NO_HISTORY \u2014 cannot confirm freshness");
|
|
83
|
+
return L.join("\n");
|
|
84
|
+
}
|
|
85
|
+
L.push(` last write: slot ${f.lastSlot.toLocaleString()} (${f.slotsBehind.toLocaleString()} slots / ~${f.secondsBehind}s ago)`);
|
|
86
|
+
L.push(` threshold: ${f.thresholdSlots.toLocaleString()} slots`);
|
|
87
|
+
L.push(` verdict: ${f.fresh ? "\u2705 FRESH" : "\u{1F6A8} STALE \u2014 last update is older than the freshness threshold"}`);
|
|
88
|
+
return L.join("\n");
|
|
89
|
+
}
|
|
90
|
+
function renderOracleMd(f) {
|
|
91
|
+
const L = ["## Oracle Freshness\n"];
|
|
92
|
+
L.push(`**Account:** \`${f.account}\` \xB7 checked ${f.checkedAt}
|
|
93
|
+
`);
|
|
94
|
+
if (f.verdict === "NO_HISTORY") {
|
|
95
|
+
L.push("\u2753 **NO_HISTORY** \u2014 no transactions were found touching this account, so freshness can't be confirmed. Double-check the address.");
|
|
96
|
+
return L.join("\n");
|
|
97
|
+
}
|
|
98
|
+
const badge = f.fresh ? "\u2705 **FRESH**" : "\u{1F6A8} **STALE**";
|
|
99
|
+
L.push(`${badge} \u2014 last written at slot ${f.lastSlot.toLocaleString()}, ${f.slotsBehind.toLocaleString()} slots (~${f.secondsBehind}s) behind the current slot (${f.currentSlot.toLocaleString()}).`);
|
|
100
|
+
L.push("");
|
|
101
|
+
L.push(`Threshold: ${f.thresholdSlots.toLocaleString()} slots. ${f.fresh ? "Within tolerance." : "**Exceeds tolerance \u2014 do not price against this feed until it updates.**"}`);
|
|
102
|
+
return L.join("\n");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
DEFAULT_STALENESS_SLOTS,
|
|
107
|
+
checkOracleFreshness,
|
|
108
|
+
renderOracleText,
|
|
109
|
+
renderOracleMd
|
|
110
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -21,13 +21,13 @@ import {
|
|
|
21
21
|
} from "./chunk-5VYTURTO.js";
|
|
22
22
|
import {
|
|
23
23
|
renderTrustGraphMd
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-QMJEZ6NO.js";
|
|
25
25
|
import {
|
|
26
26
|
buildTrustGraph,
|
|
27
27
|
cacheSize,
|
|
28
28
|
defaultCachePath,
|
|
29
29
|
loadProgramCache
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-GF37ANSW.js";
|
|
31
31
|
import {
|
|
32
32
|
audit,
|
|
33
33
|
getChangedRanges,
|
|
@@ -563,6 +563,10 @@ if (args[0] === "exploits") {
|
|
|
563
563
|
runExploits(args.slice(1));
|
|
564
564
|
process.exit(0);
|
|
565
565
|
}
|
|
566
|
+
if (args[0] === "oracle") {
|
|
567
|
+
await runOracle(args.slice(1));
|
|
568
|
+
process.exit(0);
|
|
569
|
+
}
|
|
566
570
|
if (args[0] === "fix") {
|
|
567
571
|
await runFix(args.slice(1));
|
|
568
572
|
process.exit(0);
|
|
@@ -700,6 +704,48 @@ function runDeployPlan(argv) {
|
|
|
700
704
|
writeFileSync2(mdPath, renderDeployPlanMd(plan));
|
|
701
705
|
console.log(` deploy plan: ${mdPath}`);
|
|
702
706
|
}
|
|
707
|
+
async function runOracle(argv) {
|
|
708
|
+
if (argv.includes("--help") || argv.includes("-h") || argv.filter((a) => !a.startsWith("--")).length === 0) {
|
|
709
|
+
console.log("usage: brainblast oracle <account> [--rpc URL] [--max-staleness-slots N | --max-staleness-seconds N] [--json]");
|
|
710
|
+
console.log(" Is the oracle fresh? Reports how many slots/seconds ago the price account was");
|
|
711
|
+
console.log(" last written (provider-agnostic) and gates FRESH/STALE. Exit 1 on STALE or");
|
|
712
|
+
console.log(" NO_HISTORY. Pass your own --rpc for reliable results (public RPC is rate-limited).");
|
|
713
|
+
process.exit(argv.length === 0 ? 2 : 0);
|
|
714
|
+
}
|
|
715
|
+
const { checkOracleFreshness, renderOracleText, renderOracleMd } = await import("./oracle-DVZLFJ43.js");
|
|
716
|
+
const num = (name) => {
|
|
717
|
+
const i = argv.indexOf(`--${name}`);
|
|
718
|
+
if (i < 0) return void 0;
|
|
719
|
+
const v = parseInt(argv[i + 1], 10);
|
|
720
|
+
return Number.isFinite(v) ? v : void 0;
|
|
721
|
+
};
|
|
722
|
+
const rpcIdx = argv.indexOf("--rpc");
|
|
723
|
+
const rpcUrl = rpcIdx >= 0 ? argv[rpcIdx + 1] : void 0;
|
|
724
|
+
const account = argv.find(
|
|
725
|
+
(a, i) => !a.startsWith("--") && argv[i - 1] !== "--rpc" && argv[i - 1] !== "--max-staleness-slots" && argv[i - 1] !== "--max-staleness-seconds"
|
|
726
|
+
);
|
|
727
|
+
if (!account) {
|
|
728
|
+
console.error("error: missing <account>. usage: brainblast oracle <account> [--rpc URL] [--json]");
|
|
729
|
+
process.exit(2);
|
|
730
|
+
}
|
|
731
|
+
let f;
|
|
732
|
+
try {
|
|
733
|
+
f = await checkOracleFreshness(account, {
|
|
734
|
+
rpcUrl,
|
|
735
|
+
maxStalenessSlots: num("max-staleness-slots"),
|
|
736
|
+
maxStalenessSeconds: num("max-staleness-seconds")
|
|
737
|
+
});
|
|
738
|
+
} catch (e) {
|
|
739
|
+
console.error(`error: ${e?.message ?? String(e)}`);
|
|
740
|
+
process.exit(2);
|
|
741
|
+
}
|
|
742
|
+
if (argv.includes("--json")) console.log(JSON.stringify(f, null, 2));
|
|
743
|
+
else console.log(renderOracleText(f));
|
|
744
|
+
const outDir2 = join3(process.cwd(), ".agent-research");
|
|
745
|
+
mkdirSync2(outDir2, { recursive: true });
|
|
746
|
+
writeFileSync2(join3(outDir2, "oracle-freshness.md"), renderOracleMd(f));
|
|
747
|
+
process.exit(f.fresh ? 0 : 1);
|
|
748
|
+
}
|
|
703
749
|
function runExploits(argv) {
|
|
704
750
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
705
751
|
console.log("usage: brainblast exploits [id] [--json]");
|
|
@@ -1172,8 +1218,8 @@ async function runIdlRules(argv) {
|
|
|
1172
1218
|
}
|
|
1173
1219
|
}
|
|
1174
1220
|
async function runScore(argv) {
|
|
1175
|
-
const { scoreProgram, renderScoreText, gradeAtLeast } = await import("./score-
|
|
1176
|
-
const { isValidSolanaAddress: isValidSolanaAddress2 } = await import("./trustGraph-
|
|
1221
|
+
const { scoreProgram, renderScoreText, gradeAtLeast } = await import("./score-YXFXD6QG.js");
|
|
1222
|
+
const { isValidSolanaAddress: isValidSolanaAddress2 } = await import("./trustGraph-K5PWNEL4.js");
|
|
1177
1223
|
const programId = argv.find((a) => !a.startsWith("--"));
|
|
1178
1224
|
if (!programId) {
|
|
1179
1225
|
console.error("usage: brainblast score <program-id> [--rpc URL] [--no-probe] [--min A|B|C|D|F] [--json]");
|
package/dist/index.d.ts
CHANGED
|
@@ -388,6 +388,7 @@ interface UpgradeAuthority {
|
|
|
388
388
|
address: string | null;
|
|
389
389
|
source: UpgradeAuthoritySource;
|
|
390
390
|
checkedAt?: string;
|
|
391
|
+
ownerProgram?: string;
|
|
391
392
|
}
|
|
392
393
|
type VerifiedBuildState = {
|
|
393
394
|
state: "verified";
|
|
@@ -443,6 +444,7 @@ interface RpcOpts {
|
|
|
443
444
|
|
|
444
445
|
interface BuildOpts extends RpcOpts {
|
|
445
446
|
probeRpc?: boolean;
|
|
447
|
+
classifyAuthority?: boolean;
|
|
446
448
|
directoryPath?: string;
|
|
447
449
|
cachePath?: string | null;
|
|
448
450
|
}
|
|
@@ -452,6 +454,20 @@ declare function renderTrustGraphMd(g: TrustGraph): string;
|
|
|
452
454
|
|
|
453
455
|
declare function loadDirectory(path?: string): Map<string, OnChainProgram>;
|
|
454
456
|
|
|
457
|
+
declare const SYSTEM_PROGRAM = "11111111111111111111111111111111";
|
|
458
|
+
interface KnownOwner {
|
|
459
|
+
kind: Exclude<UpgradeAuthorityKind, "renounced">;
|
|
460
|
+
label: string;
|
|
461
|
+
}
|
|
462
|
+
declare const KNOWN_AUTHORITY_OWNERS: Record<string, KnownOwner>;
|
|
463
|
+
interface AuthorityClassification {
|
|
464
|
+
kind: UpgradeAuthorityKind;
|
|
465
|
+
ownerProgram?: string;
|
|
466
|
+
ownerLabel?: string;
|
|
467
|
+
}
|
|
468
|
+
declare function classifyUpgradeAuthority(address: string, opts?: RpcOpts): Promise<AuthorityClassification>;
|
|
469
|
+
declare function enrichAuthorityClassification(authority: UpgradeAuthority, opts?: RpcOpts): Promise<UpgradeAuthority>;
|
|
470
|
+
|
|
455
471
|
declare function base58Encode(bytes: Uint8Array): string;
|
|
456
472
|
declare function base58Decode(s: string): Uint8Array;
|
|
457
473
|
declare function isValidSolanaAddress(s: string): boolean;
|
|
@@ -876,6 +892,32 @@ declare function batchScan(mints: string[], opts?: BatchScanOpts): Promise<Batch
|
|
|
876
892
|
declare function parseMintList(content: string): string[];
|
|
877
893
|
declare function renderBatchText(result: BatchResult): string;
|
|
878
894
|
|
|
895
|
+
declare const DEFAULT_STALENESS_SLOTS = 150;
|
|
896
|
+
type OracleVerdict = "FRESH" | "STALE" | "NO_HISTORY";
|
|
897
|
+
interface OracleFreshness {
|
|
898
|
+
account: string;
|
|
899
|
+
currentSlot: number;
|
|
900
|
+
/** Slot of the most recent signature touching the account; null if none. */
|
|
901
|
+
lastSlot: number | null;
|
|
902
|
+
/** Unix seconds of that signature's block, when the RPC provides it. */
|
|
903
|
+
lastBlockTime: number | null;
|
|
904
|
+
slotsBehind: number | null;
|
|
905
|
+
secondsBehind: number | null;
|
|
906
|
+
thresholdSlots: number;
|
|
907
|
+
fresh: boolean;
|
|
908
|
+
verdict: OracleVerdict;
|
|
909
|
+
checkedAt: string;
|
|
910
|
+
}
|
|
911
|
+
interface OracleOpts extends RpcOpts {
|
|
912
|
+
/** Staleness threshold in slots (default 150 ≈ 60s). */
|
|
913
|
+
maxStalenessSlots?: number;
|
|
914
|
+
/** Staleness threshold in seconds; converted to slots (~400ms each). */
|
|
915
|
+
maxStalenessSeconds?: number;
|
|
916
|
+
}
|
|
917
|
+
declare function checkOracleFreshness(account: string, opts?: OracleOpts): Promise<OracleFreshness>;
|
|
918
|
+
declare function renderOracleText(f: OracleFreshness): string;
|
|
919
|
+
declare function renderOracleMd(f: OracleFreshness): string;
|
|
920
|
+
|
|
879
921
|
interface ExploitPattern {
|
|
880
922
|
/** Stable slug, e.g. "wormhole". */
|
|
881
923
|
id: string;
|
|
@@ -905,4 +947,4 @@ declare function renderExploitsMd(patterns?: ExploitPattern[]): string;
|
|
|
905
947
|
declare function renderExploitsText(patterns?: ExploitPattern[]): string;
|
|
906
948
|
declare function renderExploitDetailText(e: ExploitPattern): string;
|
|
907
949
|
|
|
908
|
-
export { type AccountFlow, type AnchorIdl, type AuditRef, type BatchResult, type BatchRow, type BatchScanOpts, type BuildOpts, CANONICAL_BY_MINT, CANONICAL_MINTS, type Candidate, type CanonicalMint, type ChainEvent, type ChainWatchOpts, type ChainWatchState, type ChangedRanges, type CheckOutcome, type CheckResult, type CheckResultKind, type Checker, type ConfigCandidate, type ConfigChecker, type CostReport, DEFAULT_REGISTRY_URL, DEFAULT_TTL_HOURS, type DecodedInstruction, type DecodedTx, type DiffResult, type DriftAdvisory, type DriftBaseline, type DriftPackage, type DriftResult, EXPLOIT_PATTERNS, type ExploitPattern, type FirewallFinding, type FirewallOpts, type FirewallProgram, type FirewallReport, type FirewallSeverity, type FirewallVerdict, type Grade, type GraduationEvent, type IdentityStatus, type IdlAccount, type IdlConstraintParams, type IdlInstruction, KNOWN_PROGRAMS, type MintInfo, type OnChainProgram, type OsvAdvisory, PACK_MANIFEST_FILE, type PackInitOptions, type PackManifest, type PackRuleValidation, type PackValidateResult, type ParityNote, type ParsedDiff, type PreflightCheck, type PreflightOpts, type PreflightReport, type PreflightStatus, type PreflightVerdict, type PriorityFeePosture, type ProgramCache, type ProgramCacheEntry, type Recoverability, type RicoOutcome, type RicoResult, type RicoTokenSecurity, type Rule, type RustAccountField, type RustCandidate, type RustChecker, type ScoreFactor, type Severity, type TelemetrySubmitResult, type TokenIdentity, type TrustGraph, type TrustScore, type UpgradeAuthority, type UpgradeAuthorityKind, type UpgradeAuthoritySource, type VerifiedBuildState, type VerifyOpts, type WatchEvent, type WatchOptions, analyzeCosts, analyzeInstructions, analyzeToken, applyDiffToFile, audit, auditWithRule, base58Decode, base58Encode, batchScan, buildConstraintParams, buildTrustGraph, rules as bundledRules, cacheSize, canonicalMintForSymbol, checkDrift, checkerKinds, decodeTransaction, defaultCachePath, deployerFlagsFrom, diffVersions, fileChanged, findCandidates, findConfigCandidates, formatUsd, generateRulesFromIdl, generateTestForResult, getCacheEntry, getCacheEntryMeta, getChangedRanges, getExploitPattern, getRepoHash, getUserHash, getWorkingTreeChanges, gradeAtLeast, gradeForScore, idlProgramName, initPack, initialChainWatchState, inspectTransaction, isCanonicalMint, isEntryExpired, isTelemetryEnabled, isValidSolanaAddress, lamportsToSol, loadDirectory, loadPack, loadPacksFromDir, loadProgramCache, loadRules, parseCpiPrograms, parseDiff, parseIdl, parseMintAccount, parseMintList, pollChainOnce, pumpPreflight, putCacheEntry, queryOsv, rangeChanged, recordGraduationEvents, renderBatchText, renderCostReportMd, renderDiffMd, renderDiffText, renderDriftText, renderExploitDetailText, renderExploitsMd, renderExploitsText, renderFirewallText, renderPreflightText, renderRicoText, renderRulesYaml, renderScoreText, renderTest, renderTrustGraphMd, rentExemptMinimum, resolveRules, riskScore, runChecker, runIncrementalScan, saveProgramCache, scoreFromProgram, scoreProgram, seedPackages, startChainWatch, startWatch, submitTelemetry, telemetryFilePath, testKinds, toSnakeCase, totalLossUsd, validatePack, validatePackManifest, verifyTokenIdentity };
|
|
950
|
+
export { type AccountFlow, type AnchorIdl, type AuditRef, type AuthorityClassification, type BatchResult, type BatchRow, type BatchScanOpts, type BuildOpts, CANONICAL_BY_MINT, CANONICAL_MINTS, type Candidate, type CanonicalMint, type ChainEvent, type ChainWatchOpts, type ChainWatchState, type ChangedRanges, type CheckOutcome, type CheckResult, type CheckResultKind, type Checker, type ConfigCandidate, type ConfigChecker, type CostReport, DEFAULT_REGISTRY_URL, DEFAULT_STALENESS_SLOTS, DEFAULT_TTL_HOURS, type DecodedInstruction, type DecodedTx, type DiffResult, type DriftAdvisory, type DriftBaseline, type DriftPackage, type DriftResult, EXPLOIT_PATTERNS, type ExploitPattern, type FirewallFinding, type FirewallOpts, type FirewallProgram, type FirewallReport, type FirewallSeverity, type FirewallVerdict, type Grade, type GraduationEvent, type IdentityStatus, type IdlAccount, type IdlConstraintParams, type IdlInstruction, KNOWN_AUTHORITY_OWNERS, KNOWN_PROGRAMS, type MintInfo, type OnChainProgram, type OracleFreshness, type OracleOpts, type OracleVerdict, type OsvAdvisory, PACK_MANIFEST_FILE, type PackInitOptions, type PackManifest, type PackRuleValidation, type PackValidateResult, type ParityNote, type ParsedDiff, type PreflightCheck, type PreflightOpts, type PreflightReport, type PreflightStatus, type PreflightVerdict, type PriorityFeePosture, type ProgramCache, type ProgramCacheEntry, type Recoverability, type RicoOutcome, type RicoResult, type RicoTokenSecurity, type Rule, type RustAccountField, type RustCandidate, type RustChecker, SYSTEM_PROGRAM, type ScoreFactor, type Severity, type TelemetrySubmitResult, type TokenIdentity, type TrustGraph, type TrustScore, type UpgradeAuthority, type UpgradeAuthorityKind, type UpgradeAuthoritySource, type VerifiedBuildState, type VerifyOpts, type WatchEvent, type WatchOptions, analyzeCosts, analyzeInstructions, analyzeToken, applyDiffToFile, audit, auditWithRule, base58Decode, base58Encode, batchScan, buildConstraintParams, buildTrustGraph, rules as bundledRules, cacheSize, canonicalMintForSymbol, checkDrift, checkOracleFreshness, checkerKinds, classifyUpgradeAuthority, decodeTransaction, defaultCachePath, deployerFlagsFrom, diffVersions, enrichAuthorityClassification, fileChanged, findCandidates, findConfigCandidates, formatUsd, generateRulesFromIdl, generateTestForResult, getCacheEntry, getCacheEntryMeta, getChangedRanges, getExploitPattern, getRepoHash, getUserHash, getWorkingTreeChanges, gradeAtLeast, gradeForScore, idlProgramName, initPack, initialChainWatchState, inspectTransaction, isCanonicalMint, isEntryExpired, isTelemetryEnabled, isValidSolanaAddress, lamportsToSol, loadDirectory, loadPack, loadPacksFromDir, loadProgramCache, loadRules, parseCpiPrograms, parseDiff, parseIdl, parseMintAccount, parseMintList, pollChainOnce, pumpPreflight, putCacheEntry, queryOsv, rangeChanged, recordGraduationEvents, renderBatchText, renderCostReportMd, renderDiffMd, renderDiffText, renderDriftText, renderExploitDetailText, renderExploitsMd, renderExploitsText, renderFirewallText, renderOracleMd, renderOracleText, renderPreflightText, renderRicoText, renderRulesYaml, renderScoreText, renderTest, renderTrustGraphMd, rentExemptMinimum, resolveRules, riskScore, runChecker, runIncrementalScan, saveProgramCache, scoreFromProgram, scoreProgram, seedPackages, startChainWatch, startWatch, submitTelemetry, telemetryFilePath, testKinds, toSnakeCase, totalLossUsd, validatePack, validatePackManifest, verifyTokenIdentity };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_STALENESS_SLOTS,
|
|
3
|
+
checkOracleFreshness,
|
|
4
|
+
renderOracleMd,
|
|
5
|
+
renderOracleText
|
|
6
|
+
} from "./chunk-WQFLKWBY.js";
|
|
1
7
|
import {
|
|
2
8
|
checkDrift,
|
|
3
9
|
renderDriftText,
|
|
@@ -17,7 +23,7 @@ import {
|
|
|
17
23
|
renderScoreText,
|
|
18
24
|
scoreFromProgram,
|
|
19
25
|
scoreProgram
|
|
20
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-F7QOW3IM.js";
|
|
21
27
|
import {
|
|
22
28
|
parseMintAccount,
|
|
23
29
|
pumpPreflight,
|
|
@@ -64,12 +70,16 @@ import {
|
|
|
64
70
|
} from "./chunk-5VYTURTO.js";
|
|
65
71
|
import {
|
|
66
72
|
renderTrustGraphMd
|
|
67
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-QMJEZ6NO.js";
|
|
68
74
|
import {
|
|
69
75
|
DEFAULT_TTL_HOURS,
|
|
76
|
+
KNOWN_AUTHORITY_OWNERS,
|
|
77
|
+
SYSTEM_PROGRAM,
|
|
70
78
|
buildTrustGraph,
|
|
71
79
|
cacheSize,
|
|
80
|
+
classifyUpgradeAuthority,
|
|
72
81
|
defaultCachePath,
|
|
82
|
+
enrichAuthorityClassification,
|
|
73
83
|
getCacheEntry,
|
|
74
84
|
getCacheEntryMeta,
|
|
75
85
|
isEntryExpired,
|
|
@@ -77,7 +87,7 @@ import {
|
|
|
77
87
|
loadProgramCache,
|
|
78
88
|
putCacheEntry,
|
|
79
89
|
saveProgramCache
|
|
80
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-GF37ANSW.js";
|
|
81
91
|
import {
|
|
82
92
|
PACK_MANIFEST_FILE,
|
|
83
93
|
audit,
|
|
@@ -150,10 +160,13 @@ export {
|
|
|
150
160
|
CANONICAL_BY_MINT,
|
|
151
161
|
CANONICAL_MINTS,
|
|
152
162
|
DEFAULT_REGISTRY_URL,
|
|
163
|
+
DEFAULT_STALENESS_SLOTS,
|
|
153
164
|
DEFAULT_TTL_HOURS,
|
|
154
165
|
EXPLOIT_PATTERNS,
|
|
166
|
+
KNOWN_AUTHORITY_OWNERS,
|
|
155
167
|
KNOWN_PROGRAMS,
|
|
156
168
|
PACK_MANIFEST_FILE,
|
|
169
|
+
SYSTEM_PROGRAM,
|
|
157
170
|
analyzeCosts,
|
|
158
171
|
analyzeInstructions,
|
|
159
172
|
analyzeToken,
|
|
@@ -169,11 +182,14 @@ export {
|
|
|
169
182
|
cacheSize,
|
|
170
183
|
canonicalMintForSymbol,
|
|
171
184
|
checkDrift,
|
|
185
|
+
checkOracleFreshness,
|
|
172
186
|
checkerKinds,
|
|
187
|
+
classifyUpgradeAuthority,
|
|
173
188
|
decodeTransaction,
|
|
174
189
|
defaultCachePath,
|
|
175
190
|
deployerFlagsFrom,
|
|
176
191
|
diffVersions,
|
|
192
|
+
enrichAuthorityClassification,
|
|
177
193
|
fileChanged,
|
|
178
194
|
findCandidates,
|
|
179
195
|
findConfigCandidates,
|
|
@@ -223,6 +239,8 @@ export {
|
|
|
223
239
|
renderExploitsMd,
|
|
224
240
|
renderExploitsText,
|
|
225
241
|
renderFirewallText,
|
|
242
|
+
renderOracleMd,
|
|
243
|
+
renderOracleText,
|
|
226
244
|
renderPreflightText,
|
|
227
245
|
renderRicoText,
|
|
228
246
|
renderRulesYaml,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_STALENESS_SLOTS,
|
|
3
|
+
checkOracleFreshness,
|
|
4
|
+
renderOracleMd,
|
|
5
|
+
renderOracleText
|
|
6
|
+
} from "./chunk-WQFLKWBY.js";
|
|
7
|
+
import "./chunk-XSVQSK53.js";
|
|
8
|
+
import "./chunk-VG5FMOLW.js";
|
|
9
|
+
import "./chunk-3RG5ZIWI.js";
|
|
10
|
+
export {
|
|
11
|
+
DEFAULT_STALENESS_SLOTS,
|
|
12
|
+
checkOracleFreshness,
|
|
13
|
+
renderOracleMd,
|
|
14
|
+
renderOracleText
|
|
15
|
+
};
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
renderScoreText,
|
|
5
5
|
scoreFromProgram,
|
|
6
6
|
scoreProgram
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-F7QOW3IM.js";
|
|
8
|
+
import "./chunk-GF37ANSW.js";
|
|
9
9
|
import "./chunk-XSVQSK53.js";
|
|
10
10
|
import "./chunk-VG5FMOLW.js";
|
|
11
11
|
import "./chunk-3RG5ZIWI.js";
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
renderProgram,
|
|
3
3
|
renderTrustGraphMd
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QMJEZ6NO.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_TTL_HOURS,
|
|
7
|
+
KNOWN_AUTHORITY_OWNERS,
|
|
8
|
+
SYSTEM_PROGRAM,
|
|
7
9
|
buildTrustGraph,
|
|
8
10
|
cacheSize,
|
|
11
|
+
classifyUpgradeAuthority,
|
|
9
12
|
defaultCachePath,
|
|
13
|
+
enrichAuthorityClassification,
|
|
10
14
|
getCacheEntry,
|
|
11
15
|
getCacheEntryMeta,
|
|
12
16
|
isEntryExpired,
|
|
@@ -14,7 +18,7 @@ import {
|
|
|
14
18
|
loadProgramCache,
|
|
15
19
|
putCacheEntry,
|
|
16
20
|
saveProgramCache
|
|
17
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GF37ANSW.js";
|
|
18
22
|
import {
|
|
19
23
|
DEFAULT_RPC,
|
|
20
24
|
getAccountInfo,
|
|
@@ -29,11 +33,15 @@ import "./chunk-3RG5ZIWI.js";
|
|
|
29
33
|
export {
|
|
30
34
|
DEFAULT_RPC,
|
|
31
35
|
DEFAULT_TTL_HOURS,
|
|
36
|
+
KNOWN_AUTHORITY_OWNERS,
|
|
37
|
+
SYSTEM_PROGRAM,
|
|
32
38
|
base58Decode,
|
|
33
39
|
base58Encode,
|
|
34
40
|
buildTrustGraph,
|
|
35
41
|
cacheSize,
|
|
42
|
+
classifyUpgradeAuthority,
|
|
36
43
|
defaultCachePath,
|
|
44
|
+
enrichAuthorityClassification,
|
|
37
45
|
getAccountInfo,
|
|
38
46
|
getCacheEntry,
|
|
39
47
|
getCacheEntryMeta,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brainblast",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deterministic auditor for catastrophic AI-integration bugs: scan a repo, find the silent money/auth traps, and generate the behavioral test that proves they're fixed.",
|
|
6
6
|
"keywords": [
|