fix: Improve enum handling robustness in discover-drift-markets script
Co-authored-by: mindesbunister <32161838+mindesbunister@users.noreply.github.com>
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
import { initializeDriftService, getDriftService } from '../lib/drift/client'
|
||||
import { OracleSource } from '@drift-labs/sdk'
|
||||
|
||||
// Helper to decode market name from bytes (Drift stores names as 32-byte arrays)
|
||||
function decodeMarketName(nameBytes: number[] | Uint8Array | undefined): string {
|
||||
@@ -23,27 +22,87 @@ function decodeMarketName(nameBytes: number[] | Uint8Array | undefined): string
|
||||
return name.trim()
|
||||
}
|
||||
|
||||
// Map oracle source enum to human-readable string
|
||||
function getOracleSourceName(oracleSource: OracleSource | number): string {
|
||||
// OracleSource enum values from Drift SDK
|
||||
const sourceMap: Record<number, string> = {
|
||||
0: 'Pyth',
|
||||
1: 'Switchboard',
|
||||
2: 'QuoteAsset',
|
||||
3: 'Pyth1K',
|
||||
4: 'Pyth1M',
|
||||
5: 'PythStableCoin',
|
||||
6: 'Prelaunch',
|
||||
7: 'PythPull',
|
||||
8: 'Pyth1KPull',
|
||||
9: 'Pyth1MPull',
|
||||
10: 'PythStableCoinPull',
|
||||
11: 'SwitchboardOnDemand',
|
||||
/**
|
||||
* Extract numeric value from Anchor-style enum objects
|
||||
*
|
||||
* Drift SDK uses Anchor which represents enums as objects like:
|
||||
* - { pyth: {} } for OracleSource.Pyth
|
||||
* - { active: {} } for MarketStatus.Active
|
||||
*
|
||||
* This helper safely extracts the key name and maps it to a numeric index,
|
||||
* or handles direct numeric values for backwards compatibility.
|
||||
*
|
||||
* @param enumValue - The enum value (object or number)
|
||||
* @param keyMap - Map of enum key names to their string representations
|
||||
* @returns The string representation of the enum value
|
||||
*/
|
||||
function getEnumName<T extends Record<string, string>>(
|
||||
enumValue: unknown,
|
||||
keyMap: T
|
||||
): string {
|
||||
// Handle null/undefined
|
||||
if (enumValue === null || enumValue === undefined) {
|
||||
return 'Unknown'
|
||||
}
|
||||
|
||||
// Handle both enum and number types
|
||||
const sourceValue = typeof oracleSource === 'number' ? oracleSource : Object.values(oracleSource)[0]
|
||||
return sourceMap[sourceValue as number] || `Unknown(${sourceValue})`
|
||||
// Handle direct numeric values (legacy support)
|
||||
if (typeof enumValue === 'number') {
|
||||
const values = Object.values(keyMap)
|
||||
return values[enumValue] || `Unknown(${enumValue})`
|
||||
}
|
||||
|
||||
// Handle Anchor-style enum objects like { pyth: {} } or { active: {} }
|
||||
if (typeof enumValue === 'object') {
|
||||
const keys = Object.keys(enumValue as object)
|
||||
if (keys.length === 1) {
|
||||
const key = keys[0].toLowerCase()
|
||||
// Find matching key in keyMap (case-insensitive)
|
||||
for (const [mapKey, mapValue] of Object.entries(keyMap)) {
|
||||
if (mapKey.toLowerCase() === key) {
|
||||
return mapValue
|
||||
}
|
||||
}
|
||||
// Return the key name capitalized if no map match
|
||||
return keys[0].charAt(0).toUpperCase() + keys[0].slice(1)
|
||||
}
|
||||
}
|
||||
|
||||
return `Unknown(${JSON.stringify(enumValue)})`
|
||||
}
|
||||
|
||||
// Oracle source name mappings (Anchor enum key to display name)
|
||||
const ORACLE_SOURCE_MAP: Record<string, string> = {
|
||||
pyth: 'Pyth',
|
||||
switchboard: 'Switchboard',
|
||||
quoteAsset: 'QuoteAsset',
|
||||
pyth1K: 'Pyth1K',
|
||||
pyth1M: 'Pyth1M',
|
||||
pythStableCoin: 'PythStableCoin',
|
||||
prelaunch: 'Prelaunch',
|
||||
pythPull: 'PythPull',
|
||||
pyth1KPull: 'Pyth1KPull',
|
||||
pyth1MPull: 'Pyth1MPull',
|
||||
pythStableCoinPull: 'PythStableCoinPull',
|
||||
switchboardOnDemand: 'SwitchboardOnDemand',
|
||||
}
|
||||
|
||||
// Market status name mappings
|
||||
const MARKET_STATUS_MAP: Record<string, string> = {
|
||||
initialized: 'Initialized',
|
||||
active: 'Active',
|
||||
fundingPaused: 'FundingPaused',
|
||||
ammPaused: 'AmmPaused',
|
||||
fillPaused: 'FillPaused',
|
||||
withdrawPaused: 'WithdrawPaused',
|
||||
reduceOnly: 'ReduceOnly',
|
||||
settlement: 'Settlement',
|
||||
delisted: 'Delisted',
|
||||
}
|
||||
|
||||
// Contract type name mappings
|
||||
const CONTRACT_TYPE_MAP: Record<string, string> = {
|
||||
perpetual: 'Perpetual',
|
||||
future: 'Future',
|
||||
}
|
||||
|
||||
// Format number with appropriate decimals
|
||||
@@ -137,31 +196,16 @@ async function discoverMarkets(searchSymbol?: string): Promise<void> {
|
||||
? Number(market.imfFactor) / 1e6
|
||||
: 0
|
||||
|
||||
// Market status
|
||||
const statusMap: Record<number, string> = {
|
||||
0: 'Initialized',
|
||||
1: 'Active',
|
||||
2: 'FundingPaused',
|
||||
3: 'AmmPaused',
|
||||
4: 'FillPaused',
|
||||
5: 'WithdrawPaused',
|
||||
6: 'ReduceOnly',
|
||||
7: 'Settlement',
|
||||
8: 'Delisted',
|
||||
}
|
||||
const status = statusMap[Object.values(market.status)[0] as number] || 'Unknown'
|
||||
// Market status - use robust enum extraction
|
||||
const status = getEnumName(market.status, MARKET_STATUS_MAP)
|
||||
|
||||
// Contract type
|
||||
const contractTypeMap: Record<number, string> = {
|
||||
0: 'Perpetual',
|
||||
1: 'Future',
|
||||
}
|
||||
const contractType = contractTypeMap[Object.values(market.contractType)[0] as number] || 'Unknown'
|
||||
// Contract type - use robust enum extraction
|
||||
const contractType = getEnumName(market.contractType, CONTRACT_TYPE_MAP)
|
||||
|
||||
const marketInfo: MarketInfo = {
|
||||
index: i,
|
||||
symbol,
|
||||
oracleSource: getOracleSourceName(oracleSource),
|
||||
oracleSource: getEnumName(oracleSource, ORACLE_SOURCE_MAP),
|
||||
minOrderSize,
|
||||
orderStepSize,
|
||||
tickSize,
|
||||
|
||||
Reference in New Issue
Block a user