@hardkas/accounts 0.9.4-alpha → 0.9.7-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 +4 -1
- package/dist/index.js +116 -2
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -385,6 +385,9 @@ declare class KeystoreManager {
|
|
|
385
385
|
static saveEncryptedKeystore(filePath: string, keystore: EncryptedKeystoreV2): Promise<void>;
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
declare function withKeystoreLock<T>(filePath: string, operation: () => Promise<T>): Promise<T>;
|
|
389
|
+
declare function appendToKeystoreJson(workspaceRoot: string, alias: string, accountData: any): Promise<void>;
|
|
390
|
+
|
|
388
391
|
declare const DEV_ACCOUNTS_PASSWORD = "hardkas-local-dev";
|
|
389
392
|
declare function ensureDevAccounts(workspaceDir: string): Promise<void>;
|
|
390
393
|
declare function getOrCreateDevAccount(workspaceDir: string, index: number, alias: string): Promise<GeneratedKaspaDevAccount>;
|
|
@@ -393,4 +396,4 @@ declare function listDevAccountsSync(workspaceDir: string): {
|
|
|
393
396
|
address: string;
|
|
394
397
|
}[];
|
|
395
398
|
|
|
396
|
-
export { type CreateKaspaWalletOptions, DEV_ACCOUNTS_PASSWORD, type EncryptedKeystoreV2, type EvmExportResult, type GeneratedKaspaDevAccount, type HardkasAccount, type HardkasAccountKind, type HardkasBaseAccount, type HardkasEvmPrivateKeyAccount, type HardkasExternalWalletAccount, HardkasFixtureSigner, type HardkasKaspaPrivateKeyAccount, type HardkasSigner, type HardkasSignerKind, type HardkasSimulatedAccount, type HardkasTxPlanSigner, type KaspaKeyGenerator, KaspaSdkKeyGenerator, type KaspaSdkKeyGeneratorOptions, KaspaSdkRealTxSigner, type KaspaSdkRealTxSignerOptions, type KaspaSigningBackendStatus, KaspaWasmPrivateKeySigner, type KeystoreCipherParams, type KeystoreKdfParams, KeystoreManager, type KeystorePayload, type KeystoreUnlockResult, type RealAccountStore, type RealDevAccount, type RealTxSigner, type RealTxSigningInput, type RealTxSigningResult, type ResolveAccountOptions, type SignTxPlanInput, type SignTxPlanResult, SimulatedSigner, SimulatedTxPlanSigner, UnsupportedKaspaKeyGenerator, UnsupportedRealKaspaSigner, UnsupportedRealTxSigner, assertSigningNetworkAllowed, createEmptyRealAccountStore, createLocalKaspaWallet, describeAccount, ensureDevAccounts, getDefaultRealAccountsPath, getKaspaSigningBackendStatus, getOrCreateDevAccount, getRealDevAccount, getRequiredEnv, importRealDevAccount, listDevAccountsSync, listHardkasAccounts, listRealDevAccounts, loadKaspaWasm, loadOrCreateRealAccountStore, loadRealAccountStore, loadRealAccountStoreSync, prepareEvmAccountExport, removeRealDevAccount, resolveHardkasAccount, resolveHardkasAccountAddress, resolveRealAccountOrAddress, saveRealAccountStore, signTxPlanArtifact, validateAccountName, validateAddressNetwork, validateAddressPrefix };
|
|
399
|
+
export { type CreateKaspaWalletOptions, DEV_ACCOUNTS_PASSWORD, type EncryptedKeystoreV2, type EvmExportResult, type GeneratedKaspaDevAccount, type HardkasAccount, type HardkasAccountKind, type HardkasBaseAccount, type HardkasEvmPrivateKeyAccount, type HardkasExternalWalletAccount, HardkasFixtureSigner, type HardkasKaspaPrivateKeyAccount, type HardkasSigner, type HardkasSignerKind, type HardkasSimulatedAccount, type HardkasTxPlanSigner, type KaspaKeyGenerator, KaspaSdkKeyGenerator, type KaspaSdkKeyGeneratorOptions, KaspaSdkRealTxSigner, type KaspaSdkRealTxSignerOptions, type KaspaSigningBackendStatus, KaspaWasmPrivateKeySigner, type KeystoreCipherParams, type KeystoreKdfParams, KeystoreManager, type KeystorePayload, type KeystoreUnlockResult, type RealAccountStore, type RealDevAccount, type RealTxSigner, type RealTxSigningInput, type RealTxSigningResult, type ResolveAccountOptions, type SignTxPlanInput, type SignTxPlanResult, SimulatedSigner, SimulatedTxPlanSigner, UnsupportedKaspaKeyGenerator, UnsupportedRealKaspaSigner, UnsupportedRealTxSigner, appendToKeystoreJson, assertSigningNetworkAllowed, createEmptyRealAccountStore, createLocalKaspaWallet, describeAccount, ensureDevAccounts, getDefaultRealAccountsPath, getKaspaSigningBackendStatus, getOrCreateDevAccount, getRealDevAccount, getRequiredEnv, importRealDevAccount, listDevAccountsSync, listHardkasAccounts, listRealDevAccounts, loadKaspaWasm, loadOrCreateRealAccountStore, loadRealAccountStore, loadRealAccountStoreSync, prepareEvmAccountExport, removeRealDevAccount, resolveHardkasAccount, resolveHardkasAccountAddress, resolveRealAccountOrAddress, saveRealAccountStore, signTxPlanArtifact, validateAccountName, validateAddressNetwork, validateAddressPrefix, withKeystoreLock };
|
package/dist/index.js
CHANGED
|
@@ -240,6 +240,21 @@ function resolveHardkasAccount(options) {
|
|
|
240
240
|
} catch (e) {
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
|
+
const keystoreJsonPath = path2.join(workspaceRoot, ".hardkas", "keystore.json");
|
|
244
|
+
if (fs2.existsSync(keystoreJsonPath)) {
|
|
245
|
+
try {
|
|
246
|
+
const data = fs2.readFileSync(keystoreJsonPath, "utf-8");
|
|
247
|
+
const ks = JSON.parse(data);
|
|
248
|
+
if (ks[alias]) {
|
|
249
|
+
return {
|
|
250
|
+
name: alias,
|
|
251
|
+
kind: ks[alias].type === "simulated" ? "simulated" : "kaspa-private-key",
|
|
252
|
+
address: ks[alias].address
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
} catch (e) {
|
|
256
|
+
}
|
|
257
|
+
}
|
|
243
258
|
if (config?.accounts && config.accounts[alias]) {
|
|
244
259
|
const accConfig = config.accounts[alias];
|
|
245
260
|
return {
|
|
@@ -308,6 +323,29 @@ function listHardkasAccounts(config) {
|
|
|
308
323
|
}
|
|
309
324
|
}
|
|
310
325
|
}
|
|
326
|
+
const keystoreJsonPath = path2.join(workspaceRoot, ".hardkas", "keystore.json");
|
|
327
|
+
if (fs2.existsSync(keystoreJsonPath)) {
|
|
328
|
+
try {
|
|
329
|
+
const data = fs2.readFileSync(keystoreJsonPath, "utf-8");
|
|
330
|
+
const ks = JSON.parse(data);
|
|
331
|
+
for (const [name, acc] of Object.entries(ks)) {
|
|
332
|
+
if (acc.type === "simulated") {
|
|
333
|
+
accounts.set(name, {
|
|
334
|
+
name,
|
|
335
|
+
kind: "simulated",
|
|
336
|
+
address: acc.address
|
|
337
|
+
});
|
|
338
|
+
} else {
|
|
339
|
+
accounts.set(name, {
|
|
340
|
+
name,
|
|
341
|
+
kind: "kaspa-private-key",
|
|
342
|
+
address: acc.address
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} catch (e) {
|
|
347
|
+
}
|
|
348
|
+
}
|
|
311
349
|
const realStore = loadRealAccountStoreSync({ cwd: workspaceRoot });
|
|
312
350
|
if (realStore) {
|
|
313
351
|
for (const realAcc of listRealDevAccounts(realStore)) {
|
|
@@ -346,6 +384,10 @@ function listHardkasAccounts(config) {
|
|
|
346
384
|
}
|
|
347
385
|
if (config?.accounts) {
|
|
348
386
|
for (const [name, accConfig] of Object.entries(config.accounts)) {
|
|
387
|
+
const existing = accounts.get(name);
|
|
388
|
+
if (existing && existing.kind === "kaspa-private-key" && accConfig.kind === "simulated") {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
349
391
|
accounts.set(name, {
|
|
350
392
|
name,
|
|
351
393
|
...accConfig
|
|
@@ -747,7 +789,7 @@ async function getOrCreateDevAccount(workspaceDir, index, alias) {
|
|
|
747
789
|
const kp = privKey.toKeypair();
|
|
748
790
|
address = kp.toAddress(network).toString();
|
|
749
791
|
publicKey = kp.publicKey;
|
|
750
|
-
privateKey =
|
|
792
|
+
privateKey = privateKeyHex;
|
|
751
793
|
} else {
|
|
752
794
|
let sdkModule;
|
|
753
795
|
try {
|
|
@@ -1446,6 +1488,76 @@ var UnsupportedKaspaKeyGenerator = class {
|
|
|
1446
1488
|
);
|
|
1447
1489
|
}
|
|
1448
1490
|
};
|
|
1491
|
+
|
|
1492
|
+
// src/keystore-lock.ts
|
|
1493
|
+
import fs5 from "fs";
|
|
1494
|
+
import path5 from "path";
|
|
1495
|
+
async function withKeystoreLock(filePath, operation) {
|
|
1496
|
+
const lockFilePath = `${filePath}.lock`;
|
|
1497
|
+
const staleTimeoutMs = parseInt(process.env.HARDKAS_KEYSTORE_LOCK_STALE_MS || "30000", 10);
|
|
1498
|
+
const acquireTimeoutMs = parseInt(process.env.HARDKAS_KEYSTORE_LOCK_TIMEOUT_MS || "10000", 10);
|
|
1499
|
+
const start = Date.now();
|
|
1500
|
+
while (true) {
|
|
1501
|
+
try {
|
|
1502
|
+
fs5.mkdirSync(path5.dirname(lockFilePath), { recursive: true });
|
|
1503
|
+
fs5.writeFileSync(lockFilePath, process.pid.toString(), { flag: "wx" });
|
|
1504
|
+
break;
|
|
1505
|
+
} catch (err) {
|
|
1506
|
+
if (err.code === "EEXIST") {
|
|
1507
|
+
const stats = fs5.statSync(lockFilePath, { throwIfNoEntry: false });
|
|
1508
|
+
if (stats && Date.now() - stats.mtimeMs > staleTimeoutMs) {
|
|
1509
|
+
try {
|
|
1510
|
+
fs5.unlinkSync(lockFilePath);
|
|
1511
|
+
} catch (e) {
|
|
1512
|
+
}
|
|
1513
|
+
continue;
|
|
1514
|
+
}
|
|
1515
|
+
if (Date.now() - start > acquireTimeoutMs) {
|
|
1516
|
+
const e = new Error("KEYSTORE_LOCK_TIMEOUT: Failed to acquire lock for keystore.json");
|
|
1517
|
+
e.code = "KEYSTORE_LOCK_TIMEOUT";
|
|
1518
|
+
throw e;
|
|
1519
|
+
}
|
|
1520
|
+
const jitter = Math.floor(Math.random() * 75) + 25;
|
|
1521
|
+
await new Promise((resolve) => setTimeout(resolve, jitter));
|
|
1522
|
+
} else {
|
|
1523
|
+
throw err;
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
try {
|
|
1528
|
+
return await operation();
|
|
1529
|
+
} finally {
|
|
1530
|
+
try {
|
|
1531
|
+
fs5.unlinkSync(lockFilePath);
|
|
1532
|
+
} catch (e) {
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
async function appendToKeystoreJson(workspaceRoot, alias, accountData) {
|
|
1537
|
+
const keystorePath = path5.join(workspaceRoot, ".hardkas", "keystore.json");
|
|
1538
|
+
const tempPath = path5.join(workspaceRoot, ".hardkas", `keystore-${process.pid}-${Date.now()}.json.tmp`);
|
|
1539
|
+
await withKeystoreLock(keystorePath, async () => {
|
|
1540
|
+
let ks = {};
|
|
1541
|
+
if (fs5.existsSync(keystorePath)) {
|
|
1542
|
+
try {
|
|
1543
|
+
const data = await fs5.promises.readFile(keystorePath, "utf-8");
|
|
1544
|
+
ks = JSON.parse(data);
|
|
1545
|
+
} catch (e) {
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
ks[alias] = accountData;
|
|
1549
|
+
const fd = await fs5.promises.open(tempPath, "w");
|
|
1550
|
+
try {
|
|
1551
|
+
await fd.writeFile(JSON.stringify(ks, null, 2));
|
|
1552
|
+
await fd.sync();
|
|
1553
|
+
} finally {
|
|
1554
|
+
await fd.close();
|
|
1555
|
+
}
|
|
1556
|
+
await fs5.promises.rename(tempPath, keystorePath);
|
|
1557
|
+
const written = await fs5.promises.readFile(keystorePath, "utf-8");
|
|
1558
|
+
JSON.parse(written);
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1449
1561
|
export {
|
|
1450
1562
|
DEV_ACCOUNTS_PASSWORD,
|
|
1451
1563
|
HardkasFixtureSigner,
|
|
@@ -1458,6 +1570,7 @@ export {
|
|
|
1458
1570
|
UnsupportedKaspaKeyGenerator,
|
|
1459
1571
|
UnsupportedRealKaspaSigner,
|
|
1460
1572
|
UnsupportedRealTxSigner,
|
|
1573
|
+
appendToKeystoreJson,
|
|
1461
1574
|
assertSigningNetworkAllowed,
|
|
1462
1575
|
createEmptyRealAccountStore,
|
|
1463
1576
|
createLocalKaspaWallet,
|
|
@@ -1485,5 +1598,6 @@ export {
|
|
|
1485
1598
|
signTxPlanArtifact,
|
|
1486
1599
|
validateAccountName,
|
|
1487
1600
|
validateAddressNetwork,
|
|
1488
|
-
validateAddressPrefix
|
|
1601
|
+
validateAddressPrefix,
|
|
1602
|
+
withKeystoreLock
|
|
1489
1603
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardkas/accounts",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7-alpha",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"hash-wasm": "^4.12.0",
|
|
21
21
|
"kaspa-wasm": "0.13.0",
|
|
22
|
-
"@hardkas/
|
|
23
|
-
"@hardkas/
|
|
24
|
-
"@hardkas/
|
|
25
|
-
"@hardkas/localnet": "0.9.
|
|
22
|
+
"@hardkas/artifacts": "0.9.7-alpha",
|
|
23
|
+
"@hardkas/core": "0.9.7-alpha",
|
|
24
|
+
"@hardkas/config": "0.9.7-alpha",
|
|
25
|
+
"@hardkas/localnet": "0.9.7-alpha"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"tsup": "^8.3.5",
|