@dfx.swiss/wallet 0.0.0-stage → 0.1.1-beta.0

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.
Files changed (142) hide show
  1. package/README.md +39 -2
  2. package/dist/config/environment.d.ts +40 -0
  3. package/dist/config/environment.d.ts.map +1 -0
  4. package/dist/config/environment.js +37 -0
  5. package/dist/config/environment.js.map +1 -0
  6. package/dist/derivation/bitcoin-keys.d.ts +20 -0
  7. package/dist/derivation/bitcoin-keys.d.ts.map +1 -0
  8. package/dist/derivation/bitcoin-keys.js +50 -0
  9. package/dist/derivation/bitcoin-keys.js.map +1 -0
  10. package/dist/derivation/evm-keys.d.ts +8 -0
  11. package/dist/derivation/evm-keys.d.ts.map +1 -0
  12. package/dist/derivation/evm-keys.js +32 -0
  13. package/dist/derivation/evm-keys.js.map +1 -0
  14. package/dist/derivation/keyring.d.ts +68 -0
  15. package/dist/derivation/keyring.d.ts.map +1 -0
  16. package/dist/derivation/keyring.js +150 -0
  17. package/dist/derivation/keyring.js.map +1 -0
  18. package/dist/derivation/public-data.d.ts +26 -0
  19. package/dist/derivation/public-data.d.ts.map +1 -0
  20. package/dist/derivation/public-data.js +19 -0
  21. package/dist/derivation/public-data.js.map +1 -0
  22. package/dist/derivation/seed-check.d.ts +6 -0
  23. package/dist/derivation/seed-check.d.ts.map +1 -0
  24. package/dist/derivation/seed-check.js +13 -0
  25. package/dist/derivation/seed-check.js.map +1 -0
  26. package/dist/derivation/spark-keys.d.ts +14 -0
  27. package/dist/derivation/spark-keys.d.ts.map +1 -0
  28. package/dist/derivation/spark-keys.js +64 -0
  29. package/dist/derivation/spark-keys.js.map +1 -0
  30. package/dist/derivation/v1.d.ts +32 -0
  31. package/dist/derivation/v1.d.ts.map +1 -0
  32. package/dist/derivation/v1.js +64 -0
  33. package/dist/derivation/v1.js.map +1 -0
  34. package/dist/index.d.ts +46 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +36 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/passkey/ceremonies.d.ts +91 -0
  39. package/dist/passkey/ceremonies.d.ts.map +1 -0
  40. package/dist/passkey/ceremonies.js +250 -0
  41. package/dist/passkey/ceremonies.js.map +1 -0
  42. package/dist/passkey/ceremony-gate.d.ts +25 -0
  43. package/dist/passkey/ceremony-gate.d.ts.map +1 -0
  44. package/dist/passkey/ceremony-gate.js +45 -0
  45. package/dist/passkey/ceremony-gate.js.map +1 -0
  46. package/dist/passkey/credential-cache.d.ts +38 -0
  47. package/dist/passkey/credential-cache.d.ts.map +1 -0
  48. package/dist/passkey/credential-cache.js +91 -0
  49. package/dist/passkey/credential-cache.js.map +1 -0
  50. package/dist/passkey/diagnostics.d.ts +22 -0
  51. package/dist/passkey/diagnostics.d.ts.map +1 -0
  52. package/dist/passkey/diagnostics.js +59 -0
  53. package/dist/passkey/diagnostics.js.map +1 -0
  54. package/dist/passkey/errors.d.ts +49 -0
  55. package/dist/passkey/errors.d.ts.map +1 -0
  56. package/dist/passkey/errors.js +87 -0
  57. package/dist/passkey/errors.js.map +1 -0
  58. package/dist/passkey/platform.d.ts +77 -0
  59. package/dist/passkey/platform.d.ts.map +1 -0
  60. package/dist/passkey/platform.js +163 -0
  61. package/dist/passkey/platform.js.map +1 -0
  62. package/dist/passkey/webauthn-json.d.ts +35 -0
  63. package/dist/passkey/webauthn-json.d.ts.map +1 -0
  64. package/dist/passkey/webauthn-json.js +79 -0
  65. package/dist/passkey/webauthn-json.js.map +1 -0
  66. package/dist/providers/blocklist.d.ts +22 -0
  67. package/dist/providers/blocklist.d.ts.map +1 -0
  68. package/dist/providers/blocklist.js +51 -0
  69. package/dist/providers/blocklist.js.map +1 -0
  70. package/dist/providers/chain-registry.d.ts +26 -0
  71. package/dist/providers/chain-registry.d.ts.map +1 -0
  72. package/dist/providers/chain-registry.js +59 -0
  73. package/dist/providers/chain-registry.js.map +1 -0
  74. package/dist/providers/dfx-data.d.ts +25 -0
  75. package/dist/providers/dfx-data.d.ts.map +1 -0
  76. package/dist/providers/dfx-data.js +44 -0
  77. package/dist/providers/dfx-data.js.map +1 -0
  78. package/dist/providers/price.d.ts +34 -0
  79. package/dist/providers/price.d.ts.map +1 -0
  80. package/dist/providers/price.js +46 -0
  81. package/dist/providers/price.js.map +1 -0
  82. package/dist/providers/snapshot.d.ts +28 -0
  83. package/dist/providers/snapshot.d.ts.map +1 -0
  84. package/dist/providers/snapshot.js +2 -0
  85. package/dist/providers/snapshot.js.map +1 -0
  86. package/dist/session/idle-lock.d.ts +31 -0
  87. package/dist/session/idle-lock.d.ts.map +1 -0
  88. package/dist/session/idle-lock.js +73 -0
  89. package/dist/session/idle-lock.js.map +1 -0
  90. package/dist/session/passkey-auth.d.ts +95 -0
  91. package/dist/session/passkey-auth.d.ts.map +1 -0
  92. package/dist/session/passkey-auth.js +356 -0
  93. package/dist/session/passkey-auth.js.map +1 -0
  94. package/dist/session/tab-lock.d.ts +30 -0
  95. package/dist/session/tab-lock.d.ts.map +1 -0
  96. package/dist/session/tab-lock.js +79 -0
  97. package/dist/session/tab-lock.js.map +1 -0
  98. package/dist/signing/auto-signer.d.ts +26 -0
  99. package/dist/signing/auto-signer.d.ts.map +1 -0
  100. package/dist/signing/auto-signer.js +76 -0
  101. package/dist/signing/auto-signer.js.map +1 -0
  102. package/dist/signing/bitcoin-message.d.ts +11 -0
  103. package/dist/signing/bitcoin-message.d.ts.map +1 -0
  104. package/dist/signing/bitcoin-message.js +62 -0
  105. package/dist/signing/bitcoin-message.js.map +1 -0
  106. package/dist/signing/login-messages.d.ts +15 -0
  107. package/dist/signing/login-messages.d.ts.map +1 -0
  108. package/dist/signing/login-messages.js +16 -0
  109. package/dist/signing/login-messages.js.map +1 -0
  110. package/dist/signing/login-text-guard.d.ts +3 -0
  111. package/dist/signing/login-text-guard.d.ts.map +1 -0
  112. package/dist/signing/login-text-guard.js +13 -0
  113. package/dist/signing/login-text-guard.js.map +1 -0
  114. package/dist/signing/spark-login.d.ts +17 -0
  115. package/dist/signing/spark-login.d.ts.map +1 -0
  116. package/dist/signing/spark-login.js +51 -0
  117. package/dist/signing/spark-login.js.map +1 -0
  118. package/dist/util/bytes.d.ts +11 -0
  119. package/dist/util/bytes.d.ts.map +1 -0
  120. package/dist/util/bytes.js +26 -0
  121. package/dist/util/bytes.js.map +1 -0
  122. package/dist/util/emitter.d.ts +17 -0
  123. package/dist/util/emitter.d.ts.map +1 -0
  124. package/dist/util/emitter.js +53 -0
  125. package/dist/util/emitter.js.map +1 -0
  126. package/dist/util/errors.d.ts +12 -0
  127. package/dist/util/errors.d.ts.map +1 -0
  128. package/dist/util/errors.js +15 -0
  129. package/dist/util/errors.js.map +1 -0
  130. package/dist/util/jwt.d.ts +6 -0
  131. package/dist/util/jwt.d.ts.map +1 -0
  132. package/dist/util/jwt.js +23 -0
  133. package/dist/util/jwt.js.map +1 -0
  134. package/dist/util/kv-store.d.ts +51 -0
  135. package/dist/util/kv-store.d.ts.map +1 -0
  136. package/dist/util/kv-store.js +133 -0
  137. package/dist/util/kv-store.js.map +1 -0
  138. package/dist/util/random.d.ts +3 -0
  139. package/dist/util/random.d.ts.map +1 -0
  140. package/dist/util/random.js +18 -0
  141. package/dist/util/random.js.map +1 -0
  142. package/package.json +42 -4
