sememe 0.0.0-stage → 0.4.21

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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2667 -2
  3. package/bin/sememe.mjs +556 -0
  4. package/index.mjs +48 -0
  5. package/interface/ata-ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL.json +62 -0
  6. package/interface/native-11111111111111111111111111111111.json +226 -0
  7. package/interface/native-ComputeBudget111111111111111111111111111111.json +72 -0
  8. package/interface/raydium-675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8.json +352 -0
  9. package/interface/token-TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.json +334 -0
  10. package/interface/token-TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb.json +535 -0
  11. package/interface/token-metadata.json +132 -0
  12. package/package.json +71 -4
  13. package/src/account-list.mjs +308 -0
  14. package/src/account-union.mjs +523 -0
  15. package/src/account.mjs +199 -0
  16. package/src/acquire.mjs +145 -0
  17. package/src/adopt.mjs +205 -0
  18. package/src/ata-interface.mjs +276 -0
  19. package/src/ata.mjs +223 -0
  20. package/src/base58.mjs +96 -0
  21. package/src/canonical.mjs +24 -0
  22. package/src/cli-surface.mjs +300 -0
  23. package/src/codec.mjs +1069 -0
  24. package/src/conformance.mjs +431 -0
  25. package/src/corpus/harvest-compute-budget-2026-10-31.json +19122 -0
  26. package/src/corpus/harvest-system-2026-10-31.json +26090 -0
  27. package/src/decode.mjs +286 -0
  28. package/src/dialect.mjs +145 -0
  29. package/src/discriminators.mjs +177 -0
  30. package/src/drift.mjs +172 -0
  31. package/src/gap.mjs +205 -0
  32. package/src/lighthouse.mjs +168 -0
  33. package/src/lock.mjs +440 -0
  34. package/src/native-audit.mjs +56 -0
  35. package/src/native-corpus.mjs +57 -0
  36. package/src/native-interface.mjs +252 -0
  37. package/src/native.mjs +324 -0
  38. package/src/peer.mjs +95 -0
  39. package/src/program-id.mjs +74 -0
  40. package/src/pull.mjs +117 -0
  41. package/src/rawle.mjs +450 -0
  42. package/src/raydium-interface.mjs +747 -0
  43. package/src/raydium.mjs +391 -0
  44. package/src/receipt-digest.mjs +84 -0
  45. package/src/receipt-name.mjs +128 -0
  46. package/src/receipt-order.mjs +56 -0
  47. package/src/shank.mjs +73 -0
  48. package/src/short-forms.mjs +209 -0
  49. package/src/store-read.mjs +250 -0
  50. package/src/store-write.mjs +46 -0
  51. package/src/token-interface.mjs +394 -0
  52. package/src/token-metadata-interface.mjs +371 -0
  53. package/src/token-metadata.mjs +317 -0
  54. package/src/token.mjs +443 -0
  55. package/src/union.mjs +428 -0
  56. package/vendor/anza-solana-sdk/8db406e2edfafa25939ec782b77b5b6f30de164d/LICENSE.txt +201 -0
  57. package/vendor/anza-solana-sdk/8db406e2edfafa25939ec782b77b5b6f30de164d/compute-budget-interface/src/lib.rs +93 -0
  58. package/vendor/anza-solana-sdk/8db406e2edfafa25939ec782b77b5b6f30de164d/system-interface/src/instruction.rs +1899 -0
  59. package/vendor/lighthouse/4c579479c98635e419b1b167f08be02a71604a71/LICENSE +21 -0
  60. package/vendor/lighthouse/4c579479c98635e419b1b167f08be02a71604a71/lighthouse.json +2769 -0
  61. package/vendor/raydium-amm/91739d8d9f5cf347e0ce14ebe4d2bb7069fb31b6/LICENSE +201 -0
  62. package/vendor/raydium-amm/91739d8d9f5cf347e0ce14ebe4d2bb7069fb31b6/program/src/instruction.rs +1189 -0
  63. package/vendor/raydium-amm/91739d8d9f5cf347e0ce14ebe4d2bb7069fb31b6/program/src/state.rs +1348 -0
  64. package/vendor/spl-associated-token-account/fbf5379e7398ac8b231c73ee8a9ff677b43dd0ec/LICENSE +201 -0
  65. package/vendor/spl-associated-token-account/fbf5379e7398ac8b231c73ee8a9ff677b43dd0ec/interface/src/instruction.rs +169 -0
  66. package/vendor/spl-associated-token-account/fbf5379e7398ac8b231c73ee8a9ff677b43dd0ec/interface/src/lib.rs +12 -0
  67. package/vendor/spl-associated-token-account/fbf5379e7398ac8b231c73ee8a9ff677b43dd0ec/program/src/processor.rs +308 -0
  68. package/vendor/spl-token/737788ff5bcc3f1f44cfb222f25483187650be76/LICENSE.txt +176 -0
  69. package/vendor/spl-token/737788ff5bcc3f1f44cfb222f25483187650be76/interface/src/instruction.rs +1963 -0
  70. package/vendor/spl-token-2022/5251dcc07ecbcb721d6c4f0231090defadf00311/LICENSE.txt +176 -0
  71. package/vendor/spl-token-2022/5251dcc07ecbcb721d6c4f0231090defadf00311/interface/src/instruction.rs +2868 -0
  72. package/vendor/spl-token-metadata-interface/7038969ec74a89f1afdb9bc97c112d4d26fead9a/LICENSE +201 -0
  73. package/vendor/spl-token-metadata-interface/7038969ec74a89f1afdb9bc97c112d4d26fead9a/interface/src/error.rs +58 -0
  74. package/vendor/spl-token-metadata-interface/7038969ec74a89f1afdb9bc97c112d4d26fead9a/interface/src/instruction.rs +596 -0
  75. package/vendor/spl-token-metadata-interface/7038969ec74a89f1afdb9bc97c112d4d26fead9a/interface/src/lib.rs +21 -0
  76. package/vendor/spl-token-metadata-interface/7038969ec74a89f1afdb9bc97c112d4d26fead9a/interface/src/state.rs +229 -0
