@@ -4,9 +4,31 @@ const networks = require('./networks');
4
4
const payments = require ( './payments' ) ;
5
5
const bscript = require ( './script' ) ;
6
6
const types = require ( './types' ) ;
7
- const { bech32 } = require ( 'bech32' ) ;
7
+ const { bech32, bech32m } = require ( 'bech32' ) ;
8
8
const bs58check = require ( 'bs58check' ) ;
9
9
const typeforce = require ( 'typeforce' ) ;
10
+ const FUTURE_SEGWIT_MAX_SIZE = 40 ;
11
+ const FUTURE_SEGWIT_MIN_SIZE = 2 ;
12
+ const FUTURE_SEGWIT_MAX_VERSION = 16 ;
13
+ const FUTURE_SEGWIT_MIN_VERSION = 1 ;
14
+ const FUTURE_SEGWIT_VERSION_DIFF = 0x50 ;
15
+ function _toFutureSegwitAddress ( output , network ) {
16
+ const data = output . slice ( 2 ) ;
17
+ if (
18
+ data . length < FUTURE_SEGWIT_MIN_SIZE ||
19
+ data . length > FUTURE_SEGWIT_MAX_SIZE
20
+ )
21
+ throw new TypeError ( 'Invalid program length for segwit address' ) ;
22
+ const version = output [ 0 ] - FUTURE_SEGWIT_VERSION_DIFF ;
23
+ if (
24
+ version < FUTURE_SEGWIT_MIN_VERSION ||
25
+ version > FUTURE_SEGWIT_MAX_VERSION
26
+ )
27
+ throw new TypeError ( 'Invalid version for segwit address' ) ;
28
+ if ( output [ 1 ] !== data . length )
29
+ throw new TypeError ( 'Invalid script for segwit address' ) ;
30
+ return toBech32 ( data , version , network . bech32 ) ;
31
+ }
10
32
function fromBase58Check ( address ) {
11
33
const payload = bs58check . decode ( address ) ;
12
34
// TODO: 4.0.0, move to "toOutputScript"
@@ -18,10 +40,22 @@ function fromBase58Check(address) {
18
40
}
19
41
exports . fromBase58Check = fromBase58Check ;
20
42
function fromBech32 ( address ) {
21
- const result = bech32 . decode ( address ) ;
43
+ let result ;
44
+ let version ;
45
+ try {
46
+ result = bech32 . decode ( address ) ;
47
+ } catch ( e ) { }
48
+ if ( result ) {
49
+ version = result . words [ 0 ] ;
50
+ if ( version !== 0 ) throw new TypeError ( address + ' uses wrong encoding' ) ;
51
+ } else {
52
+ result = bech32m . decode ( address ) ;
53
+ version = result . words [ 0 ] ;
54
+ if ( version === 0 ) throw new TypeError ( address + ' uses wrong encoding' ) ;
55
+ }
22
56
const data = bech32 . fromWords ( result . words . slice ( 1 ) ) ;
23
57
return {
24
- version : result . words [ 0 ] ,
58
+ version,
25
59
prefix : result . prefix ,
26
60
data : Buffer . from ( data ) ,
27
61
} ;
@@ -38,7 +72,9 @@ exports.toBase58Check = toBase58Check;
38
72
function toBech32 ( data , version , prefix ) {
39
73
const words = bech32 . toWords ( data ) ;
40
74
words . unshift ( version ) ;
41
- return bech32 . encode ( prefix , words ) ;
75
+ return version === 0
76
+ ? bech32 . encode ( prefix , words )
77
+ : bech32m . encode ( prefix , words ) ;
42
78
}
43
79
exports . toBech32 = toBech32 ;
44
80
function fromOutputScript ( output , network ) {
@@ -56,6 +92,9 @@ function fromOutputScript(output, network) {
56
92
try {
57
93
return payments . p2wsh ( { output, network } ) . address ;
58
94
} catch ( e ) { }
95
+ try {
96
+ return _toFutureSegwitAddress ( output , network ) ;
97
+ } catch ( e ) { }
59
98
throw new Error ( bscript . toASM ( output ) + ' has no matching Address' ) ;
60
99
}
61
100
exports . fromOutputScript = fromOutputScript ;
@@ -83,7 +122,16 @@ function toOutputScript(address, network) {
83
122
return payments . p2wpkh ( { hash : decodeBech32 . data } ) . output ;
84
123
if ( decodeBech32 . data . length === 32 )
85
124
return payments . p2wsh ( { hash : decodeBech32 . data } ) . output ;
86
- }
125
+ } else if (
126
+ decodeBech32 . version >= FUTURE_SEGWIT_MIN_VERSION &&
127
+ decodeBech32 . version <= FUTURE_SEGWIT_MAX_VERSION &&
128
+ decodeBech32 . data . length >= FUTURE_SEGWIT_MIN_SIZE &&
129
+ decodeBech32 . data . length <= FUTURE_SEGWIT_MAX_SIZE
130
+ )
131
+ return bscript . compile ( [
132
+ decodeBech32 . version + FUTURE_SEGWIT_VERSION_DIFF ,
133
+ decodeBech32 . data ,
134
+ ] ) ;
87
135
}
88
136
}
89
137
throw new Error ( address + ' has no matching Script' ) ;
0 commit comments