@hardkas/l2 0.2.2-alpha.1 → 0.4.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 CHANGED
@@ -10,9 +10,26 @@ interface L2SecurityAssumptions {
10
10
  readonly riskProfile: L2RiskProfile;
11
11
  readonly notes: readonly string[];
12
12
  }
13
+ type L2ProfileSource = "built-in" | "user-config";
14
+ interface L2UserNetworkConfig {
15
+ readonly kind?: "igra" | string;
16
+ readonly chainId: number;
17
+ readonly rpcUrl: string;
18
+ readonly explorerUrl?: string;
19
+ readonly bridgePhase?: L2BridgePhase;
20
+ readonly trustlessExit?: boolean;
21
+ readonly nativeCurrency?: {
22
+ readonly name?: string;
23
+ readonly symbol?: string;
24
+ readonly decimals?: number;
25
+ };
26
+ readonly contracts?: Record<string, string>;
27
+ readonly metadata?: Record<string, unknown>;
28
+ }
13
29
  interface L2NetworkProfile {
14
30
  readonly schema: "hardkas.l2Profile.v1";
15
31
  readonly hardkasVersion: string;
32
+ readonly source: L2ProfileSource;
16
33
  readonly name: string;
17
34
  readonly displayName: string;
18
35
  readonly type: L2NetworkType;
@@ -27,9 +44,38 @@ interface L2NetworkProfile {
27
44
  }
28
45
  declare const BUILTIN_L2_PROFILES: readonly L2NetworkProfile[];
29
46
 
30
- declare function getBuiltInL2Profiles(): readonly L2NetworkProfile[];
31
- declare function listL2Profiles(): readonly L2NetworkProfile[];
32
- declare function getL2Profile(name: string): L2NetworkProfile | null;
47
+ interface MetaMaskChainParams {
48
+ chainId: string;
49
+ chainName: string;
50
+ nativeCurrency: {
51
+ name: string;
52
+ symbol: string;
53
+ decimals: number;
54
+ };
55
+ rpcUrls: string[];
56
+ blockExplorerUrls?: string[] | undefined;
57
+ }
58
+ /**
59
+ * Generates the standard wallet_addEthereumChain payload for MetaMask.
60
+ */
61
+ declare function generateAddEthereumChainPayload(profile: L2NetworkProfile): MetaMaskChainParams;
62
+ /**
63
+ * Generates a JavaScript snippet for browser consoles to add the network to MetaMask.
64
+ */
65
+ declare function generateMetaMaskSnippet(profile: L2NetworkProfile): string;
66
+
67
+ declare function listL2Profiles(userProfiles?: Record<string, L2UserNetworkConfig>): L2NetworkProfile[];
68
+ declare function getL2Profile(name: string, userProfiles?: Record<string, L2UserNetworkConfig>): L2NetworkProfile | null;
69
+ declare function resolveL2Profile(args: {
70
+ name?: string | undefined;
71
+ userProfiles?: Record<string, L2UserNetworkConfig> | undefined;
72
+ cliOverrides?: {
73
+ url?: string | undefined;
74
+ rpcUrl?: string | undefined;
75
+ chainId?: number | string | undefined;
76
+ [key: string]: unknown;
77
+ } | undefined;
78
+ }): L2NetworkProfile;
33
79
  declare function validateL2Profile(profile: any): {
34
80
  ok: boolean;
35
81
  errors: string[];
@@ -174,4 +220,4 @@ declare function assertValidL2BridgeAssumptions(input: unknown): L2BridgeAssumpt
174
220
  */
175
221
  declare function encodeConstructorArgs(bytecode: string, constructorSignature: string, args: string[]): string;
176
222
 
177
- export { BUILTIN_L2_PROFILES, type EvmCallRequest, EvmJsonRpcClient, type EvmJsonRpcClientOptions, type EvmRpcHealthResult, type EvmTransactionReceiptSummary, type IgraTxSigner, type IgraTxSigningInput, type IgraTxSigningResult, type L2BridgeAssumptions, type L2BridgePhase, type L2NetworkProfile, type L2NetworkType, type L2RiskProfile, type L2SecurityAssumptions, UnsupportedIgraTxSigner, ViemIgraTxSigner, type ViemIgraTxSignerOptions, assertValidL2BridgeAssumptions, assertValidL2Profile, checkEvmRpcHealth, encodeConstructorArgs, formatWeiAsEtherLike, getBuiltInL2Profiles, getL2BridgeAssumptions, getL2Profile, listL2BridgeAssumptions, listL2Profiles, normalizeEvmTransactionReceipt, toHexQuantity, validateL2BridgeAssumptions, validateL2Profile, waitForEvmRpcReady };
223
+ export { BUILTIN_L2_PROFILES, type EvmCallRequest, EvmJsonRpcClient, type EvmJsonRpcClientOptions, type EvmRpcHealthResult, type EvmTransactionReceiptSummary, type IgraTxSigner, type IgraTxSigningInput, type IgraTxSigningResult, type L2BridgeAssumptions, type L2BridgePhase, type L2NetworkProfile, type L2NetworkType, type L2ProfileSource, type L2RiskProfile, type L2SecurityAssumptions, type L2UserNetworkConfig, type MetaMaskChainParams, UnsupportedIgraTxSigner, ViemIgraTxSigner, type ViemIgraTxSignerOptions, assertValidL2BridgeAssumptions, assertValidL2Profile, checkEvmRpcHealth, encodeConstructorArgs, formatWeiAsEtherLike, generateAddEthereumChainPayload, generateMetaMaskSnippet, getL2BridgeAssumptions, resolveL2Profile as getL2NetworkProfile, getL2Profile, listL2BridgeAssumptions, listL2Profiles, normalizeEvmTransactionReceipt, resolveL2Profile, toHexQuantity, validateL2BridgeAssumptions, validateL2Profile, waitForEvmRpcReady };
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ var BUILTIN_L2_PROFILES = [
4
4
  {
5
5
  schema: "hardkas.l2Profile.v1",
6
6
  hardkasVersion: HARDKAS_VERSION,
7
+ source: "built-in",
7
8
  name: "igra",
8
9
  displayName: "Igra",
9
10
  type: "evm-based-rollup",
@@ -11,6 +12,8 @@ var BUILTIN_L2_PROFILES = [
11
12
  executionLayer: "evm",
12
13
  gasToken: "iKAS",
13
14
  nativeTokenDecimals: 18,
15
+ chainId: 19416,
16
+ rpcUrl: "http://127.0.0.1:8545",
14
17
  security: {
15
18
  bridgePhase: "pre-zk",
16
19
  trustlessExit: false,
@@ -27,15 +30,106 @@ var BUILTIN_L2_PROFILES = [
27
30
  }
28
31
  ];
29
32
 
33
+ // src/metamask.ts
34
+ function generateAddEthereumChainPayload(profile) {
35
+ if (!profile.chainId) {
36
+ throw new Error(`Profile "${profile.name}" is missing chainId`);
37
+ }
38
+ if (!profile.rpcUrl) {
39
+ throw new Error(`Profile "${profile.name}" is missing rpcUrl`);
40
+ }
41
+ return {
42
+ chainId: `0x${profile.chainId.toString(16)}`,
43
+ chainName: profile.displayName || profile.name,
44
+ nativeCurrency: {
45
+ name: profile.gasToken || "iKAS",
46
+ symbol: profile.gasToken || "iKAS",
47
+ decimals: profile.nativeTokenDecimals || 18
48
+ },
49
+ rpcUrls: [profile.rpcUrl],
50
+ blockExplorerUrls: profile.explorerUrl ? [profile.explorerUrl] : void 0
51
+ };
52
+ }
53
+ function generateMetaMaskSnippet(profile) {
54
+ const payload = generateAddEthereumChainPayload(profile);
55
+ return `await window.ethereum.request({
56
+ method: "wallet_addEthereumChain",
57
+ params: [
58
+ ${JSON.stringify(payload, null, 4).replace(/\n/g, "\n ")}
59
+ ]
60
+ });`;
61
+ }
62
+
30
63
  // src/registry.ts
31
- function getBuiltInL2Profiles() {
32
- return BUILTIN_L2_PROFILES;
64
+ import { HARDKAS_VERSION as HARDKAS_VERSION2 } from "@hardkas/artifacts";
65
+ function listL2Profiles(userProfiles) {
66
+ const profiles = [...BUILTIN_L2_PROFILES];
67
+ if (userProfiles) {
68
+ for (const [name, config] of Object.entries(userProfiles)) {
69
+ const existingIndex = profiles.findIndex((p) => p.name === name);
70
+ const profile = mapUserConfigToProfile(name, config);
71
+ if (existingIndex !== -1) {
72
+ profiles[existingIndex] = profile;
73
+ } else {
74
+ profiles.push(profile);
75
+ }
76
+ }
77
+ }
78
+ return profiles;
79
+ }
80
+ function getL2Profile(name, userProfiles) {
81
+ return listL2Profiles(userProfiles).find((p) => p.name === name) || null;
33
82
  }
34
- function listL2Profiles() {
35
- return BUILTIN_L2_PROFILES;
83
+ function resolveL2Profile(args) {
84
+ const name = args.name || "igra";
85
+ const profile = getL2Profile(name, args.userProfiles);
86
+ if (!profile) {
87
+ const available = listL2Profiles(args.userProfiles).map((p) => `${p.name} (${p.source})`).join(", ");
88
+ throw new Error(`L2 profile '${name}' not found. Available profiles: ${available}`);
89
+ }
90
+ let rpcUrl = args.cliOverrides?.rpcUrl || args.cliOverrides?.url || profile.rpcUrl;
91
+ if (args.cliOverrides?.rpcUrl && args.cliOverrides?.url && args.cliOverrides.rpcUrl !== args.cliOverrides.url) {
92
+ throw new Error("Conflict: Both --rpc-url and --url provided with different values.");
93
+ }
94
+ let chainId = profile.chainId;
95
+ if (args.cliOverrides?.chainId !== void 0) {
96
+ chainId = typeof args.cliOverrides.chainId === "string" ? parseInt(args.cliOverrides.chainId, 10) : args.cliOverrides.chainId;
97
+ if (isNaN(chainId)) {
98
+ throw new Error(`Invalid chainId: ${args.cliOverrides.chainId}`);
99
+ }
100
+ }
101
+ const resolved = {
102
+ ...profile,
103
+ ...rpcUrl ? { rpcUrl } : {},
104
+ ...chainId !== void 0 ? { chainId } : {}
105
+ };
106
+ return assertValidL2Profile(resolved);
36
107
  }
37
- function getL2Profile(name) {
38
- return listL2Profiles().find((p) => p.name === name) || null;
108
+ function mapUserConfigToProfile(name, config) {
109
+ const bridgePhase = config.bridgePhase || "pre-zk";
110
+ const trustlessExit = config.trustlessExit ?? false;
111
+ return {
112
+ schema: "hardkas.l2Profile.v1",
113
+ hardkasVersion: HARDKAS_VERSION2,
114
+ source: "user-config",
115
+ name,
116
+ displayName: name,
117
+ type: "evm-based-rollup",
118
+ settlementLayer: "kaspa",
119
+ executionLayer: "evm",
120
+ gasToken: config.nativeCurrency?.symbol || (config.kind === "igra" || !config.kind ? "iKAS" : "ETH"),
121
+ nativeTokenDecimals: config.nativeCurrency?.decimals || 18,
122
+ chainId: config.chainId,
123
+ rpcUrl: config.rpcUrl,
124
+ ...config.explorerUrl ? { explorerUrl: config.explorerUrl } : {},
125
+ security: {
126
+ bridgePhase,
127
+ trustlessExit,
128
+ custodyModel: "User-defined bridge custody.",
129
+ riskProfile: "unknown",
130
+ notes: ["User-defined network from config"]
131
+ }
132
+ };
39
133
  }
40
134
  function validateL2Profile(profile) {
41
135
  const errors = [];
@@ -45,36 +139,10 @@ function validateL2Profile(profile) {
45
139
  if (profile.schema !== "hardkas.l2Profile.v1") {
46
140
  errors.push(`Invalid schema: expected 'hardkas.l2Profile.v1', got '${profile.schema}'`);
47
141
  }
48
- if (typeof profile.hardkasVersion !== "string") {
49
- errors.push("Missing or invalid hardkasVersion");
50
- }
51
- if (!profile.name || typeof profile.name !== "string") {
52
- errors.push("Missing or invalid name");
53
- }
54
- if (profile.type !== "evm-based-rollup") {
55
- errors.push(`Invalid type: expected 'evm-based-rollup', got '${profile.type}'`);
56
- }
57
- if (profile.settlementLayer !== "kaspa") {
58
- errors.push(`Invalid settlementLayer: expected 'kaspa', got '${profile.settlementLayer}'`);
59
- }
60
- if (profile.executionLayer !== "evm") {
61
- errors.push(`Invalid executionLayer: expected 'evm', got '${profile.executionLayer}'`);
62
- }
63
- if (!profile.gasToken || typeof profile.gasToken !== "string") {
64
- errors.push("Missing or invalid gasToken");
65
- }
66
142
  if (profile.security) {
67
- if (profile.security.bridgePhase === "zk") {
68
- } else {
69
- if (profile.security.trustlessExit === true) {
70
- errors.push("Security invariant violation: trustlessExit must be false when bridgePhase is not 'zk'");
71
- }
143
+ if (profile.security.bridgePhase !== "zk" && profile.security.trustlessExit === true) {
144
+ errors.push(`Security invariant violation: trustlessExit=true is only allowed when bridgePhase='zk'. Current phase: ${profile.security.bridgePhase}`);
72
145
  }
73
- if (!Array.isArray(profile.security.notes) || profile.security.notes.length === 0) {
74
- errors.push("Security notes must not be empty");
75
- }
76
- } else {
77
- errors.push("Missing security assumptions");
78
146
  }
79
147
  return {
80
148
  ok: errors.length === 0,
@@ -370,10 +438,10 @@ function normalizeEvmTransactionReceipt(raw) {
370
438
  }
371
439
 
372
440
  // src/bridge.ts
373
- import { HARDKAS_VERSION as HARDKAS_VERSION2 } from "@hardkas/artifacts";
441
+ import { HARDKAS_VERSION as HARDKAS_VERSION3 } from "@hardkas/artifacts";
374
442
  var IGRA_BRIDGE_ASSUMPTIONS = {
375
443
  schema: "hardkas.l2BridgeAssumptions.v1",
376
- hardkasVersion: HARDKAS_VERSION2,
444
+ hardkasVersion: HARDKAS_VERSION3,
377
445
  l2Network: "igra",
378
446
  bridgePhase: "pre-zk",
379
447
  trustlessExit: false,
@@ -457,12 +525,15 @@ export {
457
525
  checkEvmRpcHealth,
458
526
  encodeConstructorArgs,
459
527
  formatWeiAsEtherLike,
460
- getBuiltInL2Profiles,
528
+ generateAddEthereumChainPayload,
529
+ generateMetaMaskSnippet,
461
530
  getL2BridgeAssumptions,
531
+ resolveL2Profile as getL2NetworkProfile,
462
532
  getL2Profile,
463
533
  listL2BridgeAssumptions,
464
534
  listL2Profiles,
465
535
  normalizeEvmTransactionReceipt,
536
+ resolveL2Profile,
466
537
  toHexQuantity,
467
538
  validateL2BridgeAssumptions,
468
539
  validateL2Profile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/l2",
3
- "version": "0.2.2-alpha.1",
3
+ "version": "0.4.0-alpha",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/index.js"
@@ -8,7 +8,7 @@
8
8
  "types": "./dist/index.d.ts",
9
9
  "dependencies": {
10
10
  "viem": "^2.48.8",
11
- "@hardkas/artifacts": "0.2.2-alpha.1"
11
+ "@hardkas/artifacts": "0.4.0-alpha"
12
12
  },
13
13
  "devDependencies": {
14
14
  "tsup": "^8.3.5",