@caatinga/core 3.2.0 → 3.3.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.cjs CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  BINDING_MARKER_FILENAME: () => BINDING_MARKER_FILENAME,
34
34
  BindingMarkerSchema: () => BindingMarkerSchema,
35
35
  CAATINGA_CORE_VERSION: () => CAATINGA_CORE_VERSION,
36
+ CURRENT_ARTIFACTS_SCHEMA_VERSION: () => CURRENT_ARTIFACTS_SCHEMA_VERSION,
36
37
  CaatingaArtifactsSchema: () => CaatingaArtifactsSchema,
37
38
  CaatingaConfigSchema: () => CaatingaConfigSchema,
38
39
  CaatingaError: () => CaatingaError,
@@ -40,6 +41,8 @@ __export(index_exports, {
40
41
  READ_CALL_FAILURE_REGEX: () => READ_CALL_FAILURE_REGEX,
41
42
  STELLAR_CLI_LAST_TESTED_VERSION: () => STELLAR_CLI_LAST_TESTED_VERSION,
42
43
  STELLAR_CLI_MIN_VERSION: () => STELLAR_CLI_MIN_VERSION,
44
+ STELLAR_SDK_LAST_TESTED_VERSION: () => STELLAR_SDK_LAST_TESTED_VERSION,
45
+ STELLAR_SDK_MIN_VERSION: () => STELLAR_SDK_MIN_VERSION,
43
46
  TemplateManifestSchema: () => TemplateManifestSchema,
44
47
  WELL_KNOWN_NETWORKS: () => WELL_KNOWN_NETWORKS,
45
48
  buildContract: () => buildContract,
@@ -47,6 +50,7 @@ __export(index_exports, {
47
50
  buildReadCallHint: () => buildReadCallHint,
48
51
  checkBinary: () => checkBinary,
49
52
  checkStellarCliVersion: () => checkStellarCliVersion,
53
+ checkStellarSdkVersion: () => checkStellarSdkVersion,
50
54
  collectProjectStatus: () => collectProjectStatus,
51
55
  createInitialArtifacts: () => createInitialArtifacts,
52
56
  createMinimalProject: () => createMinimalProject,
@@ -55,20 +59,26 @@ __export(index_exports, {
55
59
  defineConfig: () => defineConfig,
56
60
  deployContract: () => deployContract,
57
61
  deployContractGraph: () => deployContractGraph,
62
+ estimateDeployCost: () => estimateDeployCost,
58
63
  evaluateBindingFreshness: () => evaluateBindingFreshness,
59
64
  evaluateBindingsFreshness: () => evaluateBindingsFreshness,
60
65
  evaluateStellarCliCompatibility: () => evaluateStellarCliCompatibility,
66
+ evaluateStellarSdkCompatibility: () => evaluateStellarSdkCompatibility,
61
67
  formatCaatingaError: () => formatCaatingaError,
62
68
  generateBindings: () => generateBindings,
63
69
  generateBindingsGraph: () => generateBindingsGraph,
70
+ inspectContract: () => inspectContract,
64
71
  invokeContract: () => invokeContract,
65
72
  isCargoBinMissingFromPath: () => isCargoBinMissingFromPath,
66
73
  isReadCallFailure: () => isReadCallFailure,
67
74
  isTransientTestnetSmokeFailure: () => isTransientTestnetSmokeFailure,
68
75
  loadConfig: () => loadConfig,
76
+ migrateArtifactsFile: () => migrateArtifactsFile,
77
+ migrateArtifactsToV2: () => migrateArtifactsToV2,
69
78
  parseContractId: () => parseContractId,
70
79
  parseInvokeTarget: () => parseInvokeTarget,
71
80
  parseStellarCliVersion: () => parseStellarCliVersion,
81
+ parseStellarSdkVersion: () => parseStellarSdkVersion,
72
82
  readArtifacts: () => readArtifacts,
73
83
  readBindingMarker: () => readBindingMarker,
74
84
  readContract: () => readContract,
@@ -78,6 +88,8 @@ __export(index_exports, {
78
88
  resolveDeployOrder: () => resolveDeployOrder,
79
89
  resolveNetwork: () => resolveNetwork,
80
90
  resolveSubprocessEnv: () => resolveSubprocessEnv,
91
+ restoreArtifactFromHistory: () => restoreArtifactFromHistory,
92
+ rollbackContractArtifact: () => rollbackContractArtifact,
81
93
  runCommand: () => runCommand,
82
94
  toCaatingaError: () => toCaatingaError,
83
95
  updateArtifact: () => updateArtifact,
@@ -97,6 +109,8 @@ var CaatingaErrorCode = {
97
109
  STELLAR_CLI_NOT_FOUND: "CAATINGA_STELLAR_CLI_NOT_FOUND",
98
110
  STELLAR_CLI_VERSION_PARSE_FAILED: "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
99
111
  UNSUPPORTED_CLI_VERSION: "CAATINGA_UNSUPPORTED_CLI_VERSION",
112
+ STELLAR_SDK_VERSION_PARSE_FAILED: "CAATINGA_STELLAR_SDK_VERSION_PARSE_FAILED",
113
+ UNSUPPORTED_SDK_VERSION: "CAATINGA_UNSUPPORTED_SDK_VERSION",
100
114
  RUST_NOT_FOUND: "CAATINGA_RUST_NOT_FOUND",
101
115
  RUST_TARGET_NOT_FOUND: "CAATINGA_RUST_TARGET_NOT_FOUND",
102
116
  DEPLOY_FAILED: "CAATINGA_DEPLOY_FAILED",
@@ -139,6 +153,8 @@ var CaatingaErrorCode = {
139
153
  ZK_VERIFICATION_FAILED: "CAATINGA_ZK_VERIFICATION_FAILED",
140
154
  ZK_DEV_CEREMONY_BLOCKED: "CAATINGA_ZK_DEV_CEREMONY_BLOCKED",
141
155
  DOCTOR_PARTIAL_DEPLOY: "CAATINGA_DOCTOR_PARTIAL_DEPLOY",
156
+ ROLLBACK_TARGET_NOT_FOUND: "CAATINGA_ROLLBACK_TARGET_NOT_FOUND",
157
+ ESTIMATE_FAILED: "CAATINGA_ESTIMATE_FAILED",
142
158
  MULTI_AUTH_REQUIRED: "CAATINGA_MULTI_AUTH_REQUIRED"
143
159
  };
144
160
 
@@ -327,6 +343,14 @@ async function loadConfig(options = {}) {
327
343
 
328
344
  // src/artifacts/artifact.schema.ts
329
345
  var import_zod3 = require("zod");
346
+ var ArtifactSupersedeReasonSchema = import_zod3.z.enum(["upgrade", "rollback", "force-redeploy"]);
347
+ var ContractArtifactHistoryEntrySchema = import_zod3.z.object({
348
+ contractId: import_zod3.z.string().min(1),
349
+ wasmHash: import_zod3.z.string().min(1),
350
+ deployedAt: import_zod3.z.string().datetime(),
351
+ supersededAt: import_zod3.z.string().datetime(),
352
+ reason: ArtifactSupersedeReasonSchema.optional()
353
+ });
330
354
  var ContractArtifactSchema = import_zod3.z.object({
331
355
  contractId: import_zod3.z.string().min(1),
332
356
  wasmHash: import_zod3.z.string().min(1),
@@ -334,17 +358,28 @@ var ContractArtifactSchema = import_zod3.z.object({
334
358
  sourcePath: import_zod3.z.string().min(1),
335
359
  wasmPath: import_zod3.z.string().min(1),
336
360
  dependencies: import_zod3.z.array(import_zod3.z.string().min(1)).default([]),
337
- resolvedDeployArgs: import_zod3.z.record(import_zod3.z.string().min(1), import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean()])).default({})
361
+ resolvedDeployArgs: import_zod3.z.record(import_zod3.z.string().min(1), import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean()])).default({}),
362
+ history: import_zod3.z.array(ContractArtifactHistoryEntrySchema).optional()
338
363
  });
339
364
  var NetworkArtifactsSchema = import_zod3.z.object({
340
365
  contracts: import_zod3.z.record(import_zod3.z.string().min(1), ContractArtifactSchema).default({}),
341
366
  dependencyGraph: import_zod3.z.record(import_zod3.z.string().min(1), import_zod3.z.array(import_zod3.z.string().min(1))).default({})
342
367
  });
343
- var CaatingaArtifactsSchema = import_zod3.z.object({
368
+ var CaatingaArtifactsBaseSchema = import_zod3.z.object({
344
369
  project: import_zod3.z.string().min(1),
345
- version: import_zod3.z.literal(1),
346
370
  networks: import_zod3.z.record(import_zod3.z.string().min(1), NetworkArtifactsSchema).default({})
347
371
  });
372
+ var CaatingaArtifactsV1Schema = CaatingaArtifactsBaseSchema.extend({
373
+ version: import_zod3.z.literal(1)
374
+ });
375
+ var CaatingaArtifactsV2Schema = CaatingaArtifactsBaseSchema.extend({
376
+ version: import_zod3.z.literal(2)
377
+ });
378
+ var CaatingaArtifactsSchema = import_zod3.z.union([
379
+ CaatingaArtifactsV1Schema,
380
+ CaatingaArtifactsV2Schema
381
+ ]);
382
+ var CURRENT_ARTIFACTS_SCHEMA_VERSION = 2;
348
383
 
349
384
  // src/artifacts/read-artifacts.ts
350
385
  var import_promises2 = require("fs/promises");
@@ -396,29 +431,139 @@ function createInitialArtifacts(project, options = {}) {
396
431
  );
397
432
  return {
398
433
  project,
399
- version: 1,
434
+ version: 2,
400
435
  networks
401
436
  };
402
437
  }
403
438
 
404
439
  // src/artifacts/update-artifact.ts
405
- function updateArtifact(artifacts, networkName, contractName, contractArtifact, networkExtras) {
440
+ function appendHistory(existing, reason) {
441
+ if (!existing || !reason) {
442
+ return existing?.history;
443
+ }
444
+ const supersededAt = (/* @__PURE__ */ new Date()).toISOString();
445
+ const entry = {
446
+ contractId: existing.contractId,
447
+ wasmHash: existing.wasmHash,
448
+ deployedAt: existing.deployedAt,
449
+ supersededAt,
450
+ reason
451
+ };
452
+ return [...existing.history ?? [], entry];
453
+ }
454
+ function updateArtifact(artifacts, networkName, contractName, contractArtifact, options = {}) {
406
455
  const existingNetwork = artifacts.networks[networkName] ?? { contracts: {}, dependencyGraph: {} };
456
+ const existingContract = existingNetwork.contracts[contractName];
457
+ const history = appendHistory(existingContract, options.supersedeReason);
458
+ const nextVersion = artifacts.version === 1 && options.supersedeReason ? 2 : artifacts.version;
407
459
  return {
408
460
  ...artifacts,
461
+ version: nextVersion,
409
462
  networks: {
410
463
  ...artifacts.networks,
411
464
  [networkName]: {
412
465
  ...existingNetwork,
413
- dependencyGraph: networkExtras?.dependencyGraph ?? existingNetwork.dependencyGraph ?? {},
466
+ dependencyGraph: options.dependencyGraph ?? existingNetwork.dependencyGraph ?? {},
414
467
  contracts: {
415
468
  ...existingNetwork.contracts,
416
- [contractName]: contractArtifact
469
+ [contractName]: {
470
+ ...contractArtifact,
471
+ history: history ?? contractArtifact.history
472
+ }
417
473
  }
418
474
  }
419
475
  }
420
476
  };
421
477
  }
478
+ function restoreArtifactFromHistory(input) {
479
+ const network = input.artifacts.networks[input.networkName];
480
+ const current = network?.contracts[input.contractName];
481
+ if (!current) {
482
+ throw new CaatingaError(
483
+ `No artifact for "${input.contractName}" on "${input.networkName}".`,
484
+ CaatingaErrorCode.ARTIFACT_NOT_FOUND,
485
+ "Deploy the contract before attempting rollback."
486
+ );
487
+ }
488
+ if (current.contractId === input.contractId) {
489
+ return input.artifacts;
490
+ }
491
+ const fromHistory = (current.history ?? []).find(
492
+ (entry) => entry.contractId === input.contractId
493
+ );
494
+ if (!fromHistory) {
495
+ throw new CaatingaError(
496
+ `Rollback target "${input.contractId}" was not found in artifact history for "${input.contractName}".`,
497
+ CaatingaErrorCode.ROLLBACK_TARGET_NOT_FOUND,
498
+ "Use caatinga inspect to list prior contract IDs, or redeploy manually."
499
+ );
500
+ }
501
+ const supersededAt = (/* @__PURE__ */ new Date()).toISOString();
502
+ const restoredArtifact = {
503
+ contractId: fromHistory.contractId,
504
+ wasmHash: fromHistory.wasmHash,
505
+ deployedAt: fromHistory.deployedAt,
506
+ sourcePath: current.sourcePath,
507
+ wasmPath: current.wasmPath,
508
+ dependencies: current.dependencies,
509
+ resolvedDeployArgs: current.resolvedDeployArgs,
510
+ history: [
511
+ ...current.history ?? [],
512
+ {
513
+ contractId: current.contractId,
514
+ wasmHash: current.wasmHash,
515
+ deployedAt: current.deployedAt,
516
+ supersededAt,
517
+ reason: "rollback"
518
+ }
519
+ ]
520
+ };
521
+ return {
522
+ ...updateArtifact(input.artifacts, input.networkName, input.contractName, restoredArtifact),
523
+ version: 2
524
+ };
525
+ }
526
+
527
+ // src/artifacts/migrate-artifacts.ts
528
+ function migrateArtifactsToV2(artifacts) {
529
+ if (artifacts.version === CURRENT_ARTIFACTS_SCHEMA_VERSION) {
530
+ return {
531
+ artifacts,
532
+ migrated: false
533
+ };
534
+ }
535
+ const v1 = artifacts;
536
+ return {
537
+ artifacts: {
538
+ project: v1.project,
539
+ version: CURRENT_ARTIFACTS_SCHEMA_VERSION,
540
+ networks: v1.networks
541
+ },
542
+ migrated: true
543
+ };
544
+ }
545
+
546
+ // src/artifacts/migrate-artifacts-file.ts
547
+ async function migrateArtifactsFile(cwd = process.cwd()) {
548
+ const artifacts = await readArtifacts(cwd);
549
+ const { artifacts: migrated, migrated: changed } = migrateArtifactsToV2(artifacts);
550
+ const path17 = await writeArtifacts(migrated, cwd);
551
+ return { path: path17, migrated: changed, artifacts: migrated };
552
+ }
553
+
554
+ // src/artifacts/rollback-artifact.ts
555
+ async function rollbackContractArtifact(input) {
556
+ const cwd = input.cwd ?? process.cwd();
557
+ const artifacts = await readArtifacts(cwd);
558
+ const next = restoreArtifactFromHistory({
559
+ artifacts,
560
+ networkName: input.networkName,
561
+ contractName: input.contractName,
562
+ contractId: input.contractId
563
+ });
564
+ const path17 = await writeArtifacts(next, cwd);
565
+ return { path: path17, artifacts: next };
566
+ }
422
567
 
423
568
  // src/networks/resolve-network.ts
424
569
  function resolveNetwork(config, networkName) {
@@ -685,6 +830,35 @@ function evaluateStellarCliCompatibility(input) {
685
830
  };
686
831
  }
687
832
 
833
+ // src/stellar-cli/probe-stellar-cli-features.ts
834
+ var import_semver3 = __toESM(require("semver"), 1);
835
+ var STELLAR_CLI_REQUIRED_FEATURES = [
836
+ "contract-build",
837
+ "contract-deploy",
838
+ "contract-invoke-sign"
839
+ ];
840
+ var FEATURE_COMMANDS = {
841
+ "contract-build": ["contract", "build", "--help"],
842
+ "contract-deploy": ["contract", "deploy", "--help"],
843
+ "contract-invoke-sign": ["contract", "invoke", "--help"]
844
+ };
845
+ async function probeMissingStellarCliFeatures(version) {
846
+ const missing = [];
847
+ if (import_semver3.default.valid(version) && import_semver3.default.lt(version, STELLAR_CLI_MIN_VERSION)) {
848
+ return ["contract-invoke-sign"];
849
+ }
850
+ for (const feature of STELLAR_CLI_REQUIRED_FEATURES) {
851
+ try {
852
+ await runCommand("stellar", FEATURE_COMMANDS[feature], {
853
+ skipStellarVersionCheck: true
854
+ });
855
+ } catch {
856
+ missing.push(feature);
857
+ }
858
+ }
859
+ return missing;
860
+ }
861
+
688
862
  // src/stellar-cli/check-stellar-cli-version.ts
689
863
  async function checkStellarCliVersion(input = {}) {
690
864
  let rawOutput;
@@ -704,9 +878,12 @@ async function checkStellarCliVersion(input = {}) {
704
878
  }
705
879
  throw error;
706
880
  }
881
+ const version = parseStellarCliVersion(rawOutput);
882
+ const probedMissing = input.probeFeatures === false ? [] : await probeMissingStellarCliFeatures(version);
883
+ const missingFeatures = [...input.features ?? [], ...probedMissing];
707
884
  const report = evaluateStellarCliCompatibility({
708
- version: parseStellarCliVersion(rawOutput),
709
- features: input.features,
885
+ version,
886
+ features: missingFeatures.length > 0 ? missingFeatures : void 0,
710
887
  lastTestedVersion: input.lastTestedVersion
711
888
  });
712
889
  for (const warning of report.warnings) {
@@ -852,6 +1029,122 @@ function parseContractId(output) {
852
1029
  return match[0];
853
1030
  }
854
1031
 
1032
+ // src/stellar-sdk/check-stellar-sdk-version.ts
1033
+ var import_promises6 = require("fs/promises");
1034
+ var import_node_path7 = __toESM(require("path"), 1);
1035
+
1036
+ // src/stellar-sdk/compat.ts
1037
+ var import_semver4 = __toESM(require("semver"), 1);
1038
+
1039
+ // src/stellar-sdk/version.ts
1040
+ var STELLAR_SDK_MIN_VERSION = "16.0.1";
1041
+ var STELLAR_SDK_LAST_TESTED_VERSION = "16.0.1";
1042
+
1043
+ // src/stellar-sdk/compat.ts
1044
+ function evaluateStellarSdkCompatibility(input) {
1045
+ const parsed = import_semver4.default.parse(input.version);
1046
+ if (!parsed || !import_semver4.default.valid(input.version)) {
1047
+ throw new CaatingaError(
1048
+ "Could not parse @stellar/stellar-sdk version.",
1049
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
1050
+ "Use a semantic version such as 16.0.1."
1051
+ );
1052
+ }
1053
+ const lastTestedVersion = import_semver4.default.valid(input.lastTestedVersion ?? STELLAR_SDK_LAST_TESTED_VERSION) ?? STELLAR_SDK_LAST_TESTED_VERSION;
1054
+ const warnings = [];
1055
+ let status = "supported";
1056
+ if (import_semver4.default.lt(parsed, STELLAR_SDK_MIN_VERSION)) {
1057
+ throw new CaatingaError(
1058
+ `@stellar/stellar-sdk ${input.version} is below the supported minimum ${STELLAR_SDK_MIN_VERSION}.`,
1059
+ CaatingaErrorCode.UNSUPPORTED_SDK_VERSION,
1060
+ `Install @stellar/stellar-sdk ${STELLAR_SDK_MIN_VERSION} or newer.`
1061
+ );
1062
+ }
1063
+ if (import_semver4.default.gt(parsed, lastTestedVersion)) {
1064
+ status = "untested";
1065
+ warnings.push({
1066
+ code: "STELLAR_SDK_UNTESTED_VERSION",
1067
+ message: `@stellar/stellar-sdk ${input.version} is newer than the last-tested ${lastTestedVersion}; binding output may differ.`,
1068
+ remediation: "Pin @stellar/stellar-sdk to the last-tested version in package.json, or update Caatinga fixtures after validating generate output."
1069
+ });
1070
+ }
1071
+ return {
1072
+ version: input.version,
1073
+ status,
1074
+ minVersion: STELLAR_SDK_MIN_VERSION,
1075
+ lastTestedVersion,
1076
+ warnings
1077
+ };
1078
+ }
1079
+ function parseStellarSdkVersion(raw) {
1080
+ const trimmed = raw.trim();
1081
+ const match = trimmed.match(/(\d+\.\d+\.\d+(?:[-+][\w.-]+)?)/);
1082
+ if (!match) {
1083
+ throw new CaatingaError(
1084
+ "Could not parse @stellar/stellar-sdk version.",
1085
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
1086
+ "Expected output like 16.0.1."
1087
+ );
1088
+ }
1089
+ return match[1];
1090
+ }
1091
+
1092
+ // src/stellar-sdk/check-stellar-sdk-version.ts
1093
+ async function readInstalledSdkVersion(cwd) {
1094
+ try {
1095
+ const pkgPath = import_node_path7.default.join(cwd, "node_modules", "@stellar", "stellar-sdk", "package.json");
1096
+ const raw = await (0, import_promises6.readFile)(pkgPath, "utf8");
1097
+ const pkg = JSON.parse(raw);
1098
+ return typeof pkg.version === "string" ? pkg.version : void 0;
1099
+ } catch {
1100
+ return void 0;
1101
+ }
1102
+ }
1103
+ async function resolveRegistrySdkVersion() {
1104
+ const result = await runCommand("npm", ["view", "@stellar/stellar-sdk", "version"], {
1105
+ skipStellarVersionCheck: true
1106
+ });
1107
+ return parseStellarSdkVersion(result.stdout || result.all);
1108
+ }
1109
+ async function checkStellarSdkVersion(input = {}) {
1110
+ const cwd = input.cwd ?? process.cwd();
1111
+ let version;
1112
+ try {
1113
+ const installed = await readInstalledSdkVersion(cwd);
1114
+ version = installed ?? await resolveRegistrySdkVersion();
1115
+ } catch (error) {
1116
+ if (error instanceof CaatingaError) {
1117
+ throw error;
1118
+ }
1119
+ throw new CaatingaError(
1120
+ "Could not resolve @stellar/stellar-sdk version.",
1121
+ CaatingaErrorCode.STELLAR_SDK_VERSION_PARSE_FAILED,
1122
+ "Install @stellar/stellar-sdk in your project or ensure npm registry access.",
1123
+ error
1124
+ );
1125
+ }
1126
+ const report = evaluateStellarSdkCompatibility({
1127
+ version,
1128
+ lastTestedVersion: input.lastTestedVersion
1129
+ });
1130
+ for (const warning of report.warnings) {
1131
+ if (input.onWarning) {
1132
+ input.onWarning(warning);
1133
+ } else {
1134
+ defaultEmitWarning2(warning);
1135
+ }
1136
+ }
1137
+ return report;
1138
+ }
1139
+ function defaultEmitWarning2(warning) {
1140
+ const lines = [
1141
+ `Warning: ${warning.message}`,
1142
+ warning.remediation ? ` ${warning.remediation}` : void 0
1143
+ ].filter((line) => Boolean(line));
1144
+ process.stderr.write(`${lines.join("\n")}
1145
+ `);
1146
+ }
1147
+
855
1148
  // src/stellar-cli/build-stellar-network-args.ts
856
1149
  function matchesWellKnownNetwork(name, config) {
857
1150
  const known = WELL_KNOWN_NETWORKS[name];
@@ -990,7 +1283,7 @@ function validateSourceShape(source) {
990
1283
  }
991
1284
 
992
1285
  // src/contracts/resolve-contract.ts
993
- var import_node_path7 = __toESM(require("path"), 1);
1286
+ var import_node_path8 = __toESM(require("path"), 1);
994
1287
  function resolveContract(config, contractName, cwd = process.cwd()) {
995
1288
  const contract = config.contracts[contractName];
996
1289
  if (!contract) {
@@ -1003,8 +1296,8 @@ function resolveContract(config, contractName, cwd = process.cwd()) {
1003
1296
  return {
1004
1297
  name: contractName,
1005
1298
  config: contract,
1006
- sourcePath: import_node_path7.default.resolve(cwd, contract.path),
1007
- wasmPath: import_node_path7.default.resolve(cwd, contract.wasm)
1299
+ sourcePath: import_node_path8.default.resolve(cwd, contract.path),
1300
+ wasmPath: import_node_path8.default.resolve(cwd, contract.wasm)
1008
1301
  };
1009
1302
  }
1010
1303
 
@@ -1023,8 +1316,8 @@ function resolveDefaultContractName(config) {
1023
1316
 
1024
1317
  // src/contracts/wasm.ts
1025
1318
  var import_node_crypto = require("crypto");
1026
- var import_promises6 = require("fs/promises");
1027
- var import_node_path8 = __toESM(require("path"), 1);
1319
+ var import_promises7 = require("fs/promises");
1320
+ var import_node_path9 = __toESM(require("path"), 1);
1028
1321
  var LEGACY_RUST_WASM_TARGET = "wasm32-unknown-unknown";
1029
1322
  var CURRENT_RUST_WASM_TARGET = "wasm32v1-none";
1030
1323
  function toCurrentWasmTargetPath(wasmPath) {
@@ -1055,18 +1348,18 @@ function wasmNotFoundError(configuredWasmPath, options) {
1055
1348
  );
1056
1349
  }
1057
1350
  function toConfigRelativeWasmPath(absoluteWasmPath) {
1058
- const relative = import_node_path8.default.relative(process.cwd(), absoluteWasmPath);
1059
- return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(import_node_path8.default.sep).join("/")}`;
1351
+ const relative = import_node_path9.default.relative(process.cwd(), absoluteWasmPath);
1352
+ return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(import_node_path9.default.sep).join("/")}`;
1060
1353
  }
1061
1354
  function wasmFileName(configuredWasmPath) {
1062
- return import_node_path8.default.basename(configuredWasmPath);
1355
+ return import_node_path9.default.basename(configuredWasmPath);
1063
1356
  }
1064
1357
  function buildAlternateWasmCandidates(configuredWasmPath, options) {
1065
1358
  const fileName = wasmFileName(configuredWasmPath);
1066
1359
  const candidates = [];
1067
1360
  const seen = /* @__PURE__ */ new Set();
1068
1361
  function addCandidate(candidate) {
1069
- const resolved = import_node_path8.default.resolve(candidate);
1362
+ const resolved = import_node_path9.default.resolve(candidate);
1070
1363
  if (seen.has(resolved)) {
1071
1364
  return;
1072
1365
  }
@@ -1075,15 +1368,15 @@ function buildAlternateWasmCandidates(configuredWasmPath, options) {
1075
1368
  }
1076
1369
  const cargoTargetDir = process.env.CARGO_TARGET_DIR;
1077
1370
  if (cargoTargetDir) {
1078
- addCandidate(import_node_path8.default.join(cargoTargetDir, CURRENT_RUST_WASM_TARGET, "release", fileName));
1079
- addCandidate(import_node_path8.default.join(cargoTargetDir, LEGACY_RUST_WASM_TARGET, "release", fileName));
1371
+ addCandidate(import_node_path9.default.join(cargoTargetDir, CURRENT_RUST_WASM_TARGET, "release", fileName));
1372
+ addCandidate(import_node_path9.default.join(cargoTargetDir, LEGACY_RUST_WASM_TARGET, "release", fileName));
1080
1373
  }
1081
1374
  if (options?.sourcePath) {
1082
1375
  addCandidate(
1083
- import_node_path8.default.join(options.sourcePath, "target", CURRENT_RUST_WASM_TARGET, "release", fileName)
1376
+ import_node_path9.default.join(options.sourcePath, "target", CURRENT_RUST_WASM_TARGET, "release", fileName)
1084
1377
  );
1085
1378
  addCandidate(
1086
- import_node_path8.default.join(options.sourcePath, "target", LEGACY_RUST_WASM_TARGET, "release", fileName)
1379
+ import_node_path9.default.join(options.sourcePath, "target", LEGACY_RUST_WASM_TARGET, "release", fileName)
1087
1380
  );
1088
1381
  }
1089
1382
  return candidates;
@@ -1091,7 +1384,7 @@ function buildAlternateWasmCandidates(configuredWasmPath, options) {
1091
1384
  async function firstExistingPath(paths) {
1092
1385
  for (const candidate of paths) {
1093
1386
  try {
1094
- await (0, import_promises6.access)(candidate);
1387
+ await (0, import_promises7.access)(candidate);
1095
1388
  return candidate;
1096
1389
  } catch {
1097
1390
  continue;
@@ -1100,9 +1393,9 @@ async function firstExistingPath(paths) {
1100
1393
  return void 0;
1101
1394
  }
1102
1395
  async function resolveWasmArtifactPath(configuredWasmPath, options) {
1103
- const resolvedConfiguredPath = import_node_path8.default.resolve(configuredWasmPath);
1396
+ const resolvedConfiguredPath = import_node_path9.default.resolve(configuredWasmPath);
1104
1397
  try {
1105
- await (0, import_promises6.access)(resolvedConfiguredPath);
1398
+ await (0, import_promises7.access)(resolvedConfiguredPath);
1106
1399
  return resolvedConfiguredPath;
1107
1400
  } catch {
1108
1401
  const currentTargetPath = toCurrentWasmTargetPath(resolvedConfiguredPath);
@@ -1124,20 +1417,20 @@ async function resolveWasmArtifactPath(configuredWasmPath, options) {
1124
1417
  }
1125
1418
  }
1126
1419
  async function hashWasm(wasmPath) {
1127
- const bytes = await (0, import_promises6.readFile)(wasmPath);
1420
+ const bytes = await (0, import_promises7.readFile)(wasmPath);
1128
1421
  return (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex");
1129
1422
  }
1130
1423
  async function getNewestMtimeInDirectory(directory) {
1131
1424
  try {
1132
- await (0, import_promises6.access)(directory);
1425
+ await (0, import_promises7.access)(directory);
1133
1426
  } catch {
1134
1427
  return void 0;
1135
1428
  }
1136
1429
  let newest = 0;
1137
1430
  async function walk(dir) {
1138
- const entries = await (0, import_promises6.readdir)(dir, { withFileTypes: true });
1431
+ const entries = await (0, import_promises7.readdir)(dir, { withFileTypes: true });
1139
1432
  for (const entry of entries) {
1140
- const entryPath = import_node_path8.default.join(dir, entry.name);
1433
+ const entryPath = import_node_path9.default.join(dir, entry.name);
1141
1434
  if (entry.isDirectory()) {
1142
1435
  await walk(entryPath);
1143
1436
  continue;
@@ -1145,7 +1438,7 @@ async function getNewestMtimeInDirectory(directory) {
1145
1438
  if (!entry.isFile()) {
1146
1439
  continue;
1147
1440
  }
1148
- const fileStat = await (0, import_promises6.stat)(entryPath);
1441
+ const fileStat = await (0, import_promises7.stat)(entryPath);
1149
1442
  newest = Math.max(newest, fileStat.mtimeMs);
1150
1443
  }
1151
1444
  }
@@ -1153,14 +1446,14 @@ async function getNewestMtimeInDirectory(directory) {
1153
1446
  return newest > 0 ? newest : void 0;
1154
1447
  }
1155
1448
  async function isWasmOlderThanSources(input) {
1156
- const srcDir = import_node_path8.default.join(input.contractPath, "src");
1449
+ const srcDir = import_node_path9.default.join(input.contractPath, "src");
1157
1450
  const newestSourceMtime = await getNewestMtimeInDirectory(srcDir);
1158
1451
  if (newestSourceMtime === void 0) {
1159
1452
  return false;
1160
1453
  }
1161
1454
  let wasmStat;
1162
1455
  try {
1163
- wasmStat = await (0, import_promises6.stat)(input.wasmPath);
1456
+ wasmStat = await (0, import_promises7.stat)(input.wasmPath);
1164
1457
  } catch {
1165
1458
  return false;
1166
1459
  }
@@ -1228,7 +1521,38 @@ async function buildContract(options) {
1228
1521
  }
1229
1522
 
1230
1523
  // src/contracts/deploy-contract.ts
1231
- var import_node_path9 = __toESM(require("path"), 1);
1524
+ var import_node_path10 = __toESM(require("path"), 1);
1525
+
1526
+ // src/shell/is-transient-command-failure.ts
1527
+ var NO_RETRY_CAATINGA_SUBSTRINGS = [
1528
+ "CAATINGA_UNSUPPORTED_CLI_VERSION",
1529
+ "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
1530
+ "CAATINGA_STELLAR_CLI_NOT_FOUND",
1531
+ "CAATINGA_INVALID_CONFIG",
1532
+ "CAATINGA_CONFIG_NOT_FOUND"
1533
+ ];
1534
+ var TRANSIENT_COMMAND_FAILURE_PATTERN = /timeout|i\/o timeout|econnreset|connection reset|503|502|429|rate limit|temporar|bad gateway|fetch failed|network error|unavailable/i;
1535
+ function isTransientCommandFailure(logText) {
1536
+ if (!logText.trim()) {
1537
+ return false;
1538
+ }
1539
+ for (const marker of NO_RETRY_CAATINGA_SUBSTRINGS) {
1540
+ if (logText.includes(marker)) {
1541
+ return false;
1542
+ }
1543
+ }
1544
+ return TRANSIENT_COMMAND_FAILURE_PATTERN.test(logText);
1545
+ }
1546
+
1547
+ // src/contracts/is-transient-deploy-failure.ts
1548
+ function isTransientDeployFailure(error) {
1549
+ if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1550
+ return false;
1551
+ }
1552
+ const logText = `${error.message}
1553
+ ${error.hint ?? ""}`;
1554
+ return isTransientCommandFailure(logText);
1555
+ }
1232
1556
 
1233
1557
  // src/contracts/dependency-graph.ts
1234
1558
  function buildDependencyGraph(contracts) {
@@ -1290,6 +1614,12 @@ function resolveCliSource(explicit) {
1290
1614
  }
1291
1615
 
1292
1616
  // src/contracts/deploy-contract.ts
1617
+ var DEFAULT_DEPLOY_RETRY_DELAYS_MS = [2e3, 5e3];
1618
+ function sleep(ms) {
1619
+ return new Promise((resolve) => {
1620
+ setTimeout(resolve, ms);
1621
+ });
1622
+ }
1293
1623
  function toSnakeCaseFlag(key) {
1294
1624
  return key.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
1295
1625
  }
@@ -1334,7 +1664,7 @@ async function deployContract(options) {
1334
1664
  contract: contractWithWasm,
1335
1665
  network,
1336
1666
  contractId: existing.contractId,
1337
- artifactsPath: import_node_path9.default.resolve(cwd, "caatinga.artifacts.json"),
1667
+ artifactsPath: import_node_path10.default.resolve(cwd, "caatinga.artifacts.json"),
1338
1668
  output: "",
1339
1669
  skipped: true,
1340
1670
  staleWasmWarning
@@ -1374,40 +1704,69 @@ async function deployContract(options) {
1374
1704
  ...buildStellarNetworkArgs(network),
1375
1705
  ...constructorArgs
1376
1706
  ];
1377
- let output = "";
1378
- let contractId;
1379
- try {
1380
- const result = await runCommand("stellar", stellarArgs, {
1381
- cwd,
1382
- failureCode: CaatingaErrorCode.DEPLOY_FAILED
1383
- });
1384
- output = result.all || `${result.stdout}
1707
+ let deployOutcome;
1708
+ const retryDelaysMs = options.deployRetryDelaysMs ?? DEFAULT_DEPLOY_RETRY_DELAYS_MS;
1709
+ const maxDeployAttempts = retryDelaysMs.length + 1;
1710
+ for (let attempt = 0; attempt < maxDeployAttempts; attempt++) {
1711
+ try {
1712
+ const result = await runCommand("stellar", stellarArgs, {
1713
+ cwd,
1714
+ failureCode: CaatingaErrorCode.DEPLOY_FAILED
1715
+ });
1716
+ const output2 = result.all || `${result.stdout}
1385
1717
  ${result.stderr}`;
1386
- contractId = parseContractId(output);
1387
- } catch (error) {
1388
- if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1389
- throw error;
1390
- }
1391
- const recoveredContractId = await tryRecoverContractIdFromDeployFailure({
1392
- output: `${error.message}
1718
+ deployOutcome = {
1719
+ output: output2,
1720
+ contractId: parseContractId(output2)
1721
+ };
1722
+ break;
1723
+ } catch (error) {
1724
+ if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
1725
+ throw error;
1726
+ }
1727
+ const recoveredContractId = await tryRecoverContractIdFromDeployFailure({
1728
+ output: `${error.message}
1393
1729
  ${error.hint ?? ""}`,
1394
- source,
1395
- network: network.config,
1396
- cwd
1397
- });
1398
- if (!recoveredContractId) {
1399
- throw error;
1730
+ source,
1731
+ network: network.config,
1732
+ cwd
1733
+ });
1734
+ if (recoveredContractId) {
1735
+ deployOutcome = {
1736
+ output: [
1737
+ error.hint ?? "",
1738
+ "Caatinga recovered the contract ID from the on-chain deploy transaction.",
1739
+ `Contract ID: ${recoveredContractId}`
1740
+ ].filter(Boolean).join("\n"),
1741
+ contractId: recoveredContractId
1742
+ };
1743
+ break;
1744
+ }
1745
+ const isLastAttempt = attempt === maxDeployAttempts - 1;
1746
+ if (!isTransientDeployFailure(error) || isLastAttempt) {
1747
+ throw error;
1748
+ }
1749
+ const delayMs = retryDelaysMs[attempt] ?? retryDelaysMs[retryDelaysMs.length - 1] ?? 0;
1750
+ options.onTransientDeployRetry?.({
1751
+ attempt: attempt + 1,
1752
+ maxAttempts: maxDeployAttempts,
1753
+ delayMs
1754
+ });
1755
+ await sleep(delayMs);
1400
1756
  }
1401
- contractId = recoveredContractId;
1402
- output = [
1403
- error.hint ?? "",
1404
- "Caatinga recovered the contract ID from the on-chain deploy transaction.",
1405
- `Contract ID: ${contractId}`
1406
- ].filter(Boolean).join("\n");
1407
1757
  }
1758
+ if (!deployOutcome) {
1759
+ throw new CaatingaError(
1760
+ "Deploy failed without a contract ID.",
1761
+ CaatingaErrorCode.DEPLOY_FAILED,
1762
+ "Re-run the deploy command with the underlying Stellar CLI for full diagnostics."
1763
+ );
1764
+ }
1765
+ const { output, contractId } = deployOutcome;
1408
1766
  const wasmHash = await hashWasm(wasmPath);
1409
1767
  const dependencyGraph = buildDependencyGraph(options.config.contracts);
1410
1768
  const dependencies = options.dependencies ?? contract.config.dependsOn;
1769
+ const supersedeReason = existing?.contractId && options.force ? options.upgrade ? "upgrade" : "force-redeploy" : void 0;
1411
1770
  const nextArtifacts = updateArtifact(
1412
1771
  artifactsBefore,
1413
1772
  network.name,
@@ -1421,7 +1780,7 @@ ${error.hint ?? ""}`,
1421
1780
  dependencies,
1422
1781
  resolvedDeployArgs
1423
1782
  },
1424
- { dependencyGraph }
1783
+ { dependencyGraph, supersedeReason }
1425
1784
  );
1426
1785
  const artifactsPath = await writeArtifacts(nextArtifacts, cwd);
1427
1786
  return {
@@ -1585,9 +1944,11 @@ async function deployContractGraph(options) {
1585
1944
  source: options.source,
1586
1945
  cwd,
1587
1946
  force: options.force,
1947
+ upgrade: options.upgrade,
1588
1948
  checkStaleWasm: options.checkStaleWasm,
1589
1949
  resolvedDeployArgs,
1590
- dependencies: contractConfig.dependsOn
1950
+ dependencies: contractConfig.dependsOn,
1951
+ onTransientDeployRetry: options.onTransientDeployRetry
1591
1952
  });
1592
1953
  if (result.staleWasmWarning) {
1593
1954
  staleWasmWarnings.push({
@@ -1610,12 +1971,12 @@ async function deployContractGraph(options) {
1610
1971
  }
1611
1972
 
1612
1973
  // src/contracts/generate-bindings.ts
1613
- var import_promises8 = require("fs/promises");
1614
- var import_node_path11 = __toESM(require("path"), 1);
1974
+ var import_promises9 = require("fs/promises");
1975
+ var import_node_path12 = __toESM(require("path"), 1);
1615
1976
 
1616
1977
  // src/bindings/patch-generated-binding-package.ts
1617
- var import_promises7 = require("fs/promises");
1618
- var import_node_path10 = __toESM(require("path"), 1);
1978
+ var import_promises8 = require("fs/promises");
1979
+ var import_node_path11 = __toESM(require("path"), 1);
1619
1980
  var BUNDLER_ENTRY = "./src/index.ts";
1620
1981
  var ROOT_BINDING_INDEX_CONTENT = 'export * from "./src/index.js";\n';
1621
1982
  function resolveExportEntry(exportsField) {
@@ -1650,22 +2011,22 @@ function shouldPatchPackageJson(packageJson) {
1650
2011
  return pointsToDist(packageJson.main) || pointsToDist(packageJson.types) || !pointsToBundlerSource(exportEntry);
1651
2012
  }
1652
2013
  async function ensureRootBindingIndex(outputDir) {
1653
- const rootIndexPath = import_node_path10.default.join(outputDir, "index.ts");
2014
+ const rootIndexPath = import_node_path11.default.join(outputDir, "index.ts");
1654
2015
  try {
1655
- const existing = await (0, import_promises7.readFile)(rootIndexPath, "utf8");
2016
+ const existing = await (0, import_promises8.readFile)(rootIndexPath, "utf8");
1656
2017
  if (existing === ROOT_BINDING_INDEX_CONTENT) {
1657
2018
  return;
1658
2019
  }
1659
2020
  return;
1660
2021
  } catch {
1661
- await (0, import_promises7.writeFile)(rootIndexPath, ROOT_BINDING_INDEX_CONTENT, "utf8");
2022
+ await (0, import_promises8.writeFile)(rootIndexPath, ROOT_BINDING_INDEX_CONTENT, "utf8");
1662
2023
  }
1663
2024
  }
1664
2025
  async function patchGeneratedBindingPackage(outputDir) {
1665
- const packageJsonPath = import_node_path10.default.join(outputDir, "package.json");
1666
- const entryPath = import_node_path10.default.join(outputDir, "src", "index.ts");
2026
+ const packageJsonPath = import_node_path11.default.join(outputDir, "package.json");
2027
+ const entryPath = import_node_path11.default.join(outputDir, "src", "index.ts");
1667
2028
  try {
1668
- await (0, import_promises7.access)(entryPath);
2029
+ await (0, import_promises8.access)(entryPath);
1669
2030
  } catch {
1670
2031
  throw new CaatingaError(
1671
2032
  "Generated binding package is missing src/index.ts.",
@@ -1675,7 +2036,7 @@ async function patchGeneratedBindingPackage(outputDir) {
1675
2036
  }
1676
2037
  let raw;
1677
2038
  try {
1678
- raw = await (0, import_promises7.readFile)(packageJsonPath, "utf8");
2039
+ raw = await (0, import_promises8.readFile)(packageJsonPath, "utf8");
1679
2040
  } catch {
1680
2041
  throw new CaatingaError(
1681
2042
  "Generated binding package is missing package.json.",
@@ -1700,7 +2061,7 @@ async function patchGeneratedBindingPackage(outputDir) {
1700
2061
  ...typeof packageJson.exports === "object" && packageJson.exports !== null && !Array.isArray(packageJson.exports) ? packageJson.exports : {},
1701
2062
  ".": BUNDLER_ENTRY
1702
2063
  };
1703
- await (0, import_promises7.writeFile)(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
2064
+ await (0, import_promises8.writeFile)(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
1704
2065
  `, "utf8");
1705
2066
  }
1706
2067
  await ensureRootBindingIndex(outputDir);
@@ -1716,14 +2077,14 @@ function buildGenerateNetworkArgs(network) {
1716
2077
 
1717
2078
  // src/contracts/generate-bindings.ts
1718
2079
  function toBindingImportPath(bindingsOutput, contractName) {
1719
- const normalized = bindingsOutput.replace(/^\.\//, "").split(import_node_path11.default.sep).join("/");
1720
- return `./${import_node_path11.default.posix.join(normalized, contractName)}`;
2080
+ const normalized = bindingsOutput.replace(/^\.\//, "").split(import_node_path12.default.sep).join("/");
2081
+ return `./${import_node_path12.default.posix.join(normalized, contractName)}`;
1721
2082
  }
1722
2083
  async function removeLegacyBindingStub(cwd, bindingsOutput, contractName) {
1723
- const legacyPath = import_node_path11.default.resolve(cwd, bindingsOutput, `${contractName}.ts`);
2084
+ const legacyPath = import_node_path12.default.resolve(cwd, bindingsOutput, `${contractName}.ts`);
1724
2085
  try {
1725
- await (0, import_promises8.access)(legacyPath);
1726
- await (0, import_promises8.unlink)(legacyPath);
2086
+ await (0, import_promises9.access)(legacyPath);
2087
+ await (0, import_promises9.unlink)(legacyPath);
1727
2088
  return true;
1728
2089
  } catch {
1729
2090
  return false;
@@ -1748,8 +2109,9 @@ async function generateBindings(options) {
1748
2109
  "Run caatinga deploy for this contract and network before generating bindings."
1749
2110
  );
1750
2111
  }
1751
- const outputDir = import_node_path11.default.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
1752
- await (0, import_promises8.mkdir)(outputDir, { recursive: true });
2112
+ const outputDir = import_node_path12.default.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
2113
+ await (0, import_promises9.mkdir)(outputDir, { recursive: true });
2114
+ await checkStellarSdkVersion({ cwd });
1753
2115
  const result = await runCommand(
1754
2116
  "npx",
1755
2117
  [
@@ -1974,14 +2336,172 @@ async function readContract(options) {
1974
2336
  };
1975
2337
  }
1976
2338
 
2339
+ // src/contracts/estimate-deploy-cost.ts
2340
+ var import_node_path13 = __toESM(require("path"), 1);
2341
+ function toSnakeCaseFlag2(key) {
2342
+ return key.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
2343
+ }
2344
+ function formatConstructorCliArgs2(resolved) {
2345
+ const entries = Object.entries(resolved);
2346
+ if (entries.length === 0) {
2347
+ return [];
2348
+ }
2349
+ const tail = ["--"];
2350
+ for (const [key, value] of entries) {
2351
+ tail.push(`--${toSnakeCaseFlag2(key)}`, String(value));
2352
+ }
2353
+ return tail;
2354
+ }
2355
+ function parseFeeStroops(output) {
2356
+ const inclusionMatch = output.match(/inclusion[_\s-]*fee[:\s]+(\d+)/i);
2357
+ const resourceMatch = output.match(/resource[_\s-]*fee[:\s]+(\d+)/i);
2358
+ const totalMatch = output.match(/total[_\s-]*fee[:\s]+(\d+)/i);
2359
+ return {
2360
+ inclusion: inclusionMatch ? Number(inclusionMatch[1]) : void 0,
2361
+ resource: resourceMatch ? Number(resourceMatch[1]) : void 0,
2362
+ ...totalMatch && !resourceMatch ? { resource: Number(totalMatch[1]) } : {}
2363
+ };
2364
+ }
2365
+ async function estimateDeployCost(options) {
2366
+ const cwd = options.cwd ?? process.cwd();
2367
+ const contract = resolveContract(options.config, options.contractName, cwd);
2368
+ const network = resolveNetwork(options.config, options.networkName);
2369
+ const source = assertSafeSourceAccount(options.source);
2370
+ await checkBinary("stellar", "Install Stellar CLI before running caatinga estimate.");
2371
+ const wasmPath = await resolveWasmArtifactPath(contract.wasmPath, {
2372
+ sourcePath: contract.sourcePath
2373
+ });
2374
+ const artifacts = await readArtifacts(cwd);
2375
+ const rawDeployArgs = contract.config.deployArgs;
2376
+ const resolvedDeployArgs = Object.keys(rawDeployArgs).length > 0 ? resolveDeployArgs({
2377
+ deployArgs: rawDeployArgs,
2378
+ artifacts,
2379
+ network: network.name
2380
+ }) : {};
2381
+ const constructorArgs = formatConstructorCliArgs2(resolvedDeployArgs);
2382
+ const deployArgs = [
2383
+ "contract",
2384
+ "deploy",
2385
+ "--wasm",
2386
+ wasmPath,
2387
+ "--source-account",
2388
+ source,
2389
+ "--build-only",
2390
+ ...buildStellarNetworkArgs(network),
2391
+ ...constructorArgs
2392
+ ];
2393
+ let buildOutput;
2394
+ try {
2395
+ const buildResult = await runCommand("stellar", deployArgs, {
2396
+ cwd,
2397
+ failureCode: CaatingaErrorCode.ESTIMATE_FAILED
2398
+ });
2399
+ buildOutput = (buildResult.stdout || buildResult.all).trim();
2400
+ } catch (error) {
2401
+ if (error instanceof CaatingaError) {
2402
+ throw new CaatingaError(
2403
+ `Deploy cost estimate failed for "${contract.name}".`,
2404
+ CaatingaErrorCode.ESTIMATE_FAILED,
2405
+ error.hint ?? "Ensure WASM is built and deploy args resolve correctly.",
2406
+ error.cause
2407
+ );
2408
+ }
2409
+ throw error;
2410
+ }
2411
+ const simulateArgs = ["tx", "simulate", "--source-account", source, buildOutput];
2412
+ let simulateOutput = "";
2413
+ try {
2414
+ const simulateResult = await runCommand("stellar", simulateArgs, {
2415
+ cwd,
2416
+ failureCode: CaatingaErrorCode.ESTIMATE_FAILED
2417
+ });
2418
+ simulateOutput = simulateResult.all || `${simulateResult.stdout}
2419
+ ${simulateResult.stderr}`;
2420
+ } catch {
2421
+ simulateOutput = "";
2422
+ }
2423
+ const parsed = parseFeeStroops(simulateOutput);
2424
+ const inclusionFeeStroops = parsed.inclusion ?? 100;
2425
+ const resourceFeeStroops = parsed.resource;
2426
+ const totalFeeStroops = inclusionFeeStroops + (resourceFeeStroops ?? 0);
2427
+ return {
2428
+ contractName: contract.name,
2429
+ network: network.name,
2430
+ wasmPath: import_node_path13.default.relative(cwd, wasmPath) || wasmPath,
2431
+ inclusionFeeStroops,
2432
+ resourceFeeStroops,
2433
+ totalFeeStroops,
2434
+ advisory: "Advisory estimate only \u2014 actual fees may differ under network congestion or contract complexity.",
2435
+ rawOutput: simulateOutput || buildOutput
2436
+ };
2437
+ }
2438
+
2439
+ // src/contracts/inspect-contract.ts
2440
+ async function inspectContract(options) {
2441
+ const cwd = options.cwd ?? process.cwd();
2442
+ const contract = resolveContract(options.config, options.contractName, cwd);
2443
+ const network = resolveNetwork(options.config, options.networkName);
2444
+ const artifacts = await readArtifacts(cwd);
2445
+ const artifact = artifacts.networks[network.name]?.contracts[contract.name];
2446
+ if (!artifact) {
2447
+ throw new CaatingaError(
2448
+ `No deployed artifact found for "${contract.name}" on "${network.name}".`,
2449
+ CaatingaErrorCode.ARTIFACT_NOT_FOUND,
2450
+ "Run caatinga deploy before inspect."
2451
+ );
2452
+ }
2453
+ await checkBinary("stellar", "Install Stellar CLI before running caatinga inspect.");
2454
+ let reachable = false;
2455
+ let detail;
2456
+ try {
2457
+ await verifyDependencyContract({
2458
+ dependencyName: contract.name,
2459
+ contractId: artifact.contractId,
2460
+ network,
2461
+ cwd
2462
+ });
2463
+ reachable = true;
2464
+ detail = "Contract interface reachable on network.";
2465
+ } catch (error) {
2466
+ reachable = false;
2467
+ detail = error instanceof CaatingaError ? error.message : "Contract not reachable on network.";
2468
+ }
2469
+ let localHash;
2470
+ try {
2471
+ const wasmPath = await resolveWasmArtifactPath(contract.wasmPath, {
2472
+ sourcePath: contract.sourcePath
2473
+ });
2474
+ localHash = await hashWasm(wasmPath);
2475
+ } catch {
2476
+ localHash = void 0;
2477
+ }
2478
+ return {
2479
+ contractName: contract.name,
2480
+ network: network.name,
2481
+ artifact: {
2482
+ contractId: artifact.contractId,
2483
+ wasmHash: artifact.wasmHash,
2484
+ deployedAt: artifact.deployedAt,
2485
+ historyCount: artifact.history?.length ?? 0
2486
+ },
2487
+ onChain: { reachable, detail },
2488
+ localWasm: {
2489
+ path: contract.config.wasm,
2490
+ hash: localHash,
2491
+ matchesArtifact: Boolean(localHash && localHash === artifact.wasmHash)
2492
+ },
2493
+ dependencies: artifact.dependencies ?? contract.config.dependsOn ?? []
2494
+ };
2495
+ }
2496
+
1977
2497
  // src/templates/create-project-from-template.ts
1978
- var import_promises9 = require("fs/promises");
1979
- var import_node_path12 = __toESM(require("path"), 1);
2498
+ var import_promises10 = require("fs/promises");
2499
+ var import_node_path14 = __toESM(require("path"), 1);
1980
2500
  var import_zod7 = require("zod");
1981
2501
 
1982
2502
  // src/templates/template-manifest.schema.ts
1983
2503
  var import_zod6 = require("zod");
1984
- var import_semver3 = __toESM(require("semver"), 1);
2504
+ var import_semver5 = __toESM(require("semver"), 1);
1985
2505
  var CURRENT_TEMPLATE_VERSION = 1;
1986
2506
  var TemplateManifestSchema = import_zod6.z.object({
1987
2507
  name: import_zod6.z.string().min(1),
@@ -2005,14 +2525,14 @@ var TemplateManifestSchema = import_zod6.z.object({
2005
2525
  })
2006
2526
  });
2007
2527
  function defaultCompatibleCoreRange(coreVersion = CAATINGA_CORE_VERSION) {
2008
- const version = import_semver3.default.valid(import_semver3.default.coerce(coreVersion));
2528
+ const version = import_semver5.default.valid(import_semver5.default.coerce(coreVersion));
2009
2529
  if (!version) {
2010
2530
  throw new Error(`Invalid core version: ${coreVersion}`);
2011
2531
  }
2012
2532
  return `^${version}`;
2013
2533
  }
2014
2534
  function isCoreVersionCompatible(range, coreVersion = CAATINGA_CORE_VERSION) {
2015
- return import_semver3.default.satisfies(coreVersion, range);
2535
+ return import_semver5.default.satisfies(coreVersion, range);
2016
2536
  }
2017
2537
  function getTemplateCompatibilityIssue(manifest, coreVersion = CAATINGA_CORE_VERSION) {
2018
2538
  if (manifest.caatinga.templateVersion !== CURRENT_TEMPLATE_VERSION) {
@@ -2047,10 +2567,10 @@ function formatTemplateCompatibilityHint(issue) {
2047
2567
  // src/templates/create-project-from-template.ts
2048
2568
  var TEMPLATE_COPY_EXCLUDED_DIRS = /* @__PURE__ */ new Set(["target", "test_snapshots", "node_modules", ".git"]);
2049
2569
  async function createProjectFromTemplate(options) {
2050
- const targetDir = import_node_path12.default.resolve(options.targetDir);
2051
- const templateDir = import_node_path12.default.resolve(options.templateDir);
2570
+ const targetDir = import_node_path14.default.resolve(options.targetDir);
2571
+ const templateDir = import_node_path14.default.resolve(options.templateDir);
2052
2572
  try {
2053
- await (0, import_promises9.stat)(templateDir);
2573
+ await (0, import_promises10.stat)(templateDir);
2054
2574
  } catch {
2055
2575
  throw new CaatingaError(
2056
2576
  `Template directory was not found: ${templateDir}`,
@@ -2060,8 +2580,8 @@ async function createProjectFromTemplate(options) {
2060
2580
  }
2061
2581
  const manifest = await readTemplateManifest(templateDir);
2062
2582
  const mergeIntoExisting = Boolean(options.filter);
2063
- await (0, import_promises9.mkdir)(targetDir, { recursive: true });
2064
- await (0, import_promises9.cp)(templateDir, targetDir, {
2583
+ await (0, import_promises10.mkdir)(targetDir, { recursive: true });
2584
+ await (0, import_promises10.cp)(templateDir, targetDir, {
2065
2585
  recursive: true,
2066
2586
  force: true,
2067
2587
  errorOnExist: false,
@@ -2089,9 +2609,9 @@ async function ensureArtifacts(targetDir, projectName) {
2089
2609
  }
2090
2610
  }
2091
2611
  async function readTemplateManifest(templateDir) {
2092
- const manifestPath = import_node_path12.default.join(templateDir, "caatinga.template.json");
2612
+ const manifestPath = import_node_path14.default.join(templateDir, "caatinga.template.json");
2093
2613
  try {
2094
- const rawManifest = await (0, import_promises9.readFile)(manifestPath, "utf8");
2614
+ const rawManifest = await (0, import_promises10.readFile)(manifestPath, "utf8");
2095
2615
  const manifest = TemplateManifestSchema.parse(JSON.parse(rawManifest));
2096
2616
  const compatibilityIssue = getTemplateCompatibilityIssue(manifest);
2097
2617
  if (compatibilityIssue) {
@@ -2124,11 +2644,11 @@ async function readTemplateManifest(templateDir) {
2124
2644
  }
2125
2645
  }
2126
2646
  async function replaceTemplateVariables(dir, projectName) {
2127
- const entries = await (0, import_promises9.readdir)(dir);
2647
+ const entries = await (0, import_promises10.readdir)(dir);
2128
2648
  await Promise.all(
2129
2649
  entries.map(async (entry) => {
2130
- const entryPath = import_node_path12.default.join(dir, entry);
2131
- const entryStat = await (0, import_promises9.stat)(entryPath);
2650
+ const entryPath = import_node_path14.default.join(dir, entry);
2651
+ const entryStat = await (0, import_promises10.stat)(entryPath);
2132
2652
  if (entryStat.isDirectory()) {
2133
2653
  await replaceTemplateVariables(entryPath, projectName);
2134
2654
  return;
@@ -2136,39 +2656,39 @@ async function replaceTemplateVariables(dir, projectName) {
2136
2656
  if (!isTextTemplateFile(entryPath)) {
2137
2657
  return;
2138
2658
  }
2139
- const content = await (0, import_promises9.readFile)(entryPath, "utf8");
2140
- await (0, import_promises9.writeFile)(entryPath, content.replaceAll("__PROJECT_NAME__", projectName), "utf8");
2659
+ const content = await (0, import_promises10.readFile)(entryPath, "utf8");
2660
+ await (0, import_promises10.writeFile)(entryPath, content.replaceAll("__PROJECT_NAME__", projectName), "utf8");
2141
2661
  })
2142
2662
  );
2143
2663
  }
2144
2664
  function shouldCopyTemplateEntry(templateDir, source, userFilter) {
2145
- const relativePath = import_node_path12.default.relative(templateDir, source);
2665
+ const relativePath = import_node_path14.default.relative(templateDir, source);
2146
2666
  if (!relativePath || relativePath === ".") {
2147
2667
  return true;
2148
2668
  }
2149
- const normalizedPath = relativePath.split(import_node_path12.default.sep).join("/");
2669
+ const normalizedPath = relativePath.split(import_node_path14.default.sep).join("/");
2150
2670
  if (userFilter && !userFilter(normalizedPath)) {
2151
2671
  return false;
2152
2672
  }
2153
- return !relativePath.split(import_node_path12.default.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
2673
+ return !relativePath.split(import_node_path14.default.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
2154
2674
  }
2155
2675
  function isTextTemplateFile(filePath) {
2156
2676
  return [".json", ".md", ".rs", ".toml", ".ts", ".tsx", ".css", ".html"].includes(
2157
- import_node_path12.default.extname(filePath)
2677
+ import_node_path14.default.extname(filePath)
2158
2678
  );
2159
2679
  }
2160
2680
 
2161
2681
  // src/scaffold/create-zk-project.ts
2162
- var import_promises10 = require("fs/promises");
2682
+ var import_promises11 = require("fs/promises");
2163
2683
  var import_node_fs2 = require("fs");
2164
- var import_node_path13 = __toESM(require("path"), 1);
2684
+ var import_node_path15 = __toESM(require("path"), 1);
2165
2685
  var import_node_url = require("url");
2166
2686
  var import_meta3 = {};
2167
- var moduleDir = typeof __dirname === "string" ? __dirname : import_node_path13.default.dirname((0, import_node_url.fileURLToPath)(import_meta3.url));
2687
+ var moduleDir = typeof __dirname === "string" ? __dirname : import_node_path15.default.dirname((0, import_node_url.fileURLToPath)(import_meta3.url));
2168
2688
  function scaffoldRoot() {
2169
2689
  const candidates = [
2170
- import_node_path13.default.resolve(moduleDir, "../../scaffolds"),
2171
- import_node_path13.default.resolve(moduleDir, "../scaffolds")
2690
+ import_node_path15.default.resolve(moduleDir, "../../scaffolds"),
2691
+ import_node_path15.default.resolve(moduleDir, "../scaffolds")
2172
2692
  ];
2173
2693
  const found = candidates.find((candidate) => (0, import_node_fs2.existsSync)(candidate));
2174
2694
  return found ?? candidates[0];
@@ -2259,39 +2779,39 @@ Replace \`circuits/main.circom\` with your circuit. Keep the entry point named \
2259
2779
  `;
2260
2780
  }
2261
2781
  async function createZkProject(options) {
2262
- const targetDir = import_node_path13.default.resolve(options.targetDir);
2782
+ const targetDir = import_node_path15.default.resolve(options.targetDir);
2263
2783
  const force = options.force ?? false;
2264
2784
  const projectFiles = options.projectFiles ?? true;
2265
- await (0, import_promises10.mkdir)(targetDir, { recursive: true });
2785
+ await (0, import_promises11.mkdir)(targetDir, { recursive: true });
2266
2786
  if (projectFiles) {
2267
2787
  await Promise.all([
2268
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), {
2788
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), {
2269
2789
  encoding: "utf8",
2270
2790
  flag: force ? "w" : "wx"
2271
2791
  }),
2272
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, "package.json"), packageJsonSource(options.projectName), {
2792
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, "package.json"), packageJsonSource(options.projectName), {
2273
2793
  encoding: "utf8",
2274
2794
  flag: force ? "w" : "wx"
2275
2795
  }),
2276
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2796
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2277
2797
  encoding: "utf8",
2278
2798
  flag: force ? "w" : "wx"
2279
2799
  }),
2280
- (0, import_promises10.writeFile)(import_node_path13.default.join(targetDir, "README.md"), readmeSource(options.projectName), {
2800
+ (0, import_promises11.writeFile)(import_node_path15.default.join(targetDir, "README.md"), readmeSource(options.projectName), {
2281
2801
  encoding: "utf8",
2282
2802
  flag: force ? "w" : "wx"
2283
2803
  })
2284
2804
  ]);
2285
2805
  }
2286
- await (0, import_promises10.mkdir)(import_node_path13.default.join(targetDir, "contracts"), { recursive: true });
2287
- await (0, import_promises10.cp)(import_node_path13.default.join(scaffoldRoot(), "zk-circuit-stub"), import_node_path13.default.join(targetDir, "circuits"), {
2806
+ await (0, import_promises11.mkdir)(import_node_path15.default.join(targetDir, "contracts"), { recursive: true });
2807
+ await (0, import_promises11.cp)(import_node_path15.default.join(scaffoldRoot(), "zk-circuit-stub"), import_node_path15.default.join(targetDir, "circuits"), {
2288
2808
  recursive: true,
2289
2809
  force,
2290
2810
  errorOnExist: !force
2291
2811
  });
2292
- await (0, import_promises10.cp)(
2293
- import_node_path13.default.join(scaffoldRoot(), "zk-verifier"),
2294
- import_node_path13.default.join(targetDir, "contracts", "verifier"),
2812
+ await (0, import_promises11.cp)(
2813
+ import_node_path15.default.join(scaffoldRoot(), "zk-verifier"),
2814
+ import_node_path15.default.join(targetDir, "contracts", "verifier"),
2295
2815
  {
2296
2816
  recursive: true,
2297
2817
  force,
@@ -2308,16 +2828,16 @@ async function createZkProject(options) {
2308
2828
  }
2309
2829
 
2310
2830
  // src/scaffold/create-minimal-project.ts
2311
- var import_promises11 = require("fs/promises");
2831
+ var import_promises12 = require("fs/promises");
2312
2832
  var import_node_fs3 = require("fs");
2313
- var import_node_path14 = __toESM(require("path"), 1);
2833
+ var import_node_path16 = __toESM(require("path"), 1);
2314
2834
  var import_node_url2 = require("url");
2315
2835
  var import_meta4 = {};
2316
- var moduleDir2 = typeof __dirname === "string" ? __dirname : import_node_path14.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
2836
+ var moduleDir2 = typeof __dirname === "string" ? __dirname : import_node_path16.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
2317
2837
  function scaffoldRoot2() {
2318
2838
  const candidates = [
2319
- import_node_path14.default.resolve(moduleDir2, "../../scaffolds"),
2320
- import_node_path14.default.resolve(moduleDir2, "../scaffolds")
2839
+ import_node_path16.default.resolve(moduleDir2, "../../scaffolds"),
2840
+ import_node_path16.default.resolve(moduleDir2, "../scaffolds")
2321
2841
  ];
2322
2842
  const found = candidates.find((candidate) => (0, import_node_fs3.existsSync)(candidate));
2323
2843
  return found ?? candidates[0];
@@ -2408,31 +2928,31 @@ Edit \`contracts/app/src/lib.rs\` to customize the contract. Add a frontend late
2408
2928
  `;
2409
2929
  }
2410
2930
  async function createMinimalProject(options) {
2411
- const targetDir = import_node_path14.default.resolve(options.targetDir);
2931
+ const targetDir = import_node_path16.default.resolve(options.targetDir);
2412
2932
  const force = options.force ?? false;
2413
- await (0, import_promises11.mkdir)(targetDir, { recursive: true });
2933
+ await (0, import_promises12.mkdir)(targetDir, { recursive: true });
2414
2934
  await Promise.all([
2415
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, "caatinga.config.ts"), configSource2(options.projectName), {
2935
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, "caatinga.config.ts"), configSource2(options.projectName), {
2416
2936
  encoding: "utf8",
2417
2937
  flag: force ? "w" : "wx"
2418
2938
  }),
2419
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, "package.json"), packageJsonSource2(options.projectName), {
2939
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, "package.json"), packageJsonSource2(options.projectName), {
2420
2940
  encoding: "utf8",
2421
2941
  flag: force ? "w" : "wx"
2422
2942
  }),
2423
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2943
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", {
2424
2944
  encoding: "utf8",
2425
2945
  flag: force ? "w" : "wx"
2426
2946
  }),
2427
- (0, import_promises11.writeFile)(import_node_path14.default.join(targetDir, "README.md"), readmeSource2(options.projectName), {
2947
+ (0, import_promises12.writeFile)(import_node_path16.default.join(targetDir, "README.md"), readmeSource2(options.projectName), {
2428
2948
  encoding: "utf8",
2429
2949
  flag: force ? "w" : "wx"
2430
2950
  })
2431
2951
  ]);
2432
- await (0, import_promises11.mkdir)(import_node_path14.default.join(targetDir, "contracts"), { recursive: true });
2433
- await (0, import_promises11.cp)(
2434
- import_node_path14.default.join(scaffoldRoot2(), "soroban-contract-stub"),
2435
- import_node_path14.default.join(targetDir, "contracts", "app"),
2952
+ await (0, import_promises12.mkdir)(import_node_path16.default.join(targetDir, "contracts"), { recursive: true });
2953
+ await (0, import_promises12.cp)(
2954
+ import_node_path16.default.join(scaffoldRoot2(), "soroban-contract-stub"),
2955
+ import_node_path16.default.join(targetDir, "contracts", "app"),
2436
2956
  {
2437
2957
  recursive: true,
2438
2958
  force,
@@ -2447,30 +2967,15 @@ async function createMinimalProject(options) {
2447
2967
  }
2448
2968
 
2449
2969
  // src/ci/is-transient-testnet-smoke-failure.ts
2450
- var NO_RETRY_CAATINGA_SUBSTRINGS = [
2451
- "CAATINGA_UNSUPPORTED_CLI_VERSION",
2452
- "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
2453
- "CAATINGA_STELLAR_CLI_NOT_FOUND",
2454
- "CAATINGA_INVALID_CONFIG",
2455
- "CAATINGA_CONFIG_NOT_FOUND"
2456
- ];
2457
- var TRANSIENT_PATTERN = /timeout|i\/o timeout|econnreset|connection reset|503|502|429|rate limit|temporar|bad gateway|fetch failed|network error|unavailable/i;
2458
2970
  function isTransientTestnetSmokeFailure(logText) {
2459
- if (!logText.trim()) {
2460
- return false;
2461
- }
2462
- for (const marker of NO_RETRY_CAATINGA_SUBSTRINGS) {
2463
- if (logText.includes(marker)) {
2464
- return false;
2465
- }
2466
- }
2467
- return TRANSIENT_PATTERN.test(logText);
2971
+ return isTransientCommandFailure(logText);
2468
2972
  }
2469
2973
  // Annotate the CommonJS export names for ESM import in node:
2470
2974
  0 && (module.exports = {
2471
2975
  BINDING_MARKER_FILENAME,
2472
2976
  BindingMarkerSchema,
2473
2977
  CAATINGA_CORE_VERSION,
2978
+ CURRENT_ARTIFACTS_SCHEMA_VERSION,
2474
2979
  CaatingaArtifactsSchema,
2475
2980
  CaatingaConfigSchema,
2476
2981
  CaatingaError,
@@ -2478,6 +2983,8 @@ function isTransientTestnetSmokeFailure(logText) {
2478
2983
  READ_CALL_FAILURE_REGEX,
2479
2984
  STELLAR_CLI_LAST_TESTED_VERSION,
2480
2985
  STELLAR_CLI_MIN_VERSION,
2986
+ STELLAR_SDK_LAST_TESTED_VERSION,
2987
+ STELLAR_SDK_MIN_VERSION,
2481
2988
  TemplateManifestSchema,
2482
2989
  WELL_KNOWN_NETWORKS,
2483
2990
  buildContract,
@@ -2485,6 +2992,7 @@ function isTransientTestnetSmokeFailure(logText) {
2485
2992
  buildReadCallHint,
2486
2993
  checkBinary,
2487
2994
  checkStellarCliVersion,
2995
+ checkStellarSdkVersion,
2488
2996
  collectProjectStatus,
2489
2997
  createInitialArtifacts,
2490
2998
  createMinimalProject,
@@ -2493,20 +3001,26 @@ function isTransientTestnetSmokeFailure(logText) {
2493
3001
  defineConfig,
2494
3002
  deployContract,
2495
3003
  deployContractGraph,
3004
+ estimateDeployCost,
2496
3005
  evaluateBindingFreshness,
2497
3006
  evaluateBindingsFreshness,
2498
3007
  evaluateStellarCliCompatibility,
3008
+ evaluateStellarSdkCompatibility,
2499
3009
  formatCaatingaError,
2500
3010
  generateBindings,
2501
3011
  generateBindingsGraph,
3012
+ inspectContract,
2502
3013
  invokeContract,
2503
3014
  isCargoBinMissingFromPath,
2504
3015
  isReadCallFailure,
2505
3016
  isTransientTestnetSmokeFailure,
2506
3017
  loadConfig,
3018
+ migrateArtifactsFile,
3019
+ migrateArtifactsToV2,
2507
3020
  parseContractId,
2508
3021
  parseInvokeTarget,
2509
3022
  parseStellarCliVersion,
3023
+ parseStellarSdkVersion,
2510
3024
  readArtifacts,
2511
3025
  readBindingMarker,
2512
3026
  readContract,
@@ -2516,6 +3030,8 @@ function isTransientTestnetSmokeFailure(logText) {
2516
3030
  resolveDeployOrder,
2517
3031
  resolveNetwork,
2518
3032
  resolveSubprocessEnv,
3033
+ restoreArtifactFromHistory,
3034
+ rollbackContractArtifact,
2519
3035
  runCommand,
2520
3036
  toCaatingaError,
2521
3037
  updateArtifact,