@hardkas/artifacts 0.2.2-alpha → 0.3.0-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/dist/index.d.ts +137 -16
- package/dist/index.js +266 -84
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ArtifactType, NetworkId, ExecutionMode, ContentHash, WorkflowId, ArtifactId, LineageId, EventSequence, KaspaAddress,
|
|
1
|
+
import { ArtifactType, NetworkId, ExecutionMode, ContentHash, WorkflowId, ArtifactId, LineageId, EventSequence, TxId, KaspaAddress, CorruptionCode, CorruptionSeverity, EventEnvelope } from '@hardkas/core';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { TxOutput, Utxo, TxPlan as TxPlan$1 } from '@hardkas/tx-builder';
|
|
4
4
|
|
|
5
|
-
declare const HARDKAS_VERSION = "0.
|
|
5
|
+
declare const HARDKAS_VERSION = "0.3.0-alpha";
|
|
6
6
|
declare const ARTIFACT_SCHEMAS: {
|
|
7
7
|
readonly LOCALNET_STATE: "hardkas.localnetState.v1";
|
|
8
8
|
readonly REAL_ACCOUNT_STORE: "hardkas.realAccountStore.v1";
|
|
@@ -42,6 +42,7 @@ declare const BaseArtifactSchema: z.ZodObject<{
|
|
|
42
42
|
schema: z.ZodString;
|
|
43
43
|
hardkasVersion: z.ZodString;
|
|
44
44
|
version: z.ZodLiteral<"1.0.0-alpha">;
|
|
45
|
+
hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
|
|
45
46
|
networkId: z.ZodEnum<["mainnet", "testnet-10", "testnet-11", "testnet-12", "simnet", "simnet-1", "devnet"]>;
|
|
46
47
|
mode: z.ZodEnum<["simulated", "real", "readonly"]>;
|
|
47
48
|
contentHash: z.ZodOptional<z.ZodString>;
|
|
@@ -72,6 +73,7 @@ declare const BaseArtifactSchema: z.ZodObject<{
|
|
|
72
73
|
networkId: "mainnet" | "testnet-10" | "testnet-11" | "testnet-12" | "simnet" | "simnet-1" | "devnet";
|
|
73
74
|
mode: "simulated" | "real" | "readonly";
|
|
74
75
|
createdAt: string;
|
|
76
|
+
hashVersion?: string | number | undefined;
|
|
75
77
|
contentHash?: string | undefined;
|
|
76
78
|
lineage?: {
|
|
77
79
|
artifactId: string;
|
|
@@ -87,6 +89,7 @@ declare const BaseArtifactSchema: z.ZodObject<{
|
|
|
87
89
|
networkId: "mainnet" | "testnet-10" | "testnet-11" | "testnet-12" | "simnet" | "simnet-1" | "devnet";
|
|
88
90
|
mode: "simulated" | "real" | "readonly";
|
|
89
91
|
createdAt: string;
|
|
92
|
+
hashVersion?: string | number | undefined;
|
|
90
93
|
contentHash?: string | undefined;
|
|
91
94
|
lineage?: {
|
|
92
95
|
artifactId: string;
|
|
@@ -112,6 +115,7 @@ declare const AccountRefSchema: z.ZodObject<{
|
|
|
112
115
|
declare const TxPlanSchema: z.ZodObject<{
|
|
113
116
|
hardkasVersion: z.ZodString;
|
|
114
117
|
version: z.ZodLiteral<"1.0.0-alpha">;
|
|
118
|
+
hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
|
|
115
119
|
contentHash: z.ZodOptional<z.ZodString>;
|
|
116
120
|
createdAt: z.ZodString;
|
|
117
121
|
lineage: z.ZodOptional<z.ZodObject<{
|
|
@@ -245,6 +249,7 @@ declare const TxPlanSchema: z.ZodObject<{
|
|
|
245
249
|
address: string;
|
|
246
250
|
amountSompi: string;
|
|
247
251
|
}[];
|
|
252
|
+
hashVersion?: string | number | undefined;
|
|
248
253
|
contentHash?: string | undefined;
|
|
249
254
|
lineage?: {
|
|
250
255
|
artifactId: string;
|
|
@@ -290,6 +295,7 @@ declare const TxPlanSchema: z.ZodObject<{
|
|
|
290
295
|
address: string;
|
|
291
296
|
amountSompi: string;
|
|
292
297
|
}[];
|
|
298
|
+
hashVersion?: string | number | undefined;
|
|
293
299
|
contentHash?: string | undefined;
|
|
294
300
|
lineage?: {
|
|
295
301
|
artifactId: string;
|
|
@@ -374,6 +380,7 @@ declare const LocalnetUtxoSchemaV2: z.ZodObject<{
|
|
|
374
380
|
declare const SnapshotSchema: z.ZodObject<{
|
|
375
381
|
hardkasVersion: z.ZodString;
|
|
376
382
|
version: z.ZodLiteral<"1.0.0-alpha">;
|
|
383
|
+
hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
|
|
377
384
|
networkId: z.ZodEnum<["mainnet", "testnet-10", "testnet-11", "testnet-12", "simnet", "simnet-1", "devnet"]>;
|
|
378
385
|
mode: z.ZodEnum<["simulated", "real", "readonly"]>;
|
|
379
386
|
contentHash: z.ZodOptional<z.ZodString>;
|
|
@@ -452,6 +459,7 @@ declare const SnapshotSchema: z.ZodObject<{
|
|
|
452
459
|
spent: boolean;
|
|
453
460
|
createdAtDaaScore: string;
|
|
454
461
|
}[];
|
|
462
|
+
hashVersion?: string | number | undefined;
|
|
455
463
|
contentHash?: string | undefined;
|
|
456
464
|
lineage?: {
|
|
457
465
|
artifactId: string;
|
|
@@ -483,6 +491,7 @@ declare const SnapshotSchema: z.ZodObject<{
|
|
|
483
491
|
spent: boolean;
|
|
484
492
|
createdAtDaaScore: string;
|
|
485
493
|
}[];
|
|
494
|
+
hashVersion?: string | number | undefined;
|
|
486
495
|
contentHash?: string | undefined;
|
|
487
496
|
lineage?: {
|
|
488
497
|
artifactId: string;
|
|
@@ -499,6 +508,7 @@ declare const SnapshotSchema: z.ZodObject<{
|
|
|
499
508
|
declare const TxReceiptSchema: z.ZodObject<{
|
|
500
509
|
hardkasVersion: z.ZodString;
|
|
501
510
|
version: z.ZodLiteral<"1.0.0-alpha">;
|
|
511
|
+
hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
|
|
502
512
|
contentHash: z.ZodOptional<z.ZodString>;
|
|
503
513
|
createdAt: z.ZodString;
|
|
504
514
|
lineage: z.ZodOptional<z.ZodObject<{
|
|
@@ -636,6 +646,7 @@ declare const TxReceiptSchema: z.ZodObject<{
|
|
|
636
646
|
amountSompi: string;
|
|
637
647
|
txId: string;
|
|
638
648
|
feeSompi: string;
|
|
649
|
+
hashVersion?: string | number | undefined;
|
|
639
650
|
contentHash?: string | undefined;
|
|
640
651
|
lineage?: {
|
|
641
652
|
artifactId: string;
|
|
@@ -692,6 +703,7 @@ declare const TxReceiptSchema: z.ZodObject<{
|
|
|
692
703
|
amountSompi: string;
|
|
693
704
|
txId: string;
|
|
694
705
|
feeSompi: string;
|
|
706
|
+
hashVersion?: string | number | undefined;
|
|
695
707
|
contentHash?: string | undefined;
|
|
696
708
|
lineage?: {
|
|
697
709
|
artifactId: string;
|
|
@@ -731,6 +743,7 @@ declare const TxReceiptSchema: z.ZodObject<{
|
|
|
731
743
|
declare const SignedTxSchema: z.ZodObject<{
|
|
732
744
|
hardkasVersion: z.ZodString;
|
|
733
745
|
version: z.ZodLiteral<"1.0.0-alpha">;
|
|
746
|
+
hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
|
|
734
747
|
contentHash: z.ZodOptional<z.ZodString>;
|
|
735
748
|
createdAt: z.ZodString;
|
|
736
749
|
lineage: z.ZodOptional<z.ZodObject<{
|
|
@@ -823,6 +836,7 @@ declare const SignedTxSchema: z.ZodObject<{
|
|
|
823
836
|
format: string;
|
|
824
837
|
payload: string;
|
|
825
838
|
};
|
|
839
|
+
hashVersion?: string | number | undefined;
|
|
826
840
|
contentHash?: string | undefined;
|
|
827
841
|
lineage?: {
|
|
828
842
|
artifactId: string;
|
|
@@ -858,6 +872,7 @@ declare const SignedTxSchema: z.ZodObject<{
|
|
|
858
872
|
format: string;
|
|
859
873
|
payload: string;
|
|
860
874
|
};
|
|
875
|
+
hashVersion?: string | number | undefined;
|
|
861
876
|
contentHash?: string | undefined;
|
|
862
877
|
lineage?: {
|
|
863
878
|
artifactId: string;
|
|
@@ -872,6 +887,7 @@ declare const SignedTxSchema: z.ZodObject<{
|
|
|
872
887
|
declare const TxTraceSchema: z.ZodObject<{
|
|
873
888
|
hardkasVersion: z.ZodString;
|
|
874
889
|
version: z.ZodLiteral<"1.0.0-alpha">;
|
|
890
|
+
hashVersion: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
|
|
875
891
|
contentHash: z.ZodOptional<z.ZodString>;
|
|
876
892
|
createdAt: z.ZodString;
|
|
877
893
|
lineage: z.ZodOptional<z.ZodObject<{
|
|
@@ -976,6 +992,7 @@ declare const TxTraceSchema: z.ZodObject<{
|
|
|
976
992
|
timestamp: string;
|
|
977
993
|
details?: any;
|
|
978
994
|
}[];
|
|
995
|
+
hashVersion?: string | number | undefined;
|
|
979
996
|
contentHash?: string | undefined;
|
|
980
997
|
lineage?: {
|
|
981
998
|
artifactId: string;
|
|
@@ -1012,6 +1029,7 @@ declare const TxTraceSchema: z.ZodObject<{
|
|
|
1012
1029
|
timestamp: string;
|
|
1013
1030
|
details?: any;
|
|
1014
1031
|
}[];
|
|
1032
|
+
hashVersion?: string | number | undefined;
|
|
1015
1033
|
contentHash?: string | undefined;
|
|
1016
1034
|
lineage?: {
|
|
1017
1035
|
artifactId: string;
|
|
@@ -1040,6 +1058,7 @@ type Snapshot = z.infer<typeof SnapshotSchema>;
|
|
|
1040
1058
|
type TxReceipt = z.infer<typeof TxReceiptSchema>;
|
|
1041
1059
|
type SignedTx = z.infer<typeof SignedTxSchema>;
|
|
1042
1060
|
type TxTrace = z.infer<typeof TxTraceSchema>;
|
|
1061
|
+
type DagContext$1 = z.infer<typeof DagContextSchema>;
|
|
1043
1062
|
|
|
1044
1063
|
interface ArtifactValidationResult {
|
|
1045
1064
|
ok: boolean;
|
|
@@ -1118,15 +1137,16 @@ declare function assertDecimalBigIntString(value: any, field: string, errors: st
|
|
|
1118
1137
|
declare function assertHexData(value: any, field: string, errors: string[]): void;
|
|
1119
1138
|
declare function assertEvmAddress(value: any, field: string, errors: string[]): void;
|
|
1120
1139
|
declare function assertEvmTxHash(value: any, field: string, errors: string[]): void;
|
|
1121
|
-
declare function createIgraPlanId(): string;
|
|
1122
|
-
declare function createIgraSignedId(): string;
|
|
1123
|
-
declare function createIgraDeployPlanId(): string;
|
|
1140
|
+
declare function createIgraPlanId(hash: string): string;
|
|
1141
|
+
declare function createIgraSignedId(hash: string): string;
|
|
1142
|
+
declare function createIgraDeployPlanId(hash: string): string;
|
|
1124
1143
|
|
|
1125
1144
|
type AssumptionLevel = "dev" | "trusted" | "network-observed";
|
|
1126
1145
|
interface HardkasArtifactBase {
|
|
1127
1146
|
schema: HardkasArtifactSchema;
|
|
1128
1147
|
hardkasVersion: string;
|
|
1129
1148
|
version: string;
|
|
1149
|
+
hashVersion?: number | string;
|
|
1130
1150
|
networkId: NetworkId;
|
|
1131
1151
|
mode: ExecutionMode;
|
|
1132
1152
|
createdAt: string;
|
|
@@ -1135,6 +1155,7 @@ interface BaseArtifact<T extends ArtifactType> {
|
|
|
1135
1155
|
schema: `hardkas.${T}`;
|
|
1136
1156
|
hardkasVersion: string;
|
|
1137
1157
|
version: string;
|
|
1158
|
+
hashVersion?: number | string;
|
|
1138
1159
|
networkId: NetworkId;
|
|
1139
1160
|
mode: ExecutionMode;
|
|
1140
1161
|
createdAt: string;
|
|
@@ -1365,18 +1386,70 @@ interface TxTraceArtifact extends BaseArtifact<"txTrace"> {
|
|
|
1365
1386
|
dagContext?: DagContext | undefined;
|
|
1366
1387
|
}
|
|
1367
1388
|
|
|
1389
|
+
interface DeploymentRecord extends HardkasArtifactBase {
|
|
1390
|
+
schema: "hardkas.deployment.v1";
|
|
1391
|
+
/** Human-readable label (e.g., "initial-funding", "vault-covenant-v1") */
|
|
1392
|
+
label: string;
|
|
1393
|
+
/** Network where this was deployed */
|
|
1394
|
+
networkId: NetworkId;
|
|
1395
|
+
/** Deployment status */
|
|
1396
|
+
status: "planned" | "sent" | "confirmed" | "failed" | "unknown";
|
|
1397
|
+
/** The transaction ID (if sent) */
|
|
1398
|
+
txId?: TxId;
|
|
1399
|
+
/** Reference to the plan artifact that produced this deployment */
|
|
1400
|
+
planArtifactId?: ArtifactId;
|
|
1401
|
+
/** Reference to the receipt artifact (if confirmed) */
|
|
1402
|
+
receiptArtifactId?: ArtifactId;
|
|
1403
|
+
/** Deployed addresses or outputs (for covenant/contract deployments) */
|
|
1404
|
+
deployedAddresses?: string[];
|
|
1405
|
+
/** Deployment metadata */
|
|
1406
|
+
deployer?: string;
|
|
1407
|
+
/** Content hash of the deployed payload (bytecode, script, or tx content) */
|
|
1408
|
+
payloadHash?: string;
|
|
1409
|
+
/** Timestamp of deployment */
|
|
1410
|
+
deployedAt: string;
|
|
1411
|
+
/** HardKAS version used */
|
|
1412
|
+
hardkasVersion: string;
|
|
1413
|
+
/** Canonical content hash of this record */
|
|
1414
|
+
contentHash?: ContentHash;
|
|
1415
|
+
/** Notes */
|
|
1416
|
+
notes?: string;
|
|
1417
|
+
}
|
|
1418
|
+
interface DeploymentIndex extends HardkasArtifactBase {
|
|
1419
|
+
schema: "hardkas.deploymentIndex.v1";
|
|
1420
|
+
networkId: NetworkId;
|
|
1421
|
+
deployments: DeploymentSummary[];
|
|
1422
|
+
lastUpdated: string;
|
|
1423
|
+
}
|
|
1424
|
+
interface DeploymentSummary {
|
|
1425
|
+
label: string;
|
|
1426
|
+
networkId: NetworkId;
|
|
1427
|
+
status: string;
|
|
1428
|
+
txId?: string;
|
|
1429
|
+
deployedAt: string;
|
|
1430
|
+
contentHash: string;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
declare const SEMANTIC_EXCLUSIONS: Set<string>;
|
|
1434
|
+
/**
|
|
1435
|
+
* Current canonicalization version.
|
|
1436
|
+
* v1: BigInt(123) -> "123" (Collision with String "123")
|
|
1437
|
+
* v2: BigInt(123) -> "n:123" (Distinguishable)
|
|
1438
|
+
* v3: String normalization (\r\n -> \n, NFC) for cross-platform stability.
|
|
1439
|
+
*/
|
|
1440
|
+
declare const CURRENT_HASH_VERSION = 3;
|
|
1368
1441
|
/**
|
|
1369
1442
|
* Deterministically stringifies an object by sorting keys recursively.
|
|
1370
|
-
* Handles BigInt by converting to string.
|
|
1371
|
-
* Excludes
|
|
1443
|
+
* Handles BigInt by converting to string with type marker.
|
|
1444
|
+
* Excludes fields in SEMANTIC_EXCLUSIONS during serialization.
|
|
1372
1445
|
* Skips keys with undefined values (matching JSON.stringify behavior).
|
|
1373
1446
|
*/
|
|
1374
|
-
declare function canonicalStringify(obj: any): string;
|
|
1447
|
+
declare function canonicalStringify(obj: any, version?: number): string;
|
|
1375
1448
|
/**
|
|
1376
1449
|
* Calculates a SHA-256 hash of the canonical JSON representation.
|
|
1377
|
-
* Always excludes
|
|
1450
|
+
* Always excludes fields in SEMANTIC_EXCLUSIONS from the calculation.
|
|
1378
1451
|
*/
|
|
1379
|
-
declare function calculateContentHash(obj: any): string;
|
|
1452
|
+
declare function calculateContentHash(obj: any, version?: number): string;
|
|
1380
1453
|
|
|
1381
1454
|
interface Clock {
|
|
1382
1455
|
now(): number;
|
|
@@ -1388,12 +1461,13 @@ interface VerificationContext {
|
|
|
1388
1461
|
networkId?: NetworkId;
|
|
1389
1462
|
parent?: unknown;
|
|
1390
1463
|
}
|
|
1391
|
-
type VerificationSeverity =
|
|
1464
|
+
type VerificationSeverity = CorruptionSeverity | "info" | "critical";
|
|
1392
1465
|
type VerificationIssue = {
|
|
1393
|
-
code: string;
|
|
1466
|
+
code: CorruptionCode | string;
|
|
1394
1467
|
severity: VerificationSeverity;
|
|
1395
1468
|
message: string;
|
|
1396
1469
|
path?: string | undefined;
|
|
1470
|
+
pathStr?: string | undefined;
|
|
1397
1471
|
artifactId?: string | undefined;
|
|
1398
1472
|
};
|
|
1399
1473
|
type ArtifactVerificationResult = {
|
|
@@ -1420,9 +1494,9 @@ declare function verifyArtifactIntegrity(artifactOrPath: unknown): Promise<Artif
|
|
|
1420
1494
|
declare function verifyArtifactSemantics(artifact: unknown, context?: VerificationContext): ArtifactVerificationResult;
|
|
1421
1495
|
/**
|
|
1422
1496
|
* Verifies an artifact's replay consistency.
|
|
1423
|
-
*
|
|
1497
|
+
* Honest implementation: reports as unsupported or not implemented.
|
|
1424
1498
|
*/
|
|
1425
|
-
declare function verifyArtifactReplay(artifact: unknown,
|
|
1499
|
+
declare function verifyArtifactReplay(artifact: unknown, _context?: VerificationContext): Promise<ArtifactVerificationResult>;
|
|
1426
1500
|
/**
|
|
1427
1501
|
* @deprecated Use verifyArtifactIntegrity instead.
|
|
1428
1502
|
*/
|
|
@@ -1631,6 +1705,9 @@ declare function createSimulatedTxReceipt(plan: TxPlan, txId: string, extra?: {
|
|
|
1631
1705
|
spentUtxoIds?: string[];
|
|
1632
1706
|
createdUtxoIds?: string[];
|
|
1633
1707
|
daaScore?: string;
|
|
1708
|
+
preStateHash?: string;
|
|
1709
|
+
postStateHash?: string;
|
|
1710
|
+
dagContext?: DagContext$1;
|
|
1634
1711
|
}): TxReceipt;
|
|
1635
1712
|
/**
|
|
1636
1713
|
* Validates and extracts the raw transaction from a signed artifact.
|
|
@@ -1728,9 +1805,53 @@ interface LineageValidationResult {
|
|
|
1728
1805
|
ok: boolean;
|
|
1729
1806
|
issues: VerificationIssue[];
|
|
1730
1807
|
}
|
|
1808
|
+
interface LineageOptions {
|
|
1809
|
+
strict?: boolean;
|
|
1810
|
+
}
|
|
1731
1811
|
/**
|
|
1732
1812
|
* Validates the lineage relationship between an artifact and its parent.
|
|
1733
1813
|
*/
|
|
1734
|
-
declare function verifyLineage(artifact: any, parent?: any): LineageValidationResult;
|
|
1814
|
+
declare function verifyLineage(artifact: any, parent?: any, options?: LineageOptions): LineageValidationResult;
|
|
1815
|
+
|
|
1816
|
+
interface DiffEntry {
|
|
1817
|
+
path: string;
|
|
1818
|
+
kind: "added" | "removed" | "changed";
|
|
1819
|
+
left?: any;
|
|
1820
|
+
right?: any;
|
|
1821
|
+
}
|
|
1822
|
+
interface ArtifactDiff {
|
|
1823
|
+
identical: boolean;
|
|
1824
|
+
entries: DiffEntry[];
|
|
1825
|
+
}
|
|
1826
|
+
/**
|
|
1827
|
+
* Performs a semantic diff between two artifacts, ignoring volatile metadata.
|
|
1828
|
+
* Uses the same exclusion rules as canonical hashing.
|
|
1829
|
+
* Redacts secrets from the output.
|
|
1830
|
+
*/
|
|
1831
|
+
declare function diffArtifacts(left: any, right: any): ArtifactDiff;
|
|
1832
|
+
|
|
1833
|
+
declare function createDeploymentRecord(opts: {
|
|
1834
|
+
label: string;
|
|
1835
|
+
networkId: NetworkId;
|
|
1836
|
+
status?: "planned" | "sent" | "confirmed" | "failed" | "unknown";
|
|
1837
|
+
txId?: TxId;
|
|
1838
|
+
planArtifactId?: ArtifactId;
|
|
1839
|
+
receiptArtifactId?: ArtifactId;
|
|
1840
|
+
deployedAddresses?: string[];
|
|
1841
|
+
deployer?: string;
|
|
1842
|
+
payloadHash?: string;
|
|
1843
|
+
notes?: string;
|
|
1844
|
+
}): DeploymentRecord;
|
|
1845
|
+
declare function updateDeploymentStatus(record: DeploymentRecord, newStatus: DeploymentRecord["status"], txId?: TxId): DeploymentRecord;
|
|
1846
|
+
|
|
1847
|
+
/**
|
|
1848
|
+
* Manages deployment records on the filesystem.
|
|
1849
|
+
* Storage: .hardkas/deployments/<networkId>/<label>.json
|
|
1850
|
+
*/
|
|
1851
|
+
declare function saveDeployment(rootDir: string, record: DeploymentRecord): Promise<string>;
|
|
1852
|
+
declare function loadDeployment(rootDir: string, networkId: string, label: string): Promise<DeploymentRecord | null>;
|
|
1853
|
+
declare function listDeployments(rootDir: string, networkId?: string): Promise<DeploymentSummary[]>;
|
|
1854
|
+
declare function updateDeployment(rootDir: string, networkId: string, label: string, update: Partial<DeploymentRecord>): Promise<DeploymentRecord>;
|
|
1855
|
+
declare function deleteDeployment(rootDir: string, networkId: string, label: string): Promise<boolean>;
|
|
1735
1856
|
|
|
1736
|
-
export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactValidationResult, type ArtifactVerificationResult, type AssumptionLevel, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageValidationResult, LocalnetUtxoSchemaV2, NetworkInvariant, ReplayInvariant, SchemaInvariant, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canonicalStringify, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, isIgraTxPlanArtifact, listIgraTxReceiptArtifacts, loadIgraTxReceiptArtifact, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
|
|
1857
|
+
export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactDiff, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactValidationResult, type ArtifactVerificationResult, type AssumptionLevel, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, CURRENT_HASH_VERSION, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type DeploymentIndex, type DeploymentRecord, type DeploymentSummary, type DiffEntry, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageOptions, type LineageValidationResult, LocalnetUtxoSchemaV2, NetworkInvariant, ReplayInvariant, SEMANTIC_EXCLUSIONS, SchemaInvariant, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canonicalStringify, createDeploymentRecord, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, deleteDeployment, diffArtifacts, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, isIgraTxPlanArtifact, listDeployments, listIgraTxReceiptArtifacts, loadDeployment, loadIgraTxReceiptArtifact, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, saveDeployment, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, updateDeployment, updateDeploymentStatus, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
|
-
var HARDKAS_VERSION = "0.
|
|
2
|
+
var HARDKAS_VERSION = "0.3.0-alpha";
|
|
3
3
|
var ARTIFACT_SCHEMAS = {
|
|
4
4
|
LOCALNET_STATE: "hardkas.localnetState.v1",
|
|
5
5
|
REAL_ACCOUNT_STORE: "hardkas.realAccountStore.v1",
|
|
@@ -121,39 +121,64 @@ function assertEvmTxHash(value, field, errors) {
|
|
|
121
121
|
errors.push(`Invalid ${field}: must be a 0x-prefixed 64-character EVM transaction hash`);
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
function createIgraPlanId() {
|
|
125
|
-
return `igra-plan-${
|
|
124
|
+
function createIgraPlanId(hash) {
|
|
125
|
+
return `igra-plan-${hash.slice(0, 16)}`;
|
|
126
126
|
}
|
|
127
|
-
function createIgraSignedId() {
|
|
128
|
-
return `igra-signed-${
|
|
127
|
+
function createIgraSignedId(hash) {
|
|
128
|
+
return `igra-signed-${hash.slice(0, 16)}`;
|
|
129
129
|
}
|
|
130
|
-
function createIgraDeployPlanId() {
|
|
131
|
-
return `igradeploy_${
|
|
130
|
+
function createIgraDeployPlanId(hash) {
|
|
131
|
+
return `igradeploy_${hash.slice(0, 16)}`;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// src/canonical.ts
|
|
135
135
|
import { createHash } from "crypto";
|
|
136
|
-
|
|
136
|
+
var SEMANTIC_EXCLUSIONS = /* @__PURE__ */ new Set([
|
|
137
|
+
"contentHash",
|
|
138
|
+
"artifactId",
|
|
139
|
+
"planId",
|
|
140
|
+
"lineage",
|
|
141
|
+
"createdAt",
|
|
142
|
+
"rpcUrl",
|
|
143
|
+
"indexedAt",
|
|
144
|
+
"file_path",
|
|
145
|
+
"file_mtime_ms",
|
|
146
|
+
"hardkasVersion",
|
|
147
|
+
"hashVersion",
|
|
148
|
+
// Exclude hash version from hash
|
|
149
|
+
"parentArtifactId",
|
|
150
|
+
"signedId",
|
|
151
|
+
"deployedAt"
|
|
152
|
+
]);
|
|
153
|
+
var CURRENT_HASH_VERSION = 3;
|
|
154
|
+
function canonicalStringify(obj, version = CURRENT_HASH_VERSION) {
|
|
137
155
|
if (obj === null || typeof obj !== "object") {
|
|
138
156
|
if (typeof obj === "bigint") {
|
|
139
|
-
|
|
157
|
+
if (version >= 2) {
|
|
158
|
+
return JSON.stringify(`n:${obj.toString()}`);
|
|
159
|
+
}
|
|
160
|
+
return JSON.stringify(obj.toString());
|
|
161
|
+
}
|
|
162
|
+
if (typeof obj === "string" && version >= 3) {
|
|
163
|
+
const normalized = obj.normalize("NFC").replace(/\r\n/g, "\n");
|
|
164
|
+
return JSON.stringify(normalized);
|
|
140
165
|
}
|
|
141
166
|
return JSON.stringify(obj);
|
|
142
167
|
}
|
|
143
168
|
if (Array.isArray(obj)) {
|
|
144
|
-
return "[" + obj.map((item) => canonicalStringify(item)).join(",") + "]";
|
|
169
|
+
return "[" + obj.map((item) => canonicalStringify(item, version)).join(",") + "]";
|
|
145
170
|
}
|
|
146
171
|
const sortedKeys = Object.keys(obj).filter(
|
|
147
|
-
(key) => key
|
|
172
|
+
(key) => !SEMANTIC_EXCLUSIONS.has(key) && obj[key] !== void 0
|
|
148
173
|
).sort();
|
|
149
174
|
const result = sortedKeys.map((key) => {
|
|
150
175
|
const value = obj[key];
|
|
151
|
-
return JSON.stringify(key) + ":" + canonicalStringify(value);
|
|
176
|
+
return JSON.stringify(key) + ":" + canonicalStringify(value, version);
|
|
152
177
|
}).join(",");
|
|
153
178
|
return "{" + result + "}";
|
|
154
179
|
}
|
|
155
|
-
function calculateContentHash(obj) {
|
|
156
|
-
const canonical = canonicalStringify(obj);
|
|
180
|
+
function calculateContentHash(obj, version = CURRENT_HASH_VERSION) {
|
|
181
|
+
const canonical = canonicalStringify(obj, version);
|
|
157
182
|
return createHash("sha256").update(canonical).digest("hex");
|
|
158
183
|
}
|
|
159
184
|
|
|
@@ -172,6 +197,7 @@ var BaseArtifactSchema = z.object({
|
|
|
172
197
|
schema: z.string(),
|
|
173
198
|
hardkasVersion: z.string(),
|
|
174
199
|
version: z.literal(ARTIFACT_VERSION),
|
|
200
|
+
hashVersion: z.union([z.number(), z.string()]).optional(),
|
|
175
201
|
networkId: kaspaNetworkIdSchema,
|
|
176
202
|
mode: executionModeSchema,
|
|
177
203
|
contentHash: z.string().optional(),
|
|
@@ -381,14 +407,15 @@ function verifyFeeSemantics(artifact) {
|
|
|
381
407
|
}
|
|
382
408
|
|
|
383
409
|
// src/lineage.ts
|
|
384
|
-
function verifyLineage(artifact, parent) {
|
|
410
|
+
function verifyLineage(artifact, parent, options = {}) {
|
|
385
411
|
const issues = [];
|
|
386
412
|
const addIssue = (code, message, severity = "error") => {
|
|
387
413
|
issues.push({ code, severity, message });
|
|
388
414
|
};
|
|
389
415
|
const lineage = artifact.lineage;
|
|
390
416
|
if (!lineage) {
|
|
391
|
-
|
|
417
|
+
const severity = options.strict ? "error" : "warning";
|
|
418
|
+
addIssue("MISSING_LINEAGE", "Artifact has no lineage metadata", severity);
|
|
392
419
|
return {
|
|
393
420
|
ok: issues.every((i) => i.severity !== "error"),
|
|
394
421
|
issues
|
|
@@ -413,26 +440,32 @@ function verifyLineage(artifact, parent) {
|
|
|
413
440
|
if (!parentLineage) {
|
|
414
441
|
addIssue("PARENT_MISSING_LINEAGE", "Parent artifact has no lineage metadata");
|
|
415
442
|
} else {
|
|
443
|
+
if (!lineage.parentArtifactId) {
|
|
444
|
+
addIssue("MISSING_PARENT_ID", "Artifact is missing parentArtifactId reference, but parent was provided for verification.");
|
|
445
|
+
} else if (lineage.parentArtifactId !== parentLineage.artifactId) {
|
|
446
|
+
addIssue("PARENT_ID_MISMATCH", `Parent Artifact ID mismatch: expected ${parentLineage.artifactId}, got ${lineage.parentArtifactId}`);
|
|
447
|
+
}
|
|
416
448
|
if (lineage.lineageId !== parentLineage.lineageId) {
|
|
417
449
|
addIssue("LINEAGE_ID_MISMATCH", `Lineage ID mismatch: expected ${parentLineage.lineageId}, got ${lineage.lineageId}`);
|
|
418
450
|
}
|
|
419
451
|
if (lineage.rootArtifactId !== parentLineage.rootArtifactId) {
|
|
420
|
-
addIssue("
|
|
421
|
-
}
|
|
422
|
-
if (lineage.parentArtifactId && lineage.parentArtifactId !== parentLineage.artifactId) {
|
|
423
|
-
addIssue("PARENT_ID_MISMATCH", `Parent Artifact ID mismatch: expected ${parentLineage.artifactId}, got ${lineage.parentArtifactId}`);
|
|
452
|
+
addIssue("ROOT_ARTIFACT_ID_MISMATCH", `Root Artifact ID mismatch: expected ${parentLineage.rootArtifactId}, got ${lineage.rootArtifactId}`);
|
|
424
453
|
}
|
|
425
454
|
if (lineage.sequence !== void 0 && parentLineage.sequence !== void 0) {
|
|
426
455
|
if (lineage.sequence <= parentLineage.sequence) {
|
|
427
|
-
|
|
456
|
+
const severity = options.strict ? "error" : "warning";
|
|
457
|
+
addIssue("NON_MONOTONIC_SEQUENCE", `Non-monotonic sequence: current (${lineage.sequence}) <= parent (${parentLineage.sequence}).`, severity);
|
|
428
458
|
}
|
|
429
459
|
}
|
|
430
460
|
}
|
|
431
461
|
if (artifact.networkId !== parent.networkId) {
|
|
432
|
-
addIssue("
|
|
462
|
+
addIssue("NETWORK_MISMATCH", `Network mismatch: parent is ${parent.networkId}, current is ${artifact.networkId}`);
|
|
433
463
|
}
|
|
434
464
|
if (artifact.mode !== parent.mode) {
|
|
435
|
-
addIssue("
|
|
465
|
+
addIssue("MODE_MISMATCH", `Mode mismatch: parent is ${parent.mode}, current is ${artifact.mode}`);
|
|
466
|
+
}
|
|
467
|
+
if (lineage.artifactId === lineage.parentArtifactId) {
|
|
468
|
+
addIssue("SELF_PARENT", "Artifact cannot be its own parent.");
|
|
436
469
|
}
|
|
437
470
|
}
|
|
438
471
|
if (parent) {
|
|
@@ -469,9 +502,9 @@ async function verifyArtifactIntegrity(artifactOrPath) {
|
|
|
469
502
|
errors: [],
|
|
470
503
|
issues: []
|
|
471
504
|
};
|
|
472
|
-
const addError = (code, message,
|
|
505
|
+
const addError = (code, message, path4) => {
|
|
473
506
|
result.errors.push(message);
|
|
474
|
-
result.issues.push({ code, severity: "error", message, path:
|
|
507
|
+
result.issues.push({ code, severity: "error", message, path: path4 });
|
|
475
508
|
};
|
|
476
509
|
let artifact;
|
|
477
510
|
try {
|
|
@@ -490,21 +523,22 @@ async function verifyArtifactIntegrity(artifactOrPath) {
|
|
|
490
523
|
result.version = v.version;
|
|
491
524
|
result.expectedHash = v.contentHash;
|
|
492
525
|
if (!v.version || !v.schema) {
|
|
493
|
-
addError("
|
|
526
|
+
addError("ARTIFACT_SCHEMA_MISSING", "Missing version or schema (Artifact might be v1 or legacy)");
|
|
494
527
|
return result;
|
|
495
528
|
}
|
|
496
529
|
const [currentMajor] = ARTIFACT_VERSION.split(".");
|
|
497
530
|
const [artifactMajor] = v.version.split(".");
|
|
498
531
|
if (currentMajor !== artifactMajor) {
|
|
499
|
-
addError("
|
|
532
|
+
addError("ARTIFACT_SCHEMA_INVALID", `Incompatible version: current system is v${currentMajor}, artifact is v${artifactMajor}`);
|
|
500
533
|
return result;
|
|
501
534
|
}
|
|
502
|
-
const
|
|
535
|
+
const hashVersion = v.hashVersion || 1;
|
|
536
|
+
const actualHash = calculateContentHash(v, hashVersion);
|
|
503
537
|
result.actualHash = actualHash;
|
|
504
538
|
if (!v.contentHash) {
|
|
505
|
-
addError("
|
|
539
|
+
addError("ARTIFACT_HASH_MISMATCH", "Missing contentHash field");
|
|
506
540
|
} else if (actualHash !== v.contentHash) {
|
|
507
|
-
addError("
|
|
541
|
+
addError("ARTIFACT_HASH_MISMATCH", `Hash mismatch: expected ${v.contentHash}, got ${actualHash}`);
|
|
508
542
|
}
|
|
509
543
|
let schema;
|
|
510
544
|
switch (v.schema) {
|
|
@@ -529,16 +563,20 @@ async function verifyArtifactIntegrity(artifactOrPath) {
|
|
|
529
563
|
if (!validation.success) {
|
|
530
564
|
validation.error.issues.forEach((e) => {
|
|
531
565
|
const pathStr = e.path.join(".");
|
|
532
|
-
addError("
|
|
566
|
+
addError("ARTIFACT_SCHEMA_INVALID", `${pathStr}: ${e.message}`, pathStr);
|
|
533
567
|
});
|
|
534
568
|
}
|
|
535
569
|
} else {
|
|
536
|
-
addError("
|
|
570
|
+
addError("ARTIFACT_SCHEMA_INVALID", `Unsupported or unknown artifact schema: ${v.schema}`);
|
|
537
571
|
}
|
|
538
572
|
result.ok = result.issues.every((i) => i.severity !== "error" && i.severity !== "critical");
|
|
539
573
|
return result;
|
|
540
574
|
} catch (e) {
|
|
541
|
-
|
|
575
|
+
if (e instanceof SyntaxError) {
|
|
576
|
+
addError("ARTIFACT_JSON_INVALID", `Invalid JSON: ${e.message}`);
|
|
577
|
+
} else {
|
|
578
|
+
addError("ARTIFACT_ID_INVALID", `Unexpected verification error: ${e.message}`);
|
|
579
|
+
}
|
|
542
580
|
return result;
|
|
543
581
|
}
|
|
544
582
|
}
|
|
@@ -584,22 +622,10 @@ function verifyArtifactSemantics(artifact, context = {}) {
|
|
|
584
622
|
});
|
|
585
623
|
}
|
|
586
624
|
}
|
|
587
|
-
|
|
588
|
-
}
|
|
589
|
-
const lineageAudit = verifyLineage(v, context.parent);
|
|
625
|
+
const lineageAudit = verifyLineage(v, context.parent, { strict });
|
|
590
626
|
if (!lineageAudit.ok || strict && !v.lineage) {
|
|
591
|
-
if (!v.lineage && strict) {
|
|
592
|
-
addIssue({
|
|
593
|
-
code: "MISSING_LINEAGE",
|
|
594
|
-
severity: "error",
|
|
595
|
-
message: "Strict mode requires formal lineage metadata."
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
627
|
lineageAudit.issues.forEach((issue) => {
|
|
599
|
-
addIssue(
|
|
600
|
-
...issue,
|
|
601
|
-
severity: strict ? "error" : "warning"
|
|
602
|
-
});
|
|
628
|
+
addIssue(issue);
|
|
603
629
|
});
|
|
604
630
|
}
|
|
605
631
|
if (strict) {
|
|
@@ -626,31 +652,17 @@ function verifyArtifactSemantics(artifact, context = {}) {
|
|
|
626
652
|
});
|
|
627
653
|
}
|
|
628
654
|
}
|
|
629
|
-
const lineage = v.lineage;
|
|
630
|
-
if (lineage) {
|
|
631
|
-
const { artifactId, parentArtifactId, rootArtifactId } = lineage;
|
|
632
|
-
if (artifactId === parentArtifactId) {
|
|
633
|
-
addIssue({
|
|
634
|
-
code: "LINEAGE_INCONSISTENCY",
|
|
635
|
-
severity: "error",
|
|
636
|
-
message: "Artifact cannot be its own parent."
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
if (!parentArtifactId && artifactId !== rootArtifactId) {
|
|
640
|
-
addIssue({
|
|
641
|
-
code: "LINEAGE_INCONSISTENCY",
|
|
642
|
-
severity: "error",
|
|
643
|
-
message: "Root artifactId must match artifactId when no parent exists."
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
655
|
return result;
|
|
648
656
|
}
|
|
649
|
-
async function verifyArtifactReplay(artifact,
|
|
657
|
+
async function verifyArtifactReplay(artifact, _context = {}) {
|
|
650
658
|
return {
|
|
651
|
-
ok:
|
|
652
|
-
issues: [
|
|
653
|
-
|
|
659
|
+
ok: false,
|
|
660
|
+
issues: [{
|
|
661
|
+
code: "REPLAY_UNSUPPORTED_CHECK",
|
|
662
|
+
severity: "warning",
|
|
663
|
+
message: "Replay verification (full consensus simulation) is currently unsupported in this build."
|
|
664
|
+
}],
|
|
665
|
+
errors: ["Replay verification (consensus) unsupported"]
|
|
654
666
|
};
|
|
655
667
|
}
|
|
656
668
|
var verifyArtifact = verifyArtifactIntegrity;
|
|
@@ -874,16 +886,11 @@ function migrateToCanonical(v1Artifact) {
|
|
|
874
886
|
// src/io.ts
|
|
875
887
|
import fs2 from "fs/promises";
|
|
876
888
|
import path from "path";
|
|
889
|
+
import { writeFileAtomic } from "@hardkas/core";
|
|
877
890
|
var bigIntReplacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
|
|
878
891
|
async function writeArtifact(filePath, artifact) {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
await fs2.mkdir(dir, { recursive: true });
|
|
882
|
-
const content = typeof artifact === "string" ? artifact : JSON.stringify(artifact, bigIntReplacer, 2) + "\n";
|
|
883
|
-
await fs2.writeFile(filePath, content, "utf-8");
|
|
884
|
-
} catch (error) {
|
|
885
|
-
throw new Error(`Failed to write artifact at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
886
|
-
}
|
|
892
|
+
const content = typeof artifact === "string" ? artifact : JSON.stringify(artifact, bigIntReplacer, 2) + "\n";
|
|
893
|
+
await writeFileAtomic(filePath, content);
|
|
887
894
|
}
|
|
888
895
|
function getDefaultReceiptPath(txId, cwd = process.cwd()) {
|
|
889
896
|
return path.join(cwd, "artifacts", "receipts", `${txId}.json`);
|
|
@@ -1045,10 +1052,10 @@ function createTxPlanArtifact(options) {
|
|
|
1045
1052
|
schema: "hardkas.txPlan",
|
|
1046
1053
|
hardkasVersion: HARDKAS_VERSION,
|
|
1047
1054
|
version: ARTIFACT_VERSION,
|
|
1055
|
+
hashVersion: CURRENT_HASH_VERSION,
|
|
1048
1056
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1049
1057
|
networkId: options.networkId,
|
|
1050
1058
|
mode: options.mode,
|
|
1051
|
-
planId: `plan-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
1052
1059
|
from: {
|
|
1053
1060
|
address: options.from.address,
|
|
1054
1061
|
accountName: options.from.accountName,
|
|
@@ -1080,7 +1087,9 @@ function createTxPlanArtifact(options) {
|
|
|
1080
1087
|
amountSompi: options.plan.change.amountSompi.toString()
|
|
1081
1088
|
};
|
|
1082
1089
|
}
|
|
1083
|
-
|
|
1090
|
+
const hash = calculateContentHash(artifact, CURRENT_HASH_VERSION);
|
|
1091
|
+
artifact.planId = `plan-${hash.slice(0, 16)}`;
|
|
1092
|
+
artifact.contentHash = hash;
|
|
1084
1093
|
return artifact;
|
|
1085
1094
|
}
|
|
1086
1095
|
|
|
@@ -1090,22 +1099,24 @@ function createSimulatedSignedTxArtifact(plan, payload) {
|
|
|
1090
1099
|
schema: "hardkas.signedTx",
|
|
1091
1100
|
hardkasVersion: HARDKAS_VERSION,
|
|
1092
1101
|
version: ARTIFACT_VERSION,
|
|
1102
|
+
hashVersion: CURRENT_HASH_VERSION,
|
|
1093
1103
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1094
1104
|
status: "signed",
|
|
1095
|
-
signedId: `signed-${Date.now()}`,
|
|
1096
1105
|
sourcePlanId: plan.planId,
|
|
1097
1106
|
networkId: plan.networkId,
|
|
1098
1107
|
mode: plan.mode,
|
|
1099
1108
|
from: { address: plan.from.address },
|
|
1100
1109
|
to: { address: plan.to.address },
|
|
1101
1110
|
amountSompi: plan.amountSompi,
|
|
1102
|
-
txId: `simulated-${plan.planId}-${Date.now()}`,
|
|
1103
1111
|
signedTransaction: {
|
|
1104
1112
|
format: "simulated",
|
|
1105
1113
|
payload
|
|
1106
1114
|
}
|
|
1107
1115
|
};
|
|
1108
|
-
|
|
1116
|
+
const hash = calculateContentHash(artifact, CURRENT_HASH_VERSION);
|
|
1117
|
+
artifact.signedId = `signed-${hash.slice(0, 16)}`;
|
|
1118
|
+
artifact.txId = `simulated-${plan.planId}-${hash.slice(0, 8)}`;
|
|
1119
|
+
artifact.contentHash = hash;
|
|
1109
1120
|
return artifact;
|
|
1110
1121
|
}
|
|
1111
1122
|
function createSimulatedTxReceipt(plan, txId, extra) {
|
|
@@ -1113,6 +1124,7 @@ function createSimulatedTxReceipt(plan, txId, extra) {
|
|
|
1113
1124
|
schema: "hardkas.txReceipt",
|
|
1114
1125
|
hardkasVersion: HARDKAS_VERSION,
|
|
1115
1126
|
version: ARTIFACT_VERSION,
|
|
1127
|
+
hashVersion: CURRENT_HASH_VERSION,
|
|
1116
1128
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1117
1129
|
txId,
|
|
1118
1130
|
status: "accepted",
|
|
@@ -1125,9 +1137,13 @@ function createSimulatedTxReceipt(plan, txId, extra) {
|
|
|
1125
1137
|
changeSompi: plan.change?.amountSompi,
|
|
1126
1138
|
spentUtxoIds: extra?.spentUtxoIds,
|
|
1127
1139
|
createdUtxoIds: extra?.createdUtxoIds,
|
|
1128
|
-
daaScore: extra?.daaScore
|
|
1140
|
+
daaScore: extra?.daaScore,
|
|
1141
|
+
preStateHash: extra?.preStateHash,
|
|
1142
|
+
postStateHash: extra?.postStateHash,
|
|
1143
|
+
dagContext: extra?.dagContext
|
|
1129
1144
|
};
|
|
1130
|
-
|
|
1145
|
+
const hash = calculateContentHash(artifact, CURRENT_HASH_VERSION);
|
|
1146
|
+
artifact.contentHash = hash;
|
|
1131
1147
|
return artifact;
|
|
1132
1148
|
}
|
|
1133
1149
|
function getBroadcastableSignedTransaction(artifact) {
|
|
@@ -1351,6 +1367,162 @@ function validateTxHash(txHash) {
|
|
|
1351
1367
|
throw new Error(`Invalid EVM txHash: must be a 0x-prefixed 64-character hex string. Got: ${txHash}`);
|
|
1352
1368
|
}
|
|
1353
1369
|
}
|
|
1370
|
+
|
|
1371
|
+
// src/diff.ts
|
|
1372
|
+
import { maskSecrets } from "@hardkas/core";
|
|
1373
|
+
function diffArtifacts(left, right) {
|
|
1374
|
+
const entries = [];
|
|
1375
|
+
const leftRedacted = maskSecrets(left);
|
|
1376
|
+
const rightRedacted = maskSecrets(right);
|
|
1377
|
+
compareRecursive(leftRedacted, rightRedacted, "$", entries);
|
|
1378
|
+
return {
|
|
1379
|
+
identical: entries.length === 0,
|
|
1380
|
+
entries
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
function compareRecursive(left, right, path4, entries) {
|
|
1384
|
+
if (isPrimitive(left) || isPrimitive(right)) {
|
|
1385
|
+
if (left !== right) {
|
|
1386
|
+
entries.push({ path: path4, kind: "changed", left, right });
|
|
1387
|
+
}
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
1391
|
+
if (!Array.isArray(left) || !Array.isArray(right)) {
|
|
1392
|
+
entries.push({ path: path4, kind: "changed", left, right });
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
const maxLength = Math.max(left.length, right.length);
|
|
1396
|
+
for (let i = 0; i < maxLength; i++) {
|
|
1397
|
+
if (i >= left.length) {
|
|
1398
|
+
entries.push({ path: `${path4}[${i}]`, kind: "added", right: right[i] });
|
|
1399
|
+
} else if (i >= right.length) {
|
|
1400
|
+
entries.push({ path: `${path4}[${i}]`, kind: "removed", left: left[i] });
|
|
1401
|
+
} else {
|
|
1402
|
+
compareRecursive(left[i], right[i], `${path4}[${i}]`, entries);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
const leftKeys = Object.keys(left).filter((k) => !SEMANTIC_EXCLUSIONS.has(k));
|
|
1408
|
+
const rightKeys = Object.keys(right).filter((k) => !SEMANTIC_EXCLUSIONS.has(k));
|
|
1409
|
+
const allKeys = /* @__PURE__ */ new Set([...leftKeys, ...rightKeys]);
|
|
1410
|
+
for (const key of allKeys) {
|
|
1411
|
+
const nextPath = path4 === "$" ? key : `${path4}.${key}`;
|
|
1412
|
+
if (!leftKeys.includes(key)) {
|
|
1413
|
+
entries.push({ path: nextPath, kind: "added", right: right[key] });
|
|
1414
|
+
} else if (!rightKeys.includes(key)) {
|
|
1415
|
+
entries.push({ path: nextPath, kind: "removed", left: left[key] });
|
|
1416
|
+
} else {
|
|
1417
|
+
compareRecursive(left[key], right[key], nextPath, entries);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
function isPrimitive(val) {
|
|
1422
|
+
if (val === null) return true;
|
|
1423
|
+
return typeof val !== "object" && typeof val !== "function";
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// src/deployment.ts
|
|
1427
|
+
function createDeploymentRecord(opts) {
|
|
1428
|
+
const record = {
|
|
1429
|
+
schema: "hardkas.deployment.v1",
|
|
1430
|
+
label: opts.label,
|
|
1431
|
+
networkId: opts.networkId,
|
|
1432
|
+
status: opts.status || "planned",
|
|
1433
|
+
deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1434
|
+
hardkasVersion: HARDKAS_VERSION,
|
|
1435
|
+
version: ARTIFACT_VERSION,
|
|
1436
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1437
|
+
mode: "real"
|
|
1438
|
+
};
|
|
1439
|
+
if (opts.txId) record.txId = opts.txId;
|
|
1440
|
+
if (opts.planArtifactId) record.planArtifactId = opts.planArtifactId;
|
|
1441
|
+
if (opts.receiptArtifactId) record.receiptArtifactId = opts.receiptArtifactId;
|
|
1442
|
+
if (opts.deployedAddresses) record.deployedAddresses = opts.deployedAddresses;
|
|
1443
|
+
if (opts.deployer) record.deployer = opts.deployer;
|
|
1444
|
+
if (opts.payloadHash) record.payloadHash = opts.payloadHash;
|
|
1445
|
+
if (opts.notes) record.notes = opts.notes;
|
|
1446
|
+
record.contentHash = calculateContentHash(record, CURRENT_HASH_VERSION);
|
|
1447
|
+
return record;
|
|
1448
|
+
}
|
|
1449
|
+
function updateDeploymentStatus(record, newStatus, txId) {
|
|
1450
|
+
const updated = {
|
|
1451
|
+
...record,
|
|
1452
|
+
status: newStatus,
|
|
1453
|
+
deployedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1454
|
+
};
|
|
1455
|
+
if (txId) updated.txId = txId;
|
|
1456
|
+
delete updated.contentHash;
|
|
1457
|
+
updated.contentHash = calculateContentHash(updated, CURRENT_HASH_VERSION);
|
|
1458
|
+
return updated;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
// src/deployment-store.ts
|
|
1462
|
+
import fs4 from "fs/promises";
|
|
1463
|
+
import { existsSync } from "fs";
|
|
1464
|
+
import path3 from "path";
|
|
1465
|
+
import { writeFileAtomic as writeFileAtomic2 } from "@hardkas/core";
|
|
1466
|
+
async function saveDeployment(rootDir, record) {
|
|
1467
|
+
const deploymentsDir = path3.join(rootDir, ".hardkas", "deployments", record.networkId);
|
|
1468
|
+
const targetPath = path3.join(deploymentsDir, `${record.label}.json`);
|
|
1469
|
+
await writeFileAtomic2(targetPath, JSON.stringify(record, null, 2));
|
|
1470
|
+
return targetPath;
|
|
1471
|
+
}
|
|
1472
|
+
async function loadDeployment(rootDir, networkId, label) {
|
|
1473
|
+
const targetPath = path3.join(rootDir, ".hardkas", "deployments", networkId, `${label}.json`);
|
|
1474
|
+
if (!existsSync(targetPath)) return null;
|
|
1475
|
+
const content = await fs4.readFile(targetPath, "utf-8");
|
|
1476
|
+
return JSON.parse(content);
|
|
1477
|
+
}
|
|
1478
|
+
async function listDeployments(rootDir, networkId) {
|
|
1479
|
+
const baseDir = path3.join(rootDir, ".hardkas", "deployments");
|
|
1480
|
+
if (!existsSync(baseDir)) return [];
|
|
1481
|
+
const summaries = [];
|
|
1482
|
+
const networks = networkId ? [networkId] : await fs4.readdir(baseDir);
|
|
1483
|
+
for (const net of networks) {
|
|
1484
|
+
const netDir = path3.join(baseDir, net);
|
|
1485
|
+
if (!existsSync(netDir)) continue;
|
|
1486
|
+
const files = await fs4.readdir(netDir);
|
|
1487
|
+
for (const file of files) {
|
|
1488
|
+
if (!file.endsWith(".json")) continue;
|
|
1489
|
+
try {
|
|
1490
|
+
const content = await fs4.readFile(path3.join(netDir, file), "utf-8");
|
|
1491
|
+
const record = JSON.parse(content);
|
|
1492
|
+
const summary = {
|
|
1493
|
+
label: record.label,
|
|
1494
|
+
networkId: record.networkId,
|
|
1495
|
+
status: record.status,
|
|
1496
|
+
deployedAt: record.deployedAt,
|
|
1497
|
+
contentHash: record.contentHash || ""
|
|
1498
|
+
};
|
|
1499
|
+
if (record.txId) summary.txId = record.txId;
|
|
1500
|
+
summaries.push(summary);
|
|
1501
|
+
} catch (e) {
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
return summaries.sort((a, b) => new Date(b.deployedAt).getTime() - new Date(a.deployedAt).getTime());
|
|
1506
|
+
}
|
|
1507
|
+
async function updateDeployment(rootDir, networkId, label, update) {
|
|
1508
|
+
const existing = await loadDeployment(rootDir, networkId, label);
|
|
1509
|
+
if (!existing) {
|
|
1510
|
+
throw new Error(`Deployment '${label}' not found on network '${networkId}'.`);
|
|
1511
|
+
}
|
|
1512
|
+
const updated = {
|
|
1513
|
+
...existing,
|
|
1514
|
+
...update,
|
|
1515
|
+
deployedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1516
|
+
};
|
|
1517
|
+
await saveDeployment(rootDir, updated);
|
|
1518
|
+
return updated;
|
|
1519
|
+
}
|
|
1520
|
+
async function deleteDeployment(rootDir, networkId, label) {
|
|
1521
|
+
const targetPath = path3.join(rootDir, ".hardkas", "deployments", networkId, `${label}.json`);
|
|
1522
|
+
if (!existsSync(targetPath)) return false;
|
|
1523
|
+
await fs4.unlink(targetPath);
|
|
1524
|
+
return true;
|
|
1525
|
+
}
|
|
1354
1526
|
export {
|
|
1355
1527
|
ARTIFACT_SCHEMAS,
|
|
1356
1528
|
ARTIFACT_VERSION,
|
|
@@ -1359,6 +1531,7 @@ export {
|
|
|
1359
1531
|
BaseArtifactSchema,
|
|
1360
1532
|
BasicCorrelationInvariant,
|
|
1361
1533
|
BasicLineageInvariant,
|
|
1534
|
+
CURRENT_HASH_VERSION,
|
|
1362
1535
|
DagContextSchema,
|
|
1363
1536
|
HARDKAS_VERSION,
|
|
1364
1537
|
HashInvariant,
|
|
@@ -1367,6 +1540,7 @@ export {
|
|
|
1367
1540
|
LocalnetUtxoSchemaV2,
|
|
1368
1541
|
NetworkInvariant,
|
|
1369
1542
|
ReplayInvariant,
|
|
1543
|
+
SEMANTIC_EXCLUSIONS,
|
|
1370
1544
|
SchemaInvariant,
|
|
1371
1545
|
SignedTxSchema,
|
|
1372
1546
|
SnapshotSchema,
|
|
@@ -1386,6 +1560,7 @@ export {
|
|
|
1386
1560
|
bigIntReplacer,
|
|
1387
1561
|
calculateContentHash,
|
|
1388
1562
|
canonicalStringify,
|
|
1563
|
+
createDeploymentRecord,
|
|
1389
1564
|
createIgraDeployPlanId,
|
|
1390
1565
|
createIgraPlanId,
|
|
1391
1566
|
createIgraSignedId,
|
|
@@ -1393,6 +1568,8 @@ export {
|
|
|
1393
1568
|
createSimulatedTxReceipt,
|
|
1394
1569
|
createTxPlanArtifact,
|
|
1395
1570
|
defaultClock,
|
|
1571
|
+
deleteDeployment,
|
|
1572
|
+
diffArtifacts,
|
|
1396
1573
|
explainArtifact,
|
|
1397
1574
|
formatSignedTxArtifact,
|
|
1398
1575
|
formatTxPlanArtifact,
|
|
@@ -1402,7 +1579,9 @@ export {
|
|
|
1402
1579
|
getDefaultReceiptPath,
|
|
1403
1580
|
getL2ReceiptPath,
|
|
1404
1581
|
isIgraTxPlanArtifact,
|
|
1582
|
+
listDeployments,
|
|
1405
1583
|
listIgraTxReceiptArtifacts,
|
|
1584
|
+
loadDeployment,
|
|
1406
1585
|
loadIgraTxReceiptArtifact,
|
|
1407
1586
|
migrateToCanonical,
|
|
1408
1587
|
readArtifact,
|
|
@@ -1410,10 +1589,13 @@ export {
|
|
|
1410
1589
|
readTxPlanArtifact,
|
|
1411
1590
|
readTxReceiptArtifact,
|
|
1412
1591
|
recomputeMass,
|
|
1592
|
+
saveDeployment,
|
|
1413
1593
|
saveIgraTxReceiptArtifact,
|
|
1414
1594
|
sortUtxosByOutpoint,
|
|
1415
1595
|
txOutputFromArtifact,
|
|
1416
1596
|
txOutputToArtifact,
|
|
1597
|
+
updateDeployment,
|
|
1598
|
+
updateDeploymentStatus,
|
|
1417
1599
|
utxoFromArtifact,
|
|
1418
1600
|
utxoToArtifact,
|
|
1419
1601
|
validateArtifact,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardkas/artifacts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-alpha",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Javier Rodriguez",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"zod": "^3.24.1",
|
|
27
|
-
"@hardkas/core": "0.
|
|
28
|
-
"@hardkas/tx-builder": "0.
|
|
27
|
+
"@hardkas/core": "0.3.0-alpha",
|
|
28
|
+
"@hardkas/tx-builder": "0.3.0-alpha"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"tsup": "^8.3.5",
|