@openzeppelin/ui-builder-adapter-stellar 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -443,10 +443,17 @@ function extractStructFields(entries, structName) {
443
443
  for (const field of fields) {
444
444
  const fieldName = field.name().toString();
445
445
  const fieldType = extractSorobanTypeFromScSpec(field.type());
446
- structFields.push({
446
+ const fieldParam = {
447
447
  name: fieldName,
448
448
  type: fieldType
449
- });
449
+ };
450
+ if (isStructType(entries, fieldType)) {
451
+ const nestedFields = extractStructFields(entries, fieldType);
452
+ if (nestedFields && nestedFields.length > 0) {
453
+ fieldParam.components = nestedFields;
454
+ }
455
+ }
456
+ structFields.push(fieldParam);
450
457
  }
451
458
  return structFields;
452
459
  }
@@ -496,7 +503,7 @@ import {
496
503
  import { logger as logger11, userRpcConfigService as userRpcConfigService2 } from "@openzeppelin/ui-builder-utils";
497
504
 
498
505
  // src/transform/parsers/index.ts
499
- import { isEnumValue as isEnumValue2 } from "@openzeppelin/ui-builder-types";
506
+ import { isEnumValue as isEnumValue3 } from "@openzeppelin/ui-builder-types";
500
507
  import { isPlainObject as isPlainObject2, logger as logger9 } from "@openzeppelin/ui-builder-utils";
501
508
 
502
509
  // src/transform/parsers/generic-parser.ts
@@ -739,6 +746,20 @@ function extractOptionElementType(parameterType) {
739
746
  }
740
747
  return extractGenericInnerType(parameterType, "Option");
741
748
  }
