UNPKG

6.26 kBJavaScriptView Raw
1/**
2 * Bitcoin Address
3 * ===============
4 *
5 * A bitcoin address. Normal use cases:
6 * const address = new Address().fromPubKey(pubKey)
7 * const address = new Address().fromString(string)
8 * const string = address.toString()
9 * const script = address.toTxOutScript()
10 * const isValid = Address.isValid(string)
11 *
12 * Can also do testnet:
13 * const address = Address.Testnet()
14 *
15 * Note that an Address and an Addr are two completely different things. An
16 * Address is what you send bitcoin to. An Addr is an ip address and port that
17 * you connect to over the internet.
18 */
19'use strict'
20
21import { Base58Check } from './base-58-check'
22import { Constants } from './constants'
23import { Hash } from './hash'
24import { OpCode } from './op-code'
25import { PubKey } from './pub-key'
26import { PrivKey } from './priv-key'
27import { Script } from './script'
28import { Struct } from './struct'
29import { Workers } from './workers'
30
31class Address extends Struct {
32 constructor (versionByteNum, hashBuf, constants = null) {
33 super({ versionByteNum, hashBuf })
34 constants = constants || Constants.Default.Address
35 this.Constants = constants
36 }
37
38 fromBuffer (buf) {
39 if (buf.length !== 1 + 20) {
40 throw new Error('address buffers must be exactly 21 bytes')
41 }
42 if (
43 buf[0] !== this.Constants.pubKeyHash
44 ) {
45 throw new Error('address: invalid versionByteNum byte')
46 }
47 this.versionByteNum = buf[0]
48 this.hashBuf = buf.slice(1)
49 return this
50 }
51
52 fromPubKeyHashBuf (hashBuf) {
53 this.hashBuf = hashBuf
54 this.versionByteNum = this.Constants.pubKeyHash
55 return this
56 }
57
58 static fromPubKeyHashBuf (hashBuf) {
59 return new this().fromPubKeyHashBuf(hashBuf)
60 }
61
62 fromPubKey (pubKey) {
63 const hashBuf = Hash.sha256Ripemd160(pubKey.toBuffer())
64 return this.fromPubKeyHashBuf(hashBuf)
65 }
66
67 static fromPubKey (pubKey) {
68 return new this().fromPubKey(pubKey)
69 }
70
71 async asyncFromPubKey (pubKey) {
72 const args = [pubKey]
73 const workersResult = await Workers.asyncObjectMethod(
74 this,
75 'fromPubKey',
76 args
77 )
78 return this.fromFastBuffer(workersResult.resbuf)
79 }
80
81 static asyncFromPubKey (pubKey) {
82 return new this().asyncFromPubKey(pubKey)
83 }
84
85 fromPrivKey (privKey) {
86 const pubKey = new PubKey().fromPrivKey(privKey)
87 const hashBuf = Hash.sha256Ripemd160(pubKey.toBuffer())
88 return this.fromPubKeyHashBuf(hashBuf)
89 }
90
91 static fromPrivKey (privKey) {
92 return new this().fromPrivKey(privKey)
93 }
94
95 async asyncFromPrivKey (privKey) {
96 const args = [privKey]
97 const workersResult = await Workers.asyncObjectMethod(
98 this,
99 'fromPrivKey',
100 args
101 )
102 return this.fromFastBuffer(workersResult.resbuf)
103 }
104
105 static asyncFromPrivKey (privKey) {
106 return new this().fromPrivKey(privKey)
107 }
108
109 fromRandom () {
110 const randomPrivKey = new PrivKey().fromRandom()
111 return this.fromPrivKey(randomPrivKey)
112 }
113
114 static fromRandom () {
115 return new this().fromRandom()
116 }
117
118 async asyncFromRandom () {
119 const args = []
120 const workersResult = await Workers.asyncObjectMethod(
121 this,
122 'fromRandom',
123 args
124 )
125 return this.fromFastBuffer(workersResult.resbuf)
126 }
127
128 static asyncFromRandom () {
129 return new this().fromRandom()
130 }
131
132 fromString (str) {
133 const buf = Base58Check.decode(str)
134 return this.fromBuffer(buf)
135 }
136
137 async asyncFromString (str) {
138 const args = [str]
139 const workersResult = await Workers.asyncObjectMethod(
140 this,
141 'fromString',
142 args
143 )
144 return this.fromFastBuffer(workersResult.resbuf)
145 }
146
147 static asyncFromString (str) {
148 return new this().asyncFromString(str)
149 }
150
151 static isValid (addrstr) {
152 let address
153 try {
154 address = new Address().fromString(addrstr)
155 } catch (e) {
156 return false
157 }
158 return address.isValid()
159 }
160
161 isValid () {
162 try {
163 this.validate()
164 return true
165 } catch (e) {
166 return false
167 }
168 }
169
170 toTxOutScript () {
171 const script = new Script()
172 script.writeOpCode(OpCode.OP_DUP)
173 script.writeOpCode(OpCode.OP_HASH160)
174 script.writeBuffer(this.hashBuf)
175 script.writeOpCode(OpCode.OP_EQUALVERIFY)
176 script.writeOpCode(OpCode.OP_CHECKSIG)
177
178 return script
179 }
180
181 fromTxInScript (script) {
182 const pubKeyHashBuf = Hash.sha256Ripemd160(script.chunks[1].buf || Buffer.from('00'.repeat(32), 'hex'))
183 return this.fromPubKeyHashBuf(pubKeyHashBuf)
184 }
185
186 static fromTxInScript (script) {
187 return new this().fromTxInScript(script)
188 }
189
190 fromTxOutScript (script) {
191 return this.fromPubKeyHashBuf(script.chunks[2].buf)
192 }
193
194 static fromTxOutScript (script) {
195 return new this().fromTxOutScript(script)
196 }
197
198 toBuffer () {
199 const versionByteBuf = Buffer.from([this.versionByteNum])
200 const buf = Buffer.concat([versionByteBuf, this.hashBuf])
201 return buf
202 }
203
204 toJSON () {
205 const json = {}
206 if (this.hashBuf) {
207 json.hashBuf = this.hashBuf.toString('hex')
208 }
209 if (typeof this.versionByteNum !== 'undefined') {
210 json.versionByteNum = this.versionByteNum
211 }
212 return json
213 }
214
215 fromJSON (json) {
216 if (json.hashBuf) {
217 this.hashBuf = Buffer.from(json.hashBuf, 'hex')
218 }
219 if (typeof json.versionByteNum !== 'undefined') {
220 this.versionByteNum = json.versionByteNum
221 }
222 return this
223 }
224
225 toString () {
226 return Base58Check.encode(this.toBuffer())
227 }
228
229 async asyncToString () {
230 const args = []
231 const workersResult = await Workers.asyncObjectMethod(
232 this,
233 'toString',
234 args
235 )
236 return JSON.parse(workersResult.resbuf.toString())
237 }
238
239 validate () {
240 if (!Buffer.isBuffer(this.hashBuf) || this.hashBuf.length !== 20) {
241 throw new Error('hashBuf must be a buffer of 20 bytes')
242 }
243 if (
244 this.versionByteNum !== this.Constants.pubKeyHash
245 ) {
246 throw new Error('invalid versionByteNum')
247 }
248 return this
249 }
250}
251
252Address.Mainnet = class extends Address {
253 constructor (versionByteNum, hashBuf) {
254 super(versionByteNum, hashBuf, Constants.Mainnet.Address)
255 }
256}
257
258Address.Testnet = class extends Address {
259 constructor (versionByteNum, hashBuf) {
260 super(versionByteNum, hashBuf, Constants.Testnet.Address)
261 }
262}
263
264export { Address }