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:
copilot-swe-agent[bot]
2025-12-05 14:43:06 +00:00
parent e9472175ba
commit 86b69ff7c0

View File

@@ -11,7 +11,6 @@
*/ */
import { initializeDriftService, getDriftService } from '../lib/drift/client' 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) // Helper to decode market name from bytes (Drift stores names as 32-byte arrays)
function decodeMarketName(nameBytes: number[] | Uint8Array | undefined): string { function decodeMarketName(nameBytes: number[] | Uint8Array | undefined): string {
@@ -23,27 +22,87 @@ function decodeMarketName(nameBytes: number[] | Uint8Array | undefined): string
return name.trim() return name.trim()
} }
// Map oracle source enum to human-readable string /**
function getOracleSourceName(oracleSource: OracleSource | number): string { * Extract numeric value from Anchor-style enum objects
// OracleSource enum values from Drift SDK *
const sourceMap: Record<number, string> = { * Drift SDK uses Anchor which represents enums as objects like:
0: 'Pyth', * - { pyth: {} } for OracleSource.Pyth
1: 'Switchboard', * - { active: {} } for MarketStatus.Active
2: 'QuoteAsset', *
3: 'Pyth1K', * This helper safely extracts the key name and maps it to a numeric index,
4: 'Pyth1M', * or handles direct numeric values for backwards compatibility.
5: 'PythStableCoin', *
6: 'Prelaunch', * @param enumValue - The enum value (object or number)
7: 'PythPull', * @param keyMap - Map of enum key names to their string representations
8: 'Pyth1KPull', * @returns The string representation of the enum value
9: 'Pyth1MPull', */
10: 'PythStableCoinPull', function getEnumName<T extends Record<string, string>>(
11: 'SwitchboardOnDemand', enumValue: unknown,
keyMap: T
): string {
// Handle null/undefined
if (enumValue === null || enumValue === undefined) {
return 'Unknown'
} }
// Handle both enum and number types // Handle direct numeric values (legacy support)
const sourceValue = typeof oracleSource === 'number' ? oracleSource : Object.values(oracleSource)[0] if (typeof enumValue === 'number') {
return sourceMap[sourceValue as number] || `Unknown(${sourceValue})` 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 // Format number with appropriate decimals
@@ -137,31 +196,16 @@ async function discoverMarkets(searchSymbol?: string): Promise<void> {
? Number(market.imfFactor) / 1e6 ? Number(market.imfFactor) / 1e6
: 0 : 0
// Market status // Market status - use robust enum extraction
const statusMap: Record<number, string> = { const status = getEnumName(market.status, MARKET_STATUS_MAP)
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'
// Contract type // Contract type - use robust enum extraction
const contractTypeMap: Record<number, string> = { const contractType = getEnumName(market.contractType, CONTRACT_TYPE_MAP)
0: 'Perpetual',
1: 'Future',
}
const contractType = contractTypeMap[Object.values(market.contractType)[0] as number] || 'Unknown'
const marketInfo: MarketInfo = { const marketInfo: MarketInfo = {
index: i, index: i,
symbol, symbol,
oracleSource: getOracleSourceName(oracleSource), oracleSource: getEnumName(oracleSource, ORACLE_SOURCE_MAP),
minOrderSize, minOrderSize,
orderStepSize, orderStepSize,
tickSize, tickSize,