749
+ function extractTupleTypes(parameterType) {
750
+ if (!isValidTypeString(parameterType) || !parameterType.startsWith("Tuple<")) {
751
+ return null;
752
+ }
753
+ const innerContent = extractGenericInnerType(parameterType, "Tuple");
754
+ if (!innerContent) {
755
+ return null;
756
+ }
757
+ const parts = splitTopLevelTypes(innerContent);
758
+ if (parts.length === 0) {
759
+ return null;
760
+ }
761
+ return parts;
762
+ }
742
763
  function extractGenericInnerType(parameterType, genericName) {
743
764
  const prefix = `${genericName}<`;
744
765
  if (!parameterType.startsWith(prefix) || !parameterType.endsWith(">")) {
@@ -812,6 +833,30 @@ function hasInvalidCharacters(str) {
812
833
  }
813
834
  return !/^[A-Za-z0-9<>,\s_]+$/.test(str);
814
835
  }
836
+ function splitTopLevelTypes(content) {
837
+ const types = [];
838
+ let start = 0;
839
+ let level = 0;
840
+ for (let i = 0; i < content.length; i += 1) {
841
+ const char = content[i];
842
+ if (char === "<") {
843
+ level += 1;
844
+ } else if (char === ">") {
845
+ level -= 1;
846
+ } else if (char === "," && level === 0) {
847
+ const segment = content.slice(start, i).trim();
848
+ if (segment) {
849
+ types.push(segment);
850
+ }
851
+ start = i + 1;
852
+ }
853
+ }
854
+ const lastSegment = content.slice(start).trim();
855
+ if (lastSegment) {
856
+ types.push(lastSegment);
857
+ }
858
+ return types;
859
+ }
815
860
 
816
861
  // src/utils/formatting.ts
817
862
  function stringifyWithBigInt(value, space) {
@@ -886,6 +931,34 @@ function convertStellarTypeToScValType(stellarType) {
886
931
  // src/utils/input-parsing.ts
887
932
  import { nativeToScVal, xdr as xdr3 } from "@stellar/stellar-sdk";
888
933
  import { detectBytesEncoding as detectBytesEncoding2, logger as logger7, stringToBytes as stringToBytes2 } from "@openzeppelin/ui-builder-utils";
934
+
935
+ // src/utils/xdr-ordering.ts
936
+ function compareScValsByXdr(a, b) {
937
+ const aBytes = getBytes(a);
938
+ const bBytes = getBytes(b);
939
+ const minLength = Math.min(aBytes.length, bBytes.length);
940
+ for (let index = 0; index < minLength; index += 1) {
941
+ const diff = aBytes[index] - bBytes[index];
942
+ if (diff !== 0) {
943
+ return diff;
944
+ }
945
+ }
946
+ return aBytes.length - bBytes.length;
947
+ }
948
+ function getBytes(scVal) {
949
+ const xdrValue = scVal.toXDR();
950
+ if (xdrValue instanceof Uint8Array) {
951
+ return xdrValue;
952
+ }
953
+ const arrayLike = xdrValue;
954
+ const result = new Uint8Array(arrayLike.length);
955
+ for (let index = 0; index < arrayLike.length; index += 1) {
956
+ result[index] = arrayLike[index];
957
+ }
958
+ return result;
959
+ }
960
+
961
+ // src/utils/input-parsing.ts
889
962
  var SYSTEM_LOG_TAG4 = "StellarInputParsingUtils";
890
963
  function isMapArray(argValue) {
891
964
  try {
@@ -969,19 +1042,34 @@ function convertEnumToScVal(obj, scVals) {
969
1042
  }
970
1043
  function convertObjectToMap(mapArray) {
971
1044
  try {
972
- const mapVal = mapArray.reduce((acc, pair) => {
973
- const key = pair["0"].value;
1045
+ const sortedEntries = [...mapArray].sort((a, b) => {
1046
+ const aKey = getScValFromPrimitive(a["0"]);
1047
+ const bKey = getScValFromPrimitive(b["0"]);
1048
+ return compareScValsByXdr(aKey, bKey);
1049
+ });
1050
+ const mapVal = sortedEntries.reduce((acc, pair) => {
1051
+ const key = String(pair["0"].value);
974
1052
  if (Array.isArray(pair["1"])) {
975
1053
  const valueScVal = getScValFromArg(pair["1"], []);
976
1054
  acc[key] = valueScVal;
977
1055
  } else {
978
1056
  const value = pair["1"].value;
979
- acc[key] = pair["1"].type === "bool" ? value === "true" : value;
1057
+ if (pair["1"].type === "bool") {
1058
+ if (typeof value === "boolean") {
1059
+ acc[key] = value;
1060
+ } else if (typeof value === "string") {
1061
+ acc[key] = value === "true";
1062
+ } else {
1063
+ acc[key] = Boolean(value);
1064
+ }
1065
+ } else {
1066
+ acc[key] = value;
1067
+ }
980
1068
  }
981
1069
  return acc;
982
1070
  }, {});
983
- const mapType = mapArray.reduce((acc, pair) => {
984
- const key = pair["0"].value;
1071
+ const mapType = sortedEntries.reduce((acc, pair) => {
1072
+ const key = String(pair["0"].value);
985
1073
  const keyTypeHint = convertStellarTypeToScValType(pair["0"].type);
986
1074
  const valueTypeHint = convertStellarTypeToScValType(pair["1"].type);
987
1075
  acc[key] = [
@@ -998,13 +1086,44 @@ function convertObjectToMap(mapArray) {
998
1086
  }
999
1087
 
1000
1088
  // src/transform/parsers/scval-converter.ts
1001
- import { nativeToScVal as nativeToScVal4 } from "@stellar/stellar-sdk";
1002
- import { isEnumValue } from "@openzeppelin/ui-builder-types";
1089
+ import { nativeToScVal as nativeToScVal4, xdr as xdr6 } from "@stellar/stellar-sdk";
1090
+ import { isEnumValue as isEnumValue2 } from "@openzeppelin/ui-builder-types";
1091
+
1092
+ // src/utils/stellar-types.ts
1093
+ var PRIMITIVE_STELLAR_TYPES = /* @__PURE__ */ new Set([
1094
+ "Bool",
1095
+ "ScString",
1096
+ "ScSymbol",
1097
+ "Address",
1098
+ "Bytes",
1099
+ "U8",
1100
+ "U16",
1101
+ "U32",
1102
+ "U64",
1103
+ "U128",
1104
+ "U256",
1105
+ "I8",
1106
+ "I16",
1107
+ "I32",
1108
+ "I64",
1109
+ "I128",
1110
+ "I256"
1111
+ ]);
1112
+ function isPrimitiveParamType(type) {
1113
+ return PRIMITIVE_STELLAR_TYPES.has(type);
1114
+ }
1003
1115
 
1004
1116
  // src/transform/parsers/struct-parser.ts
1005
- import { nativeToScVal as nativeToScVal3 } from "@stellar/stellar-sdk";
1117
+ import { nativeToScVal as nativeToScVal3, xdr as xdr5 } from "@stellar/stellar-sdk";
1118
+ import { isEnumValue } from "@openzeppelin/ui-builder-types";
1006
1119
  import { isPlainObject, logger as logger8 } from "@openzeppelin/ui-builder-utils";
1007
1120
  var SYSTEM_LOG_TAG5 = "StructParser";
1121
+ function isTupleStructSchema(schema) {
1122
+ if (!schema?.components || schema.components.length === 0) {
1123
+ return false;
1124
+ }
1125
+ return schema.components.every((component, index) => component.name === index.toString());
1126
+ }
1008
1127
  function needsParsing(value, fieldType) {
1009
1128
  if ((fieldType === "Bytes" || fieldType.startsWith("BytesN<")) && value instanceof Uint8Array) {
1010
1129
  return false;
@@ -1029,7 +1148,23 @@ function needsParsing(value, fieldType) {
1029
1148
  }
1030
1149
  return false;
1031
1150
  }
1032
- function convertStructToScVal(structObj, parameterType, paramSchema, parseInnerValue) {
1151
+ function convertStructToScVal(structObj, parameterType, paramSchema, parseInnerValue, convertToScVal) {
1152
+ if (isTupleStructSchema(paramSchema) && paramSchema && convertToScVal) {
1153
+ const tupleValues = paramSchema.components.map((component, index) => {
1154
+ const key = component.name ?? index.toString();
1155
+ let elementValue = structObj[key];
1156
+ if (typeof elementValue === "undefined") {
1157
+ throw new Error(
1158
+ `Missing tuple value for "${key}" in struct type "${parameterType}". Received: ${JSON.stringify(structObj)}`
1159
+ );
1160
+ }
1161
+ if (typeof elementValue === "string" && isLikelyEnumType(component.type)) {
1162
+ elementValue = { tag: elementValue };
1163
+ }
1164
+ return convertToScVal(elementValue, component.type, component, parseInnerValue);
1165
+ });
1166
+ return xdr5.ScVal.scvVec(tupleValues);
1167
+ }
1033
1168
  const convertedValue = {};
1034
1169
  const typeHints = {};
1035
1170
  for (const [fieldName, fieldValue] of Object.entries(structObj)) {
@@ -1047,6 +1182,9 @@ function convertStructToScVal(structObj, parameterType, paramSchema, parseInnerV
1047
1182
  } else {
1048
1183
  parsedValue = fieldValue;
1049
1184
  }
1185
+ if (typeof parsedValue === "string" && isLikelyEnumType(fieldType)) {
1186
+ parsedValue = { tag: parsedValue };
1187
+ }
1050
1188
  if (fieldType.startsWith("Map<") && Array.isArray(parsedValue)) {
1051
1189
  const mapTypeMatch = fieldType.match(/Map<(.+),\s*(.+)>$/);
1052
1190
  const mapKeyType = mapTypeMatch ? mapTypeMatch[1] : "ScSymbol";
@@ -1068,10 +1206,21 @@ function convertStructToScVal(structObj, parameterType, paramSchema, parseInnerV
1068
1206
  convertedValue[fieldName] = mapObject;
1069
1207
  typeHints[fieldName] = ["symbol", mapTypeHints];
1070
1208
  } else {
1071
- convertedValue[fieldName] = parsedValue;
1072
- const scValType = convertStellarTypeToScValType(fieldType);
1073
- if (scValType !== "map-special") {
1074
- typeHints[fieldName] = ["symbol", Array.isArray(scValType) ? scValType[0] : scValType];
1209
+ if (convertToScVal && (fieldType.startsWith("Vec<") || isEnumValue(parsedValue))) {
1210
+ const fieldSchema = paramSchema?.components?.find((c) => c.name === fieldName);
1211
+ convertedValue[fieldName] = convertToScVal(
1212
+ parsedValue,
1213
+ fieldType,
1214
+ fieldSchema,
1215
+ parseInnerValue
1216
+ );
1217
+ typeHints[fieldName] = ["symbol", "scval"];
1218
+ } else {
1219
+ convertedValue[fieldName] = parsedValue;
1220
+ const scValType = convertStellarTypeToScValType(fieldType);
1221
+ if (scValType !== "map-special") {
1222
+ typeHints[fieldName] = ["symbol", Array.isArray(scValType) ? scValType[0] : scValType];
1223
+ }
1075
1224
  }
1076
1225
  }
1077
1226
  } else {
@@ -1085,7 +1234,40 @@ function convertStructToScVal(structObj, parameterType, paramSchema, parseInnerV
1085
1234
  convertedValue,
1086
1235
  typeHints
1087
1236
  });
1088
- const scVal = nativeToScVal3(convertedValue, { type: typeHints });
1237
+ const hasEnumFields = paramSchema?.components?.some((comp) => {
1238
+ const fieldValue = convertedValue[comp.name];
1239
+ return isEnumValue(fieldValue);
1240
+ });
1241
+ let scVal;
1242
+ if (hasEnumFields && convertToScVal && paramSchema?.components) {
1243
+ const mapEntries = [];
1244
+ for (const fieldSchema of paramSchema.components) {
1245
+ const fieldName = fieldSchema.name;
1246
+ const fieldValue = convertedValue[fieldName];
1247
+ const keyScVal = nativeToScVal3(fieldName, { type: "symbol" });
1248
+ let valueScVal;
1249
+ if (isEnumValue(fieldValue)) {
1250
+ valueScVal = convertToScVal(fieldValue, fieldSchema.type, fieldSchema, parseInnerValue);
1251
+ } else {
1252
+ const fieldTypeHint = typeHints[fieldName];
1253
+ if (fieldTypeHint && Array.isArray(fieldTypeHint) && fieldTypeHint.length > 1) {
1254
+ valueScVal = nativeToScVal3(fieldValue, { type: fieldTypeHint[1] });
1255
+ } else {
1256
+ valueScVal = nativeToScVal3(fieldValue);
1257
+ }
1258
+ }
1259
+ mapEntries.push(
1260
+ new xdr5.ScMapEntry({
1261
+ key: keyScVal,
1262
+ val: valueScVal
1263
+ })
1264
+ );
1265
+ }
1266
+ const sortedMapEntries = mapEntries.sort((a, b) => compareScValsByXdr(a.key(), b.key()));
1267
+ scVal = xdr5.ScVal.scvMap(sortedMapEntries);
1268
+ } else {
1269
+ scVal = nativeToScVal3(convertedValue, { type: typeHints });
1270
+ }
1089
1271
  logger8.debug(SYSTEM_LOG_TAG5, "convertStructToScVal generated ScVal:", {
1090
1272
  parameterType,
1091
1273
  scValType: scVal.switch().name,
@@ -1112,16 +1294,95 @@ function isStructType2(value, parameterType) {
1112
1294
  function valueToScVal(value, parameterType, paramSchema, parseInnerValue) {
1113
1295
  const parseValue = parseInnerValue || ((val) => val);
1114
1296
  const genericInfo = parseGenericType(parameterType);
1297
+ const isTypedWrapper = (v) => !!v && typeof v === "object" && "type" in v && "value" in v;
1298
+ const enumMetadata = paramSchema?.enumMetadata;
1299
+ const possibleEnumValue = typeof value === "string" && (enumMetadata || isLikelyEnumType(parameterType)) ? { tag: value } : value;
1115
1300
  if (!genericInfo) {
1116
- if (isEnumValue(value) || typeof value === "object" && value !== null && "enum" in value) {
1117
- return convertEnumToScVal(value);
1301
+ if (enumMetadata && enumMetadata.variants.every((v) => v.type === "integer")) {
1302
+ let numericValue;
1303
+ if (typeof value === "string") {
1304
+ const byName = enumMetadata.variants.find((v) => v.name === value);
1305
+ numericValue = byName?.value ?? Number(value);
1306
+ } else if (typeof value === "number") {
1307
+ numericValue = value;
1308
+ } else if (isEnumValue2(value)) {
1309
+ const byTag = enumMetadata.variants.find((v) => v.name === value.tag);
1310
+ numericValue = byTag?.value;
1311
+ }
1312
+ if (numericValue === void 0 || Number.isNaN(numericValue)) {
1313
+ const validNames = enumMetadata.variants.map((v) => v.name).join(", ");
1314
+ throw new Error(
1315
+ `Invalid integer enum value for ${parameterType}: ${String(value)}. Expected one of: ${validNames}`
1316
+ );
1317
+ }
1318
+ return nativeToScVal4(numericValue, { type: "u32" });
1319
+ }
1320
+ if (isTypedWrapper(possibleEnumValue)) {
1321
+ const wrapped = possibleEnumValue;
1322
+ const parsed = parsePrimitive(wrapped.value, wrapped.type);
1323
+ const finalVal = parsed !== null ? parsed : wrapped.value;
1324
+ const scValType2 = convertStellarTypeToScValType(wrapped.type);
1325
+ const typeHint2 = Array.isArray(scValType2) ? scValType2[0] : scValType2;
1326
+ return nativeToScVal4(finalVal, { type: typeHint2 });
1327
+ }
1328
+ if (isEnumValue2(possibleEnumValue) || typeof possibleEnumValue === "object" && possibleEnumValue !== null && "enum" in possibleEnumValue) {
1329
+ const enumValue = possibleEnumValue;
1330
+ if ("enum" in enumValue && typeof enumValue.enum === "number") {
1331
+ return nativeToScVal4(enumValue.enum, { type: "u32" });
1332
+ }
1333
+ const tagSymbol = nativeToScVal4(enumValue.tag, { type: "symbol" });
1334
+ if (!enumValue.values || enumValue.values.length === 0) {
1335
+ return xdr6.ScVal.scvVec([tagSymbol]);
1336
+ }
1337
+ const payloadValues = enumValue.values;
1338
+ let payloadScVals;
1339
+ let variant;
1340
+ if (enumMetadata) {
1341
+ variant = enumMetadata.variants.find((variantEntry) => variantEntry.name === enumValue.tag);
1342
+ if (!variant || !variant.payloadTypes) {
1343
+ return convertEnumToScVal(enumValue);
1344
+ }
1345
+ const payloadTypes = variant.payloadTypes;
1346
+ const payloadComponents = variant.payloadComponents;
1347
+ payloadScVals = payloadTypes.map((payloadType, index) => {
1348
+ const payloadSchema = payloadComponents?.[index] ? {
1349
+ name: `payload_${index}`,
1350
+ type: payloadType,
1351
+ components: payloadComponents[index]
1352
+ } : { name: `payload_${index}`, type: payloadType };
1353
+ const val = payloadValues[index];
1354
+ return valueToScVal(val, payloadType, payloadSchema, parseValue);
1355
+ });
1356
+ } else {
1357
+ return convertEnumToScVal(enumValue);
1358
+ }
1359
+ if (variant?.isSingleTuplePayload) {
1360
+ const tuplePayloadVec = xdr6.ScVal.scvVec(payloadScVals);
1361
+ return xdr6.ScVal.scvVec([tagSymbol, tuplePayloadVec]);
1362
+ }
1363
+ return xdr6.ScVal.scvVec([tagSymbol, ...payloadScVals]);
1364
+ }
1365
+ if (Array.isArray(possibleEnumValue) && paramSchema?.components && paramSchema.components.length) {
1366
+ if (possibleEnumValue.length !== paramSchema.components.length) {
1367
+ throw new Error(
1368
+ `Tuple-struct value length (${possibleEnumValue.length}) does not match schema components (${paramSchema.components.length}) for type ${parameterType}`
1369
+ );
1370
+ }
1371
+ return convertStructToScVal(
1372
+ possibleEnumValue,
1373
+ parameterType,
1374
+ paramSchema,
1375
+ parseValue,
1376
+ (innerValue, innerType, innerSchema) => valueToScVal(innerValue, innerType, innerSchema, parseInnerValue)
1377
+ );
1118
1378
  }
1119
- if (isStructType2(value, parameterType)) {
1379
+ if (!isPrimitiveParamType(parameterType) && isStructType2(value, parameterType)) {
1120
1380
  return convertStructToScVal(
1121
1381
  value,
1122
1382
  parameterType,
1123
1383
  paramSchema,
1124
- parseValue
1384
+ parseValue,
1385
+ (innerValue, innerType, innerSchema) => valueToScVal(innerValue, innerType, innerSchema, parseInnerValue)
1125
1386
  );
1126
1387
  }
1127
1388
  if (parameterType === "Bool" || parameterType === "Bytes") {
@@ -1151,15 +1412,30 @@ function valueToScVal(value, parameterType, paramSchema, parseInnerValue) {
1151
1412
  case "Vec": {
1152
1413
  const innerType = parameters[0];
1153
1414
  if (Array.isArray(value)) {
1154
- const convertedElements = value.map((element) => valueToScVal(element, innerType));
1415
+ let elementSchema;
1416
+ if (enumMetadata) {
1417
+ elementSchema = {
1418
+ name: "element",
1419
+ type: innerType,
1420
+ enumMetadata
1421
+ };
1422
+ } else if (paramSchema?.components) {
1423
+ elementSchema = {
1424
+ name: "element",
1425
+ type: innerType,
1426
+ components: paramSchema.components
1427
+ };
1428
+ }
1429
+ const convertedElements = value.map(
1430
+ (element) => valueToScVal(element, innerType, elementSchema, parseValue)
1431
+ );
1155
1432
  return nativeToScVal4(convertedElements);
1156
1433
  }
1157
1434
  return nativeToScVal4(value);
1158
1435
  }
1159
1436
  case "Map": {
1160
1437
  if (Array.isArray(value)) {
1161
- const convertedValue = {};
1162
- const typeHints = {};
1438
+ const mapEntries = [];
1163
1439
  value.forEach(
1164
1440
  (entry) => {
1165
1441
  if (typeof entry !== "object" || entry === null || !entry[0] || !entry[1] || typeof entry[0].value === "undefined" || typeof entry[1].value === "undefined") {
@@ -1175,26 +1451,74 @@ function valueToScVal(value, parameterType, paramSchema, parseInnerValue) {
1175
1451
  if (valuePrimitive !== null) {
1176
1452
  processedValue = valuePrimitive;
1177
1453
  }
1178
- const keyString = typeof processedKey === "string" ? processedKey : String(processedKey);
1179
- convertedValue[keyString] = processedValue;
1180
1454
  const keyScValType = convertStellarTypeToScValType(entry[0].type);
1455
+ const keyTypeHint = Array.isArray(keyScValType) ? keyScValType[0] : keyScValType;
1456
+ const keyScVal = nativeToScVal4(processedKey, { type: keyTypeHint });
1181
1457
  const valueScValType = convertStellarTypeToScValType(entry[1].type);
1182
- typeHints[keyString] = [
1183
- Array.isArray(keyScValType) ? keyScValType[0] : keyScValType,
1184
- Array.isArray(valueScValType) ? valueScValType[0] : valueScValType
1185
- ];
1458
+ const valueTypeHint = Array.isArray(valueScValType) ? valueScValType[0] : valueScValType;
1459
+ const valueScVal = nativeToScVal4(processedValue, { type: valueTypeHint });
1460
+ mapEntries.push(
1461
+ new xdr6.ScMapEntry({
1462
+ key: keyScVal,
1463
+ val: valueScVal
1464
+ })
1465
+ );
1186
1466
  }
1187
1467
  );
1188
- return nativeToScVal4(convertedValue, { type: typeHints });
1468
+ const sortedMapEntries = mapEntries.sort((a, b) => compareScValsByXdr(a.key(), b.key()));
1469
+ return xdr6.ScVal.scvMap(sortedMapEntries);
1189
1470
  }
1190
1471
  return nativeToScVal4(value);
1191
1472
  }
1473
+ case "Tuple": {
1474
+ if (!paramSchema?.components || paramSchema.components.length === 0) {
1475
+ throw new Error(
1476
+ `Tuple parameter "${paramSchema?.name ?? "unknown"}" is missing component metadata`
1477
+ );
1478
+ }
1479
+ const tupleComponents = paramSchema.components;
1480
+ const tupleValues = [];
1481
+ tupleComponents.forEach((component, index) => {
1482
+ const key = component.name ?? `item_${index}`;
1483
+ let elementValue;
1484
+ if (Array.isArray(value)) {
1485
+ elementValue = value[index];
1486
+ } else if (value && typeof value === "object") {
1487
+ elementValue = value[key];
1488
+ }
1489
+ if (typeof elementValue === "undefined") {
1490
+ const expectedTypes = tupleComponents.map((c) => c.type).join(", ");
1491
+ throw new Error(
1492
+ `Missing tuple value for "${key}" in parameter "${paramSchema.name ?? "unknown"}". Expected ${tupleComponents.length} values of types [${expectedTypes}] but received: ${JSON.stringify(value)}`
1493
+ );
1494
+ }
1495
+ if (typeof elementValue === "string" && isLikelyEnumType(component.type)) {
1496
+ elementValue = { tag: elementValue };
1497
+ }
1498
+ tupleValues.push(valueToScVal(elementValue, component.type, component, parseInnerValue));
1499
+ });
1500
+ return xdr6.ScVal.scvVec(tupleValues);
1501
+ }
1192
1502
  case "Option": {
1193
1503
  const innerType = parameters[0];
1194
1504
  if (value === null || value === void 0) {
1195
1505
  return nativeToScVal4(null);
1196
1506
  } else {
1197
- return valueToScVal(value, innerType);
1507
+ let innerSchema;
1508
+ if (enumMetadata) {
1509
+ innerSchema = {
1510
+ name: "inner",
1511
+ type: innerType,
1512
+ ...{ enumMetadata }
1513
+ };
1514
+ } else if (paramSchema?.components) {
1515
+ innerSchema = {
1516
+ name: "inner",
1517
+ type: innerType,
1518
+ components: paramSchema.components
1519
+ };
1520
+ }
1521
+ return valueToScVal(value, innerType, innerSchema, parseInnerValue);
1198
1522
  }
1199
1523
  }
1200
1524
  case "Result": {
@@ -1237,12 +1561,15 @@ function parseStellarInput(value, parameterType) {
1237
1561
  const result = parseGeneric(value, parameterType, parseStellarInput);
1238
1562
  return result;
1239
1563
  }
1240
- if (isEnumValue2(value) && isLikelyEnumType(parameterType)) {
1564
+ if (isEnumValue3(value) && isLikelyEnumType(parameterType)) {
1241
1565
  return value;
1242
1566
  }
1243
1567
  if (isPlainObject2(value)) {
1244
1568
  return value;
1245
1569
  }
1570
+ if (Array.isArray(value)) {
1571
+ return value;
1572
+ }
1246
1573
  if (typeof value === "string" || typeof value === "number") {
1247
1574
  return value;
1248
1575
  }
@@ -3681,11 +4008,69 @@ function getStellarCompatibleFieldTypes(parameterType) {
3681
4008
 
3682
4009
  // src/mapping/field-generator.ts
3683
4010
  import { startCase } from "lodash";
3684
- import { getDefaultValueForType, logger as logger25 } from "@openzeppelin/ui-builder-utils";
4011
+ import {
4012
+ enhanceNumericValidation,
4013
+ getDefaultValueForType,
4014
+ logger as logger25
4015
+ } from "@openzeppelin/ui-builder-utils";
3685
4016
 
3686
4017
  // src/mapping/enum-metadata.ts
3687
4018
  import { xdr as xdr11 } from "@stellar/stellar-sdk";
3688
4019
  import { logger as logger24 } from "@openzeppelin/ui-builder-utils";
4020
+
4021
+ // src/mapping/tuple-components.ts
4022
+ function buildTupleComponents(parameterType, specEntries) {
4023
+ const tupleElements = extractTupleTypes(parameterType);
4024
+ if (!tupleElements || tupleElements.length === 0) {
4025
+ return null;
4026
+ }
4027
+ return tupleElements.map((elementType, index) => {
4028
+ let nestedComponents;
4029
+ if (specEntries && isStructType(specEntries, elementType)) {
4030
+ const structFields = extractStructFields(specEntries, elementType);
4031
+ if (structFields && structFields.length > 0) {
4032
+ nestedComponents = structFields;
4033
+ }
4034
+ } else if (elementType.startsWith("Tuple<")) {
4035
+ const tupleStruct = buildTupleComponents(elementType, specEntries);
4036
+ if (tupleStruct && tupleStruct.length > 0) {
4037
+ nestedComponents = tupleStruct;
4038
+ }
4039
+ }
4040
+ return {
4041
+ name: `item_${index}`,
4042
+ type: elementType,
4043
+ displayName: `Value ${index + 1} (${elementType})`,
4044
+ ...nestedComponents && { components: nestedComponents }
4045
+ };
4046
+ });
4047
+ }
4048
+
4049
+ // src/mapping/enum-metadata.ts
4050
+ function flattenPayloadType(payloadType, entries, flattenedTypes, flattenedComponents) {
4051
+ if (payloadType.startsWith("Tuple<")) {
4052
+ const tupleComponents = buildTupleComponents(payloadType, entries);
4053
+ if (tupleComponents && tupleComponents.length > 0) {
4054
+ tupleComponents.forEach((component) => {
4055
+ flattenedTypes.push(component.type);
4056
+ if (isStructType(entries, component.type)) {
4057
+ flattenedComponents.push(extractStructFields(entries, component.type) ?? void 0);
4058
+ } else {
4059
+ flattenedComponents.push(component.components);
4060
+ }
4061
+ });
4062
+ } else {
4063
+ flattenedTypes.push(payloadType);
4064
+ flattenedComponents.push(void 0);
4065
+ }
4066
+ } else if (isStructType(entries, payloadType)) {
4067
+ flattenedTypes.push(payloadType);
4068
+ flattenedComponents.push(extractStructFields(entries, payloadType) ?? void 0);
4069
+ } else {
4070
+ flattenedTypes.push(payloadType);
4071
+ flattenedComponents.push(void 0);
4072
+ }
4073
+ }
3689
4074
  function extractEnumVariants(entries, enumName) {
3690
4075
  try {
3691
4076
  const entry = entries.find((e) => {
@@ -3714,11 +4099,29 @@ function extractEnumVariants(entries, enumName) {
3714
4099
  });
3715
4100
  } else if (caseKind.value === xdr11.ScSpecUdtUnionCaseV0Kind.scSpecUdtUnionCaseTupleV0().value) {
3716
4101
  const tupleCase = caseEntry.tupleCase();
3717
- const payloadTypes = tupleCase.type().map((typeDef) => extractSorobanTypeFromScSpec(typeDef));
4102
+ const rawPayloadTypes = tupleCase.type().map((typeDef) => extractSorobanTypeFromScSpec(typeDef));
4103
+ const isSingleTuplePayload = rawPayloadTypes.length === 1 && rawPayloadTypes[0].startsWith("Tuple<");
4104
+ const flattenedPayloadTypes = [];
4105
+ const flattenedPayloadComponents = [];
4106
+ for (const payloadType of rawPayloadTypes) {
4107
+ flattenPayloadType(
4108
+ payloadType,
4109
+ entries,
4110
+ flattenedPayloadTypes,
4111
+ flattenedPayloadComponents
4112
+ );
4113
+ }
3718
4114
  variants.push({
3719
4115
  name: tupleCase.name().toString(),
3720
4116
  type: "tuple",
3721
- payloadTypes
4117
+ payloadTypes: flattenedPayloadTypes,
4118
+ ...flattenedPayloadComponents.some(
4119
+ (components) => components && components.length > 0
4120
+ ) && {
4121
+ payloadComponents: flattenedPayloadComponents
4122
+ },
4123
+ // Store metadata about whether this needs tuple wrapping during serialization
4124
+ ...isSingleTuplePayload && { isSingleTuplePayload: true }
3722
4125
  });
3723
4126
  isUnitOnly = false;
3724
4127
  }
@@ -3779,6 +4182,14 @@ function isEnumType(entries, typeName) {
3779
4182
  function getDefaultValidationForType() {
3780
4183
  return { required: true };
3781
4184
  }
4185
+ var STELLAR_NUMERIC_BOUNDS = {
4186
+ U8: { min: 0, max: 255 },
4187
+ U16: { min: 0, max: 65535 },
4188
+ U32: { min: 0, max: 4294967295 },
4189
+ I8: { min: -128, max: 127 },
4190
+ I16: { min: -32768, max: 32767 },
4191
+ I32: { min: -2147483648, max: 2147483647 }
4192
+ };
3782
4193
  function generateStellarDefaultField(parameter, contractSchema) {
3783
4194
  const specEntries = contractSchema?.metadata?.specEntries;
3784
4195
  const fieldType = mapStellarParameterTypeToFieldType(parameter.type);
@@ -3792,8 +4203,10 @@ function generateStellarDefaultField(parameter, contractSchema) {
3792
4203
  let structComponents = null;
3793
4204
  let finalFieldType = fieldType;
3794
4205
  let options;
3795
- if (isLikelyEnumType(parameter.type)) {
3796
- if (specEntries && isEnumType(specEntries, parameter.type)) {
4206
+ const enumDetectedBySpec = !!(specEntries && isEnumType(specEntries, parameter.type));
4207
+ const enumDetectedHeuristic = isLikelyEnumType(parameter.type);
4208
+ if (enumDetectedBySpec || enumDetectedHeuristic) {
4209
+ if (enumDetectedBySpec) {
3797
4210
  enumMetadata = extractEnumVariants(specEntries, parameter.type);
3798
4211
  if (enumMetadata) {
3799
4212
  if (enumMetadata.isUnitOnly) {
@@ -3822,6 +4235,12 @@ function generateStellarDefaultField(parameter, contractSchema) {
3822
4235
  structComponents = structFields;
3823
4236
  }
3824
4237
  }
4238
+ if (!structComponents) {
4239
+ const tupleComponents = buildTupleComponents(parameter.type, specEntries);
4240
+ if (tupleComponents && tupleComponents.length > 0) {
4241
+ structComponents = tupleComponents;
4242
+ }
4243
+ }
3825
4244
  const baseField = {
3826
4245
  id: `field-${Math.random().toString(36).substring(2, 9)}`,
3827
4246
  name: parameter.name || parameter.type,
@@ -3835,6 +4254,11 @@ function generateStellarDefaultField(parameter, contractSchema) {
3835
4254
  width: "full",
3836
4255
  options
3837
4256
  };
4257
+ baseField.validation = enhanceNumericValidation(
4258
+ baseField.validation,
4259
+ parameter.type,
4260
+ STELLAR_NUMERIC_BOUNDS
4261
+ );
3838
4262
  if (isBytesNType(parameter.type)) {
3839
4263
  const sizeMatch = parameter.type.match(/^BytesN<(\d+)>$/);
3840
4264
  const maxBytes = sizeMatch ? Number.parseInt(sizeMatch[1], 10) : void 0;
@@ -3845,17 +4269,50 @@ function generateStellarDefaultField(parameter, contractSchema) {
3845
4269
  };
3846
4270
  }
3847
4271
  }
3848
- if (fieldType === "array") {
4272
+ if (fieldType === "array" || fieldType === "array-object") {
3849
4273
  const elementType = extractVecElementType(parameter.type);
3850
4274
  if (elementType) {
3851
4275
  const elementFieldType = mapStellarParameterTypeToFieldType(elementType);
4276
+ let elementEnumMetadata;
4277
+ let elementComponents;
4278
+ let finalElementFieldType = elementFieldType;
4279
+ if (isLikelyEnumType(elementType)) {
4280
+ if (specEntries && isEnumType(specEntries, elementType)) {
4281
+ elementEnumMetadata = extractEnumVariants(specEntries, elementType) ?? void 0;
4282
+ if (elementEnumMetadata) {
4283
+ finalElementFieldType = elementEnumMetadata.isUnitOnly ? "select" : "enum";
4284
+ }
4285
+ }
4286
+ }
4287
+ if (specEntries && isStructType(specEntries, elementType)) {
4288
+ const structFields = extractStructFields(specEntries, elementType);
4289
+ if (structFields && structFields.length > 0) {
4290
+ elementComponents = structFields;
4291
+ finalElementFieldType = "object";
4292
+ }
4293
+ }
4294
+ if (fieldType === "array-object" && parameter.components) {
4295
+ elementComponents = parameter.components;
4296
+ finalElementFieldType = "object";
4297
+ }
4298
+ let elementValidation = { required: true };
4299
+ elementValidation = enhanceNumericValidation(
4300
+ elementValidation,
4301
+ elementType,
4302
+ STELLAR_NUMERIC_BOUNDS
4303
+ );
3852
4304
  const arrayField = {
3853
4305
  ...baseField,
3854
- elementType: elementFieldType,
4306
+ type: "array",
4307
+ // Always use 'array' as the field type
4308
+ elementType: finalElementFieldType,
3855
4309
  elementFieldConfig: {
3856
- type: elementFieldType,
3857
- validation: { required: true },
3858
- placeholder: `Enter ${elementType}`
4310
+ type: finalElementFieldType,
4311
+ validation: elementValidation,
4312
+ placeholder: `Enter ${elementType}`,
4313
+ originalParameterType: elementType,
4314
+ ...elementEnumMetadata && { enumMetadata: elementEnumMetadata },
4315
+ ...elementComponents && { components: elementComponents }
3859
4316
  }
3860
4317
  };
3861
4318
  return arrayField;
@@ -3873,13 +4330,21 @@ function generateStellarDefaultField(parameter, contractSchema) {
3873
4330
  valueType: valueFieldType,
3874
4331
  keyFieldConfig: {
3875
4332
  type: keyFieldType,
3876
- validation: { required: true },
4333
+ validation: enhanceNumericValidation(
4334
+ { required: true },
4335
+ mapTypes.keyType,
4336
+ STELLAR_NUMERIC_BOUNDS
4337
+ ),
3877
4338
  placeholder: `Enter ${mapTypes.keyType}`,
3878
4339
  originalParameterType: mapTypes.keyType
3879
4340
  },
3880
4341
  valueFieldConfig: {
3881
4342
  type: valueFieldType,
3882
- validation: { required: true },
4343
+ validation: enhanceNumericValidation(
4344
+ { required: true },
4345
+ mapTypes.valueType,
4346
+ STELLAR_NUMERIC_BOUNDS
4347
+ ),
3883
4348
  placeholder: `Enter ${mapTypes.valueType}`,
3884
4349
  originalParameterType: mapTypes.valueType
3885
4350
  }
@@ -3915,8 +4380,36 @@ function generateStellarDefaultField(parameter, contractSchema) {
3915
4380
 
3916
4381
  // src/transaction/formatter.ts
3917
4382
  import { Address as Address3 } from "@stellar/stellar-sdk";
3918
- import { isEnumValue as isEnumValue3 } from "@openzeppelin/ui-builder-types";
4383
+ import { isEnumValue as isEnumValue4 } from "@openzeppelin/ui-builder-types";
3919
4384
  import { logger as logger26 } from "@openzeppelin/ui-builder-utils";
4385
+ function enrichParameterWithEnumMetadata(param, specEntries) {
4386
+ if (!specEntries) {
4387
+ return param;
4388
+ }
4389
+ const enriched = { ...param };
4390
+ if (isLikelyEnumType(param.type) && isEnumType(specEntries, param.type)) {
4391
+ const enumMetadata = extractEnumVariants(specEntries, param.type);
4392
+ if (enumMetadata) {
4393
+ enriched.enumMetadata = enumMetadata;
4394
+ }
4395
+ }
4396
+ const vecMatch = param.type.match(/^Vec<([^>]+)>$/);
4397
+ if (vecMatch) {
4398
+ const elementType = vecMatch[1];
4399
+ if (isLikelyEnumType(elementType) && isEnumType(specEntries, elementType)) {
4400
+ const enumMetadata = extractEnumVariants(specEntries, elementType);
4401
+ if (enumMetadata) {
4402
+ enriched.enumMetadata = enumMetadata;
4403
+ }
4404
+ }
4405
+ }
4406
+ if (enriched.components && enriched.components.length > 0) {
4407
+ enriched.components = enriched.components.map(
4408
+ (component) => enrichParameterWithEnumMetadata(component, specEntries)
4409
+ );
4410
+ }
4411
+ return enriched;
4412
+ }
3920
4413
  function formatStellarTransactionData(contractSchema, functionId, submittedInputs, fields) {
3921
4414
  logger26.info(
3922
4415
  "formatStellarTransactionData",
@@ -3956,10 +4449,10 @@ function formatStellarTransactionData(contractSchema, functionId, submittedInput
3956
4449
  }
3957
4450
  const transformedArgs = expectedArgs.map((param, index) => {
3958
4451
  let valueToParse = orderedRawValues[index];
3959
- if (isEnumValue3(valueToParse)) {
3960
- const specEntries = contractSchema.metadata?.specEntries;
3961
- if (specEntries && isEnumType(specEntries, param.type)) {
3962
- const enumMetadata = extractEnumVariants(specEntries, param.type);
4452
+ if (isEnumValue4(valueToParse)) {
4453
+ const specEntries2 = contractSchema.metadata?.specEntries;
4454
+ if (specEntries2 && isEnumType(specEntries2, param.type)) {
4455
+ const enumMetadata = extractEnumVariants(specEntries2, param.type);
3963
4456
  const enumValue = valueToParse;
3964
4457
  if (enumMetadata && enumValue.values) {
3965
4458
  const selectedVariant = enumMetadata.variants.find((v) => v.name === enumValue.tag);
@@ -3967,14 +4460,15 @@ function formatStellarTransactionData(contractSchema, functionId, submittedInput
3967
4460
  const processedValues = enumValue.values.map(
3968
4461
  (rawValue, payloadIndex) => {
3969
4462
  const expectedType = selectedVariant.payloadTypes[payloadIndex];
3970
- if (expectedType) {
3971
- const processedValue = parseStellarInput(rawValue, expectedType);
3972
- return {
3973
- type: expectedType,
3974
- value: processedValue
3975
- };
4463
+ if (!expectedType) {
4464
+ return rawValue;
4465
+ }
4466
+ const processedValue = parseStellarInput(rawValue, expectedType);
4467
+ const isPrimitivePayload = isPrimitiveParamType(expectedType) || isBytesNType(expectedType);
4468
+ if (isPrimitivePayload) {
4469
+ return { type: expectedType, value: processedValue };
3976
4470
  }
3977
- return rawValue;
4471
+ return processedValue;
3978
4472
  }
3979
4473
  );
3980
4474
  valueToParse = { ...enumValue, values: processedValues };
@@ -3995,14 +4489,64 @@ function formatStellarTransactionData(contractSchema, functionId, submittedInput
3995
4489
  } catch {
3996
4490
  throw new Error("Contract address is missing or invalid in the provided schema.");
3997
4491
  }
4492
+ const fieldByName = /* @__PURE__ */ new Map();
4493
+ fields.forEach((field) => fieldByName.set(field.name, field));
4494
+ const specEntries = contractSchema.metadata?.specEntries;
4495
+ const argSchemaWithComponents = functionDetails.inputs.map((param) => {
4496
+ const field = fieldByName.get(param.name);
4497
+ const enhanced = { ...param };
4498
+ if (param.components && param.components.length > 0) {
4499
+ enhanced.components = param.components;
4500
+ } else if (field?.components && field.components.length > 0) {
4501
+ enhanced.components = field.components;
4502
+ }
4503
+ if (field?.enumMetadata) {
4504
+ enhanced.enumMetadata = field.enumMetadata;
4505
+ }
4506
+ if (param.type.startsWith("Vec<") && field?.elementFieldConfig) {
4507
+ if (field.elementFieldConfig.enumMetadata) {
4508
+ enhanced.enumMetadata = field.elementFieldConfig.enumMetadata;
4509
+ }
4510
+ if (field.elementFieldConfig.components) {
4511
+ enhanced.components = field.elementFieldConfig.components;
4512
+ }
4513
+ }
4514
+ if (enhanced.components && enhanced.components.length > 0) {
4515
+ enhanced.components = enhanced.components.map((component) => {
4516
+ const nestedFieldName = `${param.name}.${component.name}`;
4517
+ const nestedField = fieldByName.get(nestedFieldName);
4518
+ if (nestedField) {
4519
+ const enrichedComponent = { ...component };
4520
+ if (nestedField.enumMetadata) {
4521
+ enrichedComponent.enumMetadata = nestedField.enumMetadata;
4522
+ }
4523
+ if (nestedField.components) {
4524
+ enrichedComponent.components = nestedField.components;
4525
+ }
4526
+ if (component.type.startsWith("Vec<") && nestedField.elementFieldConfig) {
4527
+ if (nestedField.elementFieldConfig.enumMetadata) {
4528
+ enrichedComponent.enumMetadata = nestedField.elementFieldConfig.enumMetadata;
4529
+ }
4530
+ if (nestedField.elementFieldConfig.components) {
4531
+ enrichedComponent.components = nestedField.elementFieldConfig.components;
4532
+ }
4533
+ }
4534
+ return enrichedComponent;
4535
+ }
4536
+ return component;
4537
+ });
4538
+ }
4539
+ const finalEnhanced = enrichParameterWithEnumMetadata(enhanced, specEntries);
4540
+ return finalEnhanced;
4541
+ });
3998
4542
  const stellarTransactionData = {
3999
4543
  contractAddress: contractSchema.address,
4000
4544
  functionName: functionDetails.name,
4001
4545
  args: transformedArgs,
4002
4546
  argTypes: functionDetails.inputs.map((param) => param.type),
4003
4547
  // Include parameter types for ScVal conversion
4004
- argSchema: functionDetails.inputs,
4005
- // Include full parameter schema with struct field definitions
4548
+ argSchema: argSchemaWithComponents,
4549
+ // Include full parameter schema with struct/tuple field definitions
4006
4550
  transactionOptions: {
4007
4551
  // Add any Stellar-specific transaction options here
4008
4552
  // For example: fee, timeout, memo, etc.