Skip to content

Commit 5382260

Browse files
committed
📄 docs: comment address namespace
1 parent b76e645 commit 5382260

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed

ts_src/address.ts

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
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+
*/
110
import { Network } from './networks';
211
import * as networks from './networks';
312
import * as payments from './payments';
413
import * as bscript from './script';
514
import { typeforce, tuple, Hash160bit, UInt8 } from './types';
615
import { bech32, bech32m } from 'bech32';
716
import * as bs58check from 'bs58check';
17+
18+
/** base58check decode result */
819
export 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 */
1327
export 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+
*/
5589
export 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+
*/
68139
export 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+
*/
93174
export 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+
*/
103194
export 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+
*/
116249
export 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+
*/
142296
export function toOutputScript(address: string, network?: Network): Buffer {
143297
network = network || networks.bitcoin;
144298

ts_src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as script from './script';
77
export { address, crypto, networks, payments, script };
88

99
export { Block } from './block';
10+
/** @hidden */
1011
export { TaggedHashPrefix } from './crypto';
1112
export {
1213
Psbt,
@@ -17,10 +18,12 @@ export {
1718
HDSigner,
1819
HDSignerAsync,
1920
} from './psbt';
21+
/** @hidden */
2022
export { OPS as opcodes } from './ops';
2123
export { Transaction } from './transaction';
22-
24+
/** @hidden */
2325
export { Network } from './networks';
26+
/** @hidden */
2427
export {
2528
Payment,
2629
PaymentCreator,

ts_src/psbt.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const DEFAULT_OPTS: PsbtOpts = {
9292
* There are 6 roles that this class fulfills. (Explained in BIP174)
9393
*
9494
* Creator: This can be done with `new Psbt()`
95+
*
9596
* Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`,
9697
* `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to
9798
* add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`,
@@ -102,20 +103,24 @@ const DEFAULT_OPTS: PsbtOpts = {
102103
* data for updateOutput.
103104
* For a list of what attributes should be what types. Check the bip174 library.
104105
* Also, check the integration tests for some examples of usage.
106+
*
105107
* Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input
106108
* information for your pubkey or pubkeyhash, and only sign inputs where it finds
107109
* your info. Or you can explicitly sign a specific input with signInput and
108110
* signInputAsync. For the async methods you can create a SignerAsync object
109111
* and use something like a hardware wallet to sign with. (You must implement this)
112+
*
110113
* Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)`
111114
* the psbt calling combine will always have precedence when a conflict occurs.
112115
* Combine checks if the internal bitcoin transaction is the same, so be sure that
113116
* all sequences, version, locktime, etc. are the same before combining.
117+
*
114118
* Input Finalizer: This role is fairly important. Not only does it need to construct
115119
* the input scriptSigs and witnesses, but it SHOULD verify the signatures etc.
116120
* Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()`
117121
* Running any finalize method will delete any data in the input(s) that are no longer
118122
* needed due to the finalized scripts containing the information.
123+
*
119124
* Transaction Extractor: This role will perform some checks before returning a
120125
* Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
121126
*/

0 commit comments

Comments
 (0)