@liquid-af/sdk 0.4.1 → 0.5.1

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 (87) hide show
  1. package/dist/client.d.ts +7 -2
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +10 -3
  4. package/dist/client.js.map +1 -1
  5. package/dist/config.d.ts +2 -0
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +2 -0
  8. package/dist/config.js.map +1 -1
  9. package/dist/events/parser.d.ts +8 -3
  10. package/dist/events/parser.d.ts.map +1 -1
  11. package/dist/events/parser.js +72 -17
  12. package/dist/events/parser.js.map +1 -1
  13. package/dist/idl/index.d.ts +12 -1
  14. package/dist/idl/index.d.ts.map +1 -1
  15. package/dist/idl/index.js +12 -1
  16. package/dist/idl/index.js.map +1 -1
  17. package/dist/idl/liquid.d.ts +7116 -2254
  18. package/dist/idl/liquid.d.ts.map +1 -1
  19. package/dist/idl/liquid.json +7200 -2338
  20. package/dist/idl/liquid_events.d.ts +3118 -0
  21. package/dist/idl/liquid_events.d.ts.map +1 -0
  22. package/dist/idl/liquid_events.js +2 -0
  23. package/dist/idl/liquid_events.js.map +1 -0
  24. package/dist/idl/liquid_events.json +3111 -0
  25. package/dist/idl/liquid_fees.d.ts +539 -0
  26. package/dist/idl/liquid_fees.d.ts.map +1 -1
  27. package/dist/idl/liquid_fees.json +539 -0
  28. package/dist/idl/liquid_state.d.ts +350 -0
  29. package/dist/idl/liquid_state.d.ts.map +1 -1
  30. package/dist/idl/liquid_state.json +350 -0
  31. package/dist/idl/liquid_swap.d.ts +1334 -17
  32. package/dist/idl/liquid_swap.d.ts.map +1 -1
  33. package/dist/idl/liquid_swap.json +1334 -17
  34. package/dist/idl/patch-idl.d.ts.map +1 -1
  35. package/dist/idl/patch-idl.js +1 -0
  36. package/dist/idl/patch-idl.js.map +1 -1
  37. package/dist/index.d.ts +2 -2
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +1 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/instructions/index.d.ts +4 -4
  42. package/dist/instructions/index.d.ts.map +1 -1
  43. package/dist/instructions/index.js +2 -2
  44. package/dist/instructions/index.js.map +1 -1
  45. package/dist/instructions/liquid-fees.d.ts +12 -0
  46. package/dist/instructions/liquid-fees.d.ts.map +1 -1
  47. package/dist/instructions/liquid-fees.js +17 -0
  48. package/dist/instructions/liquid-fees.js.map +1 -1
  49. package/dist/instructions/liquid.d.ts +15 -1
  50. package/dist/instructions/liquid.d.ts.map +1 -1
  51. package/dist/instructions/liquid.js +32 -2
  52. package/dist/instructions/liquid.js.map +1 -1
  53. package/dist/pda/index.d.ts +2 -2
  54. package/dist/pda/index.d.ts.map +1 -1
  55. package/dist/pda/index.js +2 -2
  56. package/dist/pda/index.js.map +1 -1
  57. package/dist/pda/liquid-fees.d.ts +7 -0
  58. package/dist/pda/liquid-fees.d.ts.map +1 -1
  59. package/dist/pda/liquid-fees.js +10 -0
  60. package/dist/pda/liquid-fees.js.map +1 -1
  61. package/dist/pda/liquid.d.ts +10 -3
  62. package/dist/pda/liquid.d.ts.map +1 -1
  63. package/dist/pda/liquid.js +14 -5
  64. package/dist/pda/liquid.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/client.ts +14 -2
  67. package/src/config.ts +8 -0
  68. package/src/events/parser.ts +88 -19
  69. package/src/idl/index.ts +26 -1
  70. package/src/idl/liquid.json +7200 -2338
  71. package/src/idl/liquid.ts +7200 -2338
  72. package/src/idl/liquid_events.json +3111 -0
  73. package/src/idl/liquid_events.ts +3117 -0
  74. package/src/idl/liquid_fees.json +539 -0
  75. package/src/idl/liquid_fees.ts +539 -0
  76. package/src/idl/liquid_state.json +350 -0
  77. package/src/idl/liquid_state.ts +350 -0
  78. package/src/idl/liquid_swap.json +1334 -17
  79. package/src/idl/liquid_swap.ts +1334 -17
  80. package/src/idl/patch-idl.ts +1 -0
  81. package/src/index.ts +3 -0
  82. package/src/instructions/index.ts +4 -0
  83. package/src/instructions/liquid-fees.ts +26 -0
  84. package/src/instructions/liquid.ts +70 -1
  85. package/src/pda/index.ts +2 -0
  86. package/src/pda/liquid-fees.ts +13 -0
  87. package/src/pda/liquid.ts +21 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liquid-af/sdk",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "TypeScript SDK for the Liquid DeFi protocol on Solana",
