The parser validates IDL structure before processing:
packages/worker/src/services/idl-parser.ts
export function validateIDL(idlJson: unknown): ValidationResult { const errors: string[] = [] const warnings: string[] = [] if (!idlJson || typeof idlJson !== 'object') { return { valid: false, errors: ['IDL must be a JSON object'], warnings } } const idl = idlJson as Record<string, unknown> // Required fields const metadata = idl.metadata as Record<string, unknown> | undefined if (!metadata?.version || typeof metadata.version !== 'string') { errors.push('IDL must have a "version" field (string)') } if (!metadata?.name || typeof metadata.name !== 'string') { errors.push('IDL must have a "name" field (string)') } if (!idl.instructions || !Array.isArray(idl.instructions)) { errors.push('IDL must have an "instructions" array') } else { // Validate each instruction for (let i = 0; i < idl.instructions.length; i++) { const ix = idl.instructions[i] as Record<string, unknown> if (!ix.name || typeof ix.name !== 'string') { errors.push(`Instruction at index ${i} must have a "name" field`) } if (!ix.accounts || !Array.isArray(ix.accounts)) { errors.push(`Instruction "${ix.name || i}" must have an "accounts" array`) } if (!ix.args || !Array.isArray(ix.args)) { errors.push(`Instruction "${ix.name || i}" must have an "args" array`) } } } return { valid: errors.length === 0, errors, warnings }}
If validation fails, the IDL upload is rejected with detailed error messages.
export function normalizeField( field: { name: string; type: any } | string, index: number,): { name: string; type: any } { if (typeof field === 'string') { return { name: `field_${index}`, type: field } } if (typeof field === 'object' && field !== null && !('name' in field)) { // Field is an unnamed type object like { vec: "u8" } return { name: `field_${index}`, type: field } } return field as { name: string; type: any }}
Generates default values for testing and documentation:
packages/worker/src/services/idl-parser.ts
export function getDefaultValue(type: any, idl?: AnchorIDL): any { if (typeof type === 'string') { switch (type) { case 'u8': case 'u16': case 'u32': case 'u64': case 'u128': case 'i8': case 'i16': case 'i32': case 'i64': case 'i128': return 0 case 'f32': case 'f64': return 0.0 case 'bool': return false case 'string': return '' case 'publicKey': case 'pubkey': return '11111111111111111111111111111111' case 'bytes': return [] default: return null } } if (type.vec) return [] if (type.option) return null if (type.array) return [] // Handle defined types — return default object with all struct fields const definedName = getDefinedTypeName(type) if (definedName && idl) { const resolved = resolveDefinedType(idl, definedName) if (resolved && resolved.fields.length > 0) { const obj: Record<string, any> = {} for (const field of resolved.fields) { obj[field.name] = getDefaultValue(field.type, idl) } return obj } } return null}
Default values are used in the API Explorer to pre-fill forms and provide examples.