@lasersell/lasersell-sdk 0.3.0 → 1.0.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.
@@ -48,11 +48,31 @@ export interface MarketContextMsg {
48
48
  raydium_cpmm?: RaydiumCpmmContextMsg;
49
49
  }
50
50
 
51
+ export interface TakeProfitLevelMsg {
52
+ profit_pct: number;
53
+ sell_pct: number;
54
+ trailing_stop_pct: number;
55
+ }
56
+
51
57
  export interface StrategyConfigMsg {
52
58
  target_profit_pct: number;
53
59
  stop_loss_pct: number;
54
60
  trailing_stop_pct?: number;
55
61
  sell_on_graduation?: boolean;
62
+ take_profit_levels?: TakeProfitLevelMsg[];
63
+ liquidity_guard?: boolean;
64
+ breakeven_trail_pct?: number;
65
+ }
66
+
67
+ export interface AutoBuyConfigMsg {
68
+ wallet_pubkey: string;
69
+ amount_quote_units: number;
70
+ amount_usd1_units?: number;
71
+ }
72
+
73
+ export interface WatchWalletEntryMsg {
74
+ pubkey: string;
75
+ auto_buy?: AutoBuyConfigMsg;
56
76
  }
57
77
 
58
78
  export interface LimitsMsg {
@@ -62,6 +82,7 @@ export interface LimitsMsg {
62
82
  max_wallets_per_session: number;
63
83
  max_positions_per_wallet: number;
64
84
  max_sessions_per_api_key: number;
85
+ max_watch_wallets_per_session: number;
65
86
  }
66
87
 
67
88
  export interface PingClientMessage {
@@ -73,6 +94,9 @@ export interface ConfigureClientMessage {
73
94
  type: "configure";
74
95
  wallet_pubkeys: string[];
75
96
  strategy: StrategyConfigMsg;
97
+ send_mode?: string;
98
+ tip_lamports?: number;
99
+ watch_wallets?: WatchWalletEntryMsg[];
76
100
  }
77
101
 
78
102
  export interface UpdateStrategyClientMessage {
@@ -98,13 +122,26 @@ export interface UpdateWalletsClientMessage {
98
122
  wallet_pubkeys: string[];
99
123
  }
100
124
 
125
+ export interface UpdateWatchWalletsClientMessage {
126
+ type: "update_watch_wallets";
127
+ watch_wallets: WatchWalletEntryMsg[];
128
+ }
129
+
130
+ export interface UpdatePositionStrategyClientMessage {
131
+ type: "update_position_strategy";
132
+ position_id: number;
133
+ strategy: StrategyConfigMsg;
134
+ }
135
+
101
136
  export type ClientMessage =
102
137
  | PingClientMessage
103
138
  | ConfigureClientMessage
104
139
  | UpdateStrategyClientMessage
105
140
  | ClosePositionClientMessage
106
141
  | RequestExitSignalClientMessage
107
- | UpdateWalletsClientMessage;
142
+ | UpdateWalletsClientMessage
143
+ | UpdateWatchWalletsClientMessage
144
+ | UpdatePositionStrategyClientMessage;
108
145
 
109
146
  export interface HelloOkServerMessage {
110
147
  type: "hello_ok";
@@ -130,6 +167,9 @@ export interface PnlUpdateServerMessage {
130
167
  profit_units: number;
131
168
  proceeds_units: number;
132
169
  server_time_ms: number;
170
+ token_price_quote?: number;
171
+ market_cap_quote?: number;
172
+ watched: boolean;
133
173
  }
134
174
 
135
175
  export interface SlippageBandMsg {
@@ -144,6 +184,7 @@ export interface LiquiditySnapshotServerMessage {
144
184
  bands: SlippageBandMsg[];
145
185
  liquidity_trend: string;
146
186
  server_time_ms: number;
187
+ watched: boolean;
147
188
  }
148
189
 
149
190
  export interface BalanceUpdateServerMessage {
@@ -167,6 +208,15 @@ export interface PositionOpenedServerMessage {
167
208
  entry_quote_units: number;
168
209
  market_context?: MarketContextMsg;
169
210
  slot: number;
211
+ token_name?: string;
212
+ token_symbol?: string;
213
+ token_decimals?: number;
214
+ token_price_quote?: number;
215
+ market_cap_quote?: number;
216
+ pool_liquidity_quote?: number;
217
+ opened_at_ms?: number;
218
+ mirror_source?: string;
219
+ watched: boolean;
170
220
  }
171
221
 
172
222
  export interface PositionClosedServerMessage {
@@ -177,6 +227,8 @@ export interface PositionClosedServerMessage {
177
227
  token_account?: string;
178
228
  reason: string;
179
229
  slot: number;
230
+ mirror_source?: string;
231
+ watched: boolean;
180
232
  }
181
233
 
182
234
  export interface ExitSignalWithTxServerMessage {
@@ -193,6 +245,23 @@ export interface ExitSignalWithTxServerMessage {
193
245
  triggered_at_ms: number;
194
246
  market_context?: MarketContextMsg;
195
247
  unsigned_tx_b64: string;
248
+ sell_tokens?: number;
249
+ level_index?: number;
250
+ mirror_source?: string;
251
+ watched: boolean;
252
+ }
253
+
254
+ export interface TradeTickServerMessage {
255
+ type: "trade_tick";
256
+ position_id: number;
257
+ time_ms: number;
258
+ side: string;
259
+ token_amount: number;
260
+ quote_amount: number;
261
+ price_quote: number;
262
+ maker?: string;
263
+ tx_signature?: string;
264
+ watched: boolean;
196
265
  }
197
266
 
198
267
  export type ServerMessage =
@@ -204,7 +273,8 @@ export type ServerMessage =
204
273
  | BalanceUpdateServerMessage
205
274
  | PositionOpenedServerMessage
206
275
  | PositionClosedServerMessage
207
- | ExitSignalWithTxServerMessage;
276
+ | ExitSignalWithTxServerMessage
277
+ | TradeTickServerMessage;
208
278
 
209
279
  export function clientMessageFromText(text: string): ClientMessage {
210
280
  let parsed: unknown;
@@ -229,11 +299,24 @@ export function clientMessageFromUnknown(value: unknown): ClientMessage {
229
299
  }
230
300
  case "configure": {
231
301
  const wallet_pubkeys = parseWalletPubkeys(obj);
232
- return {
302
+ const msg: ConfigureClientMessage = {
233
303
  type: "configure",
234
304
  wallet_pubkeys,
235
305
  strategy: parseStrategyConfig(obj.strategy),
236
306
  };
307
+ const send_mode = optionalString(obj.send_mode, "configure.send_mode");
308
+ if (send_mode !== undefined) {
309
+ msg.send_mode = send_mode;
310
+ }
311
+ const tip_lamports = optionalNumber(obj.tip_lamports, "configure.tip_lamports");
312
+ if (tip_lamports !== undefined) {
313
+ msg.tip_lamports = tip_lamports;
314
+ }
315
+ const watch_wallets = optionalWatchWallets(obj.watch_wallets);
316
+ if (watch_wallets !== undefined && watch_wallets.length > 0) {
317
+ msg.watch_wallets = watch_wallets;
318
+ }
319
+ return msg;
237
320
  }
238
321
  case "update_strategy": {
239
322
  return {
@@ -276,6 +359,20 @@ export function clientMessageFromUnknown(value: unknown): ClientMessage {
276
359
  wallet_pubkeys,
277
360
  };
278
361
  }
362
+ case "update_watch_wallets": {
363
+ const watch_wallets = parseWatchWallets(obj.watch_wallets);
364
+ return {
365
+ type: "update_watch_wallets",
366
+ watch_wallets,
367
+ };
368
+ }
369
+ case "update_position_strategy": {
370
+ return {
371
+ type: "update_position_strategy",
372
+ position_id: asNumber(obj.position_id, "update_position_strategy.position_id"),
373
+ strategy: parseStrategyConfig(obj.strategy),
374
+ };
375
+ }
279
376
  default:
280
377
  throw new Error(`unsupported client message type: ${type}`);
281
378
  }
@@ -322,13 +419,24 @@ export function serverMessageFromUnknown(value: unknown): ServerMessage {
322
419
  };
323
420
  }
324
421
  case "pnl_update": {
325
- return {
422
+ const msg: PnlUpdateServerMessage = {
326
423
  type: "pnl_update",
327
424
  position_id: asNumber(obj.position_id, "pnl_update.position_id"),
328
425
  profit_units: asNumber(obj.profit_units, "pnl_update.profit_units"),
329
426
  proceeds_units: asNumber(obj.proceeds_units, "pnl_update.proceeds_units"),
330
427
  server_time_ms: asNumber(obj.server_time_ms, "pnl_update.server_time_ms"),
428
+ watched: false,
331
429
  };
430
+ const token_price_quote = optionalNumber(obj.token_price_quote, "pnl_update.token_price_quote");
431
+ if (token_price_quote !== undefined) {
432
+ msg.token_price_quote = token_price_quote;
433
+ }
434
+ const market_cap_quote = optionalNumber(obj.market_cap_quote, "pnl_update.market_cap_quote");
435
+ if (market_cap_quote !== undefined) {
436
+ msg.market_cap_quote = market_cap_quote;
437
+ }
438
+ msg.watched = optionalBoolean(obj.watched, "pnl_update.watched") ?? false;
439
+ return msg;
332
440
  }
333
441
  case "liquidity_snapshot": {
334
442
  const rawBands = obj.bands;
@@ -351,6 +459,7 @@ export function serverMessageFromUnknown(value: unknown): ServerMessage {
351
459
  bands,
352
460
  liquidity_trend: asString(obj.liquidity_trend, "liquidity_snapshot.liquidity_trend"),
353
461
  server_time_ms: asNumber(obj.server_time_ms, "liquidity_snapshot.server_time_ms"),
462
+ watched: optionalBoolean(obj.watched, "liquidity_snapshot.watched") ?? false,
354
463
  };
355
464
  }
356
465
  case "balance_update": {
@@ -371,7 +480,7 @@ export function serverMessageFromUnknown(value: unknown): ServerMessage {
371
480
  };
372
481
  }
373
482
  case "position_opened": {
374
- return {
483
+ const msg: PositionOpenedServerMessage = {
375
484
  type: "position_opened",
376
485
  position_id: asNumber(obj.position_id, "position_opened.position_id"),
377
486
  wallet_pubkey: asString(
@@ -394,10 +503,45 @@ export function serverMessageFromUnknown(value: unknown): ServerMessage {
394
503
  "position_opened.market_context",
395
504
  ),
396
505
  slot: asNumber(obj.slot, "position_opened.slot"),
506
+ watched: false,
397
507
  };
508
+ const token_name = optionalString(obj.token_name, "position_opened.token_name");
509
+ if (token_name !== undefined) {
510
+ msg.token_name = token_name;
511
+ }
512
+ const token_symbol = optionalString(obj.token_symbol, "position_opened.token_symbol");
513
+ if (token_symbol !== undefined) {
514
+ msg.token_symbol = token_symbol;
515
+ }
516
+ const token_decimals = optionalNumber(obj.token_decimals, "position_opened.token_decimals");
517
+ if (token_decimals !== undefined) {
518
+ msg.token_decimals = token_decimals;
519
+ }
520
+ const token_price_quote = optionalNumber(obj.token_price_quote, "position_opened.token_price_quote");
521
+ if (token_price_quote !== undefined) {
522
+ msg.token_price_quote = token_price_quote;
523
+ }
524
+ const market_cap_quote = optionalNumber(obj.market_cap_quote, "position_opened.market_cap_quote");
525
+ if (market_cap_quote !== undefined) {
526
+ msg.market_cap_quote = market_cap_quote;
527
+ }
528
+ const pool_liquidity_quote = optionalNumber(obj.pool_liquidity_quote, "position_opened.pool_liquidity_quote");
529
+ if (pool_liquidity_quote !== undefined) {
530
+ msg.pool_liquidity_quote = pool_liquidity_quote;
531
+ }
532
+ const opened_at_ms = optionalNumber(obj.opened_at_ms, "position_opened.opened_at_ms");
533
+ if (opened_at_ms !== undefined) {
534
+ msg.opened_at_ms = opened_at_ms;
535
+ }
536
+ const mirror_source = optionalString(obj.mirror_source, "position_opened.mirror_source");
537
+ if (mirror_source !== undefined) {
538
+ msg.mirror_source = mirror_source;
539
+ }
540
+ msg.watched = optionalBoolean(obj.watched, "position_opened.watched") ?? false;
541
+ return msg;
398
542
  }
399
543
  case "position_closed": {
400
- return {
544
+ const msg: PositionClosedServerMessage = {
401
545
  type: "position_closed",
402
546
  position_id: asNumber(obj.position_id, "position_closed.position_id"),
403
547
  wallet_pubkey: asString(
@@ -411,10 +555,17 @@ export function serverMessageFromUnknown(value: unknown): ServerMessage {
411
555
  ),
412
556
  reason: asString(obj.reason, "position_closed.reason"),
413
557
  slot: asNumber(obj.slot, "position_closed.slot"),
558
+ watched: false,
414
559
  };
560
+ const mirror_source = optionalString(obj.mirror_source, "position_closed.mirror_source");
561
+ if (mirror_source !== undefined) {
562
+ msg.mirror_source = mirror_source;
563
+ }
564
+ msg.watched = optionalBoolean(obj.watched, "position_closed.watched") ?? false;
565
+ return msg;
415
566
  }
416
567
  case "exit_signal_with_tx": {
417
- return {
568
+ const msg: ExitSignalWithTxServerMessage = {
418
569
  type: "exit_signal_with_tx",
419
570
  session_id: asNumber(obj.session_id, "exit_signal_with_tx.session_id"),
420
571
  position_id: asNumber(obj.position_id, "exit_signal_with_tx.position_id"),
@@ -449,6 +600,35 @@ export function serverMessageFromUnknown(value: unknown): ServerMessage {
449
600
  obj.unsigned_tx_b64,
450
601
  "exit_signal_with_tx.unsigned_tx_b64",
451
602
  ),
603
+ watched: false,
604
+ };
605
+ const sell_tokens = optionalNumber(obj.sell_tokens, "exit_signal_with_tx.sell_tokens");
606
+ if (sell_tokens !== undefined) {
607
+ msg.sell_tokens = sell_tokens;
608
+ }
609
+ const level_index = optionalNumber(obj.level_index, "exit_signal_with_tx.level_index");
610
+ if (level_index !== undefined) {
611
+ msg.level_index = level_index;
612
+ }
613
+ const mirror_source = optionalString(obj.mirror_source, "exit_signal_with_tx.mirror_source");
614
+ if (mirror_source !== undefined) {
615
+ msg.mirror_source = mirror_source;
616
+ }
617
+ msg.watched = optionalBoolean(obj.watched, "exit_signal_with_tx.watched") ?? false;
618
+ return msg;
619
+ }
620
+ case "trade_tick": {
621
+ return {
622
+ type: "trade_tick",
623
+ position_id: asNumber(obj.position_id, "trade_tick.position_id"),
624
+ time_ms: asNumber(obj.time_ms, "trade_tick.time_ms"),
625
+ side: asString(obj.side, "trade_tick.side"),
626
+ token_amount: asNumber(obj.token_amount, "trade_tick.token_amount"),
627
+ quote_amount: asNumber(obj.quote_amount, "trade_tick.quote_amount"),
628
+ price_quote: asNumber(obj.price_quote, "trade_tick.price_quote"),
629
+ maker: optionalString(obj.maker, "trade_tick.maker"),
630
+ tx_signature: optionalString(obj.tx_signature, "trade_tick.tx_signature"),
631
+ watched: optionalBoolean(obj.watched, "trade_tick.watched") ?? false,
452
632
  };
453
633
  }
454
634
  default:
@@ -507,6 +687,34 @@ function parseStrategyConfig(value: unknown): StrategyConfigMsg {
507
687
  result.sell_on_graduation = sellOnGraduation;
508
688
  }
509
689
 
690
+ const rawLevels = obj.take_profit_levels;
691
+ if (Array.isArray(rawLevels)) {
692
+ result.take_profit_levels = rawLevels.map(
693
+ (item: unknown, idx: number) => {
694
+ const level = asRecord(item, `strategy.take_profit_levels[${idx}]`);
695
+ return {
696
+ profit_pct: asNumber(level.profit_pct, `strategy.take_profit_levels[${idx}].profit_pct`),
697
+ sell_pct: asNumber(level.sell_pct, `strategy.take_profit_levels[${idx}].sell_pct`),
698
+ trailing_stop_pct: asNumber(level.trailing_stop_pct, `strategy.take_profit_levels[${idx}].trailing_stop_pct`),
699
+ };
700
+ },
701
+ );
702
+ } else {
703
+ result.take_profit_levels = [];
704
+ }
705
+
706
+ const liquidityGuard = optionalBoolean(
707
+ obj.liquidity_guard,
708
+ "strategy.liquidity_guard",
709
+ );
710
+ result.liquidity_guard = liquidityGuard ?? false;
711
+
712
+ const breakevenTrailPct = optionalNumber(
713
+ obj.breakeven_trail_pct,
714
+ "strategy.breakeven_trail_pct",
715
+ );
716
+ result.breakeven_trail_pct = breakevenTrailPct ?? 0;
717
+
510
718
  return result;
511
719
  }
512
720
 
@@ -534,6 +742,11 @@ function parseLimits(value: unknown): LimitsMsg {
534
742
  obj.max_sessions_per_api_key,
535
743
  "limits.max_sessions_per_api_key",
536
744
  ) ?? 0,
745
+ max_watch_wallets_per_session:
746
+ optionalNumber(
747
+ obj.max_watch_wallets_per_session,
748
+ "limits.max_watch_wallets_per_session",
749
+ ) ?? 0,
537
750
  };
538
751
  }
539
752
 
@@ -583,6 +796,38 @@ function parseMarketType(value: unknown, path: string): MarketTypeMsg {
583
796
  }
584
797
  }
585
798
 
799
+ function parseWatchWallets(value: unknown): WatchWalletEntryMsg[] {
800
+ if (!Array.isArray(value)) {
801
+ throw new Error("watch_wallets must be an array");
802
+ }
803
+ return value.map((item: unknown, idx: number) => {
804
+ const entry = asRecord(item, `watch_wallets[${idx}]`);
805
+ const result: WatchWalletEntryMsg = {
806
+ pubkey: asString(entry.pubkey, `watch_wallets[${idx}].pubkey`),
807
+ };
808
+ if (entry.auto_buy !== undefined && entry.auto_buy !== null) {
809
+ const ab = asRecord(entry.auto_buy, `watch_wallets[${idx}].auto_buy`);
810
+ const autoBuy: AutoBuyConfigMsg = {
811
+ wallet_pubkey: asString(ab.wallet_pubkey, `watch_wallets[${idx}].auto_buy.wallet_pubkey`),
812
+ amount_quote_units: asNumber(ab.amount_quote_units, `watch_wallets[${idx}].auto_buy.amount_quote_units`),
813
+ };
814
+ const usd1 = optionalNumber(ab.amount_usd1_units, `watch_wallets[${idx}].auto_buy.amount_usd1_units`);
815
+ if (usd1 !== undefined) {
816
+ autoBuy.amount_usd1_units = usd1;
817
+ }
818
+ result.auto_buy = autoBuy;
819
+ }
820
+ return result;
821
+ });
822
+ }
823
+
824
+ function optionalWatchWallets(value: unknown): WatchWalletEntryMsg[] | undefined {
825
+ if (value === undefined || value === null) {
826
+ return undefined;
827
+ }
828
+ return parseWatchWallets(value);
829
+ }
830
+
586
831
  function optionalBoolean(value: unknown, path: string): boolean | undefined {
587
832
  if (value === undefined || value === null) {
588
833
  return undefined;
@@ -23,6 +23,15 @@ export interface PositionHandle {
23
23
  token_program?: string;
24
24
  tokens: number;
25
25
  entry_quote_units: number;
26
+ token_name?: string;
27
+ token_symbol?: string;
28
+ token_decimals?: number;
29
+ market_type?: string;
30
+ launch_platform?: string;
31
+ token_price_quote?: number;
32
+ market_cap_quote?: number;
33
+ pool_liquidity_quote?: number;
34
+ opened_at_ms?: number;
26
35
  }
27
36
 
28
37
  export type StreamEvent =
@@ -54,6 +63,11 @@ export type StreamEvent =
54
63
  type: "liquidity_snapshot";
55
64
  handle?: PositionHandle;
56
65
  message: ServerMessage;
66
+ }
67
+ | {
68
+ type: "trade_tick";
69
+ handle?: PositionHandle;
70
+ message: ServerMessage;
57
71
  };
58
72
 
59
73
  export class StreamSession {
@@ -174,14 +188,24 @@ export class StreamSession {
174
188
  private applyMessage(message: ServerMessage): StreamEvent {
175
189
  switch (message.type) {
176
190
  case "position_opened": {
191
+ const msg = message;
177
192
  const handle: PositionHandle = {
178
- position_id: message.position_id,
179
- token_account: message.token_account,
180
- wallet_pubkey: message.wallet_pubkey,
181
- mint: message.mint,
182
- token_program: message.token_program,
183
- tokens: message.tokens,
184
- entry_quote_units: message.entry_quote_units,
193
+ position_id: msg.position_id,
194
+ token_account: msg.token_account,
195
+ wallet_pubkey: msg.wallet_pubkey,
196
+ mint: msg.mint,
197
+ token_program: msg.token_program,
198
+ tokens: msg.tokens,
199
+ entry_quote_units: msg.entry_quote_units,
200
+ token_name: msg.token_name,
201
+ token_symbol: msg.token_symbol,
202
+ token_decimals: msg.token_decimals,
203
+ market_type: msg.market_context?.market_type?.toLowerCase(),
204
+ launch_platform: undefined,
205
+ token_price_quote: msg.token_price_quote,
206
+ market_cap_quote: msg.market_cap_quote,
207
+ pool_liquidity_quote: msg.pool_liquidity_quote,
208
+ opened_at_ms: msg.opened_at_ms,
185
209
  };
186
210
 
187
211
  this.positionsById.set(message.position_id, handle);
@@ -237,6 +261,14 @@ export class StreamSession {
237
261
  message,
238
262
  };
239
263
  }
264
+ case "trade_tick": {
265
+ const handle = this.findPosition(message.position_id);
266
+ return {
267
+ type: "trade_tick",
268
+ handle: handle ? { ...handle } : undefined,
269
+ message,
270
+ };
271
+ }
240
272
  default: {
241
273
  return {
242
274
  type: "message",
@@ -403,5 +435,8 @@ function defaultStrategy(): StrategyConfigMsg {
403
435
  return {
404
436
  target_profit_pct: 0,
405
437
  stop_loss_pct: 0,
438
+ take_profit_levels: [],
439
+ liquidity_guard: false,
440
+ breakeven_trail_pct: 0,
406
441
  };
407
442
  }