package/package.json CHANGED
@@ -1,6 +1,73 @@
1
1
  {
2
2
  "name": "sememe",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.4.21",
4
+ "description": "Local, fingerprint-verified Solana program interfaces: pull an IDL once, then decode instructions, accounts and events offline. Zero dependencies on the decode path. Ships derived wire tables for System, ComputeBudget, SPL Token, Token-2022 (incl. its token-metadata fallback), Raydium AMM v4 and the SPL Associated Token Account, pinned to upstream Rust.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./index.mjs",
8
+ "bin": {
9
+ "sememe": "bin/sememe.mjs"
10
+ },
11
+ "exports": {
12
+ ".": "./index.mjs",
13
+ "./native": "./src/native.mjs",
14
+ "./store": "./src/store-read.mjs",
15
+ "./pull": "./src/pull.mjs",
16
+ "./codec": "./src/codec.mjs",
17
+ "./canonical": "./src/canonical.mjs",
18
+ "./discriminators": "./src/discriminators.mjs",
19
+ "./native-corpus": "./src/native-corpus.mjs",
20
+ "./native-audit": "./src/native-audit.mjs",
21
+ "./package.json": "./package.json",
22
+ "./token": "./src/token.mjs",
23
+ "./token-metadata": "./src/token-metadata.mjs",
24
+ "./raydium": "./src/raydium.mjs",
25
+ "./ata": "./src/ata.mjs",
26
+ "./lighthouse": "./src/lighthouse.mjs",
27
+ "./gap": "./src/gap.mjs"
28
+ },
29
+ "files": [
30
+ "index.mjs",
31
+ "src/",
32
+ "interface/",
33
+ "vendor/",
34
+ "bin/",
35
+ "LICENSE",
36
+ "README.md"
37
+ ],
38
+ "scripts": {
39
+ "test": "node --test",
40
+ "crosscheck": "node tools/crosscheck.mjs",
41
+ "txdiff": "node tools/tx-diff.mjs",
42
+ "harvest": "node tools/harvest.mjs",
43
+ "tail-hypotheses": "node tools/tail-hypotheses.mjs",
44
+ "tail-structure": "node tools/tail-structure.mjs"
45
+ },
46
+ "peerDependencies": {
47
+ "@solana/web3.js": "^1.98.4"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "@solana/web3.js": {
51
+ "optional": true
52
+ }
53
+ },
54
+ "devDependencies": {
55
+ "@solana/web3.js": "1.98.4"
56
+ },
57
+ "engines": {
58
+ "node": ">=20"
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/auroraxo/sememe.git"
63
+ },
64
+ "keywords": [
65
+ "solana",
66
+ "anchor",
67
+ "idl",
68
+ "decoder",
69
+ "borsh",
70
+ "offline",
71
+ "instruction-decoding"
72
+ ]
73
+ }
@@ -0,0 +1,308 @@
1
+ // Account-list conformance: the DECLARED interface against the accounts a
2
+ // transaction actually passed.
3
+ //
4
+ // Why this file exists: everything else sememe verifies is BYTES. But a
5
+ // Solana instruction is bytes AND an account list, and the account list has
6
+ // its own defect class, measured on live mainnet traffic of a foreign
7
+ // first-party program (jup-ag order_engine, reported as
8
+ // jup-ag/rfq-webhook-toolkit#96): the published interface declared 11
9
+ // accounts while every observed `fill` carried 12 or 13 — and the extra
10
+ // account at the end SIGNS every fill and pays the fee in 31/141. A consumer
11
+ // that builds its signer/authority reasoning from the interface alone is
12
+ // blind to an account that signs.
13
+ //
14
+ // So this module answers one question, offline, from the same verified
15
+ // store the decoder uses:
16
+ //
17
+ // Given an instruction of a stored IDL and the account list one
18
+ // transaction passed to it, does the interface describe that list?
19
+ //
20
+ // Verdicts (ordered by severity, first match wins):
21
+ // missing-declared-accounts the wire carries FEWER accounts than the
22
+ // interface declares non-optional positions
23
+ // for. The program cannot have accepted it.
24
+ // declared-signer-not-signing the interface says position k is a signer;
25
+ // the transaction does not have it signing.
26
+ // For a SUCCESSFUL transaction this is
27
+ // interface/wire disagreement, not a rule the
28
+ // program applied.
29
+ // fixed-address-mismatch the interface pins an address (e.g.
30
+ // system_program); the wire passed another.
31
+ // undeclared-signing-account the wire carries accounts beyond the
32
+ // declared list AND one of them signs: an
33
+ // authority the interface does not name. This
34
+ // is the finding class this file was built
35
+ // for.
36
+ // unknown-instruction the instruction name is not in the IDL.
37
+ //
38
+ // Informational, never a violation on their own:
39
+ // remaining-accounts extras beyond the declared list that do NOT
40
+ // sign — Anchor's remaining_accounts is a
41
+ // legitimate, very common pattern.
42
+ // signer-at-non-signer-position the interface does not declare a position
43
+ // as a signer but the account signed anyway
44
+ // (the fee payer sits in exactly this
45
+ // position often). Signing MORE than declared
46
+ // is harmless; signing LESS is not.
47
+ //
48
+ // Limits, stated with the code because they change what a verdict means:
49
+ // - An observed position whose signer status cannot be determined (no
50
+ // message header, mangled encoding) is recorded as `unknownSigner`
51
+ // and never produces a signer verdict in either direction: absence of
52
+ // evidence must not become evidence of absence.
53
+ // - Optional accounts: Anchor's own wire shape keeps a placeholder for an
54
+ // absent optional account, so a SHORT list whose missing tail is all
55
+ // optional is reported as `short-optional-tail` (informational), not as
56
+ // a missing-account violation. Which Anchor version a program was built
57
+ // with is not in the IDL, so this stays a separate verdict rather than
58
+ // being folded into `conforms`.
59
+ // - Writable-flag mismatches are reported per position (`writableNotes`)
60
+ // but never decide the verdict: the runtime grants/revokes permission
61
+ // from the transaction, not from the IDL, so an IDL that disagrees
62
+ // about writability is documentation drift, not an acceptance bug.
63
+ // - This checks ONE instruction against ONE transaction. It does not
64
+ // prove the program accepted anything (that is `txErr`, carried by the
65
+ // caller), and it does not prove the interface is wrong rather than the
66
+ // transaction: it names the disagreement.
67
+
68
+ /** The declared account list of an instruction, normalized from either IDL
69
+ * spec (new: signer/writable/optional; legacy: isSigner/isMut/isOptional).
70
+ * The optional flag is load-bearing for conformance: a declared-OPTIONAL
71
+ * signer that arrives without a signature is the account being absent, not
72
+ * a rule violation (measured on OpenBook v2's `cancelAllAndPlaceOrders`,
73
+ * whose legacy IDL marks `openOrdersAdmin` isOptional+isSigner and whose
74
+ * live traffic passes it unsigned whenever the admin is not needed). */
75
+ export function declaredAccounts(instruction) {
76
+ if (!instruction || !Array.isArray(instruction.accounts)) return null;
77
+ return instruction.accounts.map((entry, index) => ({
78
+ index,
79
+ name: entry?.name ?? null,
80
+ signer: Boolean(entry?.signer ?? entry?.isSigner),
81
+ writable: Boolean(entry?.writable ?? entry?.isMut),
82
+ optional: Boolean(entry?.optional ?? entry?.isOptional),
83
+ address: typeof entry?.address === 'string' ? entry.address : null,
84
+ }));
85
+ }
86
+
87
+ /** Match payload bytes to an IDL instruction by its 8-byte discriminator
88
+ * (stored or derived by Anchor's rule). Returns null when no instruction
89
+ * carries these bytes. */
90
+ export function instructionByDiscriminator(idl, discriminatorBytes) {
91
+ if (!idl || !Array.isArray(discriminatorBytes) || discriminatorBytes.length !== 8) return null;
92
+ const instructions = idl.instructions ?? [];
93
+ const match = instructions.find((entry) => {
94
+ const stored = Array.isArray(entry?.discriminator) ? entry.discriminator : null;
95
+ if (!stored || stored.length !== discriminatorBytes.length) return false;
96
+ return stored.every((byte, index) => byte === discriminatorBytes[index]);
97
+ });
98
+ return match ?? null;
99
+ }
100
+
101
+ /**
102
+ * Compare one instruction's declared account list with one observed list.
103
+ *
104
+ * @param {object} instruction IDL instruction (may be null -> unknown-instruction)
105
+ * @param {Array} observed [{ address, signer?, writable? }] in wire
106
+ * order; `signer` true/false or absent.
107
+ * * @param {object} [options]
108
+ * @param {string} [options.program] program id, echoed into the verdict
109
+ * @param {string} [options.programId] program id of the instruction — when a
110
+ * DECLARED OPTIONAL position carries this
111
+ * address, Anchor's convention marks the
112
+ * account as ABSENT (the None placeholder
113
+ * is the program's own id). An absent
114
+ * optional account is not a signer and not
115
+ * a disagreement.
116
+ * @param {string} [options.name] instruction name if `instruction` is null
117
+ * @param {boolean} [options.executed] whether the transaction succeeded
118
+ * (meta.err == null). A failed transaction
119
+ * may have been rejected FOR one of these
120
+ * reasons; the verdict is tagged, not
121
+ * downgraded.
122
+ * @param {number} [options.depth] instruction call depth (0 = top-level,
123
+ * >0 = CPI). At depth > 0 the signer flag of
124
+ * an account is NOT observable from the
125
+ * top-level message header: the account may
126
+ * be a PDA signed for inside the CPI stack
127
+ * via `invoke_signed`, which never appears in
128
+ * `numRequiredSignatures` (measured on
129
+ * Whirlpool swap_v2 invoked via CPI by the
130
+ * Titan router). Such a position is reported
131
+ * as an informational note, never as a
132
+ * signature violation; at depth 0 the header
133
+ * IS the authority and the check stands.
134
+ */
135
+ export function checkAccountList(instruction, observed, options = {}) {
136
+ const { program = null, programId = null, name = null, executed = null, depth = 0 } = options;
137
+ const base = { program, instruction: instruction?.name ?? name ?? null, executed, positions: { declared: null, observed: observed?.length ?? 0 } };
138
+
139
+ if (!instruction) {
140
+ return { ...base, verdict: 'unknown-instruction', violations: [], extras: [], notes: [] };
141
+ }
142
+ const declared = declaredAccounts(instruction);
143
+ if (!declared) {
144
+ return { ...base, verdict: 'unknown-instruction', violations: [], extras: [], notes: [] };
145
+ }
146
+
147
+ const rows = observed ?? [];
148
+ const violations = [];
149
+ const notes = [];
150
+ const unknownSigner = [];
151
+
152
+ base.positions.declared = declared.length;
153
+ base.positions.required = declared.filter((entry) => !entry.optional).length;
154
+
155
+ // 1. Length: short lists, optional tails, extras.
156
+ let extras = [];
157
+ if (rows.length < declared.length) {
158
+ const missing = declared.slice(rows.length);
159
+ const missingNonOptional = missing.filter((entry) => !entry.optional);
160
+ if (missingNonOptional.length) {
161
+ violations.push({
162
+ kind: 'missing-declared-accounts',
163
+ missing: missing.map((entry) => ({ index: entry.index, name: entry.name, optional: entry.optional })),
164
+ });
165
+ } else {
166
+ notes.push({
167
+ kind: 'short-optional-tail',
168
+ missing: missing.map((entry) => ({ index: entry.index, name: entry.name })),
169
+ });
170
+ }
171
+ } else {
172
+ extras = rows.slice(declared.length).map((entry, offset) => ({
173
+ index: declared.length + offset,
174
+ address: entry?.address ?? null,
175
+ signer: entry?.signer ?? null,
176
+ writable: entry?.writable ?? null,
177
+ }));
178
+ }
179
+
180
+ // 2. Positional signer comparison over the declared range.
181
+ const limit = Math.min(declared.length, rows.length);
182
+ const writableNotes = [];
183
+ const absentOptional = [];
184
+ for (let index = 0; index < limit; index++) {
185
+ const want = declared[index];
186
+ const got = rows[index] ?? {};
187
+ const signerKnown = got.signer === true || got.signer === false;
188
+
189
+ // Anchor's absent-optional placeholder: the declared optional position
190
+ // carries the program's own id, which means "None" — not "this account".
191
+ // Comparing its signer flag would manufacture a violation out of the
192
+ // convention that avoids one.
193
+ //
194
+ // A declared-OPTIONAL signer that arrives without a signature is ALSO an
195
+ // absent optional account (Anchor lets the caller pass the program id or
196
+ // any non-signing placeholder when the signer is optional and absent;
197
+ // measured on OpenBook v2 `cancelAllAndPlaceOrders.openOrdersAdmin`).
198
+ const placeholder = want.optional && (
199
+ (programId && got.address === programId) || (want.signer && got.signer === false)
200
+ );
201
+ if (placeholder) {
202
+ absentOptional.push({ index, name: want.name, signer: want.signer });
203
+ continue;
204
+ }
205
+
206
+ if (!signerKnown) {
207
+ unknownSigner.push({ index, name: want.name, declaredSigner: want.signer });
208
+ } else if (want.signer && got.signer === false) {
209
+ // At depth > 0 the signer flag cannot be resolved from the top-level
210
+ // header: the declaring position may be a PDA signed inside the CPI
211
+ // stack via `invoke_signed`, which never shows in
212
+ // `numRequiredSignatures`. Treating it as a violation would be a false
213
+ // positive from measuring the wrong boundary.
214
+ if (depth > 0) {
215
+ notes.push({
216
+ kind: 'cpi-signer-not-observable',
217
+ index, name: want.name, depth,
218
+ reason: 'the top-level message header does not carry CPI signer authority (invoke_signed PDAs)',
219
+ });
220
+ } else {
221
+ violations.push({
222
+ kind: 'declared-signer-not-signing',
223
+ index, name: want.name,
224
+ });
225
+ }
226
+ } else if (!want.signer && got.signer === true) {
227
+ notes.push({ kind: 'signer-at-non-signer-position', index, name: want.name });
228
+ }
229
+
230
+ if (want.address && got.address && want.address !== got.address) {
231
+ violations.push({
232
+ kind: 'fixed-address-mismatch',
233
+ index, name: want.name, declared: want.address, observed: got.address,
234
+ });
235
+ }
236
+
237
+ if (typeof got.writable === 'boolean' && got.writable !== want.writable) {
238
+ writableNotes.push({ index, name: want.name, declaredWritable: want.writable, observedWritable: got.writable });
239
+ }
240
+ }
241
+
242
+ // 3. The extras: signing extras are an authority the interface does not name.
243
+ const signingExtras = extras.filter((entry) => entry.signer === true);
244
+ if (signingExtras.length) {
245
+ violations.push({
246
+ kind: 'undeclared-signing-account',
247
+ accounts: signingExtras,
248
+ extraCount: extras.length,
249
+ });
250
+ } else if (extras.length) {
251
+ notes.push({ kind: 'remaining-accounts', extraCount: extras.length, addresses: extras.map((entry) => entry.address) });
252
+ }
253
+ if (absentOptional.length) {
254
+ notes.push({ kind: 'absent-optional-accounts', accounts: absentOptional });
255
+ }
256
+
257
+ const verdict = violations.length
258
+ ? violations[0].kind
259
+ : (notes.some((entry) => entry.kind === 'short-optional-tail') ? 'short-optional-tail'
260
+ : (extras.length ? 'remaining-accounts' : 'conforms'));
261
+
262
+ return {
263
+ ...base,
264
+ verdict,
265
+ violations,
266
+ extras,
267
+ notes: [...notes, ...(writableNotes.length ? [{ kind: 'writable-disagreement', positions: writableNotes }] : [])],
268
+ unknownSigner,
269
+ };
270
+ }
271
+
272
+ /**
273
+ * Aggregate a list of per-instruction verdicts into the report shape.
274
+ * Pure: the live tool only collects rows, this derives every number in the
275
+ * summary from them (a hand-edited summary cannot disagree with its rows).
276
+ */
277
+ export function summarizeConformance(rows) {
278
+ const summary = {
279
+ instructions: rows.length,
280
+ byVerdict: {},
281
+ byProgram: {},
282
+ byInstruction: {},
283
+ executed: { total: 0, disagreements: 0 },
284
+ unknownDiscriminator: 0,
285
+ unknownSignerPositions: 0,
286
+ };
287
+ for (const row of rows) {
288
+ summary.byVerdict[row.verdict] = (summary.byVerdict[row.verdict] ?? 0) + 1;
289
+ if (row.verdict === 'unknown-discriminator') summary.unknownDiscriminator += 1;
290
+ const program = row.program ?? '(unknown)';
291
+ if (!summary.byProgram[program]) {
292
+ summary.byProgram[program] = { instructions: 0, verdicts: {} };
293
+ }
294
+ summary.byProgram[program].instructions += 1;
295
+ summary.byProgram[program].verdicts[row.verdict] = (summary.byProgram[program].verdicts[row.verdict] ?? 0) + 1;
296
+ const name = row.instruction ?? '(none)';
297
+ if (!summary.byInstruction[name]) summary.byInstruction[name] = { total: 0, verdicts: {} };
298
+ summary.byInstruction[name].total += 1;
299
+ summary.byInstruction[name].verdicts[row.verdict] = (summary.byInstruction[name].verdicts[row.verdict] ?? 0) + 1;
300
+ if (row.executed === true || row.executed === false) {
301
+ summary.executed.total += 1;
302
+ const disagreeing = Array.isArray(row.violations) && row.violations.length > 0;
303
+ if (disagreeing) summary.executed.disagreements += 1;
304
+ }
305
+ summary.unknownSignerPositions += Array.isArray(row.unknownSigner) ? row.unknownSigner.length : 0;
306
+ }
307
+ return summary;
308
+ }