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 { 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,