@oobe-protocol-labs/synapse-sap-sdk 0.6.2 → 0.7.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/cjs/constants/seeds.js +7 -0
- package/dist/cjs/constants/seeds.js.map +1 -1
- package/dist/cjs/core/client.js +42 -0
- package/dist/cjs/core/client.js.map +1 -1
- package/dist/cjs/events/geyser.js +295 -0
- package/dist/cjs/events/geyser.js.map +1 -0
- package/dist/cjs/idl/synapse_agent_sap.json +7545 -3501
- package/dist/cjs/index.js +28 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/modules/escrow-v2.js +241 -0
- package/dist/cjs/modules/escrow-v2.js.map +1 -0
- package/dist/cjs/modules/escrow.js +4 -0
- package/dist/cjs/modules/escrow.js.map +1 -1
- package/dist/cjs/modules/index.js +7 -1
- package/dist/cjs/modules/index.js.map +1 -1
- package/dist/cjs/modules/staking.js +94 -0
- package/dist/cjs/modules/staking.js.map +1 -0
- package/dist/cjs/modules/subscription.js +96 -0
- package/dist/cjs/modules/subscription.js.map +1 -0
- package/dist/cjs/pda/index.js +143 -1
- package/dist/cjs/pda/index.js.map +1 -1
- package/dist/cjs/postgres/sync.js +72 -4
- package/dist/cjs/postgres/sync.js.map +1 -1
- package/dist/cjs/registries/x402.js +88 -51
- package/dist/cjs/registries/x402.js.map +1 -1
- package/dist/cjs/types/enums.js +51 -1
- package/dist/cjs/types/enums.js.map +1 -1
- package/dist/cjs/types/index.js +4 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/instructions.js.map +1 -1
- package/dist/cjs/utils/escrow-validation.js +219 -0
- package/dist/cjs/utils/escrow-validation.js.map +1 -0
- package/dist/cjs/utils/index.js +12 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/merchant-validator.js +246 -0
- package/dist/cjs/utils/merchant-validator.js.map +1 -0
- package/dist/cjs/utils/x402-direct.js +231 -0
- package/dist/cjs/utils/x402-direct.js.map +1 -0
- package/dist/esm/constants/seeds.js +7 -0
- package/dist/esm/constants/seeds.js.map +1 -1
- package/dist/esm/core/client.js +42 -0
- package/dist/esm/core/client.js.map +1 -1
- package/dist/esm/events/geyser.js +258 -0
- package/dist/esm/events/geyser.js.map +1 -0
- package/dist/esm/idl/synapse_agent_sap.json +7545 -3501
- package/dist/esm/index.js +7 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/modules/escrow-v2.js +237 -0
- package/dist/esm/modules/escrow-v2.js.map +1 -0
- package/dist/esm/modules/escrow.js +4 -0
- package/dist/esm/modules/escrow.js.map +1 -1
- package/dist/esm/modules/index.js +3 -0
- package/dist/esm/modules/index.js.map +1 -1
- package/dist/esm/modules/staking.js +90 -0
- package/dist/esm/modules/staking.js.map +1 -0
- package/dist/esm/modules/subscription.js +92 -0
- package/dist/esm/modules/subscription.js.map +1 -0
- package/dist/esm/pda/index.js +135 -0
- package/dist/esm/pda/index.js.map +1 -1
- package/dist/esm/postgres/sync.js +72 -4
- package/dist/esm/postgres/sync.js.map +1 -1
- package/dist/esm/registries/x402.js +89 -52
- package/dist/esm/registries/x402.js.map +1 -1
- package/dist/esm/types/enums.js +50 -0
- package/dist/esm/types/enums.js.map +1 -1
- package/dist/esm/types/index.js +1 -1
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/instructions.js.map +1 -1
- package/dist/esm/utils/escrow-validation.js +212 -0
- package/dist/esm/utils/escrow-validation.js.map +1 -0
- package/dist/esm/utils/index.js +4 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/merchant-validator.js +241 -0
- package/dist/esm/utils/merchant-validator.js.map +1 -0
- package/dist/esm/utils/x402-direct.js +228 -0
- package/dist/esm/utils/x402-direct.js.map +1 -0
- package/dist/types/constants/seeds.d.ts +7 -0
- package/dist/types/constants/seeds.d.ts.map +1 -1
- package/dist/types/core/client.d.ts +33 -0
- package/dist/types/core/client.d.ts.map +1 -1
- package/dist/types/events/geyser.d.ts +150 -0
- package/dist/types/events/geyser.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modules/escrow-v2.d.ts +51 -0
- package/dist/types/modules/escrow-v2.d.ts.map +1 -0
- package/dist/types/modules/escrow.d.ts +4 -0
- package/dist/types/modules/escrow.d.ts.map +1 -1
- package/dist/types/modules/index.d.ts +3 -0
- package/dist/types/modules/index.d.ts.map +1 -1
- package/dist/types/modules/staking.d.ts +32 -0
- package/dist/types/modules/staking.d.ts.map +1 -0
- package/dist/types/modules/subscription.d.ts +33 -0
- package/dist/types/modules/subscription.d.ts.map +1 -0
- package/dist/types/pda/index.d.ts +99 -0
- package/dist/types/pda/index.d.ts.map +1 -1
- package/dist/types/plugin/schemas.d.ts +2 -2
- package/dist/types/postgres/sync.d.ts +26 -2
- package/dist/types/postgres/sync.d.ts.map +1 -1
- package/dist/types/registries/x402.d.ts +14 -12
- package/dist/types/registries/x402.d.ts.map +1 -1
- package/dist/types/types/accounts.d.ts +157 -1
- package/dist/types/types/accounts.d.ts.map +1 -1
- package/dist/types/types/enums.d.ts +64 -0
- package/dist/types/types/enums.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +4 -4
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/types/instructions.d.ts +34 -0
- package/dist/types/types/instructions.d.ts.map +1 -1
- package/dist/types/utils/escrow-validation.d.ts +145 -0
- package/dist/types/utils/escrow-validation.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +6 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/merchant-validator.d.ts +176 -0
- package/dist/types/utils/merchant-validator.d.ts.map +1 -0
- package/dist/types/utils/x402-direct.d.ts +114 -0
- package/dist/types/utils/x402-direct.d.ts.map +1 -0
- package/package.json +5 -1
- package/src/constants/seeds.ts +7 -0
- package/src/core/client.ts +45 -0
- package/src/events/geyser.ts +384 -0
- package/src/events/yellowstone.d.ts +7 -0
- package/src/idl/synapse_agent_sap.json +7545 -3501
- package/src/index.ts +51 -0
- package/src/modules/escrow-v2.ts +396 -0
- package/src/modules/escrow.ts +4 -0
- package/src/modules/index.ts +3 -0
- package/src/modules/staking.ts +122 -0
- package/src/modules/subscription.ts +147 -0
- package/src/pda/index.ts +196 -0
- package/src/postgres/sync.ts +90 -4
- package/src/registries/x402.ts +108 -69
- package/src/types/accounts.ts +192 -1
- package/src/types/enums.ts +65 -0
- package/src/types/index.ts +15 -0
- package/src/types/instructions.ts +40 -0
- package/src/utils/escrow-validation.ts +301 -0
- package/src/utils/index.ts +28 -0
- package/src/utils/merchant-validator.ts +359 -0
- package/src/utils/x402-direct.ts +370 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oobe-protocol-labs/synapse-sap-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "TypeScript SDK for the Synapse Agent Protocol (SAP v2) on Solana",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -166,6 +166,7 @@
|
|
|
166
166
|
"peerDependencies": {
|
|
167
167
|
"@coral-xyz/anchor": ">=0.30.0",
|
|
168
168
|
"@solana/web3.js": ">=1.90.0",
|
|
169
|
+
"@triton-one/yellowstone-grpc": ">=1.0.0",
|
|
169
170
|
"zod": ">=3.20.0",
|
|
170
171
|
"pg": ">=8.0.0"
|
|
171
172
|
},
|
|
@@ -175,6 +176,9 @@
|
|
|
175
176
|
},
|
|
176
177
|
"pg": {
|
|
177
178
|
"optional": true
|
|
179
|
+
},
|
|
180
|
+
"@triton-one/yellowstone-grpc": {
|
|
181
|
+
"optional": true
|
|
178
182
|
}
|
|
179
183
|
},
|
|
180
184
|
"engines": {
|
package/src/constants/seeds.ts
CHANGED
|
@@ -47,6 +47,7 @@ export const SEEDS = {
|
|
|
47
47
|
TOOL: "sap_tool",
|
|
48
48
|
CHECKPOINT: "sap_checkpoint",
|
|
49
49
|
ESCROW: "sap_escrow",
|
|
50
|
+
ESCROW_V2: "sap_escrow_v2",
|
|
50
51
|
STATS: "sap_stats",
|
|
51
52
|
TOOL_CATEGORY: "sap_tool_cat",
|
|
52
53
|
ATTESTATION: "sap_attest",
|
|
@@ -54,6 +55,12 @@ export const SEEDS = {
|
|
|
54
55
|
LEDGER_PAGE: "sap_page",
|
|
55
56
|
BUFFER: "sap_buffer",
|
|
56
57
|
DIGEST: "sap_digest",
|
|
58
|
+
PENDING: "sap_pending",
|
|
59
|
+
DISPUTE: "sap_dispute",
|
|
60
|
+
STAKE: "sap_stake",
|
|
61
|
+
SUBSCRIPTION: "sap_sub",
|
|
62
|
+
SHARD: "sap_shard",
|
|
63
|
+
INDEX_PAGE: "sap_idx_page",
|
|
57
64
|
} as const;
|
|
58
65
|
|
|
59
66
|
/**
|
package/src/core/client.ts
CHANGED
|
@@ -33,6 +33,9 @@ import { IndexingModule } from "../modules/indexing";
|
|
|
33
33
|
import { ToolsModule } from "../modules/tools";
|
|
34
34
|
import { VaultModule } from "../modules/vault";
|
|
35
35
|
import { EscrowModule } from "../modules/escrow";
|
|
36
|
+
import { EscrowV2Module } from "../modules/escrow-v2";
|
|
37
|
+
import { StakingModule } from "../modules/staking";
|
|
38
|
+
import { SubscriptionModule } from "../modules/subscription";
|
|
36
39
|
import { AttestationModule } from "../modules/attestation";
|
|
37
40
|
import { LedgerModule } from "../modules/ledger";
|
|
38
41
|
import { EventParser } from "../events";
|
|
@@ -113,6 +116,9 @@ export class SapClient {
|
|
|
113
116
|
#tools?: ToolsModule;
|
|
114
117
|
#vault?: VaultModule;
|
|
115
118
|
#escrow?: EscrowModule;
|
|
119
|
+
#escrowV2?: EscrowV2Module;
|
|
120
|
+
#staking?: StakingModule;
|
|
121
|
+
#subscription?: SubscriptionModule;
|
|
116
122
|
#attestation?: AttestationModule;
|
|
117
123
|
#ledger?: LedgerModule;
|
|
118
124
|
#events?: EventParser;
|
|
@@ -284,6 +290,45 @@ export class SapClient {
|
|
|
284
290
|
return (this.#escrow ??= new EscrowModule(this.program));
|
|
285
291
|
}
|
|
286
292
|
|
|
293
|
+
/**
|
|
294
|
+
* @name escrowV2
|
|
295
|
+
* @description V2 escrow settlement with dispute windows, co-signing,
|
|
296
|
+
* pending settlements, and migration from V1.
|
|
297
|
+
* @returns {EscrowV2Module} The lazily-instantiated `EscrowV2Module` singleton.
|
|
298
|
+
* @category Modules
|
|
299
|
+
* @since v0.7.0
|
|
300
|
+
* @see {@link EscrowV2Module}
|
|
301
|
+
*/
|
|
302
|
+
get escrowV2(): EscrowV2Module {
|
|
303
|
+
return (this.#escrowV2 ??= new EscrowV2Module(this.program));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @name staking
|
|
308
|
+
* @description Agent staking: init stake, deposit, request unstake,
|
|
309
|
+
* and complete unstake.
|
|
310
|
+
* @returns {StakingModule} The lazily-instantiated `StakingModule` singleton.
|
|
311
|
+
* @category Modules
|
|
312
|
+
* @since v0.7.0
|
|
313
|
+
* @see {@link StakingModule}
|
|
314
|
+
*/
|
|
315
|
+
get staking(): StakingModule {
|
|
316
|
+
return (this.#staking ??= new StakingModule(this.program));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @name subscription
|
|
321
|
+
* @description Recurring subscriptions: create, fund, cancel, and close
|
|
322
|
+
* subscriber-agent subscription accounts.
|
|
323
|
+
* @returns {SubscriptionModule} The lazily-instantiated `SubscriptionModule` singleton.
|
|
324
|
+
* @category Modules
|
|
325
|
+
* @since v0.7.0
|
|
326
|
+
* @see {@link SubscriptionModule}
|
|
327
|
+
*/
|
|
328
|
+
get subscription(): SubscriptionModule {
|
|
329
|
+
return (this.#subscription ??= new SubscriptionModule(this.program));
|
|
330
|
+
}
|
|
331
|
+
|
|
287
332
|
/**
|
|
288
333
|
* @name attestation
|
|
289
334
|
* @description Web of trust: create, revoke, and close on-chain
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module events/geyser
|
|
3
|
+
* @description Yellowstone gRPC (Geyser) event stream for SAP v2.
|
|
4
|
+
*
|
|
5
|
+
* Drop-in alternative to the WebSocket `connection.onLogs()` pipeline.
|
|
6
|
+
* Uses Triton / Helius / any Yellowstone-compatible gRPC endpoint to
|
|
7
|
+
* receive program transaction updates with sub-second latency and
|
|
8
|
+
* automatic reconnection.
|
|
9
|
+
*
|
|
10
|
+
* @category Events
|
|
11
|
+
* @since v0.6.3
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { GeyserEventStream } from "@oobe-protocol-labs/synapse-sap-sdk";
|
|
16
|
+
* import { EventParser } from "@oobe-protocol-labs/synapse-sap-sdk";
|
|
17
|
+
*
|
|
18
|
+
* const stream = new GeyserEventStream({
|
|
19
|
+
* endpoint: "https://grpc.triton.one",
|
|
20
|
+
* token: process.env.GEYSER_TOKEN!,
|
|
21
|
+
* programId: "SAPpUhsWLJG1FfkGRcXagEDMrMsWGjbky7AyhGpFETZ",
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* const parser = new EventParser(program);
|
|
25
|
+
*
|
|
26
|
+
* stream.on("logs", (logs, signature, slot) => {
|
|
27
|
+
* const events = parser.parseLogs(logs);
|
|
28
|
+
* for (const event of events) {
|
|
29
|
+
* console.log(event.name, event.data);
|
|
30
|
+
* }
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* stream.on("error", (err) => console.error("gRPC error:", err));
|
|
34
|
+
*
|
|
35
|
+
* await stream.connect();
|
|
36
|
+
* // ... later
|
|
37
|
+
* await stream.disconnect();
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { EventEmitter } from "events";
|
|
42
|
+
|
|
43
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
44
|
+
// Types
|
|
45
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Configuration for the Yellowstone gRPC event stream.
|
|
49
|
+
*
|
|
50
|
+
* @interface GeyserConfig
|
|
51
|
+
* @since v0.6.3
|
|
52
|
+
*/
|
|
53
|
+
export interface GeyserConfig {
|
|
54
|
+
/** Yellowstone gRPC endpoint URL (e.g. "https://grpc.triton.one") */
|
|
55
|
+
endpoint: string;
|
|
56
|
+
|
|
57
|
+
/** Authentication token for the gRPC endpoint */
|
|
58
|
+
token: string;
|
|
59
|
+
|
|
60
|
+
/** SAP program ID to filter. Defaults to SAP v2 program. */
|
|
61
|
+
programId?: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Commitment level for the subscription.
|
|
65
|
+
* @default "confirmed"
|
|
66
|
+
*/
|
|
67
|
+
commitment?: "processed" | "confirmed" | "finalized";
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Automatically reconnect on disconnect.
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
autoReconnect?: boolean;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Delay between reconnection attempts in ms.
|
|
77
|
+
* @default 3000
|
|
78
|
+
*/
|
|
79
|
+
reconnectDelayMs?: number;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Maximum number of reconnection attempts. 0 = unlimited.
|
|
83
|
+
* @default 0
|
|
84
|
+
*/
|
|
85
|
+
maxReconnectAttempts?: number;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Include failed transactions in the stream.
|
|
89
|
+
* @default false
|
|
90
|
+
*/
|
|
91
|
+
includeFailedTxs?: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Events emitted by {@link GeyserEventStream}.
|
|
96
|
+
*
|
|
97
|
+
* @interface GeyserStreamEvents
|
|
98
|
+
* @since v0.6.3
|
|
99
|
+
*/
|
|
100
|
+
export interface GeyserStreamEvents {
|
|
101
|
+
/**
|
|
102
|
+
* Emitted for each transaction's log messages.
|
|
103
|
+
* Same shape as `connection.onLogs()` callback — plug into `EventParser.parseLogs()`.
|
|
104
|
+
*/
|
|
105
|
+
logs: (logs: string[], signature: string, slot: number) => void;
|
|
106
|
+
|
|
107
|
+
/** Emitted when the gRPC stream connects or reconnects. */
|
|
108
|
+
connected: () => void;
|
|
109
|
+
|
|
110
|
+
/** Emitted when the stream disconnects. */
|
|
111
|
+
disconnected: (reason: string) => void;
|
|
112
|
+
|
|
113
|
+
/** Emitted on transport or parsing errors. */
|
|
114
|
+
error: (err: Error) => void;
|
|
115
|
+
|
|
116
|
+
/** Emitted on reconnection attempt. */
|
|
117
|
+
reconnecting: (attempt: number) => void;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
121
|
+
// Constants
|
|
122
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
123
|
+
|
|
124
|
+
const SAP_PROGRAM_ID = "SAPpUhsWLJG1FfkGRcXagEDMrMsWGjbky7AyhGpFETZ";
|
|
125
|
+
|
|
126
|
+
const COMMITMENT_MAP: Record<string, number> = {
|
|
127
|
+
processed: 0,
|
|
128
|
+
confirmed: 1,
|
|
129
|
+
finalized: 2,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
133
|
+
// GeyserEventStream
|
|
134
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Yellowstone gRPC event stream for SAP v2 programs.
|
|
138
|
+
*
|
|
139
|
+
* Wraps `@triton-one/yellowstone-grpc` and emits parsed log lines
|
|
140
|
+
* compatible with the existing {@link EventParser}.
|
|
141
|
+
*
|
|
142
|
+
* @name GeyserEventStream
|
|
143
|
+
* @category Events
|
|
144
|
+
* @since v0.6.3
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const stream = new GeyserEventStream({
|
|
149
|
+
* endpoint: "https://grpc.triton.one",
|
|
150
|
+
* token: process.env.GEYSER_TOKEN!,
|
|
151
|
+
* });
|
|
152
|
+
*
|
|
153
|
+
* stream.on("logs", (logs, sig, slot) => {
|
|
154
|
+
* const events = parser.parseLogs(logs);
|
|
155
|
+
* events.forEach(e => db.insertEvent(e));
|
|
156
|
+
* });
|
|
157
|
+
*
|
|
158
|
+
* await stream.connect();
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export class GeyserEventStream extends EventEmitter {
|
|
162
|
+
private readonly config: Required<GeyserConfig>;
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
164
|
+
private client: any = null;
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
166
|
+
private stream: any = null;
|
|
167
|
+
private reconnectAttempts = 0;
|
|
168
|
+
private _connected = false;
|
|
169
|
+
private _stopped = false;
|
|
170
|
+
|
|
171
|
+
constructor(config: GeyserConfig) {
|
|
172
|
+
super();
|
|
173
|
+
this.config = {
|
|
174
|
+
endpoint: config.endpoint,
|
|
175
|
+
token: config.token,
|
|
176
|
+
programId: config.programId ?? SAP_PROGRAM_ID,
|
|
177
|
+
commitment: config.commitment ?? "confirmed",
|
|
178
|
+
autoReconnect: config.autoReconnect ?? true,
|
|
179
|
+
reconnectDelayMs: config.reconnectDelayMs ?? 3_000,
|
|
180
|
+
maxReconnectAttempts: config.maxReconnectAttempts ?? 0,
|
|
181
|
+
includeFailedTxs: config.includeFailedTxs ?? false,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Whether the gRPC stream is currently connected. */
|
|
186
|
+
get connected(): boolean {
|
|
187
|
+
return this._connected;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Connect to the Yellowstone gRPC endpoint and start streaming.
|
|
192
|
+
*
|
|
193
|
+
* @throws If `@triton-one/yellowstone-grpc` is not installed.
|
|
194
|
+
*/
|
|
195
|
+
async connect(): Promise<void> {
|
|
196
|
+
this._stopped = false;
|
|
197
|
+
this.reconnectAttempts = 0;
|
|
198
|
+
|
|
199
|
+
// Dynamic import — yellowstone is an optional peer dependency
|
|
200
|
+
let YellowstoneClient: new (...args: unknown[]) => unknown;
|
|
201
|
+
try {
|
|
202
|
+
const mod = await import("@triton-one/yellowstone-grpc");
|
|
203
|
+
YellowstoneClient = mod.default ?? mod.Client;
|
|
204
|
+
} catch {
|
|
205
|
+
throw new Error(
|
|
206
|
+
"Missing dependency: @triton-one/yellowstone-grpc\n" +
|
|
207
|
+
"Install it with: npm i @triton-one/yellowstone-grpc",
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
212
|
+
this.client = new (YellowstoneClient as any)(
|
|
213
|
+
this.config.endpoint,
|
|
214
|
+
this.config.token,
|
|
215
|
+
undefined, // TLS options — use defaults
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
await this.subscribe();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Disconnect from the gRPC stream and stop reconnection.
|
|
223
|
+
*/
|
|
224
|
+
async disconnect(): Promise<void> {
|
|
225
|
+
this._stopped = true;
|
|
226
|
+
this._connected = false;
|
|
227
|
+
|
|
228
|
+
if (this.stream) {
|
|
229
|
+
try {
|
|
230
|
+
this.stream.cancel?.();
|
|
231
|
+
this.stream = null;
|
|
232
|
+
} catch {
|
|
233
|
+
// ignore cancel errors
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
this.emit("disconnected", "manual");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ─── Internal ──────────────────────────────────────
|
|
241
|
+
|
|
242
|
+
private async subscribe(): Promise<void> {
|
|
243
|
+
if (!this.client || this._stopped) return;
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
this.stream = await this.client.subscribe();
|
|
247
|
+
} catch (err) {
|
|
248
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
249
|
+
await this.maybeReconnect();
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Build the subscription request
|
|
254
|
+
const request = {
|
|
255
|
+
accounts: {},
|
|
256
|
+
slots: {},
|
|
257
|
+
transactions: {
|
|
258
|
+
sap: {
|
|
259
|
+
vote: false,
|
|
260
|
+
failed: this.config.includeFailedTxs,
|
|
261
|
+
signature: undefined,
|
|
262
|
+
accountInclude: [this.config.programId],
|
|
263
|
+
accountExclude: [],
|
|
264
|
+
accountRequired: [],
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
transactionsStatus: {},
|
|
268
|
+
blocks: {},
|
|
269
|
+
blocksMeta: {},
|
|
270
|
+
entry: {},
|
|
271
|
+
commitment: COMMITMENT_MAP[this.config.commitment] ?? 1,
|
|
272
|
+
accountsDataSlice: [],
|
|
273
|
+
ping: { id: 1 },
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// Send subscription
|
|
277
|
+
try {
|
|
278
|
+
await new Promise<void>((resolve, reject) => {
|
|
279
|
+
this.stream.write(request, (err: Error | null) => {
|
|
280
|
+
if (err) reject(err);
|
|
281
|
+
else resolve();
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
} catch (err) {
|
|
285
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
286
|
+
await this.maybeReconnect();
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
this._connected = true;
|
|
291
|
+
this.reconnectAttempts = 0;
|
|
292
|
+
this.emit("connected");
|
|
293
|
+
|
|
294
|
+
// Listen for data
|
|
295
|
+
this.stream.on("data", (data: GeyserUpdateMessage) => {
|
|
296
|
+
try {
|
|
297
|
+
this.handleMessage(data);
|
|
298
|
+
} catch (err) {
|
|
299
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
this.stream.on("error", (err: Error) => {
|
|
304
|
+
this.emit("error", err);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
this.stream.on("end", () => {
|
|
308
|
+
this._connected = false;
|
|
309
|
+
this.emit("disconnected", "stream-end");
|
|
310
|
+
this.maybeReconnect();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
this.stream.on("close", () => {
|
|
314
|
+
this._connected = false;
|
|
315
|
+
this.emit("disconnected", "stream-close");
|
|
316
|
+
this.maybeReconnect();
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private handleMessage(data: GeyserUpdateMessage): void {
|
|
321
|
+
// Respond to pings to keep the stream alive
|
|
322
|
+
if (data.ping) {
|
|
323
|
+
this.stream?.write({ ping: { id: data.ping.id } }, () => {});
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Extract transaction data
|
|
328
|
+
const tx = data.transaction;
|
|
329
|
+
if (!tx?.transaction?.transaction) return;
|
|
330
|
+
|
|
331
|
+
const meta = tx.transaction.meta;
|
|
332
|
+
if (!meta) return;
|
|
333
|
+
|
|
334
|
+
// Extract log messages from the transaction meta
|
|
335
|
+
const logs: string[] = meta.logMessages ?? [];
|
|
336
|
+
if (logs.length === 0) return;
|
|
337
|
+
|
|
338
|
+
const signature = tx.transaction.signature
|
|
339
|
+
? Buffer.from(tx.transaction.signature).toString("base64")
|
|
340
|
+
: "unknown";
|
|
341
|
+
|
|
342
|
+
const slot = Number(tx.slot ?? 0);
|
|
343
|
+
|
|
344
|
+
this.emit("logs", logs, signature, slot);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private async maybeReconnect(): Promise<void> {
|
|
348
|
+
if (this._stopped || !this.config.autoReconnect) return;
|
|
349
|
+
|
|
350
|
+
const max = this.config.maxReconnectAttempts;
|
|
351
|
+
if (max > 0 && this.reconnectAttempts >= max) {
|
|
352
|
+
this.emit(
|
|
353
|
+
"error",
|
|
354
|
+
new Error(`Max reconnect attempts (${max}) exceeded`),
|
|
355
|
+
);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
this.reconnectAttempts++;
|
|
360
|
+
this.emit("reconnecting", this.reconnectAttempts);
|
|
361
|
+
|
|
362
|
+
await new Promise((r) => setTimeout(r, this.config.reconnectDelayMs));
|
|
363
|
+
|
|
364
|
+
if (!this._stopped) {
|
|
365
|
+
await this.subscribe();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ─── Internal Yellowstone message types ─────────────
|
|
371
|
+
|
|
372
|
+
interface GeyserUpdateMessage {
|
|
373
|
+
ping?: { id: number };
|
|
374
|
+
transaction?: {
|
|
375
|
+
slot?: string | number;
|
|
376
|
+
transaction?: {
|
|
377
|
+
signature?: Uint8Array;
|
|
378
|
+
transaction?: unknown;
|
|
379
|
+
meta?: {
|
|
380
|
+
logMessages?: string[];
|
|
381
|
+
};
|
|
382
|
+
};
|
|
383
|
+
};
|
|
384
|
+
}
|