packages feed

blockfrost-api 0.12.2.0 → 0.15.0.0

raw patch · 15 files changed

Files

CHANGELOG.md view
@@ -1,3 +1,28 @@+# Version [0.15.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.14.0.0...api-0.15.0.0) (2026-02-02)++* Changes+  * Fix `MempoolUTxOInput` `address` field from `Text` to `Maybe Text` [#83](https://github.com/blockfrost/blockfrost-haskell/issues/83) [#84](https://github.com/blockfrost/blockfrost-haskell/pull/84)+  * Mempool API functions adjusted to not require passing in `Project` [#85](https://github.com/blockfrost/blockfrost-haskell/pull/85)+    * Previous `getMempoolTransactions prj def def` is now simply `getMempoolTransactions` and a principled+      variant `getMempoolTransactions'` is provided accepting page and sort order parameters+      (for example `allPages $ \p -> getMempoolTransactions' p def`).+    * Similar for `getMempoolTransactionsByAddress`.+    * `getMempoolTransaction` now simply doesn't require passing `Project`++# Version [0.14.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.13.0.0...api-0.14.0.0) (2025-12-02)++* Changes+  * Add `CustomURL` to `Env`, to allow arbitrary Blockfrost instance [#79](https://github.com/blockfrost/blockfrost-haskell/pull/79)+  * `BlockfrostNotFound` constructor of `BlockfrostError` is now `BlockfrostNotFound Text`+    containing path that resulted in 404 error [#81](https://github.com/blockfrost/blockfrost-haskell/pull/81)+  * Drop `Sanchonet` `Env` [#79](https://github.com/blockfrost/blockfrost-haskell/pull/79)++# Version [0.13.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.12.2.0...api-0.13.0.0) (2025-06-03)++* Additions+  * Governance support [#77](https://github.com/blockfrost/blockfrost-haskell/pull/77)+  * `AccountInfo` extended with `drepId` field [#77](https://github.com/blockfrost/blockfrost-haskell/pull/77)+ # Version [0.12.2.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.12.1.0...api-0.12.2.0) (2025-04-07)  * Additions
blockfrost-api.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                blockfrost-api-version:             0.12.2.0+version:             0.15.0.0 synopsis:            API definitions for blockfrost.io description:         Core types and Servant API description homepage:            https://github.com/blockfrost/blockfrost-haskell@@ -68,6 +68,7 @@                       , Blockfrost.API.Cardano.Assets                       , Blockfrost.API.Cardano.Blocks                       , Blockfrost.API.Cardano.Epochs+                      , Blockfrost.API.Cardano.Governance                       , Blockfrost.API.Cardano.Ledger                       , Blockfrost.API.Cardano.Mempool                       , Blockfrost.API.Cardano.Metadata@@ -91,6 +92,7 @@                       , Blockfrost.Types.Cardano.Blocks                       , Blockfrost.Types.Cardano.Epochs                       , Blockfrost.Types.Cardano.Genesis+                      , Blockfrost.Types.Cardano.Governance                       , Blockfrost.Types.Cardano.Mempool                       , Blockfrost.Types.Cardano.Metadata                       , Blockfrost.Types.Cardano.Network@@ -108,6 +110,7 @@                       , Blockfrost.Types.Shared.Epoch                       , Blockfrost.Types.Shared.CBOR                       , Blockfrost.Types.Shared.DatumHash+                      , Blockfrost.Types.Shared.DRepId                       , Blockfrost.Types.Shared.Opts                       , Blockfrost.Types.Shared.POSIXMillis                       , Blockfrost.Types.Shared.ScriptHash@@ -153,6 +156,7 @@                      , Cardano.Assets                      , Cardano.Blocks                      , Cardano.Epochs+                     , Cardano.Governance                      , Cardano.Ledger                      , Cardano.Metadata                      , Cardano.Network
src/Blockfrost/API.hs view
@@ -93,6 +93,11 @@       :- "epochs"       :> Tag "Cardano » Epochs"       :> ToServantApi EpochsAPI+    , _governance+      :: route+      :- "governance"+      :> Tag "Cardano » Governance"+      :> ToServantApi GovernanceAPI     , _ledger       :: route       :- "genesis"
src/Blockfrost/API/Cardano.hs view
@@ -8,6 +8,7 @@   , module Blockfrost.API.Cardano.Assets   , module Blockfrost.API.Cardano.Blocks   , module Blockfrost.API.Cardano.Epochs+  , module Blockfrost.API.Cardano.Governance   , module Blockfrost.API.Cardano.Ledger   , module Blockfrost.API.Cardano.Mempool   , module Blockfrost.API.Cardano.Metadata@@ -23,6 +24,7 @@ import Blockfrost.API.Cardano.Assets import Blockfrost.API.Cardano.Blocks import Blockfrost.API.Cardano.Epochs+import Blockfrost.API.Cardano.Governance import Blockfrost.API.Cardano.Ledger import Blockfrost.API.Cardano.Mempool import Blockfrost.API.Cardano.Metadata
+ src/Blockfrost/API/Cardano/Governance.hs view
@@ -0,0 +1,130 @@+-- | Governance API endpoints++{-# OPTIONS_HADDOCK hide #-}++module Blockfrost.API.Cardano.Governance+  where++import Servant.API+import Servant.API.Generic+import Servant.Docs (DocCapture (..), ToCapture (..))++import Blockfrost.Types.Cardano.Governance+import Blockfrost.Types.Shared+import Blockfrost.Util.Pagination+import Blockfrost.Util.Sorting++data GovernanceAPI route =+  GovernanceAPI+    {+      _dreps+        :: route+        :- Summary "Delegate Representatives (DReps)"+        :> Description "Return the information about Delegate Representatives (DReps)."+        :> "dreps"+        :> Pagination+        :> Sorting+        :> Get '[JSON] [DRep]+    , _drep+        :: route+        :- Summary "Specific DRep"+        :> Description "DRep information."+        :> "dreps"+        :> Capture "drep_id" DRepId+        :> Get '[JSON] DRepInfo+    , _drepDelegators+        :: route+        :- Summary "DRep delegators"+        :> Description "List of Drep delegators."+        :> "dreps"+        :> Capture "drep_id" DRepId+        :> "delegators"+        :> Pagination+        :> Sorting+        :> Get '[JSON] [DRepDelegator]+    , _drepMetadata+        :: route+        :- Summary "DRep metadata"+        :> Description "DRep metadata information."+        :> "dreps"+        :> Capture "drep_id" DRepId+        :> "metadata"+        :> Get '[JSON] DRepMeta+    , _drepUpdates+        :: route+        :- Summary "DRep updates"+        :> Description "List of certificate updates to the DRep."+        :> "dreps"+        :> Capture "drep_id" DRepId+        :> "updates"+        :> Pagination+        :> Sorting+        :> Get '[JSON] [DRepUpdate]+    , _drepVotes+        :: route+        :- Summary "DRep votes"+        :> Description "History of DReps votes."+        :> "dreps"+        :> Capture "drep_id" DRepId+        :> "votes"+        :> Pagination+        :> Sorting+        :> Get '[JSON] [DRepVote]+    , _proposals+        :: route+        :- Summary "Proposals"+        :> Description "List of proposals."+        :> "proposals"+        :> Pagination+        :> Sorting+        :> Get '[JSON] [Proposal]+    , _proposal+        :: route+        :- Summary "Specific proposal"+        :> Description "Proposal details."+        :> "proposals"+        :> Capture "hash" TxHash+        :> Capture "cert_index" Integer+        :> Get '[JSON] ProposalInfo+    , _paramProposal+        :: route+        :- Summary "Specific parameters proposal"+        :> Description "Parameter proposal details."+        :> "proposals"+        :> Capture "hash" TxHash+        :> Capture "cert_index" Integer+        :> "parameters"+        :> Get '[JSON] ParamProposal+    , _withdrawalProposal+        :: route+        :- Summary "Specific withdrawals proposal"+        :> Description "Withdrawals proposal details."+        :> "proposals"+        :> Capture "hash" TxHash+        :> Capture "cert_index" Integer+        :> "withdrawals"+        :> Get '[JSON] [WithdrawalProposal]+    , _proposalVotes+        :: route+        :- Summary "Proposal votes"+        :> Description "History of proposal votes."+        :> "proposals"+        :> Capture "hash" TxHash+        :> Capture "cert_index" Integer+        :> "votes"+        :> Pagination+        :> Sorting+        :> Get '[JSON] [ProposalVote]+    , _proposalMeta+        :: route+        :- Summary "Specific proposal metadata"+        :> Description "Proposal metadata information."+        :> "proposals"+        :> Capture "hash" TxHash+        :> Capture "cert_index" Integer+        :> "metadata"+        :> Get '[JSON] ProposalMeta+    } deriving (Generic)++instance ToCapture (Capture "cert_index" Integer) where+  toCapture _ = DocCapture "cert_index" "Index of the certificate within the transaction."
src/Blockfrost/Env.hs view
@@ -20,8 +20,8 @@   | Testnet   | Preprod   | Preview-  | Sanchonet   | Localhost+  | CustomURL String -- ^ Full URL to custom Blockfrost instance   deriving (Eq, Read, Show, Ord, Generic)  -- | Try parsing @Env@ from @Text@@@ -31,4 +31,4 @@   Nothing ->     Left       $ "Unknown environment: `" <> tEnv <> "`"-      <> " expecting one of `ipfs`, `mainnet`, `testnet`, `preprod`, `preview`, `sanchonet`, `localhost`"+      <> " expecting one of `ipfs`, `mainnet`, `testnet`, `preprod`, `preview`, `localhost`"
src/Blockfrost/Lens.hs view
@@ -45,6 +45,20 @@  makeFields ''Genesis +makeFields ''DRep+makeFields ''DRepInfo+makeFields ''DRepDelegator+makeFields ''DRepMeta+makeFields ''DRepUpdate+makeFields ''DRepVote+makeFields ''Proposal+makeFields ''ProposalInfo+makeFields ''ProposedProtocolParams+makeFields ''ParamProposal+makeFields ''WithdrawalProposal+makeFields ''ProposalVote+makeFields ''ProposalMeta+ makeFields  ''MempoolTransaction makeFields  ''TransactionInMempool makeFields  ''Amount
src/Blockfrost/Types/Cardano.hs view
@@ -7,6 +7,7 @@   , module Blockfrost.Types.Cardano.Blocks   , module Blockfrost.Types.Cardano.Epochs   , module Blockfrost.Types.Cardano.Genesis+  , module Blockfrost.Types.Cardano.Governance   , module Blockfrost.Types.Cardano.Mempool   , module Blockfrost.Types.Cardano.Metadata   , module Blockfrost.Types.Cardano.Network@@ -22,6 +23,7 @@ import Blockfrost.Types.Cardano.Blocks import Blockfrost.Types.Cardano.Epochs import Blockfrost.Types.Cardano.Genesis+import Blockfrost.Types.Cardano.Governance import Blockfrost.Types.Cardano.Mempool import Blockfrost.Types.Cardano.Metadata import Blockfrost.Types.Cardano.Network
src/Blockfrost/Types/Cardano/Accounts.hs view
@@ -31,6 +31,7 @@   , _accountInfoTreasurySum        :: Lovelaces -- ^ Sum of all funds from treasury for the account in the Lovelaces   , _accountInfoWithdrawableAmount :: Lovelaces -- ^ Sum of available rewards that haven't been withdrawn yet for the account in the Lovelaces   , _accountInfoPoolId             :: Maybe PoolId -- ^ Bech32 pool ID that owns the account+  , _accountInfoDrepId             :: Maybe DRepIdBech32 -- ^ Bech32 DRep ID to which this account is delegated   }   deriving stock (Show, Eq, Generic)   deriving (FromJSON, ToJSON)@@ -48,6 +49,7 @@     , _accountInfoTreasurySum = 12000000     , _accountInfoWithdrawableAmount = 319154618165     , _accountInfoPoolId = pure "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy"+    , _accountInfoDrepId = pure "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc"     }  -- | Reward type
+ src/Blockfrost/Types/Cardano/Governance.hs view
@@ -0,0 +1,684 @@+-- | Responses for Cardano governance queries++module Blockfrost.Types.Cardano.Governance+  ( DRep (..)+  , DRepInfo (..)+  , DRepDelegator (..)+  , DRepMeta (..)+  , DRepRegistrationAction (..)+  , DRepUpdate (..)+  , VotingAction (..)+  , DRepVote (..)+  , ProposalAction (..)+  , Proposal (..)+  , ProposalInfo (..)+  , ProposedProtocolParams (..)+  , ParamProposal (..)+  , WithdrawalProposal (..)+  , VoterRole (..)+  , ProposalVote (..)+  , ProposalMeta (..)+  ) where++import Blockfrost.Types.Shared+import Blockfrost.Types.Cardano.Epochs (CostModels, CostModelsRaw)+import Data.Aeson (FromJSON (..), ToJSON (..), Value (..), (.=), object, withText)+import Data.Proxy (Proxy (..))+import Data.Text (Text)+import Deriving.Aeson+import Servant.Docs (ToSample (..), samples, singleSample)++-- | DRep index+data DRep = DRep+  { _dRepDrepId :: DRepIdBech32 -- ^ Bech32 encoded DRep address+  , _dRepHex    :: DRepIdHex    -- ^ The raw bytes of the DRep+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_dRep", CamelToSnake]] DRep++instance ToSample DRep where+    toSamples = pure $ samples+      [ DRep+          { _dRepDrepId = "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn"+          , _dRepHex    = "db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23"+          }+      , DRep+          { _dRepDrepId = "drep1cxayn4fgy27yaucvhamsvqj3v6835mh3tjjx6x8hdnr4"+          , _dRepHex    = "c1ba49d52822bc4ef30cbf77060251668f1a6ef15ca46d18f76cc758"+          }+      ]++-- | Information about a DRep+data DRepInfo = DRepInfo+  { _dRepInfoDrepId          :: DRepIdBech32 -- ^ Bech32 encoded DRep address+  , _dRepInfoHex             :: DRepIdHex    -- ^ The raw bytes of the DRep+  , _dRepInfoAmount          :: Lovelaces    -- ^ The total amount of voting power this DRep is delegated+  , _dRepInfoHasScript       :: Bool         -- ^ Flag which indicates if this DRep credentials are a script hash+  , _dRepInfoRetired         :: Bool         -- ^ Indicates the registration state of the DRep. Set to `True` if the DRep has been deregistered; otherwise, `False`.+  , _dRepInfoExpired         :: Bool         -- ^ Indicates whether the DRep has been inactive for a consecutive number of epochs (determined by a epoch parameter `drep_activity`)+  , _dRepInfoLastActiveEpoch :: Maybe Epoch  -- ^ Epoch of the most recent action - registration, update, deregistration or voting+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_dRepInfo", CamelToSnake]] DRepInfo++instance ToSample DRepInfo where+  toSamples = pure $ singleSample $ DRepInfo+    { _dRepInfoDrepId          = "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc"+    , _dRepInfoHex             = "a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d"+    , _dRepInfoAmount          = 2000000+    , _dRepInfoHasScript       = True+    , _dRepInfoRetired         = False+    , _dRepInfoExpired         = False+    , _dRepInfoLastActiveEpoch = Just 509+    }++-- | Address delegating to a DRep+data DRepDelegator = DRepDelegator+  { _dRepDelegatorAddress :: Address   -- ^ Bech32 encoded stake addresses+  , _dRepDelegatorAmount  :: Lovelaces -- ^ Currently delegated amount+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_dRepDelegator", CamelToSnake]] DRepDelegator++instance ToSample DRepDelegator where+  toSamples = pure $ samples+    [ DRepDelegator+        { _dRepDelegatorAddress = "stake1ux4vspfvwuus9uwyp5p3f0ky7a30jq5j80jxse0fr7pa56sgn8kha"+        , _dRepDelegatorAmount  = 1137959159981411+        }+    , DRepDelegator+        { _dRepDelegatorAddress = "stake1uylayej7esmarzd4mk4aru37zh9yz0luj3g9fsvgpfaxulq564r5u"+        , _dRepDelegatorAmount  = 16958865648+        }+    , DRepDelegator+        { _dRepDelegatorAddress = "stake1u8lr2pnrgf8f7vrs9lt79hc3sxm8s2w4rwvgpncks3axx6q93d4ck"+        , _dRepDelegatorAmount  = 18605647+        }+    ]++-- | DRep metadata+data DRepMeta = DRepMeta+  { _dRepMetaDrepId          :: DRepIdBech32 -- ^ Bech32 encoded DRep address+  , _dRepMetaHex             :: DRepIdHex    -- ^ The raw bytes of the DRep+  , _dRepMetaUrl             :: Text         -- ^ URL to the drep metadata+  , _dRepMetaHash            :: Text         -- ^ Hash of the metadata file+  , _dRepMetaJsonMetadata    :: Value        -- ^ Content of the JSON metadata (validated CIP-119)+  , _dRepMetaBytes           :: Text         -- ^ Hex-encoded metadata (raw)+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_dRepMeta", CamelToSnake]] DRepMeta++instance ToSample DRepMeta where+  toSamples = pure $ singleSample $ DRepMeta+    { _dRepMetaDrepId          = "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc"+    , _dRepMetaHex             = "a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d"+    , _dRepMetaUrl             = "https://aaa.xyz/drep.json"+    , _dRepMetaHash            = "a14a5ad4f36bddc00f92ddb39fd9ac633c0fd43f8bfa57758f9163d10ef916de"+    , _dRepMetaJsonMetadata    = object+      [ "@context" .= object+          [ "CIP100" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#" :: Text)+          , "CIP119" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md#" :: Text)+          , "hashAlgorithm" .= ("CIP100:hashAlgorithm" :: Text)+          , "body" .= object+            [ "@id" .= ("CIP119:body" :: Text)+            , "@context" .= object+                [ "references" .= object+                    [ "@id" .= ("CIP119:references" :: Text)+                    , "@container" .= ("@set" :: Text)+                    , "@context" .= object+                        [ "GovernanceMetadata" .= ("CIP100:GovernanceMetadataReference" :: Text)+                        , "Other" .= ("CIP100:OtherReference" :: Text)+                        , "label" .= ("CIP100:reference-label" :: Text)+                        , "uri" .= ("CIP100:reference-uri" :: Text)+                        ]+                    ]+                    , "paymentAddress" .= ("CIP119:paymentAddress" :: Text)+                    , "givenName" .= ("CIP119:givenName" :: Text)+                    , "image" .= object+                        [ "@id" .= ("CIP119:image" :: Text)+                        , "@context" .= object+                            [ "ImageObject" .= ("https://schema.org/ImageObject" :: Text) ]+                        ]+                    , "objectives" .= ("CIP119:objectives" :: Text)+                    , "motivations" .= ("CIP119:motivations" :: Text)+                    , "qualifications" .= ("CIP119:qualifications" :: Text)+                    ]+                ]+            ]+        , "hashAlgorithm" .= ("blake2b-256" :: Text)+        , "body" .= object+            [ "paymentAddress" .= ("addr1q86dnpkva4mm859c8ur7tjxn57zgsu6vg8pdetkdve3fsacnq7twy06u2ev5759vutpjgzfryx0ud8hzedhzerava35qwh3x34" :: Text)+            , "givenName" .= ("Ryan Williams" :: Text)+            , "image" .= object+                [ "@type" .= ("ImageObject" :: Text)+                , "contentUrl" .= ("https://avatars.githubusercontent.com/u/44342099?v=4" :: Text)+                , "sha256" .= ("2a21e4f7b20c8c72f573707b068fb8fc6d8c64d5035c4e18ecae287947fe2b2e" :: Text)+                ]+            , "objectives" .= ("Buy myself an island." :: Text)+            , "motivations" .= ("I really would like to own an island." :: Text)+            , "qualifications" .= ("I have my 100m swimming badge, so I would be qualified to be able to swim around island." :: Text)+            , "references" .=+                [ object+                    [ "@type" .= ("Other" :: Text)+                    , "label" .= ("A cool island for Ryan" :: Text)+                    , "uri" .= ("https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu" :: Text)+                    ]+                , object+                    [ "@type" .= ("Link" :: Text)+                    , "label" .= ("Ryan's Twitter" :: Text)+                    , "uri" .= ("https://twitter.com/Ryun1_" :: Text)+                    ]+                ]+            ]+        ]+    , _dRepMetaBytes           = "\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6"+    }++-- | DRep registration action+data DRepRegistrationAction+  = DRepRegistrationAction_Registered+  | DRepRegistrationAction_Deregistered+  deriving stock (Show, Eq, Generic)++instance ToJSON DRepRegistrationAction where+  toJSON DRepRegistrationAction_Registered   = toJSON ("registered"   :: Text)+  toJSON DRepRegistrationAction_Deregistered = toJSON ("deregistered" :: Text)++  toEncoding DRepRegistrationAction_Registered   = toEncoding ("registered"   :: Text)+  toEncoding DRepRegistrationAction_Deregistered = toEncoding ("deregistered" :: Text)++instance FromJSON DRepRegistrationAction where+  parseJSON = withText "action" $ \case+    "registered"   -> pure DRepRegistrationAction_Registered+    "deregistered" -> pure DRepRegistrationAction_Deregistered+    x              -> fail ("Expected registration action got " ++ show x)++-- | DRep registration update+data DRepUpdate = DRepUpdate+  { _dRepUpdateTxHash    :: TxHash                 -- ^ Transaction ID+  , _dRepUpdateCertIndex :: Integer                -- ^ Index of the certificate within the update transaction+  , _dRepUpdateAction    :: DRepRegistrationAction -- ^ DRep registration action+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_dRepUpdate", CamelToSnake]] DRepUpdate++instance ToSample DRepUpdate where+  toSamples = pure $ samples+    [ DRepUpdate+        { _dRepUpdateTxHash = "f4097fbdb87ab7c7ab44b30d4e2b81713a058488975d1ab8b05c381dd946a393"+        , _dRepUpdateCertIndex = 0+        , _dRepUpdateAction = DRepRegistrationAction_Registered+        }+    , DRepUpdate+        { _dRepUpdateTxHash = "dd3243af975be4b5bedce4e5f5b483b2386d5ad207d05e0289c1df0eb261447e"+        , _dRepUpdateCertIndex = 0+        , _dRepUpdateAction = DRepRegistrationAction_Deregistered+        }+    ]++-- | DRep voting action+data VotingAction+  = VotingAction_Yes+  | VotingAction_No+  | VotingAction_Abstain+  deriving stock (Show, Eq, Generic)++instance ToJSON VotingAction where+  toJSON VotingAction_Yes     = toJSON ("yes"     :: Text)+  toJSON VotingAction_No      = toJSON ("no"      :: Text)+  toJSON VotingAction_Abstain = toJSON ("abstain" :: Text)++  toEncoding VotingAction_Yes     = toEncoding ("yes"     :: Text)+  toEncoding VotingAction_No      = toEncoding ("no"      :: Text)+  toEncoding VotingAction_Abstain = toEncoding ("abstain" :: Text)++instance FromJSON VotingAction where+  parseJSON = withText "vote" $ \case+    "yes"     -> pure VotingAction_Yes+    "no"      -> pure VotingAction_No+    "abstain" -> pure VotingAction_Abstain+    x              -> fail ("Expected DRep vote but got " ++ show x)++-- | DRep vote+data DRepVote = DRepVote+  { _dRepVoteTxHash    :: TxHash       -- ^ Transaction ID+  , _dRepVoteCertIndex :: Integer      -- ^ Index of the certificate within the update transaction+  , _dRepVoteAction    :: VotingAction -- ^ DRep voting action+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_dRepVote", CamelToSnake, Rename "action" "vote"]] DRepVote++instance ToSample DRepVote where+  toSamples = pure $ samples+    [ DRepVote+        { _dRepVoteTxHash    = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+        , _dRepVoteCertIndex = 2+        , _dRepVoteAction    = VotingAction_Yes+        }+    , DRepVote+        { _dRepVoteTxHash    = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+        , _dRepVoteCertIndex = 3+        , _dRepVoteAction    = VotingAction_Abstain+        }+    ]++-- | DRep proposal action+data ProposalAction+  = ProposalAction_HardForkInitiation+  | ProposalAction_NewCommittee+  | ProposalAction_NewConstitution+  | ProposalAction_InfoAction+  | ProposalAction_NoConfidence+  | ProposalAction_ParameterChange+  | ProposalAction_TreasuryWithdrawals+  deriving stock (Show, Eq, Generic)++instance ToJSON ProposalAction where+  toJSON ProposalAction_HardForkInitiation  = toJSON ("hard_fork_initiation" :: Text)+  toJSON ProposalAction_NewCommittee        = toJSON ("new_committee"        :: Text)+  toJSON ProposalAction_NewConstitution     = toJSON ("new_constitution"     :: Text)+  toJSON ProposalAction_InfoAction          = toJSON ("info_action"          :: Text)+  toJSON ProposalAction_NoConfidence        = toJSON ("no_confidence"        :: Text)+  toJSON ProposalAction_ParameterChange     = toJSON ("parameter_change"     :: Text)+  toJSON ProposalAction_TreasuryWithdrawals = toJSON ("treasury_withdrawals" :: Text)++  toEncoding ProposalAction_HardForkInitiation  = toEncoding ("hard_fork_initiation" :: Text)+  toEncoding ProposalAction_NewCommittee        = toEncoding ("new_committee"        :: Text)+  toEncoding ProposalAction_NewConstitution     = toEncoding ("new_constitution"     :: Text)+  toEncoding ProposalAction_InfoAction          = toEncoding ("info_action"          :: Text)+  toEncoding ProposalAction_NoConfidence        = toEncoding ("no_confidence"        :: Text)+  toEncoding ProposalAction_ParameterChange     = toEncoding ("parameter_change"     :: Text)+  toEncoding ProposalAction_TreasuryWithdrawals = toEncoding ("treasury_withdrawals" :: Text)++instance FromJSON ProposalAction where+  parseJSON = withText "proposal" $ \case+    "hard_fork_initiation" -> pure ProposalAction_HardForkInitiation+    "new_committee"        -> pure ProposalAction_NewCommittee+    "new_constitution"     -> pure ProposalAction_NewConstitution+    "info_action"          -> pure ProposalAction_InfoAction+    "no_confidence"        -> pure ProposalAction_NoConfidence+    "parameter_change"     -> pure ProposalAction_ParameterChange+    "treasury_withdrawals" -> pure ProposalAction_TreasuryWithdrawals+    x              -> fail ("Expected DRep proposal but got " ++ show x)++-- | DRep proposal+data Proposal = Proposal+  { _dRepProposalTxHash    :: TxHash             -- ^ Transaction ID+  , _dRepProposalCertIndex :: Integer            -- ^ Index of the certificate within the update transaction+  , _dRepProposalAction    :: ProposalAction -- ^ DRep proposal type+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_dRepProposal", CamelToSnake, Rename "action" "governance_type"]] Proposal++instance ToSample Proposal where+  toSamples = pure $ samples+    [ Proposal+        { _dRepProposalTxHash = "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531"+        , _dRepProposalCertIndex = 1+        , _dRepProposalAction = ProposalAction_TreasuryWithdrawals+        }+    , Proposal+        { _dRepProposalTxHash = "71317e951b20aa46e9fbf45a46a6e950d5723a481225519655bf6c60"+        , _dRepProposalCertIndex = 4+        , _dRepProposalAction = ProposalAction_NoConfidence+        }+    ]++-- | Proposal details+data ProposalInfo = ProposalInfo+  { _proposalInfoTxHash                :: TxHash             -- ^ Transaction ID+  , _proposalInfoCertIndex             :: Integer            -- ^ Index of the certificate within the proposal transaction+  , _proposalInfoGovernanceType        :: ProposalAction     -- ^ DRep proposal type+  , _proposalInfoDeposit               :: Lovelaces          -- ^ The deposit amount paid for this proposal+  , _proposalInfoReturnAddress         :: Address            -- ^ Bech32 stake address of the reward address to receive the deposit when it is repaid.+  , _proposalInfoGovernanceDescription :: Maybe Value        -- ^ An object describing the content of this GovActionProposal in a readable way.+  , _proposalInfoRatifiedEpoch         :: Maybe Epoch+  , _proposalInfoEnactedEpoch          :: Maybe Epoch+  , _proposalInfoDroppedEpoch          :: Maybe Epoch+  , _proposalInfoExpiredEpoch          :: Maybe Epoch+  , _proposalInfoExpiration            :: Epoch              -- ^ The epoch at which this governance action will expire.+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_proposalInfo", CamelToSnake]] ProposalInfo++instance ToSample ProposalInfo where+  toSamples = pure $ singleSample $ ProposalInfo+    { _proposalInfoTxHash                = "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531"+    , _proposalInfoCertIndex             = 1+    , _proposalInfoGovernanceType        = ProposalAction_TreasuryWithdrawals+    , _proposalInfoDeposit               = 12000+    , _proposalInfoReturnAddress         = "stake_test1urd3hs7rlxwwdzthe6hj026dmyt3y0heuulctscyydh2kgck6nkmz"+    , _proposalInfoGovernanceDescription = Just $ object [ "tag" .= ("InfoAction" :: Text) ]+    , _proposalInfoRatifiedEpoch         = Nothing+    , _proposalInfoEnactedEpoch          = Just 123+    , _proposalInfoDroppedEpoch          = Nothing+    , _proposalInfoExpiredEpoch          = Nothing+    , _proposalInfoExpiration            = 120+    }++-- | Proposed protocol parameters+--+-- This type is sturcturally similar to @ProtocolParams@ but every field+-- is optional.+data ProposedProtocolParams = ProposedProtocolParams+  { _proposedProtocolParamsEpoch                      :: Maybe Epoch -- ^ Epoch number+  , _proposedProtocolParamsMinFeeA                    :: Maybe Integer -- ^ The linear factor for the minimum fee calculation for given epoch+  , _proposedProtocolParamsMinFeeB                    :: Maybe Integer -- ^ The constant factor for the minimum fee calculation+  , _proposedProtocolParamsMaxBlockSize               :: Maybe Integer -- ^ Maximum block body size in Bytes+  , _proposedProtocolParamsMaxTxSize                  :: Maybe Integer -- ^ Maximum transaction size+  , _proposedProtocolParamsMaxBlockHeaderSize         :: Maybe Integer -- ^ Maximum block header size+  , _proposedProtocolParamsKeyDeposit                 :: Maybe Lovelaces -- ^ The amount of a key registration deposit in Lovelaces+  , _proposedProtocolParamsPoolDeposit                :: Maybe Lovelaces -- ^ The amount of a pool registration deposit in Lovelaces+  , _proposedProtocolParamsEMax                       :: Maybe Integer -- ^ Epoch bound on pool retirement+  , _proposedProtocolParamsNOpt                       :: Maybe Integer -- ^ Desired number of pools+  , _proposedProtocolParamsA0                         :: Maybe Rational -- ^ Pool pledge influence+  , _proposedProtocolParamsRho                        :: Maybe Rational -- ^ Monetary expansion+  , _proposedProtocolParamsTau                        :: Maybe Rational -- ^ Treasury expansion+  , _proposedProtocolParamsDecentralisationParam      :: Maybe Rational -- ^ Percentage of blocks produced by federated nodes+  , _proposedProtocolParamsExtraEntropy               :: Maybe Text -- ^ Seed for extra entropy+  , _proposedProtocolParamsProtocolMajorVer           :: Maybe Integer -- ^ Accepted protocol major version+  , _proposedProtocolParamsProtocolMinorVer           :: Maybe Integer -- ^ Accepted protocol minor version+  , _proposedProtocolParamsMinUtxo                    :: Maybe Lovelaces -- ^ Minimum UTXO value+  , _proposedProtocolParamsMinPoolCost                :: Maybe Lovelaces  -- ^ Minimum stake cost forced on the pool+  , _proposedProtocolParamsNonce                      :: Maybe Text -- ^ Epoch number only used once+  , _proposedProtocolParamsCostModels                 :: Maybe CostModels -- ^ Cost models parameters for Plutus Core scripts+  , _proposedProtocolParamsCostModelsRaw              :: Maybe CostModelsRaw+  , _proposedProtocolParamsPriceMem                   :: Maybe Rational -- ^ The per word cost of script memory usage+  , _proposedProtocolParamsPriceStep                  :: Maybe Rational -- ^ The cost of script execution step usage+  , _proposedProtocolParamsMaxTxExMem                 :: Maybe Quantity -- ^ The maximum number of execution memory allowed to be used in a single transaction+  , _proposedProtocolParamsMaxTxExSteps               :: Maybe Quantity -- ^ The maximum number of execution steps allowed to be used in a single transaction+  , _proposedProtocolParamsMaxBlockExMem              :: Maybe Quantity -- ^ The maximum number of execution memory allowed to be used in a single block+  , _proposedProtocolParamsMaxBlockExSteps            :: Maybe Quantity -- ^ The maximum number of execution steps allowed to be used in a single block+  , _proposedProtocolParamsMaxValSize                 :: Maybe Quantity -- ^ The maximum Val size+  , _proposedProtocolParamsCollateralPercent          :: Maybe Integer -- ^ The percentage of the transactions fee which must be provided as collateral when including non-native scripts+  , _proposedProtocolParamsMaxCollateralInputs        :: Maybe Integer -- ^ The maximum number of collateral inputs allowed in a transaction+  , _proposedProtocolParamsCoinsPerUtxoSize           :: Maybe Lovelaces -- ^ The cost per UTxO size. Cost per UTxO *word* for Alozno. Cost per UTxO *byte* for Babbage and later+  , _proposedProtocolParamsCoinsPerUtxoWord           :: Maybe Lovelaces -- ^ The cost per UTxO word (DEPRECATED)+  , _proposedProtocolParamsPvtMotionNoConfidence      :: Maybe Rational+  , _proposedProtocolParamsPvtCommitteeNormal         :: Maybe Rational+  , _proposedProtocolParamsPvtCommitteeNoConfidence   :: Maybe Rational+  , _proposedProtocolParamsPvtHardForkInitiation      :: Maybe Rational+  , _proposedProtocolParamsPvtppSecurityGroup         :: Maybe Rational+  , _proposedProtocolParamsDvtMotionNoConfidence      :: Maybe Rational+  , _proposedProtocolParamsDvtCommitteeNormal         :: Maybe Rational+  , _proposedProtocolParamsDvtCommitteeNoConfidence   :: Maybe Rational+  , _proposedProtocolParamsDvtUpdateToConstitution    :: Maybe Rational+  , _proposedProtocolParamsDvtHardForkInitiation      :: Maybe Rational+  , _proposedProtocolParamsDvtPPNetworkGroup          :: Maybe Rational+  , _proposedProtocolParamsDvtPPEconomicGroup         :: Maybe Rational+  , _proposedProtocolParamsDvtPPTechnicalGroup        :: Maybe Rational+  , _proposedProtocolParamsDvtPPGovGroup              :: Maybe Rational+  , _proposedProtocolParamsDvtTreasuryWithdrawal      :: Maybe Rational+  , _proposedProtocolParamsCommitteeMinSize           :: Maybe Quantity+  , _proposedProtocolParamsCommitteeMaxTermLength     :: Maybe Quantity+  , _proposedProtocolParamsGovActionLifetime          :: Maybe Quantity+  , _proposedProtocolParamsGovActionDeposit           :: Maybe Lovelaces+  , _proposedProtocolParamsDrepDeposit                :: Maybe Lovelaces+  , _proposedProtocolParamsDrepActivity               :: Maybe Quantity+  , _proposedProtocolParamsMinFeeRefScriptCostPerByte :: Maybe Rational+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_proposedProtocolParams", CamelToSnake, Rename "dvt_pp_network_group" "dvt_p_p_network_group", Rename "dvt_pp_economic_group" "dvt_p_p_economic_group", Rename "dvt_pp_technical_group" "dvt_p_p_technical_group", Rename "dvt_pp_gov_group" "dvt_p_p_gov_group"]] ProposedProtocolParams++instance ToSample ProposedProtocolParams where+  toSamples = pure $ singleSample+    ProposedProtocolParams+      { _proposedProtocolParamsEpoch = Just 225+      , _proposedProtocolParamsMinFeeA = Just 44+      , _proposedProtocolParamsMinFeeB = Just 155381+      , _proposedProtocolParamsMaxBlockSize = Just 65536+      , _proposedProtocolParamsMaxTxSize = Just 16384+      , _proposedProtocolParamsMaxBlockHeaderSize = Just 1100+      , _proposedProtocolParamsKeyDeposit = Just 2000000+      , _proposedProtocolParamsPoolDeposit = Just 500000000+      , _proposedProtocolParamsEMax = Just 18+      , _proposedProtocolParamsNOpt = Just 150+      , _proposedProtocolParamsA0 = Just 0.3+      , _proposedProtocolParamsRho = Just 0.003+      , _proposedProtocolParamsTau = Just 0.2+      , _proposedProtocolParamsDecentralisationParam = Just 0.5+      , _proposedProtocolParamsExtraEntropy = Nothing+      , _proposedProtocolParamsProtocolMajorVer = Just 2+      , _proposedProtocolParamsProtocolMinorVer = Just 0+      , _proposedProtocolParamsMinUtxo = Just 1000000+      , _proposedProtocolParamsMinPoolCost = Just 340000000+      , _proposedProtocolParamsNonce = Just "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81"+      , _proposedProtocolParamsCostModels =+          case toSamples (Proxy :: Proxy CostModels) of+            [(_, pp)] -> Just pp+            _ -> error "Absurd"+      , _proposedProtocolParamsCostModelsRaw =+          case toSamples (Proxy :: Proxy CostModelsRaw) of+            [(_, pp)] -> Just pp+            _ -> error "Absurd"+      , _proposedProtocolParamsPriceMem = Just 0.0577+      , _proposedProtocolParamsPriceStep = Just 0.0000721+      , _proposedProtocolParamsMaxTxExMem = Just 10000000+      , _proposedProtocolParamsMaxTxExSteps = Just 10000000000+      , _proposedProtocolParamsMaxBlockExMem = Just 50000000+      , _proposedProtocolParamsMaxBlockExSteps = Just 40000000000+      , _proposedProtocolParamsMaxValSize = Just 5000+      , _proposedProtocolParamsCollateralPercent = Just 150+      , _proposedProtocolParamsMaxCollateralInputs = Just 3+      , _proposedProtocolParamsCoinsPerUtxoSize = Just 34482+      , _proposedProtocolParamsCoinsPerUtxoWord = Just 34482+      , _proposedProtocolParamsPvtMotionNoConfidence = Just 0.51+      , _proposedProtocolParamsPvtCommitteeNormal = Just 0.51+      , _proposedProtocolParamsPvtCommitteeNoConfidence = Just 0.51+      , _proposedProtocolParamsPvtHardForkInitiation = Just 0.51+      , _proposedProtocolParamsPvtppSecurityGroup = Just 0.51+      , _proposedProtocolParamsDvtMotionNoConfidence = Just 0.67+      , _proposedProtocolParamsDvtCommitteeNormal = Just 0.67+      , _proposedProtocolParamsDvtCommitteeNoConfidence = Just 0.6+      , _proposedProtocolParamsDvtUpdateToConstitution = Just 0.75+      , _proposedProtocolParamsDvtHardForkInitiation = Just 0.6+      , _proposedProtocolParamsDvtPPNetworkGroup = Just 0.67+      , _proposedProtocolParamsDvtPPEconomicGroup = Just 0.67+      , _proposedProtocolParamsDvtPPTechnicalGroup = Just 0.67+      , _proposedProtocolParamsDvtPPGovGroup = Just 0.75+      , _proposedProtocolParamsDvtTreasuryWithdrawal = Just 0.67+      , _proposedProtocolParamsCommitteeMinSize = Just 7+      , _proposedProtocolParamsCommitteeMaxTermLength = Just 146+      , _proposedProtocolParamsGovActionLifetime = Just 6+      , _proposedProtocolParamsGovActionDeposit = Just 100000000000+      , _proposedProtocolParamsDrepDeposit = Just 500000000+      , _proposedProtocolParamsDrepActivity = Just 20+      , _proposedProtocolParamsMinFeeRefScriptCostPerByte = Just 15+      }++-- | Parameter proposal details+data ParamProposal = ParamProposal+  { _paramProposalTxHash     :: TxHash                 -- ^ Transaction ID+  , _paramProposalCertIndex  :: Integer                -- ^ Index of the certificate within the proposal transaction+  , _paramProposalParameters :: ProposedProtocolParams -- ^ Proposed parameters+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_paramProposal", CamelToSnake]] ParamProposal++instance ToSample ParamProposal where+  toSamples = pure $ singleSample $ ParamProposal+    { _paramProposalTxHash     = "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531"+    , _paramProposalCertIndex  = 2+    , _paramProposalParameters =+        case toSamples (Proxy :: Proxy ProposedProtocolParams) of+          [(_, pp)] -> pp+          _ -> error "Absurd"+    }++-- | Withdrawal proposal details+data WithdrawalProposal = WithdrawalProposal+  { _withdrawalProposalStakeAddress :: Address    -- ^ Bech32 stake address+  , _withdrawalProposalAmount       :: Lovelaces -- ^ Proposed withdrawal amount+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_withdrawalProposal", CamelToSnake]] WithdrawalProposal++instance ToSample WithdrawalProposal where+  toSamples = pure $ samples+    [ WithdrawalProposal+        { _withdrawalProposalStakeAddress = "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7"+        , _withdrawalProposalAmount       = 454541212442+        }+    , WithdrawalProposal+        { _withdrawalProposalStakeAddress = "stake1xx2g2c9dx2nhhehyrezyxpkstoppcqmu9hk63qgfkccw5rqttygt2"+        , _withdrawalProposalAmount       = 97846969+        }+    ]++data VoterRole+  = VoterRole_ConstitutionalCommittee+  | VoterRole_DRep+  | VoterRole_SPO+  deriving stock (Show, Eq, Generic)++instance ToJSON VoterRole where+  toJSON VoterRole_ConstitutionalCommittee = toJSON ("constitutional_committee" :: Text)+  toJSON VoterRole_DRep                    = toJSON ("drep"                     :: Text)+  toJSON VoterRole_SPO                     = toJSON ("spo"                      :: Text)++  toEncoding VoterRole_ConstitutionalCommittee = toEncoding ("constitutional_committee" :: Text)+  toEncoding VoterRole_DRep                    = toEncoding ("drep"                     :: Text)+  toEncoding VoterRole_SPO                     = toEncoding ("spo"                      :: Text)++instance FromJSON VoterRole where+  parseJSON = withText "voterRole" $ \case+    "constitutional_committee" -> pure VoterRole_ConstitutionalCommittee+    "drep"                     -> pure VoterRole_DRep+    "spo"                      -> pure VoterRole_SPO+    x              -> fail ("Expected DRep vote but got " ++ show x)++-- | Proposal vote+data ProposalVote = ProposalVote+  { _proposalVoteTxHash    :: TxHash       -- ^ Transaction ID+  , _proposalVoteCertIndex :: Integer      -- ^ Index of the certificate within the proposal transaction+  , _proposalVoteVoterRole :: VoterRole    -- ^ The role of the voter+  , _proposalVoteVoter     :: DRepId       -- ^ The actual voter+  , _proposalVoteAction    :: VotingAction -- ^ Actual voting action+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_proposalVote", CamelToSnake, Rename "action" "vote"]] ProposalVote++instance ToSample ProposalVote where+  toSamples = pure $ samples+    [ ProposalVote+        { _proposalVoteTxHash    = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+        , _proposalVoteCertIndex = 2+        , _proposalVoteVoterRole = VoterRole_DRep+        , _proposalVoteVoter     = DRepId_Bech32 "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn"+        , _proposalVoteAction    = VotingAction_Yes+        }+    , ProposalVote+        { _proposalVoteTxHash    = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+        , _proposalVoteCertIndex = 3+        , _proposalVoteVoterRole = VoterRole_ConstitutionalCommittee+        , _proposalVoteVoter     = DRepId_Hex "53a42debdc7ffd90085ab7fd9800b63e6d1c9ac481ba6eb7b6a844e4"+        , _proposalVoteAction    = VotingAction_Abstain+        }+    ]++-- | Prposal metadata+data ProposalMeta = ProposalMeta+  { _proposalMetaTxHash       :: TxHash  -- ^ Transaction ID+  , _proposalMetaCertIndex    :: Integer -- ^ Index of the certificate within the proposal transaction+  , _proposalMetaUrl          :: Text    -- ^ URL to the proposal metadata+  , _proposalMetaHash         :: Text    -- ^ Hash of the metadata file+  , _proposalMetaJsonMetadata :: Value   -- ^ Content of the JSON metadata (validated CIP-108)+  , _proposalMetaBytes        :: Text    -- ^ Hex-encoded metadata (raw)+  }+  deriving stock (Show, Eq, Generic)+  deriving (FromJSON, ToJSON)+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_proposalMeta", CamelToSnake]] ProposalMeta++instance ToSample ProposalMeta where+  toSamples = pure $ singleSample $ ProposalMeta+    { _proposalMetaTxHash       = "257d75c8ddb0434e9b63e29ebb6241add2b835a307aa33aedba2effe09ed4ec8"+    , _proposalMetaCertIndex    = 2+    , _proposalMetaUrl          = "https://raw.githubusercontent.com/carloslodelar/proposals/main/pv10.json"+    , _proposalMetaHash         = "ffa226f3863aca006172d559cf46bb8b883a47233962ae2fc94c158d7de6fa81"+    , _proposalMetaJsonMetadata = object+        [ "body" .= object+            [ "title" .= ("Hardfork to Protocol version 10" :: Text)+            , "abstract" .= ("Let's have sanchoNet in full governance as soon as possible" :: Text)+            , "rationale" .= ("Let's keep testing stuff" :: Text)+            , "motivation" .= ("PV9 is not as fun as PV10" :: Text)+            , "references" .=+                [ object+                    [ "@type" .= ("Other" :: Text)+                    , "label" .= ("Hardfork to PV10" :: Text)+                    , "uri"   .= ("" :: Text)+                    ]+                ]+            ]+        , "authors" .=+            [ object+                [ "name" .= ("Carlos" :: Text)+                , "witness" .= object+                    [ "publicKey" .= ("7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a" :: Text)+                    , "signature" .= ("a476985b4cc0d457f247797611799a6f6a80fc8cb7ec9dcb5a8223888d0618e30de165f3d869c4a0d9107d8a5b612ad7c5e42441907f5b91796f0d7187d64a01" :: Text)+                    , "witnessAlgorithm" .= ("ed25519" :: Text)+                    ]+                ]+            ]+        , "@context" .= object+            [ "CIP100" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#" :: Text)+            , "CIP108" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#" :: Text)+            , "hashAlgorithm" .= ("CIP100:hashAlgorithm" :: Text)+            , "@language" .= ("en-us" :: Text)+            , "body" .= object+                [ "@id" .= ("CIP108:body" :: Text)+                , "@context" .= object+                    [ "title" .= ("CIP108:title" :: Text)+                    , "abstract" .= ("CIP108:abstract" :: Text)+                    , "rationale" .= ("CIP108:rationale" :: Text)+                    , "motivation" .= ("CIP108:motivation" :: Text)+                    , "references" .= object+                        [ "@id" .= ("CIP108:references" :: Text)+                        , "@container" .= ("@set" :: Text)+                        , "@context" .= object+                            [ "uri" .= ("CIP100:reference-uri" :: Text)+                            , "Other" .= ("CIP100:OtherReference" :: Text)+                            , "label" .= ("CIP100:reference-label" :: Text)+                            , "GovernanceMetadata" .= ("CIP100:GovernanceMetadataReference" :: Text)+                            , "referenceHash" .= object+                                [ "@id" .= ("CIP108:referenceHash" :: Text)+                                , "@context" .= object+                                    [ "hashDigest" .= ("CIP108:hashDigest" :: Text)+                                    , "hashAlgorithm" .= ("CIP100:hashAlgorithm" :: Text)+                                    ]+                                ]+                            ]+                        ]+                    ]+                ]+            , "authors" .= object+                [ "@id" .= ("CIP100:authors" :: Text)+                , "@container" .= ("@set" :: Text)+                , "@context" .= object+                    [ "name" .= ("http://xmlns.com/foaf/0.1/name" :: Text)+                    , "witness" .= object+                        [ "@id" .= ("CIP100:witness" :: Text)+                        , "@context" .= object+                            [ "publicKey" .= ("CIP100:publicKey" :: Text)+                            , "signature" .= ("CIP100:signature" :: Text)+                            , "witnessAlgorithm" .= ("CIP100:witnessAlgorithm" :: Text)+                            ]+                        ]+                    ]+                ]+            ]+        , "hashAlgorithm" .= ("blake2b-256" :: Text)+        ]+    , _proposalMetaBytes        = "\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6d6423222c0a2020202022434950313038223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130382f524541444d452e6d6423222c0a202020202268617368416c676f726974686d223a20224349503130303a68617368416c676f726974686d222c0a2020202022626f6479223a207b0a20202020202022406964223a20224349503130383a626f6479222c0a2020202020202240636f6e74657874223a207b0a2020202020202020227265666572656e636573223a207b0a2020202020202020202022406964223a20224349503130383a7265666572656e636573222c0a202020202020202020202240636f6e7461696e6572223a202240736574222c0a202020202020202020202240636f6e74657874223a207b0a20202020202020202020202022476f7665726e616e63654d65746164617461223a20224349503130303a476f7665726e616e63654d657461646174615265666572656e6365222c0a202020202020202020202020224f74686572223a20224349503130303a4f746865725265666572656e6365222c0a202020202020202020202020226c6162656c223a20224349503130303a7265666572656e63652d6c6162656c222c0a20202020202020202020202022757269223a20224349503130303a7265666572656e63652d757269222c0a202020202020202020202020227265666572656e636548617368223a207b0a202020202020202020202020202022406964223a20224349503130383a7265666572656e636548617368222c0a20202020202020202020202020202240636f6e74657874223a207b0a202020202020202020202020202020202268617368446967657374223a20224349503130383a68617368446967657374222c0a202020202020202020202020202020202268617368416c676f726974686d223a20224349503130303a68617368416c676f726974686d220a20202020202020202020202020207d0a2020202020202020202020207d0a202020202020202020207d0a20202020202020207d2c0a2020202020202020227469746c65223a20224349503130383a7469746c65222c0a2020202020202020226162737472616374223a20224349503130383a6162737472616374222c0a2020202020202020226d6f7469766174696f6e223a20224349503130383a6d6f7469766174696f6e222c0a202020202020202022726174696f6e616c65223a20224349503130383a726174696f6e616c65220a2020202020207d0a202020207d2c0a2020202022617574686f7273223a207b0a20202020202022406964223a20224349503130303a617574686f7273222c0a2020202020202240636f6e7461696e6572223a202240736574222c0a2020202020202240636f6e74657874223a207b0a2020202020202020226e616d65223a2022687474703a2f2f786d6c6e732e636f6d2f666f61662f302e312f6e616d65222c0a2020202020202020227769746e657373223a207b0a2020202020202020202022406964223a20224349503130303a7769746e657373222c0a202020202020202020202240636f6e74657874223a207b0a202020202020202020202020227769746e657373416c676f726974686d223a20224349503130303a7769746e657373416c676f726974686d222c0a202020202020202020202020227075626c69634b6579223a20224349503130303a7075626c69634b6579222c0a202020202020202020202020227369676e6174757265223a20224349503130303a7369676e6174757265220a202020202020202020207d0a20202020202020207d0a2020202020207d0a202020207d0a20207d2c0a20202268617368416c676f726974686d223a2022626c616b6532622d323536222c0a202022626f6479223a207b0a20202020227469746c65223a202248617264666f726b20746f2050726f746f636f6c2076657273696f6e203130222c0a20202020226162737472616374223a20224c6574277320686176652073616e63686f4e657420696e2066756c6c20676f7665726e616e636520617320736f6f6e20617320706f737369626c65222c0a20202020226d6f7469766174696f6e223a2022505639206973206e6f742061732066756e2061732050563130222c0a2020202022726174696f6e616c65223a20224c65742773206b6565702074657374696e67207374756666222c0a20202020227265666572656e636573223a205b0a2020202020207b0a2020202020202020224074797065223a20224f74686572222c0a2020202020202020226c6162656c223a202248617264666f726b20746f2050563130222c0a202020202020202022757269223a2022220a2020202020207d0a202020205d0a20207d2c0a202022617574686f7273223a205b0a202020207b0a202020202020226e616d65223a20224361726c6f73222c0a202020202020227769746e657373223a207b0a2020202020202020227769746e657373416c676f726974686d223a202265643235353139222c0a2020202020202020227075626c69634b6579223a202237656130396133346165626231336339383431633731333937623163616266656335646466393530343035323933646565343936636163326634333734383061222c0a2020202020202020227369676e6174757265223a20226134373639383562346363306434353766323437373937363131373939613666366138306663386362376563396463623561383232333838386430363138653330646531363566336438363963346130643931303764386135623631326164376335653432343431393037663562393137393666306437313837643634613031220a2020202020207d0a202020207d0a20205d0a7d"+    }
src/Blockfrost/Types/Cardano/Mempool.hs view
@@ -47,7 +47,7 @@   via CustomJSON '[FieldLabelModifier '[StripPrefix "_transaction", CamelToSnake]] TransactionInMempool  data MempoolUTxOInput = MempoolUTxOInput-   { _address :: Text -- ^ Address+   { _address :: Maybe Text -- ^ Address    , _txHash :: Text -- ^ Transaction hash    , _outputIndex :: Integer -- ^ Output index    , _collateral :: Bool -- ^ True if the input is a collateral input
src/Blockfrost/Types/Shared.hs view
@@ -9,6 +9,7 @@   , module Blockfrost.Types.Shared.BlockIndex   , module Blockfrost.Types.Shared.CBOR   , module Blockfrost.Types.Shared.DatumHash+  , module Blockfrost.Types.Shared.DRepId   , module Blockfrost.Types.Shared.Epoch   , module Blockfrost.Types.Shared.Opts   , module Blockfrost.Types.Shared.POSIXMillis@@ -29,6 +30,7 @@ import Blockfrost.Types.Shared.BlockIndex import Blockfrost.Types.Shared.CBOR import Blockfrost.Types.Shared.DatumHash+import Blockfrost.Types.Shared.DRepId import Blockfrost.Types.Shared.Epoch import Blockfrost.Types.Shared.Opts import Blockfrost.Types.Shared.POSIXMillis
+ src/Blockfrost/Types/Shared/DRepId.hs view
@@ -0,0 +1,86 @@+-- | DRep identifier++module Blockfrost.Types.Shared.DRepId+  where++import Data.Aeson (FromJSON (..), ToJSON (..), withText)+import Data.String (IsString (..))+import Data.Text (Text)+import qualified Data.Text+import GHC.Generics+import Servant.API (Capture, FromHttpApiData (..), ToHttpApiData (..))+import Servant.Docs (DocCapture (..), ToCapture (..), ToSample (..), samples)++newtype DRepIdBech32 = DRepIdBech32 Text+  deriving stock (Eq, Show, Generic)+  deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON)++mkDRepIdBech32 :: Text -> DRepIdBech32+mkDRepIdBech32 = DRepIdBech32++unDRepIdBech32 :: DRepIdBech32 -> Text+unDRepIdBech32 (DRepIdBech32 a) = a++instance IsString DRepIdBech32 where+  fromString = mkDRepIdBech32 . Data.Text.pack++instance ToSample DRepIdBech32 where+    toSamples = pure $ samples+      [ "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn"+      , "drep1cxayn4fgy27yaucvhamsvqj3v6835mh3tjjx6x8hdnr4"+      ]++newtype DRepIdHex = DRepIdHex Text+  deriving stock (Eq, Show, Generic)+  deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON)++mkDRepIdHex :: Text -> DRepIdHex+mkDRepIdHex = DRepIdHex++unDRepIdHex :: DRepIdHex -> Text+unDRepIdHex (DRepIdHex a) = a++instance IsString DRepIdHex where+  fromString = mkDRepIdHex . Data.Text.pack++instance ToSample DRepIdHex where+    toSamples = pure $ samples+      [ "db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23"+      , "c1ba49d52822bc4ef30cbf77060251668f1a6ef15ca46d18f76cc758"+      ]++data DRepId+  = DRepId_Bech32 DRepIdBech32+  | DRepId_Hex DRepIdHex+  deriving stock (Eq, Show, Generic)++instance ToJSON DRepId where+  toJSON (DRepId_Bech32 dRepIdBech32) = toJSON dRepIdBech32+  toJSON (DRepId_Hex dRepIdHex)       = toJSON dRepIdHex++  toEncoding (DRepId_Bech32 dRepIdBech32) = toEncoding dRepIdBech32+  toEncoding (DRepId_Hex dRepIdHex)       = toEncoding dRepIdHex++instance FromJSON DRepId where+  parseJSON = withText "dRepId" $ \case+    x | "drep" `Data.Text.isPrefixOf` x -> pure $ DRepId_Bech32 $ DRepIdBech32 x+    x | otherwise                       -> pure $ DRepId_Hex $ DRepIdHex x++instance ToHttpApiData DRepId where+  toUrlPiece (DRepId_Bech32 x) = toUrlPiece x+  toUrlPiece (DRepId_Hex x)   = toUrlPiece x++instance FromHttpApiData DRepId where+  parseUrlPiece  x | "drep" `Data.Text.isPrefixOf` x = Right $ DRepId_Bech32 (DRepIdBech32 x)+  parseUrlPiece  x | otherwise                       = Right $ DRepId_Hex (DRepIdHex x)++instance ToSample DRepId where+    toSamples = pure $ samples+      [ DRepId_Bech32 "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn"+      , DRepId_Bech32 "drep1cxayn4fgy27yaucvhamsvqj3v6835mh3tjjx6x8hdnr4"+      , DRepId_Hex "db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23"+      , DRepId_Hex "c1ba49d52822bc4ef30cbf77060251668f1a6ef15ca46d18f76cc758"+      ]++instance ToCapture (Capture "drep_id" DRepId) where+  toCapture _ = DocCapture "drep_id" "Bech32 or hexadecimal DRep ID."
test/Cardano/Accounts.hs view
@@ -73,7 +73,8 @@     "reserves_sum": "319154618165",     "treasury_sum": "12000000",     "withdrawable_amount": "319154618165",-    "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy"+    "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy",+    "drep_id": "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc" } |] @@ -88,6 +89,7 @@     , _accountInfoTreasurySum = 12000000     , _accountInfoWithdrawableAmount = 319154618165     , _accountInfoPoolId = pure "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy"+    , _accountInfoDrepId = pure "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc"     }  accountRewardsSample = [r|
+ test/Cardano/Governance.hs view
@@ -0,0 +1,836 @@+{-# LANGUAGE NumericUnderscores #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++module Cardano.Governance+  where++import Data.Aeson (decode, eitherDecode, encode, object, (.=))+import qualified Data.Map+import Data.Text (Text)+import qualified Money+import Test.Hspec+import Test.Tasty.Hspec+import Text.RawString.QQ++import Blockfrost.Types++spec_epochs :: Spec+spec_epochs = do+  it "parses DReps sample" $ do+    eitherDecode dRepsSample+    `shouldBe`+    Right dRepsExpected++  it "parses DRepInfo sample" $ do+    eitherDecode dRepInfoSample+    `shouldBe`+    Right dRepInfoExpected++  it "parses DRepDelegators sample" $ do+    eitherDecode dRepDelegatorsSample+    `shouldBe`+    Right dRepDelegatorsExpected++  it "parses DRepMeta sample" $ do+    eitherDecode dRepMetaSample+    `shouldBe`+    Right dRepMetaExpected++  it "parses DRepUpdates sample" $ do+      eitherDecode dRepUpdatesSample+      `shouldBe`+      Right dRepUpdatesExpected++  it "parses DRepVotes sample" $ do+      eitherDecode dRepVotesSample+      `shouldBe`+      Right dRepVotesExpected++  it "parses Proposals sample" $ do+      eitherDecode dRepProposalsSample+      `shouldBe`+      Right dRepProposalsExpected++  it "parses ProposalInfo sample" $ do+      eitherDecode proposalInfoSample+      `shouldBe`+      Right proposalInfoExpected++  it "parses ParamProposal sample" $ do+    eitherDecode paramProposalSample+    `shouldBe`+    Right paramProposalExpected++  it "parses WithdrawalProposals sample" $ do+    eitherDecode withdrawalProposalSample+    `shouldBe`+    Right withdrawalProposalExpected++  it "parses ProposalVotes sample" $ do+    eitherDecode proposalVotesSample+    `shouldBe`+    Right proposalVotesExpected++  it "parses ProposalMeta sample" $ do+    eitherDecode proposalMetaSample+    `shouldBe`+    Right proposalMetaExpected++dRepsSample = [r|+[+  {+    "drep_id": "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn",+    "hex": "db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23"+  },+  {+    "drep_id": "drep1cxayn4fgy27yaucvhamsvqj3v6835mh3tjjx6x8hdnr4",+    "hex": "c1ba49d52822bc4ef30cbf77060251668f1a6ef15ca46d18f76cc758"+  }+]+|]++dRepsExpected :: [DRep]+dRepsExpected =+  [ DRep+      { _dRepDrepId = "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn"+      , _dRepHex    = "db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23"+      }+  , DRep+      { _dRepDrepId = "drep1cxayn4fgy27yaucvhamsvqj3v6835mh3tjjx6x8hdnr4"+      , _dRepHex    = "c1ba49d52822bc4ef30cbf77060251668f1a6ef15ca46d18f76cc758"+      }+  ]++dRepInfoSample = [r|+{+  "drep_id": "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc",+  "hex": "a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d",+  "amount": "2000000",+  "active": true,+  "active_epoch": 420,+  "has_script": true,+  "last_active_epoch": 509,+  "retired": false,+  "expired": false+}+|]++dRepInfoExpected :: DRepInfo+dRepInfoExpected =+  DRepInfo+    { _dRepInfoDrepId          = "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc"+    , _dRepInfoHex             = "a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d"+    , _dRepInfoAmount          = 2000000+    , _dRepInfoHasScript       = True+    , _dRepInfoRetired         = False+    , _dRepInfoExpired         = False+    , _dRepInfoLastActiveEpoch = Just 509+    }+++dRepDelegatorsSample = [r|+[+  {+    "address": "stake1ux4vspfvwuus9uwyp5p3f0ky7a30jq5j80jxse0fr7pa56sgn8kha",+    "amount": "1137959159981411"+  },+  {+    "address": "stake1uylayej7esmarzd4mk4aru37zh9yz0luj3g9fsvgpfaxulq564r5u",+    "amount": "16958865648"+  },+  {+    "address": "stake1u8lr2pnrgf8f7vrs9lt79hc3sxm8s2w4rwvgpncks3axx6q93d4ck",+    "amount": "18605647"+  }+]+|]++dRepDelegatorsExpected :: [DRepDelegator]+dRepDelegatorsExpected =+    [ DRepDelegator+        { _dRepDelegatorAddress = "stake1ux4vspfvwuus9uwyp5p3f0ky7a30jq5j80jxse0fr7pa56sgn8kha"+        , _dRepDelegatorAmount  = 1137959159981411+        }+    , DRepDelegator+        { _dRepDelegatorAddress = "stake1uylayej7esmarzd4mk4aru37zh9yz0luj3g9fsvgpfaxulq564r5u"+        , _dRepDelegatorAmount  = 16958865648+        }+    , DRepDelegator+        { _dRepDelegatorAddress = "stake1u8lr2pnrgf8f7vrs9lt79hc3sxm8s2w4rwvgpncks3axx6q93d4ck"+        , _dRepDelegatorAmount  = 18605647+        }+    ]++dRepMetaSample = [r|+{+  "drep_id": "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc",+  "hex": "a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d",+  "url": "https://aaa.xyz/drep.json",+  "hash": "a14a5ad4f36bddc00f92ddb39fd9ac633c0fd43f8bfa57758f9163d10ef916de",+  "json_metadata": {+    "@context": {+      "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#",+      "CIP119": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md#",+      "hashAlgorithm": "CIP100:hashAlgorithm",+      "body": {+        "@id": "CIP119:body",+        "@context": {+          "references": {+            "@id": "CIP119:references",+            "@container": "@set",+            "@context": {+              "GovernanceMetadata": "CIP100:GovernanceMetadataReference",+              "Other": "CIP100:OtherReference",+              "label": "CIP100:reference-label",+              "uri": "CIP100:reference-uri"+            }+          },+          "paymentAddress": "CIP119:paymentAddress",+          "givenName": "CIP119:givenName",+          "image": {+            "@id": "CIP119:image",+            "@context": {+              "ImageObject": "https://schema.org/ImageObject"+            }+          },+          "objectives": "CIP119:objectives",+          "motivations": "CIP119:motivations",+          "qualifications": "CIP119:qualifications"+        }+      }+    },+    "hashAlgorithm": "blake2b-256",+    "body": {+      "paymentAddress": "addr1q86dnpkva4mm859c8ur7tjxn57zgsu6vg8pdetkdve3fsacnq7twy06u2ev5759vutpjgzfryx0ud8hzedhzerava35qwh3x34",+      "givenName": "Ryan Williams",+      "image": {+        "@type": "ImageObject",+        "contentUrl": "https://avatars.githubusercontent.com/u/44342099?v=4",+        "sha256": "2a21e4f7b20c8c72f573707b068fb8fc6d8c64d5035c4e18ecae287947fe2b2e"+      },+      "objectives": "Buy myself an island.",+      "motivations": "I really would like to own an island.",+      "qualifications": "I have my 100m swimming badge, so I would be qualified to be able to swim around island.",+      "references": [+        {+          "@type": "Other",+          "label": "A cool island for Ryan",+          "uri": "https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu"+        },+        {+          "@type": "Link",+          "label": "Ryan's Twitter",+          "uri": "https://twitter.com/Ryun1_"+        }+      ]+    }+  },+  "bytes": "\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6"+}+|]++dRepMetaExpected :: DRepMeta+dRepMetaExpected =+  DRepMeta+    { _dRepMetaDrepId          = "drep15cfxz9exyn5rx0807zvxfrvslrjqfchrd4d47kv9e0f46uedqtc"+    , _dRepMetaHex             = "a61261172624e8333ceff098648d90f8e404e2e36d5b5f5985cbd35d"+    , _dRepMetaUrl             = "https://aaa.xyz/drep.json"+    , _dRepMetaHash            = "a14a5ad4f36bddc00f92ddb39fd9ac633c0fd43f8bfa57758f9163d10ef916de"+    , _dRepMetaJsonMetadata    = object+      [ "@context" .= object+          [ "CIP100" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#" :: Text)+          , "CIP119" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md#" :: Text)+          , "hashAlgorithm" .= ("CIP100:hashAlgorithm" :: Text)+          , "body" .= object+            [ "@id" .= ("CIP119:body" :: Text)+            , "@context" .= object+                [ "references" .= object+                    [ "@id" .= ("CIP119:references" :: Text)+                    , "@container" .= ("@set" :: Text)+                    , "@context" .= object+                        [ "GovernanceMetadata" .= ("CIP100:GovernanceMetadataReference" :: Text)+                        , "Other" .= ("CIP100:OtherReference" :: Text)+                        , "label" .= ("CIP100:reference-label" :: Text)+                        , "uri" .= ("CIP100:reference-uri" :: Text)+                        ]+                    ]+                    , "paymentAddress" .= ("CIP119:paymentAddress" :: Text)+                    , "givenName" .= ("CIP119:givenName" :: Text)+                    , "image" .= object+                        [ "@id" .= ("CIP119:image" :: Text)+                        , "@context" .= object+                            [ "ImageObject" .= ("https://schema.org/ImageObject" :: Text) ]+                        ]+                    , "objectives" .= ("CIP119:objectives" :: Text)+                    , "motivations" .= ("CIP119:motivations" :: Text)+                    , "qualifications" .= ("CIP119:qualifications" :: Text)+                    ]+                ]+            ]+        , "hashAlgorithm" .= ("blake2b-256" :: Text)+        , "body" .= object+            [ "paymentAddress" .= ("addr1q86dnpkva4mm859c8ur7tjxn57zgsu6vg8pdetkdve3fsacnq7twy06u2ev5759vutpjgzfryx0ud8hzedhzerava35qwh3x34" :: Text)+            , "givenName" .= ("Ryan Williams" :: Text)+            , "image" .= object+                [ "@type" .= ("ImageObject" :: Text)+                , "contentUrl" .= ("https://avatars.githubusercontent.com/u/44342099?v=4" :: Text)+                , "sha256" .= ("2a21e4f7b20c8c72f573707b068fb8fc6d8c64d5035c4e18ecae287947fe2b2e" :: Text)+                ]+            , "objectives" .= ("Buy myself an island." :: Text)+            , "motivations" .= ("I really would like to own an island." :: Text)+            , "qualifications" .= ("I have my 100m swimming badge, so I would be qualified to be able to swim around island." :: Text)+            , "references" .=+                [ object+                    [ "@type" .= ("Other" :: Text)+                    , "label" .= ("A cool island for Ryan" :: Text)+                    , "uri" .= ("https://www.google.com/maps/place/World's+only+5th+order+recursive+island/@62.6511465,-97.7946829,15.75z/data=!4m14!1m7!3m6!1s0x5216a167810cee39:0x11431abdfe4c7421!2sWorld's+only+5th+order+recursive+island!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n!3m5!1s0x5216a167810cee39:0x11431abdfe4c7421!8m2!3d62.651114!4d-97.7872244!16s%2Fg%2F11spwk2b6n?authuser=0&entry=ttu" :: Text)+                    ]+                , object+                    [ "@type" .= ("Link" :: Text)+                    , "label" .= ("Ryan's Twitter" :: Text)+                    , "uri" .= ("https://twitter.com/Ryun1_" :: Text)+                    ]+                ]+            ]+        ]+    , _dRepMetaBytes           = "\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6"+    }++dRepUpdatesSample = [r|+[+  {+    "tx_hash": "f4097fbdb87ab7c7ab44b30d4e2b81713a058488975d1ab8b05c381dd946a393",+    "cert_index": 0,+    "action": "registered"+  },+  {+    "tx_hash": "dd3243af975be4b5bedce4e5f5b483b2386d5ad207d05e0289c1df0eb261447e",+    "cert_index": 0,+    "action": "deregistered"+  }+]+|]++dRepUpdatesExpected :: [DRepUpdate]+dRepUpdatesExpected =+  [ DRepUpdate+      { _dRepUpdateTxHash = "f4097fbdb87ab7c7ab44b30d4e2b81713a058488975d1ab8b05c381dd946a393"+      , _dRepUpdateCertIndex = 0+      , _dRepUpdateAction = DRepRegistrationAction_Registered+      }+  , DRepUpdate+      { _dRepUpdateTxHash = "dd3243af975be4b5bedce4e5f5b483b2386d5ad207d05e0289c1df0eb261447e"+      , _dRepUpdateCertIndex = 0+      , _dRepUpdateAction = DRepRegistrationAction_Deregistered+      }+  ]++dRepVotesSample = [r|+[+  {+    "tx_hash": "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5",+    "cert_index": 2,+    "vote": "yes"+  },+  {+    "tx_hash": "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5",+    "cert_index": 3,+    "vote": "abstain"+  }+]+|]++dRepVotesExpected :: [DRepVote]+dRepVotesExpected =+  [ DRepVote+      { _dRepVoteTxHash = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+      , _dRepVoteCertIndex = 2+      , _dRepVoteAction = VotingAction_Yes+      }+  , DRepVote+      { _dRepVoteTxHash = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+      , _dRepVoteCertIndex = 3+      , _dRepVoteAction = VotingAction_Abstain+      }+  ]+++dRepProposalsSample = [r|+[+  {+    "tx_hash": "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531",+    "cert_index": 1,+    "governance_type": "treasury_withdrawals"+  },+  {+    "tx_hash": "71317e951b20aa46e9fbf45a46a6e950d5723a481225519655bf6c60",+    "cert_index": 4,+    "governance_type": "no_confidence"+  }+]+|]++dRepProposalsExpected :: [Proposal]+dRepProposalsExpected =+  [ Proposal+      { _dRepProposalTxHash = "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531"+      , _dRepProposalCertIndex = 1+      , _dRepProposalAction = ProposalAction_TreasuryWithdrawals+      }+  , Proposal+      { _dRepProposalTxHash = "71317e951b20aa46e9fbf45a46a6e950d5723a481225519655bf6c60"+      , _dRepProposalCertIndex = 4+      , _dRepProposalAction = ProposalAction_NoConfidence+      }+  ]++proposalInfoSample = [r|+{+  "tx_hash": "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531",+  "cert_index": 1,+  "governance_type": "treasury_withdrawals",+  "deposit": "12000",+  "return_address": "stake_test1urd3hs7rlxwwdzthe6hj026dmyt3y0heuulctscyydh2kgck6nkmz",+  "governance_description":+    {"tag" :"InfoAction" },+  "ratified_epoch": null,+  "enacted_epoch": 123,+  "dropped_epoch": null,+  "expired_epoch": null,+  "expiration": 120+}+|]++proposalInfoExpected :: ProposalInfo+proposalInfoExpected =+  ProposalInfo+    { _proposalInfoTxHash                = "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531"+    , _proposalInfoCertIndex             = 1+    , _proposalInfoGovernanceType        = ProposalAction_TreasuryWithdrawals+    , _proposalInfoDeposit               = 12000+    , _proposalInfoReturnAddress         = "stake_test1urd3hs7rlxwwdzthe6hj026dmyt3y0heuulctscyydh2kgck6nkmz"+    , _proposalInfoGovernanceDescription = Just $ object [ "tag" .= ("InfoAction" :: Text) ]+    , _proposalInfoRatifiedEpoch         = Nothing+    , _proposalInfoEnactedEpoch          = Just 123+    , _proposalInfoDroppedEpoch          = Nothing+    , _proposalInfoExpiredEpoch          = Nothing+    , _proposalInfoExpiration            = 120+    }++paramProposalSample = [r|+{+  "tx_hash": "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531",+  "cert_index": 2,+  "parameters": {+    "epoch": 225,+    "min_fee_a": 44,+    "min_fee_b": 155381,+    "max_block_size": 65536,+    "max_tx_size": 16384,+    "max_block_header_size": 1100,+    "key_deposit": "2000000",+    "pool_deposit": "500000000",+    "e_max": 18,+    "n_opt": 150,+    "a0": 0.3,+    "rho": 0.003,+    "tau": 0.2,+    "decentralisation_param": 0.5,+    "extra_entropy": null,+    "protocol_major_ver": 2,+    "protocol_minor_ver": 0,+    "min_utxo": "1000000",+    "min_pool_cost": "340000000",+    "nonce": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81",+    "cost_models": {+      "PlutusV1": {+        "addInteger-cpu-arguments-intercept": 197209,+        "addInteger-cpu-arguments-slope": 0+      },+      "PlutusV2":+      {+        "addInteger-cpu-arguments-intercept": 197209,+        "addInteger-cpu-arguments-slope": 0+      }+    },+    "cost_models_raw": {+      "PlutusV1": [+        197209,+        0+      ],+      "PlutusV2": [+        197209,+        0+      ],+      "PlutusV3": [+        197209,+        0+      ]+    },+    "price_mem": 0.0577,+    "price_step": 0.0000721,+    "max_tx_ex_mem": "10000000",+    "max_tx_ex_steps": "10000000000",+    "max_block_ex_mem": "50000000",+    "max_block_ex_steps": "40000000000",+    "max_val_size": "5000",+    "collateral_percent": 150,+    "max_collateral_inputs": 3,+    "coins_per_utxo_size": "34482",+    "coins_per_utxo_word": "34482",+    "pvt_motion_no_confidence": 0.51,+    "pvt_committee_normal": 0.51,+    "pvt_committee_no_confidence": 0.51,+    "pvt_hard_fork_initiation": 0.51,+    "dvt_motion_no_confidence": 0.67,+    "dvt_committee_normal": 0.67,+    "dvt_committee_no_confidence": 0.6,+    "dvt_update_to_constitution": 0.75,+    "dvt_hard_fork_initiation": 0.6,+    "dvt_p_p_network_group": 0.67,+    "dvt_p_p_economic_group": 0.67,+    "dvt_p_p_technical_group": 0.67,+    "dvt_p_p_gov_group": 0.75,+    "dvt_treasury_withdrawal": 0.67,+    "committee_min_size": "7",+    "committee_max_term_length": "146",+    "gov_action_lifetime": "6",+    "gov_action_deposit": "100000000000",+    "drep_deposit": "500000000",+    "drep_activity": "20",+    "pvtpp_security_group": 0.51,+    "min_fee_ref_script_cost_per_byte": 15+  }+}+|]++paramProposalExpected :: ParamProposal+paramProposalExpected =+  ParamProposal+    { _paramProposalTxHash     = "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531"+    , _paramProposalCertIndex  = 2+    , _paramProposalParameters =+      ProposedProtocolParams+        { _proposedProtocolParamsEpoch = Just 225+        , _proposedProtocolParamsMinFeeA = Just 44+        , _proposedProtocolParamsMinFeeB = Just 155381+        , _proposedProtocolParamsMaxBlockSize = Just 65536+        , _proposedProtocolParamsMaxTxSize = Just 16384+        , _proposedProtocolParamsMaxBlockHeaderSize = Just 1100+        , _proposedProtocolParamsKeyDeposit = Just 2000000+        , _proposedProtocolParamsPoolDeposit = Just 500000000+        , _proposedProtocolParamsEMax = Just 18+        , _proposedProtocolParamsNOpt = Just 150+        , _proposedProtocolParamsA0 = Just 0.3+        , _proposedProtocolParamsRho = Just 0.003+        , _proposedProtocolParamsTau = Just 0.2+        , _proposedProtocolParamsDecentralisationParam = Just 0.5+        , _proposedProtocolParamsExtraEntropy = Nothing+        , _proposedProtocolParamsProtocolMajorVer = Just 2+        , _proposedProtocolParamsProtocolMinorVer = Just 0+        , _proposedProtocolParamsMinUtxo = Just 1000000+        , _proposedProtocolParamsMinPoolCost = Just 340000000+        , _proposedProtocolParamsNonce = Just "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81"+        , _proposedProtocolParamsCostModels =+            Just+          $ CostModels+          $ Data.Map.fromList+          [ ( PlutusV1+            , Data.Map.fromList+              [ ("addInteger-cpu-arguments-intercept", 197209)+              , ("addInteger-cpu-arguments-slope", 0)+              ]+            )+          , (PlutusV2+            , Data.Map.fromList+              [ ("addInteger-cpu-arguments-intercept", 197209)+              , ("addInteger-cpu-arguments-slope", 0)+              ]+            )+          ]+        , _proposedProtocolParamsCostModelsRaw =+            Just+          $ CostModelsRaw+          $ Data.Map.fromList+          [ ( PlutusV1+            , [ 197209+              , 0+              ]+            )+          , (PlutusV2+            , [ 197209+              , 0+              ]+            )+          , (PlutusV3+            , [ 197209+              , 0+              ]+            )+          ]+        , _proposedProtocolParamsPriceMem = Just 0.0577+        , _proposedProtocolParamsPriceStep = Just 0.0000721+        , _proposedProtocolParamsMaxTxExMem = Just 10000000+        , _proposedProtocolParamsMaxTxExSteps = Just 10000000000+        , _proposedProtocolParamsMaxBlockExMem = Just 50000000+        , _proposedProtocolParamsMaxBlockExSteps = Just 40000000000+        , _proposedProtocolParamsMaxValSize = Just 5000+        , _proposedProtocolParamsCollateralPercent = Just 150+        , _proposedProtocolParamsMaxCollateralInputs = Just 3+        , _proposedProtocolParamsCoinsPerUtxoSize = Just 34482+        -- deprecated+        , _proposedProtocolParamsCoinsPerUtxoWord = Just 34482+        , _proposedProtocolParamsPvtMotionNoConfidence = Just 0.51+        , _proposedProtocolParamsPvtCommitteeNormal = Just 0.51+        , _proposedProtocolParamsPvtCommitteeNoConfidence = Just 0.51+        , _proposedProtocolParamsPvtHardForkInitiation = Just 0.51+        , _proposedProtocolParamsPvtppSecurityGroup = Just 0.51+        , _proposedProtocolParamsDvtMotionNoConfidence = Just 0.67+        , _proposedProtocolParamsDvtCommitteeNormal = Just 0.67+        , _proposedProtocolParamsDvtCommitteeNoConfidence = Just 0.6+        , _proposedProtocolParamsDvtUpdateToConstitution = Just 0.75+        , _proposedProtocolParamsDvtHardForkInitiation = Just 0.6+        , _proposedProtocolParamsDvtPPNetworkGroup = Just 0.67+        , _proposedProtocolParamsDvtPPEconomicGroup = Just 0.67+        , _proposedProtocolParamsDvtPPTechnicalGroup = Just 0.67+        , _proposedProtocolParamsDvtPPGovGroup = Just 0.75+        , _proposedProtocolParamsDvtTreasuryWithdrawal = Just 0.67+        , _proposedProtocolParamsCommitteeMinSize = Just 7+        , _proposedProtocolParamsCommitteeMaxTermLength = Just 146+        , _proposedProtocolParamsGovActionLifetime = Just 6+        , _proposedProtocolParamsGovActionDeposit = Just 100000000000+        , _proposedProtocolParamsDrepDeposit = Just 500000000+        , _proposedProtocolParamsDrepActivity = Just 20+        , _proposedProtocolParamsMinFeeRefScriptCostPerByte = Just 15+        }+    }++withdrawalProposalSample = [r|+[+  {+    "stake_address": "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7",+    "amount": "454541212442"+  },+  {+    "stake_address": "stake1xx2g2c9dx2nhhehyrezyxpkstoppcqmu9hk63qgfkccw5rqttygt2",+    "amount": "97846969"+  }+]+|]++withdrawalProposalExpected :: [WithdrawalProposal]+withdrawalProposalExpected =+  [ WithdrawalProposal+      { _withdrawalProposalStakeAddress = "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7"+      , _withdrawalProposalAmount       = 454541212442+      }+  , WithdrawalProposal+      { _withdrawalProposalStakeAddress = "stake1xx2g2c9dx2nhhehyrezyxpkstoppcqmu9hk63qgfkccw5rqttygt2"+      , _withdrawalProposalAmount       = 97846969+      }+  ]++proposalVotesSample = [r|+[+  {+    "tx_hash": "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5",+    "cert_index": 2,+    "voter_role": "drep",+    "voter": "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn",+    "vote": "yes"+  },+  {+    "tx_hash": "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5",+    "cert_index": 3,+    "voter_role": "constitutional_committee",+    "voter": "53a42debdc7ffd90085ab7fd9800b63e6d1c9ac481ba6eb7b6a844e4",+    "vote": "abstain"+  }+]+|]++proposalVotesExpected :: [ProposalVote]+proposalVotesExpected =+    [ ProposalVote+        { _proposalVoteTxHash    = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+        , _proposalVoteCertIndex = 2+        , _proposalVoteVoterRole = VoterRole_DRep+        , _proposalVoteVoter     = DRepId_Bech32 "drep1mvdu8slennngja7w4un6knwezufra70887zuxpprd64jxfveahn"+        , _proposalVoteAction    = VotingAction_Yes+        }+    , ProposalVote+        { _proposalVoteTxHash    = "b302de601defdf11a5261ed31a263804dac4a582a888c998ce24dec5"+        , _proposalVoteCertIndex = 3+        , _proposalVoteVoterRole = VoterRole_ConstitutionalCommittee+        , _proposalVoteVoter     = DRepId_Hex "53a42debdc7ffd90085ab7fd9800b63e6d1c9ac481ba6eb7b6a844e4"+        , _proposalVoteAction    = VotingAction_Abstain+        }+    ]++proposalMetaSample = [r|+{+  "tx_hash": "257d75c8ddb0434e9b63e29ebb6241add2b835a307aa33aedba2effe09ed4ec8",+  "cert_index": 2,+  "url": "https://raw.githubusercontent.com/carloslodelar/proposals/main/pv10.json",+  "hash": "ffa226f3863aca006172d559cf46bb8b883a47233962ae2fc94c158d7de6fa81",+  "json_metadata": {+    "body": {+      "title": "Hardfork to Protocol version 10",+      "abstract": "Let's have sanchoNet in full governance as soon as possible",+      "rationale": "Let's keep testing stuff",+      "motivation": "PV9 is not as fun as PV10",+      "references": [+        {+          "uri": "",+          "@type": "Other",+          "label": "Hardfork to PV10"+        }+      ]+    },+    "authors": [+      {+        "name": "Carlos",+        "witness": {+          "publicKey": "7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a",+          "signature": "a476985b4cc0d457f247797611799a6f6a80fc8cb7ec9dcb5a8223888d0618e30de165f3d869c4a0d9107d8a5b612ad7c5e42441907f5b91796f0d7187d64a01",+          "witnessAlgorithm": "ed25519"+        }+      }+    ],+    "@context": {+      "body": {+        "@id": "CIP108:body",+        "@context": {+          "title": "CIP108:title",+          "abstract": "CIP108:abstract",+          "rationale": "CIP108:rationale",+          "motivation": "CIP108:motivation",+          "references": {+            "@id": "CIP108:references",+            "@context": {+              "uri": "CIP100:reference-uri",+              "Other": "CIP100:OtherReference",+              "label": "CIP100:reference-label",+              "referenceHash": {+                "@id": "CIP108:referenceHash",+                "@context": {+                  "hashDigest": "CIP108:hashDigest",+                  "hashAlgorithm": "CIP100:hashAlgorithm"+                }+              },+              "GovernanceMetadata": "CIP100:GovernanceMetadataReference"+            },+            "@container": "@set"+          }+        }+      },+      "CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#",+      "CIP108": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#",+      "authors": {+        "@id": "CIP100:authors",+        "@context": {+          "name": "http://xmlns.com/foaf/0.1/name",+          "witness": {+            "@id": "CIP100:witness",+            "@context": {+              "publicKey": "CIP100:publicKey",+              "signature": "CIP100:signature",+              "witnessAlgorithm": "CIP100:witnessAlgorithm"+            }+          }+        },+        "@container": "@set"+      },+      "@language": "en-us",+      "hashAlgorithm": "CIP100:hashAlgorithm"+    },+    "hashAlgorithm": "blake2b-256"+  },+  "bytes": "\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6d6423222c0a2020202022434950313038223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130382f524541444d452e6d6423222c0a202020202268617368416c676f726974686d223a20224349503130303a68617368416c676f726974686d222c0a2020202022626f6479223a207b0a20202020202022406964223a20224349503130383a626f6479222c0a2020202020202240636f6e74657874223a207b0a2020202020202020227265666572656e636573223a207b0a2020202020202020202022406964223a20224349503130383a7265666572656e636573222c0a202020202020202020202240636f6e7461696e6572223a202240736574222c0a202020202020202020202240636f6e74657874223a207b0a20202020202020202020202022476f7665726e616e63654d65746164617461223a20224349503130303a476f7665726e616e63654d657461646174615265666572656e6365222c0a202020202020202020202020224f74686572223a20224349503130303a4f746865725265666572656e6365222c0a202020202020202020202020226c6162656c223a20224349503130303a7265666572656e63652d6c6162656c222c0a20202020202020202020202022757269223a20224349503130303a7265666572656e63652d757269222c0a202020202020202020202020227265666572656e636548617368223a207b0a202020202020202020202020202022406964223a20224349503130383a7265666572656e636548617368222c0a20202020202020202020202020202240636f6e74657874223a207b0a202020202020202020202020202020202268617368446967657374223a20224349503130383a68617368446967657374222c0a202020202020202020202020202020202268617368416c676f726974686d223a20224349503130303a68617368416c676f726974686d220a20202020202020202020202020207d0a2020202020202020202020207d0a202020202020202020207d0a20202020202020207d2c0a2020202020202020227469746c65223a20224349503130383a7469746c65222c0a2020202020202020226162737472616374223a20224349503130383a6162737472616374222c0a2020202020202020226d6f7469766174696f6e223a20224349503130383a6d6f7469766174696f6e222c0a202020202020202022726174696f6e616c65223a20224349503130383a726174696f6e616c65220a2020202020207d0a202020207d2c0a2020202022617574686f7273223a207b0a20202020202022406964223a20224349503130303a617574686f7273222c0a2020202020202240636f6e7461696e6572223a202240736574222c0a2020202020202240636f6e74657874223a207b0a2020202020202020226e616d65223a2022687474703a2f2f786d6c6e732e636f6d2f666f61662f302e312f6e616d65222c0a2020202020202020227769746e657373223a207b0a2020202020202020202022406964223a20224349503130303a7769746e657373222c0a202020202020202020202240636f6e74657874223a207b0a202020202020202020202020227769746e657373416c676f726974686d223a20224349503130303a7769746e657373416c676f726974686d222c0a202020202020202020202020227075626c69634b6579223a20224349503130303a7075626c69634b6579222c0a202020202020202020202020227369676e6174757265223a20224349503130303a7369676e6174757265220a202020202020202020207d0a20202020202020207d0a2020202020207d0a202020207d0a20207d2c0a20202268617368416c676f726974686d223a2022626c616b6532622d323536222c0a202022626f6479223a207b0a20202020227469746c65223a202248617264666f726b20746f2050726f746f636f6c2076657273696f6e203130222c0a20202020226162737472616374223a20224c6574277320686176652073616e63686f4e657420696e2066756c6c20676f7665726e616e636520617320736f6f6e20617320706f737369626c65222c0a20202020226d6f7469766174696f6e223a2022505639206973206e6f742061732066756e2061732050563130222c0a2020202022726174696f6e616c65223a20224c65742773206b6565702074657374696e67207374756666222c0a20202020227265666572656e636573223a205b0a2020202020207b0a2020202020202020224074797065223a20224f74686572222c0a2020202020202020226c6162656c223a202248617264666f726b20746f2050563130222c0a202020202020202022757269223a2022220a2020202020207d0a202020205d0a20207d2c0a202022617574686f7273223a205b0a202020207b0a202020202020226e616d65223a20224361726c6f73222c0a202020202020227769746e657373223a207b0a2020202020202020227769746e657373416c676f726974686d223a202265643235353139222c0a2020202020202020227075626c69634b6579223a202237656130396133346165626231336339383431633731333937623163616266656335646466393530343035323933646565343936636163326634333734383061222c0a2020202020202020227369676e6174757265223a20226134373639383562346363306434353766323437373937363131373939613666366138306663386362376563396463623561383232333838386430363138653330646531363566336438363963346130643931303764386135623631326164376335653432343431393037663562393137393666306437313837643634613031220a2020202020207d0a202020207d0a20205d0a7d"+}+|]++proposalMetaExpected :: ProposalMeta+proposalMetaExpected =+  ProposalMeta+    { _proposalMetaTxHash       = "257d75c8ddb0434e9b63e29ebb6241add2b835a307aa33aedba2effe09ed4ec8"+    , _proposalMetaCertIndex    = 2+    , _proposalMetaUrl          = "https://raw.githubusercontent.com/carloslodelar/proposals/main/pv10.json"+    , _proposalMetaHash         = "ffa226f3863aca006172d559cf46bb8b883a47233962ae2fc94c158d7de6fa81"+    , _proposalMetaJsonMetadata = object+        [ "body" .= object+            [ "title" .= ("Hardfork to Protocol version 10" :: Text)+            , "abstract" .= ("Let's have sanchoNet in full governance as soon as possible" :: Text)+            , "rationale" .= ("Let's keep testing stuff" :: Text)+            , "motivation" .= ("PV9 is not as fun as PV10" :: Text)+            , "references" .=+                [ object+                    [ "@type" .= ("Other" :: Text)+                    , "label" .= ("Hardfork to PV10" :: Text)+                    , "uri"   .= ("" :: Text)+                    ]+                ]+            ]+        , "authors" .=+            [ object+                [ "name" .= ("Carlos" :: Text)+                , "witness" .= object+                    [ "publicKey" .= ("7ea09a34aebb13c9841c71397b1cabfec5ddf950405293dee496cac2f437480a" :: Text)+                    , "signature" .= ("a476985b4cc0d457f247797611799a6f6a80fc8cb7ec9dcb5a8223888d0618e30de165f3d869c4a0d9107d8a5b612ad7c5e42441907f5b91796f0d7187d64a01" :: Text)+                    , "witnessAlgorithm" .= ("ed25519" :: Text)+                    ]+                ]+            ]+        , "@context" .= object+            [ "CIP100" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#" :: Text)+            , "CIP108" .= ("https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#" :: Text)+            , "hashAlgorithm" .= ("CIP100:hashAlgorithm" :: Text)+            , "@language" .= ("en-us" :: Text)+            , "body" .= object+                [ "@id" .= ("CIP108:body" :: Text)+                , "@context" .= object+                    [ "title" .= ("CIP108:title" :: Text)+                    , "abstract" .= ("CIP108:abstract" :: Text)+                    , "rationale" .= ("CIP108:rationale" :: Text)+                    , "motivation" .= ("CIP108:motivation" :: Text)+                    , "references" .= object+                        [ "@id" .= ("CIP108:references" :: Text)+                        , "@container" .= ("@set" :: Text)+                        , "@context" .= object+                            [ "uri" .= ("CIP100:reference-uri" :: Text)+                            , "Other" .= ("CIP100:OtherReference" :: Text)+                            , "label" .= ("CIP100:reference-label" :: Text)+                            , "GovernanceMetadata" .= ("CIP100:GovernanceMetadataReference" :: Text)+                            , "referenceHash" .= object+                                [ "@id" .= ("CIP108:referenceHash" :: Text)+                                , "@context" .= object+                                    [ "hashDigest" .= ("CIP108:hashDigest" :: Text)+                                    , "hashAlgorithm" .= ("CIP100:hashAlgorithm" :: Text)+                                    ]+                                ]+                            ]+                        ]+                    ]+                ]+            , "authors" .= object+                [ "@id" .= ("CIP100:authors" :: Text)+                , "@container" .= ("@set" :: Text)+                , "@context" .= object+                    [ "name" .= ("http://xmlns.com/foaf/0.1/name" :: Text)+                    , "witness" .= object+                        [ "@id" .= ("CIP100:witness" :: Text)+                        , "@context" .= object+                            [ "publicKey" .= ("CIP100:publicKey" :: Text)+                            , "signature" .= ("CIP100:signature" :: Text)+                            , "witnessAlgorithm" .= ("CIP100:witnessAlgorithm" :: Text)+                            ]+                        ]+                    ]+                ]+            ]+        , "hashAlgorithm" .= ("blake2b-256" :: Text)+        ]+    , _proposalMetaBytes        = "\\x7b0a20202240636f6e74657874223a207b0a2020202022406c616e6775616765223a2022656e2d7573222c0a2020202022434950313030223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130302f524541444d452e6d6423222c0a2020202022434950313038223a202268747470733a2f2f6769746875622e636f6d2f63617264616e6f2d666f756e646174696f6e2f434950732f626c6f622f6d61737465722f4349502d303130382f524541444d452e6d6423222c0a202020202268617368416c676f726974686d223a20224349503130303a68617368416c676f726974686d222c0a2020202022626f6479223a207b0a20202020202022406964223a20224349503130383a626f6479222c0a2020202020202240636f6e74657874223a207b0a2020202020202020227265666572656e636573223a207b0a2020202020202020202022406964223a20224349503130383a7265666572656e636573222c0a202020202020202020202240636f6e7461696e6572223a202240736574222c0a202020202020202020202240636f6e74657874223a207b0a20202020202020202020202022476f7665726e616e63654d65746164617461223a20224349503130303a476f7665726e616e63654d657461646174615265666572656e6365222c0a202020202020202020202020224f74686572223a20224349503130303a4f746865725265666572656e6365222c0a202020202020202020202020226c6162656c223a20224349503130303a7265666572656e63652d6c6162656c222c0a20202020202020202020202022757269223a20224349503130303a7265666572656e63652d757269222c0a202020202020202020202020227265666572656e636548617368223a207b0a202020202020202020202020202022406964223a20224349503130383a7265666572656e636548617368222c0a20202020202020202020202020202240636f6e74657874223a207b0a202020202020202020202020202020202268617368446967657374223a20224349503130383a68617368446967657374222c0a202020202020202020202020202020202268617368416c676f726974686d223a20224349503130303a68617368416c676f726974686d220a20202020202020202020202020207d0a2020202020202020202020207d0a202020202020202020207d0a20202020202020207d2c0a2020202020202020227469746c65223a20224349503130383a7469746c65222c0a2020202020202020226162737472616374223a20224349503130383a6162737472616374222c0a2020202020202020226d6f7469766174696f6e223a20224349503130383a6d6f7469766174696f6e222c0a202020202020202022726174696f6e616c65223a20224349503130383a726174696f6e616c65220a2020202020207d0a202020207d2c0a2020202022617574686f7273223a207b0a20202020202022406964223a20224349503130303a617574686f7273222c0a2020202020202240636f6e7461696e6572223a202240736574222c0a2020202020202240636f6e74657874223a207b0a2020202020202020226e616d65223a2022687474703a2f2f786d6c6e732e636f6d2f666f61662f302e312f6e616d65222c0a2020202020202020227769746e657373223a207b0a2020202020202020202022406964223a20224349503130303a7769746e657373222c0a202020202020202020202240636f6e74657874223a207b0a202020202020202020202020227769746e657373416c676f726974686d223a20224349503130303a7769746e657373416c676f726974686d222c0a202020202020202020202020227075626c69634b6579223a20224349503130303a7075626c69634b6579222c0a202020202020202020202020227369676e6174757265223a20224349503130303a7369676e6174757265220a202020202020202020207d0a20202020202020207d0a2020202020207d0a202020207d0a20207d2c0a20202268617368416c676f726974686d223a2022626c616b6532622d323536222c0a202022626f6479223a207b0a20202020227469746c65223a202248617264666f726b20746f2050726f746f636f6c2076657273696f6e203130222c0a20202020226162737472616374223a20224c6574277320686176652073616e63686f4e657420696e2066756c6c20676f7665726e616e636520617320736f6f6e20617320706f737369626c65222c0a20202020226d6f7469766174696f6e223a2022505639206973206e6f742061732066756e2061732050563130222c0a2020202022726174696f6e616c65223a20224c65742773206b6565702074657374696e67207374756666222c0a20202020227265666572656e636573223a205b0a2020202020207b0a2020202020202020224074797065223a20224f74686572222c0a2020202020202020226c6162656c223a202248617264666f726b20746f2050563130222c0a202020202020202022757269223a2022220a2020202020207d0a202020205d0a20207d2c0a202022617574686f7273223a205b0a202020207b0a202020202020226e616d65223a20224361726c6f73222c0a202020202020227769746e657373223a207b0a2020202020202020227769746e657373416c676f726974686d223a202265643235353139222c0a2020202020202020227075626c69634b6579223a202237656130396133346165626231336339383431633731333937623163616266656335646466393530343035323933646565343936636163326634333734383061222c0a2020202020202020227369676e6174757265223a20226134373639383562346363306434353766323437373937363131373939613666366138306663386362376563396463623561383232333838386430363138653330646531363566336438363963346130643931303764386135623631326164376335653432343431393037663562393137393666306437313837643634613031220a2020202020207d0a202020207d0a20205d0a7d"+    }