5
5
  "type": "module",
6
6
  "publishConfig": {
package/src/client.ts CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  buildMigrateNative,
29
29
  buildInitializeNativeReferralVault,
30
30
  buildWithdrawReferralRewards,
31
+ buildWithdrawReferralTokenRewards,
31
32
  buildExecuteBuybackNative,
32
33
  buildExecuteBuybackToken,
33
34
  buildCreateStableCurve,
@@ -250,13 +251,24 @@ export class LiquidClient {
250
251
  });
251
252
  }
252
253
 
253
- /** Builds a withdrawReferralRewards instruction. */
254
+ /** Builds a withdrawReferralRewards instruction (native SOL). */
254
255
  buildWithdrawReferralRewards(params: {
255
256
  user: PublicKey;
256
257
  }): Promise<TransactionInstruction> {
257
258
  return buildWithdrawReferralRewards({ ...params, config: this.config });
258
259
  }
259
260
 
261
+ /** Builds a withdrawReferralTokenRewards instruction (SPL token). */
262
+ buildWithdrawReferralTokenRewards(params: {
263
+ user: PublicKey;
264
+ quoteMint: PublicKey;
265
+ }): Promise<TransactionInstruction> {
266
+ return buildWithdrawReferralTokenRewards({
267
+ ...params,
268
+ config: this.config,
269
+ });
270
+ }
271
+
260
272
  /** Builds an executeBuybackNative instruction for native SOL curves. Permissionless; requires revoked fee config. */
