sol-trade-sdk 0.1.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 (87) hide show
  1. package/README.md +390 -0
  2. package/dist/chunk-MMQAMIKR.mjs +3735 -0
  3. package/dist/chunk-NEZDFAYA.mjs +7744 -0
  4. package/dist/clients-VITWK7B6.mjs +1370 -0
  5. package/dist/index-1BK_FXsW.d.mts +2327 -0
  6. package/dist/index-1BK_FXsW.d.ts +2327 -0
  7. package/dist/index.d.mts +2659 -0
  8. package/dist/index.d.ts +2659 -0
  9. package/dist/index.js +13265 -0
  10. package/dist/index.mjs +562 -0
  11. package/dist/perf/index.d.mts +2 -0
  12. package/dist/perf/index.d.ts +2 -0
  13. package/dist/perf/index.js +3742 -0
  14. package/dist/perf/index.mjs +214 -0
  15. package/package.json +101 -0
  16. package/src/__tests__/complete_sdk.test.ts +354 -0
  17. package/src/__tests__/hotpath.test.ts +486 -0
  18. package/src/__tests__/nonce.test.ts +45 -0
  19. package/src/__tests__/sdk.test.ts +425 -0
  20. package/src/address-lookup/index.ts +197 -0
  21. package/src/cache/cache.ts +308 -0
  22. package/src/calc/index.ts +1058 -0
  23. package/src/calc/pumpfun.ts +124 -0
  24. package/src/common/bonding_curve.ts +272 -0
  25. package/src/common/compute-budget.ts +148 -0
  26. package/src/common/confirm-any-signature.ts +184 -0
  27. package/src/common/fast-timing.ts +481 -0
  28. package/src/common/fast_fn.ts +150 -0
  29. package/src/common/gas-fee-strategy.ts +253 -0
  30. package/src/common/map-pool.ts +23 -0
  31. package/src/common/nonce.ts +40 -0
  32. package/src/common/sdk-log.ts +460 -0
  33. package/src/common/seed.ts +381 -0
  34. package/src/common/spl-token.ts +578 -0
  35. package/src/common/subscription-handle.ts +644 -0
  36. package/src/common/trading-utils.ts +239 -0
  37. package/src/common/wsol-manager.ts +325 -0
  38. package/src/compute/compute_budget_manager.ts +187 -0
  39. package/src/compute/index.ts +21 -0
  40. package/src/constants/index.ts +96 -0
  41. package/src/execution/execution.ts +532 -0
  42. package/src/execution/index.ts +42 -0
  43. package/src/hotpath/executor.ts +464 -0
  44. package/src/hotpath/index.ts +64 -0
  45. package/src/hotpath/state.ts +435 -0
  46. package/src/index.ts +2117 -0
  47. package/src/instruction/bonk_builder.ts +730 -0
  48. package/src/instruction/index.ts +24 -0
  49. package/src/instruction/meteora_damm_v2_builder.ts +509 -0
  50. package/src/instruction/pumpfun_builder.ts +1183 -0
  51. package/src/instruction/pumpswap.ts +1123 -0
  52. package/src/instruction/raydium_amm_v4_builder.ts +692 -0
  53. package/src/instruction/raydium_cpmm_builder.ts +795 -0
  54. package/src/middleware/traits.ts +407 -0
  55. package/src/params/index.ts +483 -0
  56. package/src/perf/compiler-optimization.ts +529 -0
  57. package/src/perf/hardware.ts +631 -0
  58. package/src/perf/index.ts +9 -0
  59. package/src/perf/kernel-bypass.ts +656 -0
  60. package/src/perf/protocol.ts +682 -0
  61. package/src/perf/realtime.ts +592 -0
  62. package/src/perf/simd.ts +668 -0
  63. package/src/perf/syscall-bypass.ts +331 -0
  64. package/src/perf/ultra-low-latency.ts +505 -0
  65. package/src/perf/zero-copy.ts +589 -0
  66. package/src/pool/pool.ts +294 -0
  67. package/src/rpc/client.ts +345 -0
  68. package/src/sdk-errors.ts +13 -0
  69. package/src/security/index.ts +26 -0
  70. package/src/security/secure-key.ts +303 -0
  71. package/src/security/validators.ts +281 -0
  72. package/src/seed/pda.ts +262 -0
  73. package/src/serialization/index.ts +28 -0
  74. package/src/serialization/serialization.ts +288 -0
  75. package/src/swqos/clients.ts +1754 -0
  76. package/src/swqos/index.ts +50 -0
  77. package/src/swqos/providers.ts +1707 -0
  78. package/src/trading/core/async-executor.ts +702 -0
  79. package/src/trading/core/confirmation-monitor.ts +711 -0
  80. package/src/trading/core/index.ts +82 -0
  81. package/src/trading/core/retry-handler.ts +683 -0
  82. package/src/trading/core/transaction-pool.ts +780 -0
  83. package/src/trading/executor.ts +385 -0
  84. package/src/trading/factory.ts +282 -0
  85. package/src/trading/index.ts +30 -0
  86. package/src/types.ts +8 -0
  87. package/src/utils/index.ts +155 -0
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Seed-based PDA Derivation for Sol Trade SDK
3
+ * High-performance PDA computation with caching.
4
+ */
5
+
6
+ import { LRUCache } from '../cache/cache';
7
+
8
+ // ===== Constants =====
9
+
10
+ // Program IDs - MUST match src/constants/index.ts
11
+ // These are the official Solana mainnet program IDs
12
+ export const PUMPFUN_PROGRAM_ID = '6EF8rrecthR5Dkzon8Nwu78hRvfCKopJFfWcCzNfXt3D';
13
+ export const PUMPSWAP_PROGRAM_ID = 'pAMMBay6oceH9fJKBRdGP4LmVn7LKwEqT7dPWn1oLKs';
14
+ export const RAYDIUM_AMM_V4_PROGRAM_ID = '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8';
15
+ export const RAYDIUM_CPMM_PROGRAM_ID = 'CPMMoo8L3F4NbTUBBfMTm5L2AhwDtLd6P4VeXvgQA2Po';
16
+ export const METEORA_DAMM_V2_PROGRAM_ID = 'LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YvKpNLuh';
17
+ export const TOKEN_PROGRAM_ID = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';
18
+ export const TOKEN_2022_PROGRAM_ID = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb';
19
+ export const ASSOCIATED_TOKEN_PROGRAM_ID = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';
20
+
21
+ // ===== Types =====
22
+
23
+ export interface PDA {
24
+ pubkey: Buffer;
25
+ bump: number;
26
+ }
27
+
28
+ // ===== PDA Cache =====
29
+
30
+ const pdaCache = new LRUCache<string, PDA>(1000, 60000);
31
+
32
+ // ===== Helper Functions =====
33
+
34
+ function concatBuffers(...buffers: Buffer[]): Buffer {
35
+ const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0);
36
+ const result = Buffer.alloc(totalLength);
37
+ let offset = 0;
38
+ for (const buf of buffers) {
39
+ buf.copy(result, offset);
40
+ offset += buf.length;
41
+ }
42
+ return result;
43
+ }
44
+
45
+ async function sha256(data: Buffer): Promise<Buffer> {
46
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
47
+ return Buffer.from(hashBuffer);
48
+ }
49
+
50
+ // ===== Base58 =====
51
+
52
+ const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
53
+
54
+ export function base58Encode(buffer: Buffer): string {
55
+ const digits = [0];
56
+ for (let i = 0; i < buffer.length; i++) {
57
+ let carry = buffer[i]!;
58
+ for (let j = 0; j < digits.length; j++) {
59
+ carry += digits[j]! << 8;
60
+ digits[j] = carry % 58;
61
+ carry = (carry / 58) | 0;
62
+ }
63
+ while (carry > 0) {
64
+ digits.push(carry % 58);
65
+ carry = (carry / 58) | 0;
66
+ }
67
+ }
68
+ let result = '';
69
+ for (let i = 0; i < buffer.length && buffer[i] === 0; i++) {
70
+ result += BASE58_ALPHABET[0]!;
71
+ }
72
+ for (let i = digits.length - 1; i >= 0; i--) {
73
+ result += BASE58_ALPHABET[digits[i]!]!;
74
+ }
75
+ return result;
76
+ }
77
+
78
+ export function base58Decode(str: string): Buffer {
79
+ const bytes = [0];
80
+ for (let i = 0; i < str.length; i++) {
81
+ let carry = BASE58_ALPHABET.indexOf(str[i]!);
82
+ if (carry === -1) {
83
+ throw new Error('Invalid base58 character');
84
+ }
85
+ for (let j = 0; j < bytes.length; j++) {
86
+ carry += bytes[j]! * 58;
87
+ bytes[j] = carry & 0xff;
88
+ carry >>= 8;
89
+ }
90
+ while (carry > 0) {
91
+ bytes.push(carry & 0xff);
92
+ carry >>= 8;
93
+ }
94
+ }
95
+ let leadingZeros = 0;
96
+ for (let i = 0; i < str.length && str[i] === '1'; i++) {
97
+ leadingZeros++;
98
+ }
99
+ return Buffer.concat([
100
+ Buffer.alloc(leadingZeros, 0),
101
+ Buffer.from(bytes.reverse()),
102
+ ]);
103
+ }
104
+
105
+ // ===== PDA Derivation =====
106
+
107
+ /**
108
+ * Find a program-derived address.
109
+ */
110
+ export async function findProgramAddress(
111
+ seeds: Buffer[],
112
+ programId: string
113
+ ): Promise<PDA> {
114
+ // Check cache
115
+ const cacheKey = `${programId}:${seeds.map(s => s.toString('hex')).join(':')}`;
116
+ const cached = pdaCache.get(cacheKey);
117
+ if (cached) {
118
+ return cached;
119
+ }
120
+
121
+ const programBytes = base58Decode(programId);
122
+
123
+ for (let bump = 255; bump > 0; bump--) {
124
+ try {
125
+ const address = await createProgramAddress(
126
+ [...seeds, Buffer.from([bump])],
127
+ programId
128
+ );
129
+
130
+ const pda: PDA = { pubkey: address, bump };
131
+ pdaCache.set(cacheKey, pda);
132
+ return pda;
133
+ } catch {
134
+ continue;
135
+ }
136
+ }
137
+
138
+ throw new Error('Unable to find valid PDA');
139
+ }
140
+
141
+ /**
142
+ * Create a program-derived address without bump.
143
+ */
144
+ export async function createProgramAddress(
145
+ seeds: Buffer[],
146
+ programId: string
147
+ ): Promise<Buffer> {
148
+ const programBytes = base58Decode(programId);
149
+ const data = concatBuffers(...seeds, programBytes);
150
+ const hash = await sha256(data);
151
+
152
+ // Check if on ed25519 curve (simplified check)
153
+ // In production, use proper ed25519 check
154
+ if (hash[31]! & 0x80) {
155
+ throw new Error('Invalid seeds: address on curve');
156
+ }
157
+
158
+ return hash;
159
+ }
160
+
161
+ // ===== PumpFun PDAs =====
162
+
163
+ export async function getBondingCurvePDA(mint: string): Promise<PDA> {
164
+ const mintBytes = base58Decode(mint);
165
+ return findProgramAddress(
166
+ [Buffer.from('bonding-curve'), mintBytes],
167
+ PUMPFUN_PROGRAM_ID
168
+ );
169
+ }
170
+
171
+ export async function getGlobalAccountPDA(): Promise<PDA> {
172
+ return findProgramAddress(
173
+ [Buffer.from('global')],
174
+ PUMPFUN_PROGRAM_ID
175
+ );
176
+ }
177
+
178
+ export async function getFeeRecipientPDA(isMayhemMode: boolean = false): Promise<PDA> {
179
+ const seed = isMayhemMode ? 'fee_recipient_mayhem' : 'fee_recipient';
180
+ return findProgramAddress(
181
+ [Buffer.from(seed)],
182
+ PUMPFUN_PROGRAM_ID
183
+ );
184
+ }
185
+
186
+ export async function getEventAuthorityPDA(): Promise<PDA> {
187
+ return findProgramAddress(
188
+ [Buffer.from('event')],
189
+ PUMPFUN_PROGRAM_ID
190
+ );
191
+ }
192
+
193
+ export async function getUserVolumeAccumulatorPDA(user: string): Promise<PDA> {
194
+ const userBytes = base58Decode(user);
195
+ return findProgramAddress(
196
+ [Buffer.from('user_volume_accumulator'), userBytes],
197
+ PUMPFUN_PROGRAM_ID
198
+ );
199
+ }
200
+
201
+ // ===== PumpSwap PDAs =====
202
+
203
+ export async function getPumpSwapPoolPDA(baseMint: string, quoteMint: string): Promise<PDA> {
204
+ const baseBytes = base58Decode(baseMint);
205
+ const quoteBytes = base58Decode(quoteMint);
206
+ return findProgramAddress(
207
+ [Buffer.from('pool'), baseBytes, quoteBytes],
208
+ PUMPSWAP_PROGRAM_ID
209
+ );
210
+ }
211
+
212
+ // ===== Raydium PDAs =====
213
+
214
+ export async function getRaydiumAmmAuthorityPDA(): Promise<PDA> {
215
+ return findProgramAddress(
216
+ [Buffer.from('amm authority')],
217
+ RAYDIUM_AMM_V4_PROGRAM_ID
218
+ );
219
+ }
220
+
221
+ export async function getRaydiumCpmmPoolPDA(
222
+ ammConfig: string,
223
+ baseMint: string,
224
+ quoteMint: string
225
+ ): Promise<PDA> {
226
+ const ammBytes = base58Decode(ammConfig);
227
+ const baseBytes = base58Decode(baseMint);
228
+ const quoteBytes = base58Decode(quoteMint);
229
+ return findProgramAddress(
230
+ [Buffer.from('pool'), ammBytes, baseBytes, quoteBytes],
231
+ RAYDIUM_CPMM_PROGRAM_ID
232
+ );
233
+ }
234
+
235
+ // ===== Meteora PDAs =====
236
+
237
+ export async function getMeteoraPoolPDA(tokenAMint: string, tokenBMint: string): Promise<PDA> {
238
+ const aBytes = base58Decode(tokenAMint);
239
+ const bBytes = base58Decode(tokenBMint);
240
+ return findProgramAddress(
241
+ [Buffer.from('pool'), aBytes, bBytes],
242
+ METEORA_DAMM_V2_PROGRAM_ID
243
+ );
244
+ }
245
+
246
+ // ===== Associated Token Account =====
247
+
248
+ export async function getAssociatedTokenAddress(
249
+ wallet: string,
250
+ mint: string,
251
+ tokenProgram: string = TOKEN_PROGRAM_ID
252
+ ): Promise<Buffer> {
253
+ const walletBytes = base58Decode(wallet);
254
+ const mintBytes = base58Decode(mint);
255
+ const programBytes = base58Decode(tokenProgram);
256
+
257
+ const pda = await findProgramAddress(
258
+ [walletBytes, programBytes, mintBytes],
259
+ ASSOCIATED_TOKEN_PROGRAM_ID
260
+ );
261
+ return pda.pubkey;
262
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Serialization Module for Sol Trade SDK
3
+ *
4
+ * Provides optimized transaction serialization based on Rust sol-trade-sdk:
5
+ * - Zero-allocation buffer pooling
6
+ * - Base58/Base64 encoding
7
+ * - Pooled buffer guards
8
+ */
9
+
10
+ export {
11
+ // Constants
12
+ SERIALIZER_POOL_SIZE,
13
+ SERIALIZER_BUFFER_SIZE,
14
+ SERIALIZER_PREWARM_BUFFERS,
15
+ // Base58
16
+ encodeBase58,
17
+ decodeBase58,
18
+ // Transaction encoding
19
+ TransactionEncoding,
20
+ // Serializer
21
+ ZeroAllocSerializer,
22
+ Base64Encoder,
23
+ PooledTxBufferGuard,
24
+ // Functions
25
+ serializeTransactionSync,
26
+ serializeTransactionBatchSync,
27
+ getSerializerStats,
28
+ } from './serialization';
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Transaction serialization module.
3
+ * Based on sol-trade-sdk Rust implementation with buffer pooling.
4
+ */
5
+
6
+ // ===== Constants =====
7
+
8
+ export const SERIALIZER_POOL_SIZE = 10000;
9
+ export const SERIALIZER_BUFFER_SIZE = 256 * 1024;
10
+ export const SERIALIZER_PREWARM_BUFFERS = 64;
11
+
12
+ // ===== Base58 Encoding =====
13
+
14
+ const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
15
+
16
+ /**
17
+ * Encode bytes to base58 string
18
+ */
19
+ export function encodeBase58(data: Uint8Array): string {
20
+ // Count leading zeros
21
+ let leadingZeros = 0;
22
+ for (let i = 0; i < data.length; i++) {
23
+ if (data[i] === 0) {
24
+ leadingZeros++;
25
+ } else {
26
+ break;
27
+ }
28
+ }
29
+
30
+ // Convert to base58
31
+ const digits: number[] = [0];
32
+
33
+ for (let i = leadingZeros; i < data.length; i++) {
34
+ let carry = data[i]!;
35
+ for (let j = 0; j < digits.length; j++) {
36
+ carry += digits[j]! << 8;
37
+ digits[j] = carry % 58;
38
+ carry = (carry / 58) | 0;
39
+ }
40
+ while (carry > 0) {
41
+ digits.push(carry % 58);
42
+ carry = (carry / 58) | 0;
43
+ }
44
+ }
45
+
46
+ // Build result string
47
+ let result = '';
48
+ for (let i = 0; i < leadingZeros; i++) {
49
+ result += '1';
50
+ }
51
+ for (let i = digits.length - 1; i >= 0; i--) {
52
+ result += BASE58_ALPHABET[digits[i]!]!;
53
+ }
54
+
55
+ return result;
56
+ }
57
+
58
+ /**
59
+ * Decode base58 string to bytes
60
+ */
61
+ export function decodeBase58(s: string): Uint8Array {
62
+ const bytes: number[] = [0];
63
+
64
+ for (let i = 0; i < s.length; i++) {
65
+ const char = s[i]!;
66
+ const value = BASE58_ALPHABET.indexOf(char);
67
+ if (value === -1) {
68
+ throw new Error(`Invalid base58 character: ${char}`);
69
+ }
70
+
71
+ let carry = value;
72
+ for (let j = 0; j < bytes.length; j++) {
73
+ carry += bytes[j]! * 58;
74
+ bytes[j] = carry & 0xff;
75
+ carry = carry >> 8;
76
+ }
77
+ while (carry > 0) {
78
+ bytes.push(carry & 0xff);
79
+ carry = carry >> 8;
80
+ }
81
+ }
82
+
83
+ // Count leading '1's
84
+ let leadingOnes = 0;
85
+ for (let i = 0; i < s.length; i++) {
86
+ if (s[i] === '1') {
87
+ leadingOnes++;
88
+ } else {
89
+ break;
90
+ }
91
+ }
92
+
93
+ // Build result
94
+ const result = new Uint8Array(leadingOnes + bytes.length);
95
+ result.set(new Uint8Array(leadingOnes), 0);
96
+ for (let i = 0; i < bytes.length; i++) {
97
+ result[leadingOnes + bytes.length - 1 - i] = bytes[i]!;
98
+ }
99
+
100
+ return result;
101
+ }
102
+
103
+ // ===== Transaction Encoding =====
104
+
105
+ export enum TransactionEncoding {
106
+ BASE58 = 'base58',
107
+ BASE64 = 'base64',
108
+ }
109
+
110
+ // ===== Zero-Allocation Serializer =====
111
+
112
+ /**
113
+ * Uses a buffer pool to avoid runtime allocation.
114
+ * Based on Rust's ZeroAllocSerializer pattern.
115
+ */
116
+ export class ZeroAllocSerializer {
117
+ private pool: Uint8Array[] = [];
118
+ private available = 0;
119
+ private capacity: number;
120
+
121
+ constructor(
122
+ poolSize: number = SERIALIZER_POOL_SIZE,
123
+ private bufferSize: number = SERIALIZER_BUFFER_SIZE,
124
+ prewarmBuffers: number = SERIALIZER_PREWARM_BUFFERS
125
+ ) {
126
+ this.capacity = poolSize;
127
+
128
+ // Prewarm only a small hot set
129
+ const prewarmCount = Math.min(prewarmBuffers, poolSize);
130
+ for (let i = 0; i < prewarmCount; i++) {
131
+ this.pool.push(new Uint8Array(bufferSize));
132
+ this.available++;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Serialize data using a pooled buffer
138
+ */
139
+ serializeZeroAlloc(data: Uint8Array): Uint8Array {
140
+ let buf: Uint8Array;
141
+ if (this.pool.length > 0) {
142
+ buf = this.pool.pop()!;
143
+ this.available--;
144
+ } else {
145
+ buf = new Uint8Array(this.bufferSize);
146
+ }
147
+
148
+ // Copy data
149
+ buf.set(data, 0);
150
+ return buf.slice(0, data.length);
151
+ }
152
+
153
+ /**
154
+ * Return a buffer to the pool
155
+ */
156
+ returnBuffer(buf: Uint8Array): void {
157
+ if (this.pool.length < this.capacity) {
158
+ this.pool.push(buf);
159
+ this.available++;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Get pool statistics
165
+ */
166
+ getPoolStats(): { available: number; capacity: number } {
167
+ return { available: this.available, capacity: this.capacity };
168
+ }
169
+ }
170
+
171
+ // Global serializer instance
172
+ let globalSerializer: ZeroAllocSerializer | null = null;
173
+
174
+ function getGlobalSerializer(): ZeroAllocSerializer {
175
+ if (!globalSerializer) {
176
+ globalSerializer = new ZeroAllocSerializer();
177
+ }
178
+ return globalSerializer;
179
+ }
180
+
181
+ // ===== Base64 Encoder =====
182
+
183
+ /**
184
+ * Optimized base64 encoding
185
+ */
186
+ export class Base64Encoder {
187
+ /**
188
+ * Encode data to base64
189
+ */
190
+ static encode(data: Uint8Array): string {
191
+ // Use btoa for browser, Buffer for Node.js
192
+ if (typeof btoa === 'function') {
193
+ return btoa(String.fromCharCode(...data));
194
+ }
195
+ return Buffer.from(data).toString('base64');
196
+ }
197
+
198
+ /**
199
+ * Encode using pre-allocated buffer
200
+ */
201
+ static encodeFast(data: Uint8Array): string {
202
+ return Base64Encoder.encode(data);
203
+ }
204
+ }
205
+
206
+ // ===== PooledTxBufferGuard =====
207
+
208
+ /**
209
+ * Returns buffer to pool on release.
210
+ * Use for automatic cleanup.
211
+ */
212
+ export class PooledTxBufferGuard {
213
+ private buffer: Uint8Array | null;
214
+ private serializer: ZeroAllocSerializer;
215
+
216
+ constructor(data: Uint8Array, serializer?: ZeroAllocSerializer) {
217
+ this.serializer = serializer || getGlobalSerializer();
218
+ this.buffer = this.serializer.serializeZeroAlloc(data);
219
+ }
220
+
221
+ /**
222
+ * Get the underlying buffer
223
+ */
224
+ getBuffer(): Uint8Array {
225
+ if (!this.buffer) {
226
+ throw new Error('Buffer already released');
227
+ }
228
+ return this.buffer;
229
+ }
230
+
231
+ /**
232
+ * Return buffer to pool
233
+ */
234
+ release(): void {
235
+ if (this.buffer) {
236
+ this.serializer.returnBuffer(this.buffer);
237
+ this.buffer = null;
238
+ }
239
+ }
240
+ }
241
+
242
+ // ===== Transaction Serialization =====
243
+
244
+ /**
245
+ * Serialize a transaction using buffer pool.
246
+ * Returns encoded string.
247
+ */
248
+ export function serializeTransactionSync(
249
+ transaction: Uint8Array,
250
+ encoding: TransactionEncoding
251
+ ): string {
252
+ const serializer = getGlobalSerializer();
253
+ const serialized = serializer.serializeZeroAlloc(transaction);
254
+ try {
255
+ switch (encoding) {
256
+ case TransactionEncoding.BASE58:
257
+ return encodeBase58(serialized);
258
+ case TransactionEncoding.BASE64:
259
+ return Base64Encoder.encode(serialized);
260
+ default:
261
+ throw new Error(`Unsupported encoding: ${encoding}`);
262
+ }
263
+ } finally {
264
+ serializer.returnBuffer(serialized);
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Serialize multiple transactions
270
+ */
271
+ export function serializeTransactionBatchSync(
272
+ transactions: Uint8Array[],
273
+ encoding: TransactionEncoding
274
+ ): string[] {
275
+ return transactions.map((tx) => serializeTransactionSync(tx, encoding));
276
+ }
277
+
278
+ // ===== Get Statistics =====
279
+
280
+ /**
281
+ * Get global serializer statistics
282
+ */
283
+ export function getSerializerStats(): {
284
+ available: number;
285
+ capacity: number;
286
+ } {
287
+ return getGlobalSerializer().getPoolStats();
288
+ }