@hardkas/accounts 0.10.0-alpha → 0.11.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
@@ -396,4 +396,130 @@ declare function listDevAccountsSync(workspaceDir: string): {
396
396
  address: string;
397
397
  }[];
398
398
 
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 };
399
+ type NetworkType = "simnet" | "testnet" | "mainnet" | "local-docker-simnet";
400
+ type ChainType = "receive" | "change" | 0 | 1;
401
+ interface PathRequest {
402
+ readonly accountIndex: number;
403
+ readonly chain: ChainType;
404
+ readonly addressIndex: number;
405
+ }
406
+ interface DeriveRequest {
407
+ readonly seedRef: string;
408
+ readonly accountIndex: number;
409
+ readonly chain: ChainType;
410
+ readonly addressIndex: number;
411
+ readonly network?: NetworkType;
412
+ }
413
+ interface DerivedAddress {
414
+ readonly address: string;
415
+ readonly path: string;
416
+ readonly network: NetworkType;
417
+ readonly derivationModel: "deterministic-simulated-v1";
418
+ readonly claims: {
419
+ readonly realBip39: false;
420
+ readonly productionCustody: false;
421
+ };
422
+ }
423
+ interface HelperDeriveRequest {
424
+ readonly seedRef: string;
425
+ readonly accountIndex: number;
426
+ readonly addressIndex: number;
427
+ readonly network?: NetworkType;
428
+ }
429
+ declare const AddressManager: {
430
+ path(opts: PathRequest): string;
431
+ derive(opts: DeriveRequest): DerivedAddress;
432
+ deriveReceive(opts: HelperDeriveRequest): DerivedAddress;
433
+ deriveChange(opts: HelperDeriveRequest): DerivedAddress;
434
+ };
435
+
436
+ interface WalletClaims {
437
+ readonly productionCustody: false;
438
+ readonly plaintextMnemonicStored: false;
439
+ readonly hardwareWallet: false;
440
+ }
441
+ interface WalletArtifact {
442
+ readonly schema: string;
443
+ readonly walletId: string;
444
+ readonly seedRef: string;
445
+ readonly keystoreRef: string;
446
+ readonly network: NetworkType;
447
+ readonly claims: WalletClaims;
448
+ }
449
+ interface WalletCreateRequest {
450
+ readonly walletId: string;
451
+ readonly network?: NetworkType;
452
+ }
453
+ interface WalletImportRequest {
454
+ readonly walletId: string;
455
+ readonly mnemonic: string;
456
+ readonly network?: NetworkType;
457
+ }
458
+ interface WalletMetadata {
459
+ readonly walletId: string;
460
+ readonly keystoreRef: string;
461
+ readonly network: NetworkType;
462
+ readonly createdAt: number;
463
+ }
464
+ declare class WalletManagerImpl {
465
+ private wallets;
466
+ private validateNetwork;
467
+ private generateSeedRef;
468
+ create(opts: WalletCreateRequest): WalletArtifact;
469
+ importMnemonic(opts: WalletImportRequest): WalletArtifact;
470
+ getSeedRef(walletId: string): string;
471
+ exportMetadata(walletId: string): WalletMetadata;
472
+ }
473
+ declare const WalletManager: WalletManagerImpl;
474
+
475
+ interface WalletState {
476
+ walletId: string;
477
+ receiveIndex: number;
478
+ changeIndex: number;
479
+ }
480
+ interface WalletStateStoreOptions {
481
+ /**
482
+ * The path to the JSON file where state is stored.
483
+ * If not provided, it defaults to `.hardkas/wallet-state.json` in the current working directory.
484
+ */
485
+ filePath?: string;
486
+ }
487
+ /**
488
+ * A simple JSON-based state store for wallets.
489
+ * This resolves the friction of keeping track of address derivation indices across CLI or local app sessions.
490
+ */
491
+ declare class WalletStateStoreJson {
492
+ private readonly filePath;
493
+ constructor(options?: WalletStateStoreOptions);
494
+ /**
495
+ * Ensures the directory exists before saving.
496
+ */
497
+ private ensureDir;
498
+ /**
499
+ * Loads the entire state file into memory.
500
+ */
501
+ private loadAll;
502
+ /**
503
+ * Saves the entire state file to disk.
504
+ */
505
+ private saveAll;
506
+ /**
507
+ * Retrieves the state for a specific wallet.
508
+ * If it doesn't exist, returns a default state starting at index 0.
509
+ */
510
+ getWallet(walletId: string): WalletState;
511
+ /**
512
+ * Saves or overwrites the state for a specific wallet.
513
+ */
514
+ saveWallet(wallet: WalletState): void;
515
+ /**
516
+ * Atomically gets the next receive index and increments the state.
517
+ */
518
+ nextReceiveIndex(walletId: string): number;
519
+ /**
520
+ * Atomically gets the next change index and increments the state.
521
+ */
522
+ nextChangeIndex(walletId: string): number;
523
+ }
524
+
525
+ export { AddressManager, type ChainType, type CreateKaspaWalletOptions, DEV_ACCOUNTS_PASSWORD, type DeriveRequest, type DerivedAddress, 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 HelperDeriveRequest, type KaspaKeyGenerator, KaspaSdkKeyGenerator, type KaspaSdkKeyGeneratorOptions, KaspaSdkRealTxSigner, type KaspaSdkRealTxSignerOptions, type KaspaSigningBackendStatus, KaspaWasmPrivateKeySigner, type KeystoreCipherParams, type KeystoreKdfParams, KeystoreManager, type KeystorePayload, type KeystoreUnlockResult, type NetworkType, type PathRequest, type RealAccountStore, type RealDevAccount, type RealTxSigner, type RealTxSigningInput, type RealTxSigningResult, type ResolveAccountOptions, type SignTxPlanInput, type SignTxPlanResult, SimulatedSigner, SimulatedTxPlanSigner, UnsupportedKaspaKeyGenerator, UnsupportedRealKaspaSigner, UnsupportedRealTxSigner, type WalletArtifact, type WalletClaims, type WalletCreateRequest, type WalletImportRequest, WalletManager, WalletManagerImpl, type WalletMetadata, type WalletState, WalletStateStoreJson, type WalletStateStoreOptions, 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
@@ -360,7 +360,6 @@ function listHardkasAccounts(config) {
360
360
  }
361
361
  const keystoreDir = path2.join(process.cwd(), ".hardkas", "keystore");
362
362
  if (fs2.existsSync(keystoreDir)) {
363
- const cwd = config?.cwd || process.cwd();
364
363
  const files = fs2.readdirSync(keystoreDir);
365
364
  for (const file of files) {
366
365
  if (file.endsWith(".json")) {
@@ -1558,7 +1557,221 @@ async function appendToKeystoreJson(workspaceRoot, alias, accountData) {
1558
1557
  JSON.parse(written);
1559
1558
  });
1560
1559
  }
1560
+
1561
+ // src/address-manager.ts
1562
+ import { createHash } from "crypto";
1563
+ function resolveChain(chain) {
1564
+ if (chain === "receive" || chain === 0) return 0;
1565
+ if (chain === "change" || chain === 1) return 1;
1566
+ throw new Error(`Invalid chain type: ${chain}`);
1567
+ }
1568
+ function validateIndex(index, name) {
1569
+ if (!Number.isInteger(index) || index < 0) {
1570
+ throw new Error(`Invalid ${name}: must be a non-negative integer`);
1571
+ }
1572
+ }
1573
+ var AddressManager = {
1574
+ path(opts) {
1575
+ validateIndex(opts.accountIndex, "accountIndex");
1576
+ validateIndex(opts.addressIndex, "addressIndex");
1577
+ const chainNum = resolveChain(opts.chain);
1578
+ return `m/44'/111111'/${opts.accountIndex}'/${chainNum}/${opts.addressIndex}`;
1579
+ },
1580
+ derive(opts) {
1581
+ const network = opts.network ?? "simnet";
1582
+ if (network === "mainnet") {
1583
+ throw new Error("ADDRESS_MANAGER_MAINNET_BLOCKED: mainnet derivation is blocked by default in simulated v1.");
1584
+ }
1585
+ const derivationPath = this.path({
1586
+ accountIndex: opts.accountIndex,
1587
+ chain: opts.chain,
1588
+ addressIndex: opts.addressIndex
1589
+ });
1590
+ const payload = `${opts.seedRef}:${derivationPath}:${network}`;
1591
+ const hash = createHash("sha256").update(payload).digest("hex").slice(0, 42);
1592
+ const prefix = network.includes("sim") ? "kaspasim" : "kaspatest";
1593
+ const address = `${prefix}:q${hash}`;
1594
+ return {
1595
+ address,
1596
+ path: derivationPath,
1597
+ network,
1598
+ derivationModel: "deterministic-simulated-v1",
1599
+ claims: {
1600
+ realBip39: false,
1601
+ productionCustody: false
1602
+ }
1603
+ };
1604
+ },
1605
+ deriveReceive(opts) {
1606
+ return this.derive({
1607
+ ...opts,
1608
+ chain: 0
1609
+ });
1610
+ },
1611
+ deriveChange(opts) {
1612
+ return this.derive({
1613
+ ...opts,
1614
+ chain: 1
1615
+ });
1616
+ }
1617
+ };
1618
+
1619
+ // src/wallet-manager.ts
1620
+ import { createHash as createHash2, randomUUID } from "crypto";
1621
+ var WalletManagerImpl = class {
1622
+ wallets = /* @__PURE__ */ new Map();
1623
+ validateNetwork(network) {
1624
+ const net = network ?? "simnet";
1625
+ if (net === "mainnet") {
1626
+ throw new Error("WALLET_MANAGER_MAINNET_BLOCKED: mainnet custody is blocked by default in simulated v1.");
1627
+ }
1628
+ return net;
1629
+ }
1630
+ generateSeedRef(mnemonic) {
1631
+ return "seedref_" + createHash2("sha256").update(mnemonic).digest("hex").slice(0, 32);
1632
+ }
1633
+ create(opts) {
1634
+ const network = this.validateNetwork(opts.network);
1635
+ const mockMnemonic = `dev-fixture:${opts.walletId}`;
1636
+ const seedRef = this.generateSeedRef(mockMnemonic);
1637
+ const keystoreRef = "keystore_" + randomUUID();
1638
+ const metadata = {
1639
+ walletId: opts.walletId,
1640
+ keystoreRef,
1641
+ network,
1642
+ createdAt: Date.now()
1643
+ };
1644
+ this.wallets.set(opts.walletId, { seedRef, keystoreRef, metadata });
1645
+ return {
1646
+ schema: "hardkas.walletCreated.v1",
1647
+ walletId: opts.walletId,
1648
+ seedRef,
1649
+ keystoreRef,
1650
+ network,
1651
+ claims: {
1652
+ productionCustody: false,
1653
+ plaintextMnemonicStored: false,
1654
+ hardwareWallet: false
1655
+ }
1656
+ };
1657
+ }
1658
+ importMnemonic(opts) {
1659
+ const network = this.validateNetwork(opts.network);
1660
+ const seedRef = this.generateSeedRef(opts.mnemonic);
1661
+ const keystoreRef = "keystore_" + randomUUID();
1662
+ const metadata = {
1663
+ walletId: opts.walletId,
1664
+ keystoreRef,
1665
+ network,
1666
+ createdAt: Date.now()
1667
+ };
1668
+ this.wallets.set(opts.walletId, { seedRef, keystoreRef, metadata });
1669
+ return {
1670
+ schema: "hardkas.walletImported.v1",
1671
+ walletId: opts.walletId,
1672
+ seedRef,
1673
+ keystoreRef,
1674
+ network,
1675
+ claims: {
1676
+ productionCustody: false,
1677
+ plaintextMnemonicStored: false,
1678
+ hardwareWallet: false
1679
+ }
1680
+ };
1681
+ }
1682
+ getSeedRef(walletId) {
1683
+ const state = this.wallets.get(walletId);
1684
+ if (!state) throw new Error("Wallet not found");
1685
+ return state.seedRef;
1686
+ }
1687
+ exportMetadata(walletId) {
1688
+ const state = this.wallets.get(walletId);
1689
+ if (!state) throw new Error("Wallet not found");
1690
+ return state.metadata;
1691
+ }
1692
+ };
1693
+ var WalletManager = new WalletManagerImpl();
1694
+
1695
+ // src/wallet-state-store.ts
1696
+ import * as fs6 from "fs";
1697
+ import * as path6 from "path";
1698
+ var WalletStateStoreJson = class {
1699
+ filePath;
1700
+ constructor(options) {
1701
+ this.filePath = options?.filePath || path6.join(process.cwd(), ".hardkas", "wallet-state.json");
1702
+ }
1703
+ /**
1704
+ * Ensures the directory exists before saving.
1705
+ */
1706
+ ensureDir() {
1707
+ const dir = path6.dirname(this.filePath);
1708
+ if (!fs6.existsSync(dir)) {
1709
+ fs6.mkdirSync(dir, { recursive: true });
1710
+ }
1711
+ }
1712
+ /**
1713
+ * Loads the entire state file into memory.
1714
+ */
1715
+ loadAll() {
1716
+ if (!fs6.existsSync(this.filePath)) {
1717
+ return {};
1718
+ }
1719
+ try {
1720
+ return JSON.parse(fs6.readFileSync(this.filePath, "utf-8"));
1721
+ } catch (e) {
1722
+ process.stderr.write(`[WalletStateStore] corrupt state file at ${this.filePath} \u2014 resetting indices to 0. Cause: ${e}
1723
+ `);
1724
+ return {};
1725
+ }
1726
+ }
1727
+ /**
1728
+ * Saves the entire state file to disk.
1729
+ */
1730
+ saveAll(data) {
1731
+ this.ensureDir();
1732
+ const tmp = this.filePath + ".tmp";
1733
+ fs6.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
1734
+ fs6.renameSync(tmp, this.filePath);
1735
+ }
1736
+ /**
1737
+ * Retrieves the state for a specific wallet.
1738
+ * If it doesn't exist, returns a default state starting at index 0.
1739
+ */
1740
+ getWallet(walletId) {
1741
+ const data = this.loadAll();
1742
+ return data[walletId] || { walletId, receiveIndex: 0, changeIndex: 0 };
1743
+ }
1744
+ /**
1745
+ * Saves or overwrites the state for a specific wallet.
1746
+ */
1747
+ saveWallet(wallet) {
1748
+ const data = this.loadAll();
1749
+ data[wallet.walletId] = wallet;
1750
+ this.saveAll(data);
1751
+ }
1752
+ /**
1753
+ * Atomically gets the next receive index and increments the state.
1754
+ */
1755
+ nextReceiveIndex(walletId) {
1756
+ const wallet = this.getWallet(walletId);
1757
+ const currentIndex = wallet.receiveIndex;
1758
+ wallet.receiveIndex += 1;
1759
+ this.saveWallet(wallet);
1760
+ return currentIndex;
1761
+ }
1762
+ /**
1763
+ * Atomically gets the next change index and increments the state.
1764
+ */
1765
+ nextChangeIndex(walletId) {
1766
+ const wallet = this.getWallet(walletId);
1767
+ const currentIndex = wallet.changeIndex;
1768
+ wallet.changeIndex += 1;
1769
+ this.saveWallet(wallet);
1770
+ return currentIndex;
1771
+ }
1772
+ };
1561
1773
  export {
1774
+ AddressManager,
1562
1775
  DEV_ACCOUNTS_PASSWORD,
1563
1776
  HardkasFixtureSigner,
1564
1777
  KaspaSdkKeyGenerator,
@@ -1570,6 +1783,9 @@ export {
1570
1783
  UnsupportedKaspaKeyGenerator,
1571
1784
  UnsupportedRealKaspaSigner,
1572
1785
  UnsupportedRealTxSigner,
1786
+ WalletManager,
1787
+ WalletManagerImpl,
1788
+ WalletStateStoreJson,
1573
1789
  appendToKeystoreJson,
1574
1790
  assertSigningNetworkAllowed,
1575
1791
  createEmptyRealAccountStore,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/accounts",
3
- "version": "0.10.0-alpha",
3
+ "version": "0.11.0-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/artifacts": "0.10.0-alpha",
23
- "@hardkas/config": "0.10.0-alpha",
24
- "@hardkas/core": "0.10.0-alpha",
25
- "@hardkas/localnet": "0.10.0-alpha"
22
+ "@hardkas/artifacts": "0.11.0-alpha",
23
+ "@hardkas/config": "0.11.0-alpha",
24
+ "@hardkas/core": "0.11.0-alpha",
25
+ "@hardkas/localnet": "0.11.0-alpha"
26
26
  },
27
27
  "devDependencies": {
28
28
  "tsup": "^8.3.5",