1
1
module App.Widgets.Bolt11
2
- ( bolt11 ,
2
+ ( bolt11Viewer ,
3
+ evalBolt11 ,
3
4
)
4
5
where
5
6
6
7
import App.Types
7
8
import qualified Bitcoin.Address as Btc
8
9
import qualified Data.Aeson as A
10
+ import Data.Bitraversable (bimapM )
9
11
import qualified Data.ByteString.Base16 as B16
10
12
import qualified Data.ByteString.Lazy as BL
11
13
import qualified Data.Text.Encoding as T
@@ -14,25 +16,113 @@ import Functora.Miso.Prelude
14
16
import qualified Functora.Miso.Widgets.FieldPairs as FieldPairs
15
17
import qualified Functora.Miso.Widgets.Header as Header
16
18
import qualified Functora.Prelude as Prelude
17
- import Type.Reflection
18
19
import qualified Prelude
19
20
20
- bolt11 :: Model -> [View Action ]
21
- bolt11 st =
22
- parserWidget rawLn ln
23
- <> (if isRight ln then parserWidget rawLn rh else mempty )
24
- <> parserWidget rawR r
25
- <> fromRight mempty (verifierWidget [rawLn, rawR] <$> rh <*> r)
26
- <> either (const mempty ) (invoiceWidget st) ln
27
- <> either
28
- (const mempty )
29
- (\ bsR -> if bsR == mempty then mempty else preimageWidget st rawR bsR)
30
- r
21
+ bolt11Viewer :: Model -> [View Action ]
22
+ bolt11Viewer st =
23
+ success
24
+ ( pairs st mempty
25
+ $ # modelState
26
+ . # stDoc
27
+ . # stDocSuccessViewer
28
+ )
29
+ <> failure
30
+ ( pairs st mempty
31
+ $ # modelState
32
+ . # stDoc
33
+ . # stDocFailureViewer
34
+ )
35
+ <> pairs
36
+ st
37
+ ( Header. headerViewer " Invoice Details"
38
+ )
39
+ ( # modelState . # stDoc . # stDocLnInvoiceViewer
40
+ )
41
+ <> pairs
42
+ st
43
+ ( Header. headerViewer " Preimage Details"
44
+ )
45
+ ( # modelState . # stDoc . # stDocLnPreimageViewer
46
+ )
47
+
48
+ pairs ::
49
+ ( Foldable1 f
50
+ ) =>
51
+ Model ->
52
+ [View Action ] ->
53
+ ATraversal' Model [FieldPair DynamicField f ] ->
54
+ [View Action ]
55
+ pairs st header optic =
56
+ if null widget
57
+ then mempty
58
+ else header <> widget
59
+ where
60
+ widget =
61
+ FieldPairs. fieldPairsViewer
62
+ FieldPairs. Args
63
+ { FieldPairs. argsModel = st,
64
+ FieldPairs. argsOptic = optic,
65
+ FieldPairs. argsAction = PushUpdate . Instant
66
+ }
67
+
68
+ pair :: MisoString -> MisoString -> FieldPair DynamicField Identity
69
+ pair x =
70
+ newFieldPairId x
71
+ . DynamicFieldText
72
+
73
+ success :: [View Action ] -> [View Action ]
74
+ success = css " app-success"
75
+
76
+ failure :: [View Action ] -> [View Action ]
77
+ failure = css " app-failure"
78
+
79
+ css :: MisoString -> [View action ] -> [View action ]
80
+ css x = fmap $ \ case
81
+ Node x0 x1 x2 x3 x4 -> Node x0 x1 x2 (class_ x : x3) x4
82
+ html -> html
83
+
84
+ inspectTimestamp :: Int -> MisoString
85
+ inspectTimestamp =
86
+ inspect
87
+ . posixSecondsToUTCTime
88
+ . Prelude. fromInteger
89
+ . from @ Int @ Integer
90
+
91
+ evalBolt11 :: (MonadIO m ) => StDoc Unique -> m (StDoc Unique )
92
+ evalBolt11 st = do
93
+ lnFields <-
94
+ if rawLn == mempty
95
+ then pure $ Right mempty
96
+ else bimapM plainM (mapM identityToUnique . invoiceFields) ln
97
+ preFields <-
98
+ if rawR == mempty
99
+ then pure $ Right mempty
100
+ else bimapM plainM (mapM identityToUnique . preimageFields rawR) r
101
+ verifierFields <-
102
+ if any @ [MisoString ] (== mempty ) [rawLn, rawR]
103
+ then pure $ Right mempty
104
+ else case verifyPreimage <$> rh <*> r of
105
+ Left {} -> pure $ Right mempty
106
+ Right x -> bimapM plainM plainM x
107
+ pure
108
+ $ st
109
+ & # stDocSuccessViewer
110
+ %~ mergeFieldPairs (fromRight mempty verifierFields)
111
+ & # stDocFailureViewer
112
+ %~ mergeFieldPairs
113
+ ( fromLeft mempty lnFields
114
+ <> fromLeft mempty preFields
115
+ <> fromLeft mempty verifierFields
116
+ )
117
+ & # stDocLnInvoiceViewer
118
+ %~ mergeFieldPairs (fromRight mempty lnFields)
119
+ & # stDocLnPreimageViewer
120
+ %~ mergeFieldPairs (fromRight mempty preFields)
31
121
where
32
122
rawLn :: MisoString
33
- rawLn = st ^. # modelState . # stDoc . # stDocLnInvoice . # fieldOutput
123
+ rawLn = st ^. # stDocLnInvoice . # fieldOutput
34
124
rawR :: MisoString
35
- rawR = st ^. # modelState . # stDoc . # stDocLnPreimage . # fieldOutput
125
+ rawR = st ^. # stDocLnPreimage . # fieldOutput
36
126
ln :: Either MisoString B11. Bolt11
37
127
ln =
38
128
first (mappend " Bad invoice - " . from @ Prelude. String @ MisoString )
@@ -43,55 +133,65 @@ bolt11 st =
43
133
r :: Either MisoString ByteString
44
134
r = parsePreimage rawR
45
135
46
- parserWidget :: MisoString -> Either MisoString a -> [View Action ]
47
- parserWidget src = \ case
48
- Left e | src /= mempty -> failure e
49
- _ -> mempty
136
+ plainM :: (MonadIO m ) => MisoString -> m [FieldPair DynamicField Unique ]
137
+ plainM =
138
+ fmap (: mempty ) . newFieldPair mempty . DynamicFieldText
50
139
51
- verifierWidget :: [MisoString ] -> ByteString -> ByteString -> [View Action ]
52
- verifierWidget src rh r =
53
- if any (== mempty ) src
54
- then mempty
55
- else
56
- if rh == sha256Hash r
57
- then success " The preimage matches the invoice"
58
- else failure " The preimage does not match the invoice"
59
-
60
- invoiceWidget :: Model -> B11. Bolt11 -> [View Action ]
61
- invoiceWidget st ln =
62
- Header. headerViewer " Invoice Details"
63
- <> pairs
64
- st
65
- ( [ pair " Network"
66
- $ case B11. bolt11HrpNet $ B11. bolt11Hrp ln of
67
- B11. BitcoinMainnet -> " Bitcoin Mainnet"
68
- B11. BitcoinTestnet -> " Bitcoin Testnet"
69
- B11. BitcoinRegtest -> " Bitcoin Regtest"
70
- B11. BitcoinSignet -> " Bitcoin Signet" ,
71
- pair " Amount"
72
- . maybe " 0" B11. inspectBolt11HrpAmt
73
- . B11. bolt11HrpAmt
74
- $ B11. bolt11Hrp ln,
75
- pair " Created At"
76
- . inspectTimestamp
77
- $ B11. bolt11Timestamp ln
78
- ]
79
- <> ( B11. bolt11Tags ln
80
- >>= invoiceTag ln
81
- )
82
- <> [ pair " Signature"
83
- . B11. inspectHex
84
- $ B11. bolt11SigVal sig,
85
- pair " Pubkey Recovery Flag"
86
- . inspect
87
- $ B11. bolt11SigRecoveryFlag sig
88
- ]
89
- )
140
+ parsePreimage :: MisoString -> Either MisoString ByteString
141
+ parsePreimage rawR =
142
+ case B16. decode . T. encodeUtf8 $ from @ MisoString @ Prelude. Text rawR of
143
+ (r, " " ) -> Right r
144
+ (_, e) ->
145
+ Left
146
+ $ " Bad preimage - non hex leftover "
147
+ <> from @ Prelude. String @ MisoString (Prelude. show e)
148
+
149
+ parsePreimageHash :: B11. Bolt11 -> Either MisoString ByteString
150
+ parsePreimageHash ln =
151
+ case find B11. isPaymentHash $ B11. bolt11Tags ln of
152
+ Just (B11. PaymentHash (B11. Hex rh)) -> Right rh
153
+ _ -> Left " Bad invoice - no preimage hash"
154
+
155
+ verifyPreimage ::
156
+ ByteString ->
157
+ ByteString ->
158
+ Either MisoString MisoString
159
+ verifyPreimage rh r =
160
+ if rh == sha256Hash r
161
+ then Right " The preimage matches the invoice"
162
+ else Left " The preimage does not match the invoice"
163
+
164
+ invoiceFields :: B11. Bolt11 -> [FieldPair DynamicField Identity ]
165
+ invoiceFields ln =
166
+ [ pair " Network"
167
+ $ case B11. bolt11HrpNet $ B11. bolt11Hrp ln of
168
+ B11. BitcoinMainnet -> " Bitcoin Mainnet"
169
+ B11. BitcoinTestnet -> " Bitcoin Testnet"
170
+ B11. BitcoinRegtest -> " Bitcoin Regtest"
171
+ B11. BitcoinSignet -> " Bitcoin Signet" ,
172
+ pair " Amount"
173
+ . maybe " 0" B11. inspectBolt11HrpAmt
174
+ . B11. bolt11HrpAmt
175
+ $ B11. bolt11Hrp ln,
176
+ pair " Created At"
177
+ . inspectTimestamp
178
+ $ B11. bolt11Timestamp ln
179
+ ]
180
+ <> ( B11. bolt11Tags ln
181
+ >>= invoiceFieldsTag ln
182
+ )
183
+ <> [ pair " Signature"
184
+ . B11. inspectHex
185
+ $ B11. bolt11SigVal sig,
186
+ pair " Pubkey Recovery Flag"
187
+ . inspect
188
+ $ B11. bolt11SigRecoveryFlag sig
189
+ ]
90
190
where
91
191
sig = B11. bolt11Signature ln
92
192
93
- invoiceTag :: B11. Bolt11 -> B11. Tag -> [FieldPair DynamicField Identity ]
94
- invoiceTag ln = \ case
193
+ invoiceFieldsTag :: B11. Bolt11 -> B11. Tag -> [FieldPair DynamicField Identity ]
194
+ invoiceFieldsTag ln = \ case
95
195
B11. PaymentHash x -> hex " Preimage Hash" x
96
196
B11. PaymentSecret x -> hex " Payment Secret" x
97
197
B11. Description x -> pure . pair " Description" $ inspect x
@@ -131,88 +231,8 @@ invoiceTag ln = \case
131
231
. pair x
132
232
. B11. inspectHex
133
233
134
- preimageWidget :: Model -> MisoString -> ByteString -> [View Action ]
135
- preimageWidget st rawR r =
136
- Header. headerViewer " Preimage Details"
137
- <> pairs
138
- st
139
- [ pair " Preimage" rawR,
140
- pair " Preimage Hash" . inspect @ ByteString $ sha256Hash r
141
- ]
142
-
143
- parsePreimage :: MisoString -> Either MisoString ByteString
144
- parsePreimage rawR =
145
- case B16. decode . T. encodeUtf8 $ from @ MisoString @ Prelude. Text rawR of
146
- (r, " " ) -> Right r
147
- (_, e) ->
148
- Left
149
- $ " Bad preimage - non hex leftover "
150
- <> from @ Prelude. String @ MisoString (Prelude. show e)
151
-
152
- parsePreimageHash :: B11. Bolt11 -> Either MisoString ByteString
153
- parsePreimageHash ln =
154
- case find B11. isPaymentHash $ B11. bolt11Tags ln of
155
- Just (B11. PaymentHash (B11. Hex rh)) -> Right rh
156
- _ -> Left " Bad invoice - no preimage hash"
157
-
158
- pair :: MisoString -> MisoString -> FieldPair DynamicField Identity
159
- pair x =
160
- newFieldPairId x
161
- . DynamicFieldText
162
-
163
- pairs ::
164
- ( Typeable model ,
165
- Foldable1 f
166
- ) =>
167
- model ->
168
- [FieldPair DynamicField f ] ->
169
- [View Action ]
170
- pairs st raw =
171
- case typeOf st `eqTypeRep` typeRep @ Model of
172
- Just HRefl ->
173
- FieldPairs. fieldPairsViewer
174
- FieldPairs. Args
175
- { FieldPairs. argsModel = st,
176
- FieldPairs. argsOptic = constTraversal xs,
177
- FieldPairs. argsAction = PushUpdate . Instant
178
- }
179
- Nothing ->
180
- FieldPairs. fieldPairsViewer
181
- FieldPairs. Args
182
- { FieldPairs. argsModel = st,
183
- FieldPairs. argsOptic = constTraversal xs,
184
- FieldPairs. argsAction =
185
- \ fun -> PushUpdate . Instant $ \ next -> do
186
- void $ fun st
187
- pure next
188
- }
189
- where
190
- xs =
191
- filter
192
- ( \ x ->
193
- inspectDynamicField (x ^. # fieldPairValue . # fieldOutput)
194
- /= mempty
195
- )
196
- raw
197
-
198
- success :: MisoString -> [View Action ]
199
- success msg =
200
- css " app-success"
201
- $ pairs () [newFieldPairId mempty $ DynamicFieldText msg]
202
-
203
- failure :: MisoString -> [View Action ]
204
- failure msg =
205
- css " app-failure"
206
- $ pairs () [newFieldPairId mempty $ DynamicFieldText msg]
207
-
208
- css :: MisoString -> [View action ] -> [View action ]
209
- css x = fmap $ \ case
210
- Node x0 x1 x2 x3 x4 -> Node x0 x1 x2 (class_ x : x3) x4
211
- html -> html
212
-
213
- inspectTimestamp :: Int -> MisoString
214
- inspectTimestamp =
215
- inspect
216
- . posixSecondsToUTCTime
217
- . Prelude. fromInteger
218
- . from @ Int @ Integer
234
+ preimageFields :: MisoString -> ByteString -> [FieldPair DynamicField Identity ]
235
+ preimageFields rawR r =
236
+ [ pair " Preimage" rawR,
237
+ pair " Preimage Hash" . inspect @ ByteString $ sha256Hash r
238
+ ]
0 commit comments