package/README.md CHANGED
@@ -1,3 +1,40 @@
1
- # Temporary Holding Version
1
+ # @dfx.swiss/wallet
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Self-custodial wallet core of the [DFX.swiss](https://dfx.swiss) app: a 12-word seed derived from a passkey (WebAuthn PRF),
4
+ Bitcoin, EVM and Spark accounts on that seed, and the flows that connect the wallet to the DFX API. Keys stay on the
5
+ device; the DFX API never receives them and cannot sign.
6
+
7
+ > **Status:** under construction. The public API is not stable yet and changes without notice until `1.0.0`.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @dfx.swiss/wallet
13
+ ```
14
+
15
+ The package ships ES2020 ES modules for browsers and needs no Node polyfills. It does not depend on the Breez SDK or
16
+ WalletConnect.
17
+
18
+ ## Environments
19
+
20
+ The app build selects the environment (`'prd'`, `'dev'` or `'loc'`). The WebAuthn RP ID, the DFX login message prefix
21
+ and the networks follow from it and are compiled-in constants:
22
+
23
+ | Environment | RP ID | Login message prefix | Bitcoin | EVM chains | Spark |
24
+ | ----------- | ------------------- | -------------------- | -------- | ---------- | ------- |
25
+ | `prd` | `app.dfx.swiss` | none | mainnet | mainnets | mainnet |
26
+ | `dev` | `dev.app.dfx.swiss` | `[dev]_` | testnet4 | testnets | mainnet |
27
+ | `loc` | `localhost` | `[loc]_` | testnet4 | testnets | mainnet |
28
+
29
+ ```typescript
30
+ import { RP_IDS, SIGN_MESSAGE_PREFIX, WALLET_NETWORKS } from '@dfx.swiss/wallet';
31
+
32
+ RP_IDS.prd; // 'app.dfx.swiss'
33
+ SIGN_MESSAGE_PREFIX.dev; // '[dev]_'
34
+ WALLET_NETWORKS.dev.bitcoin; // 'testnet4'
35
+ ```
36
+
37
+ ## Local storage
38
+
39
+ Local wallet data (never secrets) is kept in IndexedDB (`dfx-wallet`) through the `KeyValueStore` interface;
40
+ `MemoryKeyValueStore` serves tests and platforms without IndexedDB.
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Deployment environment of the DFX app that hosts the wallet. It is compiled into the app build and never
3
+ * taken from the server, the URL or user input: the RP ID and the login message prefix follow from it.
4
+ */
5
+ export type WalletEnv = 'prd' | 'dev' | 'loc';
6
+ export declare const WALLET_ENVS: readonly WalletEnv[];
7
+ export declare function isWalletEnv(value: unknown): value is WalletEnv;
8
+ /**
9
+ * WebAuthn relying-party ID per environment. The RP ID is the app host, never the apex `dfx.swiss`. DEV is the
10
+ * existing DEV Pages host `dev.app.dfx.swiss`, a subdomain of the production host: WebAuthn RP scope only
11
+ * grows downward, so a DEV passkey (rpId `dev.app.dfx.swiss`) can never satisfy a PRD ceremony, which pins
12
+ * `app.dfx.swiss`, and every ceremony always passes its own environment's RP ID. A passkey is bound to its
13
+ * RP ID forever, so these values must never change for an existing environment.
14
+ */
15
+ export declare const RP_IDS: Readonly<Record<WalletEnv, string>>;
16
+ /**
17
+ * Prefix of the DFX login message per environment, identical to the DFX API, which computes
18
+ * `this.environment === Environment.PRD ? '' : `[${this.environment}]_`` (DFX API source
19
+ * `src/config/config.ts:410`, environment values `src/config/config.ts:37-41`) and puts it in front of both
20
+ * login templates (`auth.signMessage` and `auth.signMessageGeneral`, `src/config/config.ts:440-445`).
21
+ */
22
+ export declare const SIGN_MESSAGE_PREFIX: Readonly<Record<WalletEnv, string>>;
23
+ export type BitcoinNetwork = 'mainnet' | 'testnet4';
24
+ /** Spark runs on mainnet in every DFX environment. */
25
+ export type SparkNetwork = 'mainnet';
26
+ export type EvmNetworkKind = 'mainnet' | 'testnet';
27
+ export interface WalletNetworks {
28
+ /** Bitcoin network of the BIP-84 account (mainnet coin type 0', testnet4 coin type 1'). */
29
+ bitcoin: BitcoinNetwork;
30
+ /** Spark network of the Breez SDK. */
31
+ spark: SparkNetwork;
32
+ /** Kind of EVM chains the wallet supports in this environment. */
33
+ evm: EvmNetworkKind;
34
+ }
35
+ /**
36
+ * Networks per environment, matching the chain list rule of the DFX API: PRD uses Bitcoin mainnet and EVM
37
+ * mainnets only; DEV and LOC use Bitcoin testnet4 and EVM test chains only; Spark is mainnet everywhere.
38
+ */
39
+ export declare const WALLET_NETWORKS: Readonly<Record<WalletEnv, Readonly<WalletNetworks>>>;
40
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/config/environment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAE9C,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAAkD,CAAC;AAE/F,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAIrD,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAIlE,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,CAAC;AAEpD,sDAAsD;AACtD,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC;AAErC,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,2FAA2F;IAC3F,OAAO,EAAE,cAAc,CAAC;IACxB,sCAAsC;IACtC,KAAK,EAAE,YAAY,CAAC;IACpB,kEAAkE;IAClE,GAAG,EAAE,cAAc,CAAC;CACrB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAIhF,CAAC"}
@@ -0,0 +1,37 @@
1
+ export const WALLET_ENVS = Object.freeze(['prd', 'dev', 'loc']);
2
+ export function isWalletEnv(value) {
3
+ return typeof value === 'string' && WALLET_ENVS.includes(value);
4
+ }
5
+ /**
6
+ * WebAuthn relying-party ID per environment. The RP ID is the app host, never the apex `dfx.swiss`. DEV is the
7
+ * existing DEV Pages host `dev.app.dfx.swiss`, a subdomain of the production host: WebAuthn RP scope only
8
+ * grows downward, so a DEV passkey (rpId `dev.app.dfx.swiss`) can never satisfy a PRD ceremony, which pins
9
+ * `app.dfx.swiss`, and every ceremony always passes its own environment's RP ID. A passkey is bound to its
10
+ * RP ID forever, so these values must never change for an existing environment.
11
+ */
12
+ export const RP_IDS = Object.freeze({
13
+ prd: 'app.dfx.swiss',
14
+ dev: 'dev.app.dfx.swiss',
15
+ loc: 'localhost',
16
+ });
17
+ /**
18
+ * Prefix of the DFX login message per environment, identical to the DFX API, which computes
19
+ * `this.environment === Environment.PRD ? '' : `[${this.environment}]_`` (DFX API source
20
+ * `src/config/config.ts:410`, environment values `src/config/config.ts:37-41`) and puts it in front of both
21
+ * login templates (`auth.signMessage` and `auth.signMessageGeneral`, `src/config/config.ts:440-445`).
22
+ */
23
+ export const SIGN_MESSAGE_PREFIX = Object.freeze({
24
+ prd: '',
25
+ dev: '[dev]_',
26
+ loc: '[loc]_',
27
+ });
28
+ /**
29
+ * Networks per environment, matching the chain list rule of the DFX API: PRD uses Bitcoin mainnet and EVM
30
+ * mainnets only; DEV and LOC use Bitcoin testnet4 and EVM test chains only; Spark is mainnet everywhere.
31
+ */
32
+ export const WALLET_NETWORKS = Object.freeze({
33
+ prd: Object.freeze({ bitcoin: 'mainnet', spark: 'mainnet', evm: 'mainnet' }),
34
+ dev: Object.freeze({ bitcoin: 'testnet4', spark: 'mainnet', evm: 'testnet' }),
35
+ loc: Object.freeze({ bitcoin: 'testnet4', spark: 'mainnet', evm: 'testnet' }),
36
+ });
37
+ //# sourceMappingURL=environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../src/config/environment.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,WAAW,GAAyB,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC,CAAC;AAE/F,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,WAAiC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAwC,MAAM,CAAC,MAAM,CAAC;IACvE,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,WAAW;CACjB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAwC,MAAM,CAAC,MAAM,CAAC;IACpF,GAAG,EAAE,EAAE;IACP,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,QAAQ;CACd,CAAC,CAAC;AAkBH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAA0D,MAAM,CAAC,MAAM,CAAC;IAClG,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;IAC5E,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;IAC7E,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;CAC9E,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Versions } from '@scure/bip32';
2
+ import type { BitcoinNetwork } from '../config/environment';
3
+ /** BIP-84 chain: 0 = receive (external), 1 = change (internal). */
4
+ export type BitcoinChain = 0 | 1;
5
+ /** BIP-44 coin type per network: mainnet 0', every test network 1'. */
6
+ export declare const BITCOIN_COIN_TYPE: Readonly<Record<BitcoinNetwork, number>>;
7
+ /** BIP-32 serialization versions (xpub/xprv, tpub/tprv). */
8
+ export declare const BITCOIN_BIP32_VERSIONS: Readonly<Record<BitcoinNetwork, Readonly<Versions>>>;
9
+ /** Segwit address HRP per network (BIP-173). */
10
+ export declare const BITCOIN_HRP: Readonly<Record<BitcoinNetwork, string>>;
11
+ /** BIP-84 account 0: `m/84'/0'/0'` on mainnet, `m/84'/1'/0'` on testnet4. */
12
+ export declare function bitcoinAccountPath(network: BitcoinNetwork): string;
13
+ export declare function bitcoinAddressPath(network: BitcoinNetwork, chain: BitcoinChain, index: number): string;
14
+ export declare function hash160(data: Uint8Array): Uint8Array;
15
+ /** Native segwit v0 P2WPKH address (`bc1q…` / `tb1q…`) of a compressed public key. */
16
+ export declare function p2wpkhAddress(publicKey: Uint8Array, network: BitcoinNetwork): string;
17
+ export declare function checkChain(chain: number): asserts chain is BitcoinChain;
18
+ /** Non-hardened BIP-32 child index. */
19
+ export declare function checkIndex(index: number): void;
20
+ //# sourceMappingURL=bitcoin-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitcoin-keys.d.ts","sourceRoot":"","sources":["../../src/derivation/bitcoin-keys.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,mEAAmE;AACnE,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC;AAEjC,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAA8C,CAAC;AAEtH,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAGtF,CAAC;AAEH,gDAAgD;AAChD,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAoD,CAAC;AAEtH,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAElE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAItG;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAEpD;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAKpF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAEvE;AAED,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI9C"}
@@ -0,0 +1,50 @@
1
+ import { ripemd160 } from '@noble/hashes/legacy';
2
+ import { sha256 } from '@noble/hashes/sha2';
3
+ import { bech32 } from '@scure/base';
4
+ import { isBytes } from '../util/bytes';
5
+ import { WalletError } from '../util/errors';
6
+ /** BIP-44 coin type per network: mainnet 0', every test network 1'. */
7
+ export const BITCOIN_COIN_TYPE = Object.freeze({ mainnet: 0, testnet4: 1 });
8
+ /** BIP-32 serialization versions (xpub/xprv, tpub/tprv). */
9
+ export const BITCOIN_BIP32_VERSIONS = Object.freeze({
10
+ mainnet: Object.freeze({ private: 0x0488ade4, public: 0x0488b21e }),
11
+ testnet4: Object.freeze({ private: 0x04358394, public: 0x043587cf }),
12
+ });
13
+ /** Segwit address HRP per network (BIP-173). */
14
+ export const BITCOIN_HRP = Object.freeze({ mainnet: 'bc', testnet4: 'tb' });
15
+ /** BIP-84 account 0: `m/84'/0'/0'` on mainnet, `m/84'/1'/0'` on testnet4. */
16
+ export function bitcoinAccountPath(network) {
17
+ return `m/84'/${coinType(network)}'/0'`;
18
+ }
19
+ export function bitcoinAddressPath(network, chain, index) {
20
+ checkChain(chain);
21
+ checkIndex(index);
22
+ return `${bitcoinAccountPath(network)}/${chain}/${index}`;
23
+ }
24
+ export function hash160(data) {
25
+ return ripemd160(sha256(data));
26
+ }
27
+ /** Native segwit v0 P2WPKH address (`bc1q…` / `tb1q…`) of a compressed public key. */
28
+ export function p2wpkhAddress(publicKey, network) {
29
+ if (!isBytes(publicKey) || publicKey.length !== 33 || (publicKey[0] !== 0x02 && publicKey[0] !== 0x03)) {
30
+ throw new WalletError('invalid-public-key', 'P2WPKH needs a 33-byte compressed public key');
31
+ }
32
+ return bech32.encode(BITCOIN_HRP[network], [0, ...bech32.toWords(hash160(publicKey))]);
33
+ }
34
+ export function checkChain(chain) {
35
+ if (chain !== 0 && chain !== 1)
36
+ throw new WalletError('invalid-derivation-path', `Invalid BIP-84 chain: ${chain}`);
37
+ }
38
+ /** Non-hardened BIP-32 child index. */
39
+ export function checkIndex(index) {
40
+ if (!Number.isSafeInteger(index) || index < 0 || index >= 0x80000000) {
41
+ throw new WalletError('invalid-derivation-path', `Invalid address index: ${index}`);
42
+ }
43
+ }
44
+ function coinType(network) {
45
+ const coin = BITCOIN_COIN_TYPE[network];
46
+ if (coin === undefined)
47
+ throw new WalletError('invalid-network', `Unknown Bitcoin network: ${network}`);
48
+ return coin;
49
+ }
50
+ //# sourceMappingURL=bitcoin-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitcoin-keys.js","sourceRoot":"","sources":["../../src/derivation/bitcoin-keys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export type EvmAddress = `0x${string}`;
2
+ /** MetaMask account path: `m/44'/60'/0'/0/i`, always derived from the master node. */
3
+ export declare function evmAddressPath(index: number): string;
4
+ /** EIP-55 address of a secp256k1 public key (33 bytes compressed or 65 bytes uncompressed). */
5
+ export declare function evmAddressFromPublicKey(publicKey: Uint8Array): EvmAddress;
6
+ /** EIP-55 mixed-case checksum spelling of a 20-byte hex address (input case is ignored). */
7
+ export declare function toChecksumAddress(address: string): EvmAddress;
8
+ //# sourceMappingURL=evm-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evm-keys.d.ts","sourceRoot":"","sources":["../../src/derivation/evm-keys.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,UAAU,GAAG,KAAK,MAAM,EAAE,CAAC;AAEvC,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,+FAA+F;AAC/F,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,UAAU,GAAG,UAAU,CAMzE;AAED,4FAA4F;AAC5F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAW7D"}
@@ -0,0 +1,32 @@
1
+ import { secp256k1 } from '@noble/curves/secp256k1';
2
+ import { keccak_256 } from '@noble/hashes/sha3';
3
+ import { bytesToHex, isBytes, utf8ToBytes } from '../util/bytes';
4
+ import { WalletError } from '../util/errors';
5
+ import { checkIndex } from './bitcoin-keys';
6
+ /** MetaMask account path: `m/44'/60'/0'/0/i`, always derived from the master node. */
7
+ export function evmAddressPath(index) {
8
+ checkIndex(index);
9
+ return `m/44'/60'/0'/0/${index}`;
10
+ }
11
+ /** EIP-55 address of a secp256k1 public key (33 bytes compressed or 65 bytes uncompressed). */
12
+ export function evmAddressFromPublicKey(publicKey) {
13
+ if (!isBytes(publicKey) || (publicKey.length !== 33 && publicKey.length !== 65)) {
14
+ throw new WalletError('invalid-public-key', 'Expected a 33- or 65-byte secp256k1 public key');
15
+ }
16
+ const uncompressed = secp256k1.ProjectivePoint.fromHex(publicKey).toRawBytes(false);
17
+ return toChecksumAddress(`0x${bytesToHex(keccak_256(uncompressed.subarray(1)).subarray(-20))}`);
18
+ }
19
+ /** EIP-55 mixed-case checksum spelling of a 20-byte hex address (input case is ignored). */
20
+ export function toChecksumAddress(address) {
21
+ if (typeof address !== 'string' || !/^0x[0-9a-fA-F]{40}$/.test(address)) {
22
+ throw new WalletError('invalid-evm-address', 'Expected a 0x-prefixed 20-byte hex address');
23
+ }
24
+ const lower = address.slice(2).toLowerCase();
25
+ const hash = bytesToHex(keccak_256(utf8ToBytes(lower)));
26
+ let result = '0x';
27
+ for (let i = 0; i < lower.length; i++) {
28
+ result += parseInt(hash[i], 16) >= 8 ? lower[i].toUpperCase() : lower[i];
29
+ }
30
+ return result;
31
+ }
32
+ //# sourceMappingURL=evm-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evm-keys.js","sourceRoot":"","sources":["../../src/derivation/evm-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C,sFAAsF;AACtF,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,UAAU,CAAC,KAAK,CAAC,CAAC;IAClB,OAAO,kBAAkB,KAAK,EAAE,CAAC;AACnC,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,uBAAuB,CAAC,SAAqB;IAC3D,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,EAAE,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,WAAW,CAAC,oBAAoB,EAAE,gDAAgD,CAAC,CAAC;IAChG,CAAC;IACD,MAAM,YAAY,GAAG,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACpF,OAAO,iBAAiB,CAAC,KAAK,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAClG,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,WAAW,CAAC,qBAAqB,EAAE,4CAA4C,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,MAAoB,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,68 @@
1
+ import type { BitcoinNetwork } from '../config/environment';
2
+ import { BitcoinChain } from './bitcoin-keys';
3
+ import { EvmAddress } from './evm-keys';
4
+ import { SPARK_IDENTITY_PATH } from './spark-keys';
5
+ export interface KeyRingOptions {
6
+ bitcoinNetwork: BitcoinNetwork;
7
+ }
8
+ export interface BitcoinAccountInfo {
9
+ path: string;
10
+ /** Account extended public key (xpub on mainnet, tpub on testnet4). */
11
+ xpub: string;
12
+ /** Master key fingerprint, 8 lowercase hex characters. */
13
+ fingerprint: string;
14
+ }
15
+ export interface BitcoinAddressInfo {
16
+ path: string;
17
+ address: string;
18
+ publicKey: Uint8Array;
19
+ }
20
+ export interface SparkIdentityInfo {
21
+ path: typeof SPARK_IDENTITY_PATH;
22
+ publicKey: Uint8Array;
23
+ address: string;
24
+ }
25
+ /** A key the wallet signs with; package-internal (see `withPrivateKey`). */
26
+ export type KeyPath = {
27
+ family: 'evm';
28
+ index: number;
29
+ } | {
30
+ family: 'bitcoin';
31
+ chain: BitcoinChain;
32
+ index: number;
33
+ } | {
34
+ family: 'spark';
35
+ };
36
+ /**
37
+ * The unlocked keys of one wallet. Every path is derived from the master node (BIP-84 Bitcoin account 0,
38
+ * MetaMask EVM accounts, Spark identity of account 1); address derivation uses public account nodes only.
39
+ */
40
+ export declare class KeyRing {
41
+ readonly bitcoinNetwork: BitcoinNetwork;
42
+ private nodes?;
43
+ private constructor();
44
+ static fromMnemonic(mnemonic: string, options: KeyRingOptions): KeyRing;
45
+ get wiped(): boolean;
46
+ /** EVM account `m/44'/60'/0'/0/index`; index 0 is the seed check address. */
47
+ evm(index: number): {
48
+ path: string;
49
+ address: EvmAddress;
50
+ };
51
+ bitcoinAccount(): BitcoinAccountInfo;
52
+ /** BIP-84 P2WPKH address of the receive (0) or change (1) chain. */
53
+ bitcoinAddress(chain: BitcoinChain, index: number): BitcoinAddressInfo;
54
+ /** Spark identity key `m/8797555'/1'/0'` and its plain mainnet `spark1` address. */
55
+ sparkIdentity(): SparkIdentityInfo;
56
+ /** The mnemonic, only for the export screen and the Spark client. */
57
+ mnemonic(): string;
58
+ /** Drops all key material; every later call throws. */
59
+ wipe(): void;
60
+ private publicNodes;
61
+ private secret;
62
+ }
63
+ /**
64
+ * Package-internal signing access: derives the private key of `path`, passes it to the synchronous `use` and
65
+ * wipes it afterwards. Not exported from the package index.
66
+ */
67
+ export declare function withPrivateKey<T>(keys: KeyRing, path: KeyPath, use: (privateKey: Uint8Array) => T): T;
68
+ //# sourceMappingURL=keyring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyring.d.ts","sourceRoot":"","sources":["../../src/derivation/keyring.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,EAEL,YAAY,EAMb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAA2C,MAAM,YAAY,CAAC;AACjF,OAAO,EAAsB,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGvE,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,mBAAmB,CAAC;IACjC,SAAS,EAAE,UAAU,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,4EAA4E;AAC5E,MAAM,MAAM,OAAO,GACf;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAmBxB;;;GAGG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,OAAO,CAAC,KAAK,CAAC,CAAc;IAE5B,OAAO;IAaP,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO;IAWvE,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,6EAA6E;IAC7E,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE;IAKzD,cAAc,IAAI,kBAAkB;IASpC,oEAAoE;IACpE,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,kBAAkB;IAYtE,oFAAoF;IACpF,aAAa,IAAI,iBAAiB;IAYlC,qEAAqE;IACrE,QAAQ,IAAI,MAAM;IAIlB,uDAAuD;IACvD,IAAI,IAAI,IAAI;IAUZ,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,MAAM;CAKf;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,CAAC,GAAG,CAAC,CAiBrG"}
@@ -0,0 +1,150 @@
1
+ import { HDKey } from '@scure/bip32';
2
+ import { wipeBytes } from '../util/bytes';
3
+ import { WalletError } from '../util/errors';
4
+ import { BITCOIN_BIP32_VERSIONS, bitcoinAccountPath, bitcoinAddressPath, checkChain, checkIndex, p2wpkhAddress, } from './bitcoin-keys';
5
+ import { evmAddressFromPublicKey, evmAddressPath } from './evm-keys';
6
+ import { encodeSparkAddress, SPARK_IDENTITY_PATH } from './spark-keys';
7
+ import { normalizeMnemonicV1, seedFromMnemonic } from './v1';
8
+ // Secrets live outside the instance, so nothing reachable from a KeyRing object exposes key material.
9
+ const secrets = new WeakMap();
10
+ /**
11
+ * The unlocked keys of one wallet. Every path is derived from the master node (BIP-84 Bitcoin account 0,
12
+ * MetaMask EVM accounts, Spark identity of account 1); address derivation uses public account nodes only.
13
+ */
14
+ export class KeyRing {
15
+ constructor(secret, bitcoinNetwork) {
16
+ this.bitcoinNetwork = bitcoinNetwork;
17
+ secrets.set(this, secret);
18
+ const bitcoinAccount = neutered(secret.master.derive(bitcoinAccountPath(bitcoinNetwork)));
19
+ this.nodes = {
20
+ bitcoinAccount,
21
+ bitcoinChains: [bitcoinAccount.deriveChild(0), bitcoinAccount.deriveChild(1)],
22
+ evmChain: neutered(secret.master.derive("m/44'/60'/0'/0")),
23
+ fingerprint: secret.master.fingerprint.toString(16).padStart(8, '0'),
24
+ };
25
+ }
26
+ static fromMnemonic(mnemonic, options) {
27
+ const network = options?.bitcoinNetwork;
28
+ if (!network || !BITCOIN_BIP32_VERSIONS[network]) {
29
+ throw new WalletError('invalid-network', `Unknown Bitcoin network: ${network}`);
30
+ }
31
+ const normalized = normalizeMnemonicV1(mnemonic);
32
+ const seed = seedFromMnemonic(normalized);
33
+ const master = HDKey.fromMasterSeed(seed, BITCOIN_BIP32_VERSIONS[network]);
34
+ return new KeyRing({ mnemonic: normalized, seed, master }, network);
35
+ }
36
+ get wiped() {
37
+ return this.nodes === undefined;
38
+ }
39
+ /** EVM account `m/44'/60'/0'/0/index`; index 0 is the seed check address. */
40
+ evm(index) {
41
+ const path = evmAddressPath(index);
42
+ return { path, address: evmAddressFromPublicKey(publicKeyOf(this.publicNodes().evmChain.deriveChild(index))) };
43
+ }
44
+ bitcoinAccount() {
45
+ const nodes = this.publicNodes();
46
+ return {
47
+ path: bitcoinAccountPath(this.bitcoinNetwork),
48
+ xpub: nodes.bitcoinAccount.publicExtendedKey,
49
+ fingerprint: nodes.fingerprint,
50
+ };
51
+ }
52
+ /** BIP-84 P2WPKH address of the receive (0) or change (1) chain. */
53
+ bitcoinAddress(chain, index) {
54
+ checkChain(chain);
55
+ checkIndex(index);
56
+ const nodes = this.publicNodes();
57
+ const publicKey = publicKeyOf(nodes.bitcoinChains[chain].deriveChild(index));
58
+ return {
59
+ path: bitcoinAddressPath(this.bitcoinNetwork, chain, index),
60
+ address: p2wpkhAddress(publicKey, this.bitcoinNetwork),
61
+ publicKey,
62
+ };
63
+ }
64
+ /** Spark identity key `m/8797555'/1'/0'` and its plain mainnet `spark1` address. */
65
+ sparkIdentity() {
66
+ const nodes = this.publicNodes();
67
+ if (!nodes.spark) {
68
+ const node = this.secret().master.derive(SPARK_IDENTITY_PATH);
69
+ const publicKey = publicKeyOf(node);
70
+ node.wipePrivateData();
71
+ nodes.spark = { path: SPARK_IDENTITY_PATH, publicKey, address: encodeSparkAddress(publicKey) };
72
+ }
73
+ const { path, publicKey, address } = nodes.spark;
74
+ return { path, publicKey: publicKey.slice(), address };
75
+ }
76
+ /** The mnemonic, only for the export screen and the Spark client. */
77
+ mnemonic() {
78
+ return this.secret().mnemonic;
79
+ }
80
+ /** Drops all key material; every later call throws. */
81
+ wipe() {
82
+ const secret = secrets.get(this);
83
+ if (secret) {
84
+ secret.master.wipePrivateData();
85
+ wipeBytes(secret.seed);
86
+ secrets.delete(this);
87
+ }
88
+ this.nodes = undefined;
89
+ }
90
+ publicNodes() {
91
+ if (!this.nodes)
92
+ throw wipedError();
93
+ return this.nodes;
94
+ }
95
+ secret() {
96
+ const secret = secrets.get(this);
97
+ if (!secret)
98
+ throw wipedError();
99
+ return secret;
100
+ }
101
+ }
102
+ /**
103
+ * Package-internal signing access: derives the private key of `path`, passes it to the synchronous `use` and
104
+ * wipes it afterwards. Not exported from the package index.
105
+ */
106
+ export function withPrivateKey(keys, path, use) {
107
+ const secret = secrets.get(keys);
108
+ if (!secret)
109
+ throw wipedError();
110
+ const node = secret.master.derive(keyPathString(keys.bitcoinNetwork, path));
111
+ const privateKey = node.privateKey?.slice();
112
+ node.wipePrivateData();
113
+ if (!privateKey)
114
+ throw new WalletError('key-unavailable', 'No private key for this path');
115
+ try {
116
+ const result = use(privateKey);
117
+ if (result instanceof Promise)
118
+ throw new WalletError('async-key-use', 'Private keys may only be used synchronously');
119
+ return result;
120
+ }
121
+ finally {
122
+ wipeBytes(privateKey);
123
+ }
124
+ }
125
+ function keyPathString(network, path) {
126
+ switch (path?.family) {
127
+ case 'evm':
128
+ return evmAddressPath(path.index);
129
+ case 'bitcoin':
130
+ return bitcoinAddressPath(network, path.chain, path.index);
131
+ case 'spark':
132
+ return SPARK_IDENTITY_PATH;
133
+ default:
134
+ throw new WalletError('invalid-derivation-path', 'Unknown key family');
135
+ }
136
+ }
137
+ function neutered(node) {
138
+ const publicNode = HDKey.fromExtendedKey(node.publicExtendedKey, node.versions);
139
+ node.wipePrivateData();
140
+ return publicNode;
141
+ }
142
+ function publicKeyOf(node) {
143
+ if (!node.publicKey)
144
+ throw new WalletError('key-unavailable', 'No public key for this path');
145
+ return node.publicKey;
146
+ }
147
+ function wipedError() {
148
+ return new WalletError('keyring-wiped', 'The key ring has been wiped');
149
+ }
150
+ //# sourceMappingURL=keyring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyring.js","sourceRoot":"","sources":["../../src/derivation/keyring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { BitcoinNetwork } from '../config/environment';
2
+ import type { EvmAddress } from './evm-keys';
3
+ import type { KeyRing } from './keyring';
4
+ /**
5
+ * Public data of a seed, cached per origin after a successful seed check so that addresses render while the
6
+ * wallet is locked. Contains no secret.
7
+ */
8
+ export interface SeedPublicData {
9
+ seedCheckAddress: EvmAddress;
10
+ evm: {
11
+ index: number;
12
+ address: EvmAddress;
13
+ }[];
14
+ bitcoin: {
15
+ network: BitcoinNetwork;
16
+ xpub: string;
17
+ fingerprint: string;
18
+ receive0: string;
19
+ };
20
+ spark: {
21
+ identityPubkey: string;
22
+ address: string;
23
+ };
24
+ }
25
+ export declare function seedPublicData(keys: KeyRing, evmIndexes?: readonly number[]): SeedPublicData;
26
+ //# sourceMappingURL=public-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-data.d.ts","sourceRoot":"","sources":["../../src/derivation/public-data.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,UAAU,CAAC;IAC7B,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC;IAC9C,OAAO,EAAE;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1F,KAAK,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,GAAE,SAAS,MAAM,EAAQ,GAAG,cAAc,CAiBjG"}
@@ -0,0 +1,19 @@
1
+ import { bytesToHex } from '../util/bytes';
2
+ export function seedPublicData(keys, evmIndexes = [0]) {
3
+ const indexes = Array.from(new Set([0, ...evmIndexes])).sort((a, b) => a - b);
4
+ const evm = indexes.map((index) => ({ index, address: keys.evm(index).address }));
5
+ const account = keys.bitcoinAccount();
6
+ const spark = keys.sparkIdentity();
7
+ return {
8
+ seedCheckAddress: evm[0].address,
9
+ evm,
10
+ bitcoin: {
11
+ network: keys.bitcoinNetwork,
12
+ xpub: account.xpub,
13
+ fingerprint: account.fingerprint,
14
+ receive0: keys.bitcoinAddress(0, 0).address,
15
+ },
16
+ spark: { identityPubkey: bytesToHex(spark.publicKey), address: spark.address },
17
+ };
18
+ }
19
+ //# sourceMappingURL=public-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-data.js","sourceRoot":"","sources":["../../src/derivation/public-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgB3C,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,aAAgC,CAAC,CAAC,CAAC;IAC/E,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9E,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAClF,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;IAEnC,OAAO;QACL,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO;QAChC,GAAG;QACH,OAAO,EAAE;YACP,OAAO,EAAE,IAAI,CAAC,cAAc;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;SAC5C;QACD,KAAK,EAAE,EAAE,cAAc,EAAE,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;KAC/E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Seed check: the derived EVM index-0 address must equal the stored seed check address (server value at login or
3
+ * the per-origin cache). Case-insensitive; anything that is not a 20-byte hex address never matches.
4
+ */
5
+ export declare function seedCheck(derivedEvm0: string, expected: string): boolean;
6
+ //# sourceMappingURL=seed-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed-check.d.ts","sourceRoot":"","sources":["../../src/derivation/seed-check.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIxE"}
@@ -0,0 +1,13 @@
1
+ const EVM_ADDRESS = /^0x[0-9a-fA-F]{40}$/;
2
+ /**
3
+ * Seed check: the derived EVM index-0 address must equal the stored seed check address (server value at login or
4
+ * the per-origin cache). Case-insensitive; anything that is not a 20-byte hex address never matches.
5
+ */
6
+ export function seedCheck(derivedEvm0, expected) {
7
+ if (typeof derivedEvm0 !== 'string' || typeof expected !== 'string')
8
+ return false;
9
+ if (!EVM_ADDRESS.test(derivedEvm0) || !EVM_ADDRESS.test(expected))
10
+ return false;
11
+ return derivedEvm0.toLowerCase() === expected.toLowerCase();
12
+ }
13
+ //# sourceMappingURL=seed-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed-check.js","sourceRoot":"","sources":["../../src/derivation/seed-check.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAE1C;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,WAAmB,EAAE,QAAgB;IAC7D,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAChF,OAAO,WAAW,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Spark identity key: Spark SDK default derivation on the main mnemonic, mainnet account 1 (Breez SDK Spark
3
+ * `defaultExternalSigners(mnemonic, null, 'mainnet', 1)`). Pinned by the known-answer vectors.
4
+ */
5
+ export declare const SPARK_IDENTITY_PATH: "m/8797555'/1'/0'";
6
+ /** Plain mainnet Spark address: bech32m(`spark`, 0x0a 0x21 ‖ identity public key), no invoice fields. */
7
+ export declare function encodeSparkAddress(publicKey: Uint8Array): string;
8
+ /**
9
+ * Strict decoder for plain mainnet Spark addresses: lowercase, HRP `spark`, payload exactly 0x0a 0x21 followed by
10
+ * a valid compressed secp256k1 point. Invoice addresses, other networks and raw-key payloads are refused.
11
+ * Returns the 33-byte identity public key.
12
+ */
13
+ export declare function decodeSparkAddress(address: string): Uint8Array;
14
+ //# sourceMappingURL=spark-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spark-keys.d.ts","sourceRoot":"","sources":["../../src/derivation/spark-keys.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAG,kBAA2B,CAAC;AAW/D,yGAAyG;AACzG,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAGhE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CA0B9D"}