1+ /**
2+ * bitcoin address decode and encode tools, include base58、bech32 and output script
3+ *
4+ * networks support bitcoin、litecoin、bitcoin testnet、litecoin testnet、bitcoin regtest、litecoin regtest and so on
5+ *
6+ * addresses support P2PKH、P2SH、P2WPKH、P2WSH、P2TR and so on
7+ *
8+ * @packageDocumentation
9+ */
110import { Network } from './networks' ;
211import * as networks from './networks' ;
312import * as payments from './payments' ;
413import * as bscript from './script' ;
514import { typeforce , tuple , Hash160bit , UInt8 } from './types' ;
615import { bech32 , bech32m } from 'bech32' ;
716import * as bs58check from 'bs58check' ;
17+
18+ /** base58check decode result */
819export interface Base58CheckResult {
20+ /** address hash */
921 hash : Buffer ;
22+ /** address version: 0x00 for P2PKH, 0x05 for P2SH */
1023 version : number ;
1124}
1225
26+ /** bech32 decode result */
1327export interface Bech32Result {
28+ /** address version: 0x00 for P2WPKH、P2WSH, 0x01 for P2TR*/
1429 version : number ;
30+ /** address prefix: bc for P2WPKH、P2WSH、P2TR */
1531 prefix : string ;
32+ /** address data:20 bytes for P2WPKH, 32 bytes for P2WSH、P2TR */
1633 data : Buffer ;
1734}
1835
@@ -52,6 +69,23 @@ function _toFutureSegwitAddress(output: Buffer, network: Network): string {
5269 return toBech32 ( data , version , network . bech32 ) ;
5370}
5471
72+ /**
73+ * decode address with base58 specification, return address version and address hash if valid
74+ * @example
75+ * ```ts
76+ * // valid case
77+ * fromBase58Check('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH')
78+ * // => {version: 0, hash: <Buffer 75 1e 76 e8 19 91 96 d4 54 94 1c 45 d1 b3 a3 23 f1 43 3b d6>}
79+ *
80+ * // invalid case: address is too short
81+ * fromBase58Check('7SeEnXWPaCCALbVrTnszCVGfRU8cGfx')
82+ * // => throw new TypeError('7SeEnXWPaCCALbVrTnszCVGfRU8cGfx is too short')
83+ *
84+ * // invalid case: address is too long
85+ * fromBase58Check('j9ywUkWg2fTQrouxxh5rSZhRvrjMkEUfuiKe')
86+ * // => throw new TypeError('j9ywUkWg2fTQrouxxh5rSZhRvrjMkEUfuiKe is too long')
87+ * ```
88+ */
5589export function fromBase58Check ( address : string ) : Base58CheckResult {
5690 const payload = Buffer . from ( bs58check . decode ( address ) ) ;
5791
@@ -65,6 +99,43 @@ export function fromBase58Check(address: string): Base58CheckResult {
6599 return { version, hash } ;
66100}
67101
102+ /**
103+ * decode address with bech32 specification, return address version、address prefix and address data if valid
104+ * @example
105+ * ```ts
106+ * // valid case
107+ * fromBech32('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4')
108+ * // => {version: 0, prefix: 'bc', data: <Buffer 75 1e 76 e8 19 91 96 d4 54 94 1c 45 d1 b3 a3 23 f1 43 3b d6>}
109+ *
110+ * // invalid case
111+ * fromBase58Check('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5')
112+ * // => Invalid checksum
113+ *
114+ * // invalid case
115+ * fromBase58Check('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7')
116+ * // => Mixed-case string
117+ *
118+ * // invalid case
119+ * fromBase58Check('tb1pw508d6qejxtdg4y5r3zarquvzkan')
120+ * // => Excess padding
121+ *
122+ * // invalid case
123+ * fromBase58Check('bc1zw508d6qejxtdg4y5r3zarvaryvq37eag7')
124+ * // => Excess padding
125+ *
126+ * // invalid case
127+ * fromBase58Check('bc1zw508d6qejxtdg4y5r3zarvaryvq37eag7')
128+ * // => Non-zero padding
129+ *
130+ * // invalid case
131+ * fromBase58Check('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv')
132+ * // => uses wrong encoding
133+ *
134+ * // invalid case
135+ * fromBase58Check('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd')
136+ * // => uses wrong encoding
137+ * ```
138+ */
68139export function fromBech32 ( address : string ) : Bech32Result {
69140 let result ;
70141 let version ;
@@ -90,6 +161,16 @@ export function fromBech32(address: string): Bech32Result {
90161 } ;
91162}
92163
164+ /**
165+ * encode address hash to base58 address with version
166+ *
167+ * @example
168+ * ```ts
169+ * // valid case
170+ * toBase58Check('751e76e8199196d454941c45d1b3a323f1433bd6', 0)
171+ * // => 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH
172+ * ```
173+ */
93174export function toBase58Check ( hash : Buffer , version : number ) : string {
94175 typeforce ( tuple ( Hash160bit , UInt8 ) , arguments ) ;
95176
@@ -100,6 +181,16 @@ export function toBase58Check(hash: Buffer, version: number): string {
100181 return bs58check . encode ( payload ) ;
101182}
102183
184+ /**
185+ * encode address hash to bech32 address with version and prefix
186+ *
187+ * @example
188+ * ```ts
189+ * // valid case
190+ * toBech32('000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433', 0, 'tb)
191+ * // => tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy
192+ * ```
193+ */
103194export function toBech32 (
104195 data : Buffer ,
105196 version : number ,
@@ -113,6 +204,48 @@ export function toBech32(
113204 : bech32m . encode ( prefix , words ) ;
114205}
115206
207+ /**
208+ * decode address from output script with network, return address if matched
209+ * @example
210+ * ```ts
211+ * // valid case
212+ * fromOutputScript('OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG', 'bicoin)
213+ * // => 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH
214+ *
215+ * // invalid case
216+ * fromOutputScript('031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95 OP_CHECKSIG', undefined)
217+ * // => has no matching Address
218+ *
219+ * // invalid case
220+ * fromOutputScript('OP_TRUE 032487c2a32f7c8d57d2a93906a6457afd00697925b0e6e145d89af6d3bca33016 02308673d16987eaa010e540901cc6fe3695e758c19f46ce604e174dac315e685a OP_2 OP_CHECKMULTISIG', undefined)
221+ * // => has no matching Address
222+ *
223+ * // invalid case
224+ * fromOutputScript('OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474', undefined)
225+ * // => has no matching Address
226+ *
227+ * // invalid case
228+ * fromOutputScript('OP_0 75', undefined)
229+ * // => has no matching Address
230+ *
231+ * // invalid case
232+ * fromOutputScript('OP_0 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd675', undefined)
233+ * // => has no matching Address
234+ *
235+ * // invalid case
236+ * fromOutputScript('OP_1 75', undefined)
237+ * // => has no matching Address
238+ *
239+ * // invalid case
240+ * fromOutputScript('OP_1 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd675', undefined)
241+ * // => has no matching Address
242+ *
243+ * // invalid case
244+ * fromOutputScript('OP_1 fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', undefined)
245+ * // => has no matching Address
246+ *
247+ * ```
248+ */
116249export function fromOutputScript ( output : Buffer , network ?: Network ) : string {
117250 // TODO: Network
118251 network = network || networks . bitcoin ;
@@ -139,6 +272,27 @@ export function fromOutputScript(output: Buffer, network?: Network): string {
139272 throw new Error ( bscript . toASM ( output ) + ' has no matching Address' ) ;
140273}
141274
275+ /**
276+ * encodes address to output script with network, return output script if address matched
277+ * @example
278+ * ```ts
279+ * // valid case
280+ * toOutputScript('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 'bicoin)
281+ * // => OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG
282+ *
283+ * // invalid case
284+ * toOutputScript('24kPZCmVgzfkpGdXExy56234MRHrsqQxNWE', undefined)
285+ * // => has no matching Script
286+ *
287+ * // invalid case
288+ * toOutputScript('BC1SW50QGDZ25J', { "bech32": "foo" })
289+ * // => has an invalid prefix
290+ *
291+ * // invalid case
292+ * toOutputScript('bc1rw5uspcuh', undefined)
293+ * // => has no matching Script
294+ * ```
295+ */
142296export function toOutputScript ( address : string , network ?: Network ) : Buffer {
143297 network = network || networks . bitcoin ;
144298
0 commit comments