UNPKG

@openzeppelin/contracts-ui-builder-adapter-stellar

Version:
160 lines (148 loc) 6.23 kB
import * as StellarSdk from '@stellar/stellar-sdk'; import { isDevelopmentOrTestEnvironment, logger } from '@openzeppelin/contracts-ui-builder-utils'; /** * Utility functions for detecting and analyzing Stellar/Soroban parameter types */ /** * Extract human-readable Soroban type name from ScSpecTypeDef * Based on the Stellar SDK type system */ export function extractSorobanTypeFromScSpec(scSpecType: StellarSdk.xdr.ScSpecTypeDef): string { try { const typeSwitch = scSpecType.switch(); switch (typeSwitch) { case StellarSdk.xdr.ScSpecType.scSpecTypeVal(): return 'Val'; case StellarSdk.xdr.ScSpecType.scSpecTypeBool(): return 'Bool'; case StellarSdk.xdr.ScSpecType.scSpecTypeVoid(): return 'Void'; case StellarSdk.xdr.ScSpecType.scSpecTypeError(): return 'Error'; case StellarSdk.xdr.ScSpecType.scSpecTypeU32(): return 'U32'; case StellarSdk.xdr.ScSpecType.scSpecTypeI32(): return 'I32'; case StellarSdk.xdr.ScSpecType.scSpecTypeU64(): return 'U64'; case StellarSdk.xdr.ScSpecType.scSpecTypeI64(): return 'I64'; case StellarSdk.xdr.ScSpecType.scSpecTypeTimepoint(): return 'Timepoint'; case StellarSdk.xdr.ScSpecType.scSpecTypeDuration(): return 'Duration'; case StellarSdk.xdr.ScSpecType.scSpecTypeU128(): return 'U128'; case StellarSdk.xdr.ScSpecType.scSpecTypeI128(): return 'I128'; case StellarSdk.xdr.ScSpecType.scSpecTypeU256(): return 'U256'; case StellarSdk.xdr.ScSpecType.scSpecTypeI256(): return 'I256'; case StellarSdk.xdr.ScSpecType.scSpecTypeBytes(): return 'Bytes'; case StellarSdk.xdr.ScSpecType.scSpecTypeBytesN(): { const bytesNType = scSpecType.bytesN(); const size = bytesNType.n(); return `BytesN<${size}>`; } case StellarSdk.xdr.ScSpecType.scSpecTypeString(): return 'ScString'; case StellarSdk.xdr.ScSpecType.scSpecTypeSymbol(): return 'ScSymbol'; case StellarSdk.xdr.ScSpecType.scSpecTypeVec(): { const vecType = scSpecType.vec(); const elementType = extractSorobanTypeFromScSpec(vecType.elementType()); return `Vec<${elementType}>`; } case StellarSdk.xdr.ScSpecType.scSpecTypeMap(): { const mapType = scSpecType.map(); const keyType = extractSorobanTypeFromScSpec(mapType.keyType()); const valueType = extractSorobanTypeFromScSpec(mapType.valueType()); return `Map<${keyType}, ${valueType}>`; } case StellarSdk.xdr.ScSpecType.scSpecTypeTuple(): { const tupleType = scSpecType.tuple(); const valueTypes = tupleType.valueTypes(); const typeNames = valueTypes.map((t) => extractSorobanTypeFromScSpec(t)); return `Tuple<${typeNames.join(', ')}>`; } case StellarSdk.xdr.ScSpecType.scSpecTypeOption(): { const optionType = scSpecType.option(); const valueType = extractSorobanTypeFromScSpec(optionType.valueType()); return `Option<${valueType}>`; } case StellarSdk.xdr.ScSpecType.scSpecTypeResult(): { const resultType = scSpecType.result(); const okType = extractSorobanTypeFromScSpec(resultType.okType()); const errorType = extractSorobanTypeFromScSpec(resultType.errorType()); return `Result<${okType}, ${errorType}>`; } case StellarSdk.xdr.ScSpecType.scSpecTypeAddress(): return 'Address'; case StellarSdk.xdr.ScSpecType.scSpecTypeMuxedAddress(): return 'MuxedAddress'; case StellarSdk.xdr.ScSpecType.scSpecTypeUdt(): { const udtType = scSpecType.udt(); return udtType.name().toString(); } default: // COMPREHENSIVE TYPE MISS DETECTION logger.error('extractSorobanTypeFromScSpec', `🚨 MISSING SCSPEC TYPE HANDLER 🚨`, { typeSwitchValue: typeSwitch.value, typeSwitchName: typeSwitch.name, rawScSpecType: scSpecType, message: 'This indicates a missing case in extractSorobanTypeFromScSpec switch statement', actionRequired: 'Add support for this ScSpec type immediately', sdkVersion: process.env.npm_package_dependencies_stellar_sdk || 'unknown', }); // Create detailed error report for unknown types const errorReport = { type: 'MISSING_SCSPEC_TYPE', scSpecType: typeSwitch.name, value: typeSwitch.value, timestamp: new Date().toISOString(), }; // In development, throw an error to fail fast if (isDevelopmentOrTestEnvironment()) { throw new Error( `Missing ScSpec type handler: ${typeSwitch.name} (value: ${typeSwitch.value}). Please add support for this type.` ); } // In production, log extensively but don't break logger.error('STELLAR_ADAPTER_MISSING_TYPE', 'Missing ScSpec type handler:', errorReport); return 'unknown'; } } catch (error) { logger.error('extractSorobanTypeFromScSpec', 'Failed to extract type:', error); return 'unknown'; } } /** * Determines if a parameter type is likely an enum based on naming conventions * and common patterns in Stellar/Soroban contracts. * * @param parameterType The parameter type string to analyze * @returns true if the type appears to be an enum based on naming patterns */ export function isLikelyEnumType(parameterType: string): boolean { // Direct enum name patterns if (parameterType.includes('Enum') || parameterType.includes('enum')) { return true; } // Common enum naming patterns in Stellar/Soroban const enumPatterns = [ /^(Status|State|Type|Kind|Mode|Level|Priority|Category)$/i, /^.*?(Status|State|Type|Kind|Mode|Level|Priority|Category)$/i, /^(Token|Asset|Account|Contract|Network)Type$/i, ]; // Only apply pattern matching if it's not a generic "UnknownType" or similar if ( parameterType === 'UnknownType' || parameterType === 'CustomStruct' || parameterType === 'UserInfo' ) { return false; } return enumPatterns.some((pattern) => pattern.test(parameterType)); }