@@ -6,6 +6,9 @@ module Functora.Bolt11
6
6
Hex (.. ),
7
7
inspectHex ,
8
8
Tag (.. ),
9
+ Feature (.. ),
10
+ FeatureName (.. ),
11
+ RequiredOrSupported (.. ),
9
12
isPaymentHash ,
10
13
Network (.. ),
11
14
Multiplier (.. ),
@@ -26,7 +29,7 @@ import Codec.Binary.Bech32 (Word5)
26
29
import qualified Codec.Binary.Bech32.Internal as Bech32
27
30
import Control.Applicative
28
31
import qualified Data.Attoparsec.Text as Atto
29
- import Data.Bits (shiftL , (.|.) )
32
+ import Data.Bits (shiftL , (.&.) , (. |.) )
30
33
import qualified Data.ByteString as BS
31
34
import qualified Data.ByteString.Base16 as B16
32
35
import qualified Data.ByteString.Builder as BS
@@ -82,11 +85,98 @@ data Tag
82
85
| MinFinalCltvExpiry Int
83
86
| OnchainFallback Btc. Address
84
87
| ExtraRouteInfo
85
- | FeatureBits [ Word5 ]
88
+ | Features [ Feature ]
86
89
| UnknownTag Int [Word5 ]
87
90
| UnparsedTag Int [Word5 ] String
88
91
deriving stock (Eq , Ord , Show , Generic )
89
92
93
+ data Feature = Feature
94
+ { featureBits :: Int ,
95
+ featureName :: FeatureName ,
96
+ featureRequiredOrSuported :: RequiredOrSupported
97
+ }
98
+ deriving stock (Eq , Ord , Show , Data , Generic )
99
+
100
+ data FeatureName
101
+ = Option_data_loss_protect
102
+ | Option_upfront_shutdown_script
103
+ | Gossip_queries
104
+ | Var_onion_optin
105
+ | Gossip_queries_ex
106
+ | Option_static_remotekey
107
+ | Payment_secret
108
+ | Basic_mpp
109
+ | Option_support_large_channel
110
+ | Option_anchors
111
+ | Option_route_blinding
112
+ | Option_shutdown_anysegwit
113
+ | Option_dual_fund
114
+ | Option_quiesce
115
+ | Option_onion_messages
116
+ | Option_channel_type
117
+ | Option_scid_alias
118
+ | Option_payment_metadata
119
+ | Option_zeroconf
120
+ | Unknown_feature
121
+ deriving stock (Eq , Ord , Show , Data , Generic )
122
+
123
+ parseFeatures :: [Word5 ] -> [Feature ]
124
+ parseFeatures [] = mempty
125
+ parseFeatures ws = sort . nubOrd $ do
126
+ (w, idx) <- zip ws [0 .. ]
127
+ i <- [0 .. bsize - 1 ]
128
+ if fromEnum w .&. shiftL 1 i == 0
129
+ then mempty
130
+ else do
131
+ let end = length ws - 1
132
+ let bit = (end - idx) * bsize + i
133
+ pure $ parseFeature bit
134
+ where
135
+ bsize :: Int
136
+ bsize = 5
137
+
138
+ parseFeature :: Int -> Feature
139
+ parseFeature bit =
140
+ Feature
141
+ { featureBits = bit,
142
+ featureName = name,
143
+ featureRequiredOrSuported =
144
+ if even bit
145
+ then Required
146
+ else Supported
147
+ }
148
+ where
149
+ bits :: [Int ] -> Bool
150
+ bits = elem bit
151
+ name :: FeatureName
152
+ name =
153
+ if
154
+ | bits [0 , 1 ] -> Option_data_loss_protect
155
+ | bits [4 , 5 ] -> Option_upfront_shutdown_script
156
+ | bits [6 , 7 ] -> Gossip_queries
157
+ | bits [8 , 9 ] -> Var_onion_optin
158
+ | bits [10 , 11 ] -> Gossip_queries_ex
159
+ | bits [12 , 13 ] -> Option_static_remotekey
160
+ | bits [14 , 15 ] -> Payment_secret
161
+ | bits [16 , 17 ] -> Basic_mpp
162
+ | bits [18 , 19 ] -> Option_support_large_channel
163
+ | bits [22 , 23 ] -> Option_anchors
164
+ | bits [24 , 25 ] -> Option_route_blinding
165
+ | bits [26 , 27 ] -> Option_shutdown_anysegwit
166
+ | bits [28 , 29 ] -> Option_dual_fund
167
+ | bits [34 , 35 ] -> Option_quiesce
168
+ | bits [38 , 39 ] -> Option_onion_messages
169
+ | bits [44 , 45 ] -> Option_channel_type
170
+ | bits [46 , 47 ] -> Option_scid_alias
171
+ | bits [48 , 49 ] -> Option_payment_metadata
172
+ | bits [50 , 51 ] -> Option_zeroconf
173
+ | otherwise -> Unknown_feature
174
+
175
+ data RequiredOrSupported
176
+ = Required
177
+ | Supported
178
+ deriving stock (Eq , Ord , Show , Data , Generic )
179
+
90
180
isPaymentHash :: Tag -> Bool
91
181
isPaymentHash PaymentHash {} = True
92
182
isPaymentHash _ = False
@@ -221,10 +311,14 @@ parseHrp = do
221
311
amt <- optional parseHrpAmount
222
312
pure (Bolt11Hrp net amt)
223
313
314
+ w5w8 :: [Word5 ] -> Either String [Word8 ]
315
+ w5w8 =
316
+ maybe (Left " Non-Base256 bits" ) Right
317
+ . Bech32. toBase256
318
+
224
319
w5bs :: [Word5 ] -> Either String ByteString
225
320
w5bs =
226
- maybe (Left " Non-Base256 bits" ) (Right . BS. pack)
227
- . Bech32. toBase256
321
+ fmap BS. pack . w5w8
228
322
229
323
w5hex :: [Word5 ] -> Either String Hex
230
324
w5hex =
@@ -299,7 +393,7 @@ parseTag net ws@(t0 : d1 : d2 : rest)
299
393
24 -> MinFinalCltvExpiry $ w5int dat
300
394
9 -> mkt OnchainFallback $ w5addr net dat
301
395
3 -> ExtraRouteInfo
302
- 5 -> FeatureBits dat
396
+ 5 -> Features $ parseFeatures dat
303
397
n -> UnknownTag n dat
304
398
305
399
data MSig
0 commit comments