22{-# LANGUAGE BangPatterns #-}
33{-# LANGUAGE DataKinds #-}
44{-# LANGUAGE DeriveGeneric #-}
5- {-# LANGUAGE DerivingStrategies #-}
65{-# LANGUAGE DerivingVia #-}
76{-# LANGUAGE FlexibleContexts #-}
87{-# LANGUAGE GADTs #-}
98{-# LANGUAGE GeneralizedNewtypeDeriving #-}
10- {-# LANGUAGE KindSignatures #-}
119{-# LANGUAGE LambdaCase #-}
1210{-# LANGUAGE MultiParamTypeClasses #-}
1311{-# LANGUAGE NamedFieldPuns #-}
2119{-# LANGUAGE TupleSections #-}
2220{-# LANGUAGE TypeApplications #-}
2321{-# LANGUAGE TypeFamilies #-}
24- {-# LANGUAGE TypeOperators #-}
2522{-# LANGUAGE TypeSynonymInstances #-}
2623{-# LANGUAGE UndecidableInstances #-}
2724
@@ -125,7 +122,7 @@ import Cardano.Ledger.Binary.Coders (
125122 (<!) ,
126123 )
127124import Cardano.Ledger.Coin (Coin )
128- import Cardano.Ledger.Credential (Credential (.. ), credToText )
125+ import Cardano.Ledger.Credential (Credential (.. ), credToText , parseCredential )
129126import Cardano.Ledger.Shelley.RewardProvenance ()
130127import Cardano.Ledger.TxIn (TxId (.. ))
131128import Cardano.Slotting.Slot (EpochNo )
@@ -135,14 +132,16 @@ import Control.Monad.Trans (lift)
135132import Control.Monad.Trans.State.Strict (get , put )
136133import Data.Aeson (
137134 FromJSON (.. ),
135+ FromJSONKey (.. ),
138136 KeyValue (.. ),
139137 ToJSON (.. ),
140138 ToJSONKey (.. ),
141139 withObject ,
142140 (.:) ,
143141 (.:?) ,
144142 )
145- import Data.Aeson.Types (toJSONKeyText )
143+ import qualified Data.Aeson as Aeson
144+ import Data.Aeson.Types (FromJSONKeyFunction (.. ), toJSONKeyText )
146145import Data.Data (Typeable )
147146import Data.Default
148147import Data.Kind
@@ -158,6 +157,7 @@ import Data.Word (Word16)
158157import GHC.Generics (Generic )
159158import Lens.Micro (Lens' , lens , (^.) )
160159import NoThunks.Class (NoThunks )
160+ import Text.Read (readMaybe )
161161
162162newtype GovActionIx = GovActionIx { unGovActionIx :: Word16 }
163163 deriving
@@ -170,6 +170,7 @@ newtype GovActionIx = GovActionIx {unGovActionIx :: Word16}
170170 , EncCBOR
171171 , DecCBOR
172172 , ToJSON
173+ , FromJSON
173174 )
174175
175176data GovActionId = GovActionId
@@ -216,6 +217,26 @@ govActionIdToText (GovActionId (TxId txidHash) (GovActionIx ix)) =
216217 <> Text. pack " #"
217218 <> Text. pack (show ix)
218219
220+ instance FromJSON GovActionId where
221+ parseJSON = withObject " GovActionId" $ \ o ->
222+ GovActionId
223+ <$> o .: " txId"
224+ <*> o .: " govActionIx"
225+
226+ instance FromJSONKey GovActionId where
227+ fromJSONKey = FromJSONKeyTextParser parseGovActionId
228+
229+ parseGovActionId :: MonadFail m => Text. Text -> m GovActionId
230+ parseGovActionId t = case Text. splitOn " #" t of
231+ [txIdText, ixText] -> do
232+ txId <- case Aeson. fromJSON (Aeson. String txIdText) of
233+ Aeson. Success v -> pure v
234+ Aeson. Error e -> fail $ " GovActionId: invalid txId: " <> e
235+ ix <-
236+ maybe (fail " GovActionId: invalid index" ) (pure . GovActionIx ) (readMaybe $ Text. unpack ixText)
237+ pure $ GovActionId txId ix
238+ _ -> fail " GovActionId: expected 'txhash#ix'"
239+
219240data GovActionState era = GovActionState
220241 { gasId :: ! GovActionId
221242 , gasCommitteeVotes :: ! (Map (Credential HotCommitteeRole ) Vote )
@@ -273,7 +294,7 @@ deriving via
273294 EraPParams era => ToJSON (GovActionState era )
274295
275296instance EraPParams era => ToKeyValuePairs (GovActionState era ) where
276- toKeyValuePairs gas@ ( GovActionState _ _ _ _ _ _ _) =
297+ toKeyValuePairs gas =
277298 let GovActionState {.. } = gas
278299 in [ " actionId" .= gasId
279300 , " committeeVotes" .= gasCommitteeVotes
@@ -352,6 +373,22 @@ instance ToJSONKey Voter where
352373 StakePoolVoter kh ->
353374 " stakepool-" <> credToText (KeyHashObj kh)
354375
376+ instance FromJSON Voter
377+
378+ instance FromJSONKey Voter where
379+ fromJSONKey = FromJSONKeyTextParser parseVoter
380+
381+ parseVoter :: MonadFail m => Text. Text -> m Voter
382+ parseVoter t = case Text. splitOn " -" t of
383+ (" committee" : rest) -> CommitteeVoter <$> parseCredential (Text. intercalate " -" rest)
384+ (" drep" : rest) -> DRepVoter <$> parseCredential (Text. intercalate " -" rest)
385+ (" stakepool" : rest) -> do
386+ cred <- parseCredential (Text. intercalate " -" rest)
387+ case cred of
388+ KeyHashObj kh -> pure $ StakePoolVoter kh
389+ ScriptHashObj _ -> fail " StakePool voter cannot be a script hash"
390+ _ -> fail $ " Invalid Voter: " <> show t
391+
355392instance DecCBOR Voter where
356393 decCBOR = decodeRecordSum " Voter" $ \ case
357394 0 -> (2 ,) . CommitteeVoter . KeyHashObj <$> decCBOR
@@ -387,6 +424,8 @@ data Vote
387424
388425instance ToJSON Vote
389426
427+ instance FromJSON Vote
428+
390429instance NoThunks Vote
391430
392431instance NFData Vote
@@ -401,7 +440,7 @@ newtype VotingProcedures era = VotingProcedures
401440 { unVotingProcedures :: Map Voter (Map GovActionId (VotingProcedure era ))
402441 }
403442 deriving stock (Generic , Eq , Show )
404- deriving newtype (NoThunks , EncCBOR , ToJSON )
443+ deriving newtype (NoThunks , EncCBOR , ToJSON , FromJSON )
405444
406445deriving newtype instance Era era => NFData (VotingProcedures era )
407446
@@ -485,6 +524,12 @@ instance EraPParams era => ToKeyValuePairs (VotingProcedure era) where
485524 , " decision" .= vProcVote
486525 ]
487526
527+ instance EraPParams era => FromJSON (VotingProcedure era ) where
528+ parseJSON = withObject " VotingProcedure" $ \ o ->
529+ VotingProcedure
530+ <$> o .: " decision"
531+ <*> o .: " anchor"
532+
488533-- | Attaches indices to a sequence of proposal procedures. The indices grow
489534-- from left to right.
490535indexedGovProps ::
@@ -549,14 +594,22 @@ deriving via
549594 EraPParams era => ToJSON (ProposalProcedure era )
550595
551596instance EraPParams era => ToKeyValuePairs (ProposalProcedure era ) where
552- toKeyValuePairs proposalProcedure@ ( ProposalProcedure _ _ _ _) =
597+ toKeyValuePairs proposalProcedure =
553598 let ProposalProcedure {.. } = proposalProcedure
554599 in [ " deposit" .= pProcDeposit
555600 , " returnAddr" .= pProcReturnAddr
556601 , " govAction" .= pProcGovAction
557602 , " anchor" .= pProcAnchor
558603 ]
559604
605+ instance EraPParams era => FromJSON (ProposalProcedure era ) where
606+ parseJSON = withObject " ProposalProcedure" $ \ o ->
607+ ProposalProcedure
608+ <$> o .: " deposit"
609+ <*> o .: " returnAddr"
610+ <*> o .: " govAction"
611+ <*> o .: " anchor"
612+
560613data Committee era = Committee
561614 { committeeMembers :: ! (Map (Credential ColdCommitteeRole ) EpochNo )
562615 -- ^ Committee members with epoch number when each of them expires
@@ -663,6 +716,10 @@ deriving newtype instance ToJSONKey (GovPurposeId (p :: GovActionPurpose))
663716
664717deriving newtype instance ToJSON (GovPurposeId (p :: GovActionPurpose ))
665718
719+ deriving newtype instance FromJSON (GovPurposeId (p :: GovActionPurpose ))
720+
721+ deriving newtype instance FromJSONKey (GovPurposeId (p :: GovActionPurpose ))
722+
666723deriving newtype instance Show (GovPurposeId (p :: GovActionPurpose ))
667724
668725-- | Abstract data type for representing relationship of governance action with the same purpose
@@ -736,7 +793,7 @@ instance
736793 (forall p . Typeable p => EncCBOR (f (GovPurposeId (p :: GovActionPurpose )))) =>
737794 EncCBOR (GovRelation f )
738795 where
739- encCBOR govPurpose@ ( GovRelation _ _ _ _) =
796+ encCBOR govPurpose =
740797 let GovRelation {.. } = govPurpose
741798 in encodeListLen 4
742799 <> encCBOR grPParamUpdate
@@ -748,7 +805,7 @@ instance
748805 (forall p . ToJSON (f (GovPurposeId (p :: GovActionPurpose )))) =>
749806 ToKeyValuePairs (GovRelation f )
750807 where
751- toKeyValuePairs govPurpose@ ( GovRelation _ _ _ _) =
808+ toKeyValuePairs govPurpose =
752809 let GovRelation {.. } = govPurpose
753810 in [ " PParamUpdate" .= grPParamUpdate
754811 , " HardFork" .= grHardFork
@@ -868,6 +925,8 @@ instance EraPParams era => NFData (GovAction era)
868925
869926instance EraPParams era => ToJSON (GovAction era )
870927
928+ instance EraPParams era => FromJSON (GovAction era )
929+
871930instance EraPParams era => DecCBOR (GovAction era ) where
872931 decCBOR =
873932 decode $ Summands " GovAction" $ \ case
0 commit comments