@openzeppelin/contracts-ui-builder-adapter-stellar
Version:
Stellar Adapter for Contracts UI Builder
4,860 lines • 185 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
// src/index.ts
var index_exports = {};
__export(index_exports, {
StellarAdapter: () => StellarAdapter,
isStellarContractArtifacts: () => isStellarContractArtifacts,
stellarAdapterConfig: () => stellarAdapterConfig,
stellarMainnetNetworks: () => stellarMainnetNetworks,
stellarNetworks: () => stellarNetworks,
stellarPublic: () => stellarPublic,
stellarTestnet: () => stellarTestnet,
stellarTestnetNetworks: () => stellarTestnetNetworks
});
module.exports = __toCommonJS(index_exports);
// src/adapter.ts
var import_contracts_ui_builder_types6 = require("@openzeppelin/contracts-ui-builder-types");
var import_contracts_ui_builder_utils34 = require("@openzeppelin/contracts-ui-builder-utils");
// src/contract/loader.ts
var StellarSdk2 = __toESM(require("@stellar/stellar-sdk"), 1);
var import_contracts_ui_builder_utils12 = require("@openzeppelin/contracts-ui-builder-utils");
// src/validation/address.ts
var import_stellar_sdk = require("@stellar/stellar-sdk");
function isValidAccountAddress(address) {
try {
return import_stellar_sdk.StrKey.isValidEd25519PublicKey(address);
} catch {
return false;
}
}
function isValidContractAddress(address) {
try {
return import_stellar_sdk.StrKey.isValidContract(address);
} catch {
return false;
}
}
function isValidMuxedAddress(address) {
try {
return import_stellar_sdk.StrKey.isValidMed25519PublicKey(address);
} catch {
return false;
}
}
function isValidSecretSeed(seed) {
try {
return import_stellar_sdk.StrKey.isValidEd25519SecretSeed(seed);
} catch {
return false;
}
}
function isValidSignedPayloadAddress(address) {
try {
return import_stellar_sdk.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 {
import_stellar_sdk.StrKey.decodePreAuthTx(address);
return true;
} catch {
return false;
}
case "hash-x":
try {
import_stellar_sdk.StrKey.decodeSha256Hash(address);
return true;
} catch {
return false;
}
default:
return false;
}
}
try {
return import_stellar_sdk.StrKey.isValidEd25519PublicKey(address) || // G... - accounts (most common)
import_stellar_sdk.StrKey.isValidContract(address) || // C... - contracts
import_stellar_sdk.StrKey.isValidMed25519PublicKey(address);
} catch {
return false;
}
}
// src/validation/eoa.ts
var import_contracts_ui_builder_utils = require("@openzeppelin/contracts-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) {
import_contracts_ui_builder_utils.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
var import_stellar_sdk2 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils3 = require("@openzeppelin/contracts-ui-builder-utils");
// src/utils/type-detection.ts
var StellarSdk = __toESM(require("@stellar/stellar-sdk"), 1);
var import_contracts_ui_builder_utils2 = require("@openzeppelin/contracts-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:
import_contracts_ui_builder_utils2.logger.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 ((0, import_contracts_ui_builder_utils2.isDevelopmentOrTestEnvironment)()) {
throw new Error(
`Missing ScSpec type handler: ${typeSwitch.name} (value: ${typeSwitch.value}). Please add support for this type.`
);
}
import_contracts_ui_builder_utils2.logger.error("STELLAR_ADAPTER_MISSING_TYPE", "Missing ScSpec type handler:", errorReport);
return "unknown";
}
} catch (error) {
import_contracts_ui_builder_utils2.logger.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));
}
// 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 === import_stellar_sdk2.xdr.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) {
import_contracts_ui_builder_utils3.logger.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 === import_stellar_sdk2.xdr.ScSpecEntryKind.scSpecEntryUdtStructV0().value;
return isStruct;
} catch (error) {
import_contracts_ui_builder_utils3.logger.error("isStructType", `Failed to check if ${typeName} is struct:`, error);
return false;
}
}
// src/query/handler.ts
var import_stellar_sdk9 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils11 = require("@openzeppelin/contracts-ui-builder-utils");
// src/transform/parsers/index.ts
var import_contracts_ui_builder_types3 = require("@openzeppelin/contracts-ui-builder-types");
var import_contracts_ui_builder_utils9 = require("@openzeppelin/contracts-ui-builder-utils");
// src/transform/parsers/generic-parser.ts
var import_contracts_ui_builder_types = require("@openzeppelin/contracts-ui-builder-types");
var import_contracts_ui_builder_utils4 = require("@openzeppelin/contracts-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 (!(0, import_contracts_ui_builder_types.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:
import_contracts_ui_builder_utils4.logger.warn(SYSTEM_LOG_TAG2, `Unknown generic type: ${baseType}`);
return null;
}
} catch (error) {
import_contracts_ui_builder_utils4.logger.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
var import_stellar_sdk3 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils5 = require("@openzeppelin/contracts-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 = (0, import_contracts_ui_builder_utils5.detectBytesEncoding)(cleanValue);
return (0, import_contracts_ui_builder_utils5.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 = (0, import_contracts_ui_builder_utils5.detectBytesEncoding)(value);
return (0, import_contracts_ui_builder_utils5.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 {
import_stellar_sdk3.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 = (0, import_contracts_ui_builder_utils5.detectBytesEncoding)(cleanValue);
return (0, import_contracts_ui_builder_utils5.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) {
import_contracts_ui_builder_utils5.logger.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
var import_stellar_sdk5 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils7 = require("@openzeppelin/contracts-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:
return stellarType.toLowerCase();
}
}
// src/utils/input-parsing.ts
var import_stellar_sdk4 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils6 = require("@openzeppelin/contracts-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 (0, import_stellar_sdk4.nativeToScVal)(boolValue);
}
if (v.type === "bytes") {
const stringValue = v.value;
const encoding = (0, import_contracts_ui_builder_utils6.detectBytesEncoding)(stringValue);
return (0, import_stellar_sdk4.nativeToScVal)((0, import_contracts_ui_builder_utils6.stringToBytes)(stringValue, encoding));
}
const typeHint = convertStellarTypeToScValType(v.type);
return (0, import_stellar_sdk4.nativeToScVal)(v.value, { type: typeHint });
} catch (error) {
import_contracts_ui_builder_utils6.logger.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 = (0, import_stellar_sdk4.nativeToScVal)(mapVal[item], {
type: mapType[item]
});
scVals.push(mapScVal);
});
}
return (0, import_stellar_sdk4.nativeToScVal)(mapVal, { type: mapType });
}
return getScValFromArg(subArray, scVals);
});
return import_stellar_sdk4.xdr.ScVal.scvVec(arrayScVals);
}
if (typeof arg === "object" && arg !== null && "type" in arg && "value" in arg) {
return getScValFromPrimitive(arg);
}
return (0, import_stellar_sdk4.nativeToScVal)(arg);
}
function convertEnumToScVal(obj, scVals) {
try {
if (obj.enum !== void 0) {
const enumScVal = (0, import_stellar_sdk4.nativeToScVal)(obj.enum, { type: "u32" });
return enumScVal;
}
if (!obj.tag) {
throw new Error('Enum object must have either "tag" or "enum" property');
}
const tagSymbol = (0, import_stellar_sdk4.nativeToScVal)(obj.tag, { type: "symbol" });
if (!obj.values || obj.values.length === 0) {
const unitVec = import_stellar_sdk4.xdr.ScVal.scvVec([tagSymbol]);
return unitVec;
}
const valuesVal = obj.values.map((v) => getScValFromArg(v, scVals || []));
const tupleVec = import_stellar_sdk4.xdr.ScVal.scvVec([tagSymbol, ...valuesVal]);
return tupleVec;
} catch (error) {
import_contracts_ui_builder_utils6.logger.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) {
import_contracts_ui_builder_utils6.logger.error(SYSTEM_LOG_TAG4, "Failed to convert map:", error);
throw new Error(`Failed to convert map: ${error}`);
}
}
// src/transform/parsers/scval-converter.ts
var import_stellar_sdk7 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_types2 = require("@openzeppelin/contracts-ui-builder-types");
// src/transform/parsers/struct-parser.ts
var import_stellar_sdk6 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils8 = require("@openzeppelin/contracts-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 ((0, import_contracts_ui_builder_utils8.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.`
);
}
}
import_contracts_ui_builder_utils8.logger.debug(SYSTEM_LOG_TAG5, "convertStructToScVal final values:", {
parameterType,
convertedValue,
typeHints
});
const scVal = (0, import_stellar_sdk6.nativeToScVal)(convertedValue, { type: typeHints });
import_contracts_ui_builder_utils8.logger.debug(SYSTEM_LOG_TAG5, "convertStructToScVal generated ScVal:", {
parameterType,
scValType: scVal.switch().name,
scValValue: scVal.value()
});
return scVal;
}
function isStructType2(value, parameterType) {
if (!(0, import_contracts_ui_builder_utils8.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 ((0, import_contracts_ui_builder_types2.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 (0, import_stellar_sdk7.nativeToScVal)(value);
}
const scValType = convertStellarTypeToScValType(parameterType);
const typeHint = Array.isArray(scValType) ? scValType[0] : scValType;
return (0, import_stellar_sdk7.nativeToScVal)(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 (0, import_stellar_sdk7.nativeToScVal)(convertedElements);
}
return (0, import_stellar_sdk7.nativeToScVal)(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 (0, import_stellar_sdk7.nativeToScVal)(convertedValue, { type: typeHints });
}
return (0, import_stellar_sdk7.nativeToScVal)(value);
}
case "Option": {
const innerType = parameters[0];
if (value === null || value === void 0) {
return (0, import_stellar_sdk7.nativeToScVal)(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 (0, import_stellar_sdk7.nativeToScVal)({ ok: okScVal });
} else if ("err" in resultObj) {
const errScVal = valueToScVal(resultObj.err, errType);
return (0, import_stellar_sdk7.nativeToScVal)({ err: errScVal });
}
}
return (0, import_stellar_sdk7.nativeToScVal)(value);
}
default: {
const scValType = convertStellarTypeToScValType(parameterType);
const typeHint = Array.isArray(scValType) ? scValType[0] : scValType;
return (0, import_stellar_sdk7.nativeToScVal)(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 ((0, import_contracts_ui_builder_types3.isEnumValue)(value) && isLikelyEnumType(parameterType)) {
return value;
}
if ((0, import_contracts_ui_builder_utils9.isPlainObject)(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) {
import_contracts_ui_builder_utils9.logger.error(SYSTEM_LOG_TAG6, "Failed to parse Stellar input:", error);
throw error;
}
}
// src/transform/output-formatter.ts
var import_stellar_sdk8 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils10 = require("@openzeppelin/contracts-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)) {
import_contracts_ui_builder_utils10.logger.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 = (0, import_stellar_sdk8.scValToNative)(scVal);
if (valueToFormat && typeof valueToFormat === "object" && "constructor" in valueToFormat && valueToFormat.constructor?.name === "Buffer") {
valueToFormat = new Uint8Array(valueToFormat);
}
} catch (error) {
import_contracts_ui_builder_utils10.logger.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 (0, import_contracts_ui_builder_utils10.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}`;
import_contracts_ui_builder_utils10.logger.error("formatStellarFunctionResult", errorMessage, {
functionName: functionDetails.name,
result,
error
});
return `[${errorMessage}]`;
}
}
function isScVal(value) {
if (!value || typeof value !== "object") {
return false;
}
try {
return typeof import_stellar_sdk8.xdr !== "undefined" && import_stellar_sdk8.xdr.ScVal && value instanceof import_stellar_sdk8.xdr.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 = import_contracts_ui_builder_utils11.userRpcConfigService.getUserRpcConfig(networkConfig.id);
const rpcUrl = customRpcConfig?.url || networkConfig.sorobanRpcUrl;
if (!rpcUrl) {
throw new Error(`No Soroban RPC URL available for network ${networkConfig.name}`);
}
import_contracts_ui_builder_utils11.logger.info(
"getSorobanRpcServer",
`Creating Soroban RPC server for ${networkConfig.name} using RPC: ${rpcUrl}`
);
const allowHttp = new URL(rpcUrl).hostname === "localhost";
return new import_stellar_sdk9.rpc.Server(rpcUrl, {
allowHttp
});
}
async function createSimulationTransaction(contractAddress, functionName, args, paramTypes, networkConfig) {
try {
const dummyKeypair = import_stellar_sdk9.Keypair.random();
const sourceAccount = new import_stellar_sdk9.Account(dummyKeypair.publicKey(), "0");
const contract2 = new import_stellar_sdk9.Contract(contractAddress);
const scValArgs = args.map((arg, index) => {
const paramType = paramTypes[index];
if (!paramType) {
return (0, import_stellar_sdk9.nativeToScVal)(arg);
}
if (paramType === "Bool" || paramType === "Bytes" || paramType.match(/^BytesN<\d+>$/)) {
return (0, import_stellar_sdk9.nativeToScVal)(arg);
}
const typeHint = convertStellarTypeToScValType(paramType);
return (0, import_stellar_sdk9.nativeToScVal)(arg, { type: typeHint });
});
const transaction = new import_stellar_sdk9.TransactionBuilder(sourceAccount, {
fee: import_stellar_sdk9.BASE_FEE,
networkPassphrase: networkConfig.networkPassphrase
}).addOperation(contract2.call(functionName, ...scValArgs)).setTimeout(30);
return transaction;
} catch (error) {
import_contracts_ui_builder_utils11.logger.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 = []) {
import_contracts_ui_builder_utils11.logger.info(
"checkStellarFunctionStateMutability",
`Checking state mutability for function: ${functionName} on ${contractAddress}`
);
try {
try {
import_stellar_sdk9.Address.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();
import_contracts_ui_builder_utils11.logger.debug(
"checkStellarFunctionStateMutability",
`[Check ${functionName}] Simulating transaction for state mutability check`
);
let simulationResult;
try {
simulationResult = await rpcServer.simulateTransaction(transaction);
} catch (simulationError) {
import_contracts_ui_builder_utils11.logger.warn(
"checkStellarFunctionStateMutability",
`[Check ${functionName}] Simulation failed, assuming function modifies state:`,
simulationError
);
return true;
}
if (import_stellar_sdk9.rpc.Api.isSimulationError(simulationResult)) {
import_contracts_ui_builder_utils11.logger.warn(
"checkStellarFunctionStateMutability",
`[Check ${functionName}] Simulation error, assuming function modifies state:`,
simulationResult.error
);
return true;
}
const hasStateChanges = simulationResult.stateChanges && simulationResult.stateChanges.length > 0;
import_contracts_ui_builder_utils11.logger.info(
"checkStellarFunctionStateMutability",
`[Check ${functionName}] State mutability check complete:`,
{
hasStateChanges,
stateChangesCount: simulationResult.stateChanges?.length || 0,
modifiesState: Boolean(hasStateChanges)
}
);
return Boolean(hasStateChanges);
} catch (error) {
import_contracts_ui_builder_utils11.logger.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) {
import_contracts_ui_builder_utils11.logger.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 {
import_stellar_sdk9.Address.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);
});
import_contracts_ui_builder_utils11.logger.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();
import_contracts_ui_builder_utils11.logger.debug(
"queryStellarViewFunction",
`[Query ${functionDetails.name}] Simulating transaction:`,
transaction.toXDR()
);
let simulationResult;
try {
simulationResult = await rpcServer.simulateTransaction(transaction);
} catch (simulationError) {
import_contracts_ui_builder_utils11.logger.error(
"queryStellarViewFunction",
`[Query ${functionDetails.name}] Simulation failed:`,
simulationError
);
throw new Error(
`Soroban RPC simulation failed for ${functionDetails.name}: ${simulationError.message}`
);
}
if (import_stellar_sdk9.rpc.Api.isSimulationError(simulationResult)) {
import_contracts_ui_builder_utils11.logger.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 simulation for ${functionDetails.name}`);
}
const rawResult = simulationResult.result.retval;
import_contracts_ui_builder_utils11.logger.debug(
"queryStellarViewFunction",
`[Query ${functionDetails.name}] Raw simulation result:`,
rawResult
);
const formattedResult = formatStellarFunctionResult(rawResult, functionDetails);
import_contracts_ui_builder_utils11.logger.info(
"queryStellarViewFunction",
`[Query ${functionDetails.name}] Formatted result:`,
formattedResult
);
return formattedResult;
} catch (error) {
const errorMessage = `Failed to query Stellar view function ${functionId} on network ${networkConfig.name}: ${error.message}`;
import_contracts_ui_builder_utils11.logger.error("queryStellarViewFunction", errorMessage, {
contractAddress,
functionId,
params,
networkConfig,
error
});
throw new Error(errorMessage);
}
}
// src/contract/loader.ts
async function loadStellarContractFromAddress(contractAddress, networkConfig) {
import_contracts_ui_builder_utils12.logger.info("loadStellarContractFromAddress", "Loading contract:", {
contractAddress,
network: networkConfig.name,
rpcUrl: networkConfig.sorobanRpcUrl,
networkPassphrase: networkConfig.networkPassphrase
});
try {
if (!StellarSdk2.StrKey.isValidContract(contractAddress)) {
throw new Error(`Invalid contract address: ${contractAddress}`);
}
let contractClient;
try {
contractClient = await StellarSdk2.contract.Client.from({
contractId: contractAddress,
networkPassphrase: networkConfig.networkPassphrase,
rpcUrl: networkConfig.sorobanRpcUrl
});
} catch (e) {
const message = e?.message || String(e);
if (message.includes("Cannot destructure property 'length'")) {
const friendly = "Unable to fetch contract metadata from RPC. The contract appears to have no published Wasm/definition on this network.";
import_contracts_ui_builder_utils12.logger.error("loadStellarContractFromAddress", friendly);
throw new Error(`NO_WASM: ${friendly}`);
}
throw e;
}
import_contracts_ui_builder_utils12.logger.info("loadStellarContractFromAddress", "Contract client created successfully");
let specEntries = [];
try {
if (contractClient.spec && typeof contractClient.spec === "object") {
const spec = contractClient.spec;
if (Array.isArray(spec.entries)) {
specEntries = spec.entries;
} else if (Array.isArray(spec._entries)) {
specEntries = spec._entries;
} else if (Array.isArray(spec.specEntries)) {
specEntries = spec.specEntries;
} else if (typeof spec.entries === "function") {
try {
specEntries = spec.entries();
} catch (e) {
import_contracts_ui_builder_utils12.logger.warn("loadStellarContractFromAddress", "entries() method failed:", e);
}
}
if (specEntries.length === 0 && typeof spec.entries === "function") {
try {
specEntries = spec.entries();
} catch (e) {
import_contracts_ui_builder_utils12.logger.warn("loadStellarContractFromAddress", "direct entries() method failed:", e);
}
}
import_contracts_ui_builder_utils12.logger.info("loadStellarContractFromAddress", `Found ${specEntries.length} spec entries`);
}
} catch (specError) {
import_contracts_ui_builder_utils12.logger.warn("loadStellarContractFromAddress", "Could not extract spec entries:", specError);
}
const functions = await extractFunctionsFromSpec(
contractClient.spec,
contractAddress,
specEntries,
networkConfig
);
import_contracts_ui_builder_utils12.logger.info(
"loadStellarContractFromAddress",
`Successfully extracted ${functions.length} functions`
);
return {
name: `Soroban Contract ${contractAddress.slice(0, 8)}...`,
ecosystem: "stellar",
functions,
metadata: {
specEntries
}
};
} catch (error) {
const msg = error?.message || String(error);
if (msg.startsWith("NO_WASM:")) {
import_contracts_ui_builder_utils12.logger.error("loadStellarContractFromAddress", msg);
throw new Error(msg);
}
import_contracts_ui_builder_utils12.logger.error("loadStellarContractFromAddress", "Failed to load contract:", error);
throw new Error(`Failed to load contract: ${msg}`);
}
}
async function extractFunctionsFromSpec(spec, contractAddress, specEntries, networkConfig) {
try {
const specFunctions = spec.funcs();
import_contracts_ui_builder_utils12.logger.info("extractFunctionsFromSpec", `Found ${specFunctions.length} functions in spec`);
return await Promise.all(
specFunctions.map(async (func, index) => {
try {
const functionName = func.name().toString();
import_contracts_ui_builder_utils12.logger.info("extractFunctionsFromSpec", `Processing function: ${functionName}`);
const inputs = func.inputs().map((input, inputIndex) => {
try {
const inputName = input.name().toString();
const inputType = extractSorobanTypeFromScSpec(input.type());
if (inputType === "unknown") {
import_contracts_ui_builder_utils12.logger.warn(
"extractFunctionsFromSpec",
`Unknown type for parameter "${inputName}" in function "${functionName}"`
);
}
let components;
if (specEntries && specEntries.length > 0 && isStructType(specEntries, inputType)) {
const structFields = extractStructFields(specEntries, inputType);
if (structFields && structFields.length > 0) {
components = structFields;
import_contracts_ui_builder_utils12.logger.debug(
"extractFunctionsFromSpec",
`Extracted ${structFields.length} fields for struct type "${inputType}": ${structFields.map((f) => `${f.name}:${f.type}`).join(", ")}`
);
} else {
import_contracts_ui_builder_utils12.logger.warn(
"extractFunctionsFromSpec",
`No fields extracted for struct "${inputType}"`
);
}
}
return {
name: inputName || `param_${inputIndex}`,
type: inputType,
...components && { components }
};
} catch (error) {
import_contracts_ui_builder_utils12.logger.warn(
"extractFunctionsFromSpec",
`Failed to parse input ${inputIndex}:`,
error
);
return {
name: `param_${inputIndex}`,
type: "unknown"
};
}
});
const outputs = func.outputs().map((output, outputIndex) => {
try {
const outputType = extractSorobanTypeFromScSpec(output);
return {
name: `result_${outputIndex}`,
type: outputType
};
} catch (error) {
import_contracts_ui_builder_utils12.logger.warn(
"extractFunctionsFromSpec",
`Failed to parse output ${outputIndex}:`,
error
);
return {
name: `result_${outputIndex}`,
type: "unknown"
};
}
});
let modifiesState = true;
let stateMutability = "nonpayable";
if (networkConfig) {
try {
const inputTypes = inputs.map((input) => input.type);
import_contracts_ui_builder_utils12.logger.debug(
"extractFunctionsFromSpec",
`Checking state mutability for ${functionName} with input types: ${inputTypes.join(", ")}`
);
modifiesState = await checkStellarFunctionStateMutability(
contractAddress,
functionName,
networkConfig,
inputTypes
);
stateMutability = modifiesState ? "nonpayable" : "view";
import_contracts_ui_builder_utils12.logger.info(
"extractFunctionsFromSpec",
`Function ${functionName} state mutability determined:`,
{ modifiesState, stateMutability }
);
} catch (error) {
import_contracts_ui_builder_utils12.logger.warn(
"extractFunctionsFromSpec",
`Failed to determine state mutability for ${functionName}, assuming it modifies state:`,
error
);
}
} else {
import_contracts_ui_builder_utils12.logger.warn(
"extractFunctionsFromSpec",
`No network config provided for ${functionName}, assuming it modifies state`
);
}
const functionId = `${functionName}_${inputs.map((i) => i.type).join("_")}`;
return {
id: functionId,
name: functionName,
displayName: functionName.charAt(0).toUpperCase() + functionName.slice(1).replace(/_/g, " "),
description: `Soroban function: ${functionName}`,
inputs,
outputs,
type: "function",
modifiesState,
stateMutability
};
} catch (error) {
import_contracts_ui_builder_utils12.logger.error("extractFunctionsFromSpec", `Failed to process function ${index}:`, error);
return {
id: `function_${index}`,
name: `function_${index}`,
displayName: `Function ${index}`,
description: `Failed to parse function ${index}: ${error.message}`,
inputs: [],
outputs: [],
type: "function",
modifiesState: true,
stateMutability: "nonpayable"
};
}
})
);
} catch (error) {
import_contracts_ui_builder_utils12.logger.error("extractFunctionsFromSpec", "Failed to extract functions from spec:", error);
throw new Error(`Failed to extract functions: ${error.message}`);
}
}
async function loadStellarContract(artifacts, networkConfig) {
if (typeof artifacts.contractAddress !== "string") {
throw new Error("A contract address must be provided.");
}
const schema = await loadStellarContractFromAddress(artifacts.contractAddress, networkConfig);
const schemaWithAddress = { ...schema, address: artifacts.contractAddress };
return {
schema: schemaWithAddress,
source: "fetched",
contractDefinitionOriginal: JSON.stringify(schemaWithAddress),
metadata: {
fetchedFrom: getStellarExplorerAddressUrl(artifacts.contractAddress, networkConfig) || networkConfig.sorobanRpcUrl,
contractName: schema.name,
fetchTimestamp: /* @__PURE__ */ new Date()
}
};
}
async function loadStellarContractWithMetadata(artifacts, networkConfig) {
if (typeof artifacts.contractAddress !== "string") {
throw new Error("A contract address must be provided.");
}
try {
const contractData = await loadStellarContractFromAddress(
artifacts.contractAddress,
networkConfig
);
const schema = {
...contractData,
address: artifacts.contractAddress
};
return {
schema,
source: "fetched",
contractDefinitionOriginal: JSON.stringify(schema),
metadata: {
fetchedFrom: getStellarExplorerAddressUrl(artifacts.contractAddress, networkConfig) || networkConfig.sorobanRpcUrl,
contractName: schema.name,
fetchTimestamp: /* @__PURE__ */ new Date()
}
};
} catch (error) {
const errorMessage = error.message || "";
if (errorMessage.startsWith("NO_WASM:")) {
throw new Error(errorMessage.replace(/^NO_WASM:\s*/, ""));
}
if (errorMessage.includes("Failed to load contract")) {
throw new Error(
`Contract at ${artifacts.contractAddress} could not be loaded from the network. Please verify the contract ID is correct and the network is accessible.`
);
}
throw error;
}
}
// src/transaction/components/StellarRelayerOptions.tsx
var import_react2 = __toESM(require("react"), 1);
var import_contracts_ui_builder_ui4 = require("@openzeppelin/contracts-ui-builder-ui");
// src/transaction/components/AdvancedInfo.tsx
var import_lucide_react = require("lucide-react");
var import_contracts_ui_builder_ui = require("@openzeppelin/contracts-ui-builder-ui");
var import_jsx_runtime = require("react/jsx-runtime");
var AdvancedInfo = ({ showAdvancedInfo, onToggle }) => {
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-base font-medium", children: "Stellar Transaction Configuration" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_contracts_ui_builder_ui.Button, { variant: "ghost", size: "sm", onClick: onToggle, className: "text-xs", type: "button", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Info, { className: "h-3 w-3 mr-1" }),
"Stellar Options"
] })
] }),
showAdvancedInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-3 rounded-lg bg-muted/30 p-4", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-sm text-muted-foreground leading-relaxed", children: [
"Configure Stellar-specific transaction parameters: ",
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "maxFee" }),
" sets the maximum fee in stroops you're willing to pay, ",
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "validUntil" }),
" sets transaction expiration, and ",
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "feeBump" }),
" enables automatic fee increases for stuck transactions."
] }) })
] });
};
// src/transaction/components/FeeConfiguration.tsx
var import_contracts_ui_builder_ui2 = require("@openzeppelin/contracts-ui-builder-ui");
var import_jsx_runtime2 = require("react/jsx-runtime");
var FeeConfiguration = ({
control,
showBasicFeeOnly
}) => {
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-4", children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_contracts_ui_builder_ui2.NumberField,
{
id: "maxFee",
label: "Maximum Fee (stroops)",
name: "transactionOptions.maxFee",
control,
placeholder: "e.g., 1000000 (0.1 XLM)",
helperText: "Maximum fee you're willing to pay in stroops (1 XLM = 10,000,000 stroops). Leave empty to use network defaults.",
min: 0,
step: 1
}
),
!showBasicFeeOnly && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_contracts_ui_builder_ui2.BooleanField,
{
id: "feeBump",
label: "Enable Fee Bump",
name: "transactionOptions.feeBump",
control,
helperText: "Automatically increase fee if transaction gets stuck in the network."
}
)
] });
};
// src/transaction/components/TransactionTiming.tsx
var import_react_hook_form = require("react-hook-form");
var import_contracts_ui_builder_ui3 = require("@openzeppelin/contracts-ui-builder-ui");
var import_jsx_runtime3 = require("react/jsx-runtime");
var TransactionTiming = ({ control }) => {
const getOneHourFromNow = () => {
const now = /* @__PURE__ */ new Date();
now.setHours(now.getHours() + 1);
return now.toISOString().slice(0, 16);
};
const getTwentyFourHoursFromNow = () => {
const now = /* @__PURE__ */ new Date();
now.setHours(now.getHours() + 24);
return now.toISOString().slice(0, 16);
};
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "space-y-4", children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_contracts_ui_builder_ui3.DateTimeField,
{
id: "validUntil",
label: "Transaction Expiration",
name: "transactionOptions.validUntil",
control,
placeholder: "YYYY-MM-DDTHH:mm",
helperText: "Set when this transaction should expire. Leave empty for no expiration limit."
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex gap-2 pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_react_hook_form.Controller,
{
name: "transactionOptions.validUntil",
control,
render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_contracts_ui_builder_ui3.Button,
{
type: "button",
variant: "outline",
size: "sm",
onClick: () => field.onChange(new Date(getOneHourFromNow()).toISOString()),
className: "text-xs",
children: "+1 Hour"
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_contracts_ui_builder_ui3.Button,
{
type: "button",
variant: "outline",
size: "sm",
onClick: () => field.onChange(new Date(getTwentyFourHoursFromNow()).toISOString()),
className: "text-xs",
children: "+24 Hours"
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_contracts_ui_builder_ui3.Button,
{
type: "button",
variant: "outline",
size: "sm",
onClick: () => field.onChange(""),
className: "text-xs",
children: "Clear"
}
)
] })
}
) })
] });
};
// src/transaction/components/useStellarRelayerOptions.ts
var import_react = require("react");
var import_react_hook_form2 = require("react-hook-form");
var useStellarRelayerOptions = ({ options, onChange }) => {
const onChangeRef = (0, import_react.useRef)(onChange);
onChangeRef.current = onChange;
const initialOptions = {
maxFee: options.maxFee,
validUntil: options.validUntil,
feeBump: options.feeBump
};
const { control, setValue, watch } = (0, import_react_hook_form2.useForm)({
defaultValues: {
transactionOptions: initialOptions
}
});
const formValues = watch("transactionOptions");
const isInitialMount = (0, import_react.useRef)(true);
const [userMode, setUserMode] = (0, import_react.useState)(() => {
const hasAdvancedSettings = Boolean(formValues.validUntil || formValues.feeBump);
return hasAdvancedSettings ? "advanced" : "basic";
});
const configMode = userMode;
(0, import_react.useEffect)(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
return;
}
}, []);
(0, import_react.useEffect)(() => {
if (isInitialMount.current) {
return;
}
const timeoutId = setTimeout(() => {
const newOptions = {};
if (formValues.maxFee !== void 0 && formValues.maxFee !== null) {
newOptions.maxFee = formValues.maxFee;
}
if (formValues.validUntil && formValues.validUntil.trim() !== "") {
newOptions.validUntil = formValues.validUntil;
}
if (formValues.feeBump !== void 0) {
newOptions.feeBump = formValues.feeBump;
}
onChangeRef.current(newOptions);
}, 100);
return () => clearTimeout(timeoutId);
}, [formValues.maxFee, formValues.validUntil, formValues.feeBump]);
const handleModeChange = (mode) => {
const newMode = mode;
setUserMode(newMode);
if (newMode === "basic") {
setValue("transactionOptions", {
...formValues,
validUntil: void 0,
feeBump: void 0
});
} else {
setValue("transactionOptions", {
...formValues,
validUntil: formValues.validUntil || void 0,
feeBump: formValues.feeBump || false
});
}
};
return {
control,
formValues,
configMode,
handleModeChange
};
};
// src/transaction/components/StellarRelayerOptions.tsx
var import_jsx_runtime4 = require("react/jsx-runtime");
var StellarRelayerOptions = ({ options, onChange }) => {
const [showAdvancedInfo, setShowAdvancedInfo] = import_react2.default.useState(false);
const { control, configMode, handleModeChange } = useStellarRelayerOptions({
options,
onChange
});
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "space-y-4", children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
AdvancedInfo,
{
showAdvancedInfo,
onToggle: () => setShowAdvancedInfo(!showAdvancedInfo)
}
),
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_contracts_ui_builder_ui4.Tabs, { value: configMode, onValueChange: handleModeChange, children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_contracts_ui_builder_ui4.TabsList, { className: "grid w-full grid-cols-2", children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_contracts_ui_builder_ui4.TabsTrigger, { value: "basic", children: "Basic" }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_contracts_ui_builder_ui4.TabsTrigger, { value: "advanced", children: "Advanced" })
] }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_contracts_ui_builder_ui4.TabsContent, { value: "basic", className: "space-y-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FeeConfiguration, { control, showBasicFeeOnly: true }) }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_contracts_ui_builder_ui4.TabsContent, { value: "advanced", className: "space-y-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "space-y-6", children: [
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FeeConfiguration, { control, showBasicFeeOnly: false }),
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TransactionTiming, { control })
] }) })
] })
] });
};
// src/transaction/relayer.ts
var import_stellar_sdk10 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils18 = require("@openzeppelin/contracts-ui-builder-utils");
var import_relayer_sdk = require("@openzeppelin/relayer-sdk");
// src/wallet/connection.ts
var import_contracts_ui_builder_utils17 = require("@openzeppelin/contracts-ui-builder-utils");
// src/wallet/utils/stellarWalletImplementationManager.ts
var import_contracts_ui_builder_utils14 = require("@openzeppelin/contracts-ui-builder-utils");
// src/wallet/implementation/wallets-kit-implementation.ts
var import_stellar_wallets_kit = require("@creit.tech/stellar-wallets-kit");
var import_contracts_ui_builder_utils13 = require("@openzeppelin/contracts-ui-builder-utils");
var LOG_SYSTEM = "StellarWalletImplementation";
var WalletsKitImplementation = class {
/**
* Constructs the StellarWalletImplementation.
* Configuration for StellarWalletsKit is deferred until actually needed or set externally.
* @param networkConfig - Stellar network configuration
* @param initialUiKitConfig - Optional initial UI kit configuration, primarily for logging the anticipated kit.
*/
constructor(networkConfig, initialUiKitConfig) {
__publicField(this, "defaultInstanceKit", null);
__publicField(this, "activeStellarKit", null);
// To be set by StellarUiKitManager
__publicField(this, "unsubscribeFromStatusChanges");
__publicField(this, "initialized", false);
__publicField(this, "networkConfig", null);
// Internal state tracking for connection status
__publicField(this, "currentAddress", null);
__publicField(this, "currentWalletId", null);
__publicField(this, "connectionStatusListeners", /* @__PURE__ */ new Set());
this.networkConfig = networkConfig || null;
import_contracts_ui_builder_utils13.logger.info(
LOG_SYSTEM,
"Constructor called. Initial anticipated kitName:",
initialUiKitConfig?.kitName,
"Network:",
networkConfig?.name
);
this.initialized = true;
import_contracts_ui_builder_utils13.logger.info(
LOG_SYSTEM,
"StellarWalletImplementation instance initialized (StellarWalletsKit config creation deferred)."
);
}
/**
* Sets the network configuration for the wallet implementation
* @param config - The Stellar network configuration
*/
setNetworkConfig(config) {
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Network config updated:", config.name);
this.networkConfig = config;
if (this.activeStellarKit || this.defaultInstanceKit) {
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Active kits detected - may need reconfiguration for new network");
}
}
/**
* Sets the externally determined, currently active StellarWalletsKit instance.
* This is typically called by StellarUiKitManager after it has resolved the appropriate
* kit for the selected UI kit mode.
* @param kit - The StellarWalletsKit object to set as active, or null to clear it.
*/
setActiveStellarKit(kit) {
import_contracts_ui_builder_utils13.logger.info(
LOG_SYSTEM,
"setActiveStellarKit called with kit:",
kit ? "Valid StellarWalletsKit" : "Null"
);
this.activeStellarKit = kit;
if (this.unsubscribeFromStatusChanges) {
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Re-establishing connection status monitoring with new kit");
}
}
/**
* Creates a default StellarWalletsKit instance when no active kit is available.
* This ensures wallet functionality works even without explicit UI kit configuration.
* @returns A default StellarWalletsKit instance
*/
createDefaultKit() {
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Creating default StellarWalletsKit instance");
const network = this.getWalletNetwork();
const kit = new import_stellar_wallets_kit.StellarWalletsKit({
network,
selectedWalletId: void 0,
modules: (0, import_stellar_wallets_kit.allowAllModules)()
});
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Default StellarWalletsKit instance created");
return kit;
}
/**
* Gets the appropriate WalletNetwork enum value based on network configuration
*/
getWalletNetwork() {
if (!this.networkConfig) {
import_contracts_ui_builder_utils13.logger.warn(LOG_SYSTEM, "No network config available, defaulting to TESTNET");
return import_stellar_wallets_kit.WalletNetwork.TESTNET;
}
return this.networkConfig.type === "mainnet" ? import_stellar_wallets_kit.WalletNetwork.PUBLIC : import_stellar_wallets_kit.WalletNetwork.TESTNET;
}
/**
* Gets the kit to use for operations (active or default)
*/
getKitToUse() {
const kit = this.activeStellarKit || this.defaultInstanceKit || (this.defaultInstanceKit = this.createDefaultKit());
return kit;
}
/**
* Gets available wallet connectors from StellarWalletsKit
* @returns Promise resolving to array of available connectors
*/
async getAvailableConnectors() {
if (!this.initialized) {
import_contracts_ui_builder_utils13.logger.warn(LOG_SYSTEM, "getAvailableConnectors called before initialization");
return [];
}
try {
const kit = this.getKitToUse();
const wallets = await kit.getSupportedWallets();
const connectors = wallets.map((wallet) => ({
id: wallet.id,
name: wallet.name,
icon: wallet.icon,
installed: wallet.isAvailable,
type: wallet.type || "browser"
}));
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, `Found ${connectors.length} available wallet connectors`);
return connectors;
} catch (error) {
import_contracts_ui_builder_utils13.logger.error(LOG_SYSTEM, "Failed to get available connectors:", error);
return [];
}
}
/**
* Connects to a wallet using the specified connector ID
* @param connectorId - The ID of the wallet connector to use
* @returns Promise resolving to connection result
*/
async connect(connectorId) {
if (!this.initialized) {
return { connected: false, error: "Wallet implementation not initialized" };
}
try {
const prevStatus = this.getWalletConnectionStatus();
const kit = this.getKitToUse();
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, `Attempting to connect to wallet: ${connectorId}`);
kit.setWallet(connectorId);
const result = await kit.getAddress();
if (result.address) {
this.currentAddress = result.address;
this.currentWalletId = connectorId;
const newStatus = this.getWalletConnectionStatus();
this.notifyConnectionListeners(newStatus, prevStatus);
import_contracts_ui_builder_utils13.logger.info(
LOG_SYSTEM,
`Successfully connected to wallet: ${connectorId}, address: ${result.address}`
);
return {
connected: true,
address: result.address,
chainId: this.networkConfig?.id
};
} else {
return {
connected: false,
error: "Failed to get address from wallet"
};
}
} catch (error) {
import_contracts_ui_builder_utils13.logger.error(LOG_SYSTEM, `Failed to connect to wallet ${connectorId}:`, error);
return {
connected: false,
error: error instanceof Error ? error.message : "Unknown error occurred"
};
}
}
/**
* Disconnects from the currently connected wallet
* @returns Promise resolving to disconnection result
*/
async disconnect() {
if (!this.initialized) {
return { disconnected: false, error: "Wallet implementation not initialized" };
}
try {
const prevStatus = this.getWalletConnectionStatus();
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Disconnecting wallet");
this.currentAddress = null;
this.currentWalletId = null;
const newStatus = this.getWalletConnectionStatus();
this.notifyConnectionListeners(newStatus, prevStatus);
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Successfully disconnected wallet");
return { disconnected: true };
} catch (error) {
import_contracts_ui_builder_utils13.logger.error(LOG_SYSTEM, "Failed to disconnect wallet:", error);
return {
disconnected: false,
error: error instanceof Error ? error.message : "Unknown error occurred"
};
}
}
/**
* Gets the current wallet connection status
* @returns The current connection status
*/
getWalletConnectionStatus() {
const isConnected = this.currentAddress !== null;
const chainId = this.networkConfig?.id || "stellar-testnet";
return {
isConnected,
isConnecting: false,
// We don't track intermediate connecting state yet
isDisconnected: !isConnected,
isReconnecting: false,
status: isConnected ? "connected" : "disconnected",
address: this.currentAddress || void 0,
walletId: this.currentWalletId || void 0,
chainId
};
}
/**
* Subscribes to wallet connection status changes
* @param callback - Function to call when connection status changes
* @returns A function to unsubscribe from the changes
*/
onWalletConnectionChange(callback) {
if (!this.initialized) {
import_contracts_ui_builder_utils13.logger.warn(LOG_SYSTEM, "onWalletConnectionChange called before initialization. No-op.");
return () => {
};
}
this.connectionStatusListeners.add(callback);
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Connection status listener added");
return () => {
this.connectionStatusListeners.delete(callback);
import_contracts_ui_builder_utils13.logger.debug(LOG_SYSTEM, "Connection status listener removed");
};
}
/**
* Manually updates the cached connection address and wallet ID
* This is used when the connection status is determined externally
* @param address - The wallet address or null
* @param walletId - The wallet ID or null
*/
updateConnectionStatus(address, walletId) {
const prevStatus = this.getWalletConnectionStatus();
this.currentAddress = address;
this.currentWalletId = walletId ?? null;
const newStatus = this.getWalletConnectionStatus();
this.notifyConnectionListeners(newStatus, prevStatus);
}
/**
* Gets the active StellarWalletsKit instance for advanced operations
* @returns The active kit or null if not available
*/
getActiveKit() {
return this.activeStellarKit || this.defaultInstanceKit;
}
/**
* Signs a transaction using the connected wallet
* @param xdr - The transaction XDR to sign
* @param address - The account address
* @returns Promise resolving to signed transaction
*/
async signTransaction(xdr11, address) {
if (!this.initialized) {
throw new Error("Wallet implementation not initialized");
}
const kit = this.getKitToUse();
const networkPassphrase = this.getWalletNetwork();
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Signing transaction with wallet");
return await kit.signTransaction(xdr11, {
address,
networkPassphrase
});
}
/**
* Notifies all connection listeners of status changes
*/
notifyConnectionListeners(currentStatus, previousStatus) {
this.connectionStatusListeners.forEach((listener) => {
try {
listener(currentStatus, previousStatus);
} catch (error) {
import_contracts_ui_builder_utils13.logger.error(LOG_SYSTEM, "Error in connection status listener:", String(error));
}
});
}
/**
* Cleanup resources when implementation is no longer needed
*/
cleanup() {
if (this.unsubscribeFromStatusChanges) {
this.unsubscribeFromStatusChanges();
this.unsubscribeFromStatusChanges = void 0;
}
this.connectionStatusListeners.clear();
import_contracts_ui_builder_utils13.logger.info(LOG_SYSTEM, "Cleanup completed");
}
};
// src/wallet/utils/stellarWalletImplementationManager.ts
var walletImplementationInstance;
var walletImplementationPromise;
var LOG_SYSTEM2 = "StellarWalletImplementationManager";
async function getStellarWalletImplementation(networkConfig) {
if (walletImplementationInstance) {
if (networkConfig) {
walletImplementationInstance.setNetworkConfig(networkConfig);
}
return walletImplementationInstance;
}
if (walletImplementationPromise) {
const instance = await walletImplementationPromise;
if (networkConfig) {
instance.setNetworkConfig(networkConfig);
}
return instance;
}
walletImplementationPromise = (async () => {
try {
import_contracts_ui_builder_utils14.logger.info(LOG_SYSTEM2, "Initializing StellarWalletImplementation singleton (async)...");
const initialUiKitConfig = import_contracts_ui_builder_utils14.appConfigService.getTypedNestedConfig(
"walletui",
"config"
);
const instance = new WalletsKitImplementation(networkConfig, initialUiKitConfig);
import_contracts_ui_builder_utils14.logger.info(LOG_SYSTEM2, "WalletsKitImplementation singleton created (async).");
walletImplementationInstance = instance;
return instance;
} catch (error) {
import_contracts_ui_builder_utils14.logger.error(LOG_SYSTEM2, "Failed to initialize WalletsKitImplementation (async):", error);
const fallbackInstance = new WalletsKitImplementation(networkConfig);
walletImplementationInstance = fallbackInstance;
return fallbackInstance;
}
})();
return walletImplementationPromise;
}
function getInitializedStellarWalletImplementation() {
if (!walletImplementationInstance) {
import_contracts_ui_builder_utils14.logger.warn(
LOG_SYSTEM2,
"getInitializedStellarWalletImplementation called before instance was ready."
);
}
return walletImplementationInstance;
}
// src/wallet/stellar-wallets-kit/stellarUiKitManager.ts
var import_stellar_wallets_kit2 = require("@creit.tech/stellar-wallets-kit");
var import_contracts_ui_builder_utils15 = require("@openzeppelin/contracts-ui-builder-utils");
var getInitialState = () => ({
isConfigured: false,
isInitializing: false,
hasConfigError: false,
error: null,
lastConfigError: null,
currentFullUiKitConfig: null,
stellarKitProvider: null,
kitProviderComponent: null,
isKitAssetsLoaded: false,
networkConfig: null
});
var state = getInitialState();
var listeners = /* @__PURE__ */ new Set();
function notifyListeners() {
listeners.forEach((listener) => listener(state));
}
function subscribe(listener) {
listeners.add(listener);
listener(state);
return () => {
listeners.delete(listener);
};
}
function getState() {
return state;
}
function setNetworkConfig(config) {
state = {
...state,
networkConfig: config
};
notifyListeners();
}
function getWalletNetwork(networkConfig) {
if (!networkConfig) {
import_contracts_ui_builder_utils15.logger.warn("StellarUiKitManager", "No network config available, defaulting to TESTNET");
return import_stellar_wallets_kit2.WalletNetwork.TESTNET;
}
return networkConfig.type === "mainnet" ? import_stellar_wallets_kit2.WalletNetwork.PUBLIC : import_stellar_wallets_kit2.WalletNetwork.TESTNET;
}
async function configure(newFullUiKitConfig) {
import_contracts_ui_builder_utils15.logger.info(
"StellarUiKitManager:configure",
"Configuring UI kit. New config:",
newFullUiKitConfig
);
const oldKitName = state.currentFullUiKitConfig?.kitName;
const newKitName = newFullUiKitConfig.kitName;
const kitChanged = oldKitName !== newKitName;
state = {
...state,
isInitializing: true,
error: null,
currentFullUiKitConfig: newFullUiKitConfig,
kitProviderComponent: kitChanged ? null : state.kitProviderComponent,
isKitAssetsLoaded: kitChanged ? false : state.isKitAssetsLoaded
};
notifyListeners();
try {
const walletNetwork = getWalletNetwork(state.networkConfig);
if (newKitName === "stellar-wallets-kit") {
const kit = new import_stellar_wallets_kit2.StellarWalletsKit({
network: walletNetwork,
selectedWalletId: void 0,
modules: (0, import_stellar_wallets_kit2.allowAllModules)()
// Use all available wallet modules
});
state.stellarKitProvider = kit;
state.kitProviderComponent = null;
state.isKitAssetsLoaded = true;
state.error = null;
import_contracts_ui_builder_utils15.logger.info(
"StellarUiKitManager:configure",
"Stellar Wallets Kit configured with built-in UI and all wallet modules"
);
} else if (newKitName === "custom" || !newKitName) {
const kit = new import_stellar_wallets_kit2.StellarWalletsKit({
network: walletNetwork,
selectedWalletId: void 0,
modules: (0, import_stellar_wallets_kit2.allowAllModules)()
});
state.stellarKitProvider = kit;
state.kitProviderComponent = null;
state.isKitAssetsLoaded = true;
state.error = null;
import_contracts_ui_builder_utils15.logger.info(
"StellarUiKitManager:configure",
"Stellar Wallets Kit configured for custom UI components"
);
} else if (newKitName === "none") {
state.stellarKitProvider = null;
state.kitProviderComponent = null;
state.isKitAssetsLoaded = false;
state.error = null;
import_contracts_ui_builder_utils15.logger.info("StellarUiKitManager:configure", 'UI kit set to "none", no wallet UI provided');
} else {
throw new Error(`Unknown UI kit name: ${newKitName}`);
}
state = {
...state,
isConfigured: true,
isInitializing: false,
hasConfigError: false,
error: null
};
notifyListeners();
} catch (error) {
import_contracts_ui_builder_utils15.logger.error("StellarUiKitManager:configure", "Failed to configure UI kit:", error);
state = {
...state,
isInitializing: false,
hasConfigError: true,
error: error instanceof Error ? error : new Error("Failed to configure UI kit"),
lastConfigError: error instanceof Error ? error : new Error("Failed to configure UI kit"),
isConfigured: false
};
notifyListeners();
throw error;
}
}
var stellarUiKitManager = {
configure,
getState,
subscribe,
setNetworkConfig
};
// src/wallet/stellar-wallets-kit/config-generator.ts
function generateStellarWalletsKitConfigFile(userConfig) {
const config = userConfig || {};
const appName = config.appName || "My Stellar App";
const network = config.network || "TESTNET";
const walletConnectProjectId = config.walletConnectProjectId || "";
const modalTitle = config.modalTitle || `Connect to ${appName}`;
const buttonText = config.buttonText || "Connect Wallet";
const fileContent = `// Stellar Wallets Kit configuration for your exported application
// This file is used ONLY in the exported app, not in the builder app preview
import {
StellarWalletsKit,
WalletNetwork,
allowAllModules,
WalletConnectModule,
WalletConnectAllowedMethods
} from '@creit.tech/stellar-wallets-kit';
/**
* Stellar Wallets Kit configuration wrapper
*
* The kit supports multiple wallets including:
* - Freighter
* - xBull
* - Ledger
* - Trezor
* - WalletConnect
* - And more...
*/
export const stellarWalletsKitConfig = {
// App information
appName: '${appName}',
// Network configuration (TESTNET or PUBLIC/MAINNET)
network: WalletNetwork.${network === "MAINNET" || network === "PUBLIC" ? "PUBLIC" : "TESTNET"},
// UI customization
buttonText: '${buttonText}',
modalTitle: '${modalTitle}',
// WalletConnect configuration
${walletConnectProjectId ? `walletConnectProjectId: '${walletConnectProjectId}',` : "// walletConnectProjectId: 'YOUR_PROJECT_ID', // Get yours at https://cloud.walletconnect.com"}
};
/**
* Creates and configures a StellarWalletsKit instance
* @returns Configured StellarWalletsKit instance
*/
export function createStellarWalletsKit(): StellarWalletsKit {
const modules = [
...allowAllModules(),
${walletConnectProjectId ? `
// WalletConnect module with custom configuration
new WalletConnectModule({
url: window.location.origin,
projectId: stellarWalletsKitConfig.walletConnectProjectId,
method: WalletConnectAllowedMethods.SIGN,
description: stellarWalletsKitConfig.appName,
name: stellarWalletsKitConfig.appName,
icons: [],
network: stellarWalletsKitConfig.network,
}),` : ""}
];
return new StellarWalletsKit({
network: stellarWalletsKitConfig.network,
modules,
});
}
export default stellarWalletsKitConfig;`;
return fileContent;
}
// src/wallet/stellar-wallets-kit/export-service.ts
function generateStellarWalletsKitExportables(uiKitConfig) {
const filePath = "src/config/wallet/stellar-wallets-kit.config.ts";
const content = uiKitConfig.customCode || generateStellarWalletsKitConfigFile(uiKitConfig.kitConfig);
return { [filePath]: content };
}
// src/wallet/stellar-wallets-kit/StellarWalletsKitConnectButton.tsx
var import_react3 = require("react");
var import_contracts_ui_builder_utils16 = require("@openzeppelin/contracts-ui-builder-utils");
var import_jsx_runtime5 = require("react/jsx-runtime");
function StellarWalletsKitConnectButton() {
const containerRef = (0, import_react3.useRef)(null);
(0, import_react3.useEffect)(() => {
const state2 = stellarUiKitManager.getState();
const kit = state2.stellarKitProvider;
if (!kit || !containerRef.current) {
import_contracts_ui_builder_utils16.logger.error(
"StellarWalletsKitConnectButton",
"Kit not initialized or container not available"
);
return;
}
kit.createButton({
container: containerRef.current,
onConnect: ({ address }) => {
import_contracts_ui_builder_utils16.logger.info("StellarWalletsKitConnectButton", `Connected to address: ${address}`);
},
onDisconnect: () => {
import_contracts_ui_builder_utils16.logger.info("StellarWalletsKitConnectButton", "Disconnected");
},
buttonText: "Connect Wallet"
});
return () => {
if (typeof kit.removeButton === "function") {
try {
kit.removeButton();
} catch (error) {
import_contracts_ui_builder_utils16.logger.warn("StellarWalletsKitConnectButton", "Error removing button:", error);
}
} else {
import_contracts_ui_builder_utils16.logger.warn(
"StellarWalletsKitConnectButton",
"removeButton method not available on kit instance"
);
}
};
}, []);
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: containerRef, className: "stellar-native-button" });
}
// src/wallet/connection.ts
function supportsStellarWalletConnection() {
return true;
}
async function getStellarAvailableConnectors() {
const impl = await getStellarWalletImplementation();
return impl.getAvailableConnectors();
}
async function connectStellarWallet(connectorId) {
const impl = await getStellarWalletImplementation();
return impl.connect(connectorId);
}
async function disconnectStellarWallet() {
const impl = await getStellarWalletImplementation();
return impl.disconnect();
}
function getStellarWalletConnectionStatus() {
const impl = getInitializedStellarWalletImplementation();
if (!impl) {
import_contracts_ui_builder_utils17.logger.warn(
"getStellarWalletConnectionStatus",
"Wallet implementation not ready. Returning default disconnected state."
);
return {
isConnected: false,
address: void 0,
chainId: stellarUiKitManager.getState().networkConfig?.id || "stellar-testnet",
walletId: void 0
};
}
const status = impl.getWalletConnectionStatus();
return {
isConnected: status.isConnected,
address: status.address,
chainId: typeof status.chainId === "number" ? status.chainId.toString() : status.chainId,
walletId: status.walletId
};
}
function onStellarWalletConnectionChange(callback) {
const impl = getInitializedStellarWalletImplementation();
if (!impl) {
import_contracts_ui_builder_utils17.logger.warn(
"onStellarWalletConnectionChange",
"Wallet implementation not ready. Returning no-op."
);
return () => {
};
}
return impl.onWalletConnectionChange((currentImplStatus, prevImplStatus) => {
const currentStatus = {
isConnected: currentImplStatus.isConnected,
address: currentImplStatus.address,
chainId: currentImplStatus.chainId,
walletId: currentImplStatus.walletId
};
const previousStatus = {
isConnected: prevImplStatus.isConnected,
address: prevImplStatus.address,
chainId: prevImplStatus.chainId,
walletId: prevImplStatus.walletId
};
try {
callback(currentStatus, previousStatus);
} catch (error) {
import_contracts_ui_builder_utils17.logger.error("Error in Stellar connection status listener:", String(error));
}
});
}
async function signTransaction(xdr11, address) {
const impl = await getStellarWalletImplementation();
return impl.signTransaction(xdr11, address);
}
// src/transaction/relayer.ts
var RelayerExecutionStrategy = class {
async execute(transactionData, executionConfig, networkConfig, onStatusChange, runtimeApiKey) {
const relayerConfig = executionConfig;
if (!runtimeApiKey) {
throw new Error("API Key is required for Relayer execution.");
}
const { transactionId } = await this.sendTransactionViaRelayer(
transactionData,
relayerConfig,
networkConfig,
runtimeApiKey
);
onStatusChange("pendingRelayer", { transactionId });
const sdkConfig = new import_relayer_sdk.Configuration({
basePath: relayerConfig.serviceUrl,
accessToken: runtimeApiKey
});
const txHash = await this.pollForTransactionHash(
relayerConfig.relayer.relayerId,
transactionId,
sdkConfig
);
return { txHash };
}
/**
* Fetches and filters relayers for Stellar networks from the OpenZeppelin Relayer service.
* This function handles pagination to retrieve all available relayers.
*
* @param serviceUrl The base URL of the relayer service.
* @param accessToken The session-based API key for authentication.
* @param networkConfig The Stellar network configuration to filter relayers by.
* @returns A promise that resolves to an array of compatible relayer details.
* @throws If the API call fails or returns an unsuccessful response.
*/
async getStellarRelayers(serviceUrl, accessToken, networkConfig) {
import_contracts_ui_builder_utils18.logger.info(
"[StellarRelayer] Getting relayers with access token",
accessToken.slice(0, 5).padEnd(accessToken.length, "*")
);
const sdkConfig = new import_relayer_sdk.Configuration({
basePath: serviceUrl,
accessToken
});
const relayersApi = new import_relayer_sdk.RelayersApi(sdkConfig);
let allRelayers = [];
let currentPage = 1;
let totalItems = 0;
let hasMore = true;
do {
const { data } = await relayersApi.listRelayers(currentPage, 100);
if (!data.success || !data.data) {
throw new Error(`Failed to fetch relayers on page ${currentPage}.`);
}
allRelayers = [...allRelayers, ...data.data];
totalItems = data.pagination?.total_items || 0;
if (allRelayers.length >= totalItems) {
hasMore = false;
} else {
currentPage++;
}
} while (hasMore);
return allRelayers.filter(
(r) => r.network_type === "stellar" && networkConfig.id.includes(r.network)
).map((r) => ({
relayerId: r.id,
name: r.name,
address: r.address || "",
network: r.network,
paused: r.paused || false
}));
}
/**
* Fetches comprehensive information about a specific Stellar relayer including balance and status.
* This function combines multiple SDK API calls to provide rich relayer details.
*
* @param serviceUrl The base URL of the relayer service.
* @param accessToken The session-based API key for authentication.
* @param relayerId The unique identifier of the relayer.
* @param networkConfig The Stellar network configuration for context.
* @returns A promise that resolves to enhanced relayer details including balance and status.
* @throws If any API call fails or returns an unsuccessful response.
*/
async getStellarRelayer(serviceUrl, accessToken, relayerId, _networkConfig) {
import_contracts_ui_builder_utils18.logger.info("[StellarRelayer] Getting detailed relayer info", relayerId);
const sdkConfig = new import_relayer_sdk.Configuration({
basePath: serviceUrl,
accessToken
});
const relayersApi = new import_relayer_sdk.RelayersApi(sdkConfig);
try {
const [relayerResponse, balanceResponse, statusResponse] = await Promise.all([
relayersApi.getRelayer(relayerId),
relayersApi.getRelayerBalance(relayerId).catch((err) => {
import_contracts_ui_builder_utils18.logger.warn("[StellarRelayer] Failed to fetch balance", err);
return null;
}),
relayersApi.getRelayerStatus(relayerId).catch((err) => {
import_contracts_ui_builder_utils18.logger.warn("[StellarRelayer] Failed to fetch status", err);
return null;
})
]);
if (!relayerResponse.data.success || !relayerResponse.data.data) {
throw new Error(`Failed to fetch relayer details for ID: ${relayerId}`);
}
const relayerData = relayerResponse.data.data;
const enhancedDetails = {
relayerId: relayerData.id,
name: relayerData.name,
address: relayerData.address || "",
network: relayerData.network,
paused: relayerData.paused || false,
systemDisabled: relayerData.system_disabled || false
};
if (balanceResponse?.data?.success && balanceResponse.data.data?.balance) {
try {
const balanceInStroops = Number(balanceResponse.data.data.balance);
const balanceInXlm = balanceInStroops / 1e7;
enhancedDetails.balance = `${balanceInXlm.toFixed(7)} XLM`;
} catch (error) {
import_contracts_ui_builder_utils18.logger.warn("[StellarRelayer] Failed to format balance, using raw value", String(error));
enhancedDetails.balance = String(balanceResponse.data.data.balance);
}
}
if (statusResponse?.data?.success && statusResponse.data.data) {
const statusData = statusResponse.data.data;
if (statusData.network_type === "stellar") {
const stellarStatusData = statusData;
if (stellarStatusData.sequence_number !== void 0 && stellarStatusData.sequence_number !== null) {
enhancedDetails.nonce = String(stellarStatusData.sequence_number);
}
if (stellarStatusData.pending_transactions_count !== void 0) {
enhancedDetails.pendingTransactionsCount = stellarStatusData.pending_transactions_count;
}
if (stellarStatusData.last_confirmed_transaction_timestamp) {
enhancedDetails.lastConfirmedTransactionTimestamp = stellarStatusData.last_confirmed_transaction_timestamp;
}
}
}
import_contracts_ui_builder_utils18.logger.info(
"[StellarRelayer] Retrieved enhanced relayer details",
JSON.stringify(enhancedDetails)
);
return enhancedDetails;
} catch (error) {
import_contracts_ui_builder_utils18.logger.error(
"[StellarRelayer] Failed to get relayer details",
error instanceof Error ? error.message : String(error)
);
throw error;
}
}
/**
* Submits a Stellar transaction to the relayer service for asynchronous processing.
* @param transactionData The Stellar contract transaction data.
* @param executionConfig The relayer-specific execution configuration.
* @param networkConfig The Stellar network configuration.
* @param runtimeApiKey The user's session-only API key.
* @returns A promise that resolves to an object containing the transaction ID assigned by the relayer.
*/
async sendTransactionViaRelayer(transactionData, executionConfig, _networkConfig, runtimeApiKey) {
const stellarOptions = executionConfig.transactionOptions;
let relayerTxRequest;
if (stellarOptions?.feeBump) {
const signedInnerXdr = await this.buildSignedInnerTransactionXdr(
transactionData,
_networkConfig,
stellarOptions
);
relayerTxRequest = {
network: executionConfig.relayer.network,
transaction_xdr: signedInnerXdr,
fee_bump: true,
...stellarOptions?.maxFee !== void 0 && { max_fee: stellarOptions.maxFee },
...stellarOptions?.validUntil !== void 0 && { valid_until: stellarOptions.validUntil }
};
} else {
relayerTxRequest = {
network: executionConfig.relayer.network,
// Use relayer's network (e.g., 'testnet', 'mainnet')
source_account: executionConfig.relayer.address,
// Use relayer's address as source account
operations: [
{
type: "invoke_contract",
contract_address: transactionData.contractAddress,
function_name: transactionData.functionName,
args: this.convertArgsToScVal(transactionData)
// No auth field needed - using source_account at top level
}
],
// Include optional parameters if provided
...stellarOptions?.maxFee !== void 0 && { max_fee: stellarOptions.maxFee },
...stellarOptions?.validUntil !== void 0 && { valid_until: stellarOptions.validUntil }
// Note: fee_bump is not supported by the relayer service in operations mode
// Memos are not supported for Soroban contract operations
};
}
const sdkConfig = new import_relayer_sdk.Configuration({
basePath: executionConfig.serviceUrl,
accessToken: runtimeApiKey
});
const relayersApi = new import_relayer_sdk.RelayersApi(sdkConfig);
const result = await relayersApi.sendTransaction(
executionConfig.relayer.relayerId,
relayerTxRequest
);
if (!result.data.success || !result.data.data?.id) {
throw new Error(`Relayer API failed to return a transaction ID. Error: ${result.data.error}`);
}
return { transactionId: result.data.data.id };
}
/**
* Converts Stellar transaction arguments to ScVal format for the relayer.
* Uses the same comprehensive conversion utility as the EOA execution strategy.
*/
convertArgsToScVal(transactionData) {
return transactionData.args.map((arg, index) => {
const argType = transactionData.argTypes[index];
const argSchema = transactionData.argSchema?.[index];
const scVal = valueToScVal(arg, argType, argSchema);
return this.stellarScValToRelayerScVal(scVal);
});
}
/**
* Build and sign the inner transaction using the connected wallet.
* Returns the signed inner transaction XDR to be wrapped by the relayer as a fee bump.
*/
async buildSignedInnerTransactionXdr(txData, stellarConfig, _options) {
const rpcServer = this.getSorobanRpcServer(stellarConfig);
const connectedAddress = this.getConnectedWalletAddress();
const accountResponse = await rpcServer.getAccount(connectedAddress);
const sourceAccount = new import_stellar_sdk10.Account(connectedAddress, accountResponse.sequenceNumber());
const contract2 = new import_stellar_sdk10.Contract(txData.contractAddress);
const transactionBuilder = new import_stellar_sdk10.TransactionBuilder(sourceAccount, {
fee: import_stellar_sdk10.BASE_FEE,
networkPassphrase: stellarConfig.networkPassphrase
});
const scValArgs = txData.args.map((arg, index) => {
const argType = txData.argTypes[index];
const argSchema = txData.argSchema?.[index];
return valueToScVal(arg, argType, argSchema);
});
transactionBuilder.addOperation(contract2.call(txData.functionName, ...scValArgs));
transactionBuilder.setTimeout(30);
let transaction = transactionBuilder.build();
const simulation = await rpcServer.simulateTransaction(transaction);
if (import_stellar_sdk10.rpc.Api.isSimulationError(simulation)) {
throw new Error(`Transaction simulation failed: ${simulation.error}`);
}
transaction = await rpcServer.prepareTransaction(transaction);
const signResult = await signTransaction(transaction.toXDR(), connectedAddress);
const signedTx = import_stellar_sdk10.TransactionBuilder.fromXDR(
signResult.signedTxXdr,
stellarConfig.networkPassphrase
);
if ("memo" in signedTx && "sequence" in signedTx) {
return signedTx.toXDR();
}
throw new Error("Unexpected transaction type returned from signing");
}
/**
* Get Soroban RPC Server instance with current configuration and user overrides.
*/
getSorobanRpcServer(networkConfig) {
const rpcUrl = networkConfig.sorobanRpcUrl;
if (!rpcUrl) {
throw new Error(`No Soroban RPC URL available for network ${networkConfig.name}`);
}
const allowHttp = new URL(rpcUrl).hostname === "localhost";
return new import_stellar_sdk10.rpc.Server(rpcUrl, { allowHttp });
}
getConnectedWalletAddress() {
const connectionStatus = getStellarWalletConnectionStatus();
if (!connectionStatus.isConnected || !connectionStatus.address) {
throw new Error("No connected wallet found. Please connect your Stellar wallet first.");
}
return connectionStatus.address;
}
/**
* Converts a Stellar SDK ScVal to the relayer SDK ScVal format.
* The relayer SDK uses a simplified ScVal representation compared to Stellar SDK's XDR types.
*/
stellarScValToRelayerScVal(stellarScVal) {
const scValType = stellarScVal.switch();
switch (scValType.name) {
case "scvBool":
return { bool: stellarScVal.b() };
case "scvVoid":
return { bool: false };
// Fallback for void
case "scvU32":
return { u32: stellarScVal.u32() };
case "scvI32":
return { i32: stellarScVal.i32() };
case "scvU64":
return { u64: stellarScVal.u64().toString() };
case "scvI64":
return { i64: stellarScVal.i64().toString() };
case "scvU128": {
const u128Parts = stellarScVal.u128();
return {
u128: {
hi: u128Parts.hi().toString(),
lo: u128Parts.lo().toString()
}
};
}
case "scvI128": {
const i128Parts = stellarScVal.i128();
return {
i128: {
hi: i128Parts.hi().toString(),
lo: i128Parts.lo().toString()
}
};
}
case "scvU256": {
const u256Parts = stellarScVal.u256();
return {
u256: {
hi_hi: u256Parts.hiHi().toString(),
hi_lo: u256Parts.hiLo().toString(),
lo_hi: u256Parts.loHi().toString(),
lo_lo: u256Parts.loLo().toString()
}
};
}
case "scvI256": {
const i256Parts = stellarScVal.i256();
return {
i256: {
hi_hi: i256Parts.hiHi().toString(),
hi_lo: i256Parts.hiLo().toString(),
lo_hi: i256Parts.loHi().toString(),
lo_lo: i256Parts.loLo().toString()
}
};
}
case "scvBytes":
return { bytes: stellarScVal.bytes().toString("hex") };
case "scvString":
return { string: stellarScVal.str().toString() };
case "scvSymbol":
return { symbol: stellarScVal.sym().toString() };
case "scvVec":
return {
vec: stellarScVal.vec()?.map((val) => this.stellarScValToRelayerScVal(val)) || []
};
case "scvMap": {
const mapEntries = stellarScVal.map() || [];
return {
map: mapEntries.map((entry) => ({
key: this.stellarScValToRelayerScVal(entry.key()),
val: this.stellarScValToRelayerScVal(entry.val())
}))
};
}
case "scvAddress":
return { address: stellarScVal.address().toString() };
default:
return { string: stellarScVal.toString() };
}
}
/**
* Polls the relayer for a Stellar transaction's status until it is confirmed and has a hash, or fails.
* @param relayerId The ID of the relayer processing the transaction.
* @param transactionId The ID of the transaction to poll.
* @param sdkConfig The SDK configuration containing the necessary authentication.
* @returns A promise that resolves to the final transaction hash.
* @throws If the transaction fails or polling times out.
*/
async pollForTransactionHash(relayerId, transactionId, sdkConfig) {
const relayersApi = new import_relayer_sdk.RelayersApi(sdkConfig);
const POLLING_INTERVAL = 2e3;
const POLLING_TIMEOUT = 3e5;
const startTime = Date.now();
while (Date.now() - startTime < POLLING_TIMEOUT) {
const { data } = await relayersApi.getTransactionById(relayerId, transactionId);
if (!data.success || !data.data) {
throw new Error(`Failed to get transaction status for ID: ${transactionId}`);
}
const txResponse = data.data;
if (txResponse.status === "mined" || txResponse.status === "confirmed") {
if (!txResponse.hash) {
throw new Error(
`Transaction is confirmed but no hash was returned for ID: ${transactionId}`
);
}
return txResponse.hash;
}
if (txResponse.status === "failed" || txResponse.status === "canceled" || txResponse.status === "expired") {
throw new Error(`Transaction ${txResponse.status}`);
}
await new Promise((resolve) => setTimeout(resolve, POLLING_INTERVAL));
}
throw new Error(`Polling for transaction hash timed out for ID: ${transactionId}`);
}
};
// src/configuration/execution.ts
var import_contracts_ui_builder_utils19 = require("@openzeppelin/contracts-ui-builder-utils");
var SYSTEM_LOG_TAG7 = "adapter-stellar-execution-config";
async function getStellarSupportedExecutionMethods() {
import_contracts_ui_builder_utils19.logger.warn(
"adapter-stellar-execution-config",
"getStellarSupportedExecutionMethods is using placeholder implementation."
);
return Promise.resolve([
{
type: "eoa",
name: "EOA (External Account)",
description: "Execute using a standard Stellar account address."
},
{
type: "relayer",
name: "OpenZeppelin Relayer",
description: "Execute via a OpenZeppelin open source transaction relayer service.",
disabled: false
},
{
type: "multisig",
name: "Stellar Multisig",
// Example for future
description: "Execute via a Stellar multisignature configuration.",
disabled: true
}
]);
}
async function _validateMultisigConfig(_config, _walletStatus) {
import_contracts_ui_builder_utils19.logger.info(SYSTEM_LOG_TAG7, "Multisig execution config validation: Not yet fully implemented.");
return true;
}
async function validateStellarExecutionConfig(config, walletStatus) {
import_contracts_ui_builder_utils19.logger.info(SYSTEM_LOG_TAG7, "Validating Stellar execution config:", { config, walletStatus });
switch (config.method) {
case "eoa":
return validateEoaConfig(config, walletStatus);
case "relayer":
return validateRelayerConfig(config);
case "multisig":
return _validateMultisigConfig(config, walletStatus);
default: {
const unknownMethod = config.method;
import_contracts_ui_builder_utils19.logger.warn(
SYSTEM_LOG_TAG7,
`Unsupported execution method type encountered: ${unknownMethod}`
);
return `Unsupported execution method type: ${unknownMethod}`;
}
}
}
// src/configuration/rpc.ts
var import_contracts_ui_builder_utils20 = require("@openzeppelin/contracts-ui-builder-utils");
function validateStellarRpcEndpoint(rpcConfig) {
try {
if (!(0, import_contracts_ui_builder_utils20.isValidUrl)(rpcConfig.url)) {
import_contracts_ui_builder_utils20.logger.error("validateStellarRpcEndpoint", `Invalid RPC URL format: ${rpcConfig.url}`);
return false;
}
return true;
} catch (error) {
import_contracts_ui_builder_utils20.logger.error("validateStellarRpcEndpoint", "Error validating RPC endpoint:", error);
return false;
}
}
async function testStellarRpcConnection(rpcConfig, timeoutMs = 5e3) {
if (!rpcConfig.url) {
return { success: false, error: "Soroban RPC URL is required" };
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
try {
const startTime = Date.now();
const response = await fetch(rpcConfig.url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getHealth"
}),
signal: controller.signal
});
if (!response.ok) {
return { success: false, error: `HTTP error: ${response.status}` };
}
const data = await response.json();
const latency = Date.now() - startTime;
if (data.error) {
return {
success: false,
error: `Soroban RPC error: ${data.error.message || "Unknown RPC error"}`
};
}
if (!data.result) {
return await testWithFallbackMethod(rpcConfig, controller.signal, startTime);
}
const healthStatus = data.result.status;
if (healthStatus && healthStatus !== "healthy") {
return {
success: false,
error: `Soroban RPC service unhealthy: ${healthStatus}`,
latency
};
}
return { success: true, latency };
} catch (error) {
import_contracts_ui_builder_utils20.logger.error("testStellarRpcConnection", "Connection test failed:", error);
if (error instanceof Error && error.name === "AbortError") {
return {
success: false,
error: `Connection timeout after ${timeoutMs}ms`
};
}
try {
return await testWithFallbackMethod(rpcConfig, controller.signal, Date.now());
} catch {
return {
success: false,
error: error instanceof Error ? error.message : "Connection failed"
};
}
} finally {
clearTimeout(timeoutId);
}
}
async function testWithFallbackMethod(rpcConfig, signal, startTime) {
const response = await fetch(rpcConfig.url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getLatestLedger"
}),
signal
});
if (!response.ok) {
return { success: false, error: `HTTP error: ${response.status}` };
}
const data = await response.json();
const latency = Date.now() - startTime;
if (data.error) {
return {
success: false,
error: `Soroban RPC error: ${data.error.message || "Unknown RPC error"}`
};
}
if (data.result && data.result.sequence) {
return { success: true, latency };
}
return {
success: false,
error: "Unexpected response format from Soroban RPC endpoint"
};
}
// src/mapping/constants.ts
var STELLAR_TYPE_TO_FIELD_TYPE = {
// Address types
Address: "blockchain-address",
MuxedAddress: "blockchain-address",
// String types
ScString: "text",
ScSymbol: "text",
// Numeric types - unsigned integers
U32: "number",
U64: "number",
U128: "number",
U256: "number",
// Numeric types - signed integers
I32: "number",
I64: "number",
I128: "number",
I256: "number",
// Boolean type
Bool: "checkbox",
// Byte types
Bytes: "bytes",
DataUrl: "bytes",
// Collection types
Vec: "array",
Map: "map",
// Complex types
Tuple: "object",
Enum: "select",
// Instance types (for compatibility)
Instance: "object"
};
// src/mapping/type-mapper.ts
function mapStellarParameterTypeToFieldType(parameterType) {
const vecComplexMatch = parameterType.match(/^Vec<([^>]+)>$/);
if (vecComplexMatch) {
const innerType = vecComplexMatch[1];
if (!STELLAR_TYPE_TO_FIELD_TYPE[innerType]) {
return "array-object";
}
return "array";
}
if (parameterType === "Vec" || parameterType.startsWith("Vec<")) {
return "array";
}
if (parameterType === "Map" || parameterType.startsWith("Map<")) {
return "map";
}
const genericMatch = parameterType.match(/^(\w+)<(.+)>$/);
if (genericMatch) {
const baseType = genericMatch[1];
if (baseType === "Option" || baseType === "Result") {
const innerType = genericMatch[2];
return mapStellarParameterTypeToFieldType(innerType);
}
}
const mappedType = STELLAR_TYPE_TO_FIELD_TYPE[parameterType];
if (mappedType) {
return mappedType;
}
if (parameterType.startsWith("BytesN<")) {
return "textarea";
}
if (isLikelyEnumType(parameterType)) {
return "select";
}
if (parameterType[0] && parameterType[0] === parameterType[0].toUpperCase()) {
const knownUppercaseTypes = [
"U32",
"U64",
"U128",
"U256",
"I32",
"I64",
"I128",
"I256",
"Bool",
"Bytes"
];
if (!knownUppercaseTypes.includes(parameterType) && !parameterType.startsWith("Vec") && !parameterType.startsWith("Map") && !parameterType.includes("Unknown")) {
return "object";
}
}
return "text";
}
function getStellarCompatibleFieldTypes(parameterType) {
const vecComplexMatch = parameterType.match(/^Vec<([^>]+)>$/);
if (vecComplexMatch) {
const innerType = vecComplexMatch[1];
if (!STELLAR_TYPE_TO_FIELD_TYPE[innerType]) {
return ["array-object", "textarea", "text"];
}
return ["array", "textarea", "text"];
}
if (parameterType === "Vec" || parameterType.startsWith("Vec<")) {
return ["array", "textarea", "text"];
}
if (parameterType === "Map" || parameterType.startsWith("Map<")) {
return ["map", "textarea", "text"];
}
const genericMatch = parameterType.match(/^(\w+)<(.+)>$/);
if (genericMatch) {
const baseType = genericMatch[1];
if (baseType === "Option" || baseType === "Result") {
const innerType = genericMatch[2];
return getStellarCompatibleFieldTypes(innerType);
}
}
const compatibilityMap = {
Address: ["blockchain-address", "text"],
// Unsigned integers
U32: ["number", "amount", "text"],
U64: ["number", "amount", "text"],
U128: ["number", "amount", "text"],
U256: ["number", "amount", "text"],
// Signed integers
I32: ["number", "amount", "text"],
I64: ["number", "amount", "text"],
I128: ["number", "amount", "text"],
I256: ["number", "amount", "text"],
// Boolean
Bool: ["checkbox", "select", "radio", "text"],
// String types
ScString: ["text", "textarea", "email", "password"],
ScSymbol: ["text", "textarea"],
// Byte types
Bytes: ["bytes", "textarea", "text"],
DataUrl: ["bytes", "textarea", "text"],
// BytesN types like BytesN<32> for hashes
"BytesN<32>": ["bytes", "textarea", "text"],
// Complex types
Tuple: ["object", "textarea", "text"],
Instance: ["object", "textarea", "text"]
};
const compatibleTypes = compatibilityMap[parameterType];
if (compatibleTypes) {
return compatibleTypes;
}
if (isLikelyEnumType(parameterType)) {
return ["enum", "select", "radio", "text"];
}
if (parameterType[0] && parameterType[0] === parameterType[0].toUpperCase()) {
const knownUppercaseTypes = [
"U32",
"U64",
"U128",
"U256",
"I32",
"I64",
"I128",
"I256",
"Bool",
"Bytes"
];
if (!knownUppercaseTypes.includes(parameterType) && !parameterType.startsWith("Vec") && !parameterType.startsWith("Map") && !parameterType.includes("Unknown")) {
return ["object", "textarea", "text"];
}
}
return ["text"];
}
// src/mapping/field-generator.ts
var import_lodash = require("lodash");
var import_contracts_ui_builder_utils22 = require("@openzeppelin/contracts-ui-builder-utils");
// src/mapping/enum-metadata.ts
var import_stellar_sdk11 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils21 = require("@openzeppelin/contracts-ui-builder-utils");
function extractEnumVariants(entries, enumName) {
try {
const entry = entries.find((e) => {
try {
return e.value().name().toString() === enumName;
} catch {
return false;
}
});
if (!entry) {
return null;
}
const entryKind = entry.switch();
if (entryKind.value === import_stellar_sdk11.xdr.ScSpecEntryKind.scSpecEntryUdtUnionV0().value) {
const unionUdt = entry.udtUnionV0();
const cases = unionUdt.cases();
const variants = [];
let isUnitOnly = true;
for (const caseEntry of cases) {
const caseKind = caseEntry.switch();
if (caseKind.value === import_stellar_sdk11.xdr.ScSpecUdtUnionCaseV0Kind.scSpecUdtUnionCaseVoidV0().value) {
const voidCase = caseEntry.voidCase();
variants.push({
name: voidCase.name().toString(),
type: "void"
});
} else if (caseKind.value === import_stellar_sdk11.xdr.ScSpecUdtUnionCaseV0Kind.scSpecUdtUnionCaseTupleV0().value) {
const tupleCase = caseEntry.tupleCase();
const payloadTypes = tupleCase.type().map((typeDef) => extractSorobanTypeFromScSpec(typeDef));
variants.push({
name: tupleCase.name().toString(),
type: "tuple",
payloadTypes
});
isUnitOnly = false;
}
}
return {
name: enumName,
variants,
isUnitOnly
};
}
if (entryKind.value === import_stellar_sdk11.xdr.ScSpecEntryKind.scSpecEntryUdtEnumV0().value) {
const enumUdt = entry.udtEnumV0();
const cases = enumUdt.cases();
const variants = [];
for (const caseEntry of cases) {
variants.push({
name: caseEntry.name().toString(),
type: "integer",
value: caseEntry.value()
});
}
return {
name: enumName,
variants,
isUnitOnly: true
// Integer enums are considered unit-only for UI purposes
};
}
return null;
} catch (error) {
import_contracts_ui_builder_utils21.logger.error("extractEnumVariants", `Failed to extract enum variants for ${enumName}:`, error);
return null;
}
}
function isEnumType(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 isEnum = entryKind.value === import_stellar_sdk11.xdr.ScSpecEntryKind.scSpecEntryUdtUnionV0().value || entryKind.value === import_stellar_sdk11.xdr.ScSpecEntryKind.scSpecEntryUdtEnumV0().value;
return isEnum;
} catch (error) {
import_contracts_ui_builder_utils21.logger.error("isEnumType", `Failed to check if ${typeName} is enum:`, error);
return false;
}
}
// src/mapping/field-generator.ts
function getDefaultValidationForType() {
return { required: true };
}
function generateStellarDefaultField(parameter, contractSchema) {
const specEntries = contractSchema?.metadata?.specEntries;
const fieldType = mapStellarParameterTypeToFieldType(parameter.type);
if (parameter.type === "unknown") {
import_contracts_ui_builder_utils22.logger.warn(
"adapter-stellar",
`[generateStellarDefaultField] Parameter "${parameter.name}" has type "unknown"`
);
}
let enumMetadata = null;
let finalFieldType = fieldType;
let options;
if (isLikelyEnumType(parameter.type)) {
if (specEntries && isEnumType(specEntries, parameter.type)) {
enumMetadata = extractEnumVariants(specEntries, parameter.type);
if (enumMetadata) {
if (enumMetadata.isUnitOnly) {
finalFieldType = "select";
options = enumMetadata.variants.map((variant) => ({
label: variant.name,
value: variant.type === "integer" ? variant.value.toString() : variant.name
}));
} else {
finalFieldType = "enum";
}
}
} else {
finalFieldType = "enum";
enumMetadata = {
name: parameter.type,
variants: [],
// Empty variants will trigger fallback UI
isUnitOnly: false
};
}
}
const baseField = {
id: `field-${Math.random().toString(36).substring(2, 9)}`,
name: parameter.name || parameter.type,
// Use type if name missing
label: (0, import_lodash.startCase)(parameter.displayName || parameter.name || parameter.type),
type: finalFieldType,
placeholder: enumMetadata ? `Select ${parameter.displayName || parameter.name || parameter.type}` : `Enter ${parameter.displayName || parameter.name || parameter.type}`,
helperText: parameter.description || "",
defaultValue: (0, import_contracts_ui_builder_utils22.getDefaultValueForType)(finalFieldType),
validation: getDefaultValidationForType(),
width: "full",
options
};
if (fieldType === "array") {
const elementType = extractVecElementType(parameter.type);
if (elementType) {
const elementFieldType = mapStellarParameterTypeToFieldType(elementType);
const arrayField = {
...baseField,
elementType: elementFieldType,
elementFieldConfig: {
type: elementFieldType,
validation: { required: true },
placeholder: `Enter ${elementType}`
}
};
return arrayField;
}
}
if (fieldType === "map") {
const mapTypes = extractMapTypes(parameter.type);
if (mapTypes) {
const keyFieldType = mapStellarParameterTypeToFieldType(mapTypes.keyType);
const valueFieldType = mapStellarParameterTypeToFieldType(mapTypes.valueType);
const mapField = {
...baseField,
mapMetadata: {
keyType: keyFieldType,
valueType: valueFieldType,
keyFieldConfig: {
type: keyFieldType,
validation: { required: true },
placeholder: `Enter ${mapTypes.keyType}`,
originalParameterType: mapTypes.keyType
},
valueFieldConfig: {
type: valueFieldType,
validation: { required: true },
placeholder: `Enter ${mapTypes.valueType}`,
originalParameterType: mapTypes.valueType
}
},
validation: {
...getDefaultValidationForType(),
min: 0
// No max limit - users can add as many map entries as needed
}
};
return mapField;
}
}
if (parameter.components && (fieldType === "object" || fieldType === "array-object")) {
const result = {
...baseField,
components: parameter.components
};
return result;
}
if (enumMetadata) {
const result = {
...baseField,
enumMetadata
};
return result;
}
return baseField;
}
// src/transaction/formatter.ts
var import_stellar_sdk12 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_types4 = require("@openzeppelin/contracts-ui-builder-types");
var import_contracts_ui_builder_utils23 = require("@openzeppelin/contracts-ui-builder-utils");
function formatStellarTransactionData(contractSchema, functionId, submittedInputs, fields) {
import_contracts_ui_builder_utils23.logger.info(
"formatStellarTransactionData",
`Formatting Stellar transaction data for function: ${functionId}`
);
const functionDetails = contractSchema.functions.find((fn) => fn.id === functionId);
if (!functionDetails) {
throw new Error(`Function definition for ${functionId} not found in provided contract schema.`);
}
const expectedArgs = functionDetails.inputs;
const orderedRawValues = [];
for (const expectedArg of expectedArgs) {
const fieldConfig = fields.find((field) => field.name === expectedArg.name);
if (!fieldConfig) {
throw new Error(`Configuration missing for argument: ${expectedArg.name} in provided fields`);
}
let value;
if (fieldConfig.isHardcoded) {
if (fieldConfig.hardcodedValue === void 0 && fieldConfig.name in submittedInputs) {
import_contracts_ui_builder_utils23.logger.warn(
"formatStellarTransactionData",
`Field '${fieldConfig.name}' is hardcoded with undefined value but has submitted input. Using submitted input instead.`
);
value = submittedInputs[fieldConfig.name];
} else {
value = fieldConfig.hardcodedValue;
}
} else if (fieldConfig.isHidden) {
throw new Error(`Field '${fieldConfig.name}' cannot be hidden without being hardcoded.`);
} else {
if (!(fieldConfig.name in submittedInputs)) {
throw new Error(`Missing submitted input for required field: ${fieldConfig.name}`);
}
value = submittedInputs[fieldConfig.name];
}
orderedRawValues.push(value);
}
const transformedArgs = expectedArgs.map((param, index) => {
let valueToParse = orderedRawValues[index];
if ((0, import_contracts_ui_builder_types4.isEnumValue)(valueToParse)) {
const specEntries = contractSchema.metadata?.specEntries;
if (specEntries && isEnumType(specEntries, param.type)) {
const enumMetadata = extractEnumVariants(specEntries, param.type);
const enumValue = valueToParse;
if (enumMetadata && enumValue.values) {
const selectedVariant = enumMetadata.variants.find((v) => v.name === enumValue.tag);
if (selectedVariant && selectedVariant.payloadTypes) {
const processedValues = enumValue.values.map(
(rawValue, payloadIndex) => {
const expectedType = selectedVariant.payloadTypes[payloadIndex];
if (expectedType) {
const processedValue = parseStellarInput(rawValue, expectedType);
return {
type: expectedType,
value: processedValue
};
}
return rawValue;
}
);
valueToParse = { ...enumValue, values: processedValues };
}
}
}
}
if (typeof param.type === "string" && param.type.startsWith("Vec<") && Array.isArray(valueToParse)) {
return parseStellarInput(valueToParse, param.type);
}
return parseStellarInput(valueToParse, param.type);
});
if (!contractSchema.address) {
throw new Error("Contract address is missing or invalid in the provided schema.");
}
try {
import_stellar_sdk12.Address.fromString(contractSchema.address);
} catch {
throw new Error("Contract address is missing or invalid in the provided schema.");
}
const stellarTransactionData = {
contractAddress: contractSchema.address,
functionName: functionDetails.name,
args: transformedArgs,
argTypes: functionDetails.inputs.map((param) => param.type),
// Include parameter types for ScVal conversion
argSchema: functionDetails.inputs,
// Include full parameter schema with struct field definitions
transactionOptions: {
// Add any Stellar-specific transaction options here
// For example: fee, timeout, memo, etc.
}
};
import_contracts_ui_builder_utils23.logger.debug(
"formatStellarTransactionData",
"Formatted transaction data:",
stellarTransactionData
);
return stellarTransactionData;
}
// src/transaction/sender.ts
var import_stellar_sdk14 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils25 = require("@openzeppelin/contracts-ui-builder-utils");
// src/transaction/eoa.ts
var import_stellar_sdk13 = require("@stellar/stellar-sdk");
var import_contracts_ui_builder_utils24 = require("@openzeppelin/contracts-ui-builder-utils");
var SYSTEM_LOG_TAG8 = "EoaExecutionStrategy";
function getSorobanRpcServer2(networkConfig) {
const customRpcConfig = import_contracts_ui_builder_utils24.userRpcConfigService.getUserRpcConfig(networkConfig.id);
const rpcUrl = customRpcConfig?.url || networkConfig.sorobanRpcUrl;
if (!rpcUrl) {
throw new Error(`No Soroban RPC URL available for network ${networkConfig.name}`);
}
const allowHttp = new URL(rpcUrl).hostname === "localhost";
return new import_stellar_sdk13.rpc.Server(rpcUrl, {
allowHttp
});
}
var EoaExecutionStrategy = class {
async execute(transactionData, executionConfig, networkConfig, onStatusChange, _runtimeApiKey) {
import_contracts_ui_builder_utils24.logger.info(SYSTEM_LOG_TAG8, "Using Stellar EOA execution strategy");
if (executionConfig.method !== "eoa") {
throw new Error(`Expected EOA execution config, got: ${executionConfig.method}`);
}
return this.executeEoaTransaction(transactionData, networkConfig, onStatusChange);
}
async executeEoaTransaction(txData, stellarConfig, onStatusChange) {
try {
const rpcServer = getSorobanRpcServer2(stellarConfig);
const connectedAddress = this.getConnectedWalletAddress();
import_contracts_ui_builder_utils24.logger.info(SYSTEM_LOG_TAG8, `Connected address: ${connectedAddress}`);
let sourceAccount;
try {
const accountResponse = await rpcServer.getAccount(connectedAddress);
sourceAccount = new import_stellar_sdk13.Account(connectedAddress, accountResponse.sequenceNumber());
} catch (error) {
throw new Error(`Failed to load account details: ${error.message}`);
}
const contract2 = new import_stellar_sdk13.Contract(txData.contractAddress);
const transactionBuilder = new import_stellar_sdk13.TransactionBuilder(sourceAccount, {
fee: import_stellar_sdk13.BASE_FEE,
networkPassphrase: stellarConfig.networkPassphrase
});
const scValArgs = txData.args.map((arg, index) => {
const argType = txData.argTypes[index];
const argSchema = txData.argSchema?.[index];
return valueToScVal(arg, argType, argSchema);
});
transactionBuilder.addOperation(contract2.call(txData.functionName, ...scValArgs));
transactionBuilder.setTimeout(30);
let transaction = transactionBuilder.build();
try {
const simulation = await rpcServer.simulateTransaction(transaction);
if (import_stellar_sdk13.rpc.Api.isSimulationError(simulation)) {
throw new Error(`Transaction simulation failed: ${simulation.error}`);
}
transaction = await rpcServer.prepareTransaction(transaction);
} catch (error) {
throw new Error(`Transaction simulation/preparation failed: ${error.message}`);
}
onStatusChange("pendingSignature", {});
try {
const signResult = await signTransaction(transaction.toXDR(), connectedAddress);
const signedTx = import_stellar_sdk13.TransactionBuilder.fromXDR(
signResult.signedTxXdr,
stellarConfig.networkPassphrase
);
if ("memo" in signedTx && "sequence" in signedTx) {
transaction = signedTx;
} else {
throw new Error("Unexpected transaction type returned from signing");
}
} catch (error) {
if (error.message.includes("User declined")) {
throw new Error("Transaction was rejected by user");
}
throw new Error(`Failed to sign transaction: ${error.message}`);
}
onStatusChange("pendingConfirmation", {});
let sendResult;
try {
sendResult = await rpcServer.sendTransaction(transaction);
} catch (error) {
throw new Error(`Failed to broadcast transaction: ${error.message}`);
}
if (sendResult.status !== "PENDING") {
throw new Error(`Transaction failed to submit: ${sendResult.status}`);
}
const txHash = sendResult.hash;
import_contracts_ui_builder_utils24.logger.info(SYSTEM_LOG_TAG8, `Transaction submitted successfully: ${txHash}`);
try {
let txResponse;
const MAX_ATTEMPTS = 10;
let attempts = 0;
while (attempts++ < MAX_ATTEMPTS && txResponse?.status !== "SUCCESS") {
await new Promise((resolve) => setTimeout(resolve, 1e3));
txResponse = await rpcServer.getTransaction(txHash);
switch (txResponse.status) {
case "FAILED":
throw new Error(`Transaction failed: ${JSON.stringify(txResponse.resultXdr)}`);
case "NOT_FOUND":
continue;
case "SUCCESS":
break;
default:
}
}
if (attempts >= MAX_ATTEMPTS || txResponse?.status !== "SUCCESS") {
import_contracts_ui_builder_utils24.logger.warn(SYSTEM_LOG_TAG8, `Transaction confirmation timeout for ${txHash}`);
}
} catch (confirmError) {
import_contracts_ui_builder_utils24.logger.error(SYSTEM_LOG_TAG8, "Error waiting for confirmation:", confirmError);
}
onStatusChange("success", {
txHash
});
return { txHash };
} catch (error) {
const errorMessage = `Failed to execute Stellar EOA transaction: ${error.message}`;
import_contracts_ui_builder_utils24.logger.error(SYSTEM_LOG_TAG8, errorMessage, error);
onStatusChange("error", {});
throw new Error(errorMessage);
}
}
getConnectedWalletAddress() {
const connectionStatus = getStellarWalletConnectionStatus();
if (!connectionStatus.isConnected || !connectionStatus.address) {
throw new Error("No connected wallet found. Please connect your Stellar wallet first.");
}
return connectionStatus.address;
}
};
// src/transaction/sender.ts
var SYSTEM_LOG_TAG9 = "adapter-stellar";
async function signAndBroadcastStellarTransaction(transactionData, executionConfig, networkConfig, onStatusChange, runtimeApiKey) {
import_contracts_ui_builder_utils25.logger.info(
SYSTEM_LOG_TAG9,
"Stellar signAndBroadcast called with executionConfig:",
executionConfig
);
if (!networkConfig || networkConfig.ecosystem !== "stellar") {
throw new Error("Invalid Stellar network configuration provided.");
}
const txData = transactionData;
let strategy;
switch (executionConfig.method) {
case "eoa":
strategy = new EoaExecutionStrategy();
break;
case "relayer":
strategy = new RelayerExecutionStrategy();
break;
case "multisig":
throw new Error("Multisig execution method not yet implemented for Stellar.");
default: {
const exhaustiveCheck = executionConfig;
import_contracts_ui_builder_utils25.logger.error(SYSTEM_LOG_TAG9, `Unsupported execution method encountered: ${exhaustiveCheck}`);
throw new Error(`Unsupported execution method: ${exhaustiveCheck}`);
}
}
return strategy.execute(
txData,
executionConfig,
networkConfig,
onStatusChange || (() => {
}),
runtimeApiKey
);
}
// src/wallet/components/StellarWalletUiRoot.tsx
var import_react5 = require("react");
var import_contracts_ui_builder_utils26 = require("@openzeppelin/contracts-ui-builder-utils");
// src/wallet/context/StellarWalletContext.ts
var import_react4 = require("react");
var StellarWalletContext = (0, import_react4.createContext)(void 0);
// src/wallet/components/StellarWalletUiRoot.tsx
var import_jsx_runtime6 = require("react/jsx-runtime");
function StellarWalletUiRoot({ children, uiKitConfig }) {
const [uiKitManagerState, setUiKitManagerState] = (0, import_react5.useState)(
stellarUiKitManager.getState()
);
const [address, setAddress] = (0, import_react5.useState)(null);
const [isConnecting, setIsConnecting] = (0, import_react5.useState)(false);
const [availableWallets, setAvailableWallets] = (0, import_react5.useState)([]);
(0, import_react5.useEffect)(() => {
const currentState = stellarUiKitManager.getState();
if (uiKitConfig || !currentState.currentFullUiKitConfig) {
const configToUse = uiKitConfig || { kitName: "custom", kitConfig: {} };
import_contracts_ui_builder_utils26.logger.debug("StellarWalletUiRoot", "Configuring UI kit with:", configToUse);
stellarUiKitManager.configure(configToUse).catch((error) => {
import_contracts_ui_builder_utils26.logger.error("Failed to configure Stellar UI kit:", error);
});
}
}, [uiKitConfig]);
(0, import_react5.useEffect)(() => {
const unsubscribe = stellarUiKitManager.subscribe(() => {
setUiKitManagerState(stellarUiKitManager.getState());
});
return unsubscribe;
}, []);
(0, import_react5.useEffect)(() => {
const unsubscribeFromConnectionChanges = onStellarWalletConnectionChange(
(currentStatus, _previousStatus) => {
setAddress(currentStatus.address || null);
import_contracts_ui_builder_utils26.logger.debug(
"StellarWalletUiRoot",
`Connection status changed: ${currentStatus.isConnected ? "connected" : "disconnected"}`,
currentStatus.address
);
}
);
const initialStatus = getStellarWalletConnectionStatus();
setAddress(initialStatus.address || null);
return () => {
unsubscribeFromConnectionChanges();
};
}, [address]);
(0, import_react5.useEffect)(() => {
const loadWallets = async () => {
try {
const connectors = await getStellarAvailableConnectors();
setAvailableWallets(connectors);
} catch (error) {
import_contracts_ui_builder_utils26.logger.error("Failed to load available wallets:", String(error));
}
};
if (!uiKitManagerState.isInitializing && uiKitManagerState.stellarKitProvider) {
loadWallets();
}
}, [uiKitManagerState.isInitializing, uiKitManagerState.stellarKitProvider]);
const connect = (0, import_react5.useCallback)(async (walletId) => {
setIsConnecting(true);
try {
const result = await connectStellarWallet(walletId);
if (result.connected && result.address) {
setAddress(result.address);
} else {
throw new Error(result.error || "Failed to connect wallet");
}
} catch (error) {
import_contracts_ui_builder_utils26.logger.error("Failed to connect:", String(error));
throw error;
} finally {
setIsConnecting(false);
}
}, []);
const disconnect = (0, import_react5.useCallback)(async () => {
try {
const result = await disconnectStellarWallet();
if (result.disconnected) {
setAddress(null);
} else {
throw new Error(result.error || "Failed to disconnect wallet");
}
} catch (error) {
import_contracts_ui_builder_utils26.logger.error("Failed to disconnect:", String(error));
throw error;
}
}, []);
const contextValue = {
address,
isConnected: address !== null,
isConnecting,
availableWallets,
connect,
disconnect,
uiKitManagerState,
kit: uiKitManagerState.stellarKitProvider
};
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StellarWalletContext.Provider, { value: contextValue, children });
}
// src/wallet/context/useStellarWalletContext.ts
var import_react6 = require("react");
function useStellarWalletContext() {
const context = (0, import_react6.useContext)(StellarWalletContext);
if (context === void 0) {
throw new Error("useStellarWalletContext must be used within a StellarWalletUiRoot");
}
return context;
}
// src/wallet/hooks/useStellarAccount.ts
function useStellarAccount() {
const { address, isConnected, isConnecting } = useStellarWalletContext();
return {
address,
isConnected,
isConnecting
};
}
// src/wallet/hooks/useStellarConnect.ts
var import_react7 = require("react");
function useStellarConnect() {
const { connect, isConnecting, availableWallets } = useStellarWalletContext();
const [error, setError] = (0, import_react7.useState)(null);
const connectFunction = (0, import_react7.useCallback)(
async ({ connector }) => {
try {
setError(null);
await connect(connector.id);
} catch (err) {
const connectError = err instanceof Error ? err : new Error(String(err));
setError(connectError);
throw connectError;
}
},
[connect]
);
const connectors = availableWallets.map((wallet) => ({
id: wallet.id,
name: wallet.name,
icon: wallet.icon,
installed: wallet.isAvailable,
type: wallet.type || "browser"
}));
return {
connect: connectFunction,
connectors,
isLoading: isConnecting,
isPending: isConnecting,
error
};
}
// src/wallet/hooks/useStellarDisconnect.ts
var import_react8 = require("react");
function useStellarDisconnect() {
const { disconnect } = useStellarWalletContext();
const [isDisconnecting, setIsDisconnecting] = (0, import_react8.useState)(false);
const [error, setError] = (0, import_react8.useState)(null);
const disconnectFunction = (0, import_react8.useCallback)(async () => {
try {
setError(null);
setIsDisconnecting(true);
await disconnect();
} catch (err) {
const disconnectError = err instanceof Error ? err : new Error(String(err));
setError(disconnectError);
throw disconnectError;
} finally {
setIsDisconnecting(false);
}
}, [disconnect]);
return {
disconnect: disconnectFunction,
isLoading: isDisconnecting,
isPending: isDisconnecting,
error
};
}
// src/wallet/hooks/facade-hooks.ts
var stellarFacadeHooks = {
// Account management
useAccount: useStellarAccount,
// Connection management
useConnect: useStellarConnect,
useDisconnect: useStellarDisconnect,
// Stellar doesn't have the same network switching capabilities as EVM
// These are included for interface compatibility but may not be fully functional
useSwitchChain: () => ({ switchChain: void 0 }),
useChainId: () => "stellar",
useChains: () => [],
// Transaction and signing hooks - to be implemented as needed
useBalance: () => ({ data: void 0, isLoading: false }),
useSendTransaction: () => ({ sendTransaction: void 0 }),
useWaitForTransactionReceipt: () => ({ data: void 0 }),
useSignMessage: () => ({ signMessage: void 0 }),
useSignTypedData: () => ({ signTypedData: void 0 })
};
// src/wallet/hooks/useUiKitConfig.ts
var import_contracts_ui_builder_utils27 = require("@openzeppelin/contracts-ui-builder-utils");
var defaultConfig = {
kitName: "custom",
// Default to using our custom implementation for Stellar
kitConfig: {}
};
function loadInitialConfigFromAppService() {
import_contracts_ui_builder_utils27.logger.debug(
"stellar:useUiKitConfig",
"Attempting to load initial config from AppConfigService..."
);
const configObj = import_contracts_ui_builder_utils27.appConfigService.getWalletUIConfig("stellar");
if (configObj && configObj.kitName) {
import_contracts_ui_builder_utils27.logger.info(
"stellar:useUiKitConfig",
`Loaded initial config from AppConfigService: kitName=${configObj.kitName}`,
configObj.kitConfig
);
return {
kitName: configObj.kitName,
kitConfig: { ...defaultConfig.kitConfig, ...configObj.kitConfig || {} }
};
}
import_contracts_ui_builder_utils27.logger.debug(
"stellar:useUiKitConfig",
"No initial config found in AppConfigService, using module default."
);
return { ...defaultConfig };
}
// src/wallet/components/connect/ConnectButton.tsx
var import_lucide_react2 = require("lucide-react");
var import_react10 = require("react");
var import_contracts_ui_builder_ui6 = require("@openzeppelin/contracts-ui-builder-ui");
var import_contracts_ui_builder_utils29 = require("@openzeppelin/contracts-ui-builder-utils");
// src/wallet/components/connect/ConnectorDialog.tsx
var import_react9 = require("react");
var import_contracts_ui_builder_ui5 = require("@openzeppelin/contracts-ui-builder-ui");
var import_contracts_ui_builder_utils28 = require("@openzeppelin/contracts-ui-builder-utils");
var import_jsx_runtime7 = require("react/jsx-runtime");
var ConnectorDialog = ({ open, onOpenChange }) => {
const { connect } = useStellarConnect();
const { isConnected, isConnecting } = useStellarAccount();
const [connectingId, setConnectingId] = (0, import_react9.useState)(null);
const [error, setError] = (0, import_react9.useState)(null);
const [connectors, setConnectors] = (0, import_react9.useState)([]);
const [loadingConnectors, setLoadingConnectors] = (0, import_react9.useState)(true);
(0, import_react9.useEffect)(() => {
const loadConnectors = async () => {
try {
const availableConnectors = await getStellarAvailableConnectors();
setConnectors(availableConnectors);
} catch (err) {
import_contracts_ui_builder_utils28.logger.error("Failed to load Stellar connectors:", String(err));
setError("Failed to load available wallets");
} finally {
setLoadingConnectors(false);
}
};
if (open) {
loadConnectors();
}
}, [open]);
(0, import_react9.useEffect)(() => {
if (isConnected && connectingId) {
onOpenChange(false);
setConnectingId(null);
setError(null);
}
}, [isConnected, connectingId, onOpenChange]);
if (!connect) {
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_contracts_ui_builder_ui5.Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_contracts_ui_builder_ui5.DialogContent, { className: "sm:max-w-[425px]", children: [
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_contracts_ui_builder_ui5.DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_contracts_ui_builder_ui5.DialogTitle, { children: "Error" }) }),
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "Wallet connection function is not available." })
] }) });
}
const handleConnectorSelect = async (selectedConnector) => {
setConnectingId(selectedConnector.id);
setError(null);
try {
await connect({ connector: selectedConnector });
} catch (err) {
setError(err instanceof Error ? err.message : "Failed to connect");
setConnectingId(null);
}
};
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_contracts_ui_builder_ui5.Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_contracts_ui_builder_ui5.DialogContent, { className: "sm:max-w-[425px]", children: [
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_contracts_ui_builder_ui5.DialogHeader, { children: [
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_contracts_ui_builder_ui5.DialogTitle, { children: "Connect Wallet" }),
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_contracts_ui_builder_ui5.DialogDescription, { children: "Select a wallet provider to connect with this application." })
] }),
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "grid gap-4 py-4", children: loadingConnectors ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-center text-muted-foreground", children: "Loading available wallets..." }) : connectors.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-center text-muted-foreground", children: "No wallet connectors available." }) : connectors.map((connector) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
import_contracts_ui_builder_ui5.Button,
{
onClick: () => handleConnectorSelect(connector),
disabled: isConnecting && connectingId === connector.id,
variant: "outline",
className: "flex justify-between items-center w-full py-6",
children: [
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: connector.name }),
isConnecting && connectingId === connector.id && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ml-2 text-xs", children: "Connecting..." })
]
},
connector.id
)) }),
error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-sm text-red-500 mt-1", children: error })
] }) });
};
// src/wallet/components/connect/ConnectButton.tsx
var import_jsx_runtime8 = require("react/jsx-runtime");
var CustomConnectButton = ({
className,
hideWhenConnected = true
}) => {
const [dialogOpen, setDialogOpen] = (0, import_react10.useState)(false);
const { isConnected, isConnecting } = useStellarAccount();
const [isManuallyInitiated, setIsManuallyInitiated] = (0, import_react10.useState)(false);
(0, import_react10.useEffect)(() => {
if (isConnected && hideWhenConnected) {
setDialogOpen(false);
setIsManuallyInitiated(false);
}
}, [isConnected, hideWhenConnected]);
(0, import_react10.useEffect)(() => {
if (!dialogOpen) {
setIsManuallyInitiated(false);
}
}, [dialogOpen]);
(0, import_react10.useEffect)(() => {
if (isConnecting) {
setIsManuallyInitiated(false);
}
}, [isConnecting]);
const handleConnectClick = () => {
if (!isConnected) {
setIsManuallyInitiated(true);
setDialogOpen(true);
}
};
if (isConnected && hideWhenConnected) {
return null;
}
const showButtonLoading = isConnecting || isManuallyInitiated;
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: (0, import_contracts_ui_builder_utils29.cn)("flex items-center", className), children: [
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
import_contracts_ui_builder_ui6.Button,
{
onClick: handleConnectClick,
disabled: showButtonLoading || isConnected,
variant: "outline",
size: "sm",
className: "h-8 px-2 text-xs",
title: isConnected ? "Connected" : "Connect Wallet",
children: [
showButtonLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Loader2, { className: "size-3.5 animate-spin mr-1" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Wallet, { className: "size-3.5 mr-1" }),
showButtonLoading ? "Connecting..." : "Connect Wallet"
]
}
),
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
ConnectorDialog,
{
open: dialogOpen,
onOpenChange: (open) => {
setDialogOpen(open);
if (!open) {
setIsManuallyInitiated(false);
}
}
}
)
] });
};
// src/wallet/components/account/AccountDisplay.tsx
var import_lucide_react3 = require("lucide-react");
var import_contracts_ui_builder_ui7 = require("@openzeppelin/contracts-ui-builder-ui");
var import_contracts_ui_builder_utils30 = require("@openzeppelin/contracts-ui-builder-utils");
var import_jsx_runtime9 = require("react/jsx-runtime");
var CustomAccountDisplay = ({ className }) => {
const { isConnected, address } = useStellarAccount();
const { disconnect } = useStellarDisconnect();
if (!isConnected || !address || !disconnect) {
return null;
}
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: (0, import_contracts_ui_builder_utils30.cn)("flex items-center gap-2", className), children: [
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col", children: [
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs font-medium", children: (0, import_contracts_ui_builder_utils30.truncateMiddle)(address, 4, 4) }),
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[9px] text-muted-foreground -mt-0.5", children: "Stellar Account" })
] }),
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
import_contracts_ui_builder_ui7.Button,
{
onClick: () => disconnect(),
variant: "ghost",
size: "icon",
className: "size-6 p-0",
title: "Disconnect wallet",
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.LogOut, { className: "size-3.5" })
}
)
] });
};
// src/wallet/utils/filterWalletComponents.ts
var import_contracts_ui_builder_types5 = require("@openzeppelin/contracts-ui-builder-types");
var import_contracts_ui_builder_utils31 = require("@openzeppelin/contracts-ui-builder-utils");
function filterWalletComponents(allPossibleComponents, exclusions, kitName = "custom") {
import_contracts_ui_builder_utils31.logger.debug(
"filterWalletComponents",
`Filtering components for kit: ${kitName}. Exclusions: ${exclusions.join(", ")}.`
);
if (!allPossibleComponents || Object.keys(allPossibleComponents).length === 0) {
import_contracts_ui_builder_utils31.logger.debug("filterWalletComponents", `No components provided to filter for kit: ${kitName}.`);
return void 0;
}
if (exclusions.length === 0) {
import_contracts_ui_builder_utils31.logger.debug(
"filterWalletComponents",
`Providing all components for kit: ${kitName}.`,
allPossibleComponents
);
return allPossibleComponents;
}
const filteredComponents = {};
let componentCount = 0;
for (const key in allPossibleComponents) {
const componentKey = key;
if (!exclusions.includes(componentKey)) {
if (allPossibleComponents[componentKey]) {
filteredComponents[componentKey] = allPossibleComponents[componentKey];
componentCount++;
}
}
}
if (componentCount > 0) {
import_contracts_ui_builder_utils31.logger.debug(
"filterWalletComponents",
`Providing filtered components for kit: ${kitName} after exclusions (${exclusions.join(", ")}).`,
filteredComponents
);
return filteredComponents;
}
import_contracts_ui_builder_utils31.logger.debug("filterWalletComponents", `All components were excluded for kit: ${kitName}.`);
return void 0;
}
function getComponentExclusionsFromConfig(kitConfig) {
if (kitConfig && typeof kitConfig === "object" && "components" in kitConfig) {
const componentsCfg = kitConfig.components;
if (componentsCfg && typeof componentsCfg === "object" && "exclude" in componentsCfg && Array.isArray(componentsCfg.exclude)) {
return componentsCfg.exclude.filter(
(key) => typeof key === "string" && import_contracts_ui_builder_types5.ECOSYSTEM_WALLET_COMPONENT_KEYS.includes(key)
);
}
}
return [];
}
// src/wallet/utils/uiKitService.ts
var import_contracts_ui_builder_utils32 = require("@openzeppelin/contracts-ui-builder-utils");
function getResolvedWalletComponents(uiKitConfiguration) {
import_contracts_ui_builder_utils32.logger.debug(
"stellar:uiKitService:getResolvedWalletComponents",
"Received uiKitConfiguration:",
JSON.stringify(uiKitConfiguration)
);
const currentKitName = uiKitConfiguration.kitName || "custom";
if (currentKitName === "none") {
import_contracts_ui_builder_utils32.logger.info(
"stellar:uiKitService",
'UI Kit set to "none" for getResolvedWalletComponents, not providing wallet components.'
);
return void 0;
}
const exclusions = getComponentExclusionsFromConfig(uiKitConfiguration.kitConfig);
import_contracts_ui_builder_utils32.logger.debug(
"stellar:uiKitService",
`Extracted component exclusions for ${currentKitName}: ${exclusions.join(", ") || "none"}.`
);
if (currentKitName === "custom") {
const allCustomComponents = {
ConnectButton: CustomConnectButton,
AccountDisplay: CustomAccountDisplay
// NetworkSwitcher is not included as Stellar doesn't support network switching
};
import_contracts_ui_builder_utils32.logger.info(
"stellar:uiKitService",
`Providing custom Stellar wallet components for kit: ${currentKitName}`
);
return filterWalletComponents(allCustomComponents, exclusions, currentKitName);
}
if (currentKitName === "stellar-wallets-kit") {
const stellarKitComponents = {
ConnectButton: StellarWalletsKitConnectButton,
// The kit's native button handles account display internally
AccountDisplay: void 0
};
import_contracts_ui_builder_utils32.logger.info("stellar:uiKitService", "Using Stellar Wallets Kit native button");
return stellarKitComponents;
}
import_contracts_ui_builder_utils32.logger.warn(
"stellar:uiKitService",
`UI Kit "${currentKitName}" for getResolvedWalletComponents not explicitly supported. No components provided.`
);
return void 0;
}
// src/wallet/services/configResolutionService.ts
var import_contracts_ui_builder_utils33 = require("@openzeppelin/contracts-ui-builder-utils");
async function resolveFullUiKitConfiguration(programmaticOverrides, initialAppServiceKitName, currentAppServiceConfig, options) {
import_contracts_ui_builder_utils33.logger.debug(
"stellar:configResolutionService:resolveFullUiKitConfiguration",
"Starting resolution with:",
{
programmaticOverrides,
initialAppServiceKitName,
currentAppServiceConfig,
hasLoadNativeCallback: !!options?.loadUiKitNativeConfig
}
);
if (options?.loadUiKitNativeConfig) {
import_contracts_ui_builder_utils33.logger.debug(
"stellar:configResolutionService",
"Native config loader provided but not currently supported for Stellar adapter"
);
}
const effectiveKitName = programmaticOverrides.kitName || currentAppServiceConfig.kitName || initialAppServiceKitName || "custom";
const finalFullConfig = {
kitName: effectiveKitName,
kitConfig: {
...currentAppServiceConfig.kitConfig || {},
...programmaticOverrides.kitConfig || {}
}
};
import_contracts_ui_builder_utils33.logger.debug(
"stellar:configResolutionService:resolveFullUiKitConfiguration",
"Resolved finalFullConfig:",
finalFullConfig
);
return finalFullConfig;
}
// src/adapter.ts
var StellarAdapter = class {
constructor(networkConfig) {
__publicField(this, "networkConfig");
__publicField(this, "initialAppServiceKitName");
if (!(0, import_contracts_ui_builder_types6.isStellarNetworkConfig)(networkConfig)) {
throw new Error("StellarAdapter requires a valid Stellar network configuration.");
}
this.networkConfig = networkConfig;
stellarUiKitManager.setNetworkConfig(networkConfig);
getStellarWalletImplementation(networkConfig).catch((error) => {
import_contracts_ui_builder_utils34.logger.error(
"StellarAdapter:constructor",
"Failed to initialize wallet implementation:",
error
);
});
const initialGlobalConfig = loadInitialConfigFromAppService();
this.initialAppServiceKitName = initialGlobalConfig.kitName || "custom";
import_contracts_ui_builder_utils34.logger.info(
"StellarAdapter:constructor",
"Initial kitName from AppConfigService noted:",
this.initialAppServiceKitName
);
import_contracts_ui_builder_utils34.logger.info(
"StellarAdapter",
`Adapter initialized for network: ${networkConfig.name} (ID: ${networkConfig.id})`
);
}
// --- Contract Loading --- //
/**
* NOTE about artifact inputs (single input with auto-detection):
*
* The Builder renders the contract definition step using whatever fields the
* adapter returns here. EVM uses one optional ABI field; Midnight provides
* multiple fields. Stellar should use a single input approach with automatic
* content detection when we add manual-spec support:
*
* - Keep `contractAddress` (required)
* - Add optional `contractDefinition` (type: `code-editor`, language: `json`)
* with file upload support for both JSON and Wasm binary content
*
* When this field is added:
* - Extend `validateAndConvertStellarArtifacts(...)` to accept
* `{ contractAddress, contractDefinition? }`
* - In the loader, branch: if `contractDefinition` provided, auto-detect
* content type (JSON vs Wasm using magic bytes `\0asm`):
* - For JSON: Parse and validate as Soroban spec, use `transformStellarSpecToSchema`
* - For Wasm: Extract embedded spec from binary, parse locally (no RPC)
* - Set `source: 'manual'` with `contractDefinitionOriginal` to the raw
* user-provided content. This ensures auto-save captures and restores the
* manual contract definition exactly like the EVM/Midnight flows.
* - Provide clear UI hints about supported formats (JSON spec or Wasm binary).
*/
getContractDefinitionInputs() {
return [
{
id: "contractAddress",
name: "contractAddress",
label: "Contract ID",
type: "blockchain-address",
validation: { required: true },
placeholder: "C...",
helperText: "Enter the Stellar contract ID (C...)."
}
];
}
/**
* @inheritdoc
*/
async loadContract(source) {
const artifacts = validateAndConvertStellarArtifacts(source);
const result = await loadStellarContract(artifacts, this.networkConfig);
return result.schema;
}
/**
* @inheritdoc
*/
async loadContractWithMetadata(source) {
try {
const artifacts = validateAndConvertStellarArtifacts(source);
const result = await loadStellarContractWithMetadata(artifacts, this.networkConfig);
return {
schema: result.schema,
source: result.source,
contractDefinitionOriginal: result.contractDefinitionOriginal,
metadata: result.metadata
};
} catch (error) {
throw error;
}
}
getWritableFunctions(contractSchema) {
return getStellarWritableFunctions(contractSchema);
}
// --- Type Mapping & Field Generation --- //
mapParameterTypeToFieldType(parameterType) {
return mapStellarParameterTypeToFieldType(parameterType);
}
getCompatibleFieldTypes(parameterType) {
return getStellarCompatibleFieldTypes(parameterType);
}
generateDefaultField(parameter, contractSchema) {
return generateStellarDefaultField(parameter, contractSchema);
}
// --- Transaction Formatting & Execution --- //
formatTransactionData(contractSchema, functionId, submittedInputs, fields) {
return formatStellarTransactionData(contractSchema, functionId, submittedInputs, fields);
}
async signAndBroadcast(transactionData, executionConfig, onStatusChange, runtimeApiKey) {
return signAndBroadcastStellarTransaction(
transactionData,
executionConfig,
this.networkConfig,
onStatusChange,
runtimeApiKey
);
}
// NOTE: waitForTransactionConfirmation? is optional in the interface.
// Since the imported function is currently undefined, we omit the method here.
// If implemented in ./transaction/sender.ts later, add the method back:
// async waitForTransactionConfirmation?(...) { ... }
// --- View Function Querying --- //
isViewFunction(functionDetails) {
return isStellarViewFunction(functionDetails);
}
// Implement queryViewFunction with the correct signature from ContractAdapter
async queryViewFunction(contractAddress, functionId, params = [], contractSchema) {
return queryStellarViewFunction(
contractAddress,
functionId,
this.networkConfig,
params,
contractSchema,
(address) => this.loadContract({ contractAddress: address })
);
}
formatFunctionResult(decodedValue, functionDetails) {
return formatStellarFunctionResult(decodedValue, functionDetails);
}
// --- Wallet Interaction --- //
supportsWalletConnection() {
return supportsStellarWalletConnection();
}
async getAvailableConnectors() {
return getStellarAvailableConnectors();
}
async connectWallet(connectorId) {
return connectStellarWallet(connectorId);
}
async disconnectWallet() {
return disconnectStellarWallet();
}
getWalletConnectionStatus() {
const impl = getInitializedStellarWalletImplementation();
if (!impl) {
return {
isConnected: false,
address: void 0,
chainId: stellarUiKitManager.getState().networkConfig?.id || "stellar-testnet"
};
}
const stellarStatus = impl.getWalletConnectionStatus();
return stellarStatus;
}
/**
* @inheritdoc
*/
onWalletConnectionChange(callback) {
const walletImplementation = getInitializedStellarWalletImplementation();
if (!walletImplementation) {
import_contracts_ui_builder_utils34.logger.warn(
"StellarAdapter:onWalletConnectionChange",
"Wallet implementation not ready. Subscription may not work."
);
return () => {
};
}
return walletImplementation.onWalletConnectionChange(
(currentImplStatus, previousImplStatus) => {
callback(currentImplStatus, previousImplStatus);
}
);
}
// --- Configuration & Metadata --- //
async getSupportedExecutionMethods() {
return getStellarSupportedExecutionMethods();
}
async validateExecutionConfig(config) {
const walletStatus = this.getWalletConnectionStatus();
return validateStellarExecutionConfig(config, walletStatus);
}
// Implement getExplorerUrl with the correct signature from ContractAdapter
getExplorerUrl(address) {
return getStellarExplorerAddressUrl(address, this.networkConfig);
}
// Implement getExplorerTxUrl with the correct signature from ContractAdapter
getExplorerTxUrl(txHash) {
if (getStellarExplorerTxUrl) {
return getStellarExplorerTxUrl(txHash, this.networkConfig);
}
return null;
}
// --- Validation --- //
isValidAddress(address, addressType) {
return isValidAddress(address, addressType);
}
async getAvailableUiKits() {
return [
{
id: "custom",
name: "Stellar Wallets Kit Custom",
configFields: []
},
{
id: "stellar-wallets-kit",
name: "Stellar Wallets Kit",
configFields: []
}
];
}
/**
* @inheritdoc
*/
async configureUiKit(programmaticOverrides = {}, options) {
const currentAppServiceConfig = loadInitialConfigFromAppService();
const finalFullConfig = await resolveFullUiKitConfiguration(
programmaticOverrides,
this.initialAppServiceKitName,
currentAppServiceConfig,
options
);
await stellarUiKitManager.configure(finalFullConfig);
import_contracts_ui_builder_utils34.logger.info(
"StellarAdapter:configureUiKit",
"StellarUiKitManager configuration requested with final config:",
finalFullConfig
);
}
/**
* @inheritdoc
*/
async getExportableWalletConfigFiles(uiKitConfig) {
if (uiKitConfig?.kitName === "stellar-wallets-kit") {
return generateStellarWalletsKitExportables(uiKitConfig);
}
return {};
}
/**
* @inheritdoc
*/
getEcosystemWalletComponents() {
const currentManagerState = stellarUiKitManager.getState();
if (!currentManagerState.currentFullUiKitConfig) {
import_contracts_ui_builder_utils34.logger.debug(
"StellarAdapter:getEcosystemWalletComponents",
"No UI kit configuration available in manager yet. Returning undefined components."
);
return void 0;
}
const components = getResolvedWalletComponents(currentManagerState.currentFullUiKitConfig);
return components;
}
/**
* @inheritdoc
*/
getEcosystemReactUiContextProvider() {
import_contracts_ui_builder_utils34.logger.info(
"StellarAdapter:getEcosystemReactUiContextProvider",
"Returning StellarWalletUiRoot."
);
return StellarWalletUiRoot;
}
/**
* @inheritdoc
*/
getEcosystemReactHooks() {
return stellarFacadeHooks;
}
async getRelayers(serviceUrl, accessToken) {
const relayerStrategy = new RelayerExecutionStrategy();
try {
return await relayerStrategy.getStellarRelayers(serviceUrl, accessToken, this.networkConfig);
} catch (error) {
import_contracts_ui_builder_utils34.logger.error("StellarAdapter", "Failed to fetch Stellar relayers:", error);
return Promise.resolve([]);
}
}
async getRelayer(serviceUrl, accessToken, relayerId) {
const relayerStrategy = new RelayerExecutionStrategy();
try {
return await relayerStrategy.getStellarRelayer(
serviceUrl,
accessToken,
relayerId,
this.networkConfig
);
} catch (error) {
import_contracts_ui_builder_utils34.logger.error("StellarAdapter", "Failed to fetch Stellar relayer details:", error);
return Promise.resolve({});
}
}
/**
* Returns a React component for configuring Stellar-specific relayer transaction options.
* @returns The Stellar relayer options component
*/
getRelayerOptionsComponent() {
return StellarRelayerOptions;
}
/**
* @inheritdoc
*/
async validateRpcEndpoint(rpcConfig) {
return validateStellarRpcEndpoint(rpcConfig);
}
/**
* @inheritdoc
*/
async testRpcConnection(rpcConfig) {
return testStellarRpcConnection(rpcConfig);
}
/**
* @inheritdoc
*/
getUiLabels() {
return {
relayerConfigTitle: "Transaction Configuration",
relayerConfigActiveDesc: "Customize transaction parameters for submission",
relayerConfigInactiveDesc: "Using recommended transaction configuration for reliability",
relayerConfigPresetTitle: "Recommended Preset Active",
relayerConfigPresetDesc: "Transactions will use recommended parameters for quick inclusion",
relayerConfigCustomizeBtn: "Customize Settings",
detailsTitle: "Relayer Details",
network: "Network",
relayerId: "Relayer ID",
active: "Active",
paused: "Paused",
systemDisabled: "System Disabled",
balance: "Balance",
// For Stellar, sequence number is conceptually similar; adapters supply the value
nonce: "Sequence",
pending: "Pending Transactions",
lastTransaction: "Last Transaction"
};
}
};
// src/networks/mainnet.ts
var stellarPublic = {
id: "stellar-public",
exportConstName: "stellarPublic",
name: "Stellar",
ecosystem: "stellar",
network: "stellar",
type: "mainnet",
isTestnet: false,
horizonUrl: "https://horizon.stellar.org",
sorobanRpcUrl: "https://mainnet.sorobanrpc.com",
networkPassphrase: "Public Global Stellar Network ; September 2015",
explorerUrl: "https://stellar.expert/explorer/public",
icon: "stellar"
};
// src/networks/testnet.ts
var stellarTestnet = {
id: "stellar-testnet",
exportConstName: "stellarTestnet",
name: "Stellar Testnet",
ecosystem: "stellar",
network: "stellar",
type: "testnet",
isTestnet: true,
horizonUrl: "https://horizon-testnet.stellar.org",
sorobanRpcUrl: "https://soroban-testnet.stellar.org",
networkPassphrase: "Test SDF Network ; September 2015",
explorerUrl: "https://stellar.expert/explorer/testnet",
icon: "stellar"
};
// src/networks/index.ts
var stellarMainnetNetworks = [stellarPublic];
var stellarTestnetNetworks = [stellarTestnet];
var stellarNetworks = [
...stellarMainnetNetworks,
...stellarTestnetNetworks
];
// src/config.ts
var stellarAdapterConfig = {
/**
* Dependencies required by the Stellar adapter
* These will be included in exported projects that use this adapter
*/
dependencies: {
// Runtime dependencies
runtime: {
// Core Stellar libraries
"@stellar/stellar-sdk": "^14.1.1",
// Wallet connection and integration
"@creit.tech/stellar-wallets-kit": "^1.9.5",
// OpenZeppelin Relayer integration (optional, for gasless transactions)
"@openzeppelin/relayer-sdk": "1.1.0",
// React integration for wallet components
react: "^19.0.0",
"react-dom": "^19.0.0"
},
// Development dependencies
dev: {
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0"
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
StellarAdapter,
isStellarContractArtifacts,
stellarAdapterConfig,
stellarMainnetNetworks,
stellarNetworks,
stellarPublic,
stellarTestnet,
stellarTestnetNetworks
});
//# sourceMappingURL=index.cjs.map