@caatinga/core 2.3.0 → 2.4.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/{browser-Cq4ZofIq.d.cts → artifact.schema-BH5K-IiZ.d.cts} +2 -1
- package/dist/{browser-Cq4ZofIq.d.ts → artifact.schema-BH5K-IiZ.d.ts} +2 -1
- package/dist/browser.cjs +20 -0
- package/dist/browser.d.cts +5 -1
- package/dist/browser.d.ts +5 -1
- package/dist/browser.js +19 -0
- package/dist/index.cjs +440 -29
- package/dist/index.d.cts +52 -12
- package/dist/index.d.ts +52 -12
- package/dist/index.js +430 -29
- package/package.json +2 -1
- package/scaffolds/soroban-contract-stub/Cargo.toml +24 -0
- package/scaffolds/soroban-contract-stub/src/lib.rs +42 -0
- package/scaffolds/zk-circuit-stub/input.json +3 -0
- package/scaffolds/zk-circuit-stub/main.circom +9 -0
- package/scaffolds/zk-verifier/Cargo.lock +1880 -0
- package/scaffolds/zk-verifier/Cargo.toml +27 -0
- package/scaffolds/zk-verifier/src/lib.rs +64 -0
- package/scaffolds/zk-verifier/src/test.rs +100 -0
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/errors/CaatingaErrorCode.ts
|
|
2
2
|
var CaatingaErrorCode = {
|
|
3
3
|
CONFIG_NOT_FOUND: "CAATINGA_CONFIG_NOT_FOUND",
|
|
4
|
+
DEPENDENCIES_NOT_INSTALLED: "CAATINGA_DEPENDENCIES_NOT_INSTALLED",
|
|
4
5
|
INVALID_CONFIG: "CAATINGA_INVALID_CONFIG",
|
|
5
6
|
COMMAND_FAILED: "CAATINGA_COMMAND_FAILED",
|
|
6
7
|
UNEXPECTED_ERROR: "CAATINGA_UNEXPECTED_ERROR",
|
|
@@ -105,7 +106,7 @@ function formatCause(cause) {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
// src/version.ts
|
|
108
|
-
var CAATINGA_CORE_VERSION = "2.
|
|
109
|
+
var CAATINGA_CORE_VERSION = "2.4.0";
|
|
109
110
|
|
|
110
111
|
// src/config/config.schema.ts
|
|
111
112
|
import { z } from "zod";
|
|
@@ -143,7 +144,7 @@ var CaatingaConfigSchema = z.object({
|
|
|
143
144
|
frontend: z.object({
|
|
144
145
|
framework: z.enum(["vite-react", "next", "astro"]).default("vite-react"),
|
|
145
146
|
bindingsOutput: z.string().min(1)
|
|
146
|
-
}),
|
|
147
|
+
}).optional(),
|
|
147
148
|
zk: ZkConfigSchema
|
|
148
149
|
});
|
|
149
150
|
|
|
@@ -157,6 +158,28 @@ import { access } from "fs/promises";
|
|
|
157
158
|
import path from "path";
|
|
158
159
|
import { createJiti } from "jiti";
|
|
159
160
|
import { z as z2 } from "zod";
|
|
161
|
+
|
|
162
|
+
// src/config/is-dependencies-not-installed-error.ts
|
|
163
|
+
function isDependenciesNotInstalledError(error) {
|
|
164
|
+
if (!error || typeof error !== "object") {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
const candidate = error;
|
|
168
|
+
const code = candidate.code;
|
|
169
|
+
const message = String(candidate.message ?? error);
|
|
170
|
+
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
|
|
171
|
+
return /@caatinga\/core/.test(message);
|
|
172
|
+
}
|
|
173
|
+
if (/Cannot find (module|package).+@caatinga\/core/i.test(message)) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
if (candidate.cause !== void 0) {
|
|
177
|
+
return isDependenciesNotInstalledError(candidate.cause);
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/config/load-config.ts
|
|
160
183
|
async function loadConfig(options = {}) {
|
|
161
184
|
const cwd = options.cwd ?? process.cwd();
|
|
162
185
|
const configPath = path.resolve(cwd, options.configPath ?? "caatinga.config.ts");
|
|
@@ -181,6 +204,14 @@ async function loadConfig(options = {}) {
|
|
|
181
204
|
error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ")
|
|
182
205
|
);
|
|
183
206
|
}
|
|
207
|
+
if (isDependenciesNotInstalledError(error)) {
|
|
208
|
+
throw new CaatingaError(
|
|
209
|
+
"Project dependencies are not installed.",
|
|
210
|
+
CaatingaErrorCode.DEPENDENCIES_NOT_INSTALLED,
|
|
211
|
+
"Run npm install (or pnpm install) in the project root, then retry.",
|
|
212
|
+
error
|
|
213
|
+
);
|
|
214
|
+
}
|
|
184
215
|
throw error;
|
|
185
216
|
}
|
|
186
217
|
}
|
|
@@ -341,6 +372,15 @@ async function listGeneratedEntries(outputDir) {
|
|
|
341
372
|
}
|
|
342
373
|
async function evaluateBindingFreshness(options) {
|
|
343
374
|
const cwd = options.cwd ?? process.cwd();
|
|
375
|
+
if (!options.config.frontend) {
|
|
376
|
+
return {
|
|
377
|
+
contractName: options.contractName,
|
|
378
|
+
status: "unknown",
|
|
379
|
+
outputDir: "",
|
|
380
|
+
marker: null,
|
|
381
|
+
reason: "frontend bindings are not configured"
|
|
382
|
+
};
|
|
383
|
+
}
|
|
344
384
|
const outputDir = path5.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
|
|
345
385
|
const contractArtifact = options.artifacts.networks[options.networkName]?.contracts[options.contractName];
|
|
346
386
|
if (!contractArtifact) {
|
|
@@ -578,6 +618,64 @@ function defaultEmitWarning(warning) {
|
|
|
578
618
|
`);
|
|
579
619
|
}
|
|
580
620
|
|
|
621
|
+
// src/shell/resolve-subprocess-env.ts
|
|
622
|
+
import { existsSync } from "fs";
|
|
623
|
+
import os from "os";
|
|
624
|
+
import path6 from "path";
|
|
625
|
+
function uniquePaths(entries) {
|
|
626
|
+
const seen = /* @__PURE__ */ new Set();
|
|
627
|
+
const ordered = [];
|
|
628
|
+
for (const entry of entries) {
|
|
629
|
+
if (!entry || seen.has(entry)) {
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
seen.add(entry);
|
|
633
|
+
ordered.push(entry);
|
|
634
|
+
}
|
|
635
|
+
return ordered;
|
|
636
|
+
}
|
|
637
|
+
function hasExecutable(binDir, name) {
|
|
638
|
+
return existsSync(path6.join(binDir, name));
|
|
639
|
+
}
|
|
640
|
+
function toolchainBinDirs(home, env) {
|
|
641
|
+
const candidates = [
|
|
642
|
+
path6.join(home, ".cargo", "bin"),
|
|
643
|
+
env.CARGO_HOME ? path6.join(env.CARGO_HOME, "bin") : void 0
|
|
644
|
+
];
|
|
645
|
+
return candidates.filter((entry) => Boolean(entry && existsSync(entry)));
|
|
646
|
+
}
|
|
647
|
+
function buildToolchainPrepend(existingPath, toolchainBins, executableExists = hasExecutable) {
|
|
648
|
+
const prepend = [];
|
|
649
|
+
for (const binDir of toolchainBins) {
|
|
650
|
+
const externalStellarDir = existingPath.find(
|
|
651
|
+
(entry) => entry !== binDir && executableExists(entry, "stellar")
|
|
652
|
+
);
|
|
653
|
+
if (externalStellarDir && executableExists(binDir, "stellar")) {
|
|
654
|
+
prepend.push(externalStellarDir);
|
|
655
|
+
}
|
|
656
|
+
prepend.push(binDir);
|
|
657
|
+
}
|
|
658
|
+
return prepend;
|
|
659
|
+
}
|
|
660
|
+
function resolveSubprocessEnv(overrides = {}) {
|
|
661
|
+
const env = { ...process.env, ...overrides };
|
|
662
|
+
const home = env.HOME ?? os.homedir();
|
|
663
|
+
const existingPath = (env.PATH ?? "").split(path6.delimiter).filter(Boolean);
|
|
664
|
+
const toolchainBins = toolchainBinDirs(home, env);
|
|
665
|
+
const prepend = buildToolchainPrepend(existingPath, toolchainBins);
|
|
666
|
+
env.PATH = uniquePaths([...prepend, ...existingPath]).join(path6.delimiter);
|
|
667
|
+
return env;
|
|
668
|
+
}
|
|
669
|
+
function isCargoBinMissingFromPath(baseEnv = process.env) {
|
|
670
|
+
const home = baseEnv.HOME ?? os.homedir();
|
|
671
|
+
const cargoBin = path6.join(home, ".cargo", "bin", "cargo");
|
|
672
|
+
if (!existsSync(cargoBin)) {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
const pathEntries = (baseEnv.PATH ?? "").split(path6.delimiter);
|
|
676
|
+
return !pathEntries.some((entry) => entry === path6.join(home, ".cargo", "bin"));
|
|
677
|
+
}
|
|
678
|
+
|
|
581
679
|
// src/shell/run-command.ts
|
|
582
680
|
async function runCommand(command, args, options = {}) {
|
|
583
681
|
try {
|
|
@@ -586,7 +684,7 @@ async function runCommand(command, args, options = {}) {
|
|
|
586
684
|
}
|
|
587
685
|
const result = await execa(command, args, {
|
|
588
686
|
cwd: options.cwd,
|
|
589
|
-
env: options.env,
|
|
687
|
+
env: resolveSubprocessEnv(options.env ?? {}),
|
|
590
688
|
input: options.input,
|
|
591
689
|
all: true,
|
|
592
690
|
reject: true
|
|
@@ -784,7 +882,7 @@ function validateSourceShape(source) {
|
|
|
784
882
|
}
|
|
785
883
|
|
|
786
884
|
// src/contracts/resolve-contract.ts
|
|
787
|
-
import
|
|
885
|
+
import path7 from "path";
|
|
788
886
|
function resolveContract(config, contractName, cwd = process.cwd()) {
|
|
789
887
|
const contract = config.contracts[contractName];
|
|
790
888
|
if (!contract) {
|
|
@@ -797,8 +895,8 @@ function resolveContract(config, contractName, cwd = process.cwd()) {
|
|
|
797
895
|
return {
|
|
798
896
|
name: contractName,
|
|
799
897
|
config: contract,
|
|
800
|
-
sourcePath:
|
|
801
|
-
wasmPath:
|
|
898
|
+
sourcePath: path7.resolve(cwd, contract.path),
|
|
899
|
+
wasmPath: path7.resolve(cwd, contract.wasm)
|
|
802
900
|
};
|
|
803
901
|
}
|
|
804
902
|
|
|
@@ -818,7 +916,7 @@ function resolveDefaultContractName(config) {
|
|
|
818
916
|
// src/contracts/wasm.ts
|
|
819
917
|
import { createHash } from "crypto";
|
|
820
918
|
import { access as access2, readdir as readdir2, readFile as readFile3, stat } from "fs/promises";
|
|
821
|
-
import
|
|
919
|
+
import path8 from "path";
|
|
822
920
|
var LEGACY_RUST_WASM_TARGET = "wasm32-unknown-unknown";
|
|
823
921
|
var CURRENT_RUST_WASM_TARGET = "wasm32v1-none";
|
|
824
922
|
function toCurrentWasmTargetPath(wasmPath) {
|
|
@@ -841,8 +939,8 @@ function wasmNotFoundError(configuredWasmPath, options) {
|
|
|
841
939
|
);
|
|
842
940
|
}
|
|
843
941
|
function toConfigRelativeWasmPath(absoluteWasmPath) {
|
|
844
|
-
const relative =
|
|
845
|
-
return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(
|
|
942
|
+
const relative = path8.relative(process.cwd(), absoluteWasmPath);
|
|
943
|
+
return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(path8.sep).join("/")}`;
|
|
846
944
|
}
|
|
847
945
|
async function resolveWasmArtifactPath(configuredWasmPath) {
|
|
848
946
|
try {
|
|
@@ -875,7 +973,7 @@ async function getNewestMtimeInDirectory(directory) {
|
|
|
875
973
|
async function walk(dir) {
|
|
876
974
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
877
975
|
for (const entry of entries) {
|
|
878
|
-
const entryPath =
|
|
976
|
+
const entryPath = path8.join(dir, entry.name);
|
|
879
977
|
if (entry.isDirectory()) {
|
|
880
978
|
await walk(entryPath);
|
|
881
979
|
continue;
|
|
@@ -891,7 +989,7 @@ async function getNewestMtimeInDirectory(directory) {
|
|
|
891
989
|
return newest > 0 ? newest : void 0;
|
|
892
990
|
}
|
|
893
991
|
async function isWasmOlderThanSources(input) {
|
|
894
|
-
const srcDir =
|
|
992
|
+
const srcDir = path8.join(input.contractPath, "src");
|
|
895
993
|
const newestSourceMtime = await getNewestMtimeInDirectory(srcDir);
|
|
896
994
|
if (newestSourceMtime === void 0) {
|
|
897
995
|
return false;
|
|
@@ -964,7 +1062,7 @@ async function buildContract(options) {
|
|
|
964
1062
|
}
|
|
965
1063
|
|
|
966
1064
|
// src/contracts/deploy-contract.ts
|
|
967
|
-
import
|
|
1065
|
+
import path9 from "path";
|
|
968
1066
|
|
|
969
1067
|
// src/contracts/dependency-graph.ts
|
|
970
1068
|
function buildDependencyGraph(contracts) {
|
|
@@ -1021,6 +1119,9 @@ function assertSafeSourceAccount(source) {
|
|
|
1021
1119
|
}
|
|
1022
1120
|
return source;
|
|
1023
1121
|
}
|
|
1122
|
+
function resolveCliSource(explicit) {
|
|
1123
|
+
return assertSafeSourceAccount(explicit ?? process.env.CAATINGA_SOURCE ?? "alice");
|
|
1124
|
+
}
|
|
1024
1125
|
|
|
1025
1126
|
// src/contracts/deploy-contract.ts
|
|
1026
1127
|
function toSnakeCaseFlag(key) {
|
|
@@ -1065,7 +1166,7 @@ async function deployContract(options) {
|
|
|
1065
1166
|
contract: contractWithWasm,
|
|
1066
1167
|
network,
|
|
1067
1168
|
contractId: existing.contractId,
|
|
1068
|
-
artifactsPath:
|
|
1169
|
+
artifactsPath: path9.resolve(cwd, "caatinga.artifacts.json"),
|
|
1069
1170
|
output: "",
|
|
1070
1171
|
skipped: true,
|
|
1071
1172
|
staleWasmWarning
|
|
@@ -1342,13 +1443,13 @@ async function deployContractGraph(options) {
|
|
|
1342
1443
|
|
|
1343
1444
|
// src/contracts/generate-bindings.ts
|
|
1344
1445
|
import { access as access3, mkdir as mkdir2, unlink } from "fs/promises";
|
|
1345
|
-
import
|
|
1446
|
+
import path10 from "path";
|
|
1346
1447
|
function toBindingImportPath(bindingsOutput, contractName) {
|
|
1347
|
-
const normalized = bindingsOutput.replace(/^\.\//, "").split(
|
|
1348
|
-
return `./${
|
|
1448
|
+
const normalized = bindingsOutput.replace(/^\.\//, "").split(path10.sep).join("/");
|
|
1449
|
+
return `./${path10.posix.join(normalized, contractName, "src", "index.js")}`;
|
|
1349
1450
|
}
|
|
1350
1451
|
async function removeLegacyBindingStub(cwd, bindingsOutput, contractName) {
|
|
1351
|
-
const legacyPath =
|
|
1452
|
+
const legacyPath = path10.resolve(cwd, bindingsOutput, `${contractName}.ts`);
|
|
1352
1453
|
try {
|
|
1353
1454
|
await access3(legacyPath);
|
|
1354
1455
|
await unlink(legacyPath);
|
|
@@ -1359,6 +1460,13 @@ async function removeLegacyBindingStub(cwd, bindingsOutput, contractName) {
|
|
|
1359
1460
|
}
|
|
1360
1461
|
async function generateBindings(options) {
|
|
1361
1462
|
const cwd = options.cwd ?? process.cwd();
|
|
1463
|
+
if (!options.config.frontend) {
|
|
1464
|
+
throw new CaatingaError(
|
|
1465
|
+
"Frontend bindings are not configured.",
|
|
1466
|
+
CaatingaErrorCode.INVALID_CONFIG,
|
|
1467
|
+
"Add a frontend.bindingsOutput entry to caatinga.config.ts before running caatinga generate."
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1362
1470
|
const network = resolveNetwork(options.config, options.networkName);
|
|
1363
1471
|
const artifacts = await readArtifacts(cwd);
|
|
1364
1472
|
const contractArtifact = artifacts.networks[network.name]?.contracts[options.contractName];
|
|
@@ -1370,7 +1478,7 @@ async function generateBindings(options) {
|
|
|
1370
1478
|
);
|
|
1371
1479
|
}
|
|
1372
1480
|
await checkBinary("stellar", "Install Stellar CLI before running caatinga generate.");
|
|
1373
|
-
const outputDir =
|
|
1481
|
+
const outputDir = path10.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
|
|
1374
1482
|
await mkdir2(outputDir, { recursive: true });
|
|
1375
1483
|
const result = await runCommand("stellar", [
|
|
1376
1484
|
"contract",
|
|
@@ -1444,8 +1552,8 @@ async function generateBindingsGraph(options) {
|
|
|
1444
1552
|
return { network, results };
|
|
1445
1553
|
}
|
|
1446
1554
|
|
|
1447
|
-
// src/contracts/invoke-
|
|
1448
|
-
var
|
|
1555
|
+
// src/contracts/invoke-target.ts
|
|
1556
|
+
var READ_CALL_FAILURE_REGEX = /this is a read call|read-only/i;
|
|
1449
1557
|
function parseInvokeTarget(target) {
|
|
1450
1558
|
const [contractName, method, extra] = target.split(".");
|
|
1451
1559
|
if (!contractName || !method || extra) {
|
|
@@ -1457,6 +1565,29 @@ function parseInvokeTarget(target) {
|
|
|
1457
1565
|
}
|
|
1458
1566
|
return { contractName, method };
|
|
1459
1567
|
}
|
|
1568
|
+
function buildReadCallHint(target, networkName) {
|
|
1569
|
+
return [
|
|
1570
|
+
`"${target.contractName}.${target.method}" is a read-only contract method.`,
|
|
1571
|
+
"Simulate without signing instead:",
|
|
1572
|
+
` npx caatinga read ${target.contractName}.${target.method} --network ${networkName}`,
|
|
1573
|
+
" (--source is optional; Caatinga resolves CAATINGA_SOURCE or defaults to alice)",
|
|
1574
|
+
"In browser code, use:",
|
|
1575
|
+
` client.contract("${target.contractName}").read("${target.method}")`,
|
|
1576
|
+
` client.contract("${target.contractName}").simulate("${target.method}")`,
|
|
1577
|
+
"Pass method args as the second argument to read() when the contract method takes parameters.",
|
|
1578
|
+
"Only pass Stellar CLI --force when you intentionally need a signed read simulation."
|
|
1579
|
+
].join("\n");
|
|
1580
|
+
}
|
|
1581
|
+
function isReadCallFailure(error) {
|
|
1582
|
+
if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.INVOKE_FAILED) {
|
|
1583
|
+
return false;
|
|
1584
|
+
}
|
|
1585
|
+
return READ_CALL_FAILURE_REGEX.test(`${error.message}
|
|
1586
|
+
${error.hint ?? ""}`);
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
// src/contracts/invoke-contract.ts
|
|
1590
|
+
var INVOKE_SIGNING_FAILURE_REGEX = /xdr processing error: xdr value invalid/i;
|
|
1460
1591
|
async function invokeContract(options) {
|
|
1461
1592
|
const cwd = options.cwd ?? process.cwd();
|
|
1462
1593
|
const network = resolveNetwork(options.config, options.networkName);
|
|
@@ -1490,6 +1621,14 @@ async function invokeContract(options) {
|
|
|
1490
1621
|
failureCode: CaatingaErrorCode.INVOKE_FAILED
|
|
1491
1622
|
});
|
|
1492
1623
|
} catch (error) {
|
|
1624
|
+
if (error instanceof CaatingaError && error.code === CaatingaErrorCode.INVOKE_FAILED && isReadCallFailure(error)) {
|
|
1625
|
+
throw new CaatingaError(
|
|
1626
|
+
error.message,
|
|
1627
|
+
error.code,
|
|
1628
|
+
buildReadCallHint(target, network.name),
|
|
1629
|
+
error
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1493
1632
|
if (error instanceof CaatingaError && error.code === CaatingaErrorCode.INVOKE_FAILED && INVOKE_SIGNING_FAILURE_REGEX.test(`${error.message}
|
|
1494
1633
|
${error.hint ?? ""}`)) {
|
|
1495
1634
|
throw new CaatingaError(
|
|
@@ -1515,9 +1654,48 @@ ${error.hint ?? ""}`)) {
|
|
|
1515
1654
|
};
|
|
1516
1655
|
}
|
|
1517
1656
|
|
|
1657
|
+
// src/contracts/read-contract.ts
|
|
1658
|
+
async function readContract(options) {
|
|
1659
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1660
|
+
const network = resolveNetwork(options.config, options.networkName);
|
|
1661
|
+
const target = parseInvokeTarget(options.target);
|
|
1662
|
+
const artifacts = await readArtifacts(cwd);
|
|
1663
|
+
const contractArtifact = artifacts.networks[network.name]?.contracts[target.contractName];
|
|
1664
|
+
if (!contractArtifact) {
|
|
1665
|
+
throw new CaatingaError(
|
|
1666
|
+
`No deployed artifact found for "${target.contractName}" on "${network.name}".`,
|
|
1667
|
+
CaatingaErrorCode.ARTIFACT_NOT_FOUND,
|
|
1668
|
+
"Run caatinga deploy for this contract and network before reading it."
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
await checkBinary("stellar", "Install Stellar CLI before running caatinga read.");
|
|
1672
|
+
const stellarArgs = [
|
|
1673
|
+
"contract",
|
|
1674
|
+
"invoke",
|
|
1675
|
+
"--id",
|
|
1676
|
+
contractArtifact.contractId,
|
|
1677
|
+
"--source-account",
|
|
1678
|
+
resolveCliSource(options.source),
|
|
1679
|
+
"--send=no",
|
|
1680
|
+
...buildStellarNetworkArgs(network),
|
|
1681
|
+
"--",
|
|
1682
|
+
target.method,
|
|
1683
|
+
...options.args ?? []
|
|
1684
|
+
];
|
|
1685
|
+
const result = await runCommand("stellar", stellarArgs, {
|
|
1686
|
+
cwd,
|
|
1687
|
+
failureCode: CaatingaErrorCode.INVOKE_FAILED
|
|
1688
|
+
});
|
|
1689
|
+
return {
|
|
1690
|
+
target,
|
|
1691
|
+
network,
|
|
1692
|
+
result: result.stdout || result.all
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1518
1696
|
// src/templates/create-project-from-template.ts
|
|
1519
1697
|
import { cp, mkdir as mkdir3, readFile as readFile4, readdir as readdir3, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
1520
|
-
import
|
|
1698
|
+
import path11 from "path";
|
|
1521
1699
|
import { z as z7 } from "zod";
|
|
1522
1700
|
|
|
1523
1701
|
// src/templates/template-manifest.schema.ts
|
|
@@ -1593,8 +1771,8 @@ var TEMPLATE_COPY_EXCLUDED_DIRS = /* @__PURE__ */ new Set([
|
|
|
1593
1771
|
".git"
|
|
1594
1772
|
]);
|
|
1595
1773
|
async function createProjectFromTemplate(options) {
|
|
1596
|
-
const targetDir =
|
|
1597
|
-
const templateDir =
|
|
1774
|
+
const targetDir = path11.resolve(options.targetDir);
|
|
1775
|
+
const templateDir = path11.resolve(options.templateDir);
|
|
1598
1776
|
try {
|
|
1599
1777
|
await stat2(templateDir);
|
|
1600
1778
|
} catch {
|
|
@@ -1632,7 +1810,7 @@ async function ensureArtifacts(targetDir, projectName) {
|
|
|
1632
1810
|
}
|
|
1633
1811
|
}
|
|
1634
1812
|
async function readTemplateManifest(templateDir) {
|
|
1635
|
-
const manifestPath =
|
|
1813
|
+
const manifestPath = path11.join(templateDir, "caatinga.template.json");
|
|
1636
1814
|
try {
|
|
1637
1815
|
const rawManifest = await readFile4(manifestPath, "utf8");
|
|
1638
1816
|
const manifest = TemplateManifestSchema.parse(JSON.parse(rawManifest));
|
|
@@ -1669,7 +1847,7 @@ async function readTemplateManifest(templateDir) {
|
|
|
1669
1847
|
async function replaceTemplateVariables(dir, projectName) {
|
|
1670
1848
|
const entries = await readdir3(dir);
|
|
1671
1849
|
await Promise.all(entries.map(async (entry) => {
|
|
1672
|
-
const entryPath =
|
|
1850
|
+
const entryPath = path11.join(dir, entry);
|
|
1673
1851
|
const entryStat = await stat2(entryPath);
|
|
1674
1852
|
if (entryStat.isDirectory()) {
|
|
1675
1853
|
await replaceTemplateVariables(entryPath, projectName);
|
|
@@ -1683,15 +1861,15 @@ async function replaceTemplateVariables(dir, projectName) {
|
|
|
1683
1861
|
}));
|
|
1684
1862
|
}
|
|
1685
1863
|
function shouldCopyTemplateEntry(templateDir, source, userFilter) {
|
|
1686
|
-
const relativePath =
|
|
1864
|
+
const relativePath = path11.relative(templateDir, source);
|
|
1687
1865
|
if (!relativePath || relativePath === ".") {
|
|
1688
1866
|
return true;
|
|
1689
1867
|
}
|
|
1690
|
-
const normalizedPath = relativePath.split(
|
|
1868
|
+
const normalizedPath = relativePath.split(path11.sep).join("/");
|
|
1691
1869
|
if (userFilter && !userFilter(normalizedPath)) {
|
|
1692
1870
|
return false;
|
|
1693
1871
|
}
|
|
1694
|
-
return !relativePath.split(
|
|
1872
|
+
return !relativePath.split(path11.sep).some((segment) => TEMPLATE_COPY_EXCLUDED_DIRS.has(segment));
|
|
1695
1873
|
}
|
|
1696
1874
|
function isTextTemplateFile(filePath) {
|
|
1697
1875
|
return [
|
|
@@ -1703,7 +1881,222 @@ function isTextTemplateFile(filePath) {
|
|
|
1703
1881
|
".tsx",
|
|
1704
1882
|
".css",
|
|
1705
1883
|
".html"
|
|
1706
|
-
].includes(
|
|
1884
|
+
].includes(path11.extname(filePath));
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
// src/scaffold/create-zk-project.ts
|
|
1888
|
+
import { cp as cp2, mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
|
|
1889
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1890
|
+
import path12 from "path";
|
|
1891
|
+
import { fileURLToPath } from "url";
|
|
1892
|
+
var moduleDir = typeof __dirname === "string" ? __dirname : path12.dirname(fileURLToPath(import.meta.url));
|
|
1893
|
+
function scaffoldRoot() {
|
|
1894
|
+
const candidates = [
|
|
1895
|
+
path12.resolve(moduleDir, "../../scaffolds"),
|
|
1896
|
+
path12.resolve(moduleDir, "../scaffolds")
|
|
1897
|
+
];
|
|
1898
|
+
const found = candidates.find((candidate) => existsSync2(candidate));
|
|
1899
|
+
return found ?? candidates[0];
|
|
1900
|
+
}
|
|
1901
|
+
function configSource(projectName) {
|
|
1902
|
+
return `import { defineConfig } from "@caatinga/core";
|
|
1903
|
+
|
|
1904
|
+
export default defineConfig({
|
|
1905
|
+
project: "${projectName}",
|
|
1906
|
+
defaultNetwork: "testnet",
|
|
1907
|
+
contracts: {
|
|
1908
|
+
verifier: {
|
|
1909
|
+
path: "./contracts/verifier",
|
|
1910
|
+
wasm: "./contracts/verifier/target/wasm32v1-none/release/verifier.wasm"
|
|
1911
|
+
}
|
|
1912
|
+
},
|
|
1913
|
+
networks: {
|
|
1914
|
+
testnet: {
|
|
1915
|
+
rpcUrl: "https://soroban-testnet.stellar.org",
|
|
1916
|
+
networkPassphrase: "Test SDF Network ; September 2015"
|
|
1917
|
+
}
|
|
1918
|
+
},
|
|
1919
|
+
zk: {
|
|
1920
|
+
circuits: {
|
|
1921
|
+
main: {
|
|
1922
|
+
path: "./circuits",
|
|
1923
|
+
protocol: "groth16",
|
|
1924
|
+
curve: "bls12381",
|
|
1925
|
+
verifierContract: "verifier"
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1930
|
+
`;
|
|
1931
|
+
}
|
|
1932
|
+
function packageJsonSource(projectName) {
|
|
1933
|
+
return `${JSON.stringify({
|
|
1934
|
+
name: projectName,
|
|
1935
|
+
version: "0.1.0",
|
|
1936
|
+
private: true,
|
|
1937
|
+
type: "module",
|
|
1938
|
+
scripts: {
|
|
1939
|
+
"zk:build": "caatinga zk build main",
|
|
1940
|
+
"zk:prove": "caatinga zk prove main",
|
|
1941
|
+
build: "caatinga build verifier",
|
|
1942
|
+
deploy: "caatinga deploy verifier"
|
|
1943
|
+
},
|
|
1944
|
+
devDependencies: {
|
|
1945
|
+
"@caatinga/cli": `^${CAATINGA_CORE_VERSION}`,
|
|
1946
|
+
"@caatinga/core": `^${CAATINGA_CORE_VERSION}`
|
|
1947
|
+
}
|
|
1948
|
+
}, null, 2)}
|
|
1949
|
+
`;
|
|
1950
|
+
}
|
|
1951
|
+
function readmeSource(projectName) {
|
|
1952
|
+
return `# ${projectName}
|
|
1953
|
+
|
|
1954
|
+
Minimal Caatinga ZK project.
|
|
1955
|
+
|
|
1956
|
+
## Workflow
|
|
1957
|
+
|
|
1958
|
+
\`\`\`bash
|
|
1959
|
+
npm install
|
|
1960
|
+
npx caatinga zk build main
|
|
1961
|
+
npx caatinga build verifier
|
|
1962
|
+
npx caatinga deploy verifier --network testnet
|
|
1963
|
+
npx caatinga zk prove main
|
|
1964
|
+
\`\`\`
|
|
1965
|
+
|
|
1966
|
+
Replace \`circuits/main.circom\` with your circuit. Keep the entry point named \`main\`.
|
|
1967
|
+
`;
|
|
1968
|
+
}
|
|
1969
|
+
async function createZkProject(options) {
|
|
1970
|
+
const targetDir = path12.resolve(options.targetDir);
|
|
1971
|
+
const force = options.force ?? false;
|
|
1972
|
+
const projectFiles = options.projectFiles ?? true;
|
|
1973
|
+
await mkdir4(targetDir, { recursive: true });
|
|
1974
|
+
if (projectFiles) {
|
|
1975
|
+
await Promise.all([
|
|
1976
|
+
writeFile4(path12.join(targetDir, "caatinga.config.ts"), configSource(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" }),
|
|
1977
|
+
writeFile4(path12.join(targetDir, "package.json"), packageJsonSource(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" }),
|
|
1978
|
+
writeFile4(path12.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", { encoding: "utf8", flag: force ? "w" : "wx" }),
|
|
1979
|
+
writeFile4(path12.join(targetDir, "README.md"), readmeSource(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" })
|
|
1980
|
+
]);
|
|
1981
|
+
}
|
|
1982
|
+
await mkdir4(path12.join(targetDir, "contracts"), { recursive: true });
|
|
1983
|
+
await cp2(path12.join(scaffoldRoot(), "zk-circuit-stub"), path12.join(targetDir, "circuits"), {
|
|
1984
|
+
recursive: true,
|
|
1985
|
+
force,
|
|
1986
|
+
errorOnExist: !force
|
|
1987
|
+
});
|
|
1988
|
+
await cp2(path12.join(scaffoldRoot(), "zk-verifier"), path12.join(targetDir, "contracts", "verifier"), {
|
|
1989
|
+
recursive: true,
|
|
1990
|
+
force,
|
|
1991
|
+
errorOnExist: !force
|
|
1992
|
+
});
|
|
1993
|
+
if (projectFiles) {
|
|
1994
|
+
await writeArtifacts(createInitialArtifacts(options.projectName, { networks: ["testnet"] }), targetDir);
|
|
1995
|
+
}
|
|
1996
|
+
return { targetDir };
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
// src/scaffold/create-minimal-project.ts
|
|
2000
|
+
import { cp as cp3, mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
2001
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2002
|
+
import path13 from "path";
|
|
2003
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2004
|
+
var moduleDir2 = typeof __dirname === "string" ? __dirname : path13.dirname(fileURLToPath2(import.meta.url));
|
|
2005
|
+
function scaffoldRoot2() {
|
|
2006
|
+
const candidates = [
|
|
2007
|
+
path13.resolve(moduleDir2, "../../scaffolds"),
|
|
2008
|
+
path13.resolve(moduleDir2, "../scaffolds")
|
|
2009
|
+
];
|
|
2010
|
+
const found = candidates.find((candidate) => existsSync3(candidate));
|
|
2011
|
+
return found ?? candidates[0];
|
|
2012
|
+
}
|
|
2013
|
+
function configSource2(projectName) {
|
|
2014
|
+
return `import { defineConfig } from "@caatinga/core";
|
|
2015
|
+
|
|
2016
|
+
export default defineConfig({
|
|
2017
|
+
project: "${projectName}",
|
|
2018
|
+
defaultNetwork: "testnet",
|
|
2019
|
+
contracts: {
|
|
2020
|
+
app: {
|
|
2021
|
+
path: "./contracts/app",
|
|
2022
|
+
wasm: "./contracts/app/target/wasm32v1-none/release/app.wasm"
|
|
2023
|
+
}
|
|
2024
|
+
},
|
|
2025
|
+
networks: {
|
|
2026
|
+
testnet: {
|
|
2027
|
+
rpcUrl: "https://soroban-testnet.stellar.org",
|
|
2028
|
+
networkPassphrase: "Test SDF Network ; September 2015"
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
});
|
|
2032
|
+
`;
|
|
2033
|
+
}
|
|
2034
|
+
function packageJsonSource2(projectName) {
|
|
2035
|
+
return `${JSON.stringify({
|
|
2036
|
+
name: projectName,
|
|
2037
|
+
version: "0.1.0",
|
|
2038
|
+
private: true,
|
|
2039
|
+
type: "module",
|
|
2040
|
+
scripts: {
|
|
2041
|
+
build: "caatinga build app",
|
|
2042
|
+
deploy: "caatinga deploy app --network testnet --source ${CAATINGA_SOURCE:-alice}",
|
|
2043
|
+
doctor: "caatinga doctor",
|
|
2044
|
+
"read:hello": "caatinga read app.hello --network testnet --source ${CAATINGA_SOURCE:-alice}",
|
|
2045
|
+
"read:version": "caatinga read app.version --network testnet --source ${CAATINGA_SOURCE:-alice}"
|
|
2046
|
+
},
|
|
2047
|
+
devDependencies: {
|
|
2048
|
+
"@caatinga/cli": `^${CAATINGA_CORE_VERSION}`,
|
|
2049
|
+
"@caatinga/core": `^${CAATINGA_CORE_VERSION}`
|
|
2050
|
+
}
|
|
2051
|
+
}, null, 2)}
|
|
2052
|
+
`;
|
|
2053
|
+
}
|
|
2054
|
+
function readmeSource2(projectName) {
|
|
2055
|
+
return `# ${projectName}
|
|
2056
|
+
|
|
2057
|
+
Minimal Caatinga project with a Soroban contract stub (no frontend template).
|
|
2058
|
+
|
|
2059
|
+
## Workflow
|
|
2060
|
+
|
|
2061
|
+
\`\`\`bash
|
|
2062
|
+
npm install
|
|
2063
|
+
npx caatinga doctor
|
|
2064
|
+
npx caatinga build app
|
|
2065
|
+
npx caatinga deploy app --network testnet --source <identity>
|
|
2066
|
+
npx caatinga read app.version --network testnet
|
|
2067
|
+
npx caatinga read app.hello --network testnet
|
|
2068
|
+
\`\`\`
|
|
2069
|
+
|
|
2070
|
+
## Contract
|
|
2071
|
+
|
|
2072
|
+
- \`hello()\` \u2014 read-only; returns Soroban Symbol \`hello\`
|
|
2073
|
+
- \`version()\` \u2014 read-only; returns \`1\`
|
|
2074
|
+
|
|
2075
|
+
Use \`caatinga read\` for read-only methods. Use \`caatinga invoke\` only after you add state-changing methods to the contract.
|
|
2076
|
+
|
|
2077
|
+
Soroban \`Symbol\` parameters are generated as TypeScript \`string\` values with host-specific restrictions \u2014 see the Caatinga docs on [Soroban types](https://github.com/caatinga/caatinga/blob/main/docs/soroban-types.md).
|
|
2078
|
+
|
|
2079
|
+
Edit \`contracts/app/src/lib.rs\` to customize the contract. Add a frontend later with \`@caatinga/client\` and your chosen UI stack.
|
|
2080
|
+
`;
|
|
2081
|
+
}
|
|
2082
|
+
async function createMinimalProject(options) {
|
|
2083
|
+
const targetDir = path13.resolve(options.targetDir);
|
|
2084
|
+
const force = options.force ?? false;
|
|
2085
|
+
await mkdir5(targetDir, { recursive: true });
|
|
2086
|
+
await Promise.all([
|
|
2087
|
+
writeFile5(path13.join(targetDir, "caatinga.config.ts"), configSource2(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" }),
|
|
2088
|
+
writeFile5(path13.join(targetDir, "package.json"), packageJsonSource2(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" }),
|
|
2089
|
+
writeFile5(path13.join(targetDir, ".gitignore"), "node_modules\n.artifacts\ntarget\n", { encoding: "utf8", flag: force ? "w" : "wx" }),
|
|
2090
|
+
writeFile5(path13.join(targetDir, "README.md"), readmeSource2(options.projectName), { encoding: "utf8", flag: force ? "w" : "wx" })
|
|
2091
|
+
]);
|
|
2092
|
+
await mkdir5(path13.join(targetDir, "contracts"), { recursive: true });
|
|
2093
|
+
await cp3(path13.join(scaffoldRoot2(), "soroban-contract-stub"), path13.join(targetDir, "contracts", "app"), {
|
|
2094
|
+
recursive: true,
|
|
2095
|
+
force,
|
|
2096
|
+
errorOnExist: !force
|
|
2097
|
+
});
|
|
2098
|
+
await writeArtifacts(createInitialArtifacts(options.projectName, { networks: ["testnet"] }), targetDir);
|
|
2099
|
+
return { targetDir };
|
|
1707
2100
|
}
|
|
1708
2101
|
|
|
1709
2102
|
// src/ci/is-transient-testnet-smoke-failure.ts
|
|
@@ -1734,17 +2127,21 @@ export {
|
|
|
1734
2127
|
CaatingaConfigSchema,
|
|
1735
2128
|
CaatingaError,
|
|
1736
2129
|
CaatingaErrorCode,
|
|
2130
|
+
READ_CALL_FAILURE_REGEX,
|
|
1737
2131
|
STELLAR_CLI_LAST_TESTED_VERSION,
|
|
1738
2132
|
STELLAR_CLI_MIN_VERSION,
|
|
1739
2133
|
TemplateManifestSchema,
|
|
1740
2134
|
WELL_KNOWN_NETWORKS,
|
|
1741
2135
|
buildContract,
|
|
1742
2136
|
buildDependencyGraph,
|
|
2137
|
+
buildReadCallHint,
|
|
1743
2138
|
checkBinary,
|
|
1744
2139
|
checkStellarCliVersion,
|
|
1745
2140
|
collectProjectStatus,
|
|
1746
2141
|
createInitialArtifacts,
|
|
2142
|
+
createMinimalProject,
|
|
1747
2143
|
createProjectFromTemplate,
|
|
2144
|
+
createZkProject,
|
|
1748
2145
|
defineConfig,
|
|
1749
2146
|
deployContract,
|
|
1750
2147
|
deployContractGraph,
|
|
@@ -1755,6 +2152,8 @@ export {
|
|
|
1755
2152
|
generateBindings,
|
|
1756
2153
|
generateBindingsGraph,
|
|
1757
2154
|
invokeContract,
|
|
2155
|
+
isCargoBinMissingFromPath,
|
|
2156
|
+
isReadCallFailure,
|
|
1758
2157
|
isTransientTestnetSmokeFailure,
|
|
1759
2158
|
loadConfig,
|
|
1760
2159
|
parseContractId,
|
|
@@ -1762,11 +2161,13 @@ export {
|
|
|
1762
2161
|
parseStellarCliVersion,
|
|
1763
2162
|
readArtifacts,
|
|
1764
2163
|
readBindingMarker,
|
|
2164
|
+
readContract,
|
|
1765
2165
|
resolveContract,
|
|
1766
2166
|
resolveDefaultContractName,
|
|
1767
2167
|
resolveDeployArgs,
|
|
1768
2168
|
resolveDeployOrder,
|
|
1769
2169
|
resolveNetwork,
|
|
2170
|
+
resolveSubprocessEnv,
|
|
1770
2171
|
runCommand,
|
|
1771
2172
|
toCaatingaError,
|
|
1772
2173
|
updateArtifact,
|