UNPKG

@openzeppelin/ui-builder-adapter-stellar

Version:
1,436 lines (1,409 loc) 180 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // src/adapter.ts import { isStellarNetworkConfig } from "@openzeppelin/ui-builder-types"; import { logger as logger35 } from "@openzeppelin/ui-builder-utils"; // src/contract/loader.ts import * as StellarSdk2 from "@stellar/stellar-sdk"; import { logger as logger15 } from "@openzeppelin/ui-builder-utils"; // src/validation/address.ts import { StrKey } from "@stellar/stellar-sdk"; function isValidAccountAddress(address) { try { return StrKey.isValidEd25519PublicKey(address); } catch { return false; } } function isValidContractAddress(address) { try { return StrKey.isValidContract(address); } catch { return false; } } function isValidMuxedAddress(address) { try { return StrKey.isValidMed25519PublicKey(address); } catch { return false; } } function isValidSecretSeed(seed) { try { return StrKey.isValidEd25519SecretSeed(seed); } catch { return false; } } function isValidSignedPayloadAddress(address) { try { return StrKey.isValidSignedPayload(address); } catch { return false; } } function isValidAddress(address, addressType) { if (!address || typeof address !== "string") { return false; } if (addressType) { switch (addressType) { case "account": return isValidAccountAddress(address); case "contract": return isValidContractAddress(address); case "muxed": return isValidMuxedAddress(address); case "secret": return isValidSecretSeed(address); case "signed-payload": return isValidSignedPayloadAddress(address); case "pre-auth-tx": try { StrKey.decodePreAuthTx(address); return true; } catch { return false; } case "hash-x": try { StrKey.decodeSha256Hash(address); return true; } catch { return false; } default: return false; } } try { return StrKey.isValidEd25519PublicKey(address) || // G... - accounts (most common) StrKey.isValidContract(address) || // C... - contracts StrKey.isValidMed25519PublicKey(address); } catch { return false; } } // src/validation/eoa.ts import { logger } from "@openzeppelin/ui-builder-utils"; var SYSTEM_LOG_TAG = "StellarEoaValidator"; async function validateEoaConfig(config, walletStatus) { if (!config.allowAny) { if (!config.specificAddress) { return "EOA execution selected, but no specific address was provided when 'allowAny' is false."; } if (!isValidAddress(config.specificAddress)) { return `Invalid specific Stellar address format: ${config.specificAddress}`; } if (walletStatus.isConnected && walletStatus.address) { if (walletStatus.address !== config.specificAddress) { return `Connected wallet address (${walletStatus.address}) does not match the required specific Stellar address (${config.specificAddress}). Please connect the correct wallet.`; } } else if (walletStatus.isConnected && !walletStatus.address) { logger.warn( SYSTEM_LOG_TAG, "Wallet is connected but address is unavailable for Stellar EOA validation." ); return "Connected wallet address is not available for validation against specific Stellar address."; } } return true; } // src/validation/relayer.ts async function validateRelayerConfig(config) { if (!config.serviceUrl) { return "Relayer execution selected, but no service URL was provided."; } if (!config.relayer?.relayerId) { return "Relayer execution selected, but no relayer was chosen from the list."; } return true; } // src/configuration/explorer.ts function getStellarExplorerAddressUrl(address, networkConfig) { if (!address || !networkConfig.explorerUrl) { return null; } const baseUrl = networkConfig.explorerUrl.replace(/\/+$/, ""); const path = isValidContractAddress(address) ? "contract" : "account"; return `${baseUrl}/${path}/${encodeURIComponent(address)}`; } function getStellarExplorerTxUrl(txHash, networkConfig) { if (!txHash || !networkConfig.explorerUrl) { return null; } const baseUrl = networkConfig.explorerUrl.replace(/\/+$/, ""); return `${baseUrl}/tx/${encodeURIComponent(txHash)}`; } // src/mapping/struct-fields.ts import { xdr as xdr2 } from "@stellar/stellar-sdk"; import { logger as logger3 } from "@openzeppelin/ui-builder-utils"; // src/utils/type-detection.ts import * as StellarSdk from "@stellar/stellar-sdk"; import { isDevelopmentOrTestEnvironment, logger as logger2 } from "@openzeppelin/ui-builder-utils"; function extractSorobanTypeFromScSpec(scSpecType) { 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: logger2.error("extractSorobanTypeFromScSpec", `\u{1F6A8} MISSING SCSPEC TYPE HANDLER \u{1F6A8}`, { 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" }); const errorReport = { type: "MISSING_SCSPEC_TYPE", scSpecType: typeSwitch.name, value: typeSwitch.value, timestamp: (/* @__PURE__ */ new Date()).toISOString() }; if (isDevelopmentOrTestEnvironment()) { throw new Error( `Missing ScSpec type handler: ${typeSwitch.name} (value: ${typeSwitch.value}). Please add support for this type.` ); } logger2.error("STELLAR_ADAPTER_MISSING_TYPE", "Missing ScSpec type handler:", errorReport); return "unknown"; } } catch (error) { logger2.error("extractSorobanTypeFromScSpec", "Failed to extract type:", error); return "unknown"; } } function isLikelyEnumType(parameterType) { if (parameterType.includes("Enum") || parameterType.includes("enum")) { return true; } 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 ]; if (parameterType === "UnknownType" || parameterType === "CustomStruct" || parameterType === "UserInfo") { return false; } return enumPatterns.some((pattern) => pattern.test(parameterType)); } function isBytesNType(parameterType) { return /^BytesN<\d+>$/.test(parameterType); } // src/mapping/struct-fields.ts function extractStructFields(entries, structName) { try { const entry = entries.find((e) => { try { return e.value().name().toString() === structName; } catch { return false; } }); if (!entry) { return null; } const entryKind = entry.switch(); if (entryKind.value === xdr2.ScSpecEntryKind.scSpecEntryUdtStructV0().value) { const structUdt = entry.udtStructV0(); const fields = structUdt.fields(); const structFields = []; for (const field of fields) { const fieldName = field.name().toString(); const fieldType = extractSorobanTypeFromScSpec(field.type()); structFields.push({ name: fieldName, type: fieldType }); } return structFields; } return null; } catch (error) { logger3.error( "extractStructFields", `Failed to extract struct fields for ${structName}:`, error ); return null; } } function isStructType(entries, typeName) { try { const entry = entries.find((e) => { try { const entryName = e.value().name().toString(); return entryName === typeName; } catch { return false; } }); if (!entry) { return false; } const entryKind = entry.switch(); const isStruct = entryKind.value === xdr2.ScSpecEntryKind.scSpecEntryUdtStructV0().value; return isStruct; } catch (error) { logger3.error("isStructType", `Failed to check if ${typeName} is struct:`, error); return false; } } // src/query/handler.ts import { Account, Address as Address2, BASE_FEE, Contract, Keypair, nativeToScVal as nativeToScVal5, rpc as StellarRpc, TransactionBuilder } from "@stellar/stellar-sdk"; import { logger as logger10, userRpcConfigService } from "@openzeppelin/ui-builder-utils"; // src/transform/parsers/index.ts import { isEnumValue as isEnumValue2 } from "@openzeppelin/ui-builder-types"; import { isPlainObject as isPlainObject2, logger as logger8 } from "@openzeppelin/ui-builder-utils"; // src/transform/parsers/generic-parser.ts import { isMapEntryArray } from "@openzeppelin/ui-builder-types"; import { logger as logger4 } from "@openzeppelin/ui-builder-utils"; var SYSTEM_LOG_TAG2 = "GenericParser"; function parseGenericType(typeString) { const match = typeString.match(/^(\w+)<(.*)>$/); if (!match) return null; const baseType = match[1]; const paramString = match[2]; const parameters = []; let current = ""; let depth = 0; let i = 0; while (i < paramString.length) { const char = paramString[i]; if (char === "<") { depth++; current += char; } else if (char === ">") { depth--; current += char; } else if (char === "," && depth === 0) { parameters.push(current.trim()); current = ""; } else { current += char; } i++; } if (current.trim()) { parameters.push(current.trim()); } return { baseType, parameters }; } function parseGeneric(value, parameterType, parseInnerValue) { try { const genericInfo = parseGenericType(parameterType); if (!genericInfo) { return null; } const { baseType, parameters } = genericInfo; switch (baseType) { case "Vec": { if (!Array.isArray(value)) { throw new Error(`Array expected for Vec type ${parameterType}, got ${typeof value}`); } const innerType = parameters[0]; if (!innerType) { throw new Error(`Could not parse Vec inner type: ${parameterType}`); } return value.map((item) => parseInnerValue(item, innerType)); } case "Map": { if (!isMapEntryArray(value)) { throw new Error(`Array of MapEntry objects expected for Map type, got ${typeof value}`); } if (parameters.length < 2) { throw new Error(`Could not parse Map types: ${parameterType}`); } const mapKeyType = parameters[0]; const mapValueType = parameters[1]; return value.map((entry) => ({ 0: { value: entry.key, type: mapKeyType }, 1: { value: entry.value, type: mapValueType } })); } case "Option": { if (value === null || value === void 0 || value === "") { return null; } const innerType = parameters[0]; if (!innerType) { throw new Error(`Could not parse Option inner type: ${parameterType}`); } return parseInnerValue(value, innerType); } case "Result": { if (parameters.length < 2) { throw new Error(`Could not parse Result types: ${parameterType}`); } if (typeof value === "object" && value !== null) { const resultObj = value; if ("ok" in resultObj) { return { ok: parseInnerValue(resultObj.ok, parameters[0]) }; } else if ("err" in resultObj) { return { err: parseInnerValue(resultObj.err, parameters[1]) }; } } return value; } default: logger4.warn(SYSTEM_LOG_TAG2, `Unknown generic type: ${baseType}`); return null; } } catch (error) { logger4.error(SYSTEM_LOG_TAG2, `Failed to parse generic type ${parameterType}:`, error); throw error; } } function isGenericType(parameterType) { const genericInfo = parseGenericType(parameterType); return genericInfo !== null && ["Vec", "Map", "Option", "Result"].includes(genericInfo.baseType); } // src/transform/parsers/primitive-parser.ts import { Address } from "@stellar/stellar-sdk"; import { detectBytesEncoding, logger as logger5, stringToBytes } from "@openzeppelin/ui-builder-utils"; var SYSTEM_LOG_TAG3 = "PrimitiveParser"; function parsePrimitive(value, parameterType) { try { if (value === null || value === void 0) { return null; } switch (parameterType) { // Boolean: convert string "true"/"false" to actual boolean case "Bool": if (typeof value === "boolean") { return value; } if (typeof value === "string") { return value.toLowerCase() === "true"; } throw new Error(`Boolean parameter expected, got ${typeof value}`); // Bytes: handle encoding detection case "Bytes": if (typeof value === "string") { const cleanValue = value.startsWith("0x") ? value.slice(2) : value; const encoding = detectBytesEncoding(cleanValue); return stringToBytes(cleanValue, encoding); } throw new Error(`Bytes parameter must be a string, got ${typeof value}`); // DataUrl: handle base64 encoded data (similar to Bytes) case "DataUrl": if (typeof value === "string") { const encoding = detectBytesEncoding(value); return stringToBytes(value, encoding); } throw new Error(`DataUrl parameter must be a string, got ${typeof value}`); // Address: validate format case "Address": if (typeof value === "string") { try { Address.fromString(value); return value; } catch { throw new Error(`Invalid Stellar address format: ${value}`); } } throw new Error(`Address parameter must be a string, got ${typeof value}`); // String types: return as-is case "ScString": case "ScSymbol": if (typeof value === "string") { return value; } throw new Error(`String parameter expected, got ${typeof value}`); default: if (/^BytesN<\d+>$/.test(parameterType)) { if (typeof value === "string") { const cleanValue = value.startsWith("0x") ? value.slice(2) : value; const encoding = detectBytesEncoding(cleanValue); return stringToBytes(cleanValue, encoding); } throw new Error(`Bytes parameter must be a string, got ${typeof value}`); } if (/^[UI](32|64|128|256)$/.test(parameterType)) { if (typeof value === "string") { if (!/^-?\d+$/.test(value.trim())) { throw new Error(`Invalid number format for ${parameterType}: ${value}`); } return value; } if (typeof value === "number") { return value.toString(); } throw new Error(`Numeric parameter expected for ${parameterType}, got ${typeof value}`); } return null; } } catch (error) { logger5.error(SYSTEM_LOG_TAG3, `Failed to parse primitive ${parameterType}:`, error); throw error; } } function isPrimitiveType(parameterType) { return parameterType === "Bool" || parameterType === "Bytes" || parameterType === "DataUrl" || parameterType === "Address" || parameterType === "ScString" || parameterType === "ScSymbol" || /^BytesN<\d+>$/.test(parameterType) || /^[UI](32|64|128|256)$/.test(parameterType); } // src/transform/parsers/complex-parser.ts import { nativeToScVal as nativeToScVal2, xdr as xdr4 } from "@stellar/stellar-sdk"; import { detectBytesEncoding as detectBytesEncoding3, stringToBytes as stringToBytes3 } from "@openzeppelin/ui-builder-utils"; // src/utils/safe-type-parser.ts var PARSING_LIMITS = { /** Maximum depth for nested generic types to prevent stack overflow */ MAX_NESTING_DEPTH: 10, /** Maximum string length for type parsing to prevent DoS */ MAX_TYPE_STRING_LENGTH: 1e3 }; function extractVecElementType(parameterType) { if (!isValidTypeString(parameterType) || !parameterType.startsWith("Vec<")) { return null; } return extractGenericInnerType(parameterType, "Vec"); } function extractMapTypes(parameterType) { if (!isValidTypeString(parameterType) || !parameterType.startsWith("Map<")) { return null; } const innerContent = extractGenericInnerType(parameterType, "Map"); if (!innerContent) { return null; } const commaIndex = findTopLevelComma(innerContent); if (commaIndex === -1) { return null; } const keyType = innerContent.slice(0, commaIndex).trim(); const valueType = innerContent.slice(commaIndex + 1).trim(); if (!keyType || !valueType || hasInvalidCharacters(keyType) || hasInvalidCharacters(valueType)) { return null; } return { keyType, valueType }; } function extractOptionElementType(parameterType) { if (!isValidTypeString(parameterType) || !parameterType.startsWith("Option<")) { return null; } return extractGenericInnerType(parameterType, "Option"); } function extractGenericInnerType(parameterType, genericName) { const prefix = `${genericName}<`; if (!parameterType.startsWith(prefix) || !parameterType.endsWith(">")) { return null; } const innerContent = parameterType.slice(prefix.length, -1); if (!innerContent || hasInvalidCharacters(innerContent)) { return null; } if (!isBalancedBrackets(innerContent)) { return null; } return innerContent.trim(); } function findTopLevelComma(content) { let angleLevel = 0; for (let i = 0; i < content.length; i++) { const char = content[i]; switch (char) { case "<": angleLevel++; break; case ">": angleLevel--; if (angleLevel < 0) return -1; break; case ",": if (angleLevel === 0) { return i; } break; } } return -1; } function isBalancedBrackets(content) { let angleLevel = 0; let maxNesting = 0; for (const char of content) { switch (char) { case "<": angleLevel++; maxNesting = Math.max(maxNesting, angleLevel); if (maxNesting > PARSING_LIMITS.MAX_NESTING_DEPTH) { return false; } break; case ">": angleLevel--; if (angleLevel < 0) return false; break; } } return angleLevel === 0; } function isValidTypeString(typeString) { if (!typeString || typeof typeString !== "string") { return false; } if (typeString.length > PARSING_LIMITS.MAX_TYPE_STRING_LENGTH) { return false; } if (hasInvalidCharacters(typeString)) { return false; } return isBalancedBrackets(typeString); } function hasInvalidCharacters(str) { if (/[\x00-\x1F\x7F\r\n]/.test(str)) { return true; } return !/^[A-Za-z0-9<>,\s_]+$/.test(str); } // src/utils/formatting.ts function stringifyWithBigInt(value, space) { const replacer = (_key, val) => { if (typeof val === "bigint") { return val.toString(); } return val; }; return JSON.stringify(value, replacer, space); } function isSerializableObject(value) { return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof Uint8Array) && value.constructor === Object; } function convertStellarTypeToScValType(stellarType) { if (!isValidTypeString(stellarType)) { return stellarType.toLowerCase(); } if (stellarType.startsWith("Vec<")) { const innerType = extractVecElementType(stellarType); if (innerType) { const innerScValType = convertStellarTypeToScValType(innerType); return Array.isArray(innerScValType) ? innerScValType[0] : innerScValType; } } if (stellarType.startsWith("Map<")) { return "map-special"; } if (stellarType.startsWith("Option<")) { const innerType = extractOptionElementType(stellarType); if (innerType) { return convertStellarTypeToScValType(innerType); } } switch (stellarType) { case "Address": return "address"; case "U32": return "u32"; case "U64": return "u64"; case "U128": return "u128"; case "U256": return "u256"; case "I32": return "i32"; case "I64": return "i64"; case "I128": return "i128"; case "I256": return "i256"; case "ScString": return "string"; case "ScSymbol": return "symbol"; case "Bool": return "bool"; case "Bytes": return "bytes"; case "DataUrl": return "bytes"; default: if (/^BytesN<\d+>$/.test(stellarType)) { return "bytes"; } return stellarType.toLowerCase(); } } // src/utils/input-parsing.ts import { nativeToScVal, xdr as xdr3 } from "@stellar/stellar-sdk"; import { detectBytesEncoding as detectBytesEncoding2, logger as logger6, stringToBytes as stringToBytes2 } from "@openzeppelin/ui-builder-utils"; var SYSTEM_LOG_TAG4 = "StellarInputParsingUtils"; function isMapArray(argValue) { try { return Array.isArray(argValue) && argValue.every((obj) => { if (typeof obj !== "object" || obj === null) return false; const keys = Object.keys(obj); if (keys.length !== 2 || !keys.includes("0") || !keys.includes("1")) { return false; } const keyEntry = obj["0"]; return typeof keyEntry === "object" && keyEntry !== null && "value" in keyEntry && "type" in keyEntry; }); } catch { return false; } } function getScValFromPrimitive(v) { try { if (v.type === "bool") { const boolValue = typeof v.value === "boolean" ? v.value : v.value === "true"; return nativeToScVal(boolValue); } if (v.type === "bytes") { const stringValue = v.value; const encoding = detectBytesEncoding2(stringValue); return nativeToScVal(stringToBytes2(stringValue, encoding)); } const typeHint = convertStellarTypeToScValType(v.type); return nativeToScVal(v.value, { type: typeHint }); } catch (error) { logger6.error(SYSTEM_LOG_TAG4, `Failed to convert primitive ${v.type}:`, error); throw new Error(`Failed to convert primitive value of type ${v.type}: ${error}`); } } function getScValFromArg(arg, scVals) { if (Array.isArray(arg) && arg.length > 0) { const arrayScVals = arg.map((subArray) => { if (Array.isArray(subArray) && isMapArray(subArray)) { const { mapVal, mapType } = convertObjectToMap(subArray); const items = Object.keys(mapVal); if (items.length > 1) { items.forEach((item) => { const mapScVal = nativeToScVal(mapVal[item], { type: mapType[item] }); scVals.push(mapScVal); }); } return nativeToScVal(mapVal, { type: mapType }); } return getScValFromArg(subArray, scVals); }); return xdr3.ScVal.scvVec(arrayScVals); } if (typeof arg === "object" && arg !== null && "type" in arg && "value" in arg) { return getScValFromPrimitive(arg); } return nativeToScVal(arg); } function convertEnumToScVal(obj, scVals) { try { if (obj.enum !== void 0) { const enumScVal = nativeToScVal(obj.enum, { type: "u32" }); return enumScVal; } if (!obj.tag) { throw new Error('Enum object must have either "tag" or "enum" property'); } const tagSymbol = nativeToScVal(obj.tag, { type: "symbol" }); if (!obj.values || obj.values.length === 0) { const unitVec = xdr3.ScVal.scvVec([tagSymbol]); return unitVec; } const valuesVal = obj.values.map((v) => getScValFromArg(v, scVals || [])); const tupleVec = xdr3.ScVal.scvVec([tagSymbol, ...valuesVal]); return tupleVec; } catch (error) { logger6.error(SYSTEM_LOG_TAG4, "Failed to convert enum:", error); throw new Error(`Failed to convert enum: ${error}`); } } function convertObjectToMap(mapArray) { try { const mapVal = mapArray.reduce((acc, pair) => { const key = pair["0"].value; if (Array.isArray(pair["1"])) { const valueScVal = getScValFromArg(pair["1"], []); acc[key] = valueScVal; } else { const value = pair["1"].value; acc[key] = pair["1"].type === "bool" ? value === "true" : value; } return acc; }, {}); const mapType = mapArray.reduce((acc, pair) => { const key = pair["0"].value; const keyTypeHint = convertStellarTypeToScValType(pair["0"].type); const valueTypeHint = convertStellarTypeToScValType(pair["1"].type); acc[key] = [ ...Array.isArray(keyTypeHint) ? keyTypeHint : [keyTypeHint], ...Array.isArray(valueTypeHint) ? valueTypeHint : [valueTypeHint] ]; return acc; }, {}); return { mapVal, mapType }; } catch (error) { logger6.error(SYSTEM_LOG_TAG4, "Failed to convert map:", error); throw new Error(`Failed to convert map: ${error}`); } } // src/transform/parsers/scval-converter.ts import { nativeToScVal as nativeToScVal4 } from "@stellar/stellar-sdk"; import { isEnumValue } from "@openzeppelin/ui-builder-types"; // src/transform/parsers/struct-parser.ts import { nativeToScVal as nativeToScVal3 } from "@stellar/stellar-sdk"; import { isPlainObject, logger as logger7 } from "@openzeppelin/ui-builder-utils"; var SYSTEM_LOG_TAG5 = "StructParser"; function needsParsing(value, fieldType) { if ((fieldType === "Bytes" || fieldType.startsWith("BytesN<")) && value instanceof Uint8Array) { return false; } if (fieldType.startsWith("Vec<")) { if (!Array.isArray(value)) { return true; } const innerTypeMatch = fieldType.match(/Vec<(.+)>$/); if (innerTypeMatch) { return true; } } if (fieldType.startsWith("Map<")) { return true; } if (typeof value === "string") { return true; } if (isPlainObject(value)) { return true; } return false; } function convertStructToScVal(structObj, parameterType, paramSchema, parseInnerValue) { const convertedValue = {}; const typeHints = {}; for (const [fieldName, fieldValue] of Object.entries(structObj)) { let fieldType; if (paramSchema?.components) { const fieldSchema = paramSchema.components.find( (comp) => comp.name === fieldName ); fieldType = fieldSchema?.type; } if (fieldType) { let parsedValue; if (needsParsing(fieldValue, fieldType)) { parsedValue = parseInnerValue(fieldValue, fieldType); } else { parsedValue = fieldValue; } if (fieldType.startsWith("Map<") && Array.isArray(parsedValue)) { const mapTypeMatch = fieldType.match(/Map<(.+),\s*(.+)>$/); const mapKeyType = mapTypeMatch ? mapTypeMatch[1] : "ScSymbol"; const mapValueType = mapTypeMatch ? mapTypeMatch[2] : "Bytes"; const mapObject = {}; const mapTypeHints = {}; parsedValue.forEach((entry) => { const processedKey = parseInnerValue(entry[0].value, entry[0].type || mapKeyType); const processedVal = parseInnerValue(entry[1].value, entry[1].type || mapValueType); const keyString = typeof processedKey === "string" ? processedKey : String(processedKey); mapObject[keyString] = processedVal; const keyScValType = convertStellarTypeToScValType(entry[0].type || mapKeyType); const valueScValType = convertStellarTypeToScValType(entry[1].type || mapValueType); mapTypeHints[keyString] = [ Array.isArray(keyScValType) ? keyScValType[0] : keyScValType === "map-special" ? "symbol" : keyScValType, Array.isArray(valueScValType) ? valueScValType[0] : valueScValType === "map-special" ? "bytes" : valueScValType ]; }); convertedValue[fieldName] = mapObject; typeHints[fieldName] = ["symbol", mapTypeHints]; } else { convertedValue[fieldName] = parsedValue; const scValType = convertStellarTypeToScValType(fieldType); if (scValType !== "map-special") { typeHints[fieldName] = ["symbol", Array.isArray(scValType) ? scValType[0] : scValType]; } } } else { throw new Error( `Missing schema information for struct field "${fieldName}" in struct type "${parameterType}". Schema-based type resolution is required for accurate ScVal conversion.` ); } } logger7.debug(SYSTEM_LOG_TAG5, "convertStructToScVal final values:", { parameterType, convertedValue, typeHints }); const scVal = nativeToScVal3(convertedValue, { type: typeHints }); logger7.debug(SYSTEM_LOG_TAG5, "convertStructToScVal generated ScVal:", { parameterType, scValType: scVal.switch().name, scValValue: scVal.value() }); return scVal; } function isStructType2(value, parameterType) { if (!isPlainObject(value)) { return false; } const genericInfo = parseGenericType(parameterType); if (genericInfo) { return false; } const obj = value; if ("tag" in obj || "enum" in obj || "values" in obj) { return false; } return !(value instanceof Uint8Array) && !(value instanceof Date) && typeof value.constructor === "function" && value.constructor === Object; } // src/transform/parsers/scval-converter.ts function valueToScVal(value, parameterType, paramSchema, parseInnerValue) { const parseValue = parseInnerValue || ((val) => val); const genericInfo = parseGenericType(parameterType); if (!genericInfo) { if (isEnumValue(value) || typeof value === "object" && value !== null && "enum" in value) { return convertEnumToScVal(value); } if (isStructType2(value, parameterType)) { return convertStructToScVal( value, parameterType, paramSchema, parseValue ); } if (parameterType === "Bool" || parameterType === "Bytes") { return nativeToScVal4(value); } if (isBytesNType(parameterType)) { const match = parameterType.match(/^BytesN<(\d+)>$/); if (!match) { throw new Error(`Invalid BytesN parameterType format: ${parameterType}`); } const expectedBytes = Number.parseInt(match[1], 10); const decoded = parsePrimitive(value, "Bytes"); const bytesValue = decoded instanceof Uint8Array ? decoded : decoded ?? value; if (Number.isFinite(expectedBytes) && bytesValue instanceof Uint8Array && bytesValue.length !== expectedBytes) { throw new Error( `BytesN value must be exactly ${expectedBytes} bytes, received ${bytesValue.length}` ); } return nativeToScVal4(bytesValue); } const scValType = convertStellarTypeToScValType(parameterType); const typeHint = Array.isArray(scValType) ? scValType[0] : scValType; return nativeToScVal4(value, { type: typeHint }); } const { baseType, parameters } = genericInfo; switch (baseType) { case "Vec": { const innerType = parameters[0]; if (Array.isArray(value)) { const convertedElements = value.map((element) => valueToScVal(element, innerType)); return nativeToScVal4(convertedElements); } return nativeToScVal4(value); } case "Map": { if (Array.isArray(value)) { const convertedValue = {}; const typeHints = {}; value.forEach( (entry) => { if (typeof entry !== "object" || entry === null || !entry[0] || !entry[1] || typeof entry[0].value === "undefined" || typeof entry[1].value === "undefined") { throw new Error("Invalid Stellar SDK map format in valueToScVal"); } let processedKey = entry[0].value; let processedValue = entry[1].value; const keyPrimitive = parsePrimitive(entry[0].value, entry[0].type); if (keyPrimitive !== null) { processedKey = keyPrimitive; } const valuePrimitive = parsePrimitive(entry[1].value, entry[1].type); if (valuePrimitive !== null) { processedValue = valuePrimitive; } const keyString = typeof processedKey === "string" ? processedKey : String(processedKey); convertedValue[keyString] = processedValue; const keyScValType = convertStellarTypeToScValType(entry[0].type); const valueScValType = convertStellarTypeToScValType(entry[1].type); typeHints[keyString] = [ Array.isArray(keyScValType) ? keyScValType[0] : keyScValType, Array.isArray(valueScValType) ? valueScValType[0] : valueScValType ]; } ); return nativeToScVal4(convertedValue, { type: typeHints }); } return nativeToScVal4(value); } case "Option": { const innerType = parameters[0]; if (value === null || value === void 0) { return nativeToScVal4(null); } else { return valueToScVal(value, innerType); } } case "Result": { const okType = parameters[0]; const errType = parameters[1]; if (typeof value === "object" && value !== null) { const resultObj = value; if ("ok" in resultObj) { const okScVal = valueToScVal(resultObj.ok, okType); return nativeToScVal4({ ok: okScVal }); } else if ("err" in resultObj) { const errScVal = valueToScVal(resultObj.err, errType); return nativeToScVal4({ err: errScVal }); } } return nativeToScVal4(value); } default: { const scValType = convertStellarTypeToScValType(parameterType); const typeHint = Array.isArray(scValType) ? scValType[0] : scValType; return nativeToScVal4(value, { type: typeHint }); } } } // src/transform/parsers/index.ts var SYSTEM_LOG_TAG6 = "StellarInputParser"; function parseStellarInput(value, parameterType) { try { if (value === null || value === void 0) { return null; } if (isPrimitiveType(parameterType)) { const result = parsePrimitive(value, parameterType); if (result !== null) { return result; } } if (isGenericType(parameterType)) { const result = parseGeneric(value, parameterType, parseStellarInput); return result; } if (isEnumValue2(value) && isLikelyEnumType(parameterType)) { return value; } if (isPlainObject2(value)) { return value; } if (typeof value === "string" || typeof value === "number") { return value; } throw new Error(`Unsupported parameter type: ${parameterType} with value type ${typeof value}`); } catch (error) { logger8.error(SYSTEM_LOG_TAG6, "Failed to parse Stellar input:", error); throw error; } } // src/transform/output-formatter.ts import { scValToNative, xdr as xdr7 } from "@stellar/stellar-sdk"; import { bytesToHex, logger as logger9 } from "@openzeppelin/ui-builder-utils"; // src/types/artifacts.ts function isStellarContractArtifacts(obj) { return typeof obj === "object" && obj !== null && typeof obj.contractAddress === "string"; } // src/utils/artifacts.ts function validateAndConvertStellarArtifacts(source) { if (typeof source === "string") { return { contractAddress: source }; } if (!isStellarContractArtifacts(source)) { throw new Error( "Invalid contract artifacts provided. Expected an object with contractAddress property." ); } return source; } // src/transform/output-formatter.ts function formatStellarFunctionResult(result, functionDetails) { if (!functionDetails.outputs || !Array.isArray(functionDetails.outputs)) { logger9.warn( "formatStellarFunctionResult", `Output definition missing or invalid for function ${functionDetails.name}.` ); return "[Error: Output definition missing]"; } try { let valueToFormat; if (result === null || result === void 0) { return "(null)"; } if (isScVal(result)) { try { const scVal = result; if (scVal.switch().name === "scvVoid") { return "(void)"; } valueToFormat = scValToNative(scVal); if (valueToFormat && typeof valueToFormat === "object" && "constructor" in valueToFormat && valueToFormat.constructor?.name === "Buffer") { valueToFormat = new Uint8Array(valueToFormat); } } catch (error) { logger9.error("formatStellarFunctionResult", "Failed to convert ScVal to native", { functionName: functionDetails.name, error }); return "[Error: Failed to decode ScVal]"; } } else { valueToFormat = result; } if (typeof valueToFormat === "bigint") { return valueToFormat.toString(); } else if (typeof valueToFormat === "string") { return valueToFormat; } else if (typeof valueToFormat === "number") { return valueToFormat.toString(); } else if (typeof valueToFormat === "boolean") { return String(valueToFormat); } else if (valueToFormat instanceof Uint8Array) { return bytesToHex(valueToFormat, true); } else if (Array.isArray(valueToFormat)) { if (valueToFormat.length === 0) { return "[]"; } if (valueToFormat.every( (item) => typeof item === "string" || typeof item === "number" || typeof item === "boolean" || typeof item === "bigint" )) { return stringifyWithBigInt(valueToFormat); } return stringifyWithBigInt(valueToFormat, 2); } else if (isSerializableObject(valueToFormat)) { if (Object.keys(valueToFormat).length === 0) { return "{}"; } return stringifyWithBigInt(valueToFormat, 2); } else if (valueToFormat === null || valueToFormat === void 0) { return "(null)"; } else { return stringifyWithBigInt(valueToFormat, 2); } } catch (error) { const errorMessage = `Error formatting result for ${functionDetails.name}: ${error.message}`; logger9.error("formatStellarFunctionResult", errorMessage, { functionName: functionDetails.name, result, error }); return `[${errorMessage}]`; } } function isScVal(value) { if (!value || typeof value !== "object") { return false; } try { return typeof xdr7 !== "undefined" && xdr7.ScVal && value instanceof xdr7.ScVal; } catch { return false; } } // src/query/view-checker.ts function isStellarViewFunction(functionDetails) { if (functionDetails.stateMutability) { return functionDetails.stateMutability === "view" || functionDetails.stateMutability === "pure"; } return !functionDetails.modifiesState; } function getStellarWritableFunctions(contractSchema) { return contractSchema.functions.filter((func) => !isStellarViewFunction(func)); } // src/query/handler.ts function getSorobanRpcServer(networkConfig) { const customRpcConfig = userRpcConfigService.getUserRpcConfig(networkConfig.id); const rpcUrl = customRpcConfig?.url || networkConfig.sorobanRpcUrl; if (!rpcUrl) { throw new Error(`No Soroban RPC URL available for network ${networkConfig.name}`); } logger10.info( "getSorobanRpcServer", `Creating Soroban RPC server for ${networkConfig.name} using RPC: ${rpcUrl}` ); const allowHttp = new URL(rpcUrl).hostname === "localhost"; return new StellarRpc.Server(rpcUrl, { allowHttp }); } async function createSimulationTransaction(contractAddress, functionName, args, paramTypes, networkConfig) { try { const dummyKeypair = Keypair.random(); const sourceAccount = new Account(dummyKeypair.publicKey(), "0"); const contract2 = new Contract(contractAddress); const scValArgs = args.map((arg, index) => { const paramType = paramTypes[index]; if (!paramType) { return nativeToScVal5(arg); } if (paramType === "Bool" || paramType === "Bytes" || paramType.match(/^BytesN<\d+>$/)) { return nativeToScVal5(arg); } const typeHint = convertStellarTypeToScValType(paramType); return nativeToScVal5(arg, { type: typeHint }); }); const transaction = new TransactionBuilder(sourceAccount, { fee: BASE_FEE, networkPassphrase: networkConfig.networkPassphrase }).addOperation(contract2.call(functionName, ...scValArgs)).setTimeout(30); return transaction; } catch (error) { logger10.error("createSimulationTransaction", "Failed to create simulation transaction:", error); throw new Error(`Failed to create simulation transaction: ${error.message}`); } } async function checkStellarFunctionStateMutability(contractAddress, functionName, networkConfig, inputTypes = []) { logger10.info( "checkStellarFunctionStateMutability", `Checking state mutability for function: ${functionName} on ${contractAddress}` ); try { try { Address2.fromString(contractAddress); } catch { throw new Error(`Invalid Stellar contract address provided: ${contractAddress}`); } const rpcServer = getSorobanRpcServer(networkConfig); const dummyArgs = inputTypes.map((paramType) => { switch (paramType) { case "Bool": return false; case "I32": case "U32": case "I64": case "U64": case "I128": case "U128": case "I256": case "U256": return 0; case "String": return ""; case "Bytes": return Buffer.alloc(0); case "Address": return contractAddress; default: return null; } }); const transactionBuilder = await createSimulationTransaction( contractAddress, functionName, dummyArgs, inputTypes, networkConfig ); const transaction = transactionBuilder.build(); logger10.debug( "checkStellarFunctionStateMutability", `[Check ${functionName}] Simulating transaction for state mutability check` ); let simulationResult; try { simulationResult = await rpcServer.simulateTransaction(transaction); } catch (simulationError) { logger10.warn( "checkStellarFunctionStateMutability", `[Check ${functionName}] Simulation failed, assuming function modifies state:`, simulationError ); return true; } if (StellarRpc.Api.isSimulationError(simulationResult)) { logger10.warn( "checkStellarFunctionStateMutability", `[Check ${functionName}] Simulation error, assuming function modifies state:`, simulationResult.error ); return true; } const hasStateChanges = simulationResult.stateChanges && simulationResult.stateChanges.length > 0; logger10.info( "checkStellarFunctionStateMutability", `[Check ${functionName}] State mutability check complete:`, { hasStateChanges, stateChangesCount: simulationResult.stateChanges?.length || 0, modifiesState: Boolean(hasStateChanges) } ); return Boolean(hasStateChanges); } catch (error) { logger10.warn( "checkStellarFunctionStateMutability", `Failed to check state mutability for ${functionName}, assuming it modifies state:`, error ); return true; } } async function queryStellarViewFunction(contractAddress, functionId, networkConfig, params = [], contractSchema, loadContractFn) { logger10.info( "queryStellarViewFunction", `Querying Stellar view function: ${functionId} on ${contractAddress} (${networkConfig.name})`, { params } ); if (networkConfig.ecosystem !== "stellar") { throw new Error("Invalid network configuration for Stellar query."); } const stellarConfig = networkConfig; try { try { Address2.fromString(contractAddress); } catch { throw new Error(`Invalid Stellar contract address provided: ${contractAddress}`); } const rpcServer = getSorobanRpcServer(stellarConfig); let schema = contractSchema; if (!schema && loadContractFn) { schema = await loadContractFn(contractAddress); } if (!schema) { throw new Error( `Contract schema not provided and loadContractFn not available for ${contractAddress}` ); } const functionDetails = schema.functions.find((fn) => fn.id === functionId); if (!functionDetails) { throw new Error(`Function with ID ${functionId} not found in contract schema.`); } if (!isStellarViewFunction(functionDetails)) { throw new Error(`Function ${functionDetails.name} is not a view function.`); } const expectedInputs = functionDetails.inputs; if (params.length !== expectedInputs.length) { throw new Error( `Incorrect number of parameters provided for ${functionDetails.name}. Expected ${expectedInputs.length}, got ${params.length}.` ); } const args = expectedInputs.map((inputParam, index) => { const rawValue = params[index]; return parseStellarInput(rawValue, inputParam.type); }); logger10.debug("queryStellarViewFunction", "Parsed Args for contract call:", args); const paramTypes = expectedInputs.map((input) => input.type); const transactionBuilder = await createSimulationTransaction( contractAddress, functionDetails.name, args, paramTypes, stellarConfig ); const transaction = transactionBuilder.build(); logger10.debug( "queryStellarViewFunction", `[Query ${functionDetails.name}] Simulating transaction:`, transaction.toXDR() ); let simulationResult; try { simulationResult = await rpcServer.simulateTransaction(transaction); } catch (simulationError) { logger10.error( "queryStellarViewFunction", `[Query ${functionDetails.name}] Simulation failed:`, simulationError ); throw new Error( `Soroban RPC simulation failed for ${functionDetails.name}: ${simulationError.message}` ); } if (StellarRpc.Api.isSimulationError(simulationResult)) { logger10.error( "queryStellarViewFunction", `[Query ${functionDetails.name}] Simulation error:`, simulationResult.error ); throw new Error(`Contract simulation failed: ${simulationResult.error}`); } if (!simulationResult.result) { throw new Error(`No result returned from contract s