sol-parser-sdk-nodejs 0.3.0 → 0.4.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.
Files changed (93) hide show
  1. package/.env.example +24 -0
  2. package/README.md +94 -352
  3. package/README_CN.md +101 -253
  4. package/dist/accounts/mod.d.ts +2 -0
  5. package/dist/accounts/mod.js +5 -1
  6. package/dist/accounts/rpc_wallet.d.ts +5 -0
  7. package/dist/accounts/rpc_wallet.js +18 -0
  8. package/dist/accounts/rust_aliases.d.ts +9 -0
  9. package/dist/accounts/rust_aliases.js +19 -0
  10. package/dist/accounts/wallet_resolve.d.ts +1 -0
  11. package/dist/accounts/wallet_resolve.js +28 -0
  12. package/dist/common/constants.d.ts +10 -0
  13. package/dist/common/constants.js +13 -0
  14. package/dist/core/account_dispatcher_rpc.js +26 -5
  15. package/dist/core/account_fill_meteora.d.ts +4 -2
  16. package/dist/core/account_fill_meteora.js +5 -2
  17. package/dist/core/account_pubkey_cache.d.ts +12 -0
  18. package/dist/core/account_pubkey_cache.js +26 -0
  19. package/dist/core/clock.d.ts +6 -0
  20. package/dist/core/clock.js +13 -0
  21. package/dist/core/dex_event.d.ts +25 -44
  22. package/dist/core/metadata.d.ts +1 -0
  23. package/dist/core/unified_parser.d.ts +2 -2
  24. package/dist/core/unified_parser.js +6 -6
  25. package/dist/grpc/client.d.ts +6 -0
  26. package/dist/grpc/client.js +121 -64
  27. package/dist/grpc/event_parser.d.ts +6 -0
  28. package/dist/grpc/event_parser.js +15 -0
  29. package/dist/grpc/geyser_connect.d.ts +30 -0
  30. package/dist/grpc/geyser_connect.js +40 -0
  31. package/dist/grpc/program_ids.d.ts +25 -0
  32. package/dist/grpc/program_ids.js +54 -0
  33. package/dist/grpc/rpc_to_grpc.d.ts +18 -0
  34. package/dist/grpc/rpc_to_grpc.js +127 -0
  35. package/dist/grpc/subscribe_builder.d.ts +13 -0
  36. package/dist/grpc/subscribe_builder.js +66 -0
  37. package/dist/grpc/transaction_meta.d.ts +29 -0
  38. package/dist/grpc/transaction_meta.js +208 -0
  39. package/dist/grpc/types.d.ts +53 -2
  40. package/dist/grpc/types.js +98 -7
  41. package/dist/grpc/yellowstone_parse.d.ts +5 -0
  42. package/dist/grpc/yellowstone_parse.js +15 -2
  43. package/dist/index.d.ts +36 -6
  44. package/dist/index.js +172 -2
  45. package/dist/instr/bonk_ix.d.ts +4 -1
  46. package/dist/instr/bonk_ix.js +106 -27
  47. package/dist/instr/meteora_damm_ix.d.ts +4 -2
  48. package/dist/instr/meteora_damm_ix.js +248 -13
  49. package/dist/instr/mod.js +7 -2
  50. package/dist/instr/orca_whirlpool_ix.d.ts +4 -1
  51. package/dist/instr/orca_whirlpool_ix.js +45 -16
  52. package/dist/instr/program_ids.d.ts +7 -13
  53. package/dist/instr/program_ids.js +19 -15
  54. package/dist/instr/pumpswap_ix.d.ts +1 -1
  55. package/dist/instr/pumpswap_ix.js +78 -57
  56. package/dist/instr/raydium_amm_v4_ix.d.ts +1 -1
  57. package/dist/instr/raydium_amm_v4_ix.js +94 -28
  58. package/dist/instr/raydium_clmm_ix.d.ts +1 -1
  59. package/dist/instr/raydium_clmm_ix.js +59 -26
  60. package/dist/instr/raydium_cpmm_ix.d.ts +1 -1
  61. package/dist/instr/raydium_cpmm_ix.js +46 -12
  62. package/dist/instr/rust_aliases.d.ts +7 -0
  63. package/dist/instr/rust_aliases.js +14 -0
  64. package/dist/instr/utils.d.ts +1 -1
  65. package/dist/instr/utils.js +2 -1
  66. package/dist/logs/discriminator_lut.d.ts +19 -0
  67. package/dist/logs/discriminator_lut.js +60 -0
  68. package/dist/logs/meteora_damm.d.ts +3 -4
  69. package/dist/logs/meteora_damm.js +3 -369
  70. package/dist/logs/optimized_matcher.d.ts +2 -2
  71. package/dist/logs/optimized_matcher.js +3 -3
  72. package/dist/logs/rust_aliases.d.ts +6 -0
  73. package/dist/logs/rust_aliases.js +13 -0
  74. package/dist/rpc_parser.d.ts +1 -0
  75. package/dist/rpc_parser.js +4 -1
  76. package/dist/shredstream/alt_lookup.d.ts +9 -0
  77. package/dist/shredstream/alt_lookup.js +70 -0
  78. package/dist/shredstream/client.d.ts +62 -0
  79. package/dist/shredstream/client.js +399 -0
  80. package/dist/shredstream/config.d.ts +30 -0
  81. package/dist/shredstream/config.js +34 -0
  82. package/dist/shredstream/entries_decode.d.ts +28 -0
  83. package/dist/shredstream/entries_decode.js +251 -0
  84. package/dist/shredstream/index.d.ts +17 -0
  85. package/dist/shredstream/index.js +33 -0
  86. package/dist/shredstream/instruction_parse.d.ts +34 -0
  87. package/dist/shredstream/instruction_parse.js +47 -0
  88. package/dist/shredstream/proto_types.d.ts +9 -0
  89. package/dist/shredstream/proto_types.js +2 -0
  90. package/dist/shredstream/shredstream.proto +15 -0
  91. package/dist/shredstream/wire_to_shred_tx.d.ts +2 -0
  92. package/dist/shredstream/wire_to_shred_tx.js +59 -0
  93. package/package.json +28 -11
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.defaultGeyserConnectConfig = defaultGeyserConnectConfig;
7
+ exports.geyserGrpcChannelOptions = geyserGrpcChannelOptions;
8
+ exports.connectYellowstoneGeyser = connectYellowstoneGeyser;
9
+ const yellowstone_grpc_1 = __importDefault(require("@triton-one/yellowstone-grpc"));
10
+ /** 与 Rust `GeyserConnectConfig::default` 一致 */
11
+ function defaultGeyserConnectConfig() {
12
+ return {
13
+ connectTimeoutMs: 8000,
14
+ maxDecodingMessageSize: 1024 * 1024 * 1024,
15
+ xToken: undefined,
16
+ keepAliveIntervalMs: 30_000,
17
+ keepAliveTimeoutMs: 5000,
18
+ };
19
+ }
20
+ /** 与 `ClientConfig` / `grpc.keepalive_*` 对齐,用于长连接抗 NAT/负载均衡 idle 断开 */
21
+ function geyserGrpcChannelOptions(config = defaultGeyserConnectConfig()) {
22
+ const max = config.maxDecodingMessageSize;
23
+ const interval = config.keepAliveIntervalMs ?? 30_000;
24
+ const timeout = config.keepAliveTimeoutMs ?? 5000;
25
+ return {
26
+ "grpc.max_receive_message_length": max,
27
+ "grpc.max_send_message_length": max,
28
+ "grpc.keepalive_time_ms": interval,
29
+ "grpc.keepalive_timeout_ms": timeout,
30
+ /** 无活跃 RPC 时仍发 keepalive,避免长时间仅订阅时被中间设备掐断 */
31
+ "grpc.keepalive_permit_without_calls": 1,
32
+ };
33
+ }
34
+ /**
35
+ * 建立 Yellowstone Geyser 客户端(与 Rust `connect_yellowstone_geyser` 一致)。
36
+ * Rust 为 async;此处构造同步完成,返回 `Promise` 以保持 `await connectYellowstoneGeyser(...)` 写法。
37
+ */
38
+ async function connectYellowstoneGeyser(endpoint, config = defaultGeyserConnectConfig()) {
39
+ return new yellowstone_grpc_1.default(endpoint, config.xToken, geyserGrpcChannelOptions(config));
40
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 与 Rust `sol-parser-sdk/src/grpc/program_ids.rs` 对齐的 DEX 程序 ID 与协议映射。
3
+ */
4
+ import type { Protocol } from "./types.js";
5
+ import type { AccountFilter, TransactionFilter } from "./types.js";
6
+ export declare const PUMPFUN_PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
7
+ export declare const PUMPSWAP_PROGRAM_ID = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA";
8
+ export declare const PUMPSWAP_FEES_PROGRAM_ID = "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ";
9
+ /** 与 Rust `BONK_PROGRAM_ID`(`Protocol::Bonk`)一致 */
10
+ export declare const BONK_PROGRAM_ID = "BSwp6bEBihVLdqJRKS58NaebUBSDNjN7MdpFwNaR6gn3";
11
+ export declare const RAYDIUM_CPMM_PROGRAM_ID = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
12
+ export declare const RAYDIUM_CLMM_PROGRAM_ID = "CAMMCzo5YL8w4VFF8KVHrK22GGUQtcaMpgYqJPXBDvfE";
13
+ export declare const RAYDIUM_AMM_V4_PROGRAM_ID = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
14
+ export declare const ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
15
+ export declare const METEORA_POOLS_PROGRAM_ID = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB";
16
+ export declare const METEORA_DAMM_V2_PROGRAM_ID = "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG";
17
+ export declare const METEORA_DLMM_PROGRAM_ID = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo";
18
+ /** 与 Rust `PROTOCOL_PROGRAM_IDS` 一致(仅含 Rust 中存在的协议) */
19
+ export declare const PROTOCOL_PROGRAM_IDS: Record<Protocol, readonly string[]>;
20
+ /** 与 Rust `get_program_ids_for_protocols` 一致 */
21
+ export declare function getProgramIdsForProtocols(protocols: readonly Protocol[]): string[];
22
+ /** 与 Rust `TransactionFilter::for_protocols` 一致 */
23
+ export declare function transactionFilterForProtocols(protocols: readonly Protocol[]): TransactionFilter;
24
+ /** 与 Rust `AccountFilter::for_protocols` 一致 */
25
+ export declare function accountFilterForProtocols(protocols: readonly Protocol[]): AccountFilter;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROTOCOL_PROGRAM_IDS = exports.METEORA_DLMM_PROGRAM_ID = exports.METEORA_DAMM_V2_PROGRAM_ID = exports.METEORA_POOLS_PROGRAM_ID = exports.ORCA_WHIRLPOOL_PROGRAM_ID = exports.RAYDIUM_AMM_V4_PROGRAM_ID = exports.RAYDIUM_CLMM_PROGRAM_ID = exports.RAYDIUM_CPMM_PROGRAM_ID = exports.BONK_PROGRAM_ID = exports.PUMPSWAP_FEES_PROGRAM_ID = exports.PUMPSWAP_PROGRAM_ID = exports.PUMPFUN_PROGRAM_ID = void 0;
4
+ exports.getProgramIdsForProtocols = getProgramIdsForProtocols;
5
+ exports.transactionFilterForProtocols = transactionFilterForProtocols;
6
+ exports.accountFilterForProtocols = accountFilterForProtocols;
7
+ exports.PUMPFUN_PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
8
+ exports.PUMPSWAP_PROGRAM_ID = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA";
9
+ exports.PUMPSWAP_FEES_PROGRAM_ID = "pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ";
10
+ /** 与 Rust `BONK_PROGRAM_ID`(`Protocol::Bonk`)一致 */
11
+ exports.BONK_PROGRAM_ID = "BSwp6bEBihVLdqJRKS58NaebUBSDNjN7MdpFwNaR6gn3";
12
+ exports.RAYDIUM_CPMM_PROGRAM_ID = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
13
+ exports.RAYDIUM_CLMM_PROGRAM_ID = "CAMMCzo5YL8w4VFF8KVHrK22GGUQtcaMpgYqJPXBDvfE";
14
+ exports.RAYDIUM_AMM_V4_PROGRAM_ID = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
15
+ exports.ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
16
+ exports.METEORA_POOLS_PROGRAM_ID = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB";
17
+ exports.METEORA_DAMM_V2_PROGRAM_ID = "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG";
18
+ exports.METEORA_DLMM_PROGRAM_ID = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo";
19
+ /** 与 Rust `PROTOCOL_PROGRAM_IDS` 一致(仅含 Rust 中存在的协议) */
20
+ exports.PROTOCOL_PROGRAM_IDS = {
21
+ PumpFun: [exports.PUMPFUN_PROGRAM_ID],
22
+ PumpSwap: [exports.PUMPSWAP_PROGRAM_ID],
23
+ Bonk: [exports.BONK_PROGRAM_ID],
24
+ RaydiumCpmm: [exports.RAYDIUM_CPMM_PROGRAM_ID],
25
+ RaydiumClmm: [exports.RAYDIUM_CLMM_PROGRAM_ID],
26
+ RaydiumAmmV4: [exports.RAYDIUM_AMM_V4_PROGRAM_ID],
27
+ MeteoraDammV2: [exports.METEORA_DAMM_V2_PROGRAM_ID],
28
+ };
29
+ /** 与 Rust `get_program_ids_for_protocols` 一致 */
30
+ function getProgramIdsForProtocols(protocols) {
31
+ const out = [];
32
+ for (const p of protocols) {
33
+ const ids = exports.PROTOCOL_PROGRAM_IDS[p];
34
+ if (ids)
35
+ out.push(...ids);
36
+ }
37
+ return [...new Set(out)].sort();
38
+ }
39
+ /** 与 Rust `TransactionFilter::for_protocols` 一致 */
40
+ function transactionFilterForProtocols(protocols) {
41
+ return {
42
+ account_include: getProgramIdsForProtocols(protocols),
43
+ account_exclude: [],
44
+ account_required: [],
45
+ };
46
+ }
47
+ /** 与 Rust `AccountFilter::for_protocols` 一致 */
48
+ function accountFilterForProtocols(protocols) {
49
+ return {
50
+ account: [],
51
+ owner: getProgramIdsForProtocols(protocols),
52
+ filters: [],
53
+ };
54
+ }
@@ -0,0 +1,18 @@
1
+ import type { Transaction as YTransaction, TransactionStatusMeta } from "@triton-one/yellowstone-grpc/dist/grpc/solana-storage.js";
2
+ import { type VersionedTransactionResponse } from "@solana/web3.js";
3
+ import type { ParseError } from "../core/error.js";
4
+ export type ConvertRpcToGrpcOk = {
5
+ ok: true;
6
+ meta: TransactionStatusMeta;
7
+ transaction: YTransaction;
8
+ };
9
+ export type ConvertRpcToGrpcErr = {
10
+ ok: false;
11
+ error: ParseError;
12
+ };
13
+ /**
14
+ * 与 Rust `convert_rpc_to_grpc` 对齐:输入为 RPC `getTransaction` 的 **非 jsonParsed**、已编译 message 的响应。
15
+ */
16
+ export declare function convertRpcToGrpc(tx: VersionedTransactionResponse): ConvertRpcToGrpcOk | ConvertRpcToGrpcErr;
17
+ /** Rust 蛇形命名 */
18
+ export declare const convert_rpc_to_grpc: typeof convertRpcToGrpc;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.convert_rpc_to_grpc = void 0;
7
+ exports.convertRpcToGrpc = convertRpcToGrpc;
8
+ /**
9
+ * 将 `@solana/web3.js` 的 `VersionedTransactionResponse` 转为 Yellowstone `Transaction` + `TransactionStatusMeta`,
10
+ * 与 Rust `rpc_parser::convert_rpc_to_grpc` 字段取舍一致(token balances / rewards 置空,err 置空等)。
11
+ */
12
+ const bs58_1 = __importDefault(require("bs58"));
13
+ const rpc_invoke_map_js_1 = require("../core/rpc_invoke_map.js");
14
+ function toYCompiled(ix) {
15
+ const accounts = "accountKeyIndexes" in ix ? ix.accountKeyIndexes : ix.accounts;
16
+ return {
17
+ programIdIndex: ix.programIdIndex,
18
+ accounts: Uint8Array.from(accounts),
19
+ data: (0, rpc_invoke_map_js_1.decodeIxData)(ix.data),
20
+ };
21
+ }
22
+ function toYInnerInstruction(ix) {
23
+ const stackHeight = ix.stackHeight;
24
+ return {
25
+ programIdIndex: ix.programIdIndex,
26
+ accounts: Uint8Array.from(ix.accounts),
27
+ data: (0, rpc_invoke_map_js_1.decodeIxData)(ix.data),
28
+ ...(stackHeight !== undefined ? { stackHeight } : {}),
29
+ };
30
+ }
31
+ function legacyMessageToYellowstone(msg) {
32
+ return {
33
+ header: {
34
+ numRequiredSignatures: msg.header.numRequiredSignatures,
35
+ numReadonlySignedAccounts: msg.header.numReadonlySignedAccounts,
36
+ numReadonlyUnsignedAccounts: msg.header.numReadonlyUnsignedAccounts,
37
+ },
38
+ accountKeys: msg.accountKeys.map((k) => new Uint8Array(k.toBytes())),
39
+ recentBlockhash: new Uint8Array(bs58_1.default.decode(msg.recentBlockhash)),
40
+ instructions: msg.compiledInstructions.map(toYCompiled),
41
+ versioned: false,
42
+ addressTableLookups: [],
43
+ };
44
+ }
45
+ function v0MessageToYellowstone(msg) {
46
+ const lookups = msg.addressTableLookups.map((l) => ({
47
+ accountKey: new Uint8Array(l.accountKey.toBytes()),
48
+ writableIndexes: l.writableIndexes instanceof Uint8Array ? l.writableIndexes : Uint8Array.from(l.writableIndexes),
49
+ readonlyIndexes: l.readonlyIndexes instanceof Uint8Array ? l.readonlyIndexes : Uint8Array.from(l.readonlyIndexes),
50
+ }));
51
+ return {
52
+ header: {
53
+ numRequiredSignatures: msg.header.numRequiredSignatures,
54
+ numReadonlySignedAccounts: msg.header.numReadonlySignedAccounts,
55
+ numReadonlyUnsignedAccounts: msg.header.numReadonlyUnsignedAccounts,
56
+ },
57
+ accountKeys: msg.staticAccountKeys.map((k) => new Uint8Array(k.toBytes())),
58
+ recentBlockhash: new Uint8Array(bs58_1.default.decode(msg.recentBlockhash)),
59
+ instructions: msg.compiledInstructions.map(toYCompiled),
60
+ versioned: true,
61
+ addressTableLookups: lookups,
62
+ };
63
+ }
64
+ function metaToYellowstone(meta) {
65
+ const innerGroups = meta.innerInstructions;
66
+ const innerInstructions = [];
67
+ if (innerGroups) {
68
+ for (const g of innerGroups) {
69
+ innerInstructions.push({
70
+ index: g.index,
71
+ instructions: g.instructions.map(toYInnerInstruction),
72
+ });
73
+ }
74
+ }
75
+ const loaded = meta.loadedAddresses;
76
+ const loadedWritable = loaded?.writable.map((k) => new Uint8Array(k.toBytes())) ?? [];
77
+ const loadedReadonly = loaded?.readonly.map((k) => new Uint8Array(k.toBytes())) ?? [];
78
+ const logs = meta.logMessages ?? [];
79
+ return {
80
+ err: undefined,
81
+ fee: String(meta.fee),
82
+ preBalances: meta.preBalances.map(String),
83
+ postBalances: meta.postBalances.map(String),
84
+ innerInstructions,
85
+ innerInstructionsNone: innerGroups == null,
86
+ logMessages: [...logs],
87
+ logMessagesNone: logs.length === 0,
88
+ preTokenBalances: [],
89
+ postTokenBalances: [],
90
+ rewards: [],
91
+ loadedWritableAddresses: loadedWritable,
92
+ loadedReadonlyAddresses: loadedReadonly,
93
+ returnData: undefined,
94
+ returnDataNone: true,
95
+ computeUnitsConsumed: meta.computeUnitsConsumed !== undefined ? String(meta.computeUnitsConsumed) : undefined,
96
+ };
97
+ }
98
+ /**
99
+ * 与 Rust `convert_rpc_to_grpc` 对齐:输入为 RPC `getTransaction` 的 **非 jsonParsed**、已编译 message 的响应。
100
+ */
101
+ function convertRpcToGrpc(tx) {
102
+ const msg = tx.transaction?.message;
103
+ if (!msg || !(0, rpc_invoke_map_js_1.isCompiledVersionedMessage)(msg)) {
104
+ return {
105
+ ok: false,
106
+ error: {
107
+ kind: "ConversionError",
108
+ message: "交易 message 非编译形态(例如 jsonParsed)。请使用默认编码的 getTransaction 响应后再转换。",
109
+ },
110
+ };
111
+ }
112
+ const meta = tx.meta;
113
+ if (meta == null) {
114
+ return {
115
+ ok: false,
116
+ error: { kind: "MissingField", field: "meta" },
117
+ };
118
+ }
119
+ const yMsg = msg.version === "legacy" ? legacyMessageToYellowstone(msg) : v0MessageToYellowstone(msg);
120
+ const transaction = {
121
+ signatures: tx.transaction.signatures.map((s) => new Uint8Array(bs58_1.default.decode(s))),
122
+ message: yMsg,
123
+ };
124
+ return { ok: true, meta: metaToYellowstone(meta), transaction };
125
+ }
126
+ /** Rust 蛇形命名 */
127
+ exports.convert_rpc_to_grpc = convertRpcToGrpc;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Yellowstone `SubscribeRequest` 构造(与 Rust `grpc/subscribe_builder` 对齐)。
3
+ */
4
+ import type { SubscribeRequest } from "@triton-one/yellowstone-grpc";
5
+ import { CommitmentLevel } from "@triton-one/yellowstone-grpc";
6
+ import type { AccountFilter, TransactionFilter } from "./types.js";
7
+ export declare function buildSubscribeRequest(txFilters: TransactionFilter[], accFilters: AccountFilter[]): SubscribeRequest;
8
+ export declare function buildSubscribeRequestWithCommitment(txFilters: TransactionFilter[], accFilters: AccountFilter[], commitment: CommitmentLevel): SubscribeRequest;
9
+ export declare function buildSubscribeTransactionFiltersNamed(namedTxFilters: readonly {
10
+ name: string;
11
+ filter: TransactionFilter;
12
+ }[], accFilters: AccountFilter[], commitment: CommitmentLevel): SubscribeRequest;
13
+ export { CommitmentLevel };
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CommitmentLevel = void 0;
4
+ exports.buildSubscribeRequest = buildSubscribeRequest;
5
+ exports.buildSubscribeRequestWithCommitment = buildSubscribeRequestWithCommitment;
6
+ exports.buildSubscribeTransactionFiltersNamed = buildSubscribeTransactionFiltersNamed;
7
+ const yellowstone_grpc_1 = require("@triton-one/yellowstone-grpc");
8
+ Object.defineProperty(exports, "CommitmentLevel", { enumerable: true, get: function () { return yellowstone_grpc_1.CommitmentLevel; } });
9
+ function txFilterToProto(f) {
10
+ return {
11
+ vote: false,
12
+ failed: false,
13
+ signature: undefined,
14
+ accountInclude: f.account_include,
15
+ accountExclude: f.account_exclude,
16
+ accountRequired: f.account_required,
17
+ };
18
+ }
19
+ function accFilterToProto(f) {
20
+ return {
21
+ account: f.account,
22
+ owner: f.owner,
23
+ filters: f.filters,
24
+ nonemptyTxnSignature: undefined,
25
+ };
26
+ }
27
+ function finalize(transactions, accounts, commitment) {
28
+ return {
29
+ slots: {},
30
+ accounts,
31
+ transactions,
32
+ transactionsStatus: {},
33
+ blocks: {},
34
+ blocksMeta: {},
35
+ entry: {},
36
+ commitment,
37
+ accountsDataSlice: [],
38
+ ping: undefined,
39
+ fromSlot: undefined,
40
+ };
41
+ }
42
+ function buildSubscribeRequest(txFilters, accFilters) {
43
+ return buildSubscribeRequestWithCommitment(txFilters, accFilters, yellowstone_grpc_1.CommitmentLevel.PROCESSED);
44
+ }
45
+ function buildSubscribeRequestWithCommitment(txFilters, accFilters, commitment) {
46
+ const transactions = {};
47
+ txFilters.forEach((f, i) => {
48
+ transactions[`tx_${i}`] = txFilterToProto(f);
49
+ });
50
+ const accounts = {};
51
+ accFilters.forEach((f, i) => {
52
+ accounts[`acc_${i}`] = accFilterToProto(f);
53
+ });
54
+ return finalize(transactions, accounts, commitment);
55
+ }
56
+ function buildSubscribeTransactionFiltersNamed(namedTxFilters, accFilters, commitment) {
57
+ const transactions = {};
58
+ for (const { name, filter } of namedTxFilters) {
59
+ transactions[name] = txFilterToProto(filter);
60
+ }
61
+ const accounts = {};
62
+ accFilters.forEach((f, i) => {
63
+ accounts[`acc_${i}`] = accFilterToProto(f);
64
+ });
65
+ return finalize(transactions, accounts, commitment);
66
+ }
@@ -0,0 +1,29 @@
1
+ import type { TokenBalance, Transaction, TransactionStatusMeta } from "@triton-one/yellowstone-grpc/dist/grpc/solana-storage.js";
2
+ /** 32 字节公钥 → Base58(无效长度返回 `null`) */
3
+ export declare function pubkeyBytesToBs58(bytes: Uint8Array): string | null;
4
+ /**
5
+ * 消息静态 `accountKeys` + meta 中 `loadedWritableAddresses` / `loadedReadonlyAddresses`,
6
+ * 顺序与 `preBalances` / `postBalances` 对齐。
7
+ */
8
+ export declare function collectAccountKeysBs58(tx: Transaction, meta: TransactionStatusMeta): string[] | null;
9
+ /** 每个账户索引的 lamports 变化(post − pre) */
10
+ export declare function lamportBalanceDeltas(meta: TransactionStatusMeta): bigint[];
11
+ /**
12
+ * 启发式原生 SOL:对 `watchedBs58` 中出现的账户,若 lamports 净减少 ≥ `minOutflowLamports`,
13
+ * 再与其它索引配对,要求对方 delta ≥ `minOutflowLamports/2`。
14
+ */
15
+ export declare function heuristicSolCounterpartiesForWatchedKeys(accountKeysBs58: string[], lamportDeltas: bigint[], watchedBs58: Set<string>, minOutflowLamports: bigint): [string, string][];
16
+ /** `TokenBalance.uiTokenAmount.amount` → 原始整数;解析失败为 `0n` */
17
+ export declare function tokenBalanceRawAmount(t: TokenBalance): bigint;
18
+ /**
19
+ * SPL:当 `watchOwnerBs58` 在某 mint 上余额净减少 ≥ `minWatchDecreaseRaw` 时,
20
+ * 找同 mint 下余额增加的其它 owner,返回 `(watch_owner, counterparty_owner)`。
21
+ */
22
+ export declare function splTokenCounterpartyByOwner(meta: TransactionStatusMeta, watchOwnerBs58: string, minWatchDecreaseRaw: bigint): [string, string][];
23
+ /**
24
+ * 汇总监控地址在一笔交易中的转出对手方(原生 SOL 启发式 + SPL token balance 启发式)。
25
+ * 若账户 key 与 balance 数组长度不一致则返回 `null`。
26
+ */
27
+ export declare function collectWatchTransferCounterpartyPairs(tx: Transaction, meta: TransactionStatusMeta, watchedBs58: string[], minNativeOutflowLamports: bigint, splMinWatchDecreaseRaw: bigint): [string, string][] | null;
28
+ /** Yellowstone 交易签名原始字节(64)→ Base58 签名字符串;长度非 64 返回 `null` */
29
+ export declare function tryYellowstoneSignature(sig: Uint8Array): string | null;
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.pubkeyBytesToBs58 = pubkeyBytesToBs58;
7
+ exports.collectAccountKeysBs58 = collectAccountKeysBs58;
8
+ exports.lamportBalanceDeltas = lamportBalanceDeltas;
9
+ exports.heuristicSolCounterpartiesForWatchedKeys = heuristicSolCounterpartiesForWatchedKeys;
10
+ exports.tokenBalanceRawAmount = tokenBalanceRawAmount;
11
+ exports.splTokenCounterpartyByOwner = splTokenCounterpartyByOwner;
12
+ exports.collectWatchTransferCounterpartyPairs = collectWatchTransferCounterpartyPairs;
13
+ exports.tryYellowstoneSignature = tryYellowstoneSignature;
14
+ /**
15
+ * Yellowstone `Transaction` / `TransactionStatusMeta` 通用工具(与 Rust `grpc/transaction_meta` 对齐)。
16
+ * 不依赖 DEX 日志解析,用于 mentions 订阅后的 SOL/SPL 转账启发式分析等。
17
+ */
18
+ const bs58_1 = __importDefault(require("bs58"));
19
+ const web3_js_1 = require("@solana/web3.js");
20
+ /** 32 字节公钥 → Base58(无效长度返回 `null`) */
21
+ function pubkeyBytesToBs58(bytes) {
22
+ if (bytes.length !== 32)
23
+ return null;
24
+ try {
25
+ return new web3_js_1.PublicKey(bytes).toBase58();
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ /**
32
+ * 消息静态 `accountKeys` + meta 中 `loadedWritableAddresses` / `loadedReadonlyAddresses`,
33
+ * 顺序与 `preBalances` / `postBalances` 对齐。
34
+ */
35
+ function collectAccountKeysBs58(tx, meta) {
36
+ const msg = tx.message;
37
+ if (!msg)
38
+ return null;
39
+ const keys = [];
40
+ for (const b of msg.accountKeys) {
41
+ const s = pubkeyBytesToBs58(b);
42
+ if (!s)
43
+ continue;
44
+ keys.push(s);
45
+ }
46
+ for (const b of meta.loadedWritableAddresses) {
47
+ const s = pubkeyBytesToBs58(b);
48
+ if (!s)
49
+ continue;
50
+ keys.push(s);
51
+ }
52
+ for (const b of meta.loadedReadonlyAddresses) {
53
+ const s = pubkeyBytesToBs58(b);
54
+ if (!s)
55
+ continue;
56
+ keys.push(s);
57
+ }
58
+ return keys;
59
+ }
60
+ /** 每个账户索引的 lamports 变化(post − pre) */
61
+ function lamportBalanceDeltas(meta) {
62
+ const n = Math.min(meta.preBalances.length, meta.postBalances.length);
63
+ const out = [];
64
+ for (let i = 0; i < n; i++) {
65
+ out.push(BigInt(meta.postBalances[i] ?? "0") - BigInt(meta.preBalances[i] ?? "0"));
66
+ }
67
+ return out;
68
+ }
69
+ /**
70
+ * 启发式原生 SOL:对 `watchedBs58` 中出现的账户,若 lamports 净减少 ≥ `minOutflowLamports`,
71
+ * 再与其它索引配对,要求对方 delta ≥ `minOutflowLamports/2`。
72
+ */
73
+ function heuristicSolCounterpartiesForWatchedKeys(accountKeysBs58, lamportDeltas, watchedBs58, minOutflowLamports) {
74
+ const minL = minOutflowLamports;
75
+ const half = minL / 2n;
76
+ const pairs = [];
77
+ for (let i = 0; i < accountKeysBs58.length; i++) {
78
+ const key = accountKeysBs58[i];
79
+ if (!watchedBs58.has(key))
80
+ continue;
81
+ const d = lamportDeltas[i] ?? 0n;
82
+ if (d >= -minL)
83
+ continue;
84
+ for (let j = 0; j < lamportDeltas.length; j++) {
85
+ if (i === j)
86
+ continue;
87
+ const dj = lamportDeltas[j] ?? 0n;
88
+ if (dj <= half)
89
+ continue;
90
+ pairs.push([key, accountKeysBs58[j]]);
91
+ }
92
+ }
93
+ return pairs;
94
+ }
95
+ /** `TokenBalance.uiTokenAmount.amount` → 原始整数;解析失败为 `0n` */
96
+ function tokenBalanceRawAmount(t) {
97
+ const a = t.uiTokenAmount?.amount;
98
+ if (a === undefined || a === "")
99
+ return 0n;
100
+ try {
101
+ return BigInt(a);
102
+ }
103
+ catch {
104
+ return 0n;
105
+ }
106
+ }
107
+ function mapKey(mint, owner) {
108
+ return `${mint}\0${owner}`;
109
+ }
110
+ function parseMapKey(k) {
111
+ const i = k.indexOf("\0");
112
+ if (i <= 0)
113
+ return null;
114
+ return { mint: k.slice(0, i), owner: k.slice(i + 1) };
115
+ }
116
+ /**
117
+ * SPL:当 `watchOwnerBs58` 在某 mint 上余额净减少 ≥ `minWatchDecreaseRaw` 时,
118
+ * 找同 mint 下余额增加的其它 owner,返回 `(watch_owner, counterparty_owner)`。
119
+ */
120
+ function splTokenCounterpartyByOwner(meta, watchOwnerBs58, minWatchDecreaseRaw) {
121
+ const pre = meta.preTokenBalances ?? [];
122
+ const post = meta.postTokenBalances ?? [];
123
+ const preM = new Map();
124
+ for (const b of pre) {
125
+ if (!b.owner)
126
+ continue;
127
+ const k = mapKey(b.mint, b.owner);
128
+ preM.set(k, (preM.get(k) ?? 0n) + tokenBalanceRawAmount(b));
129
+ }
130
+ const postM = new Map();
131
+ for (const b of post) {
132
+ if (!b.owner)
133
+ continue;
134
+ const k = mapKey(b.mint, b.owner);
135
+ postM.set(k, (postM.get(k) ?? 0n) + tokenBalanceRawAmount(b));
136
+ }
137
+ const mints = new Set();
138
+ for (const k of preM.keys()) {
139
+ const p = parseMapKey(k);
140
+ if (p && p.owner === watchOwnerBs58)
141
+ mints.add(p.mint);
142
+ }
143
+ for (const k of postM.keys()) {
144
+ const p = parseMapKey(k);
145
+ if (p && p.owner === watchOwnerBs58)
146
+ mints.add(p.mint);
147
+ }
148
+ const out = [];
149
+ const minL = minWatchDecreaseRaw > 0n ? minWatchDecreaseRaw : 1n;
150
+ for (const mint of mints) {
151
+ const wPre = preM.get(mapKey(mint, watchOwnerBs58)) ?? 0n;
152
+ const wPost = postM.get(mapKey(mint, watchOwnerBs58)) ?? 0n;
153
+ const lost = wPre > wPost ? wPre - wPost : 0n;
154
+ if (lost < minL)
155
+ continue;
156
+ for (const [k, po] of postM) {
157
+ const parsed = parseMapKey(k);
158
+ if (!parsed || parsed.mint !== mint || parsed.owner === watchOwnerBs58)
159
+ continue;
160
+ const pr = preM.get(k) ?? 0n;
161
+ if (po > pr) {
162
+ out.push([watchOwnerBs58, parsed.owner]);
163
+ }
164
+ }
165
+ }
166
+ out.sort((a, b) => a[1].localeCompare(b[1]));
167
+ const dedup = [];
168
+ for (const p of out) {
169
+ const prev = dedup[dedup.length - 1];
170
+ if (prev && prev[0] === p[0] && prev[1] === p[1])
171
+ continue;
172
+ dedup.push(p);
173
+ }
174
+ return dedup;
175
+ }
176
+ /**
177
+ * 汇总监控地址在一笔交易中的转出对手方(原生 SOL 启发式 + SPL token balance 启发式)。
178
+ * 若账户 key 与 balance 数组长度不一致则返回 `null`。
179
+ */
180
+ function collectWatchTransferCounterpartyPairs(tx, meta, watchedBs58, minNativeOutflowLamports, splMinWatchDecreaseRaw) {
181
+ const keys = collectAccountKeysBs58(tx, meta);
182
+ if (!keys)
183
+ return null;
184
+ const n = keys.length;
185
+ if (meta.preBalances.length !== n || meta.postBalances.length !== n)
186
+ return null;
187
+ const deltas = lamportBalanceDeltas(meta);
188
+ const watchedH = new Set(watchedBs58);
189
+ const pairs = heuristicSolCounterpartiesForWatchedKeys(keys, deltas, watchedH, minNativeOutflowLamports);
190
+ for (const w of watchedBs58) {
191
+ pairs.push(...splTokenCounterpartyByOwner(meta, w, splMinWatchDecreaseRaw));
192
+ }
193
+ pairs.sort((a, b) => a[1].localeCompare(b[1]));
194
+ const dedup = [];
195
+ for (const p of pairs) {
196
+ const prev = dedup[dedup.length - 1];
197
+ if (prev && prev[0] === p[0] && prev[1] === p[1])
198
+ continue;
199
+ dedup.push(p);
200
+ }
201
+ return dedup;
202
+ }
203
+ /** Yellowstone 交易签名原始字节(64)→ Base58 签名字符串;长度非 64 返回 `null` */
204
+ function tryYellowstoneSignature(sig) {
205
+ if (sig.length !== 64)
206
+ return null;
207
+ return bs58_1.default.encode(sig);
208
+ }