@leather.io/crypto 1.5.1 → 1.6.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.
- package/dist/index.d.mts +6 -3
- package/dist/index.mjs +15 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -8,9 +8,10 @@ declare enum DerivationPathDepth {
|
|
|
8
8
|
ChangeReceive = 4,
|
|
9
9
|
AddressIndex = 5
|
|
10
10
|
}
|
|
11
|
+
declare const extractPurposeFromPath: (path: string) => number;
|
|
11
12
|
declare const extractAccountIndexFromPath: (path: string) => number;
|
|
12
13
|
declare const extractAddressIndexFromPath: (path: string) => number;
|
|
13
|
-
declare function
|
|
14
|
+
declare function appendAddressIndexToPath(path: string, index: number): string;
|
|
14
15
|
declare function extractFingerprintFromKeyOriginPath(keyOriginPath: string): string;
|
|
15
16
|
/**
|
|
16
17
|
* @description
|
|
@@ -48,6 +49,7 @@ declare function extractAccountIndexFromDescriptor(descriptor: string): number;
|
|
|
48
49
|
* @example `[0a3fd8ef/84'/0'/6']xpuba1b…2c3` -> `xpuba1b…2c3`
|
|
49
50
|
*/
|
|
50
51
|
declare function extractKeyFromDescriptor(descriptor: string): string;
|
|
52
|
+
declare function keyOriginToDerivationPath(keyOrigin: string): string;
|
|
51
53
|
declare function decomposeDescriptor(descriptor: string): {
|
|
52
54
|
descriptor: string;
|
|
53
55
|
keyOrigin: string;
|
|
@@ -62,7 +64,8 @@ declare function deriveBip39SeedFromMnemonic(mnemonic: string, passphrase?: stri
|
|
|
62
64
|
declare const deriveBip39MnemonicFromSeed: typeof deriveBip39SeedFromMnemonic;
|
|
63
65
|
declare function deriveRootBip32Keychain(seed: Uint8Array): HDKey;
|
|
64
66
|
declare function deriveRootKeychainFromMnemonic(mnemonic: string, passphrase?: string): Promise<HDKey>;
|
|
65
|
-
declare function
|
|
67
|
+
declare function deriveChildKeychainFromMnemnonic(path: string, mnemonic: string, passphrase?: string): Promise<HDKey>;
|
|
68
|
+
declare const deriveKeychainFromXpub: (xpub: string) => HDKey;
|
|
66
69
|
/**
|
|
67
70
|
* Gets keychain fingerprint directly from mnemonic. This is useful for
|
|
68
71
|
* referencing a mnemonic safely by an identifier.
|
|
@@ -80,4 +83,4 @@ interface Signer {
|
|
|
80
83
|
derivationPath: string;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
export { DerivationPathDepth, type Signer,
|
|
86
|
+
export { DerivationPathDepth, type Signer, appendAddressIndexToPath, createDescriptor, createKeyOriginPath, decomposeDescriptor, deriveBip39MnemonicFromSeed, deriveBip39SeedFromMnemonic, deriveChildKeychainFromMnemnonic, deriveKeychainExtendedPublicKeyDescriptor, deriveKeychainFromXpub, deriveRootBip32Keychain, deriveRootKeychainFromMnemonic, extractAccountIndexFromDescriptor, extractAccountIndexFromPath, extractAddressIndexFromPath, extractDerivationPathFromDescriptor, extractFingerprintFromDescriptor, extractFingerprintFromKeyOriginPath, extractKeyFromDescriptor, extractKeyOriginPathFromDescriptor, extractPurposeFromPath, generateMnemonic, getMnemonicRootKeyFingerprint, isValidMnemonic, isValidMnemonicWord, keyOriginToDerivationPath, validateKeyOriginPath };
|
package/dist/index.mjs
CHANGED
|
@@ -17,13 +17,14 @@ function extractSectionFromDerivationPath(depth) {
|
|
|
17
17
|
return accountNum;
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
+
var extractPurposeFromPath = extractSectionFromDerivationPath(1 /* Purpose */);
|
|
20
21
|
var extractAccountIndexFromPath = extractSectionFromDerivationPath(
|
|
21
22
|
3 /* Account */
|
|
22
23
|
);
|
|
23
24
|
var extractAddressIndexFromPath = extractSectionFromDerivationPath(
|
|
24
25
|
5 /* AddressIndex */
|
|
25
26
|
);
|
|
26
|
-
function
|
|
27
|
+
function appendAddressIndexToPath(path, index) {
|
|
27
28
|
const accountIndex = extractAccountIndexFromPath(path);
|
|
28
29
|
if (!Number.isInteger(accountIndex)) throw new Error("Invalid path, must have account index");
|
|
29
30
|
const assumedReceiveChangeIndex = 0;
|
|
@@ -71,6 +72,10 @@ function extractAccountIndexFromDescriptor(descriptor) {
|
|
|
71
72
|
function extractKeyFromDescriptor(descriptor) {
|
|
72
73
|
return descriptor.split("]")[1];
|
|
73
74
|
}
|
|
75
|
+
function keyOriginToDerivationPath(keyOrigin) {
|
|
76
|
+
const [_fingerprint, ...remainingPath] = keyOrigin.split("/");
|
|
77
|
+
return `m/${remainingPath.join("/")}`;
|
|
78
|
+
}
|
|
74
79
|
function decomposeDescriptor(descriptor) {
|
|
75
80
|
return {
|
|
76
81
|
descriptor,
|
|
@@ -89,6 +94,7 @@ import {
|
|
|
89
94
|
validateMnemonic
|
|
90
95
|
} from "@scure/bip39";
|
|
91
96
|
import { wordlist } from "@scure/bip39/wordlists/english";
|
|
97
|
+
import memoize from "just-memoize";
|
|
92
98
|
import { toHexString } from "@leather.io/utils";
|
|
93
99
|
function generateMnemonic() {
|
|
94
100
|
return scureGenerateMnemonic(wordlist, 256);
|
|
@@ -103,9 +109,11 @@ function deriveRootBip32Keychain(seed) {
|
|
|
103
109
|
async function deriveRootKeychainFromMnemonic(mnemonic, passphrase) {
|
|
104
110
|
return deriveRootBip32Keychain(await deriveBip39SeedFromMnemonic(mnemonic, passphrase));
|
|
105
111
|
}
|
|
106
|
-
function
|
|
107
|
-
|
|
112
|
+
async function deriveChildKeychainFromMnemnonic(path, mnemonic, passphrase) {
|
|
113
|
+
const rootKeychain = deriveRootBip32Keychain(await mnemonicToSeed(mnemonic, passphrase));
|
|
114
|
+
return rootKeychain.derive(keyOriginToDerivationPath(path));
|
|
108
115
|
}
|
|
116
|
+
var deriveKeychainFromXpub = memoize((xpub) => HDKey.fromExtendedKey(xpub));
|
|
109
117
|
async function getMnemonicRootKeyFingerprint(mnemonic, passphrase) {
|
|
110
118
|
const keychain = deriveRootBip32Keychain(await deriveBip39SeedFromMnemonic(mnemonic, passphrase));
|
|
111
119
|
return toHexString(keychain.fingerprint);
|
|
@@ -126,12 +134,13 @@ function isValidMnemonic(mnemonic) {
|
|
|
126
134
|
}
|
|
127
135
|
export {
|
|
128
136
|
DerivationPathDepth,
|
|
129
|
-
|
|
137
|
+
appendAddressIndexToPath,
|
|
130
138
|
createDescriptor,
|
|
131
139
|
createKeyOriginPath,
|
|
132
140
|
decomposeDescriptor,
|
|
133
141
|
deriveBip39MnemonicFromSeed,
|
|
134
142
|
deriveBip39SeedFromMnemonic,
|
|
143
|
+
deriveChildKeychainFromMnemnonic,
|
|
135
144
|
deriveKeychainExtendedPublicKeyDescriptor,
|
|
136
145
|
deriveKeychainFromXpub,
|
|
137
146
|
deriveRootBip32Keychain,
|
|
@@ -144,10 +153,12 @@ export {
|
|
|
144
153
|
extractFingerprintFromKeyOriginPath,
|
|
145
154
|
extractKeyFromDescriptor,
|
|
146
155
|
extractKeyOriginPathFromDescriptor,
|
|
156
|
+
extractPurposeFromPath,
|
|
147
157
|
generateMnemonic,
|
|
148
158
|
getMnemonicRootKeyFingerprint,
|
|
149
159
|
isValidMnemonic,
|
|
150
160
|
isValidMnemonicWord,
|
|
161
|
+
keyOriginToDerivationPath,
|
|
151
162
|
validateKeyOriginPath
|
|
152
163
|
};
|
|
153
164
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/derivation-path-utils.ts","../src/keychain.ts"],"sourcesContent":["import { isHexString } from '@leather.io/utils';\n\nexport enum DerivationPathDepth {\n Root = 0,\n Purpose = 1,\n CoinType = 2,\n Account = 3,\n ChangeReceive = 4,\n AddressIndex = 5,\n}\n\nfunction extractSectionFromDerivationPath(depth: DerivationPathDepth) {\n return (path: string) => {\n const segments = path.split('/');\n const accountNum = parseInt(segments[depth].replaceAll(\"'\", ''), 10);\n if (isNaN(accountNum)) throw new Error(`Cannot parse ${DerivationPathDepth[depth]} from path`);\n return accountNum;\n };\n}\n\nexport const extractAccountIndexFromPath = extractSectionFromDerivationPath(\n DerivationPathDepth.Account\n);\n\nexport const extractAddressIndexFromPath = extractSectionFromDerivationPath(\n DerivationPathDepth.AddressIndex\n);\n\nexport function addAddressIndexToPath(path: string, index: number) {\n const accountIndex = extractAccountIndexFromPath(path);\n if (!Number.isInteger(accountIndex)) throw new Error('Invalid path, must have account index');\n const assumedReceiveChangeIndex = 0;\n return `${path}/${assumedReceiveChangeIndex}/${index}`;\n}\n\nexport function extractFingerprintFromKeyOriginPath(keyOriginPath: string) {\n const fingerprint = keyOriginPath.split('/')[0];\n if (!isHexString(fingerprint)) throw new Error('Fingerprint must be a hexadecimal string');\n return fingerprint;\n}\n\n/**\n * @description\n * A key origin path refers to the identifier commonly used as part of the key\n * information provided as part of a Output Descriptor described in BIP-380. It\n * replaces the `m/` part of a derivation path with the master key fingerprint to which the\n * key it describes belongs.\n * @example `0a3fd8ef/84'/0'/0'`\n */\nexport function createKeyOriginPath(fingerprint: string, path: string) {\n if (!isHexString(fingerprint)) throw new Error('Fingerprint must be a hexadecimal string');\n return `${fingerprint}/${path.replace('m/', '')}`;\n}\n\nexport function validateKeyOriginPath(keyOriginPath: string) {\n if (keyOriginPath.includes('[') || keyOriginPath.includes(']'))\n throw new Error('Key origin path should not contain square brackets');\n\n if (!keyOriginPath.includes('/'))\n throw new Error('Key origin path must contain a fingerprint and derivation path');\n\n if (!isHexString(extractFingerprintFromKeyOriginPath(keyOriginPath)))\n throw new Error('Fingerprint must be a hexadecimal string');\n\n if (keyOriginPath.split('/').length < 4)\n throw new Error('Key origin path is too short. Should describe at least to the account level');\n\n return true;\n}\n\n/**\n * @description\n * Creates a descriptor with key origin and xpub or public key\n * @returns `[0a3fd8ef/84'/0'/0']xpuba1b…2c3`\n */\nexport function createDescriptor(keyOriginPath: string, key: string) {\n validateKeyOriginPath(keyOriginPath);\n return `[${keyOriginPath}]${key}`;\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/0']xpuba1b…2c3` -> `0a3fd8ef/84'/0'/0'`\n */\nexport function extractKeyOriginPathFromDescriptor(descriptor: string) {\n const keyOriginPath = descriptor.split(']')[0].replace('[', '');\n validateKeyOriginPath(keyOriginPath);\n return keyOriginPath;\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/0']xpuba1b…2c3` -> `m/84'/0'/0'`\n */\nexport function extractDerivationPathFromDescriptor(descriptor: string) {\n const keyOriginPath = extractKeyOriginPathFromDescriptor(descriptor);\n return 'm/' + keyOriginPath.split('/').slice(1).join('/');\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/0']xpuba1b…2c3` -> `0a3fd8ef`\n */\nexport function extractFingerprintFromDescriptor(descriptor: string) {\n return extractFingerprintFromKeyOriginPath(extractKeyOriginPathFromDescriptor(descriptor));\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/6']xpuba1b…2c3` -> `6`\n */\nexport function extractAccountIndexFromDescriptor(descriptor: string) {\n return extractAccountIndexFromPath(extractKeyOriginPathFromDescriptor(descriptor));\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/6']xpuba1b…2c3` -> `xpuba1b…2c3`\n */\nexport function extractKeyFromDescriptor(descriptor: string) {\n return descriptor.split(']')[1];\n}\n\nexport function decomposeDescriptor(descriptor: string) {\n return {\n descriptor,\n keyOrigin: extractKeyOriginPathFromDescriptor(descriptor),\n fingerprint: extractFingerprintFromDescriptor(descriptor),\n derivationPath: extractDerivationPathFromDescriptor(descriptor),\n accountIndex: extractAccountIndexFromDescriptor(descriptor),\n };\n}\n","import { HDKey } from '@scure/bip32';\nimport {\n mnemonicToSeed,\n generateMnemonic as scureGenerateMnemonic,\n validateMnemonic,\n} from '@scure/bip39';\nimport { wordlist } from '@scure/bip39/wordlists/english';\n\nimport { toHexString } from '@leather.io/utils';\n\nimport {\n DerivationPathDepth,\n createDescriptor,\n createKeyOriginPath,\n} from './derivation-path-utils';\n\nexport function generateMnemonic() {\n return scureGenerateMnemonic(wordlist, 256);\n}\n\nexport async function deriveBip39SeedFromMnemonic(mnemonic: string, passphrase?: string) {\n return mnemonicToSeed(mnemonic, passphrase);\n}\n/** @deprecated Inaccurately named fn, use `deriveBip39SeedFromMnemonic` */\nexport const deriveBip39MnemonicFromSeed = deriveBip39SeedFromMnemonic;\n\nexport function deriveRootBip32Keychain(seed: Uint8Array) {\n return HDKey.fromMasterSeed(seed);\n}\n\nexport async function deriveRootKeychainFromMnemonic(mnemonic: string, passphrase?: string) {\n return deriveRootBip32Keychain(await deriveBip39SeedFromMnemonic(mnemonic, passphrase));\n}\n\nexport function deriveKeychainFromXpub(xpub: string) {\n return HDKey.fromExtendedKey(xpub);\n}\n\n/**\n * Gets keychain fingerprint directly from mnemonic. This is useful for\n * referencing a mnemonic safely by an identifier.\n */\nexport async function getMnemonicRootKeyFingerprint(mnemonic: string, passphrase?: string) {\n const keychain = deriveRootBip32Keychain(await deriveBip39SeedFromMnemonic(mnemonic, passphrase));\n return toHexString(keychain.fingerprint);\n}\n\nexport function deriveKeychainExtendedPublicKeyDescriptor(rootKeychain: HDKey, path: string) {\n const masterFingerprint = toHexString(rootKeychain.fingerprint);\n const keyOriginPath = createKeyOriginPath(masterFingerprint, path);\n\n if (rootKeychain.depth !== DerivationPathDepth.Root)\n throw new Error('Cannot derive account keychain from non-root keychain');\n\n const accountKeychain = rootKeychain.derive(path);\n return createDescriptor(keyOriginPath, accountKeychain.publicExtendedKey);\n}\n\nexport function isValidMnemonicWord(word: string): boolean {\n return wordlist.includes(word);\n}\n\nexport function isValidMnemonic(mnemonic: string): boolean {\n return validateMnemonic(mnemonic, wordlist);\n}\n"],"mappings":"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","names":["DerivationPathDepth"]}
|
|
1
|
+
{"version":3,"sources":["../src/derivation-path-utils.ts","../src/keychain.ts"],"sourcesContent":["import { isHexString } from '@leather.io/utils';\n\nexport enum DerivationPathDepth {\n Root = 0,\n Purpose = 1,\n CoinType = 2,\n Account = 3,\n ChangeReceive = 4,\n AddressIndex = 5,\n}\n\nfunction extractSectionFromDerivationPath(depth: DerivationPathDepth) {\n return (path: string) => {\n const segments = path.split('/');\n const accountNum = parseInt(segments[depth].replaceAll(\"'\", ''), 10);\n if (isNaN(accountNum)) throw new Error(`Cannot parse ${DerivationPathDepth[depth]} from path`);\n return accountNum;\n };\n}\n\nexport const extractPurposeFromPath = extractSectionFromDerivationPath(DerivationPathDepth.Purpose);\n\nexport const extractAccountIndexFromPath = extractSectionFromDerivationPath(\n DerivationPathDepth.Account\n);\n\nexport const extractAddressIndexFromPath = extractSectionFromDerivationPath(\n DerivationPathDepth.AddressIndex\n);\n\nexport function appendAddressIndexToPath(path: string, index: number) {\n const accountIndex = extractAccountIndexFromPath(path);\n if (!Number.isInteger(accountIndex)) throw new Error('Invalid path, must have account index');\n const assumedReceiveChangeIndex = 0;\n return `${path}/${assumedReceiveChangeIndex}/${index}`;\n}\n\nexport function extractFingerprintFromKeyOriginPath(keyOriginPath: string) {\n const fingerprint = keyOriginPath.split('/')[0];\n if (!isHexString(fingerprint)) throw new Error('Fingerprint must be a hexadecimal string');\n return fingerprint;\n}\n\n/**\n * @description\n * A key origin path refers to the identifier commonly used as part of the key\n * information provided as part of a Output Descriptor described in BIP-380. It\n * replaces the `m/` part of a derivation path with the master key fingerprint to which the\n * key it describes belongs.\n * @example `0a3fd8ef/84'/0'/0'`\n */\nexport function createKeyOriginPath(fingerprint: string, path: string) {\n if (!isHexString(fingerprint)) throw new Error('Fingerprint must be a hexadecimal string');\n return `${fingerprint}/${path.replace('m/', '')}`;\n}\n\nexport function validateKeyOriginPath(keyOriginPath: string) {\n if (keyOriginPath.includes('[') || keyOriginPath.includes(']'))\n throw new Error('Key origin path should not contain square brackets');\n\n if (!keyOriginPath.includes('/'))\n throw new Error('Key origin path must contain a fingerprint and derivation path');\n\n if (!isHexString(extractFingerprintFromKeyOriginPath(keyOriginPath)))\n throw new Error('Fingerprint must be a hexadecimal string');\n\n if (keyOriginPath.split('/').length < 4)\n throw new Error('Key origin path is too short. Should describe at least to the account level');\n\n return true;\n}\n\n/**\n * @description\n * Creates a descriptor with key origin and xpub or public key\n * @returns `[0a3fd8ef/84'/0'/0']xpuba1b…2c3`\n */\nexport function createDescriptor(keyOriginPath: string, key: string) {\n validateKeyOriginPath(keyOriginPath);\n return `[${keyOriginPath}]${key}`;\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/0']xpuba1b…2c3` -> `0a3fd8ef/84'/0'/0'`\n */\nexport function extractKeyOriginPathFromDescriptor(descriptor: string) {\n const keyOriginPath = descriptor.split(']')[0].replace('[', '');\n validateKeyOriginPath(keyOriginPath);\n return keyOriginPath;\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/0']xpuba1b…2c3` -> `m/84'/0'/0'`\n */\nexport function extractDerivationPathFromDescriptor(descriptor: string) {\n const keyOriginPath = extractKeyOriginPathFromDescriptor(descriptor);\n return 'm/' + keyOriginPath.split('/').slice(1).join('/');\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/0']xpuba1b…2c3` -> `0a3fd8ef`\n */\nexport function extractFingerprintFromDescriptor(descriptor: string) {\n return extractFingerprintFromKeyOriginPath(extractKeyOriginPathFromDescriptor(descriptor));\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/6']xpuba1b…2c3` -> `6`\n */\nexport function extractAccountIndexFromDescriptor(descriptor: string) {\n return extractAccountIndexFromPath(extractKeyOriginPathFromDescriptor(descriptor));\n}\n\n/**\n * @example `[0a3fd8ef/84'/0'/6']xpuba1b…2c3` -> `xpuba1b…2c3`\n */\nexport function extractKeyFromDescriptor(descriptor: string) {\n return descriptor.split(']')[1];\n}\n\nexport function keyOriginToDerivationPath(keyOrigin: string) {\n const [_fingerprint, ...remainingPath] = keyOrigin.split('/');\n return `m/${remainingPath.join('/')}`;\n}\n\nexport function decomposeDescriptor(descriptor: string) {\n return {\n descriptor,\n keyOrigin: extractKeyOriginPathFromDescriptor(descriptor),\n fingerprint: extractFingerprintFromDescriptor(descriptor),\n derivationPath: extractDerivationPathFromDescriptor(descriptor),\n accountIndex: extractAccountIndexFromDescriptor(descriptor),\n };\n}\n","import { HDKey } from '@scure/bip32';\nimport {\n mnemonicToSeed,\n generateMnemonic as scureGenerateMnemonic,\n validateMnemonic,\n} from '@scure/bip39';\nimport { wordlist } from '@scure/bip39/wordlists/english';\nimport memoize from 'just-memoize';\n\nimport { toHexString } from '@leather.io/utils';\n\nimport {\n DerivationPathDepth,\n createDescriptor,\n createKeyOriginPath,\n keyOriginToDerivationPath,\n} from './derivation-path-utils';\n\nexport function generateMnemonic() {\n return scureGenerateMnemonic(wordlist, 256);\n}\n\nexport async function deriveBip39SeedFromMnemonic(mnemonic: string, passphrase?: string) {\n return mnemonicToSeed(mnemonic, passphrase);\n}\n/** @deprecated Inaccurately named fn, use `deriveBip39SeedFromMnemonic` */\nexport const deriveBip39MnemonicFromSeed = deriveBip39SeedFromMnemonic;\n\nexport function deriveRootBip32Keychain(seed: Uint8Array) {\n return HDKey.fromMasterSeed(seed);\n}\n\nexport async function deriveRootKeychainFromMnemonic(mnemonic: string, passphrase?: string) {\n return deriveRootBip32Keychain(await deriveBip39SeedFromMnemonic(mnemonic, passphrase));\n}\n\nexport async function deriveChildKeychainFromMnemnonic(\n path: string,\n mnemonic: string,\n passphrase?: string\n) {\n const rootKeychain = deriveRootBip32Keychain(await mnemonicToSeed(mnemonic, passphrase));\n return rootKeychain.derive(keyOriginToDerivationPath(path));\n}\n\nexport const deriveKeychainFromXpub = memoize((xpub: string) => HDKey.fromExtendedKey(xpub));\n\n/**\n * Gets keychain fingerprint directly from mnemonic. This is useful for\n * referencing a mnemonic safely by an identifier.\n */\nexport async function getMnemonicRootKeyFingerprint(mnemonic: string, passphrase?: string) {\n const keychain = deriveRootBip32Keychain(await deriveBip39SeedFromMnemonic(mnemonic, passphrase));\n return toHexString(keychain.fingerprint);\n}\n\nexport function deriveKeychainExtendedPublicKeyDescriptor(rootKeychain: HDKey, path: string) {\n const masterFingerprint = toHexString(rootKeychain.fingerprint);\n const keyOriginPath = createKeyOriginPath(masterFingerprint, path);\n\n if (rootKeychain.depth !== DerivationPathDepth.Root)\n throw new Error('Cannot derive account keychain from non-root keychain');\n\n const accountKeychain = rootKeychain.derive(path);\n return createDescriptor(keyOriginPath, accountKeychain.publicExtendedKey);\n}\n\nexport function isValidMnemonicWord(word: string): boolean {\n return wordlist.includes(word);\n}\n\nexport function isValidMnemonic(mnemonic: string): boolean {\n return validateMnemonic(mnemonic, wordlist);\n}\n"],"mappings":"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","names":["DerivationPathDepth"]}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@leather.io/crypto",
|
|
3
3
|
"author": "leather.io",
|
|
4
4
|
"description": "Generic crypto utils package for Leather",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.6.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./dist/index.mjs"
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@scure/bip32": "1.4.0",
|
|
12
12
|
"@scure/bip39": "1.3.0",
|
|
13
|
-
"
|
|
13
|
+
"just-memoize": "2.2.0",
|
|
14
|
+
"@leather.io/utils": "0.16.0"
|
|
14
15
|
},
|
|
15
16
|
"devDependencies": {
|
|
16
|
-
"@vitest/coverage-istanbul": "0.34.6",
|
|
17
|
-
"@vitest/coverage-v8": "2.0.4",
|
|
18
17
|
"tsup": "8.1.0",
|
|
19
18
|
"vitest": "2.0.5"
|
|
20
19
|
},
|
|
@@ -28,6 +27,7 @@
|
|
|
28
27
|
"build": "tsup",
|
|
29
28
|
"build:watch": "tsup --watch --onSuccess 'tsup --dts-only'",
|
|
30
29
|
"prepublish": "pnpm build",
|
|
30
|
+
"test:coverage": "vitest run --coverage",
|
|
31
31
|
"test:unit": "vitest run",
|
|
32
32
|
"typecheck": "tsc --noEmit"
|
|
33
33
|
}
|