@hardkas/sdk 0.8.20-alpha → 0.9.1-alpha
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/README.md +51 -40
- package/dist/index.d.ts +492 -7
- package/dist/index.js +2165 -232
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { HardkasError as HardkasError3 } from "@hardkas/core";
|
|
|
11
11
|
|
|
12
12
|
// src/accounts.ts
|
|
13
13
|
import { resolveHardkasAccount } from "@hardkas/accounts";
|
|
14
|
-
import {
|
|
14
|
+
import { formatSompiToKas } from "@hardkas/core";
|
|
15
15
|
var HardkasAccounts = class {
|
|
16
16
|
constructor(sdk) {
|
|
17
17
|
this.sdk = sdk;
|
|
@@ -37,7 +37,7 @@ var HardkasAccounts = class {
|
|
|
37
37
|
const sompi = BigInt(balanceSompi);
|
|
38
38
|
return {
|
|
39
39
|
sompi,
|
|
40
|
-
formatted:
|
|
40
|
+
formatted: formatSompiToKas(sompi)
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
@@ -47,10 +47,12 @@ var HardkasAccounts = class {
|
|
|
47
47
|
return this.getBalance(accountNameOrAddress);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
* Lists all
|
|
50
|
+
* Lists all available HardKAS accounts.
|
|
51
51
|
*/
|
|
52
52
|
async list() {
|
|
53
|
-
|
|
53
|
+
const { listHardkasAccounts, describeAccount } = await import("@hardkas/accounts");
|
|
54
|
+
const accounts = listHardkasAccounts({ ...this.sdk.config.config, cwd: this.sdk.workspace.root });
|
|
55
|
+
return accounts.map((a) => describeAccount(a));
|
|
54
56
|
}
|
|
55
57
|
/**
|
|
56
58
|
* Funds an account from another account (defaults to 'default' account).
|
|
@@ -59,7 +61,8 @@ var HardkasAccounts = class {
|
|
|
59
61
|
let from = options?.from;
|
|
60
62
|
const amount = options?.amount || "1000000000";
|
|
61
63
|
if (!from) {
|
|
62
|
-
const
|
|
64
|
+
const accountsList = await this.list();
|
|
65
|
+
const accounts = accountsList.map((a) => a.name);
|
|
63
66
|
if (accounts.includes("faucet")) {
|
|
64
67
|
from = "faucet";
|
|
65
68
|
} else if (accounts.includes("simulated_faucet")) {
|
|
@@ -67,7 +70,9 @@ var HardkasAccounts = class {
|
|
|
67
70
|
} else if (this.sdk.network === "simulated" && accounts.includes("alice")) {
|
|
68
71
|
from = "alice";
|
|
69
72
|
} else {
|
|
70
|
-
throw new Error(
|
|
73
|
+
throw new Error(
|
|
74
|
+
"No funding account available.\nFor simulated mode, run Hardkas.create({ network: 'simulated', autoBootstrap: true })\nor call accounts.fund(target, { from: 'alice' })."
|
|
75
|
+
);
|
|
71
76
|
}
|
|
72
77
|
}
|
|
73
78
|
if (from === accountNameOrAddress) {
|
|
@@ -90,7 +95,6 @@ var HardkasAccounts = class {
|
|
|
90
95
|
// src/tx.ts
|
|
91
96
|
import { systemRuntimeContext, deterministicCompare } from "@hardkas/core";
|
|
92
97
|
import {
|
|
93
|
-
buildPaymentPlan,
|
|
94
98
|
verifySignedTxSemantics
|
|
95
99
|
} from "@hardkas/tx-builder";
|
|
96
100
|
import {
|
|
@@ -106,15 +110,22 @@ import {
|
|
|
106
110
|
getBroadcastableSignedTransaction
|
|
107
111
|
} from "@hardkas/artifacts";
|
|
108
112
|
import { coreEvents } from "@hardkas/core";
|
|
109
|
-
import {
|
|
113
|
+
import {
|
|
114
|
+
signTxPlanArtifact,
|
|
115
|
+
validateAddressNetwork
|
|
116
|
+
} from "@hardkas/accounts";
|
|
110
117
|
import { parseKasToSompi } from "@hardkas/core";
|
|
118
|
+
import { TxPlanService } from "@hardkas/tx-builder";
|
|
119
|
+
import { HardkasSchemas } from "@hardkas/artifacts";
|
|
111
120
|
function normalizeSimulatedPlanInput(target, fallbackId) {
|
|
112
121
|
if (target.schema === ARTIFACT_SCHEMAS.TX_PLAN && Array.isArray(target.inputs)) {
|
|
113
122
|
return target;
|
|
114
123
|
}
|
|
115
124
|
if (target.from && target.to && target.amountSompi) {
|
|
116
125
|
if (target.mode !== "simulated") {
|
|
117
|
-
throw new Error(
|
|
126
|
+
throw new Error(
|
|
127
|
+
"Cannot simulate real signed artifact without parent plan. Missing plan inputs data."
|
|
128
|
+
);
|
|
118
129
|
}
|
|
119
130
|
return {
|
|
120
131
|
schema: ARTIFACT_SCHEMAS.TX_PLAN,
|
|
@@ -130,14 +141,18 @@ function normalizeSimulatedPlanInput(target, fallbackId) {
|
|
|
130
141
|
outputs: [{ address: target.to.address, amountSompi: target.amountSompi || "0" }],
|
|
131
142
|
plan: {
|
|
132
143
|
inputs: [],
|
|
133
|
-
outputs: [
|
|
144
|
+
outputs: [
|
|
145
|
+
{ address: target.to.address, amountSompi: BigInt(target.amountSompi || 0) }
|
|
146
|
+
],
|
|
134
147
|
feeSompi: 0n,
|
|
135
148
|
mass: 0n,
|
|
136
149
|
changeSompi: 0n
|
|
137
150
|
}
|
|
138
151
|
};
|
|
139
152
|
}
|
|
140
|
-
throw new Error(
|
|
153
|
+
throw new Error(
|
|
154
|
+
"Cannot simulate signed artifact without parent plan or embedded plan data."
|
|
155
|
+
);
|
|
141
156
|
}
|
|
142
157
|
var HardkasTx = class {
|
|
143
158
|
constructor(sdk) {
|
|
@@ -156,7 +171,9 @@ var HardkasTx = class {
|
|
|
156
171
|
throw new Error(`To account ${toAccount.name} has no address.`);
|
|
157
172
|
const amountSompi = typeof options.amount === "string" ? parseKasToSompi(options.amount) : typeof options.amount === "number" ? parseKasToSompi(options.amount.toString()) : options.amount;
|
|
158
173
|
if (amountSompi === 0n) {
|
|
159
|
-
throw new Error(
|
|
174
|
+
throw new Error(
|
|
175
|
+
"Kaspa value-transfer outputs require amount > 0.\nFor metadata/notary/DID marker transactions use --amount 1.\nFuture: hardkas tx anchor."
|
|
176
|
+
);
|
|
160
177
|
}
|
|
161
178
|
const activeNetwork = this.sdk.config.config.defaultNetwork || "simnet";
|
|
162
179
|
const allowMainnet = this.sdk.config.config.networks?.mainnet?.allowMainnet === true;
|
|
@@ -165,96 +182,57 @@ var HardkasTx = class {
|
|
|
165
182
|
if (options.changeAddress) {
|
|
166
183
|
validateAddressNetwork(options.changeAddress, activeNetwork, allowMainnet);
|
|
167
184
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}));
|
|
210
|
-
}
|
|
211
|
-
const sortedUtxos = [...allFetchedUtxos].sort((a, b) => {
|
|
212
|
-
if (a.amountSompi > b.amountSompi) return -1;
|
|
213
|
-
if (a.amountSompi < b.amountSompi) return 1;
|
|
214
|
-
return 0;
|
|
215
|
-
});
|
|
216
|
-
const MAX_INPUTS_PER_TX = 512;
|
|
217
|
-
const WARN_INPUTS = 128;
|
|
218
|
-
const HARD_LIMIT = 1e3;
|
|
219
|
-
const MARGIN_FEE_PER_INPUT = 1500n * (options.feeRate ?? 1n);
|
|
220
|
-
let selectedAmount = 0n;
|
|
221
|
-
let selectedInputsCount = 0;
|
|
222
|
-
const builderUtxos = [];
|
|
223
|
-
for (const utxo of sortedUtxos) {
|
|
224
|
-
builderUtxos.push(utxo);
|
|
225
|
-
selectedAmount += utxo.amountSompi;
|
|
226
|
-
selectedInputsCount++;
|
|
227
|
-
const requiredTotal = amountSompi + BigInt(selectedInputsCount) * MARGIN_FEE_PER_INPUT;
|
|
228
|
-
if (selectedAmount >= requiredTotal) {
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
231
|
-
if (selectedInputsCount >= HARD_LIMIT) {
|
|
232
|
-
break;
|
|
185
|
+
const utxoProvider = {
|
|
186
|
+
getUtxos: async (address) => {
|
|
187
|
+
if (activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated") {
|
|
188
|
+
const { loadOrCreateLocalnetState, getSpendableUtxos } = await import("@hardkas/localnet");
|
|
189
|
+
const localState = await loadOrCreateLocalnetState({
|
|
190
|
+
cwd: this.sdk.workspace.root
|
|
191
|
+
});
|
|
192
|
+
const unspent = getSpendableUtxos(localState, address);
|
|
193
|
+
return unspent.map((u) => {
|
|
194
|
+
const parts = u.id.split(":");
|
|
195
|
+
const index = Number(parts[parts.length - 1]);
|
|
196
|
+
const transactionId = parts.slice(0, -1).join(":");
|
|
197
|
+
return {
|
|
198
|
+
outpoint: { transactionId, index },
|
|
199
|
+
address: u.address,
|
|
200
|
+
amountSompi: BigInt(u.amountSompi),
|
|
201
|
+
scriptPublicKey: "mock-script"
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
const rpcUtxos = await this.sdk.rpc.getUtxosByAddress(address);
|
|
206
|
+
return rpcUtxos.map((u) => ({
|
|
207
|
+
outpoint: {
|
|
208
|
+
transactionId: u.outpoint.transactionId,
|
|
209
|
+
index: u.outpoint.index
|
|
210
|
+
},
|
|
211
|
+
address: u.address,
|
|
212
|
+
amountSompi: BigInt(u.amountSompi),
|
|
213
|
+
scriptPublicKey: u.scriptPublicKey || "",
|
|
214
|
+
blockDaaScore: u.blockDaaScore !== void 0 ? BigInt(u.blockDaaScore) : void 0,
|
|
215
|
+
isCoinbase: u.isCoinbase
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
getVirtualDaaScore: async () => {
|
|
220
|
+
try {
|
|
221
|
+
const dagInfo = await this.sdk.rpc.getBlockDagInfo();
|
|
222
|
+
return dagInfo.virtualDaaScore;
|
|
223
|
+
} catch {
|
|
224
|
+
return void 0;
|
|
225
|
+
}
|
|
233
226
|
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
if (selectedInputsCount > MAX_INPUTS_PER_TX) {
|
|
239
|
-
const err = new Error(`TOO_MANY_INPUTS_FOR_SINGLE_TX: Transaction requires ${selectedInputsCount} inputs to cover the amount, which exceeds the safe limit of ${MAX_INPUTS_PER_TX} inputs.
|
|
240
|
-
Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
241
|
-
err.code = "TOO_MANY_INPUTS_FOR_SINGLE_TX";
|
|
242
|
-
throw err;
|
|
243
|
-
}
|
|
244
|
-
if (selectedInputsCount >= WARN_INPUTS) {
|
|
245
|
-
console.warn(`\u26A0\uFE0F WARNING: Transaction requires ${selectedInputsCount} inputs. Consider running 'hardkas accounts consolidate'.`);
|
|
246
|
-
}
|
|
247
|
-
const builderPlan = buildPaymentPlan({
|
|
227
|
+
};
|
|
228
|
+
const planService = new TxPlanService(utxoProvider);
|
|
229
|
+
const result = await planService.planTransaction({
|
|
248
230
|
fromAddress: fromAccount.address,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
address: toAccount.address,
|
|
253
|
-
amountSompi
|
|
254
|
-
}
|
|
255
|
-
],
|
|
256
|
-
feeRateSompiPerMass: options.feeRate ?? 1n
|
|
231
|
+
toAddress: toAccount.address,
|
|
232
|
+
amountSompi,
|
|
233
|
+
...options.feeRate !== void 0 ? { feeRate: options.feeRate } : {}
|
|
257
234
|
});
|
|
235
|
+
const builderPlan = result.plan;
|
|
258
236
|
const isSimulated = activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated";
|
|
259
237
|
let resolvedAssumptionLevel = options.assumption;
|
|
260
238
|
if (!resolvedAssumptionLevel) {
|
|
@@ -284,11 +262,7 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
284
262
|
...systemRuntimeContext,
|
|
285
263
|
...options.workflowId ? { workflowId: options.workflowId } : {},
|
|
286
264
|
assumptionLevel: resolvedAssumptionLevel,
|
|
287
|
-
utxoSelection:
|
|
288
|
-
totalUtxosSeen: allFetchedUtxos.length,
|
|
289
|
-
selectedUtxos: selectedInputsCount,
|
|
290
|
-
selectionStrategy: "largest-first"
|
|
291
|
-
}
|
|
265
|
+
utxoSelection: result.utxoSelection
|
|
292
266
|
}
|
|
293
267
|
});
|
|
294
268
|
if (options.policy || options.policies) {
|
|
@@ -323,21 +297,25 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
323
297
|
basePlan.assumptionRef = options.assumption;
|
|
324
298
|
}
|
|
325
299
|
}
|
|
326
|
-
const { CURRENT_HASH_VERSION:
|
|
327
|
-
const newHash =
|
|
300
|
+
const { CURRENT_HASH_VERSION: CURRENT_HASH_VERSION3, calculateContentHash: calculateContentHash7 } = await import("@hardkas/artifacts");
|
|
301
|
+
const newHash = calculateContentHash7(basePlan, CURRENT_HASH_VERSION3);
|
|
328
302
|
basePlan.contentHash = newHash;
|
|
329
303
|
if (basePlan.lineage) {
|
|
330
304
|
basePlan.lineage.lineageId = newHash;
|
|
331
305
|
basePlan.lineage.parentArtifactId = "";
|
|
332
306
|
basePlan.lineage.rootArtifactId = newHash;
|
|
333
|
-
const finalHash =
|
|
307
|
+
const finalHash = calculateContentHash7(basePlan, CURRENT_HASH_VERSION3);
|
|
334
308
|
basePlan.contentHash = finalHash;
|
|
335
309
|
basePlan.lineage.artifactId = finalHash;
|
|
336
310
|
basePlan.planId = `plan-${finalHash.slice(0, 16)}`;
|
|
337
311
|
}
|
|
338
312
|
this.sdk.artifacts.cacheArtifact(basePlan);
|
|
339
313
|
if (basePlan.policyRefs && basePlan.policyRefs.length > 0) {
|
|
340
|
-
await this.sdk.artifacts.verify(basePlan, {
|
|
314
|
+
await this.sdk.artifacts.verify(basePlan, {
|
|
315
|
+
throwOnInvalid: true,
|
|
316
|
+
strict: true,
|
|
317
|
+
enforceMetadata: false
|
|
318
|
+
});
|
|
341
319
|
}
|
|
342
320
|
return basePlan;
|
|
343
321
|
}
|
|
@@ -353,43 +331,28 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
353
331
|
resolvedAccount = options.account;
|
|
354
332
|
}
|
|
355
333
|
if (!resolvedAccount.address) {
|
|
356
|
-
throw new Error(
|
|
334
|
+
throw new Error(
|
|
335
|
+
`Account '${resolvedAccount.name || options.account}' has no address.`
|
|
336
|
+
);
|
|
357
337
|
}
|
|
358
338
|
const activeNetwork = options.network || this.sdk.config.config.defaultNetwork || "simnet";
|
|
359
339
|
const isSimulated = activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated";
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
outpoint: {
|
|
366
|
-
transactionId: u.outpoint.transactionId,
|
|
367
|
-
index: u.outpoint.index
|
|
368
|
-
},
|
|
369
|
-
address: u.address,
|
|
370
|
-
amountSompi: amount,
|
|
371
|
-
scriptPublicKey: u.scriptPublicKey || ""
|
|
372
|
-
};
|
|
373
|
-
});
|
|
374
|
-
const feeRate = options.feeRate ?? 1n;
|
|
375
|
-
const massPerInput = 1500n;
|
|
376
|
-
const estimatedMass = BigInt(options.selectedUtxos.length) * massPerInput + 500n;
|
|
377
|
-
const expectedFee = estimatedMass * feeRate;
|
|
378
|
-
if (totalAmount <= expectedFee) {
|
|
379
|
-
throw new Error(`Consolidation failed: Total selected UTXO amount (${totalAmount}) is less than or equal to the estimated fee (${expectedFee}).`);
|
|
380
|
-
}
|
|
381
|
-
const outputAmount = totalAmount - expectedFee;
|
|
382
|
-
const builderPlan = buildPaymentPlan({
|
|
340
|
+
const dummyProvider = {
|
|
341
|
+
getUtxos: async () => []
|
|
342
|
+
};
|
|
343
|
+
const planService = new TxPlanService(dummyProvider);
|
|
344
|
+
const result = await planService.planConsolidation({
|
|
383
345
|
fromAddress: resolvedAccount.address,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
address: options.destination,
|
|
388
|
-
amountSompi: outputAmount
|
|
389
|
-
}
|
|
390
|
-
],
|
|
391
|
-
feeRateSompiPerMass: feeRate
|
|
346
|
+
selectedUtxos: options.selectedUtxos,
|
|
347
|
+
toAddress: options.destination,
|
|
348
|
+
...options.feeRate !== void 0 ? { feeRate: options.feeRate } : {}
|
|
392
349
|
});
|
|
350
|
+
const builderPlan = result.plan;
|
|
351
|
+
const firstOutput = builderPlan.outputs[0];
|
|
352
|
+
if (!firstOutput) {
|
|
353
|
+
throw new Error("Consolidation failed: transaction builder produced no outputs.");
|
|
354
|
+
}
|
|
355
|
+
const outputAmount = firstOutput.amountSompi;
|
|
393
356
|
let resolvedAssumptionLevel = isSimulated ? "local-simulated" : "local-rpc";
|
|
394
357
|
const basePlan = createTxPlanArtifact({
|
|
395
358
|
networkId: activeNetwork,
|
|
@@ -409,21 +372,21 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
409
372
|
...systemRuntimeContext,
|
|
410
373
|
assumptionLevel: resolvedAssumptionLevel,
|
|
411
374
|
utxoSelection: {
|
|
412
|
-
strategy:
|
|
375
|
+
strategy: result.utxoSelection.selectionStrategy,
|
|
413
376
|
totalUtxosSeen: options.totalUtxosSeen ?? options.selectedUtxos.length,
|
|
414
|
-
selectedUtxos:
|
|
415
|
-
purpose:
|
|
377
|
+
selectedUtxos: result.utxoSelection.selectedUtxos,
|
|
378
|
+
purpose: result.utxoSelection.purpose
|
|
416
379
|
}
|
|
417
380
|
}
|
|
418
381
|
});
|
|
419
|
-
const { CURRENT_HASH_VERSION:
|
|
420
|
-
const newHash =
|
|
382
|
+
const { CURRENT_HASH_VERSION: CURRENT_HASH_VERSION3, calculateContentHash: calculateContentHash7 } = await import("@hardkas/artifacts");
|
|
383
|
+
const newHash = calculateContentHash7(basePlan, CURRENT_HASH_VERSION3);
|
|
421
384
|
basePlan.contentHash = newHash;
|
|
422
385
|
if (basePlan.lineage) {
|
|
423
386
|
basePlan.lineage.lineageId = newHash;
|
|
424
387
|
basePlan.lineage.parentArtifactId = "";
|
|
425
388
|
basePlan.lineage.rootArtifactId = newHash;
|
|
426
|
-
const finalHash =
|
|
389
|
+
const finalHash = calculateContentHash7(basePlan, CURRENT_HASH_VERSION3);
|
|
427
390
|
basePlan.contentHash = finalHash;
|
|
428
391
|
basePlan.lineage.artifactId = finalHash;
|
|
429
392
|
basePlan.planId = `plan-${finalHash.slice(0, 16)}`;
|
|
@@ -436,10 +399,16 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
436
399
|
*/
|
|
437
400
|
async sign(plan, account, options) {
|
|
438
401
|
if (typeof plan === "object" && plan !== null && plan.contentHash) {
|
|
439
|
-
await this.sdk.artifacts.verify(plan, {
|
|
402
|
+
await this.sdk.artifacts.verify(plan, {
|
|
403
|
+
throwOnInvalid: true,
|
|
404
|
+
strict: true,
|
|
405
|
+
enforceMetadata: false
|
|
406
|
+
});
|
|
440
407
|
}
|
|
441
|
-
if (this.sdk.signer && plan.schema ===
|
|
442
|
-
const signedArtifact2 = await this.sdk.signer.signTransaction(
|
|
408
|
+
if (this.sdk.signer && plan.schema === HardkasSchemas.TxPlan) {
|
|
409
|
+
const signedArtifact2 = await this.sdk.signer.signTransaction(
|
|
410
|
+
plan
|
|
411
|
+
);
|
|
443
412
|
const { absolutePath: absolutePath2 } = await this.sdk.artifacts.write(signedArtifact2);
|
|
444
413
|
const { coreEvents: coreEvents3 } = await import("@hardkas/core");
|
|
445
414
|
const signedRecord2 = signedArtifact2;
|
|
@@ -475,7 +444,7 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
475
444
|
resolvedAccount = await this.sdk.accounts.resolve(fromName);
|
|
476
445
|
}
|
|
477
446
|
let signedArtifact;
|
|
478
|
-
if (plan.schema ===
|
|
447
|
+
if (plan.schema === HardkasSchemas.SignedTx) {
|
|
479
448
|
if (plan.status === "signed") {
|
|
480
449
|
throw new Error(
|
|
481
450
|
"Cannot append signature to an already completed signed transaction."
|
|
@@ -535,7 +504,7 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
535
504
|
signatures: newSignatures
|
|
536
505
|
},
|
|
537
506
|
signatureMetadata: newMeta,
|
|
538
|
-
lineage: createLineageTransition(partialTx,
|
|
507
|
+
lineage: createLineageTransition(partialTx, HardkasSchemas.SignedTx)
|
|
539
508
|
};
|
|
540
509
|
if (thresholdReached) {
|
|
541
510
|
draft.signedTransaction = {
|
|
@@ -547,13 +516,13 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
547
516
|
delete draft.signedTransaction;
|
|
548
517
|
delete draft.txId;
|
|
549
518
|
}
|
|
550
|
-
const { CURRENT_HASH_VERSION:
|
|
551
|
-
const hash = calculateContentHash(draft,
|
|
519
|
+
const { CURRENT_HASH_VERSION: CURRENT_HASH_VERSION3 } = await import("@hardkas/artifacts");
|
|
520
|
+
const hash = calculateContentHash(draft, CURRENT_HASH_VERSION3);
|
|
552
521
|
draft.signedId = `signed-${hash.slice(0, 16)}`;
|
|
553
522
|
draft.contentHash = hash;
|
|
554
523
|
if (draft.lineage) draft.lineage.artifactId = hash;
|
|
555
524
|
signedArtifact = draft;
|
|
556
|
-
} else if (plan.schema ===
|
|
525
|
+
} else if (plan.schema === HardkasSchemas.TxPlan) {
|
|
557
526
|
if (options?.append) {
|
|
558
527
|
throw new Error(
|
|
559
528
|
"Do not use --append for the first signature of a transaction plan."
|
|
@@ -591,13 +560,13 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
591
560
|
];
|
|
592
561
|
const thresholdReached = signatures.length >= threshold;
|
|
593
562
|
const finalStatus = thresholdReached ? "signed" : "partially_signed";
|
|
594
|
-
const { HARDKAS_VERSION:
|
|
563
|
+
const { HARDKAS_VERSION: HARDKAS_VERSION6, ARTIFACT_VERSION: ARTIFACT_VERSION2, CURRENT_HASH_VERSION: CURRENT_HASH_VERSION3 } = await import("@hardkas/artifacts");
|
|
595
564
|
const draft = {
|
|
596
|
-
schema:
|
|
597
|
-
schemaVersion:
|
|
598
|
-
hardkasVersion:
|
|
565
|
+
schema: HardkasSchemas.SignedTx,
|
|
566
|
+
schemaVersion: HardkasSchemas.ArtifactV1,
|
|
567
|
+
hardkasVersion: HARDKAS_VERSION6,
|
|
599
568
|
version: ARTIFACT_VERSION2,
|
|
600
|
-
hashVersion:
|
|
569
|
+
hashVersion: CURRENT_HASH_VERSION3,
|
|
601
570
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
602
571
|
status: finalStatus,
|
|
603
572
|
sourcePlanId: plan.planId,
|
|
@@ -613,7 +582,7 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
613
582
|
signatures
|
|
614
583
|
},
|
|
615
584
|
signatureMetadata,
|
|
616
|
-
lineage: createLineageTransition(plan,
|
|
585
|
+
lineage: createLineageTransition(plan, HardkasSchemas.SignedTx),
|
|
617
586
|
...plan.workflowId ? { workflowId: plan.workflowId } : {}
|
|
618
587
|
};
|
|
619
588
|
if (thresholdReached) {
|
|
@@ -623,19 +592,21 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
623
592
|
};
|
|
624
593
|
draft.txId = `simulated-${plan.planId}-tx`;
|
|
625
594
|
}
|
|
626
|
-
let hash = calculateContentHash(draft,
|
|
595
|
+
let hash = calculateContentHash(draft, CURRENT_HASH_VERSION3);
|
|
627
596
|
draft.signedId = `signed-${hash.slice(0, 16)}`;
|
|
628
597
|
draft.contentHash = hash;
|
|
629
598
|
if (draft.lineage) {
|
|
630
599
|
draft.lineage.artifactId = hash;
|
|
631
|
-
hash = calculateContentHash(draft,
|
|
600
|
+
hash = calculateContentHash(draft, CURRENT_HASH_VERSION3);
|
|
632
601
|
draft.contentHash = hash;
|
|
633
602
|
draft.lineage.artifactId = hash;
|
|
634
603
|
}
|
|
635
604
|
signedArtifact = draft;
|
|
636
605
|
} else {
|
|
637
606
|
if (resolvedAccount.address !== plan.from.address) {
|
|
638
|
-
throw new Error(
|
|
607
|
+
throw new Error(
|
|
608
|
+
`Signer account '${resolvedAccount.address}' is not authorized to sign for '${plan.from.address}'.`
|
|
609
|
+
);
|
|
639
610
|
}
|
|
640
611
|
signedArtifact = await signTxPlanArtifact({
|
|
641
612
|
planArtifact: plan,
|
|
@@ -675,7 +646,11 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
675
646
|
async simulate(target, options = {}) {
|
|
676
647
|
if (typeof target === "object" && target !== null && target.contentHash) {
|
|
677
648
|
try {
|
|
678
|
-
await this.sdk.artifacts.verify(target, {
|
|
649
|
+
await this.sdk.artifacts.verify(target, {
|
|
650
|
+
throwOnInvalid: true,
|
|
651
|
+
strict: true,
|
|
652
|
+
enforceMetadata: false
|
|
653
|
+
});
|
|
679
654
|
} catch (e) {
|
|
680
655
|
if (e.message.includes("PARENT_MISSING")) {
|
|
681
656
|
throw new Error("parent_plan_unresolved: Missing context plan for simulation.");
|
|
@@ -688,7 +663,9 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
688
663
|
const checkTxId = target.txId || (target.schema === ARTIFACT_SCHEMAS.SIGNED_TX ? `simulated-${target.sourcePlanId || "unknown"}-tx` : `simulated-${target.planId || target.id || "unknown"}-tx`);
|
|
689
664
|
if (checkTxId) {
|
|
690
665
|
try {
|
|
691
|
-
const existingReceipt = await this.sdk.artifacts.read(checkTxId, {
|
|
666
|
+
const existingReceipt = await this.sdk.artifacts.read(checkTxId, {
|
|
667
|
+
expectedSchema: ARTIFACT_SCHEMAS.TX_RECEIPT
|
|
668
|
+
});
|
|
692
669
|
if (existingReceipt && existingReceipt.schema === ARTIFACT_SCHEMAS.TX_RECEIPT) {
|
|
693
670
|
const receiptPath2 = getDefaultReceiptPath(checkTxId, this.sdk.config.cwd);
|
|
694
671
|
return { receipt: existingReceipt, receiptPath: receiptPath2 };
|
|
@@ -705,7 +682,7 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
705
682
|
saveSimulatedReceipt,
|
|
706
683
|
saveSimulatedTrace
|
|
707
684
|
} = await import("@hardkas/localnet");
|
|
708
|
-
const
|
|
685
|
+
const path9 = await import("path");
|
|
709
686
|
const state = await loadOrCreateLocalnetState({ cwd: this.sdk.workspace.root });
|
|
710
687
|
const startTime = Date.now();
|
|
711
688
|
const events = [
|
|
@@ -718,9 +695,13 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
718
695
|
let targetObj = target;
|
|
719
696
|
if (typeof target === "string") {
|
|
720
697
|
try {
|
|
721
|
-
targetObj = await this.sdk.artifacts.read(target, {
|
|
698
|
+
targetObj = await this.sdk.artifacts.read(target, {
|
|
699
|
+
expectedSchema: ARTIFACT_SCHEMAS.TX_PLAN
|
|
700
|
+
});
|
|
722
701
|
} catch (e) {
|
|
723
|
-
throw new Error(
|
|
702
|
+
throw new Error(
|
|
703
|
+
`Artifact '${target}' not found. If you already have an in-memory artifact, pass the object directly to tx.simulate(artifact).`
|
|
704
|
+
);
|
|
724
705
|
}
|
|
725
706
|
}
|
|
726
707
|
if (targetObj.schema === ARTIFACT_SCHEMAS.SIGNED_TX) {
|
|
@@ -730,7 +711,9 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
730
711
|
planArtifact = this.sdk.artifacts.getCached(sourcePlanId);
|
|
731
712
|
if (!planArtifact) {
|
|
732
713
|
try {
|
|
733
|
-
planArtifact = await this.sdk.artifacts.read(sourcePlanId, {
|
|
714
|
+
planArtifact = await this.sdk.artifacts.read(sourcePlanId, {
|
|
715
|
+
expectedSchema: ARTIFACT_SCHEMAS.TX_PLAN
|
|
716
|
+
});
|
|
734
717
|
} catch (e) {
|
|
735
718
|
throw new Error("parent_plan_unresolved");
|
|
736
719
|
}
|
|
@@ -776,7 +759,7 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
776
759
|
const isSimulated = activeNetwork === "simulated" || this.sdk.config.config.networks?.[activeNetwork]?.kind === "simulated";
|
|
777
760
|
const receiptBase = {
|
|
778
761
|
schema: ARTIFACT_SCHEMAS.TX_RECEIPT,
|
|
779
|
-
schemaVersion:
|
|
762
|
+
schemaVersion: HardkasSchemas.TxReceiptV1,
|
|
780
763
|
hardkasVersion: HARDKAS_VERSION,
|
|
781
764
|
version: ARTIFACT_VERSION,
|
|
782
765
|
hashVersion: CURRENT_HASH_VERSION,
|
|
@@ -878,7 +861,11 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
878
861
|
async send(signedArtifact, urlOrOptions) {
|
|
879
862
|
if (typeof signedArtifact === "object" && signedArtifact !== null && signedArtifact.contentHash) {
|
|
880
863
|
try {
|
|
881
|
-
await this.sdk.artifacts.verify(signedArtifact, {
|
|
864
|
+
await this.sdk.artifacts.verify(signedArtifact, {
|
|
865
|
+
throwOnInvalid: true,
|
|
866
|
+
strict: true,
|
|
867
|
+
enforceMetadata: false
|
|
868
|
+
});
|
|
882
869
|
} catch (e) {
|
|
883
870
|
if (e.message.includes("PARENT_MISSING")) {
|
|
884
871
|
throw new Error("parent_plan_unresolved: Missing context plan for simulation.");
|
|
@@ -906,7 +893,9 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
906
893
|
try {
|
|
907
894
|
const { loadSimulatedReceipt, getReceiptPath } = await import("@hardkas/localnet");
|
|
908
895
|
const txIdToLoad = signedArtifact.txId || `simulated-${signedArtifact.sourcePlanId}-tx`;
|
|
909
|
-
const existingReceipt = await loadSimulatedReceipt(txIdToLoad, {
|
|
896
|
+
const existingReceipt = await loadSimulatedReceipt(txIdToLoad, {
|
|
897
|
+
cwd: this.sdk.workspace.root
|
|
898
|
+
});
|
|
910
899
|
if (existingReceipt) {
|
|
911
900
|
if (existingReceipt.schema === ARTIFACT_SCHEMAS.TX_RECEIPT && (existingReceipt.status === "confirmed" || existingReceipt.status === "accepted")) {
|
|
912
901
|
return {
|
|
@@ -917,7 +906,10 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
917
906
|
artifactId: existingReceipt.txId,
|
|
918
907
|
// simulated receipts use txId as artifactId
|
|
919
908
|
receipt: existingReceipt,
|
|
920
|
-
receiptPath: getReceiptPath(
|
|
909
|
+
receiptPath: getReceiptPath(
|
|
910
|
+
existingReceipt.txId,
|
|
911
|
+
this.sdk.workspace.root
|
|
912
|
+
)
|
|
921
913
|
};
|
|
922
914
|
}
|
|
923
915
|
}
|
|
@@ -972,7 +964,7 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
972
964
|
...signedArtifact.networkProfileRef ? { networkProfileRef: signedArtifact.networkProfileRef } : {},
|
|
973
965
|
...signedArtifact.assumptionRef ? { assumptionRef: signedArtifact.assumptionRef } : {},
|
|
974
966
|
tracePath: void 0,
|
|
975
|
-
lineage: createLineageTransition(signedArtifact,
|
|
967
|
+
lineage: createLineageTransition(signedArtifact, HardkasSchemas.TxReceipt)
|
|
976
968
|
};
|
|
977
969
|
realReceiptBase.contentHash = calculateContentHash(
|
|
978
970
|
realReceiptBase,
|
|
@@ -980,7 +972,10 @@ Hint: Run 'hardkas accounts consolidate' to merge dust UTXOs.`);
|
|
|
980
972
|
);
|
|
981
973
|
if (realReceiptBase.lineage) {
|
|
982
974
|
realReceiptBase.lineage.artifactId = realReceiptBase.contentHash;
|
|
983
|
-
realReceiptBase.contentHash = calculateContentHash(
|
|
975
|
+
realReceiptBase.contentHash = calculateContentHash(
|
|
976
|
+
realReceiptBase,
|
|
977
|
+
CURRENT_HASH_VERSION
|
|
978
|
+
);
|
|
984
979
|
realReceiptBase.lineage.artifactId = realReceiptBase.contentHash;
|
|
985
980
|
}
|
|
986
981
|
const receipt = realReceiptBase;
|
|
@@ -1051,11 +1046,13 @@ var HardkasQuery = class {
|
|
|
1051
1046
|
* Synchronizes the query store with the filesystem artifacts.
|
|
1052
1047
|
*/
|
|
1053
1048
|
async sync(options) {
|
|
1054
|
-
const
|
|
1055
|
-
const
|
|
1056
|
-
const hardkasDir =
|
|
1057
|
-
if (!
|
|
1058
|
-
throw new Error(
|
|
1049
|
+
const fs9 = await import("fs");
|
|
1050
|
+
const path9 = await import("path");
|
|
1051
|
+
const hardkasDir = path9.join(this.sdk.workspace.root, ".hardkas");
|
|
1052
|
+
if (!fs9.existsSync(hardkasDir)) {
|
|
1053
|
+
throw new Error(
|
|
1054
|
+
"Workspace not initialized. Run hardkas init or Hardkas.create({ autoBootstrap:true })."
|
|
1055
|
+
);
|
|
1059
1056
|
}
|
|
1060
1057
|
let HardkasStore, HardkasIndexer;
|
|
1061
1058
|
try {
|
|
@@ -1063,10 +1060,12 @@ var HardkasQuery = class {
|
|
|
1063
1060
|
HardkasStore = qs.HardkasStore;
|
|
1064
1061
|
HardkasIndexer = qs.HardkasIndexer;
|
|
1065
1062
|
} catch (e) {
|
|
1066
|
-
throw new Error(
|
|
1063
|
+
throw new Error(
|
|
1064
|
+
"Query store backend unavailable. Install @hardkas/query-store or run query.store.rebuild."
|
|
1065
|
+
);
|
|
1067
1066
|
}
|
|
1068
1067
|
const { withLock } = await import("@hardkas/core");
|
|
1069
|
-
const dbPath =
|
|
1068
|
+
const dbPath = path9.join(hardkasDir, "store.db");
|
|
1070
1069
|
const store = new HardkasStore({ dbPath });
|
|
1071
1070
|
let stats;
|
|
1072
1071
|
try {
|
|
@@ -1089,7 +1088,9 @@ var HardkasQuery = class {
|
|
|
1089
1088
|
);
|
|
1090
1089
|
} catch (e) {
|
|
1091
1090
|
if (e.message?.includes("SQLITE") || e.message?.includes("Cannot read properties")) {
|
|
1092
|
-
throw new Error(
|
|
1091
|
+
throw new Error(
|
|
1092
|
+
"Query store database is not configured correctly or corrupted. Try running query.sync({ force: true })."
|
|
1093
|
+
);
|
|
1093
1094
|
}
|
|
1094
1095
|
throw e;
|
|
1095
1096
|
}
|
|
@@ -1118,6 +1119,8 @@ var HardkasQuery = class {
|
|
|
1118
1119
|
};
|
|
1119
1120
|
|
|
1120
1121
|
// src/localnet.ts
|
|
1122
|
+
import { execFileSync } from "child_process";
|
|
1123
|
+
import { HardkasSchemas as HardkasSchemas2 } from "@hardkas/artifacts";
|
|
1121
1124
|
var HardkasLocalnet = class {
|
|
1122
1125
|
constructor(sdk) {
|
|
1123
1126
|
this.sdk = sdk;
|
|
@@ -1135,17 +1138,141 @@ var HardkasLocalnet = class {
|
|
|
1135
1138
|
}
|
|
1136
1139
|
}
|
|
1137
1140
|
/**
|
|
1138
|
-
*
|
|
1141
|
+
* Status check with the same claim boundaries as `hardkas localnet status --json`.
|
|
1139
1142
|
*/
|
|
1140
|
-
async
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
+
async status(options = {}) {
|
|
1144
|
+
const profile = options.profile || "toccata-v2";
|
|
1145
|
+
const node = await this.detectToccataNode();
|
|
1146
|
+
return {
|
|
1147
|
+
schema: HardkasSchemas2.LocalnetStatusV1,
|
|
1148
|
+
profile,
|
|
1149
|
+
node,
|
|
1150
|
+
miner: this.inspectDockerContainer("hardkas-toccata-stratum-v2"),
|
|
1151
|
+
simulationLevels: {
|
|
1152
|
+
artifactCoherence: "READY",
|
|
1153
|
+
runtimeOutcome: "PARTIAL",
|
|
1154
|
+
vmConsensusEquivalence: "NOT_CLAIMED"
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Initializes the in-memory simulated workspace.
|
|
1160
|
+
*
|
|
1161
|
+
* Docker Toccata process control remains a CLI/localnet responsibility in
|
|
1162
|
+
* 0.9.1-alpha; the SDK reports that boundary instead of silently shelling out.
|
|
1163
|
+
*/
|
|
1164
|
+
async start(options = {}) {
|
|
1165
|
+
const profile = options.profile || "simulated";
|
|
1166
|
+
if (profile === "simulated") {
|
|
1167
|
+
const { loadOrCreateLocalnetState } = await import("@hardkas/localnet");
|
|
1168
|
+
await loadOrCreateLocalnetState({ cwd: this.sdk.cwd });
|
|
1169
|
+
return {
|
|
1170
|
+
schema: HardkasSchemas2.LocalnetControlV1,
|
|
1171
|
+
profile,
|
|
1172
|
+
status: "SIMULATED_LOCALNET_READY",
|
|
1173
|
+
message: "Simulated localnet state is ready."
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
return {
|
|
1177
|
+
schema: HardkasSchemas2.LocalnetControlV1,
|
|
1178
|
+
profile,
|
|
1179
|
+
status: "SDK_LOCALNET_CONTROL_UNSUPPORTED",
|
|
1180
|
+
message: "SDK Docker localnet start is not supported in 0.9.1-alpha. Use `hardkas localnet start --profile toccata-v2`."
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Funds a simulated account through the SDK transaction flow.
|
|
1185
|
+
*
|
|
1186
|
+
* Toccata Docker mining/funding remains CLI-only in 0.9.1-alpha because it
|
|
1187
|
+
* depends on a local stratum/miner companion and host Docker state.
|
|
1188
|
+
*/
|
|
1189
|
+
async fund(identifier, options = {}) {
|
|
1190
|
+
const profile = options.profile || (this.sdk.network === "simulated" ? "simulated" : "toccata-v2");
|
|
1191
|
+
if (profile === "simulated") {
|
|
1192
|
+
const fundOptions = {};
|
|
1193
|
+
if (options.from !== void 0) fundOptions.from = options.from;
|
|
1194
|
+
if (options.amount !== void 0) fundOptions.amount = options.amount;
|
|
1195
|
+
const receipt = await this.sdk.accounts.fund(identifier, fundOptions);
|
|
1196
|
+
return {
|
|
1197
|
+
schema: HardkasSchemas2.LocalnetFundingV1,
|
|
1198
|
+
profile,
|
|
1199
|
+
identifier,
|
|
1200
|
+
status: "SIMULATED_ACCOUNT_FUNDED",
|
|
1201
|
+
receipt,
|
|
1202
|
+
message: "Simulated account funded through SDK transaction simulation."
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
return {
|
|
1206
|
+
schema: HardkasSchemas2.LocalnetFundingV1,
|
|
1207
|
+
profile,
|
|
1208
|
+
identifier,
|
|
1209
|
+
status: "SDK_TOCCATA_FUNDING_UNSUPPORTED",
|
|
1210
|
+
message: "SDK Toccata funding is not supported in 0.9.1-alpha. Use `hardkas localnet fund <account> --profile toccata-v2`."
|
|
1211
|
+
};
|
|
1143
1212
|
}
|
|
1144
1213
|
/**
|
|
1145
1214
|
* Resets the localnet state (simulated or node).
|
|
1146
1215
|
*/
|
|
1147
1216
|
async reset() {
|
|
1148
|
-
|
|
1217
|
+
const { resetLocalnetState } = await import("@hardkas/localnet");
|
|
1218
|
+
await resetLocalnetState({ cwd: this.sdk.cwd });
|
|
1219
|
+
}
|
|
1220
|
+
async detectToccataNode() {
|
|
1221
|
+
const rpcUrl = "ws://127.0.0.1:18210";
|
|
1222
|
+
const { JsonWrpcKaspaClient: JsonWrpcKaspaClient2 } = await import("@hardkas/kaspa-rpc");
|
|
1223
|
+
const client = new JsonWrpcKaspaClient2({ rpcUrl, timeoutMs: 3e3 });
|
|
1224
|
+
try {
|
|
1225
|
+
const server = await client.getServerInfo();
|
|
1226
|
+
const info = await client.getInfo();
|
|
1227
|
+
const serverNetworkId = String(server.networkId || "");
|
|
1228
|
+
const result = {
|
|
1229
|
+
ready: true,
|
|
1230
|
+
rpcUrl,
|
|
1231
|
+
networkId: serverNetworkId === "unknown" ? "simnet" : server.networkId || info.networkId || "simnet",
|
|
1232
|
+
serverVersion: server.serverVersion || info.serverVersion,
|
|
1233
|
+
isSynced: server.isSynced ?? info.isSynced,
|
|
1234
|
+
virtualDaaScore: info.virtualDaaScore?.toString()
|
|
1235
|
+
};
|
|
1236
|
+
await client.close();
|
|
1237
|
+
return result;
|
|
1238
|
+
} catch (error) {
|
|
1239
|
+
await client.close().catch(() => {
|
|
1240
|
+
});
|
|
1241
|
+
return {
|
|
1242
|
+
ready: false,
|
|
1243
|
+
rpcUrl,
|
|
1244
|
+
lastError: error?.message || String(error)
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
inspectDockerContainer(name) {
|
|
1249
|
+
const image = "hardkas/stratum-bridge:v2.0.0-local-simnet-unsynced";
|
|
1250
|
+
try {
|
|
1251
|
+
const stdout = execFileSync(
|
|
1252
|
+
"docker",
|
|
1253
|
+
["inspect", "--format", "{{.State.Status}}|{{.Config.Image}}|{{.Name}}", name],
|
|
1254
|
+
{
|
|
1255
|
+
encoding: "utf8",
|
|
1256
|
+
stdio: "pipe"
|
|
1257
|
+
}
|
|
1258
|
+
);
|
|
1259
|
+
const [status, detectedImage, rawName] = stdout.trim().split("|");
|
|
1260
|
+
return {
|
|
1261
|
+
exists: true,
|
|
1262
|
+
running: status === "running",
|
|
1263
|
+
status: status || "unknown",
|
|
1264
|
+
image: detectedImage || image,
|
|
1265
|
+
name: rawName?.replace(/^\//, "") || name
|
|
1266
|
+
};
|
|
1267
|
+
} catch {
|
|
1268
|
+
return {
|
|
1269
|
+
exists: false,
|
|
1270
|
+
running: false,
|
|
1271
|
+
status: "not-found",
|
|
1272
|
+
image,
|
|
1273
|
+
name
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1149
1276
|
}
|
|
1150
1277
|
};
|
|
1151
1278
|
|
|
@@ -1159,6 +1286,7 @@ import {
|
|
|
1159
1286
|
writeArtifact as writeArtifact2
|
|
1160
1287
|
} from "@hardkas/artifacts";
|
|
1161
1288
|
import { deterministicCompare as deterministicCompare2 } from "@hardkas/core";
|
|
1289
|
+
import { HardkasSchemas as HardkasSchemas3 } from "@hardkas/artifacts";
|
|
1162
1290
|
function resolveReplayTargets(cwd, options) {
|
|
1163
1291
|
if (options.path) {
|
|
1164
1292
|
const fullPath = path.resolve(cwd, options.path);
|
|
@@ -1212,13 +1340,13 @@ function resolveFromDirectory(dir, source) {
|
|
|
1212
1340
|
const raw = fs.readFileSync(path.join(dir, f), "utf-8");
|
|
1213
1341
|
const data = JSON.parse(raw);
|
|
1214
1342
|
if (!data || !data.schema) continue;
|
|
1215
|
-
if (data.schema ===
|
|
1343
|
+
if (data.schema === HardkasSchemas3.TxPlan) {
|
|
1216
1344
|
plans.push({
|
|
1217
1345
|
file: f,
|
|
1218
1346
|
planId: data.planId || "",
|
|
1219
1347
|
createdAt: data.createdAt || ""
|
|
1220
1348
|
});
|
|
1221
|
-
} else if (data.schema ===
|
|
1349
|
+
} else if (data.schema === HardkasSchemas3.TxReceipt) {
|
|
1222
1350
|
receipts.push({
|
|
1223
1351
|
file: f,
|
|
1224
1352
|
sourcePlanId: data.sourcePlanId || data.lineage?.parentArtifactId || data.lineage?.rootArtifactId || "",
|
|
@@ -1269,7 +1397,7 @@ function findReceiptByPlanId(dir, planId) {
|
|
|
1269
1397
|
try {
|
|
1270
1398
|
const raw = fs.readFileSync(path.join(dir, f), "utf-8");
|
|
1271
1399
|
const data = JSON.parse(raw);
|
|
1272
|
-
if (data && data.schema ===
|
|
1400
|
+
if (data && data.schema === HardkasSchemas3.TxReceipt && (data.sourcePlanId && data.sourcePlanId === planId || data.lineage?.parentArtifactId && data.lineage.parentArtifactId === planId || data.lineage?.rootArtifactId && data.lineage.rootArtifactId === planId || data.txId && data.txId.includes(planId))) {
|
|
1273
1401
|
return path.join(dir, f);
|
|
1274
1402
|
}
|
|
1275
1403
|
} catch {
|
|
@@ -1289,7 +1417,10 @@ var HardkasReplay = class {
|
|
|
1289
1417
|
async verify(targetOrOptions, options) {
|
|
1290
1418
|
const throwOnInvalid = options?.throwOnInvalid !== false;
|
|
1291
1419
|
if (typeof targetOrOptions === "object" && targetOrOptions !== null && targetOrOptions.contentHash) {
|
|
1292
|
-
const verifyRes = await this.sdk.artifacts.verify(targetOrOptions, {
|
|
1420
|
+
const verifyRes = await this.sdk.artifacts.verify(targetOrOptions, {
|
|
1421
|
+
throwOnInvalid,
|
|
1422
|
+
strict: true
|
|
1423
|
+
});
|
|
1293
1424
|
if (!verifyRes.valid && !throwOnInvalid) {
|
|
1294
1425
|
return {
|
|
1295
1426
|
passed: false,
|
|
@@ -1360,10 +1491,10 @@ var HardkasReplay = class {
|
|
|
1360
1491
|
artifactCount++;
|
|
1361
1492
|
if (isContaminated(json)) contaminationOk = false;
|
|
1362
1493
|
const isCoreArtifact = [
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1494
|
+
HardkasSchemas3.TxPlan,
|
|
1495
|
+
HardkasSchemas3.SignedTx,
|
|
1496
|
+
HardkasSchemas3.TxReceipt,
|
|
1497
|
+
HardkasSchemas3.Snapshot
|
|
1367
1498
|
].includes(json.schema);
|
|
1368
1499
|
if (isCoreArtifact) {
|
|
1369
1500
|
const integrity = await verifyArtifactIntegrity(json);
|
|
@@ -1390,7 +1521,7 @@ var HardkasReplay = class {
|
|
|
1390
1521
|
"utf-8"
|
|
1391
1522
|
);
|
|
1392
1523
|
const wfArtifact = JSON.parse(wfArtifactStr);
|
|
1393
|
-
if (wfArtifact.schema !==
|
|
1524
|
+
if (wfArtifact.schema !== HardkasSchemas3.WorkflowV1) {
|
|
1394
1525
|
throw new Error(`Artifact ${opts.workflowId} is not a workflow artifact`);
|
|
1395
1526
|
}
|
|
1396
1527
|
const childArtifacts = wfArtifact.producedArtifacts || [];
|
|
@@ -1566,8 +1697,8 @@ var HardkasArtifactsManager = class {
|
|
|
1566
1697
|
async write(artifact, options = {}) {
|
|
1567
1698
|
const record = artifact;
|
|
1568
1699
|
if (!record.hashVersion) {
|
|
1569
|
-
const { CURRENT_HASH_VERSION:
|
|
1570
|
-
record.hashVersion =
|
|
1700
|
+
const { CURRENT_HASH_VERSION: CURRENT_HASH_VERSION3 } = await import("@hardkas/artifacts");
|
|
1701
|
+
record.hashVersion = CURRENT_HASH_VERSION3;
|
|
1571
1702
|
}
|
|
1572
1703
|
const hash = record.contentHash || "unknown";
|
|
1573
1704
|
if (record.planId) this.cache.set(record.planId, artifact);
|
|
@@ -1588,8 +1719,8 @@ var HardkasArtifactsManager = class {
|
|
|
1588
1719
|
const shortSchema = schema.replace("hardkas.", "");
|
|
1589
1720
|
const fileName = options.fileName || `${shortSchema}-${hash}.json`;
|
|
1590
1721
|
const absolutePath = path3.join(outputDir, fileName);
|
|
1591
|
-
const { writeArtifact:
|
|
1592
|
-
await
|
|
1722
|
+
const { writeArtifact: writeArtifact5 } = await import("@hardkas/artifacts");
|
|
1723
|
+
await writeArtifact5(absolutePath, artifact);
|
|
1593
1724
|
const {
|
|
1594
1725
|
coreEvents: coreEvents2,
|
|
1595
1726
|
createEventEnvelope,
|
|
@@ -1642,7 +1773,10 @@ var HardkasArtifactsManager = class {
|
|
|
1642
1773
|
const rootRel = path3.relative(this.workspace.root, resolvedPath);
|
|
1643
1774
|
const artifactsRel = path3.relative(this.workspace.artifactsDir, resolvedPath);
|
|
1644
1775
|
if ((rootRel.startsWith("..") || path3.isAbsolute(rootRel)) && (artifactsRel.startsWith("..") || path3.isAbsolute(artifactsRel))) {
|
|
1645
|
-
throw new HardkasError(
|
|
1776
|
+
throw new HardkasError(
|
|
1777
|
+
"PATH_TRAVERSAL",
|
|
1778
|
+
"Artifact path escapes workspace boundary"
|
|
1779
|
+
);
|
|
1646
1780
|
}
|
|
1647
1781
|
if (!fs3.existsSync(filePath)) {
|
|
1648
1782
|
filePath = path3.join(this.workspace.artifactsDir, `${id}.json`);
|
|
@@ -1680,7 +1814,9 @@ var HardkasArtifactsManager = class {
|
|
|
1680
1814
|
}
|
|
1681
1815
|
const artifact = await readArtifact(filePath);
|
|
1682
1816
|
if (options?.expectedSchema && artifact.schema !== options.expectedSchema) {
|
|
1683
|
-
throw new Error(
|
|
1817
|
+
throw new Error(
|
|
1818
|
+
`Artifact ${id} has schema '${artifact.schema}' but expected '${options.expectedSchema}'`
|
|
1819
|
+
);
|
|
1684
1820
|
}
|
|
1685
1821
|
return artifact;
|
|
1686
1822
|
}
|
|
@@ -1703,7 +1839,9 @@ var HardkasArtifactsManager = class {
|
|
|
1703
1839
|
for (const file of files) {
|
|
1704
1840
|
if (file.endsWith(".json")) {
|
|
1705
1841
|
try {
|
|
1706
|
-
const artifact = await readArtifact(
|
|
1842
|
+
const artifact = await readArtifact(
|
|
1843
|
+
path3.join(this.workspace.artifactsDir, file)
|
|
1844
|
+
);
|
|
1707
1845
|
artifacts.push(artifact);
|
|
1708
1846
|
} catch (e) {
|
|
1709
1847
|
}
|
|
@@ -1724,14 +1862,24 @@ var HardkasArtifactsManager = class {
|
|
|
1724
1862
|
if (typeof target === "string") {
|
|
1725
1863
|
id = target;
|
|
1726
1864
|
if (!id) {
|
|
1727
|
-
if (throwOnInvalid)
|
|
1728
|
-
|
|
1865
|
+
if (throwOnInvalid)
|
|
1866
|
+
throw new Error("No artifact target provided for verification.");
|
|
1867
|
+
return {
|
|
1868
|
+
valid: false,
|
|
1869
|
+
reason: "unknown",
|
|
1870
|
+
message: "No artifact target provided for verification."
|
|
1871
|
+
};
|
|
1729
1872
|
}
|
|
1730
1873
|
try {
|
|
1731
1874
|
artifact = await this.read(id);
|
|
1732
1875
|
} catch (e) {
|
|
1733
1876
|
if (throwOnInvalid) throw e;
|
|
1734
|
-
return {
|
|
1877
|
+
return {
|
|
1878
|
+
valid: false,
|
|
1879
|
+
reason: "missing_artifact",
|
|
1880
|
+
message: e.message,
|
|
1881
|
+
artifactId: id
|
|
1882
|
+
};
|
|
1735
1883
|
}
|
|
1736
1884
|
} else {
|
|
1737
1885
|
artifact = target;
|
|
@@ -1755,7 +1903,9 @@ var HardkasArtifactsManager = class {
|
|
|
1755
1903
|
if (!result.ok) {
|
|
1756
1904
|
const mappedReason = result.issues[0]?.code === "HASH_MISMATCH" ? "content_hash_mismatch" : result.issues[0]?.code === "MISSING_CONTENT_HASH" ? "missing_content_hash" : result.issues[0]?.code === "MISSING_SIGNATURE" ? "missing_signature" : result.issues[0]?.code === "REFERENCE_MISSING" ? "reference_missing" : result.issues[0]?.code === "REFERENCE_HASH_MISMATCH" ? "reference_hash_mismatch" : result.issues[0]?.code === "POLICY_VIOLATION" ? "policy_violation" : result.issues[0]?.code === "LEGACY_HASH_VERSION_UNSAFE" ? "legacy_hash_version_unsafe" : result.issues[0]?.code === "PARENT_MISSING" ? "parent_missing" : "schema_invalid";
|
|
1757
1905
|
if (throwOnInvalid) {
|
|
1758
|
-
throw new Error(
|
|
1906
|
+
throw new Error(
|
|
1907
|
+
`Artifact ${id} corrupted or invalid: ` + JSON.stringify(result.issues, null, 2)
|
|
1908
|
+
);
|
|
1759
1909
|
}
|
|
1760
1910
|
return {
|
|
1761
1911
|
valid: false,
|
|
@@ -1785,7 +1935,9 @@ var HardkasArtifactsManager = class {
|
|
|
1785
1935
|
const { migrateArtifactPayload, generateMigrationReceipt } = await import("@hardkas/artifacts");
|
|
1786
1936
|
const result = migrateArtifactPayload(artifact, void 0, { strictPolicy: false });
|
|
1787
1937
|
if (!result.migrated) {
|
|
1788
|
-
throw new Error(
|
|
1938
|
+
throw new Error(
|
|
1939
|
+
`Artifact ${artifact.artifactId || artifact.contentHash} is already at the target version or cannot be migrated.`
|
|
1940
|
+
);
|
|
1789
1941
|
}
|
|
1790
1942
|
const receipt = generateMigrationReceipt(artifact, result.artifact, migrationId);
|
|
1791
1943
|
await this.write(result.artifact);
|
|
@@ -1797,6 +1949,7 @@ var HardkasArtifactsManager = class {
|
|
|
1797
1949
|
// src/workflow.ts
|
|
1798
1950
|
import { HARDKAS_VERSION as HARDKAS_VERSION2 } from "@hardkas/artifacts";
|
|
1799
1951
|
import { HardkasError as HardkasError2, deterministicCompare as deterministicCompare3 } from "@hardkas/core";
|
|
1952
|
+
import { HardkasSchemas as HardkasSchemas4 } from "@hardkas/artifacts";
|
|
1800
1953
|
var HardkasWorkflow = class {
|
|
1801
1954
|
constructor(sdk) {
|
|
1802
1955
|
this.sdk = sdk;
|
|
@@ -1806,9 +1959,9 @@ var HardkasWorkflow = class {
|
|
|
1806
1959
|
* Executes a sequence of declarative steps and returns a definitive WorkflowArtifact.
|
|
1807
1960
|
*/
|
|
1808
1961
|
async run(options) {
|
|
1809
|
-
const { calculateContentHash:
|
|
1962
|
+
const { calculateContentHash: calculateContentHash7 } = await import("@hardkas/artifacts");
|
|
1810
1963
|
const intentPayload = {
|
|
1811
|
-
type:
|
|
1964
|
+
type: HardkasSchemas4.WorkflowIntent,
|
|
1812
1965
|
schemaVersion: "v1",
|
|
1813
1966
|
workflowSpec: options.steps,
|
|
1814
1967
|
normalizedInputs: {},
|
|
@@ -1825,9 +1978,9 @@ var HardkasWorkflow = class {
|
|
|
1825
1978
|
network: this.sdk.network
|
|
1826
1979
|
},
|
|
1827
1980
|
runtimeVersion: HARDKAS_VERSION2,
|
|
1828
|
-
workspaceSchemaVersion:
|
|
1981
|
+
workspaceSchemaVersion: HardkasSchemas4.WorkflowV1
|
|
1829
1982
|
};
|
|
1830
|
-
const intentHash =
|
|
1983
|
+
const intentHash = calculateContentHash7(intentPayload);
|
|
1831
1984
|
const workflowId = `wf_${intentHash.slice(0, 16)}`;
|
|
1832
1985
|
const artifactSteps = [];
|
|
1833
1986
|
const producedArtifacts = [];
|
|
@@ -1978,7 +2131,6 @@ var HardkasWorkflow = class {
|
|
|
1978
2131
|
if (producedArtifactId) stepRecord.producedArtifactId = producedArtifactId;
|
|
1979
2132
|
artifactSteps.push(stepRecord);
|
|
1980
2133
|
} catch (e) {
|
|
1981
|
-
console.error("DEBUG WORKFLOW ERROR:", e.stack);
|
|
1982
2134
|
status = "failed";
|
|
1983
2135
|
errorEnvelope = {
|
|
1984
2136
|
code: e.code || "WORKFLOW_STEP_FAILED",
|
|
@@ -1998,7 +2150,7 @@ var HardkasWorkflow = class {
|
|
|
1998
2150
|
}
|
|
1999
2151
|
const executionMode = this.sdk.network === "simulated" ? "simulated" : "real";
|
|
2000
2152
|
const artifact = {
|
|
2001
|
-
schema:
|
|
2153
|
+
schema: HardkasSchemas4.WorkflowV1,
|
|
2002
2154
|
version: "1.0.0-alpha",
|
|
2003
2155
|
hardkasVersion: HARDKAS_VERSION2,
|
|
2004
2156
|
networkId: this.sdk.network,
|
|
@@ -2028,7 +2180,7 @@ var HardkasWorkflow = class {
|
|
|
2028
2180
|
if (errorEnvelope) {
|
|
2029
2181
|
artifact.errorEnvelope = errorEnvelope;
|
|
2030
2182
|
}
|
|
2031
|
-
artifact.contentHash =
|
|
2183
|
+
artifact.contentHash = calculateContentHash7(artifact, 1);
|
|
2032
2184
|
if (!options.dryRun) {
|
|
2033
2185
|
this.sdk.enforcePolicy("mutation", "Workflow Runtime saving artifact");
|
|
2034
2186
|
await this.sdk.artifacts.write(artifact, {
|
|
@@ -2039,6 +2191,1750 @@ var HardkasWorkflow = class {
|
|
|
2039
2191
|
}
|
|
2040
2192
|
};
|
|
2041
2193
|
|
|
2194
|
+
// src/capabilities.ts
|
|
2195
|
+
import { CURRENT_HASH_VERSION as CURRENT_HASH_VERSION2, HARDKAS_VERSION as HARDKAS_VERSION3 } from "@hardkas/artifacts";
|
|
2196
|
+
var HardkasCapabilitiesApi = class {
|
|
2197
|
+
async get() {
|
|
2198
|
+
return createHardkasCapabilities();
|
|
2199
|
+
}
|
|
2200
|
+
};
|
|
2201
|
+
function createHardkasCapabilities() {
|
|
2202
|
+
return {
|
|
2203
|
+
version: HARDKAS_VERSION3,
|
|
2204
|
+
maturity: "hardened-alpha",
|
|
2205
|
+
proofVersion: "repro-v0",
|
|
2206
|
+
hashVersion: CURRENT_HASH_VERSION2,
|
|
2207
|
+
capabilities: {
|
|
2208
|
+
artifacts: true,
|
|
2209
|
+
lineageVerification: true,
|
|
2210
|
+
deterministicHashing: true,
|
|
2211
|
+
atomicPersistence: true,
|
|
2212
|
+
workspaceLocks: true,
|
|
2213
|
+
corruptionDetection: true,
|
|
2214
|
+
secretRedaction: true,
|
|
2215
|
+
mainnetGuards: true,
|
|
2216
|
+
localnetSimulation: true,
|
|
2217
|
+
ghostdagSimulation: true,
|
|
2218
|
+
dagConflictResolution: true,
|
|
2219
|
+
massProfiler: true,
|
|
2220
|
+
simulationScenarios: true,
|
|
2221
|
+
queryStore: true,
|
|
2222
|
+
replayVerification: true,
|
|
2223
|
+
schemaMigrations: true,
|
|
2224
|
+
dockerNode: true,
|
|
2225
|
+
scriptRunner: true,
|
|
2226
|
+
testingFramework: true,
|
|
2227
|
+
l2Profiles: true,
|
|
2228
|
+
l2BridgeAssumptions: true,
|
|
2229
|
+
consensusValidation: false,
|
|
2230
|
+
productionWallet: false,
|
|
2231
|
+
silverScript: false,
|
|
2232
|
+
covenants: false,
|
|
2233
|
+
trustlessExit: false,
|
|
2234
|
+
differentialDagValidation: false
|
|
2235
|
+
},
|
|
2236
|
+
trustBoundaries: {
|
|
2237
|
+
replay: "local-workflow-only",
|
|
2238
|
+
artifacts: "internal-integrity-only",
|
|
2239
|
+
simulator: "research-experimental",
|
|
2240
|
+
queryStore: "rebuildable-read-model",
|
|
2241
|
+
l2Bridge: "pre-zk-assumptions"
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
// src/corpus.ts
|
|
2247
|
+
import fs4 from "fs";
|
|
2248
|
+
import path4 from "path";
|
|
2249
|
+
import { calculateContentHash as calculateContentHash2 } from "@hardkas/artifacts";
|
|
2250
|
+
import { HardkasSchemas as HardkasSchemas5 } from "@hardkas/artifacts";
|
|
2251
|
+
var EXPECTED_LIMITATION = "PARTIAL_VM_SIMULATION";
|
|
2252
|
+
var HardkasCorpus = class {
|
|
2253
|
+
constructor(sdk) {
|
|
2254
|
+
this.sdk = sdk;
|
|
2255
|
+
}
|
|
2256
|
+
sdk;
|
|
2257
|
+
async verify(targetPath) {
|
|
2258
|
+
return verifyToccataCorpus(targetPath, this.sdk.cwd);
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
function verifyToccataCorpus(targetPath, workspaceRoot = process.cwd()) {
|
|
2262
|
+
const corpusPath = path4.resolve(workspaceRoot, targetPath);
|
|
2263
|
+
const issues = [];
|
|
2264
|
+
const opTrueDir = path4.join(corpusPath, "op-true");
|
|
2265
|
+
const failuresDir = path4.join(corpusPath, "failures");
|
|
2266
|
+
const opManifestPath = path4.join(opTrueDir, "manifest.json");
|
|
2267
|
+
const failureManifestPath = path4.join(failuresDir, "manifest.json");
|
|
2268
|
+
const opManifest = readRequiredJson(opManifestPath, issues);
|
|
2269
|
+
const failureManifest = readRequiredJson(failureManifestPath, issues);
|
|
2270
|
+
if (opManifest) {
|
|
2271
|
+
expectEqual(
|
|
2272
|
+
opManifest.schema,
|
|
2273
|
+
HardkasSchemas5.ToccataGoldenManifestV1,
|
|
2274
|
+
issues,
|
|
2275
|
+
"OP_TRUE_SCHEMA_INVALID",
|
|
2276
|
+
opManifestPath
|
|
2277
|
+
);
|
|
2278
|
+
validateCommonClaims(opManifest, issues, opManifestPath);
|
|
2279
|
+
}
|
|
2280
|
+
if (failureManifest) {
|
|
2281
|
+
expectEqual(
|
|
2282
|
+
failureManifest.schema,
|
|
2283
|
+
HardkasSchemas5.ToccataGoldenFailureManifestV1,
|
|
2284
|
+
issues,
|
|
2285
|
+
"FAILURE_SCHEMA_INVALID",
|
|
2286
|
+
failureManifestPath
|
|
2287
|
+
);
|
|
2288
|
+
validateCommonClaims(failureManifest, issues, failureManifestPath);
|
|
2289
|
+
}
|
|
2290
|
+
let artifactsChecked = 0;
|
|
2291
|
+
if (Array.isArray(opManifest?.files)) {
|
|
2292
|
+
for (const file of opManifest.files) {
|
|
2293
|
+
const filePath = path4.join(opTrueDir, file);
|
|
2294
|
+
if (!fs4.existsSync(filePath)) {
|
|
2295
|
+
issues.push({
|
|
2296
|
+
code: "CORPUS_FILE_MISSING",
|
|
2297
|
+
message: `Missing referenced OP_TRUE file ${file}.`,
|
|
2298
|
+
file: filePath
|
|
2299
|
+
});
|
|
2300
|
+
continue;
|
|
2301
|
+
}
|
|
2302
|
+
if (file === "manifest.json" || file === "compare-report.json") continue;
|
|
2303
|
+
const artifact = readRequiredJson(filePath, issues);
|
|
2304
|
+
if (!artifact) continue;
|
|
2305
|
+
artifactsChecked += 1;
|
|
2306
|
+
verifyContentHash(artifact, issues, filePath);
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
const comparePath = path4.join(opTrueDir, "compare-report.json");
|
|
2310
|
+
const compareReport = readRequiredJson(comparePath, issues);
|
|
2311
|
+
if (compareReport) {
|
|
2312
|
+
expectEqual(
|
|
2313
|
+
compareReport.schema,
|
|
2314
|
+
HardkasSchemas5.ToccataGoldenCompareV1,
|
|
2315
|
+
issues,
|
|
2316
|
+
"COMPARE_SCHEMA_INVALID",
|
|
2317
|
+
comparePath
|
|
2318
|
+
);
|
|
2319
|
+
expectEqual(
|
|
2320
|
+
compareReport.compareMode,
|
|
2321
|
+
"artifact-coherence",
|
|
2322
|
+
issues,
|
|
2323
|
+
"COMPARE_MODE_INVALID",
|
|
2324
|
+
comparePath
|
|
2325
|
+
);
|
|
2326
|
+
expectEqual(
|
|
2327
|
+
compareReport.status,
|
|
2328
|
+
"SILVERSCRIPT_SIMULATION_MATCH",
|
|
2329
|
+
issues,
|
|
2330
|
+
"COMPARE_STATUS_INVALID",
|
|
2331
|
+
comparePath
|
|
2332
|
+
);
|
|
2333
|
+
if (!Array.isArray(compareReport.drift) || compareReport.drift.length !== 0) {
|
|
2334
|
+
issues.push({
|
|
2335
|
+
code: "COMPARE_DRIFT_NOT_EMPTY",
|
|
2336
|
+
message: "artifact-coherence compare report must not contain drift.",
|
|
2337
|
+
file: comparePath
|
|
2338
|
+
});
|
|
2339
|
+
}
|
|
2340
|
+
expectKnownLimitation(compareReport, issues, comparePath);
|
|
2341
|
+
const strictNotes = compareReport.semanticNotes || [];
|
|
2342
|
+
if (!Array.isArray(strictNotes) || strictNotes.length === 0) {
|
|
2343
|
+
issues.push({
|
|
2344
|
+
code: "STRICT_DRIFT_NOT_DECLARED",
|
|
2345
|
+
message: "Strict/runtime lineage differences must be declared as semantic notes.",
|
|
2346
|
+
file: comparePath
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
let failureFixtures = 0;
|
|
2351
|
+
if (Array.isArray(failureManifest?.cases)) {
|
|
2352
|
+
for (const entry of failureManifest.cases) {
|
|
2353
|
+
failureFixtures += 1;
|
|
2354
|
+
const filePath = path4.join(failuresDir, entry.file);
|
|
2355
|
+
const fixture = readRequiredJson(filePath, issues);
|
|
2356
|
+
if (!fixture) continue;
|
|
2357
|
+
expectEqual(
|
|
2358
|
+
fixture.schema,
|
|
2359
|
+
HardkasSchemas5.ToccataGoldenFailureCaseV1,
|
|
2360
|
+
issues,
|
|
2361
|
+
"FAILURE_CASE_SCHEMA_INVALID",
|
|
2362
|
+
filePath
|
|
2363
|
+
);
|
|
2364
|
+
if (!entry.expectedSimulatorError) {
|
|
2365
|
+
issues.push({
|
|
2366
|
+
code: "EXPECTED_SIMULATOR_ERROR_MISSING",
|
|
2367
|
+
message: `Failure case ${entry.caseId} must declare expectedSimulatorError.`,
|
|
2368
|
+
file: failureManifestPath
|
|
2369
|
+
});
|
|
2370
|
+
}
|
|
2371
|
+
const expectedError = fixture.expectedSimulator?.error || fixture.expectedSimulator?.secondAttempt?.error;
|
|
2372
|
+
expectEqual(
|
|
2373
|
+
expectedError,
|
|
2374
|
+
entry.expectedSimulatorError,
|
|
2375
|
+
issues,
|
|
2376
|
+
"EXPECTED_SIMULATOR_ERROR_MISMATCH",
|
|
2377
|
+
filePath
|
|
2378
|
+
);
|
|
2379
|
+
validateFailureReferences(fixture, issues, filePath, corpusPath);
|
|
2380
|
+
if (entry.caseId === "mainnet-guard") {
|
|
2381
|
+
validateMainnetGuard(entry, fixture, issues, filePath);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
const ok = issues.length === 0;
|
|
2386
|
+
return {
|
|
2387
|
+
ok,
|
|
2388
|
+
schema: HardkasSchemas5.ToccataCorpusV1,
|
|
2389
|
+
path: path4.relative(workspaceRoot, corpusPath).replace(/\\/g, "/"),
|
|
2390
|
+
summary: {
|
|
2391
|
+
happyPathFixtures: opManifest ? 1 : 0,
|
|
2392
|
+
failureFixtures,
|
|
2393
|
+
artifactsChecked,
|
|
2394
|
+
contentHashes: issues.some((issue) => issue.code.includes("HASH")) ? "FAIL" : "PASS",
|
|
2395
|
+
compareMode: compareReport?.compareMode ?? "unknown",
|
|
2396
|
+
simulationStatus: compareReport?.status ?? "unknown",
|
|
2397
|
+
knownLimitations: collectKnownLimitations(
|
|
2398
|
+
opManifest,
|
|
2399
|
+
failureManifest,
|
|
2400
|
+
compareReport
|
|
2401
|
+
)
|
|
2402
|
+
},
|
|
2403
|
+
claims: {
|
|
2404
|
+
artifactCoherence: ok ? "READY_MATCH" : "INVALID",
|
|
2405
|
+
runtimeOutcome: ok ? "PARTIAL" : "INVALID",
|
|
2406
|
+
vmConsensusEquivalence: ok ? "NOT_CLAIMED" : "INVALID",
|
|
2407
|
+
mainnet: ok ? "BLOCKED_BY_POLICY" : "INVALID"
|
|
2408
|
+
},
|
|
2409
|
+
issues
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
function readRequiredJson(filePath, issues) {
|
|
2413
|
+
if (!fs4.existsSync(filePath)) {
|
|
2414
|
+
issues.push({
|
|
2415
|
+
code: "FILE_MISSING",
|
|
2416
|
+
message: `Missing required file ${filePath}.`,
|
|
2417
|
+
file: filePath
|
|
2418
|
+
});
|
|
2419
|
+
return void 0;
|
|
2420
|
+
}
|
|
2421
|
+
try {
|
|
2422
|
+
return JSON.parse(fs4.readFileSync(filePath, "utf8"));
|
|
2423
|
+
} catch (error) {
|
|
2424
|
+
issues.push({
|
|
2425
|
+
code: "JSON_INVALID",
|
|
2426
|
+
message: error?.message || `Invalid JSON in ${filePath}.`,
|
|
2427
|
+
file: filePath
|
|
2428
|
+
});
|
|
2429
|
+
return void 0;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
function validateCommonClaims(manifest, issues, filePath) {
|
|
2433
|
+
expectEqual(manifest.network, "simnet", issues, "NETWORK_INVALID", filePath);
|
|
2434
|
+
expectEqual(manifest.profile, "toccata-v2", issues, "PROFILE_INVALID", filePath);
|
|
2435
|
+
const claim = manifest.simulationClaim || manifest.simulationLevel;
|
|
2436
|
+
expectEqual(
|
|
2437
|
+
claim?.artifactCoherence,
|
|
2438
|
+
"READY",
|
|
2439
|
+
issues,
|
|
2440
|
+
"ARTIFACT_COHERENCE_CLAIM_INVALID",
|
|
2441
|
+
filePath
|
|
2442
|
+
);
|
|
2443
|
+
expectEqual(
|
|
2444
|
+
claim?.runtimeOutcome,
|
|
2445
|
+
"PARTIAL",
|
|
2446
|
+
issues,
|
|
2447
|
+
"RUNTIME_OUTCOME_CLAIM_INVALID",
|
|
2448
|
+
filePath
|
|
2449
|
+
);
|
|
2450
|
+
expectEqual(
|
|
2451
|
+
claim?.vmConsensusEquivalence,
|
|
2452
|
+
"NOT_CLAIMED",
|
|
2453
|
+
issues,
|
|
2454
|
+
"VM_CONSENSUS_CLAIM_INVALID",
|
|
2455
|
+
filePath
|
|
2456
|
+
);
|
|
2457
|
+
expectKnownLimitation(manifest, issues, filePath);
|
|
2458
|
+
}
|
|
2459
|
+
function expectKnownLimitation(value, issues, filePath) {
|
|
2460
|
+
const limitations = value.expectedKnownLimitations || [value.expectedCompareStatus].filter(Boolean);
|
|
2461
|
+
if (!Array.isArray(limitations) || !limitations.includes(EXPECTED_LIMITATION)) {
|
|
2462
|
+
issues.push({
|
|
2463
|
+
code: "PARTIAL_VM_SIMULATION_NOT_DECLARED",
|
|
2464
|
+
message: "Expected known limitations must include PARTIAL_VM_SIMULATION.",
|
|
2465
|
+
file: filePath
|
|
2466
|
+
});
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
function verifyContentHash(artifact, issues, filePath) {
|
|
2470
|
+
if (typeof artifact.contentHash !== "string") {
|
|
2471
|
+
issues.push({
|
|
2472
|
+
code: "CONTENT_HASH_MISSING",
|
|
2473
|
+
message: "Artifact is missing contentHash.",
|
|
2474
|
+
file: filePath
|
|
2475
|
+
});
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
const actual = calculateContentHash2(artifact, artifact.hashVersion ?? 4);
|
|
2479
|
+
if (actual !== artifact.contentHash) {
|
|
2480
|
+
issues.push({
|
|
2481
|
+
code: "CONTENT_HASH_MISMATCH",
|
|
2482
|
+
message: `Expected ${artifact.contentHash}, got ${actual}.`,
|
|
2483
|
+
file: filePath
|
|
2484
|
+
});
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
function validateFailureReferences(fixture, issues, filePath, corpusPath) {
|
|
2488
|
+
for (const ref of collectFixtureRefs(fixture)) {
|
|
2489
|
+
const refPath = ref.split("#")[0];
|
|
2490
|
+
if (!refPath) {
|
|
2491
|
+
issues.push({
|
|
2492
|
+
code: "FAILURE_REFERENCE_INVALID",
|
|
2493
|
+
message: `Referenced fixture path is empty: ${ref}.`,
|
|
2494
|
+
file: filePath
|
|
2495
|
+
});
|
|
2496
|
+
continue;
|
|
2497
|
+
}
|
|
2498
|
+
const resolved = path4.resolve(path4.dirname(filePath), refPath);
|
|
2499
|
+
if (!resolved.startsWith(corpusPath) || !fs4.existsSync(resolved)) {
|
|
2500
|
+
issues.push({
|
|
2501
|
+
code: "FAILURE_REFERENCE_INVALID",
|
|
2502
|
+
message: `Referenced fixture file does not exist or escapes corpus: ${ref}.`,
|
|
2503
|
+
file: filePath
|
|
2504
|
+
});
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
function collectFixtureRefs(fixture) {
|
|
2509
|
+
const refs = [fixture.baseArtifact, fixture.requiredState].filter(Boolean);
|
|
2510
|
+
const setupRefs = fixture.stateSetup ? [fixture.stateSetup.deployPlan, fixture.stateSetup.deploySimulationReceipt] : [];
|
|
2511
|
+
const normalizationRefs = fixture.stateSetup?.simulatorSpendInputNormalization ?? [];
|
|
2512
|
+
for (const entry of normalizationRefs) {
|
|
2513
|
+
if (entry.valueFrom) refs.push(entry.valueFrom);
|
|
2514
|
+
}
|
|
2515
|
+
return [...refs, ...setupRefs].filter(Boolean);
|
|
2516
|
+
}
|
|
2517
|
+
function validateMainnetGuard(entry, fixture, issues, filePath) {
|
|
2518
|
+
const status = fixture.expectedReal?.status;
|
|
2519
|
+
const error = fixture.expectedReal?.error || entry.expectedRealError;
|
|
2520
|
+
if (status !== "BLOCKED_BY_POLICY" || error !== "SILVERSCRIPT_MAINNET_NOT_ENABLED") {
|
|
2521
|
+
issues.push({
|
|
2522
|
+
code: "MAINNET_GUARD_CLAIM_INVALID",
|
|
2523
|
+
message: "mainnet-guard must declare BLOCKED_BY_POLICY / SILVERSCRIPT_MAINNET_NOT_ENABLED.",
|
|
2524
|
+
file: filePath
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
function collectKnownLimitations(...values) {
|
|
2529
|
+
return Array.from(
|
|
2530
|
+
new Set(
|
|
2531
|
+
values.flatMap((value) => {
|
|
2532
|
+
if (!value) return [];
|
|
2533
|
+
if (Array.isArray(value.expectedKnownLimitations))
|
|
2534
|
+
return value.expectedKnownLimitations;
|
|
2535
|
+
return [value.expectedCompareStatus].filter(Boolean);
|
|
2536
|
+
})
|
|
2537
|
+
)
|
|
2538
|
+
).sort();
|
|
2539
|
+
}
|
|
2540
|
+
function expectEqual(actual, expected, issues, code, file) {
|
|
2541
|
+
if (actual !== expected) {
|
|
2542
|
+
issues.push({
|
|
2543
|
+
code,
|
|
2544
|
+
message: `Expected ${String(expected)}, got ${String(actual)}.`,
|
|
2545
|
+
file
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
// src/silver.ts
|
|
2551
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
2552
|
+
import { createHash } from "crypto";
|
|
2553
|
+
import fs5 from "fs";
|
|
2554
|
+
import path5 from "path";
|
|
2555
|
+
import { calculateContentHash as calculateContentHash3, HARDKAS_VERSION as HARDKAS_VERSION4, writeArtifact as writeArtifact3 } from "@hardkas/artifacts";
|
|
2556
|
+
import {
|
|
2557
|
+
createKaspaP2shBlake2bLock,
|
|
2558
|
+
createPushOnlySignatureScript,
|
|
2559
|
+
parseKasToSompi as parseKasToSompi2
|
|
2560
|
+
} from "@hardkas/core";
|
|
2561
|
+
import {
|
|
2562
|
+
createSilverSimulationState,
|
|
2563
|
+
simulateSilverDeploy,
|
|
2564
|
+
simulateSilverSpend
|
|
2565
|
+
} from "@hardkas/simulator";
|
|
2566
|
+
import { HardkasSchemas as HardkasSchemas6 } from "@hardkas/artifacts";
|
|
2567
|
+
var HardkasSilver = class {
|
|
2568
|
+
constructor(sdk) {
|
|
2569
|
+
this.sdk = sdk;
|
|
2570
|
+
}
|
|
2571
|
+
sdk;
|
|
2572
|
+
simulate = {
|
|
2573
|
+
deploy: (deployPlan, options = {}) => this.simulateDeploy(deployPlan, options),
|
|
2574
|
+
spend: (spendPlan, state = this.loadSimulationState(), options = {}) => this.simulateSpend(spendPlan, state, options),
|
|
2575
|
+
compare: (options) => this.compare(options)
|
|
2576
|
+
};
|
|
2577
|
+
async compile(options) {
|
|
2578
|
+
const network = options.network || "simnet";
|
|
2579
|
+
assertSimnet(network);
|
|
2580
|
+
const filePath = path5.resolve(this.sdk.cwd, options.file);
|
|
2581
|
+
if (!fs5.existsSync(filePath)) {
|
|
2582
|
+
throw new Error(`SILVERSCRIPT_SOURCE_NOT_FOUND: ${filePath}`);
|
|
2583
|
+
}
|
|
2584
|
+
const compilerPath = resolveCompilerPath(this.sdk.cwd, options.compilerPath);
|
|
2585
|
+
if (!isExecutableAvailable(compilerPath)) {
|
|
2586
|
+
throw new Error(
|
|
2587
|
+
"SILVERSCRIPT_COMPILER_UNAVAILABLE: pass compilerPath, set HARDKAS_SILVERC_PATH, or install .hardkas/bin/silverc."
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
const sourceContent = fs5.readFileSync(filePath, "utf8");
|
|
2591
|
+
const compilerOutput = execFileSync2(compilerPath, [filePath, "-c"], {
|
|
2592
|
+
encoding: "utf8",
|
|
2593
|
+
stdio: "pipe"
|
|
2594
|
+
});
|
|
2595
|
+
const normalized = normalizeSilverCompilerOutput(compilerOutput);
|
|
2596
|
+
if (!normalized.scriptHex) {
|
|
2597
|
+
throw new Error(
|
|
2598
|
+
"SILVERSCRIPT_COMPILER_OUTPUT_INVALID: compiled script hex not found."
|
|
2599
|
+
);
|
|
2600
|
+
}
|
|
2601
|
+
const artifact = {
|
|
2602
|
+
schema: HardkasSchemas6.SilverCompile,
|
|
2603
|
+
hardkasVersion: HARDKAS_VERSION4,
|
|
2604
|
+
version: "1.0.0-alpha",
|
|
2605
|
+
hashVersion: 4,
|
|
2606
|
+
networkId: network,
|
|
2607
|
+
mode: "simulated",
|
|
2608
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2609
|
+
sourcePath: filePath,
|
|
2610
|
+
sourceHash: createHash("sha256").update(sourceContent).digest("hex"),
|
|
2611
|
+
compilerName: "silverc",
|
|
2612
|
+
compilerVersion: "unknown",
|
|
2613
|
+
compilerCommand: `${compilerPath} "${filePath}" -c`,
|
|
2614
|
+
compiledScriptHex: normalized.scriptHex,
|
|
2615
|
+
compiledScriptHash: normalized.scriptHash || createHash("sha256").update(Buffer.from(normalized.scriptHex, "hex")).digest("hex"),
|
|
2616
|
+
abi: normalized.abi,
|
|
2617
|
+
network,
|
|
2618
|
+
assumptions: ["toccata-v2", "mainnet-disabled"]
|
|
2619
|
+
};
|
|
2620
|
+
finalizeArtifact(artifact, "silver");
|
|
2621
|
+
return this.writeSdkArtifact(artifact, options);
|
|
2622
|
+
}
|
|
2623
|
+
async deployPlan(options) {
|
|
2624
|
+
const network = options.network || "simnet";
|
|
2625
|
+
assertSimnet(network);
|
|
2626
|
+
const compileArtifact = await this.resolveArtifact(
|
|
2627
|
+
options.artifact,
|
|
2628
|
+
HardkasSchemas6.SilverCompile
|
|
2629
|
+
);
|
|
2630
|
+
const amountSompi = parseKasToSompi2(String(options.amount ?? "1")).toString();
|
|
2631
|
+
const fromAccount = await this.sdk.accounts.resolve(options.from);
|
|
2632
|
+
const lock = createKaspaP2shBlake2bLock(compileArtifact.compiledScriptHex);
|
|
2633
|
+
const artifact = {
|
|
2634
|
+
schema: HardkasSchemas6.SilverDeployPlan,
|
|
2635
|
+
hardkasVersion: HARDKAS_VERSION4,
|
|
2636
|
+
version: "1.0.0-alpha",
|
|
2637
|
+
hashVersion: 4,
|
|
2638
|
+
networkId: network,
|
|
2639
|
+
mode: "simulated",
|
|
2640
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2641
|
+
compileArtifactHash: compileArtifact.contentHash,
|
|
2642
|
+
compiledScriptHash: compileArtifact.compiledScriptHash,
|
|
2643
|
+
redeemScriptHex: lock.redeemScriptHex,
|
|
2644
|
+
redeemScriptHash: lock.redeemScriptHash,
|
|
2645
|
+
lockingScriptHex: lock.lockingScriptHex,
|
|
2646
|
+
scriptPublicKeyVersion: lock.scriptPublicKeyVersion,
|
|
2647
|
+
amountSompi,
|
|
2648
|
+
deployerAddress: fromAccount.address
|
|
2649
|
+
};
|
|
2650
|
+
finalizeArtifact(artifact, "silverdeployplan");
|
|
2651
|
+
return this.writeSdkArtifact(artifact, options);
|
|
2652
|
+
}
|
|
2653
|
+
async deploy(options) {
|
|
2654
|
+
if (options.mode === "real") {
|
|
2655
|
+
throw new Error(
|
|
2656
|
+
"SDK_SILVER_REAL_LIFECYCLE_UNSUPPORTED: use `hardkas silver deploy` for Docker/RPC execution in 0.9.1-alpha."
|
|
2657
|
+
);
|
|
2658
|
+
}
|
|
2659
|
+
return this.simulateDeploy(options.artifact, options);
|
|
2660
|
+
}
|
|
2661
|
+
async spendPlan(options) {
|
|
2662
|
+
const deployArtifact = await this.resolveArtifact(
|
|
2663
|
+
options.receipt,
|
|
2664
|
+
HardkasSchemas6.SilverDeploy
|
|
2665
|
+
);
|
|
2666
|
+
assertSimnet(deployArtifact.networkId);
|
|
2667
|
+
const args = options.args ?? readArgsFile(this.sdk.cwd, options.argsPath);
|
|
2668
|
+
const lock = createKaspaP2shBlake2bLock(deployArtifact.redeemScriptHex);
|
|
2669
|
+
if (lock.lockingScriptHex !== deployArtifact.lockingScriptHex) {
|
|
2670
|
+
throw new Error("SILVERSCRIPT_LOCKING_SCRIPT_MISMATCH");
|
|
2671
|
+
}
|
|
2672
|
+
if (lock.redeemScriptHash !== deployArtifact.redeemScriptHash) {
|
|
2673
|
+
throw new Error("SILVERSCRIPT_REDEEM_HASH_MISMATCH");
|
|
2674
|
+
}
|
|
2675
|
+
const signatureScriptHex = createPushOnlySignatureScript(
|
|
2676
|
+
args.map((arg) => arg.value),
|
|
2677
|
+
lock.redeemScriptHex
|
|
2678
|
+
);
|
|
2679
|
+
const feeSompi = 200000n;
|
|
2680
|
+
const sendAmount = BigInt(deployArtifact.amountSompi) - feeSompi;
|
|
2681
|
+
if (sendAmount <= 0n) {
|
|
2682
|
+
throw new Error("SILVERSCRIPT_AMOUNT_TOO_SMALL");
|
|
2683
|
+
}
|
|
2684
|
+
const artifact = {
|
|
2685
|
+
schema: HardkasSchemas6.SilverSpendPlan,
|
|
2686
|
+
hardkasVersion: HARDKAS_VERSION4,
|
|
2687
|
+
version: "1.0.0-alpha",
|
|
2688
|
+
hashVersion: 4,
|
|
2689
|
+
networkId: deployArtifact.networkId,
|
|
2690
|
+
mode: "simulated",
|
|
2691
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2692
|
+
deployArtifactHash: deployArtifact.contentHash,
|
|
2693
|
+
compileArtifactHash: deployArtifact.compileArtifactHash,
|
|
2694
|
+
redeemScriptHash: lock.redeemScriptHash,
|
|
2695
|
+
lockingScriptHex: lock.lockingScriptHex,
|
|
2696
|
+
contractUtxoRef: {
|
|
2697
|
+
transactionId: deployArtifact.deployTxId,
|
|
2698
|
+
index: deployArtifact.outputIndex
|
|
2699
|
+
},
|
|
2700
|
+
args,
|
|
2701
|
+
argsHash: calculateArgsHash(args),
|
|
2702
|
+
signatureScriptHex,
|
|
2703
|
+
expectedOutputs: [
|
|
2704
|
+
{
|
|
2705
|
+
address: options.to,
|
|
2706
|
+
amountSompi: sendAmount.toString()
|
|
2707
|
+
}
|
|
2708
|
+
]
|
|
2709
|
+
};
|
|
2710
|
+
finalizeArtifact(artifact, "silverspendplan");
|
|
2711
|
+
return this.writeSdkArtifact(artifact, options);
|
|
2712
|
+
}
|
|
2713
|
+
async spend(options) {
|
|
2714
|
+
if (options.mode === "real") {
|
|
2715
|
+
throw new Error(
|
|
2716
|
+
"SDK_SILVER_REAL_LIFECYCLE_UNSUPPORTED: use `hardkas silver spend` for Docker/RPC execution in 0.9.1-alpha."
|
|
2717
|
+
);
|
|
2718
|
+
}
|
|
2719
|
+
return this.simulateSpend(
|
|
2720
|
+
options.artifact,
|
|
2721
|
+
options.state ?? this.loadSimulationState(),
|
|
2722
|
+
options
|
|
2723
|
+
);
|
|
2724
|
+
}
|
|
2725
|
+
async simulateDeploy(deployPlan, options = {}) {
|
|
2726
|
+
const artifact = await this.resolveArtifact(deployPlan, HardkasSchemas6.SilverDeployPlan);
|
|
2727
|
+
const result = simulateSilverDeploy(artifact);
|
|
2728
|
+
this.saveSimulationState(mergeState(this.loadSimulationState(), result.state));
|
|
2729
|
+
return this.writeSdkArtifact(result.receipt, options);
|
|
2730
|
+
}
|
|
2731
|
+
async simulateSpend(spendPlan, state = this.loadSimulationState(), options = {}) {
|
|
2732
|
+
const artifact = await this.resolveArtifact(spendPlan, HardkasSchemas6.SilverSpendPlan);
|
|
2733
|
+
const result = simulateSilverSpend(artifact, state);
|
|
2734
|
+
this.saveSimulationState(result.state);
|
|
2735
|
+
return this.writeSdkArtifact(result.receipt, options);
|
|
2736
|
+
}
|
|
2737
|
+
async compare(options) {
|
|
2738
|
+
const simulated = await this.resolveArtifact(options.simulated);
|
|
2739
|
+
const docker = await this.resolveArtifact(options.docker);
|
|
2740
|
+
const mode = normalizeCompareMode(options.mode || "artifact-coherence");
|
|
2741
|
+
const { drift, notes } = compareSilverReceipts(simulated, docker, mode);
|
|
2742
|
+
return {
|
|
2743
|
+
status: drift.length === 0 ? "SILVERSCRIPT_SIMULATION_MATCH" : "SILVERSCRIPT_SIMULATION_DRIFT",
|
|
2744
|
+
mode,
|
|
2745
|
+
drift,
|
|
2746
|
+
notes,
|
|
2747
|
+
expectedKnownLimitations: ["PARTIAL_VM_SIMULATION"]
|
|
2748
|
+
};
|
|
2749
|
+
}
|
|
2750
|
+
async resolveArtifact(target, expectedSchema) {
|
|
2751
|
+
const artifact = typeof target === "string" ? await this.sdk.artifacts.read(target) : target;
|
|
2752
|
+
if (expectedSchema && artifact.schema !== expectedSchema) {
|
|
2753
|
+
throw new Error(
|
|
2754
|
+
`SILVERSCRIPT_SCHEMA_INVALID: expected ${expectedSchema}, got ${artifact.schema}.`
|
|
2755
|
+
);
|
|
2756
|
+
}
|
|
2757
|
+
return artifact;
|
|
2758
|
+
}
|
|
2759
|
+
async writeSdkArtifact(artifact, options) {
|
|
2760
|
+
if (options.write === false) return { artifact };
|
|
2761
|
+
const artifactPath = options.outputPath ? path5.resolve(this.sdk.cwd, options.outputPath) : path5.join(this.sdk.cwd, `${artifact.artifactId}.json`);
|
|
2762
|
+
await writeArtifact3(artifactPath, artifact);
|
|
2763
|
+
this.sdk.artifacts.cacheArtifact(artifact);
|
|
2764
|
+
return { artifact, artifactPath };
|
|
2765
|
+
}
|
|
2766
|
+
simulationStatePath() {
|
|
2767
|
+
return path5.join(this.sdk.workspace.hardkasDir, "silver-simulator", "state.json");
|
|
2768
|
+
}
|
|
2769
|
+
loadSimulationState() {
|
|
2770
|
+
const statePath = this.simulationStatePath();
|
|
2771
|
+
if (!fs5.existsSync(statePath)) return createSilverSimulationState();
|
|
2772
|
+
return JSON.parse(fs5.readFileSync(statePath, "utf8"));
|
|
2773
|
+
}
|
|
2774
|
+
saveSimulationState(state) {
|
|
2775
|
+
const statePath = this.simulationStatePath();
|
|
2776
|
+
fs5.mkdirSync(path5.dirname(statePath), { recursive: true });
|
|
2777
|
+
fs5.writeFileSync(statePath, `${JSON.stringify(state, null, 2)}
|
|
2778
|
+
`, "utf8");
|
|
2779
|
+
}
|
|
2780
|
+
};
|
|
2781
|
+
function assertSimnet(network) {
|
|
2782
|
+
if (network !== "simnet") {
|
|
2783
|
+
throw new Error(
|
|
2784
|
+
"SILVERSCRIPT_MAINNET_NOT_ENABLED: Only simnet is supported for SilverScript lifecycle."
|
|
2785
|
+
);
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
function resolveCompilerPath(cwd, explicit) {
|
|
2789
|
+
return explicit || process.env.HARDKAS_SILVERC_PATH || path5.join(
|
|
2790
|
+
cwd,
|
|
2791
|
+
".hardkas",
|
|
2792
|
+
"bin",
|
|
2793
|
+
process.platform === "win32" ? "silverc.exe" : "silverc"
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
function isExecutableAvailable(command) {
|
|
2797
|
+
try {
|
|
2798
|
+
execFileSync2(command, ["--help"], { stdio: "ignore" });
|
|
2799
|
+
return true;
|
|
2800
|
+
} catch {
|
|
2801
|
+
return fs5.existsSync(command);
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
function normalizeSilverCompilerOutput(rawOutput) {
|
|
2805
|
+
const normalized = {};
|
|
2806
|
+
const hexMatch = rawOutput.match(/Compiled script:\s*([a-fA-F0-9]+)/i);
|
|
2807
|
+
if (hexMatch?.[1]) normalized.scriptHex = hexMatch[1];
|
|
2808
|
+
const hashMatch = rawOutput.match(/Script Hash:\s*([a-fA-F0-9]+)/i);
|
|
2809
|
+
if (hashMatch?.[1]) normalized.scriptHash = hashMatch[1];
|
|
2810
|
+
try {
|
|
2811
|
+
const parsed = JSON.parse(rawOutput);
|
|
2812
|
+
if (Array.isArray(parsed.script)) {
|
|
2813
|
+
normalized.scriptHex = Buffer.from(parsed.script).toString("hex");
|
|
2814
|
+
} else if (typeof parsed.scriptHex === "string") {
|
|
2815
|
+
normalized.scriptHex = parsed.scriptHex;
|
|
2816
|
+
}
|
|
2817
|
+
if (typeof parsed.scriptHash === "string") normalized.scriptHash = parsed.scriptHash;
|
|
2818
|
+
if (parsed.abi !== void 0) normalized.abi = parsed.abi;
|
|
2819
|
+
} catch {
|
|
2820
|
+
}
|
|
2821
|
+
return normalized;
|
|
2822
|
+
}
|
|
2823
|
+
function readArgsFile(cwd, argsPath) {
|
|
2824
|
+
if (!argsPath) return [];
|
|
2825
|
+
const parsed = JSON.parse(fs5.readFileSync(path5.resolve(cwd, argsPath), "utf8"));
|
|
2826
|
+
const args = parsed.args ?? parsed;
|
|
2827
|
+
if (!Array.isArray(args))
|
|
2828
|
+
throw new Error("SILVERSCRIPT_SPEND_PLAN_INVALID: args must be an array.");
|
|
2829
|
+
return args.map((arg) => {
|
|
2830
|
+
if (arg.type !== "hex" || typeof arg.value !== "string") {
|
|
2831
|
+
throw new Error(
|
|
2832
|
+
"SILVERSCRIPT_SPEND_PLAN_INVALID: args must be { type: 'hex', value }."
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2835
|
+
return { type: "hex", value: arg.value };
|
|
2836
|
+
});
|
|
2837
|
+
}
|
|
2838
|
+
function calculateArgsHash(args) {
|
|
2839
|
+
return createHash("sha256").update(JSON.stringify(args)).digest("hex");
|
|
2840
|
+
}
|
|
2841
|
+
function finalizeArtifact(artifact, prefix) {
|
|
2842
|
+
artifact.contentHash = calculateContentHash3(artifact);
|
|
2843
|
+
artifact.artifactId = `${prefix}-${artifact.contentHash.substring(0, 16)}`;
|
|
2844
|
+
}
|
|
2845
|
+
function mergeState(existing, next) {
|
|
2846
|
+
return {
|
|
2847
|
+
...next,
|
|
2848
|
+
deployReceipts: {
|
|
2849
|
+
...existing.deployReceipts,
|
|
2850
|
+
...next.deployReceipts
|
|
2851
|
+
},
|
|
2852
|
+
utxos: {
|
|
2853
|
+
...existing.utxos,
|
|
2854
|
+
...next.utxos
|
|
2855
|
+
},
|
|
2856
|
+
spentOutpoints: Array.from(
|
|
2857
|
+
/* @__PURE__ */ new Set([...existing.spentOutpoints, ...next.spentOutpoints])
|
|
2858
|
+
).sort()
|
|
2859
|
+
};
|
|
2860
|
+
}
|
|
2861
|
+
function normalizeCompareMode(mode) {
|
|
2862
|
+
if (mode === "artifact-coherence" || mode === "runtime-outcome" || mode === "strict")
|
|
2863
|
+
return mode;
|
|
2864
|
+
throw new Error(
|
|
2865
|
+
"SILVERSCRIPT_COMPARE_MODE_INVALID: Expected artifact-coherence, runtime-outcome, or strict."
|
|
2866
|
+
);
|
|
2867
|
+
}
|
|
2868
|
+
function stableJson(value) {
|
|
2869
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
2870
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
2871
|
+
const record = value;
|
|
2872
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
|
|
2873
|
+
}
|
|
2874
|
+
function valuesMatch(field, simulated, docker) {
|
|
2875
|
+
if (field === "status") {
|
|
2876
|
+
return simulated === docker || simulated === "SIMULATED_ACCEPTED" && (docker === "accepted" || docker === "submitted");
|
|
2877
|
+
}
|
|
2878
|
+
return stableJson(simulated) === stableJson(docker);
|
|
2879
|
+
}
|
|
2880
|
+
function compareSilverReceipts(simulated, docker, mode) {
|
|
2881
|
+
const drift = [];
|
|
2882
|
+
const notes = [];
|
|
2883
|
+
const fields = [
|
|
2884
|
+
"redeemScriptHash",
|
|
2885
|
+
"lockingScriptHex",
|
|
2886
|
+
"signatureScriptHex",
|
|
2887
|
+
"expectedOutputs",
|
|
2888
|
+
"status"
|
|
2889
|
+
];
|
|
2890
|
+
if (mode === "runtime-outcome" || mode === "strict")
|
|
2891
|
+
fields.push("networkId", "spentOutpoint");
|
|
2892
|
+
if (mode === "strict") fields.push("lineage", "txId", "simulatedSpendTxId");
|
|
2893
|
+
for (const field of fields) {
|
|
2894
|
+
const entry = compareField(field, simulated[field], docker[field]);
|
|
2895
|
+
if (entry.classification === "MATCH") continue;
|
|
2896
|
+
const nonConsensusRuntimeIds = mode === "runtime-outcome" && (field === "spentOutpoint" || field === "txId" || field === "simulatedSpendTxId");
|
|
2897
|
+
if (nonConsensusRuntimeIds) {
|
|
2898
|
+
notes.push({
|
|
2899
|
+
...entry,
|
|
2900
|
+
classification: "SEMANTICALLY_DERIVED",
|
|
2901
|
+
reason: "synthetic simulator runtime identifier differs from Docker-observed runtime identifier"
|
|
2902
|
+
});
|
|
2903
|
+
continue;
|
|
2904
|
+
}
|
|
2905
|
+
drift.push(entry);
|
|
2906
|
+
}
|
|
2907
|
+
if (mode !== "strict") {
|
|
2908
|
+
const lineageReport = compareLineageSemantics(simulated, docker, mode);
|
|
2909
|
+
drift.push(...lineageReport.drift);
|
|
2910
|
+
notes.push(...lineageReport.notes);
|
|
2911
|
+
}
|
|
2912
|
+
return { drift, notes };
|
|
2913
|
+
}
|
|
2914
|
+
function compareField(field, simulatedValue, dockerValue) {
|
|
2915
|
+
if (simulatedValue === void 0) {
|
|
2916
|
+
return {
|
|
2917
|
+
field,
|
|
2918
|
+
reason: "missing in simulated receipt",
|
|
2919
|
+
classification: "MISSING_IN_SIM"
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
if (dockerValue === void 0) {
|
|
2923
|
+
return {
|
|
2924
|
+
field,
|
|
2925
|
+
reason: "missing in docker receipt",
|
|
2926
|
+
classification: "MISSING_IN_REAL"
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
if (valuesMatch(field, simulatedValue, dockerValue)) {
|
|
2930
|
+
return { field, reason: "match", classification: "MATCH" };
|
|
2931
|
+
}
|
|
2932
|
+
return { field, reason: "semantic mismatch", classification: "SEMANTIC_MISMATCH" };
|
|
2933
|
+
}
|
|
2934
|
+
function compareLineageSemantics(simulated, docker, mode) {
|
|
2935
|
+
const drift = [];
|
|
2936
|
+
const notes = [];
|
|
2937
|
+
if (!simulated.lineage) {
|
|
2938
|
+
drift.push({
|
|
2939
|
+
field: "lineage",
|
|
2940
|
+
reason: "missing in simulated receipt",
|
|
2941
|
+
classification: "MISSING_IN_SIM"
|
|
2942
|
+
});
|
|
2943
|
+
return { drift, notes };
|
|
2944
|
+
}
|
|
2945
|
+
if (!docker.lineage) {
|
|
2946
|
+
drift.push({
|
|
2947
|
+
field: "lineage",
|
|
2948
|
+
reason: "missing in docker receipt",
|
|
2949
|
+
classification: "MISSING_IN_REAL"
|
|
2950
|
+
});
|
|
2951
|
+
return { drift, notes };
|
|
2952
|
+
}
|
|
2953
|
+
for (const check of [
|
|
2954
|
+
[
|
|
2955
|
+
"lineage.redeemScriptHash",
|
|
2956
|
+
simulated.redeemScriptHash,
|
|
2957
|
+
docker.redeemScriptHash,
|
|
2958
|
+
"redeem script hash anchors artifact coherence"
|
|
2959
|
+
],
|
|
2960
|
+
[
|
|
2961
|
+
"lineage.lockingScriptHex",
|
|
2962
|
+
simulated.lockingScriptHex,
|
|
2963
|
+
docker.lockingScriptHex,
|
|
2964
|
+
"locking script anchors artifact coherence"
|
|
2965
|
+
],
|
|
2966
|
+
[
|
|
2967
|
+
"lineage.signatureScriptHex",
|
|
2968
|
+
simulated.signatureScriptHex,
|
|
2969
|
+
docker.signatureScriptHex,
|
|
2970
|
+
"unlock script anchors artifact coherence"
|
|
2971
|
+
],
|
|
2972
|
+
[
|
|
2973
|
+
"lineage.expectedOutputs",
|
|
2974
|
+
simulated.expectedOutputs,
|
|
2975
|
+
docker.expectedOutputs,
|
|
2976
|
+
"expected outputs anchor artifact coherence"
|
|
2977
|
+
],
|
|
2978
|
+
["lineage.network", simulated.networkId, docker.networkId, "network must match"]
|
|
2979
|
+
]) {
|
|
2980
|
+
const entry = compareField(check[0], check[1], check[2]);
|
|
2981
|
+
if (entry.classification !== "MATCH") drift.push({ ...entry, reason: check[3] });
|
|
2982
|
+
}
|
|
2983
|
+
notes.push({
|
|
2984
|
+
field: "lineage.blob",
|
|
2985
|
+
reason: mode === "artifact-coherence" ? "raw lineage IDs are domain-specific: simulator lineage is synthetic, Docker lineage is receipt artifact lineage" : "raw lineage IDs are compared by semantic anchors; VM/consensus lineage equivalence is not claimed",
|
|
2986
|
+
classification: "SEMANTICALLY_DERIVED"
|
|
2987
|
+
});
|
|
2988
|
+
if (simulated.simulatedSpendTxId || docker.txId) {
|
|
2989
|
+
notes.push({
|
|
2990
|
+
field: "lineage.runtime.txid",
|
|
2991
|
+
reason: "simulatedSpendTxId and Docker txId are intentionally different runtime identifiers",
|
|
2992
|
+
classification: "IGNORED_NON_CONSENSUS"
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2995
|
+
return { drift, notes };
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
// src/zk.ts
|
|
2999
|
+
import fs6 from "fs";
|
|
3000
|
+
import path6 from "path";
|
|
3001
|
+
import { calculateContentHash as calculateContentHash4 } from "@hardkas/artifacts";
|
|
3002
|
+
import { HardkasSchemas as HardkasSchemas7 } from "@hardkas/artifacts";
|
|
3003
|
+
var ZK_KNOWN_LIMITATIONS = [
|
|
3004
|
+
"ZK_ONCHAIN_VERIFICATION_NOT_CLAIMED",
|
|
3005
|
+
"PARTIAL_VM_SIMULATION"
|
|
3006
|
+
];
|
|
3007
|
+
var HardkasZk = class {
|
|
3008
|
+
constructor(sdk) {
|
|
3009
|
+
this.sdk = sdk;
|
|
3010
|
+
this.proof = {
|
|
3011
|
+
inspect: (targetPath) => inspectZkProof(targetPath, this.sdk.cwd),
|
|
3012
|
+
verifyLocal: (targetPath) => verifyZkProofLocal(targetPath, this.sdk.cwd)
|
|
3013
|
+
};
|
|
3014
|
+
this.corpus = {
|
|
3015
|
+
verify: (targetPath) => verifyZkCorpus(targetPath, this.sdk.cwd)
|
|
3016
|
+
};
|
|
3017
|
+
}
|
|
3018
|
+
sdk;
|
|
3019
|
+
proof;
|
|
3020
|
+
corpus;
|
|
3021
|
+
async capabilities() {
|
|
3022
|
+
return createZkCapabilities();
|
|
3023
|
+
}
|
|
3024
|
+
};
|
|
3025
|
+
function createZkCapabilities() {
|
|
3026
|
+
return {
|
|
3027
|
+
schema: HardkasSchemas7.ZkCapabilitiesV1,
|
|
3028
|
+
experimental: true,
|
|
3029
|
+
proofSystems: {
|
|
3030
|
+
groth16: {
|
|
3031
|
+
inspect: true,
|
|
3032
|
+
verifyLocal: "FIXTURE_COHERENCE_ONLY",
|
|
3033
|
+
proofGeneration: "NOT_CLAIMED"
|
|
3034
|
+
},
|
|
3035
|
+
risc0: {
|
|
3036
|
+
inspect: true,
|
|
3037
|
+
verifyLocal: "RISC0_LOCAL_VERIFICATION_NOT_IMPLEMENTED",
|
|
3038
|
+
proofGeneration: "NOT_CLAIMED"
|
|
3039
|
+
}
|
|
3040
|
+
},
|
|
3041
|
+
claims: zkClaims(),
|
|
3042
|
+
errors: [
|
|
3043
|
+
"SDK_ZK_ONCHAIN_VERIFICATION_UNSUPPORTED",
|
|
3044
|
+
"ZK_ONCHAIN_VERIFICATION_NOT_CLAIMED",
|
|
3045
|
+
"ZK_VERIFIER_UNSUPPORTED",
|
|
3046
|
+
"ZK_VERIFIER_UNAVAILABLE",
|
|
3047
|
+
"ZK_CORPUS_MANIFEST_INVALID",
|
|
3048
|
+
"ZK_CORPUS_HASH_MISMATCH",
|
|
3049
|
+
"RISC0_VERIFIER_UNAVAILABLE",
|
|
3050
|
+
"RISC0_LOCAL_VERIFICATION_NOT_IMPLEMENTED"
|
|
3051
|
+
]
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
async function inspectZkProof(targetPath, workspaceRoot = process.cwd()) {
|
|
3055
|
+
const resolved = path6.resolve(workspaceRoot, targetPath);
|
|
3056
|
+
const issues = [];
|
|
3057
|
+
const manifestPath = resolveManifestPath(resolved, issues);
|
|
3058
|
+
const manifest = manifestPath ? readJson(manifestPath, issues) : void 0;
|
|
3059
|
+
const dir = manifestPath ? path6.dirname(manifestPath) : path6.dirname(resolved);
|
|
3060
|
+
const proofSystem = detectProofSystem(manifest, resolved);
|
|
3061
|
+
const fixtureFiles = collectFixtureFiles(manifest);
|
|
3062
|
+
const files = fixtureFiles.map((entry) => entry.file);
|
|
3063
|
+
const contentHashes = {};
|
|
3064
|
+
for (const { key, file } of fixtureFiles) {
|
|
3065
|
+
const filePath = path6.join(dir, file);
|
|
3066
|
+
const value = readJson(filePath, issues);
|
|
3067
|
+
if (!value) continue;
|
|
3068
|
+
const actual = calculateContentHash4(value);
|
|
3069
|
+
contentHashes[file] = actual;
|
|
3070
|
+
const expected = manifest?.contentHashes?.[key];
|
|
3071
|
+
if (typeof expected === "string" && expected !== actual) {
|
|
3072
|
+
issues.push({
|
|
3073
|
+
code: "ZK_CORPUS_HASH_MISMATCH",
|
|
3074
|
+
message: `Expected ${expected}, got ${actual}.`,
|
|
3075
|
+
file: filePath
|
|
3076
|
+
});
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
const ok = issues.length === 0 && proofSystem !== "unknown";
|
|
3080
|
+
if (proofSystem === "unknown") {
|
|
3081
|
+
issues.push({
|
|
3082
|
+
code: "ZK_VERIFIER_UNSUPPORTED",
|
|
3083
|
+
message: "Could not determine proof system from artifact or manifest.",
|
|
3084
|
+
file: resolved
|
|
3085
|
+
});
|
|
3086
|
+
}
|
|
3087
|
+
return {
|
|
3088
|
+
ok,
|
|
3089
|
+
schema: HardkasSchemas7.ZkProofInspectV1,
|
|
3090
|
+
path: path6.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3091
|
+
proofSystem,
|
|
3092
|
+
status: ok ? "ZK_PROOF_INSPECTED" : "ZK_PROOF_INSPECT_FAILED",
|
|
3093
|
+
experimental: true,
|
|
3094
|
+
summary: {
|
|
3095
|
+
files,
|
|
3096
|
+
contentHashes,
|
|
3097
|
+
verifierAdapter: manifest?.verifierAdapter,
|
|
3098
|
+
expectedStatus: manifest?.expectedStatus
|
|
3099
|
+
},
|
|
3100
|
+
claims: zkClaims(),
|
|
3101
|
+
issues
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
async function verifyZkProofLocal(targetPath, workspaceRoot = process.cwd()) {
|
|
3105
|
+
const resolved = path6.resolve(workspaceRoot, targetPath);
|
|
3106
|
+
const issues = [];
|
|
3107
|
+
const manifestPath = resolveManifestPath(resolved, issues);
|
|
3108
|
+
const manifest = manifestPath ? readJson(manifestPath, issues) : void 0;
|
|
3109
|
+
const dir = manifestPath ? path6.dirname(manifestPath) : path6.dirname(resolved);
|
|
3110
|
+
const proofSystem = detectProofSystem(manifest, resolved);
|
|
3111
|
+
if (proofSystem === "risc0") {
|
|
3112
|
+
return {
|
|
3113
|
+
ok: false,
|
|
3114
|
+
schema: HardkasSchemas7.ZkProofVerificationV1,
|
|
3115
|
+
path: path6.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3116
|
+
proofSystem,
|
|
3117
|
+
status: "RISC0_LOCAL_VERIFICATION_NOT_IMPLEMENTED",
|
|
3118
|
+
experimental: true,
|
|
3119
|
+
summary: {
|
|
3120
|
+
verifierAdapter: manifest?.verifierAdapter ?? "risc0-helper",
|
|
3121
|
+
contentHashes: "PASS",
|
|
3122
|
+
localVerification: "NOT_IMPLEMENTED"
|
|
3123
|
+
},
|
|
3124
|
+
claims: zkClaims(),
|
|
3125
|
+
issues: [
|
|
3126
|
+
{
|
|
3127
|
+
code: "RISC0_VERIFIER_UNAVAILABLE",
|
|
3128
|
+
message: "RISC0 local receipt verification helper is not bundled in 0.9.1-alpha."
|
|
3129
|
+
},
|
|
3130
|
+
{
|
|
3131
|
+
code: "RISC0_LOCAL_VERIFICATION_NOT_IMPLEMENTED",
|
|
3132
|
+
message: "RISC0 is inspect-only in this experimental lab scaffold."
|
|
3133
|
+
}
|
|
3134
|
+
]
|
|
3135
|
+
};
|
|
3136
|
+
}
|
|
3137
|
+
if (proofSystem !== "groth16") {
|
|
3138
|
+
return unsupportedVerification(
|
|
3139
|
+
resolved,
|
|
3140
|
+
workspaceRoot,
|
|
3141
|
+
proofSystem,
|
|
3142
|
+
issues,
|
|
3143
|
+
manifest?.verifierAdapter
|
|
3144
|
+
);
|
|
3145
|
+
}
|
|
3146
|
+
verifyGroth16Fixture(dir, manifest, issues);
|
|
3147
|
+
const ok = issues.length === 0;
|
|
3148
|
+
return {
|
|
3149
|
+
ok,
|
|
3150
|
+
schema: HardkasSchemas7.ZkProofVerificationV1,
|
|
3151
|
+
path: path6.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3152
|
+
proofSystem,
|
|
3153
|
+
status: ok ? "ZK_FIXTURE_COHERENCE_PASS" : "ZK_FIXTURE_COHERENCE_FAIL",
|
|
3154
|
+
experimental: true,
|
|
3155
|
+
summary: {
|
|
3156
|
+
verifierAdapter: manifest?.verifierAdapter ?? "hardkas-groth16-fixture-coherence-v1",
|
|
3157
|
+
contentHashes: issues.some((issue) => issue.code.includes("HASH")) ? "FAIL" : "PASS",
|
|
3158
|
+
localVerification: ok ? "PASS" : "FAIL"
|
|
3159
|
+
},
|
|
3160
|
+
claims: zkClaims(),
|
|
3161
|
+
issues
|
|
3162
|
+
};
|
|
3163
|
+
}
|
|
3164
|
+
async function verifyZkCorpus(targetPath, workspaceRoot = process.cwd()) {
|
|
3165
|
+
const corpusPath = path6.resolve(workspaceRoot, targetPath);
|
|
3166
|
+
const issues = [];
|
|
3167
|
+
const manifestPath = path6.join(corpusPath, "manifest.json");
|
|
3168
|
+
const manifest = readJson(manifestPath, issues);
|
|
3169
|
+
if (manifest) {
|
|
3170
|
+
expectEqual2(
|
|
3171
|
+
manifest.schema,
|
|
3172
|
+
HardkasSchemas7.ZkCorpusV1,
|
|
3173
|
+
issues,
|
|
3174
|
+
"ZK_CORPUS_MANIFEST_INVALID",
|
|
3175
|
+
manifestPath
|
|
3176
|
+
);
|
|
3177
|
+
expectEqual2(
|
|
3178
|
+
manifest.network,
|
|
3179
|
+
"simnet",
|
|
3180
|
+
issues,
|
|
3181
|
+
"ZK_NETWORK_UNSUPPORTED",
|
|
3182
|
+
manifestPath
|
|
3183
|
+
);
|
|
3184
|
+
expectEqual2(
|
|
3185
|
+
manifest.profile,
|
|
3186
|
+
"toccata-v2",
|
|
3187
|
+
issues,
|
|
3188
|
+
"ZK_PROFILE_UNSUPPORTED",
|
|
3189
|
+
manifestPath
|
|
3190
|
+
);
|
|
3191
|
+
expectEqual2(
|
|
3192
|
+
manifest.claims?.zkOnchainVerification,
|
|
3193
|
+
"NOT_CLAIMED",
|
|
3194
|
+
issues,
|
|
3195
|
+
"ZK_ONCHAIN_VERIFICATION_NOT_CLAIMED",
|
|
3196
|
+
manifestPath
|
|
3197
|
+
);
|
|
3198
|
+
expectEqual2(
|
|
3199
|
+
manifest.claims?.vmConsensusEquivalence,
|
|
3200
|
+
"NOT_CLAIMED",
|
|
3201
|
+
issues,
|
|
3202
|
+
"ZK_VM_CONSENSUS_CLAIM_INVALID",
|
|
3203
|
+
manifestPath
|
|
3204
|
+
);
|
|
3205
|
+
expectEqual2(
|
|
3206
|
+
manifest.claims?.mainnet,
|
|
3207
|
+
"BLOCKED_BY_POLICY",
|
|
3208
|
+
issues,
|
|
3209
|
+
"ZK_MAINNET_GUARD_INVALID",
|
|
3210
|
+
manifestPath
|
|
3211
|
+
);
|
|
3212
|
+
for (const limitation of ZK_KNOWN_LIMITATIONS) {
|
|
3213
|
+
if (!Array.isArray(manifest.expectedKnownLimitations) || !manifest.expectedKnownLimitations.includes(limitation)) {
|
|
3214
|
+
issues.push({
|
|
3215
|
+
code: "ZK_LIMITATION_NOT_DECLARED",
|
|
3216
|
+
message: `ZK corpus must declare ${limitation}.`,
|
|
3217
|
+
file: manifestPath
|
|
3218
|
+
});
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
let fixturesChecked = 0;
|
|
3223
|
+
let artifactsChecked = 0;
|
|
3224
|
+
const proofSystems = /* @__PURE__ */ new Set();
|
|
3225
|
+
if (Array.isArray(manifest?.fixtures)) {
|
|
3226
|
+
for (const fixture of manifest.fixtures) {
|
|
3227
|
+
fixturesChecked += 1;
|
|
3228
|
+
const fixturePath = path6.join(corpusPath, fixture.path);
|
|
3229
|
+
const inspect = await inspectZkProof(fixturePath, workspaceRoot);
|
|
3230
|
+
artifactsChecked += inspect.summary.files.length;
|
|
3231
|
+
if (inspect.proofSystem !== "unknown") proofSystems.add(inspect.proofSystem);
|
|
3232
|
+
issues.push(...inspect.issues);
|
|
3233
|
+
if (inspect.proofSystem === "groth16") {
|
|
3234
|
+
const verified = await verifyZkProofLocal(fixturePath, workspaceRoot);
|
|
3235
|
+
issues.push(...verified.issues);
|
|
3236
|
+
expectEqual2(
|
|
3237
|
+
verified.status,
|
|
3238
|
+
fixture.expectedStatus,
|
|
3239
|
+
issues,
|
|
3240
|
+
"ZK_FIXTURE_STATUS_MISMATCH",
|
|
3241
|
+
fixturePath
|
|
3242
|
+
);
|
|
3243
|
+
} else if (inspect.proofSystem === "risc0") {
|
|
3244
|
+
const verified = await verifyZkProofLocal(fixturePath, workspaceRoot);
|
|
3245
|
+
expectEqual2(
|
|
3246
|
+
verified.status,
|
|
3247
|
+
fixture.expectedStatus,
|
|
3248
|
+
issues,
|
|
3249
|
+
"ZK_FIXTURE_STATUS_MISMATCH",
|
|
3250
|
+
fixturePath
|
|
3251
|
+
);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
} else if (manifest) {
|
|
3255
|
+
issues.push({
|
|
3256
|
+
code: "ZK_CORPUS_MANIFEST_INVALID",
|
|
3257
|
+
message: "ZK corpus manifest must include fixtures array.",
|
|
3258
|
+
file: manifestPath
|
|
3259
|
+
});
|
|
3260
|
+
}
|
|
3261
|
+
const ok = issues.length === 0;
|
|
3262
|
+
return {
|
|
3263
|
+
ok,
|
|
3264
|
+
schema: HardkasSchemas7.ZkCorpusVerificationV1,
|
|
3265
|
+
path: path6.relative(workspaceRoot, corpusPath).replace(/\\/g, "/"),
|
|
3266
|
+
experimental: true,
|
|
3267
|
+
status: ok ? "ZK_CORPUS_VERIFICATION_PASS" : "ZK_CORPUS_VERIFICATION_FAIL",
|
|
3268
|
+
summary: {
|
|
3269
|
+
proofSystems: Array.from(proofSystems).sort(),
|
|
3270
|
+
fixturesChecked,
|
|
3271
|
+
artifactsChecked,
|
|
3272
|
+
contentHashes: issues.some((issue) => issue.code.includes("HASH")) ? "FAIL" : "PASS",
|
|
3273
|
+
localVerification: ok ? "PARTIAL" : "FAIL",
|
|
3274
|
+
knownLimitations: Array.isArray(manifest?.expectedKnownLimitations) ? manifest.expectedKnownLimitations : []
|
|
3275
|
+
},
|
|
3276
|
+
claims: {
|
|
3277
|
+
zkArtifactCoherence: ok ? "READY_MATCH" : "INVALID",
|
|
3278
|
+
zkLocalVerification: ok ? "READY_GROTH16_FIXTURE_COHERENCE" : "INVALID",
|
|
3279
|
+
zkOnchainVerification: ok ? "NOT_CLAIMED" : "INVALID",
|
|
3280
|
+
runtimeOutcome: ok ? "PARTIAL" : "INVALID",
|
|
3281
|
+
vmConsensusEquivalence: ok ? "NOT_CLAIMED" : "INVALID",
|
|
3282
|
+
mainnet: ok ? "BLOCKED_BY_POLICY" : "INVALID"
|
|
3283
|
+
},
|
|
3284
|
+
issues
|
|
3285
|
+
};
|
|
3286
|
+
}
|
|
3287
|
+
function verifyGroth16Fixture(dir, manifest, issues) {
|
|
3288
|
+
if (!manifest) return;
|
|
3289
|
+
const proofPath = path6.join(dir, manifest.proof ?? "proof.json");
|
|
3290
|
+
const inputsPath = path6.join(dir, manifest.publicInputs ?? "public-inputs.json");
|
|
3291
|
+
const keyPath = path6.join(dir, manifest.verificationKey ?? "verification-key.json");
|
|
3292
|
+
const metadataPath = path6.join(
|
|
3293
|
+
dir,
|
|
3294
|
+
manifest.verifierMetadata ?? "verifier-metadata.json"
|
|
3295
|
+
);
|
|
3296
|
+
const reportPath = path6.join(dir, manifest.verifyReport ?? "verify-report.json");
|
|
3297
|
+
const proof = readJson(proofPath, issues);
|
|
3298
|
+
const publicInputs = readJson(inputsPath, issues);
|
|
3299
|
+
const verificationKey = readJson(keyPath, issues);
|
|
3300
|
+
const metadata = readJson(metadataPath, issues);
|
|
3301
|
+
const report = readJson(reportPath, issues);
|
|
3302
|
+
if (!proof || !publicInputs || !verificationKey || !metadata || !report) return;
|
|
3303
|
+
verifyManifestHash(manifest, "proof", proof, issues, proofPath);
|
|
3304
|
+
verifyManifestHash(manifest, "publicInputs", publicInputs, issues, inputsPath);
|
|
3305
|
+
verifyManifestHash(manifest, "verificationKey", verificationKey, issues, keyPath);
|
|
3306
|
+
verifyManifestHash(manifest, "verifierMetadata", metadata, issues, metadataPath);
|
|
3307
|
+
verifyManifestHash(manifest, "verifyReport", report, issues, reportPath);
|
|
3308
|
+
const publicInputsHash = calculateContentHash4(publicInputs);
|
|
3309
|
+
const verificationKeyHash = calculateContentHash4(verificationKey);
|
|
3310
|
+
const proofHash = calculateContentHash4(proof);
|
|
3311
|
+
expectEqual2(
|
|
3312
|
+
proof.publicInputsHash,
|
|
3313
|
+
publicInputsHash,
|
|
3314
|
+
issues,
|
|
3315
|
+
"ZK_GROTH16_PUBLIC_INPUTS_HASH_MISMATCH",
|
|
3316
|
+
proofPath
|
|
3317
|
+
);
|
|
3318
|
+
expectEqual2(
|
|
3319
|
+
proof.verificationKeyHash,
|
|
3320
|
+
verificationKeyHash,
|
|
3321
|
+
issues,
|
|
3322
|
+
"ZK_GROTH16_VERIFICATION_KEY_HASH_MISMATCH",
|
|
3323
|
+
proofPath
|
|
3324
|
+
);
|
|
3325
|
+
expectEqual2(
|
|
3326
|
+
metadata.proofHash,
|
|
3327
|
+
proofHash,
|
|
3328
|
+
issues,
|
|
3329
|
+
"ZK_GROTH16_PROOF_HASH_MISMATCH",
|
|
3330
|
+
metadataPath
|
|
3331
|
+
);
|
|
3332
|
+
expectEqual2(
|
|
3333
|
+
metadata.publicInputsHash,
|
|
3334
|
+
publicInputsHash,
|
|
3335
|
+
issues,
|
|
3336
|
+
"ZK_GROTH16_PUBLIC_INPUTS_HASH_MISMATCH",
|
|
3337
|
+
metadataPath
|
|
3338
|
+
);
|
|
3339
|
+
expectEqual2(
|
|
3340
|
+
metadata.verificationKeyHash,
|
|
3341
|
+
verificationKeyHash,
|
|
3342
|
+
issues,
|
|
3343
|
+
"ZK_GROTH16_VERIFICATION_KEY_HASH_MISMATCH",
|
|
3344
|
+
metadataPath
|
|
3345
|
+
);
|
|
3346
|
+
expectEqual2(
|
|
3347
|
+
report.status,
|
|
3348
|
+
"ZK_FIXTURE_COHERENCE_PASS",
|
|
3349
|
+
issues,
|
|
3350
|
+
"ZK_GROTH16_REPORT_STATUS_INVALID",
|
|
3351
|
+
reportPath
|
|
3352
|
+
);
|
|
3353
|
+
expectEqual2(
|
|
3354
|
+
report.claims?.zkOnchainVerification,
|
|
3355
|
+
"NOT_CLAIMED",
|
|
3356
|
+
issues,
|
|
3357
|
+
"ZK_ONCHAIN_VERIFICATION_NOT_CLAIMED",
|
|
3358
|
+
reportPath
|
|
3359
|
+
);
|
|
3360
|
+
const coherenceDigest = calculateContentHash4({
|
|
3361
|
+
proofSystem: "groth16",
|
|
3362
|
+
proofHash,
|
|
3363
|
+
publicInputsHash,
|
|
3364
|
+
verificationKeyHash,
|
|
3365
|
+
statementHash: publicInputs.statementHash,
|
|
3366
|
+
verifierAdapter: manifest.verifierAdapter
|
|
3367
|
+
});
|
|
3368
|
+
expectEqual2(
|
|
3369
|
+
metadata.coherenceDigest,
|
|
3370
|
+
coherenceDigest,
|
|
3371
|
+
issues,
|
|
3372
|
+
"ZK_GROTH16_COHERENCE_MISMATCH",
|
|
3373
|
+
metadataPath
|
|
3374
|
+
);
|
|
3375
|
+
expectEqual2(
|
|
3376
|
+
report.coherenceDigest,
|
|
3377
|
+
coherenceDigest,
|
|
3378
|
+
issues,
|
|
3379
|
+
"ZK_GROTH16_COHERENCE_MISMATCH",
|
|
3380
|
+
reportPath
|
|
3381
|
+
);
|
|
3382
|
+
}
|
|
3383
|
+
function unsupportedVerification(resolved, workspaceRoot, proofSystem, issues, verifierAdapter) {
|
|
3384
|
+
return {
|
|
3385
|
+
ok: false,
|
|
3386
|
+
schema: HardkasSchemas7.ZkProofVerificationV1,
|
|
3387
|
+
path: path6.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3388
|
+
proofSystem,
|
|
3389
|
+
status: "ZK_VERIFIER_UNSUPPORTED",
|
|
3390
|
+
experimental: true,
|
|
3391
|
+
summary: {
|
|
3392
|
+
...verifierAdapter ? { verifierAdapter } : {},
|
|
3393
|
+
contentHashes: issues.some((issue) => issue.code.includes("HASH")) ? "FAIL" : "PASS",
|
|
3394
|
+
localVerification: "FAIL"
|
|
3395
|
+
},
|
|
3396
|
+
claims: zkClaims(),
|
|
3397
|
+
issues: [
|
|
3398
|
+
...issues,
|
|
3399
|
+
{
|
|
3400
|
+
code: "ZK_VERIFIER_UNSUPPORTED",
|
|
3401
|
+
message: `No local verifier is available for proof system ${proofSystem}.`
|
|
3402
|
+
}
|
|
3403
|
+
]
|
|
3404
|
+
};
|
|
3405
|
+
}
|
|
3406
|
+
function resolveManifestPath(resolved, issues) {
|
|
3407
|
+
if (!fs6.existsSync(resolved)) {
|
|
3408
|
+
issues.push({
|
|
3409
|
+
code: "ZK_PROOF_FILE_MISSING",
|
|
3410
|
+
message: `Missing ${resolved}.`,
|
|
3411
|
+
file: resolved
|
|
3412
|
+
});
|
|
3413
|
+
return void 0;
|
|
3414
|
+
}
|
|
3415
|
+
const stat = fs6.statSync(resolved);
|
|
3416
|
+
if (stat.isDirectory()) return path6.join(resolved, "manifest.json");
|
|
3417
|
+
return resolved;
|
|
3418
|
+
}
|
|
3419
|
+
function collectFixtureFiles(manifest) {
|
|
3420
|
+
if (!manifest) return [];
|
|
3421
|
+
return [
|
|
3422
|
+
["proof", manifest.proof],
|
|
3423
|
+
["publicInputs", manifest.publicInputs],
|
|
3424
|
+
["verificationKey", manifest.verificationKey],
|
|
3425
|
+
["verifierMetadata", manifest.verifierMetadata],
|
|
3426
|
+
["verifyReport", manifest.verifyReport],
|
|
3427
|
+
["receipt", manifest.receipt],
|
|
3428
|
+
["journal", manifest.journal],
|
|
3429
|
+
["imageId", manifest.imageId]
|
|
3430
|
+
].filter((entry) => typeof entry[1] === "string").map(([key, file]) => ({ key, file }));
|
|
3431
|
+
}
|
|
3432
|
+
function detectProofSystem(manifest, resolved) {
|
|
3433
|
+
const declared = manifest?.proofSystem;
|
|
3434
|
+
if (declared === "groth16" || declared === "risc0") return declared;
|
|
3435
|
+
const lower = resolved.toLowerCase();
|
|
3436
|
+
if (lower.includes("groth16")) return "groth16";
|
|
3437
|
+
if (lower.includes("risc0")) return "risc0";
|
|
3438
|
+
return "unknown";
|
|
3439
|
+
}
|
|
3440
|
+
function verifyManifestHash(manifest, key, value, issues, filePath) {
|
|
3441
|
+
const expected = manifest.contentHashes?.[key];
|
|
3442
|
+
if (typeof expected !== "string") {
|
|
3443
|
+
issues.push({
|
|
3444
|
+
code: "ZK_CORPUS_HASH_MISSING",
|
|
3445
|
+
message: `Missing content hash for ${key}.`,
|
|
3446
|
+
file: filePath
|
|
3447
|
+
});
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
const actual = calculateContentHash4(value);
|
|
3451
|
+
if (actual !== expected) {
|
|
3452
|
+
issues.push({
|
|
3453
|
+
code: "ZK_CORPUS_HASH_MISMATCH",
|
|
3454
|
+
message: `Expected ${expected}, got ${actual}.`,
|
|
3455
|
+
file: filePath
|
|
3456
|
+
});
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
function readJson(filePath, issues) {
|
|
3460
|
+
if (!fs6.existsSync(filePath)) {
|
|
3461
|
+
issues.push({
|
|
3462
|
+
code: "ZK_FILE_MISSING",
|
|
3463
|
+
message: `Missing ${filePath}.`,
|
|
3464
|
+
file: filePath
|
|
3465
|
+
});
|
|
3466
|
+
return void 0;
|
|
3467
|
+
}
|
|
3468
|
+
try {
|
|
3469
|
+
return JSON.parse(fs6.readFileSync(filePath, "utf8"));
|
|
3470
|
+
} catch (error) {
|
|
3471
|
+
issues.push({
|
|
3472
|
+
code: "ZK_JSON_INVALID",
|
|
3473
|
+
message: error?.message || `Invalid JSON in ${filePath}.`,
|
|
3474
|
+
file: filePath
|
|
3475
|
+
});
|
|
3476
|
+
return void 0;
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
function expectEqual2(actual, expected, issues, code, file) {
|
|
3480
|
+
if (actual !== expected) {
|
|
3481
|
+
issues.push({
|
|
3482
|
+
code,
|
|
3483
|
+
message: `Expected ${String(expected)}, got ${String(actual)}.`,
|
|
3484
|
+
file
|
|
3485
|
+
});
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
function zkClaims() {
|
|
3489
|
+
return {
|
|
3490
|
+
zkArtifactCoherence: "EXPERIMENTAL",
|
|
3491
|
+
zkLocalVerification: "EXPERIMENTAL_FIXTURE_ONLY",
|
|
3492
|
+
zkOnchainVerification: "NOT_CLAIMED",
|
|
3493
|
+
vmConsensusEquivalence: "NOT_CLAIMED",
|
|
3494
|
+
mainnet: "BLOCKED_BY_POLICY"
|
|
3495
|
+
};
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
// src/vprogs.ts
|
|
3499
|
+
import fs7 from "fs";
|
|
3500
|
+
import path7 from "path";
|
|
3501
|
+
import { calculateContentHash as calculateContentHash5 } from "@hardkas/artifacts";
|
|
3502
|
+
import { HardkasSchemas as HardkasSchemas8 } from "@hardkas/artifacts";
|
|
3503
|
+
var HardkasVprogs = class {
|
|
3504
|
+
constructor(sdk) {
|
|
3505
|
+
this.sdk = sdk;
|
|
3506
|
+
}
|
|
3507
|
+
sdk;
|
|
3508
|
+
async capabilities() {
|
|
3509
|
+
return createVprogsCapabilities();
|
|
3510
|
+
}
|
|
3511
|
+
async status() {
|
|
3512
|
+
return createVprogsStatus();
|
|
3513
|
+
}
|
|
3514
|
+
async inspect(targetPath) {
|
|
3515
|
+
return inspectVprogsArtifact(targetPath, this.sdk.cwd);
|
|
3516
|
+
}
|
|
3517
|
+
};
|
|
3518
|
+
function createVprogsCapabilities() {
|
|
3519
|
+
return {
|
|
3520
|
+
ok: true,
|
|
3521
|
+
schema: HardkasSchemas8.VProgsCapabilitiesV1,
|
|
3522
|
+
status: "VPROGS_INSPECT_SURFACE_READY",
|
|
3523
|
+
claims: vprogsClaims(),
|
|
3524
|
+
errors: [
|
|
3525
|
+
"VPROGS_RUNTIME_NOT_CLAIMED",
|
|
3526
|
+
"VPROGS_STABLE_API_NOT_CLAIMED",
|
|
3527
|
+
"ZK_ONCHAIN_VERIFICATION_NOT_CLAIMED"
|
|
3528
|
+
]
|
|
3529
|
+
};
|
|
3530
|
+
}
|
|
3531
|
+
function createVprogsStatus() {
|
|
3532
|
+
return {
|
|
3533
|
+
ok: true,
|
|
3534
|
+
schema: HardkasSchemas8.VProgsStatusV1,
|
|
3535
|
+
status: "VPROGS_INSPECT_SURFACE_READY",
|
|
3536
|
+
claims: vprogsClaims()
|
|
3537
|
+
};
|
|
3538
|
+
}
|
|
3539
|
+
async function inspectVprogsArtifact(targetPath, workspaceRoot = process.cwd()) {
|
|
3540
|
+
const resolved = path7.resolve(workspaceRoot, targetPath);
|
|
3541
|
+
if (!fs7.existsSync(resolved)) {
|
|
3542
|
+
return {
|
|
3543
|
+
ok: false,
|
|
3544
|
+
schema: HardkasSchemas8.VProgsInspectV1,
|
|
3545
|
+
status: "VPROGS_ARTIFACT_INVALID",
|
|
3546
|
+
path: path7.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3547
|
+
claims: vprogsClaims(),
|
|
3548
|
+
issues: [
|
|
3549
|
+
{
|
|
3550
|
+
code: "VPROGS_ARTIFACT_MISSING",
|
|
3551
|
+
message: `Missing ${resolved}.`,
|
|
3552
|
+
file: resolved
|
|
3553
|
+
}
|
|
3554
|
+
]
|
|
3555
|
+
};
|
|
3556
|
+
}
|
|
3557
|
+
try {
|
|
3558
|
+
const artifact = JSON.parse(fs7.readFileSync(resolved, "utf8"));
|
|
3559
|
+
return {
|
|
3560
|
+
ok: true,
|
|
3561
|
+
schema: HardkasSchemas8.VProgsInspectV1,
|
|
3562
|
+
status: "VPROGS_ARTIFACT_INSPECTED",
|
|
3563
|
+
path: path7.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3564
|
+
artifactHash: calculateContentHash5(artifact),
|
|
3565
|
+
artifactSchema: artifact.schema,
|
|
3566
|
+
claims: vprogsClaims(),
|
|
3567
|
+
issues: []
|
|
3568
|
+
};
|
|
3569
|
+
} catch (error) {
|
|
3570
|
+
return {
|
|
3571
|
+
ok: false,
|
|
3572
|
+
schema: HardkasSchemas8.VProgsInspectV1,
|
|
3573
|
+
status: "VPROGS_ARTIFACT_INVALID",
|
|
3574
|
+
path: path7.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3575
|
+
claims: vprogsClaims(),
|
|
3576
|
+
issues: [
|
|
3577
|
+
{
|
|
3578
|
+
code: "VPROGS_ARTIFACT_INVALID",
|
|
3579
|
+
message: error?.message || "Invalid vProgs artifact JSON.",
|
|
3580
|
+
file: resolved
|
|
3581
|
+
}
|
|
3582
|
+
]
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
function vprogsClaims() {
|
|
3587
|
+
return {
|
|
3588
|
+
vProgsArtifactInspection: "READY",
|
|
3589
|
+
vProgsRuntime: "NOT_CLAIMED",
|
|
3590
|
+
vProgsStableApi: "NOT_CLAIMED",
|
|
3591
|
+
zkOnchainVerification: "NOT_CLAIMED",
|
|
3592
|
+
vmConsensusEquivalence: "NOT_CLAIMED",
|
|
3593
|
+
mainnet: "BLOCKED_BY_POLICY"
|
|
3594
|
+
};
|
|
3595
|
+
}
|
|
3596
|
+
|
|
3597
|
+
// src/programmability.ts
|
|
3598
|
+
import fs8 from "fs";
|
|
3599
|
+
import path8 from "path";
|
|
3600
|
+
import { calculateContentHash as calculateContentHash6, verifyArtifactIntegritySync } from "@hardkas/artifacts";
|
|
3601
|
+
import { HardkasSchemas as HardkasSchemas9 } from "@hardkas/artifacts";
|
|
3602
|
+
var HardkasProgrammability = class {
|
|
3603
|
+
constructor(sdk) {
|
|
3604
|
+
this.sdk = sdk;
|
|
3605
|
+
this.corpus = {
|
|
3606
|
+
verify: (options = {}) => this.verifyCorpus(options)
|
|
3607
|
+
};
|
|
3608
|
+
this.app = {
|
|
3609
|
+
plan: (options = {}) => this.planApp(options)
|
|
3610
|
+
};
|
|
3611
|
+
}
|
|
3612
|
+
sdk;
|
|
3613
|
+
corpus;
|
|
3614
|
+
app;
|
|
3615
|
+
async capabilities() {
|
|
3616
|
+
return createProgrammabilityCapabilities();
|
|
3617
|
+
}
|
|
3618
|
+
async inspect(options) {
|
|
3619
|
+
if (options.kind === "zk") {
|
|
3620
|
+
const result = await this.sdk.zk.proof.inspect(options.path);
|
|
3621
|
+
return {
|
|
3622
|
+
ok: result.ok,
|
|
3623
|
+
schema: HardkasSchemas9.ProgrammabilityInspectV1,
|
|
3624
|
+
status: result.ok ? "PROGRAMMABILITY_ARTIFACT_INSPECTED" : "PROGRAMMABILITY_ARTIFACT_INVALID",
|
|
3625
|
+
kind: "zk",
|
|
3626
|
+
path: result.path,
|
|
3627
|
+
sourceStatus: result.status,
|
|
3628
|
+
claims: programmabilityClaims(),
|
|
3629
|
+
issues: result.issues
|
|
3630
|
+
};
|
|
3631
|
+
}
|
|
3632
|
+
if (options.kind === "vprog") {
|
|
3633
|
+
const result = await this.sdk.vprogs.inspect(options.path);
|
|
3634
|
+
return {
|
|
3635
|
+
ok: result.ok,
|
|
3636
|
+
schema: HardkasSchemas9.ProgrammabilityInspectV1,
|
|
3637
|
+
status: result.ok ? "PROGRAMMABILITY_ARTIFACT_INSPECTED" : "PROGRAMMABILITY_ARTIFACT_INVALID",
|
|
3638
|
+
kind: "vprog",
|
|
3639
|
+
path: result.path,
|
|
3640
|
+
...result.artifactSchema ? { artifactSchema: result.artifactSchema } : {},
|
|
3641
|
+
...result.artifactHash ? { contentHash: result.artifactHash } : {},
|
|
3642
|
+
sourceStatus: result.status,
|
|
3643
|
+
claims: programmabilityClaims(),
|
|
3644
|
+
issues: result.issues
|
|
3645
|
+
};
|
|
3646
|
+
}
|
|
3647
|
+
return inspectJsonArtifact(this.sdk.cwd, options.path, "silver");
|
|
3648
|
+
}
|
|
3649
|
+
async verify(options) {
|
|
3650
|
+
if (options.kind === "zk") {
|
|
3651
|
+
const result2 = await this.sdk.zk.proof.verifyLocal(options.path);
|
|
3652
|
+
return {
|
|
3653
|
+
ok: result2.ok,
|
|
3654
|
+
schema: HardkasSchemas9.ProgrammabilityVerifyV1,
|
|
3655
|
+
status: result2.ok ? "PROGRAMMABILITY_VERIFY_PASS" : "PROGRAMMABILITY_VERIFY_PARTIAL",
|
|
3656
|
+
kind: "zk",
|
|
3657
|
+
path: result2.path,
|
|
3658
|
+
sourceStatus: result2.status,
|
|
3659
|
+
claims: programmabilityClaims(),
|
|
3660
|
+
issues: result2.issues
|
|
3661
|
+
};
|
|
3662
|
+
}
|
|
3663
|
+
if (options.kind === "vprog") {
|
|
3664
|
+
const inspected = await this.sdk.vprogs.inspect(options.path);
|
|
3665
|
+
return {
|
|
3666
|
+
ok: inspected.ok,
|
|
3667
|
+
schema: HardkasSchemas9.ProgrammabilityVerifyV1,
|
|
3668
|
+
status: inspected.ok ? "PROGRAMMABILITY_VERIFY_PASS" : "PROGRAMMABILITY_VERIFY_FAIL",
|
|
3669
|
+
kind: "vprog",
|
|
3670
|
+
path: inspected.path,
|
|
3671
|
+
sourceStatus: inspected.status,
|
|
3672
|
+
claims: programmabilityClaims(),
|
|
3673
|
+
issues: inspected.issues
|
|
3674
|
+
};
|
|
3675
|
+
}
|
|
3676
|
+
const resolved = path8.resolve(this.sdk.cwd, options.path);
|
|
3677
|
+
const result = verifyArtifactIntegritySync(resolved, { strict: false });
|
|
3678
|
+
return {
|
|
3679
|
+
ok: result.ok,
|
|
3680
|
+
schema: HardkasSchemas9.ProgrammabilityVerifyV1,
|
|
3681
|
+
status: result.ok ? "PROGRAMMABILITY_VERIFY_PASS" : "PROGRAMMABILITY_VERIFY_FAIL",
|
|
3682
|
+
kind: "silver",
|
|
3683
|
+
path: path8.relative(this.sdk.cwd, resolved).replace(/\\/g, "/"),
|
|
3684
|
+
sourceStatus: result.ok ? "ARTIFACT_INTEGRITY_PASS" : "ARTIFACT_INTEGRITY_FAIL",
|
|
3685
|
+
claims: programmabilityClaims(),
|
|
3686
|
+
issues: result.issues.map((issue) => ({
|
|
3687
|
+
code: String(issue.code),
|
|
3688
|
+
message: issue.message,
|
|
3689
|
+
...issue.path ? { file: issue.path } : {}
|
|
3690
|
+
}))
|
|
3691
|
+
};
|
|
3692
|
+
}
|
|
3693
|
+
async verifyCorpus(options) {
|
|
3694
|
+
const root = path8.resolve(this.sdk.cwd, options.path ?? "fixtures/toccata-v2");
|
|
3695
|
+
const include = new Set(options.include ?? ["silver", "zk", "vprogs"]);
|
|
3696
|
+
const issues = [];
|
|
3697
|
+
const manifestPath = path8.join(root, "manifest.json");
|
|
3698
|
+
const manifest = readJson2(manifestPath, issues);
|
|
3699
|
+
if (manifest) {
|
|
3700
|
+
expectEqual3(
|
|
3701
|
+
manifest.schema,
|
|
3702
|
+
HardkasSchemas9.ToccataProgrammabilityCorpusV1,
|
|
3703
|
+
issues,
|
|
3704
|
+
"PROGRAMMABILITY_CORPUS_SCHEMA_INVALID",
|
|
3705
|
+
manifestPath
|
|
3706
|
+
);
|
|
3707
|
+
expectEqual3(
|
|
3708
|
+
manifest.network,
|
|
3709
|
+
"simnet",
|
|
3710
|
+
issues,
|
|
3711
|
+
"PROGRAMMABILITY_CORPUS_NETWORK_INVALID",
|
|
3712
|
+
manifestPath
|
|
3713
|
+
);
|
|
3714
|
+
expectEqual3(
|
|
3715
|
+
manifest.profile,
|
|
3716
|
+
"toccata-v2",
|
|
3717
|
+
issues,
|
|
3718
|
+
"PROGRAMMABILITY_CORPUS_PROFILE_INVALID",
|
|
3719
|
+
manifestPath
|
|
3720
|
+
);
|
|
3721
|
+
expectEqual3(
|
|
3722
|
+
manifest.claims?.artifactCoherence,
|
|
3723
|
+
"READY_MATCH",
|
|
3724
|
+
issues,
|
|
3725
|
+
"PROGRAMMABILITY_CLAIM_INVALID",
|
|
3726
|
+
manifestPath
|
|
3727
|
+
);
|
|
3728
|
+
expectEqual3(
|
|
3729
|
+
manifest.claims?.runtimeOutcome,
|
|
3730
|
+
"PARTIAL",
|
|
3731
|
+
issues,
|
|
3732
|
+
"PROGRAMMABILITY_CLAIM_INVALID",
|
|
3733
|
+
manifestPath
|
|
3734
|
+
);
|
|
3735
|
+
expectEqual3(
|
|
3736
|
+
manifest.claims?.vmConsensusEquivalence,
|
|
3737
|
+
"NOT_CLAIMED",
|
|
3738
|
+
issues,
|
|
3739
|
+
"PROGRAMMABILITY_CLAIM_INVALID",
|
|
3740
|
+
manifestPath
|
|
3741
|
+
);
|
|
3742
|
+
expectEqual3(
|
|
3743
|
+
manifest.claims?.mainnet,
|
|
3744
|
+
"BLOCKED_BY_POLICY",
|
|
3745
|
+
issues,
|
|
3746
|
+
"PROGRAMMABILITY_CLAIM_INVALID",
|
|
3747
|
+
manifestPath
|
|
3748
|
+
);
|
|
3749
|
+
if (!Array.isArray(manifest.expectedKnownLimitations) || !manifest.expectedKnownLimitations.includes("PARTIAL_VM_SIMULATION")) {
|
|
3750
|
+
issues.push({
|
|
3751
|
+
code: "PROGRAMMABILITY_LIMITATION_NOT_DECLARED",
|
|
3752
|
+
message: "Root corpus must declare PARTIAL_VM_SIMULATION.",
|
|
3753
|
+
file: manifestPath
|
|
3754
|
+
});
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
let silver = "SKIPPED";
|
|
3758
|
+
let zk = "SKIPPED";
|
|
3759
|
+
let vprogs = "SKIPPED";
|
|
3760
|
+
if (include.has("silver")) {
|
|
3761
|
+
const result = await this.sdk.corpus.verify(
|
|
3762
|
+
path8.join(path8.relative(this.sdk.cwd, root), "silver")
|
|
3763
|
+
);
|
|
3764
|
+
silver = result.ok ? "PASS" : "FAIL";
|
|
3765
|
+
issues.push(...result.issues);
|
|
3766
|
+
}
|
|
3767
|
+
if (include.has("zk")) {
|
|
3768
|
+
const result = await this.sdk.zk.corpus.verify(
|
|
3769
|
+
path8.join(path8.relative(this.sdk.cwd, root), "zk")
|
|
3770
|
+
);
|
|
3771
|
+
zk = result.ok ? "PASS" : "FAIL";
|
|
3772
|
+
issues.push(...result.issues);
|
|
3773
|
+
}
|
|
3774
|
+
if (include.has("vprogs")) {
|
|
3775
|
+
const artifact = manifest?.components?.vprogs?.artifact ?? "vprogs/inspect-only-artifact.json";
|
|
3776
|
+
const result = await this.sdk.vprogs.inspect(
|
|
3777
|
+
path8.join(path8.relative(this.sdk.cwd, root), artifact)
|
|
3778
|
+
);
|
|
3779
|
+
vprogs = result.ok ? "PASS" : "FAIL";
|
|
3780
|
+
issues.push(...result.issues);
|
|
3781
|
+
}
|
|
3782
|
+
const ok = issues.length === 0;
|
|
3783
|
+
return {
|
|
3784
|
+
ok,
|
|
3785
|
+
schema: HardkasSchemas9.ProgrammabilityCorpusReportV1,
|
|
3786
|
+
path: path8.relative(this.sdk.cwd, root).replace(/\\/g, "/"),
|
|
3787
|
+
status: ok ? "PROGRAMMABILITY_CORPUS_PASS" : "PROGRAMMABILITY_CORPUS_FAIL",
|
|
3788
|
+
summary: {
|
|
3789
|
+
silver,
|
|
3790
|
+
zk,
|
|
3791
|
+
vprogs,
|
|
3792
|
+
rootManifest: manifest ? "PASS" : "FAIL",
|
|
3793
|
+
knownLimitations: Array.isArray(manifest?.expectedKnownLimitations) ? manifest.expectedKnownLimitations : []
|
|
3794
|
+
},
|
|
3795
|
+
claims: programmabilityClaims(),
|
|
3796
|
+
issues
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
planApp(options) {
|
|
3800
|
+
const kind = options.kind ?? "full-lab";
|
|
3801
|
+
const template = options.template ?? defaultTemplate(kind);
|
|
3802
|
+
return {
|
|
3803
|
+
ok: true,
|
|
3804
|
+
schema: HardkasSchemas9.ProgrammabilityAppPlanV1,
|
|
3805
|
+
status: "PROGRAMMABILITY_APP_PLAN_READY",
|
|
3806
|
+
kind,
|
|
3807
|
+
template,
|
|
3808
|
+
commands: commandsForKind(kind),
|
|
3809
|
+
sdkSurfaces: sdkSurfacesForKind(kind),
|
|
3810
|
+
claims: programmabilityClaims(),
|
|
3811
|
+
nonClaims: nonClaims()
|
|
3812
|
+
};
|
|
3813
|
+
}
|
|
3814
|
+
};
|
|
3815
|
+
function createProgrammabilityCapabilities() {
|
|
3816
|
+
return {
|
|
3817
|
+
ok: true,
|
|
3818
|
+
schema: HardkasSchemas9.ProgrammabilityCapabilitiesV1,
|
|
3819
|
+
status: "PROGRAMMABILITY_SURFACE_READY",
|
|
3820
|
+
surfaces: {
|
|
3821
|
+
silverScript: "SILVERSCRIPT_BUILDER_READY",
|
|
3822
|
+
zkCorpus: "ZK_CORPUS_SURFACE_READY",
|
|
3823
|
+
groth16FixtureCoherence: "READY_GROTH16_FIXTURE_COHERENCE",
|
|
3824
|
+
risc0Inspect: "RISC0_INSPECT_SURFACE_READY",
|
|
3825
|
+
vProgsInspect: "VPROGS_INSPECT_SURFACE_READY"
|
|
3826
|
+
},
|
|
3827
|
+
claims: programmabilityClaims(),
|
|
3828
|
+
nonClaims: nonClaims()
|
|
3829
|
+
};
|
|
3830
|
+
}
|
|
3831
|
+
function programmabilityClaims() {
|
|
3832
|
+
return {
|
|
3833
|
+
artifactCoherence: "READY_MATCH",
|
|
3834
|
+
silverScriptBuilder: "SILVERSCRIPT_BUILDER_READY",
|
|
3835
|
+
zkCorpusSurface: "ZK_CORPUS_SURFACE_READY",
|
|
3836
|
+
zkLocalVerification: "READY_GROTH16_FIXTURE_COHERENCE",
|
|
3837
|
+
risc0InspectSurface: "RISC0_INSPECT_SURFACE_READY",
|
|
3838
|
+
vProgsInspectSurface: "VPROGS_INSPECT_SURFACE_READY",
|
|
3839
|
+
runtimeOutcome: "PARTIAL",
|
|
3840
|
+
vmConsensusEquivalence: "NOT_CLAIMED",
|
|
3841
|
+
zkOnchainVerification: "NOT_CLAIMED",
|
|
3842
|
+
vProgsRuntime: "NOT_CLAIMED",
|
|
3843
|
+
vProgsStableApi: "NOT_CLAIMED",
|
|
3844
|
+
mainnet: "BLOCKED_BY_POLICY"
|
|
3845
|
+
};
|
|
3846
|
+
}
|
|
3847
|
+
function inspectJsonArtifact(workspaceRoot, targetPath, kind) {
|
|
3848
|
+
const resolved = path8.resolve(workspaceRoot, targetPath);
|
|
3849
|
+
const issues = [];
|
|
3850
|
+
const artifact = readJson2(resolved, issues);
|
|
3851
|
+
const ok = Boolean(artifact);
|
|
3852
|
+
return {
|
|
3853
|
+
ok,
|
|
3854
|
+
schema: HardkasSchemas9.ProgrammabilityInspectV1,
|
|
3855
|
+
status: ok ? "PROGRAMMABILITY_ARTIFACT_INSPECTED" : "PROGRAMMABILITY_ARTIFACT_INVALID",
|
|
3856
|
+
kind,
|
|
3857
|
+
path: path8.relative(workspaceRoot, resolved).replace(/\\/g, "/"),
|
|
3858
|
+
...artifact?.schema ? { artifactSchema: artifact.schema } : {},
|
|
3859
|
+
...artifact ? { contentHash: calculateContentHash6(artifact, artifact.hashVersion ?? 4) } : {},
|
|
3860
|
+
claims: programmabilityClaims(),
|
|
3861
|
+
issues
|
|
3862
|
+
};
|
|
3863
|
+
}
|
|
3864
|
+
function readJson2(filePath, issues) {
|
|
3865
|
+
if (!fs8.existsSync(filePath)) {
|
|
3866
|
+
issues.push({
|
|
3867
|
+
code: "PROGRAMMABILITY_FILE_MISSING",
|
|
3868
|
+
message: `Missing ${filePath}.`,
|
|
3869
|
+
file: filePath
|
|
3870
|
+
});
|
|
3871
|
+
return void 0;
|
|
3872
|
+
}
|
|
3873
|
+
try {
|
|
3874
|
+
return JSON.parse(fs8.readFileSync(filePath, "utf8"));
|
|
3875
|
+
} catch (error) {
|
|
3876
|
+
issues.push({
|
|
3877
|
+
code: "PROGRAMMABILITY_JSON_INVALID",
|
|
3878
|
+
message: error?.message || `Invalid JSON in ${filePath}.`,
|
|
3879
|
+
file: filePath
|
|
3880
|
+
});
|
|
3881
|
+
return void 0;
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
function expectEqual3(actual, expected, issues, code, file) {
|
|
3885
|
+
if (actual !== expected) {
|
|
3886
|
+
issues.push({
|
|
3887
|
+
code,
|
|
3888
|
+
message: `Expected ${String(expected)}, got ${String(actual)}.`,
|
|
3889
|
+
file
|
|
3890
|
+
});
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
function defaultTemplate(kind) {
|
|
3894
|
+
if (kind === "silver") return "templates/programmability/silver-policy-app";
|
|
3895
|
+
if (kind === "zk") return "templates/programmability/zk-fixture-app";
|
|
3896
|
+
if (kind === "vprog") return "templates/programmability/vprogs-inspect-app";
|
|
3897
|
+
return "templates/programmability/full-lab-app";
|
|
3898
|
+
}
|
|
3899
|
+
function commandsForKind(kind) {
|
|
3900
|
+
const common = [
|
|
3901
|
+
"hardkas programmability capabilities --json",
|
|
3902
|
+
"hardkas programmability corpus verify fixtures/toccata-v2 --json"
|
|
3903
|
+
];
|
|
3904
|
+
if (kind === "silver") return [...common, "hardkas silver inspect <artifact>"];
|
|
3905
|
+
if (kind === "zk")
|
|
3906
|
+
return [...common, "hardkas zk corpus verify fixtures/toccata-v2/zk --json"];
|
|
3907
|
+
if (kind === "vprog") return [...common, "hardkas vprogs inspect <artifact> --json"];
|
|
3908
|
+
return [
|
|
3909
|
+
...common,
|
|
3910
|
+
"hardkas silver inspect <artifact>",
|
|
3911
|
+
"hardkas zk corpus verify fixtures/toccata-v2/zk --json",
|
|
3912
|
+
"hardkas vprogs inspect <artifact> --json"
|
|
3913
|
+
];
|
|
3914
|
+
}
|
|
3915
|
+
function sdkSurfacesForKind(kind) {
|
|
3916
|
+
const common = [
|
|
3917
|
+
"hardkas.programmability.capabilities()",
|
|
3918
|
+
"hardkas.programmability.corpus.verify()"
|
|
3919
|
+
];
|
|
3920
|
+
if (kind === "silver") return [...common, "hardkas.silver.*"];
|
|
3921
|
+
if (kind === "zk")
|
|
3922
|
+
return [...common, "hardkas.zk.proof.*", "hardkas.zk.corpus.verify()"];
|
|
3923
|
+
if (kind === "vprog") return [...common, "hardkas.vprogs.inspect()"];
|
|
3924
|
+
return [...common, "hardkas.silver.*", "hardkas.zk.*", "hardkas.vprogs.*"];
|
|
3925
|
+
}
|
|
3926
|
+
function nonClaims() {
|
|
3927
|
+
return [
|
|
3928
|
+
"no mainnet",
|
|
3929
|
+
"no testnet claim",
|
|
3930
|
+
"no bridge",
|
|
3931
|
+
"no trustless exit",
|
|
3932
|
+
"no on-chain ZK verification",
|
|
3933
|
+
"no full vProgs runtime",
|
|
3934
|
+
"no VM/consensus equivalence"
|
|
3935
|
+
];
|
|
3936
|
+
}
|
|
3937
|
+
|
|
2042
3938
|
// src/index.ts
|
|
2043
3939
|
import { defineHardkasConfig as defineHardkasConfig2 } from "@hardkas/config";
|
|
2044
3940
|
|
|
@@ -2074,16 +3970,16 @@ var defineTask = taskRegistry.defineTask.bind(taskRegistry);
|
|
|
2074
3970
|
import { buildPaymentPlan as buildPaymentPlan2 } from "@hardkas/tx-builder";
|
|
2075
3971
|
import { signTxPlanArtifact as signTxPlanArtifact2 } from "@hardkas/accounts";
|
|
2076
3972
|
import {
|
|
2077
|
-
writeArtifact as
|
|
3973
|
+
writeArtifact as writeArtifact4,
|
|
2078
3974
|
createTxPlanArtifact as createTxPlanArtifact2,
|
|
2079
3975
|
ARTIFACT_SCHEMAS as ARTIFACT_SCHEMAS2,
|
|
2080
|
-
HARDKAS_VERSION as
|
|
3976
|
+
HARDKAS_VERSION as HARDKAS_VERSION5
|
|
2081
3977
|
} from "@hardkas/artifacts";
|
|
2082
3978
|
import {
|
|
2083
3979
|
SOMPI_PER_KAS,
|
|
2084
3980
|
HardkasError as HardkasError4,
|
|
2085
|
-
parseKasToSompi as
|
|
2086
|
-
|
|
3981
|
+
parseKasToSompi as parseKasToSompi3,
|
|
3982
|
+
formatSompiToKas as formatSompiToKas2
|
|
2087
3983
|
} from "@hardkas/core";
|
|
2088
3984
|
var Hardkas = class _Hardkas {
|
|
2089
3985
|
constructor(config, options, rpc) {
|
|
@@ -2109,6 +4005,12 @@ var Hardkas = class _Hardkas {
|
|
|
2109
4005
|
this.replay = new HardkasReplay(this);
|
|
2110
4006
|
this.lineage = new HardkasLineage(this);
|
|
2111
4007
|
this.workflow = new HardkasWorkflow(this);
|
|
4008
|
+
this.capabilitiesApi = new HardkasCapabilitiesApi();
|
|
4009
|
+
this.corpus = new HardkasCorpus(this);
|
|
4010
|
+
this.silver = new HardkasSilver(this);
|
|
4011
|
+
this.zk = new HardkasZk(this);
|
|
4012
|
+
this.vprogs = new HardkasVprogs(this);
|
|
4013
|
+
this.programmability = new HardkasProgrammability(this);
|
|
2112
4014
|
}
|
|
2113
4015
|
config;
|
|
2114
4016
|
workspace;
|
|
@@ -2121,6 +4023,12 @@ var Hardkas = class _Hardkas {
|
|
|
2121
4023
|
replay;
|
|
2122
4024
|
lineage;
|
|
2123
4025
|
workflow;
|
|
4026
|
+
capabilitiesApi;
|
|
4027
|
+
corpus;
|
|
4028
|
+
silver;
|
|
4029
|
+
zk;
|
|
4030
|
+
vprogs;
|
|
4031
|
+
programmability;
|
|
2124
4032
|
signer;
|
|
2125
4033
|
mode;
|
|
2126
4034
|
policy;
|
|
@@ -2142,21 +4050,23 @@ var Hardkas = class _Hardkas {
|
|
|
2142
4050
|
const activeNetwork = options.network || loaded.config.defaultNetwork || "simnet";
|
|
2143
4051
|
const isSimulated = activeNetwork === "simulated" || loaded.config.networks?.[activeNetwork]?.kind === "simulated";
|
|
2144
4052
|
const autoBootstrap = options.autoBootstrap ?? (isSimulated ? true : false);
|
|
2145
|
-
const
|
|
2146
|
-
const
|
|
4053
|
+
const fs9 = await import("fs");
|
|
4054
|
+
const path9 = await import("path");
|
|
2147
4055
|
const cwd = options.cwd || process.cwd();
|
|
2148
|
-
const hardkasDir =
|
|
4056
|
+
const hardkasDir = path9.join(cwd, ".hardkas");
|
|
2149
4057
|
if (autoBootstrap) {
|
|
2150
4058
|
if (!isSimulated) {
|
|
2151
4059
|
if (options.logger) {
|
|
2152
|
-
options.logger.warn(
|
|
4060
|
+
options.logger.warn(
|
|
4061
|
+
"[HardKAS] autoBootstrap ignored for non-simulated network"
|
|
4062
|
+
);
|
|
2153
4063
|
}
|
|
2154
4064
|
} else {
|
|
2155
|
-
if (!
|
|
4065
|
+
if (!fs9.existsSync(hardkasDir)) {
|
|
2156
4066
|
if (options.logger) {
|
|
2157
4067
|
options.logger.info("[HardKAS] Auto-bootstrapping simulated workspace");
|
|
2158
4068
|
}
|
|
2159
|
-
|
|
4069
|
+
fs9.mkdirSync(hardkasDir, { recursive: true });
|
|
2160
4070
|
}
|
|
2161
4071
|
try {
|
|
2162
4072
|
const { loadOrCreateLocalnetState } = await import("@hardkas/localnet");
|
|
@@ -2165,8 +4075,11 @@ var Hardkas = class _Hardkas {
|
|
|
2165
4075
|
}
|
|
2166
4076
|
}
|
|
2167
4077
|
} else {
|
|
2168
|
-
if (!
|
|
2169
|
-
throw new HardkasError3(
|
|
4078
|
+
if (!fs9.existsSync(hardkasDir)) {
|
|
4079
|
+
throw new HardkasError3(
|
|
4080
|
+
"NOT_INITIALIZED",
|
|
4081
|
+
"Workspace not initialized. Run npx hardkas init . or pass autoBootstrap: true."
|
|
4082
|
+
);
|
|
2170
4083
|
}
|
|
2171
4084
|
}
|
|
2172
4085
|
if (options.network) {
|
|
@@ -2197,6 +4110,9 @@ var Hardkas = class _Hardkas {
|
|
|
2197
4110
|
get cwd() {
|
|
2198
4111
|
return this.config.cwd;
|
|
2199
4112
|
}
|
|
4113
|
+
async capabilities() {
|
|
4114
|
+
return this.capabilitiesApi.get();
|
|
4115
|
+
}
|
|
2200
4116
|
/**
|
|
2201
4117
|
* Validates an action against the active security policy.
|
|
2202
4118
|
* Throws HardkasError if the policy is violated.
|
|
@@ -2226,26 +4142,43 @@ var Hardkas = class _Hardkas {
|
|
|
2226
4142
|
};
|
|
2227
4143
|
export {
|
|
2228
4144
|
ARTIFACT_SCHEMAS2 as ARTIFACT_SCHEMAS,
|
|
2229
|
-
|
|
4145
|
+
HARDKAS_VERSION5 as HARDKAS_VERSION,
|
|
2230
4146
|
Hardkas,
|
|
2231
4147
|
HardkasAccounts,
|
|
2232
4148
|
HardkasArtifactsManager,
|
|
4149
|
+
HardkasCapabilitiesApi,
|
|
4150
|
+
HardkasCorpus,
|
|
2233
4151
|
HardkasError4 as HardkasError,
|
|
2234
4152
|
HardkasL2,
|
|
2235
4153
|
HardkasLineage,
|
|
2236
4154
|
HardkasLocalnet,
|
|
4155
|
+
HardkasProgrammability,
|
|
2237
4156
|
HardkasQuery,
|
|
2238
4157
|
HardkasReplay,
|
|
4158
|
+
HardkasSilver,
|
|
2239
4159
|
HardkasTx,
|
|
4160
|
+
HardkasVprogs,
|
|
2240
4161
|
HardkasWorkspace,
|
|
4162
|
+
HardkasZk,
|
|
2241
4163
|
SOMPI_PER_KAS,
|
|
2242
4164
|
buildPaymentPlan2 as buildPaymentPlan,
|
|
4165
|
+
createHardkasCapabilities,
|
|
2243
4166
|
createHardkasClient,
|
|
4167
|
+
createProgrammabilityCapabilities,
|
|
2244
4168
|
createTxPlanArtifact2 as createTxPlanArtifact,
|
|
4169
|
+
createVprogsCapabilities,
|
|
4170
|
+
createVprogsStatus,
|
|
4171
|
+
createZkCapabilities,
|
|
2245
4172
|
defineHardkasConfig2 as defineHardkasConfig,
|
|
2246
4173
|
defineTask,
|
|
2247
|
-
|
|
2248
|
-
|
|
4174
|
+
formatSompiToKas2 as formatSompiToKas,
|
|
4175
|
+
inspectVprogsArtifact,
|
|
4176
|
+
inspectZkProof,
|
|
4177
|
+
parseKasToSompi3 as parseKasToSompi,
|
|
4178
|
+
programmabilityClaims,
|
|
2249
4179
|
signTxPlanArtifact2 as signTxPlanArtifact,
|
|
2250
|
-
|
|
4180
|
+
verifyToccataCorpus,
|
|
4181
|
+
verifyZkCorpus,
|
|
4182
|
+
verifyZkProofLocal,
|
|
4183
|
+
writeArtifact4 as writeArtifact
|
|
2251
4184
|
};
|