File tree Expand file tree Collapse file tree 4 files changed +52
-1
lines changed Expand file tree Collapse file tree 4 files changed +52
-1
lines changed Original file line number Diff line number Diff line change @@ -19,6 +19,8 @@ export type BIP44Depth = MinBIP44Depth | 1 | 2 | 3 | 4 | MaxBIP44Depth;
1919// always "0". Here's an example Ethereum HD path for account "0":
2020// m / 44' / 60' / 0' / 0 / 0
2121
22+ export type UnprefixedNode = `${number } '`;
23+
2224export type AnonymizedBIP39Node = 'm' ;
2325export type BIP39StringNode = `bip39:${string } `;
2426export type BIP39Node = BIP39StringNode | Uint8Array ;
@@ -35,6 +37,13 @@ export const BIP44PurposeNodeToken = `bip32:44'`;
3537
3638export const UNPREFIXED_PATH_REGEX = / ^ \d + $ / u;
3739
40+ /**
41+ * e.g.
42+ * - 0
43+ * - 0'
44+ */
45+ export const UNPREFIXED_BIP_32_PATH_REGEX = / ^ (?< index > \d + ) ' ? $ / u;
46+
3847/**
3948 * e.g.
4049 * - bip32:0
Original file line number Diff line number Diff line change @@ -28,4 +28,4 @@ export {
2828 getBIP44AddressKeyDeriver ,
2929} from './BIP44CoinTypeNode' ;
3030export * from './constants' ;
31- export type { CoinTypeToAddressIndices } from './utils' ;
31+ export type { CoinTypeToAddressIndices , isValidBIP32Path } from './utils' ;
Original file line number Diff line number Diff line change @@ -23,6 +23,7 @@ import {
2323 decodeBase58check ,
2424 mnemonicPhraseToBytes ,
2525 getBytesUnsafe ,
26+ isValidBIP32Path ,
2627} from './utils' ;
2728
2829// Inputs used for testing non-negative integers
@@ -197,6 +198,24 @@ describe('isValidBIP32Index', () => {
197198 } ) ;
198199} ) ;
199200
201+ describe ( 'isValidBIP32Path' , ( ) => {
202+ it ( 'returns true if the path is valid' , ( ) => {
203+ expect ( isValidBIP32Path ( `0` ) ) . toBe ( true ) ;
204+ expect ( isValidBIP32Path ( `0'` ) ) . toBe ( true ) ;
205+ expect ( isValidBIP32Path ( `1` ) ) . toBe ( true ) ;
206+ expect ( isValidBIP32Path ( `1'` ) ) . toBe ( true ) ;
207+ expect ( isValidBIP32Path ( `1000` ) ) . toBe ( true ) ;
208+ expect ( isValidBIP32Path ( `1000'` ) ) . toBe ( true ) ;
209+ } ) ;
210+
211+ it . each ( [ 'foo' , `123''` , `'123'` , `123'/456'` ] ) (
212+ 'returns false if the index is invalid' ,
213+ ( input ) => {
214+ expect ( isValidBIP32Path ( input ) ) . toBe ( false ) ;
215+ } ,
216+ ) ;
217+ } ) ;
218+
200219describe ( 'isHardened' , ( ) => {
201220 it ( 'returns true if the index is hardened' , ( ) => {
202221 expect ( isHardened ( `0'` ) ) . toBe ( true ) ;
Original file line number Diff line number Diff line change @@ -13,6 +13,8 @@ import {
1313 HardenedBIP32Node ,
1414 MAX_BIP_32_INDEX ,
1515 UnhardenedBIP32Node ,
16+ UNPREFIXED_BIP_32_PATH_REGEX ,
17+ UnprefixedNode ,
1618} from './constants' ;
1719import { curves , SupportedCurve } from './curves' ;
1820
@@ -170,6 +172,27 @@ export function isValidBIP32Index(index: number): boolean {
170172 return isValidInteger ( index ) && index <= MAX_BIP_32_INDEX ;
171173}
172174
175+ /**
176+ * Check if the value is a valid BIP-32 path, i.e., a string of the form
177+ * `0'`.
178+ *
179+ * @param path - The BIP-32 path to test.
180+ * @returns Whether the path is a valid BIP-32 path.
181+ */
182+ export function isValidBIP32Path ( path : string ) : path is UnprefixedNode {
183+ if ( typeof path !== 'string' ) {
184+ return false ;
185+ }
186+
187+ const match = path . match ( UNPREFIXED_BIP_32_PATH_REGEX ) ;
188+ if ( ! match ?. groups ) {
189+ return false ;
190+ }
191+
192+ const index = parseInt ( match . groups . index , 10 ) ;
193+ return isValidBIP32Index ( index ) ;
194+ }
195+
173196/**
174197 * Check if the value is a hardened BIP-32 index. This only checks if the value
175198 * ends with a `'` character, and does not validate that the index is a valid
You can’t perform that action at this time.
0 commit comments