@k256/sdk 0.1.6 → 0.1.7
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/README.md +2 -2
- package/dist/index.cjs +61 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +61 -76
- package/dist/index.js.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +44 -10
- package/dist/types/index.d.ts +44 -10
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.cjs +20 -4
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +20 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/ws/index.cjs +41 -72
- package/dist/ws/index.cjs.map +1 -1
- package/dist/ws/index.d.cts +34 -24
- package/dist/ws/index.d.ts +34 -24
- package/dist/ws/index.js +41 -72
- package/dist/ws/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/types/index.ts +46 -11
- package/src/utils/base58.ts +35 -7
- package/src/ws/client.ts +5 -5
- package/src/ws/decoder.ts +48 -102
- package/src/ws/index.ts +1 -1
- package/src/ws/types.ts +31 -25
package/src/utils/base58.ts
CHANGED
|
@@ -58,9 +58,19 @@ export function base58Encode(bytes: Uint8Array): string {
|
|
|
58
58
|
* ```
|
|
59
59
|
*/
|
|
60
60
|
export function base58Decode(str: string): Uint8Array {
|
|
61
|
+
if (str.length === 0) {
|
|
62
|
+
return new Uint8Array(0);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Count leading '1's (they represent leading zero bytes)
|
|
66
|
+
let leadingZeros = 0;
|
|
67
|
+
for (let i = 0; i < str.length && str[i] === '1'; i++) {
|
|
68
|
+
leadingZeros++;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Process remaining characters through base conversion
|
|
61
72
|
const bytes = [0];
|
|
62
|
-
|
|
63
|
-
for (let i = 0; i < str.length; i++) {
|
|
73
|
+
for (let i = leadingZeros; i < str.length; i++) {
|
|
64
74
|
const char = str[i];
|
|
65
75
|
const value = BASE58_ALPHABET.indexOf(char);
|
|
66
76
|
|
|
@@ -80,12 +90,30 @@ export function base58Decode(str: string): Uint8Array {
|
|
|
80
90
|
}
|
|
81
91
|
}
|
|
82
92
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
// Build result: leading zeros + converted bytes (reversed)
|
|
94
|
+
bytes.reverse();
|
|
95
|
+
|
|
96
|
+
// Handle case where input was all '1's (all leading zeros, no data to convert)
|
|
97
|
+
// In this case, bytes is just [0] from initialization, which we should ignore
|
|
98
|
+
if (leadingZeros > 0 && bytes.length === 1 && bytes[0] === 0) {
|
|
99
|
+
// Input was all '1's, return that many zero bytes
|
|
100
|
+
return new Uint8Array(leadingZeros);
|
|
86
101
|
}
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
|
|
103
|
+
// Remove leading zero from conversion if present (artifact of starting with [0])
|
|
104
|
+
const startIdx = bytes.length > 1 && bytes[0] === 0 ? 1 : 0;
|
|
105
|
+
|
|
106
|
+
const result = new Uint8Array(leadingZeros + bytes.length - startIdx);
|
|
107
|
+
// Fill leading zeros
|
|
108
|
+
for (let i = 0; i < leadingZeros; i++) {
|
|
109
|
+
result[i] = 0;
|
|
110
|
+
}
|
|
111
|
+
// Copy converted bytes
|
|
112
|
+
for (let i = startIdx; i < bytes.length; i++) {
|
|
113
|
+
result[leadingZeros + i - startIdx] = bytes[i];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return result;
|
|
89
117
|
}
|
|
90
118
|
|
|
91
119
|
/**
|
package/src/ws/client.ts
CHANGED
|
@@ -153,8 +153,8 @@ export interface K256WebSocketClientConfig {
|
|
|
153
153
|
onPoolUpdate?: (update: PoolUpdateMessage) => void;
|
|
154
154
|
/** Called on batched pool updates (for efficiency) */
|
|
155
155
|
onPoolUpdateBatch?: (updates: PoolUpdateMessage[]) => void;
|
|
156
|
-
/** Called on
|
|
157
|
-
|
|
156
|
+
/** Called on fee market update (per-writable-account fees) */
|
|
157
|
+
onFeeMarket?: (data: DecodedMessage & { type: 'fee_market' }) => void;
|
|
158
158
|
/** Called on blockhash update */
|
|
159
159
|
onBlockhash?: (data: DecodedMessage & { type: 'blockhash' }) => void;
|
|
160
160
|
/** Called on quote update */
|
|
@@ -225,7 +225,7 @@ export class K256WebSocketClient {
|
|
|
225
225
|
private ws: WebSocket | null = null;
|
|
226
226
|
private config: Required<Omit<K256WebSocketClientConfig,
|
|
227
227
|
'onStateChange' | 'onConnect' | 'onDisconnect' | 'onReconnecting' | 'onError' |
|
|
228
|
-
'onSubscribed' | 'onPoolUpdate' | 'onPoolUpdateBatch' | '
|
|
228
|
+
'onSubscribed' | 'onPoolUpdate' | 'onPoolUpdateBatch' | 'onFeeMarket' |
|
|
229
229
|
'onBlockhash' | 'onQuote' | 'onQuoteSubscribed' | 'onHeartbeat' | 'onPong' |
|
|
230
230
|
'onMessage' | 'onRawMessage'
|
|
231
231
|
>> & K256WebSocketClientConfig;
|
|
@@ -536,8 +536,8 @@ export class K256WebSocketClient {
|
|
|
536
536
|
case 'pool_update':
|
|
537
537
|
this.config.onPoolUpdate?.(decoded as PoolUpdateMessage);
|
|
538
538
|
break;
|
|
539
|
-
case '
|
|
540
|
-
this.config.
|
|
539
|
+
case 'fee_market':
|
|
540
|
+
this.config.onFeeMarket?.(decoded as DecodedMessage & { type: 'fee_market' });
|
|
541
541
|
break;
|
|
542
542
|
case 'blockhash':
|
|
543
543
|
this.config.onBlockhash?.(decoded as DecodedMessage & { type: 'blockhash' });
|
package/src/ws/decoder.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { base58Encode } from '../utils/base58';
|
|
11
|
-
import { MessageType, type DecodedMessage, type PoolUpdateMessage } from './types';
|
|
11
|
+
import { MessageType, type DecodedMessage, type PoolUpdateMessage, type FeeMarketMessage } from './types';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Decode a binary WebSocket message from K2
|
|
@@ -69,84 +69,60 @@ export function decodeMessage(data: ArrayBuffer): DecodedMessage | null {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
case MessageType.PriorityFees: {
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
// Offset 94: top_10_fee: u64
|
|
88
|
-
// Offset 102: top_25_fee: u64
|
|
89
|
-
// Offset 110: spike_detected: bool
|
|
90
|
-
// Offset 111: spike_fee: u64
|
|
91
|
-
// Total: 119 bytes
|
|
92
|
-
if (payload.byteLength < 24) return null;
|
|
72
|
+
// FeeMarketWire bincode layout (per-writable-account model):
|
|
73
|
+
// Header (42 bytes):
|
|
74
|
+
// Offset 0: slot: u64 (8 bytes)
|
|
75
|
+
// Offset 8: timestamp_ms: u64 (8 bytes)
|
|
76
|
+
// Offset 16: recommended: u64 (8 bytes)
|
|
77
|
+
// Offset 24: state: u8 (1 byte)
|
|
78
|
+
// Offset 25: is_stale: bool (1 byte)
|
|
79
|
+
// Offset 26: block_utilization_pct: f32 (4 bytes)
|
|
80
|
+
// Offset 30: blocks_in_window: u32 (4 bytes)
|
|
81
|
+
// Offset 34: account_count: u64 (8 bytes) [bincode Vec length]
|
|
82
|
+
// Per account (92 bytes each):
|
|
83
|
+
// pubkey: [u8; 32], total_txs: u32, active_slots: u32,
|
|
84
|
+
// cu_consumed: u64, utilization_pct: f32,
|
|
85
|
+
// p25: u64, p50: u64, p75: u64, p90: u64, min_nonzero_price: u64
|
|
86
|
+
if (payload.byteLength < 42) return null;
|
|
93
87
|
|
|
94
88
|
const slot = Number(payloadView.getBigUint64(0, true));
|
|
95
89
|
const timestampMs = Number(payloadView.getBigUint64(8, true));
|
|
96
90
|
const recommended = Number(payloadView.getBigUint64(16, true));
|
|
97
|
-
const state =
|
|
98
|
-
const isStale =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
spikeDetected = payloadView.getUint8(110) !== 0;
|
|
124
|
-
spikeFee = Number(payloadView.getBigUint64(111, true));
|
|
91
|
+
const state = payloadView.getUint8(24);
|
|
92
|
+
const isStale = payloadView.getUint8(25) !== 0;
|
|
93
|
+
const blockUtilizationPct = payloadView.getFloat32(26, true);
|
|
94
|
+
const blocksInWindow = payloadView.getUint32(30, true);
|
|
95
|
+
const accountCount = Number(payloadView.getBigUint64(34, true));
|
|
96
|
+
|
|
97
|
+
const accounts: FeeMarketMessage['data']['accounts'] = [];
|
|
98
|
+
let offset = 42;
|
|
99
|
+
for (let i = 0; i < accountCount && offset + 92 <= payload.byteLength; i++) {
|
|
100
|
+
const pubkeyBytes = new Uint8Array(payload, offset, 32);
|
|
101
|
+
const pubkey = base58Encode(pubkeyBytes);
|
|
102
|
+
const totalTxs = payloadView.getUint32(offset + 32, true);
|
|
103
|
+
const activeSlots = payloadView.getUint32(offset + 36, true);
|
|
104
|
+
const cuConsumed = Number(payloadView.getBigUint64(offset + 40, true));
|
|
105
|
+
const utilizationPct = payloadView.getFloat32(offset + 48, true);
|
|
106
|
+
const p25 = Number(payloadView.getBigUint64(offset + 52, true));
|
|
107
|
+
const p50 = Number(payloadView.getBigUint64(offset + 60, true));
|
|
108
|
+
const p75 = Number(payloadView.getBigUint64(offset + 68, true));
|
|
109
|
+
const p90 = Number(payloadView.getBigUint64(offset + 76, true));
|
|
110
|
+
const minNonzeroPrice = Number(payloadView.getBigUint64(offset + 84, true));
|
|
111
|
+
|
|
112
|
+
accounts.push({
|
|
113
|
+
pubkey, totalTxs, activeSlots, cuConsumed, utilizationPct,
|
|
114
|
+
p25, p50, p75, p90, minNonzeroPrice,
|
|
115
|
+
});
|
|
116
|
+
offset += 92;
|
|
125
117
|
}
|
|
126
118
|
|
|
127
119
|
return {
|
|
128
|
-
type: '
|
|
120
|
+
type: 'fee_market',
|
|
129
121
|
data: {
|
|
130
|
-
slot,
|
|
131
|
-
|
|
132
|
-
recommended,
|
|
133
|
-
state,
|
|
134
|
-
isStale,
|
|
135
|
-
swapP50,
|
|
136
|
-
swapP75,
|
|
137
|
-
swapP90,
|
|
138
|
-
swapP99,
|
|
139
|
-
swapSamples,
|
|
140
|
-
landingP50Fee,
|
|
141
|
-
landingP75Fee,
|
|
142
|
-
landingP90Fee,
|
|
143
|
-
landingP99Fee,
|
|
144
|
-
top10Fee,
|
|
145
|
-
top25Fee,
|
|
146
|
-
spikeDetected,
|
|
147
|
-
spikeFee,
|
|
122
|
+
slot, timestampMs, recommended, state, isStale,
|
|
123
|
+
blockUtilizationPct, blocksInWindow, accounts,
|
|
148
124
|
},
|
|
149
|
-
};
|
|
125
|
+
} as FeeMarketMessage;
|
|
150
126
|
}
|
|
151
127
|
|
|
152
128
|
case MessageType.Blockhash: {
|
|
@@ -341,19 +317,7 @@ function decodePoolUpdate(payload: ArrayBuffer, payloadView: DataView): PoolUpda
|
|
|
341
317
|
},
|
|
342
318
|
};
|
|
343
319
|
} catch {
|
|
344
|
-
return
|
|
345
|
-
type: 'pool_update',
|
|
346
|
-
data: {
|
|
347
|
-
sequence: 0,
|
|
348
|
-
slot: 0,
|
|
349
|
-
writeVersion: 0,
|
|
350
|
-
protocol: 'unknown',
|
|
351
|
-
poolAddress: '',
|
|
352
|
-
tokenMints: [],
|
|
353
|
-
tokenBalances: [],
|
|
354
|
-
tokenDecimals: [],
|
|
355
|
-
},
|
|
356
|
-
};
|
|
320
|
+
return null;
|
|
357
321
|
}
|
|
358
322
|
}
|
|
359
323
|
|
|
@@ -461,24 +425,6 @@ function decodeQuote(payload: ArrayBuffer, payloadView: DataView): DecodedMessag
|
|
|
461
425
|
},
|
|
462
426
|
};
|
|
463
427
|
} catch {
|
|
464
|
-
return
|
|
465
|
-
type: 'quote',
|
|
466
|
-
data: {
|
|
467
|
-
topicId: '',
|
|
468
|
-
timestampMs: 0,
|
|
469
|
-
sequence: 0,
|
|
470
|
-
inputMint: '',
|
|
471
|
-
outputMint: '',
|
|
472
|
-
inAmount: '0',
|
|
473
|
-
outAmount: '0',
|
|
474
|
-
priceImpactBps: 0,
|
|
475
|
-
contextSlot: 0,
|
|
476
|
-
algorithm: '',
|
|
477
|
-
isImprovement: false,
|
|
478
|
-
isCached: false,
|
|
479
|
-
isStale: false,
|
|
480
|
-
routePlan: null,
|
|
481
|
-
},
|
|
482
|
-
};
|
|
428
|
+
return null;
|
|
483
429
|
}
|
|
484
430
|
}
|
package/src/ws/index.ts
CHANGED
package/src/ws/types.ts
CHANGED
|
@@ -66,39 +66,45 @@ export interface PoolUpdateMessage {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
* Decoded
|
|
70
|
-
*
|
|
71
|
-
* All fields from K2
|
|
69
|
+
* Decoded fee market from binary message (per-writable-account model)
|
|
70
|
+
*
|
|
71
|
+
* All fields from K2 FeeMarketWire
|
|
72
72
|
*/
|
|
73
|
-
export interface
|
|
74
|
-
type: '
|
|
73
|
+
export interface FeeMarketMessage {
|
|
74
|
+
type: 'fee_market';
|
|
75
75
|
data: {
|
|
76
76
|
slot: number;
|
|
77
77
|
timestampMs: number;
|
|
78
|
-
/** Recommended priority fee in
|
|
78
|
+
/** Recommended priority fee in microlamports/CU (max p75 across hottest accounts) */
|
|
79
79
|
recommended: number;
|
|
80
80
|
/** Fee state: 0=low, 1=normal, 2=high, 3=extreme */
|
|
81
81
|
state: number;
|
|
82
82
|
/** True if data is stale (no recent samples) */
|
|
83
83
|
isStale: boolean;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
84
|
+
/** Block utilization percentage (0-100) */
|
|
85
|
+
blockUtilizationPct: number;
|
|
86
|
+
/** Number of blocks in the observation window */
|
|
87
|
+
blocksInWindow: number;
|
|
88
|
+
/** Per-writable-account fee data */
|
|
89
|
+
accounts: {
|
|
90
|
+
/** Account public key (Base58) */
|
|
91
|
+
pubkey: string;
|
|
92
|
+
/** Total transactions touching this account */
|
|
93
|
+
totalTxs: number;
|
|
94
|
+
/** Active slots for this account */
|
|
95
|
+
activeSlots: number;
|
|
96
|
+
/** Total CU consumed */
|
|
97
|
+
cuConsumed: number;
|
|
98
|
+
/** Utilization percentage (0-100) of 12M CU limit */
|
|
99
|
+
utilizationPct: number;
|
|
100
|
+
/** Fee percentiles in microlamports/CU */
|
|
101
|
+
p25: number;
|
|
102
|
+
p50: number;
|
|
103
|
+
p75: number;
|
|
104
|
+
p90: number;
|
|
105
|
+
/** Minimum non-zero fee observed */
|
|
106
|
+
minNonzeroPrice: number;
|
|
107
|
+
}[];
|
|
102
108
|
};
|
|
103
109
|
}
|
|
104
110
|
|
|
@@ -216,7 +222,7 @@ export interface PongMessage {
|
|
|
216
222
|
*/
|
|
217
223
|
export type DecodedMessage =
|
|
218
224
|
| PoolUpdateMessage
|
|
219
|
-
|
|
|
225
|
+
| FeeMarketMessage
|
|
220
226
|
| BlockhashMessage
|
|
221
227
|
| QuoteMessage
|
|
222
228
|
| HeartbeatMessage
|