261
273
  buildExecuteBuybackNative(params: {
262
274
  payer: PublicKey;
@@ -372,7 +384,7 @@ export class LiquidClient {
372
384
  return buildMigrateStable({ ...params, config: this.config });
373
385
  }
374
386
 
375
- /** Builds an initializeReferralTokenVault instruction (creates a referral token vault for stable curves). */
387
+ /** Builds an initializeReferralTokenVault instruction (creates a PDA token vault for stable curve referral rewards). */
376
388
  buildInitializeReferralTokenVault(params: {
377
389
  user: PublicKey;
378
390
  quoteMint: PublicKey;
package/src/config.ts CHANGED
@@ -12,6 +12,8 @@ export interface LiquidConfig {
12
12
  liquidFeesProgramId: PublicKey;
13
13
  /** Program ID for the user state program */
14
14
  liquidStateProgramId: PublicKey;
15
+ /** Program ID for the events program */
16
+ liquidEventsProgramId: PublicKey;
15
17
  }
16
18
 
17
19
  /** Mainnet program IDs */
@@ -28,6 +30,9 @@ export const MAINNET_CONFIG: LiquidConfig = {
28
30
  liquidStateProgramId: new PublicKey(
29
31
  "State3HtEfi7cXdsTpAtRoBvrij8zSFCiGTAVWmYH2d",
30
32
  ),
33
+ liquidEventsProgramId: new PublicKey(
34
+ "EventsQeXA43nLKR69DhHwNsJ6aM512AweMCgG3wG8zG",
35
+ ),
31
36
  } as const;
32
37
 
33
38
  /** Devnet program IDs (liquid differs, others same as mainnet) */
@@ -44,6 +49,9 @@ export const DEVNET_CONFIG: LiquidConfig = {
44
49
  liquidStateProgramId: new PublicKey(
45
50
  "9ZcKPa3HAEVEKxwFX8fYD56ZJCKPEQgqjgr9rfUvtwKJ",
46
51
  ),
52
+ liquidEventsProgramId: new PublicKey(
53
+ "Bast7hBDiqSsxiwEmqazwvPvXC3N4z8UQR5ZmkqXnCiY",
54
+ ),
47
55
  } as const;
48
56
 
49
57
  /** Localnet program IDs (same as mainnet per Anchor.toml) */
@@ -1,4 +1,4 @@
1
- import { BorshCoder, EventParser, type Program } from "@coral-xyz/anchor";
1
+ import { BorshCoder, type Program } from "@coral-xyz/anchor";
2
2
 
3
3
  /** Parsed event with name and data */
4
4
  export interface ParsedEvent<T = unknown> {
@@ -6,8 +6,15 @@ export interface ParsedEvent<T = unknown> {
6
6
  data: T;
7
7
  }
8
8
 
9
+ const PROGRAM_DATA = "Program data: ";
10
+ const PROGRAM_LOG = "Program log: ";
11
+ const INVOKE_RE = /^Program ([1-9A-HJ-NP-Za-km-z]+) invoke \[(\d+)\]$/;
12
+ const EXIT_RE = /^Program ([1-9A-HJ-NP-Za-km-z]+) (success|failed)/;
13
+
9
14
  /**
10
15
  * Parses events from transaction logs for a given program.
16
+ * Unlike Anchor's built-in EventParser, this correctly identifies events
17
+ * from programs invoked via CPI (not just top-level invocations).
11
18
  *
12
19
  * @param logs - Transaction log messages
13
20
  * @param program - The Anchor program to parse events for
@@ -17,16 +24,11 @@ export const parseTransactionEvents = (
17
24
  logs: string[],
18
25
  program: Program,
19
26
  ): ParsedEvent[] => {
20
- const parser = new EventParser(
21
- program.programId,
27
+ return parseCpiLogs(
28
+ logs,
29
+ program.programId.toString(),
22
30
  new BorshCoder(program.idl),
23
31
  );
24
- const events: ParsedEvent[] = [];
25
- const generator = parser.parseLogs(logs);
26
- for (const event of generator) {
27
- events.push({ name: event.name, data: event.data });
28
- }
29
- return events;
30
32
  };
31
33
 
32
34
  /**
@@ -49,10 +51,13 @@ export const addEventListener = <T>(
49
51
  };
50
52
 
51
53
  /**
52
- * Registers an event listener, fires a trigger, and polls until the event
53
- * arrives or the timeout is exceeded.
54
+ * Subscribes to logs via WebSocket, fires a trigger, and polls until the
55
+ * event arrives or the timeout is exceeded.
54
56
  *
55
- * @param program - The Anchor program
57
+ * Uses CPI-aware log parsing so events emitted by programs that are only
58
+ * invoked via CPI (e.g., a centralized events program) are correctly detected.
59
+ *
60
+ * @param program - The Anchor program whose events to listen for
56
61
  * @param eventName - Name of the event to wait for
57
62
  * @param trigger - Async function to trigger the event (e.g., sendAndConfirm)
58
63
  * @param timeoutMs - Maximum wait time in milliseconds (default: 5000)
@@ -67,24 +72,88 @@ export async function waitForEvent<TEvent, TResult = string>(
67
72
  timeoutMs = 5000,
68
73
  ): Promise<{ result: TResult; event: TEvent }> {
69
74
  let eventData: TEvent | null = null;
70
- const listenerId = program.addEventListener(eventName, (data: TEvent) => {
71
- eventData = data;
72
- });
75
+ const programId = program.programId.toString();
76
+ const coder = new BorshCoder(program.idl);
77
+
78
+ // Subscribe to logs mentioning this program (includes CPI invocations)
79
+ const subscriptionId = program.provider.connection.onLogs(
80
+ program.programId,
81
+ (logs) => {
82
+ if (logs.err) return;
83
+ const events = parseCpiLogs(logs.logs, programId, coder);
84
+ for (const event of events) {
85
+ if (event.name === eventName) {
86
+ eventData = event.data as TEvent;
87
+ }
88
+ }
89
+ },
90
+ );
91
+
73
92
  try {
74
93
  const result = await trigger();
75
94
  const start = Date.now();
76
95
  while (!eventData && Date.now() - start < timeoutMs) {
77
96
  await new Promise((r) => setTimeout(r, 200));
78
97
  }
79
- await program.removeEventListener(listenerId);
80
98
  if (!eventData) {
81
99
  throw new Error(
82
100
  `Event '${eventName}' not received within ${timeoutMs}ms`,
83
101
  );
84
102
  }
85
103
  return { result, event: eventData };
86
- } catch (err) {
87
- await program.removeEventListener(listenerId);
88
- throw err;
104
+ } finally {
105
+ await program.provider.connection.removeOnLogsListener(subscriptionId);
89
106
  }
90
107
  }
108
+
109
+ /**
110
+ * Parses events from transaction logs, properly handling CPI contexts.
111
+ *
112
+ * Anchor's built-in EventParser pushes a generic "cpi" string onto its
113
+ * execution stack for nested invocations, so it cannot identify events
114
+ * emitted by a CPI-only program. This parser extracts the actual program
115
+ * ID from each `invoke` log line, enabling correct attribution of events
116
+ * to programs at any CPI depth.
117
+ */
118
+ function parseCpiLogs(
119
+ logs: string[],
120
+ programId: string,
121
+ coder: BorshCoder,
122
+ ): ParsedEvent[] {
123
+ const events: ParsedEvent[] = [];
124
+ const stack: string[] = [];
125
+
126
+ for (const log of logs) {
127
+ if (!log.startsWith("Program ")) continue;
128
+
129
+ const invokeMatch = INVOKE_RE.exec(log);
130
+ if (invokeMatch) {
131
+ stack.push(invokeMatch[1]);
132
+ continue;
133
+ }
134
+
135
+ const exitMatch = EXIT_RE.exec(log);
136
+ if (exitMatch) {
137
+ stack.pop();
138
+ continue;
139
+ }
140
+
141
+ // Only try to decode events when inside the target program's context
142
+ if (stack.length > 0 && stack[stack.length - 1] === programId) {
143
+ let logStr: string | null = null;
144
+ if (log.startsWith(PROGRAM_DATA)) {
145
+ logStr = log.slice(PROGRAM_DATA.length);
146
+ } else if (log.startsWith(PROGRAM_LOG)) {
147
+ logStr = log.slice(PROGRAM_LOG.length);
148
+ }
149
+ if (logStr) {
150
+ const event = coder.events.decode(logStr);
151
+ if (event) {
152
+ events.push({ name: event.name, data: event.data });
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ return events;
159
+ }
package/src/idl/index.ts CHANGED
@@ -8,8 +8,15 @@ import liquidIdl from "./liquid.json" with { type: "json" };
8
8
  import liquidSwapIdl from "./liquid_swap.json" with { type: "json" };
9
9
  import liquidFeesIdl from "./liquid_fees.json" with { type: "json" };
10
10
  import liquidStateIdl from "./liquid_state.json" with { type: "json" };
11
+ import liquidEventsIdl from "./liquid_events.json" with { type: "json" };
11
12
 
12
- export { liquidIdl, liquidSwapIdl, liquidFeesIdl, liquidStateIdl };
13
+ export {
14
+ liquidIdl,
15
+ liquidSwapIdl,
16
+ liquidFeesIdl,
17
+ liquidStateIdl,
18
+ liquidEventsIdl,
19
+ };
13
20
  export { patchIdl } from "./patch-idl.js";
14
21
 
15
22
  // Re-export Anchor-generated IDL types
@@ -17,11 +24,13 @@ export type { Liquid } from "./liquid.js";
17
24
  export type { LiquidSwap } from "./liquid_swap.js";
18
25
  export type { LiquidFees } from "./liquid_fees.js";
19
26
  export type { LiquidState } from "./liquid_state.js";
27
+ export type { LiquidEvents } from "./liquid_events.js";
20
28
 
21
29
  import type { Liquid } from "./liquid.js";
22
30
  import type { LiquidSwap } from "./liquid_swap.js";
23
31
  import type { LiquidFees } from "./liquid_fees.js";
24
32
  import type { LiquidState } from "./liquid_state.js";
33
+ import type { LiquidEvents } from "./liquid_events.js";
25
34
 
26
35
  /**
27
36
  * Creates a typed Program instance for the Liquid bonding curve program.
@@ -115,3 +124,19 @@ export function getLiquidStateProgram(
115
124
  : liquidStateIdl;
116
125
  return new Program(idl as LiquidState, createReadonlyProvider(connection));
117
126
  }
127
+
128
+ /**
129
+ * Creates a typed Program instance for the Liquid Events program.
130
+ * Uses a readonly provider — no signing capability.
131
+ *
132
+ * @param connection - Solana RPC connection
133
+ * @returns Read-only Program instance typed as LiquidEvents
134
+ */
135
+ export function getLiquidEventsProgram(
136
+ connection: Connection,
137
+ ): Program<LiquidEvents> {
138
+ return new Program(
139
+ liquidEventsIdl as LiquidEvents,
140
+ createReadonlyProvider(connection),
141
+ );
142
+ }