@@ -114,17 +114,19 @@ export function addIPCaveatToMacaroon(macaroonBase64: string, ip: string): strin
114114 return bytesToBase64 ( macaroon . exportBinary ( ) ) ;
115115}
116116
117- const PURPOSE_WRAPPED_P2WKH = 49 ;
118- const PURPOSE_P2WKH = 84 ;
119- const PURPOSE_P2TR = 86 ;
120- const PURPOSE_ALL_OTHERS = 1017 ;
117+ export const PURPOSE_WRAPPED_P2WKH = 49 ;
118+ export const PURPOSE_P2WKH = 84 ;
119+ export const PURPOSE_P2TR = 86 ;
120+ export const PURPOSE_ALL_OTHERS = 1017 ;
121121
122- type ExtendedKeyPurpose =
122+ export type ExtendedKeyPurpose =
123123 | typeof PURPOSE_WRAPPED_P2WKH
124124 | typeof PURPOSE_P2WKH
125125 | typeof PURPOSE_P2TR
126126 | typeof PURPOSE_ALL_OTHERS ;
127127
128+ export type ExtendedKeyAddressPurpose = typeof PURPOSE_WRAPPED_P2WKH | typeof PURPOSE_P2WKH | typeof PURPOSE_P2TR ;
129+
128130/**
129131 * Converts an extended public key (xpub) to the appropriate prefix (ypub, vpub, etc.) based on its purpose and network.
130132 */
@@ -151,6 +153,43 @@ function convertXpubPrefix(xpub: string, purpose: ExtendedKeyPurpose, isMainnet:
151153 return bs58check . encode ( data ) ;
152154}
153155
156+ /**
157+ * Converts a prefix related to purpose and network (ypub, vpub, etc.) to extended public key (xpub).
158+ */
159+ export function revertXpubPrefix ( xpub : string , purpose : ExtendedKeyPurpose , isMainnet : boolean ) : string {
160+ // If the purpose is P2TR or ALL_OTHERS, the key is already in the standard format (xpub/tpub),
161+ // so we return it unmodified. This is the same bypass condition.
162+ if ( purpose === PURPOSE_P2TR || purpose === PURPOSE_ALL_OTHERS ) {
163+ return xpub ;
164+ }
165+
166+ // 1. Decode the extended public key to get the raw bytes
167+ const data = bs58check . decode ( xpub ) ;
168+
169+ let versionBytes : Buffer ;
170+
171+ // 2. Determine the standard prefix (xpub/tpub) based on the network
172+ switch ( purpose ) {
173+ case PURPOSE_WRAPPED_P2WKH :
174+ case PURPOSE_P2WKH :
175+ // All standard, non-SegWit-specific keys use the same prefix (xpub for mainnet, tpub for testnet)
176+ versionBytes = isMainnet
177+ ? Buffer . from ( [ 0x04 , 0x88 , 0xb2 , 0x1e ] ) // xpub
178+ : Buffer . from ( [ 0x04 , 0x35 , 0x87 , 0xcf ] ) ; // tpub
179+ break ;
180+ default :
181+ // This case should ideally not be hit if the input key is one of the converted types
182+ throw new Error ( 'Unsupported purpose for reversal' ) ;
183+ }
184+
185+ // 3. Overwrite the existing prefix (ypub, zpub, upub, or vpub)
186+ // with the standard xpub or tpub prefix.
187+ versionBytes . copy ( data , 0 , 0 , 4 ) ;
188+
189+ // 4. Encode the modified byte data back to a Base58Check string
190+ return bs58check . encode ( data ) ;
191+ }
192+
154193/**
155194 * Derives watch-only accounts from the master HD node for the given purposes and network.
156195 */
0 commit comments