@openzeppelin/ui-builder-adapter-stellar
Version:
Stellar Adapter for UI Builder
1,436 lines (1,409 loc) • 180 kB
JavaScript
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