diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,47 @@
+# 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
+  * `/blocks/:hash_or_number/txs/cbor`
+    and `/blocks/latest/txs/cbor` endpoints with `[TxHashCBOR]` data type [#73](https://github.com/blockfrost/blockfrost-haskell/pull/73) [#75](https://github.com/blockfrost/blockfrost-haskell/pull/75)
+* Removal of problematic overlapping `From/ToJSON`
+  instances on `Mabye PoolMetadata` [#72](https://github.com/blockfrost/blockfrost-haskell/pull/72)
+
+# Version [0.12.1.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.12.0.0...api-0.12.1.0) (2024-09-25)
+
+* Fix return type of `/txs/:hash/cbor` endpoint from `[TransactionCBOR]` to `TransactionCBOR`.
+
+# Version [0.12.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.11.0.0...api-0.12.0.0) (2024-09-19)
+
+* Additions
+  * `ProtocolParams` extended with Conway related protocol parameters and raw cost models [#59](https://github.com/blockfrost/blockfrost-haskell/pull/59)
+  * Mempool endpoints [#62](https://github.com/blockfrost/blockfrost-haskell/pull/62)
+  * `/txs/:hash/cbor` endpoint with `TransactionCBOR` data type [#63](https://github.com/blockfrost/blockfrost-haskell/pull/63)
+
 # Version [0.11.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.10.0.0...api-0.11.0.0) (2024-08-26)
 
 Changes
diff --git a/blockfrost-api.cabal b/blockfrost-api.cabal
--- a/blockfrost-api.cabal
+++ b/blockfrost-api.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.2
 name:                blockfrost-api
-version:             0.11.0.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
@@ -34,6 +34,7 @@
     DeriveAnyClass
     DeriveGeneric
     DerivingVia
+    DuplicateRecordFields
     GADTs
     GeneralizedNewtypeDeriving
     FlexibleContexts
@@ -67,7 +68,9 @@
                       , 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
                       , Blockfrost.API.Cardano.Network
                       , Blockfrost.API.Cardano.Pools
@@ -89,6 +92,8 @@
                       , 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
                       , Blockfrost.Types.Cardano.Pools
@@ -105,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
@@ -150,6 +156,7 @@
                      , Cardano.Assets
                      , Cardano.Blocks
                      , Cardano.Epochs
+                     , Cardano.Governance
                      , Cardano.Ledger
                      , Cardano.Metadata
                      , Cardano.Network
diff --git a/src/Blockfrost/API.hs b/src/Blockfrost/API.hs
--- a/src/Blockfrost/API.hs
+++ b/src/Blockfrost/API.hs
@@ -93,11 +93,21 @@
       :- "epochs"
       :> Tag "Cardano » Epochs"
       :> ToServantApi EpochsAPI
+    , _governance
+      :: route
+      :- "governance"
+      :> Tag "Cardano » Governance"
+      :> ToServantApi GovernanceAPI
     , _ledger
       :: route
       :- "genesis"
       :> Tag "Cardano » Ledger"
       :> ToServantApi LedgerAPI
+    , _mempool
+      :: route
+      :- "mempool"
+      :> Tag "Cardano » Mempool"
+      :> ToServantApi MempoolAPI
     , _metadata
       :: route
       :- "metadata"
diff --git a/src/Blockfrost/API/Cardano.hs b/src/Blockfrost/API/Cardano.hs
--- a/src/Blockfrost/API/Cardano.hs
+++ b/src/Blockfrost/API/Cardano.hs
@@ -8,7 +8,9 @@
   , 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
   , module Blockfrost.API.Cardano.Network
   , module Blockfrost.API.Cardano.Pools
@@ -22,7 +24,9 @@
 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
 import Blockfrost.API.Cardano.Network
 import Blockfrost.API.Cardano.Pools
diff --git a/src/Blockfrost/API/Cardano/Blocks.hs b/src/Blockfrost/API/Cardano/Blocks.hs
--- a/src/Blockfrost/API/Cardano/Blocks.hs
+++ b/src/Blockfrost/API/Cardano/Blocks.hs
@@ -32,6 +32,16 @@
         :> Pagination
         :> Sorting
         :> Get '[JSON] [TxHash]
+      , _latestTxsCBOR
+        :: route
+        :- Summary "Latest transactions with CBOR data"
+        :> Description "Return the transactions within the latest block, including CBOR representations."
+        :> "latest"
+        :> "txs"
+        :> "cbor"
+        :> Pagination
+        :> Sorting
+        :> Get '[JSON] [TxHashCBOR]
      , _block
         :: route
         :- Summary "Latest block transactions"
@@ -79,6 +89,16 @@
         :> Pagination
         :> Sorting
         :> Get '[JSON] [TxHash]
+      , _blockTxsCBOR
+        :: route
+        :- Summary "Block transactions with CBOR data"
+        :> Description "Return the transactions within the block, including CBOR representations."
+        :> Capture "hash_or_number" (Either Integer BlockHash)
+        :> "txs"
+        :> "cbor"
+        :> Pagination
+        :> Sorting
+        :> Get '[JSON] [TxHashCBOR]
       , _blockAffectedAddresses
         :: route
         :- Summary "Addresses affected in a specific block"
diff --git a/src/Blockfrost/API/Cardano/Governance.hs b/src/Blockfrost/API/Cardano/Governance.hs
new file mode 100644
--- /dev/null
+++ b/src/Blockfrost/API/Cardano/Governance.hs
@@ -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."
diff --git a/src/Blockfrost/API/Cardano/Mempool.hs b/src/Blockfrost/API/Cardano/Mempool.hs
new file mode 100644
--- /dev/null
+++ b/src/Blockfrost/API/Cardano/Mempool.hs
@@ -0,0 +1,42 @@
+-- | Cardano Mempool endpoints
+
+{-# OPTIONS_HADDOCK hide #-}
+
+module Blockfrost.API.Cardano.Mempool
+  where
+
+import Servant.API
+import Servant.API.Generic
+
+import Blockfrost.Types
+import Blockfrost.Util.Pagination
+import Blockfrost.Util.Sorting
+
+data MempoolAPI route =
+  MempoolAPI
+    {
+      _mempoolTransactions
+        :: route
+        :- Summary "Transactions in Mempool."
+        :> Description "Tx hash list of all transactions that are currently stored in the mempool."
+        :> Pagination
+        :> Sorting
+        :> Get '[JSON] [TxHashObject]
+    , _specificTransaction
+        :: route
+        :- Summary "Transaction in mempoool."
+        :> Description "Content of a specific transaction in the mempool."
+        :> Capture "hash" TxHash
+        :> Get '[JSON] MempoolTransaction
+    , _specificAddress
+        :: route
+        :- Summary "Transactions involving an address in mempool."
+        :> Description "List of transactions in the mempool that involves a specific address."
+        :> "addresses"
+        :> Capture "address" Address
+        :> Pagination
+        :> Sorting
+        :> Get '[JSON] [TxHashObject]
+    } deriving (Generic)
+
+
diff --git a/src/Blockfrost/API/Cardano/Pools.hs b/src/Blockfrost/API/Cardano/Pools.hs
--- a/src/Blockfrost/API/Cardano/Pools.hs
+++ b/src/Blockfrost/API/Cardano/Pools.hs
@@ -68,7 +68,7 @@
         :> Description "Stake pool registration metadata."
         :> Capture "pool_id" PoolId
         :> "metadata"
-        :> Get '[JSON] (Maybe PoolMetadata)
+        :> Get '[JSON] PoolMetadataResponse
     , _getPoolRelays
         :: route
         :- Summary "Stake pool relays"
diff --git a/src/Blockfrost/API/Cardano/Transactions.hs b/src/Blockfrost/API/Cardano/Transactions.hs
--- a/src/Blockfrost/API/Cardano/Transactions.hs
+++ b/src/Blockfrost/API/Cardano/Transactions.hs
@@ -83,6 +83,13 @@
         :> Capture "hash" TxHash
         :> "metadata"
         :> Get '[JSON] [TransactionMetaJSON]
+    , _txCBOR
+        :: route
+        :- Summary "Transaction in CBOR"
+        :> Description "Obtain the CBOR serialized transaction."
+        :> Capture "hash" TxHash
+        :> "cbor"
+        :> Get '[JSON] TransactionCBOR
     , _txMetadataCBOR
         :: route
         :- Summary "Transaction metadata in CBOR"
diff --git a/src/Blockfrost/Env.hs b/src/Blockfrost/Env.hs
--- a/src/Blockfrost/Env.hs
+++ b/src/Blockfrost/Env.hs
@@ -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`"
diff --git a/src/Blockfrost/Lens.hs b/src/Blockfrost/Lens.hs
--- a/src/Blockfrost/Lens.hs
+++ b/src/Blockfrost/Lens.hs
@@ -45,6 +45,26 @@
 
 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
+makeFields  ''MempoolUTxOInput
+makeFields  ''MempoolRedeemer
+
 makeFields ''TxMeta
 makeFields ''TxMetaJSON
 makeFields ''TxMetaCBOR
@@ -78,6 +98,7 @@
 makeFields ''PoolUpdateMetadata
 makeFields ''TransactionPoolRetiring
 makeFields ''TransactionMetaJSON
+makeFields ''TransactionCBOR
 makeFields ''TransactionMetaCBOR
 makeFields ''TransactionRedeemer
 
diff --git a/src/Blockfrost/Types/Cardano.hs b/src/Blockfrost/Types/Cardano.hs
--- a/src/Blockfrost/Types/Cardano.hs
+++ b/src/Blockfrost/Types/Cardano.hs
@@ -7,6 +7,8 @@
   , 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
   , module Blockfrost.Types.Cardano.Pools
@@ -21,6 +23,8 @@
 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
 import Blockfrost.Types.Cardano.Pools
diff --git a/src/Blockfrost/Types/Cardano/Accounts.hs b/src/Blockfrost/Types/Cardano/Accounts.hs
--- a/src/Blockfrost/Types/Cardano/Accounts.hs
+++ b/src/Blockfrost/Types/Cardano/Accounts.hs
@@ -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
diff --git a/src/Blockfrost/Types/Cardano/Blocks.hs b/src/Blockfrost/Types/Cardano/Blocks.hs
--- a/src/Blockfrost/Types/Cardano/Blocks.hs
+++ b/src/Blockfrost/Types/Cardano/Blocks.hs
@@ -2,6 +2,7 @@
 
 module Blockfrost.Types.Cardano.Blocks
   ( Block (..)
+  , TxHashCBOR (..)
   ) where
 
 import Data.Text (Text)
@@ -12,6 +13,7 @@
 import Servant.Docs (ToSample (..), singleSample)
 
 import Blockfrost.Types.Shared
+import Blockfrost.Types.Cardano.Transactions (TransactionCBOR(..))
 
 -- | Information about a block
 data Block = Block
@@ -73,3 +75,30 @@
       o
       "transactions"
     pure (addr, txs)
+
+-- | Transaction @TxHash@ to its respective @TransactionCBOR@ wrapper.
+-- Intentionally not a Map to preserve ordering
+newtype TxHashCBOR = TxHashCBOR { getTxHashCBOR :: (TxHash, TransactionCBOR) }
+  deriving stock (Show, Eq, Generic)
+
+instance ToSample TxHashCBOR where
+  toSamples _ =
+      singleSample
+    $ TxHashCBOR
+        ( TxHash "6f044565223657acdde3c569d6555b2edbd71bc2bfb4df0b1cce0ef805f606d4"
+        , TransactionCBOR "84a300d9010281825820787b3a89b1d32806968b867a4a31f1e33054b573821293a1c915559e34810a3602018282583900bd71b1547ab3ec95725100d0c0fb06da5ffae9cf54fb97e0f52fb9cab51adb784c4997143ba56990c0584111137d02898950245f5db5e2631a05f5e10082583900bd71b1547ab3ec95725100d0c0fb06da5ffae9cf54fb97e0f52fb9cab51adb784c4997143ba56990c0584111137d02898950245f5db5e2631b0000001588345487021a0002922da100818258206a7884092084c018eed71f9df5ff61935ab021f578b2d57d8ffb0b0e8ac0ea285840a2045496acf31996336ef187f9f3c2bd24c24995b540541586cbbc73a1550a50c2fdc3d4b99766c2823eb520866b03a38a60a4eb94f24994f441fb2852447c0ef5f6"
+        )
+
+instance ToJSON TxHashCBOR where
+  toJSON (TxHashCBOR (k, v)) =
+    object
+      [ "tx_hash" .= toJSON k
+      , "cbor" .= toJSON v
+      ]
+
+instance FromJSON TxHashCBOR where
+  parseJSON =
+    withObject "txHashCBOR" $ \to -> do
+      th <- to .: "tx_hash"
+      cb <- TransactionCBOR <$> to .: "cbor"
+      pure $ TxHashCBOR (th, cb)
diff --git a/src/Blockfrost/Types/Cardano/Epochs.hs b/src/Blockfrost/Types/Cardano/Epochs.hs
--- a/src/Blockfrost/Types/Cardano/Epochs.hs
+++ b/src/Blockfrost/Types/Cardano/Epochs.hs
@@ -5,6 +5,7 @@
   , PoolStakeDistribution (..)
   , ProtocolParams (..)
   , CostModels (..)
+  , CostModelsRaw (..)
   , StakeDistribution (..)
   ) where
 
@@ -77,6 +78,7 @@
   , _protocolParamsMinPoolCost           :: Lovelaces  -- ^ Minimum stake cost forced on the pool
   , _protocolParamsNonce                 :: Text -- ^ Epoch number only used once
   , _protocolParamsCostModels            :: CostModels -- ^ Cost models parameters for Plutus Core scripts
+  , _protocolParamsCostModelsRaw         :: CostModelsRaw
   , _protocolParamsPriceMem               :: Rational -- ^ The per word cost of script memory usage
   , _protocolParamsPriceStep              :: Rational -- ^ The cost of script execution step usage
   , _protocolParamsMaxTxExMem             :: Quantity -- ^ The maximum number of execution memory allowed to be used in a single transaction
@@ -88,10 +90,32 @@
   , _protocolParamsMaxCollateralInputs    :: Integer -- ^ The maximum number of collateral inputs allowed in a transaction
   , _protocolParamsCoinsPerUtxoSize       :: Lovelaces -- ^ The cost per UTxO size. Cost per UTxO *word* for Alozno. Cost per UTxO *byte* for Babbage and later
   , _protocolParamsCoinsPerUtxoWord       :: Lovelaces -- ^ The cost per UTxO word (DEPRECATED)
+  , _protocolParamsPvtMotionNoConfidence :: Maybe Rational
+  , _protocolParamsPvtCommitteeNormal :: Maybe Rational
+  , _protocolParamsPvtCommitteeNoConfidence :: Maybe Rational
+  , _protocolParamsPvtHardForkInitiation :: Maybe Rational
+  , _protocolParamsPvtppSecurityGroup :: Maybe Rational
+  , _protocolParamsDvtMotionNoConfidence :: Maybe Rational
+  , _protocolParamsDvtCommitteeNormal :: Maybe Rational
+  , _protocolParamsDvtCommitteeNoConfidence :: Maybe Rational
+  , _protocolParamsDvtUpdateToConstitution :: Maybe Rational
+  , _protocolParamsDvtHardForkInitiation :: Maybe Rational
+  , _protocolParamsDvtPPNetworkGroup :: Maybe Rational
+  , _protocolParamsDvtPPEconomicGroup :: Maybe Rational
+  , _protocolParamsDvtPPTechnicalGroup :: Maybe Rational
+  , _protocolParamsDvtPPGovGroup :: Maybe Rational
+  , _protocolParamsDvtTreasuryWithdrawal :: Maybe Rational
+  , _protocolParamsCommitteeMinSize :: Maybe Quantity
+  , _protocolParamsCommitteeMaxTermLength :: Maybe Quantity
+  , _protocolParamsGovActionLifetime :: Maybe Quantity
+  , _protocolParamsGovActionDeposit :: Maybe Lovelaces
+  , _protocolParamsDrepDeposit :: Maybe Lovelaces
+  , _protocolParamsDrepActivity :: Maybe Quantity
+  , _protocolParamsMinFeeRefScriptCostPerByte :: Maybe Rational
   }
   deriving stock (Show, Eq, Generic)
   deriving (FromJSON, ToJSON)
-  via CustomJSON '[FieldLabelModifier '[StripPrefix "_protocolParams", CamelToSnake]] ProtocolParams
+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_protocolParams", 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"]] ProtocolParams
 
 instance ToSample ProtocolParams where
   toSamples = pure $ singleSample
@@ -117,6 +141,7 @@
       , _protocolParamsMinPoolCost = 340000000
       , _protocolParamsNonce = "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81"
       , _protocolParamsCostModels = costModelsSample
+      , _protocolParamsCostModelsRaw = costModelsRawSample
       , _protocolParamsPriceMem = 0.0577
       , _protocolParamsPriceStep = 0.0000721
       , _protocolParamsMaxTxExMem = 10000000
@@ -128,6 +153,28 @@
       , _protocolParamsMaxCollateralInputs = 3
       , _protocolParamsCoinsPerUtxoSize = 34482
       , _protocolParamsCoinsPerUtxoWord = 34482
+      , _protocolParamsPvtMotionNoConfidence = Just 0.51
+      , _protocolParamsPvtCommitteeNormal = Just 0.51
+      , _protocolParamsPvtCommitteeNoConfidence = Just 0.51
+      , _protocolParamsPvtHardForkInitiation = Just 0.51
+      , _protocolParamsPvtppSecurityGroup = Just 0.51
+      , _protocolParamsDvtMotionNoConfidence = Just 0.67
+      , _protocolParamsDvtCommitteeNormal = Just 0.67
+      , _protocolParamsDvtCommitteeNoConfidence = Just 0.6
+      , _protocolParamsDvtUpdateToConstitution = Just 0.75
+      , _protocolParamsDvtHardForkInitiation = Just 0.6
+      , _protocolParamsDvtPPNetworkGroup = Just 0.67
+      , _protocolParamsDvtPPEconomicGroup = Just 0.67
+      , _protocolParamsDvtPPTechnicalGroup = Just 0.67
+      , _protocolParamsDvtPPGovGroup = Just 0.75
+      , _protocolParamsDvtTreasuryWithdrawal = Just 0.67
+      , _protocolParamsCommitteeMinSize = Just 7
+      , _protocolParamsCommitteeMaxTermLength = Just 146
+      , _protocolParamsGovActionLifetime = Just 6
+      , _protocolParamsGovActionDeposit = Just 100000000000
+      , _protocolParamsDrepDeposit = Just 500000000
+      , _protocolParamsDrepActivity = Just 20
+      , _protocolParamsMinFeeRefScriptCostPerByte = Just 15
       }
 
 newtype CostModels = CostModels { unCostModels :: Map ScriptType (Map Text Integer) }
@@ -169,6 +216,37 @@
 
     pure $ CostModels $ Data.Map.fromList langs
 
+newtype CostModelsRaw = CostModelsRaw { unCostModelsRaw :: Map ScriptType [Integer] }
+  deriving (Eq, Show, Generic)
+
+instance ToJSON CostModelsRaw where
+  toJSON =
+      object
+    . map (\(lang, params) ->
+        ( Data.Aeson.Key.fromString $ show lang
+        , toJSON params)
+        )
+    . Data.Map.toList
+    . unCostModelsRaw
+
+instance FromJSON CostModelsRaw where
+  parseJSON = withObject "CostModelsRaw" $ \o -> do
+    langs <- mapM
+               (\(kLang, vParams) -> do
+                 l <- parseJSON
+                    $ toJSON
+                    $ (\lang -> case lang of
+                        [] -> fail "Absurd empty language in CostModelsRaw"
+                        (x:xs) -> Data.Char.toLower x:xs
+                      )
+                    $ Data.Aeson.Key.toString kLang
+                 ps <- parseJSON vParams
+                 pure (l, ps)
+               )
+               $ Data.Aeson.KeyMap.toList o
+
+    pure $ CostModelsRaw $ Data.Map.fromList langs
+
 costModelsSample :: CostModels
 costModelsSample = CostModels
       $ Data.Map.fromList
@@ -188,6 +266,24 @@
 
 instance ToSample CostModels where
   toSamples = pure $ singleSample costModelsSample
+
+costModelsRawSample :: CostModelsRaw
+costModelsRawSample = CostModelsRaw
+      $ Data.Map.fromList
+      [ ( PlutusV1
+        , [ 197209
+          , 0
+          ]
+        )
+      , (PlutusV2
+        , [ 197209
+          , 0
+          ]
+        )
+      ]
+
+instance ToSample CostModelsRaw where
+  toSamples = pure $ singleSample costModelsRawSample
 
 -- | Active stake distribution for an epoch
 data StakeDistribution = StakeDistribution
diff --git a/src/Blockfrost/Types/Cardano/Governance.hs b/src/Blockfrost/Types/Cardano/Governance.hs
new file mode 100644
--- /dev/null
+++ b/src/Blockfrost/Types/Cardano/Governance.hs
@@ -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"
+    }
diff --git a/src/Blockfrost/Types/Cardano/Mempool.hs b/src/Blockfrost/Types/Cardano/Mempool.hs
new file mode 100644
--- /dev/null
+++ b/src/Blockfrost/Types/Cardano/Mempool.hs
@@ -0,0 +1,68 @@
+-- | Transaction metadata
+
+module Blockfrost.Types.Cardano.Mempool
+  ( MempoolTransaction(..)
+  , TransactionInMempool (..)
+  , MempoolUTxOInput(..)
+  , MempoolRedeemer(..)
+  ) where
+
+import Data.Text
+import Deriving.Aeson
+import Blockfrost.Types.Cardano.Transactions
+import Blockfrost.Types.Shared.Ada
+import Blockfrost.Types.Shared.Amount
+
+data MempoolTransaction = MempoolTransaction
+  { _tx :: TransactionInMempool
+  , _inputs :: [MempoolUTxOInput]
+  , _outputs :: [UtxoOutput]
+  , _redeemers :: Maybe [MempoolRedeemer]
+  }
+  deriving stock (Show, Eq, Generic)
+  deriving (FromJSON, ToJSON)
+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_", CamelToSnake]] MempoolTransaction
+
+data TransactionInMempool = TransactionInMempool
+  { _transactionHash                 :: Text -- ^ Transaction hash
+  , _transactionOutputAmount         :: [Amount] -- ^ Transaction outputs
+  , _transactionFees                 :: Lovelaces -- ^ Transaction fee
+  , _transactionDeposit              :: Lovelaces -- ^ Deposit within the transaction in Lovelaces
+  , _transactionSize                 :: Integer -- ^ Size of the transaction in Bytes
+  , _transactionInvalidBefore        :: Maybe Text -- ^ Left (included) endpoint of the timelock validity intervals
+  , _transactionInvalidHereafter     :: Maybe Text -- ^ Right (excluded) endpoint of the timelock validity intervals
+  , _transactionUtxoCount            :: Integer -- ^ Count of UTXOs within the transaction
+  , _transactionWithdrawalCount      :: Integer -- ^ Count of the withdrawals within the transaction
+  , _transactionMirCertCount         :: Integer -- ^ Count of the MIR certificates within the transaction
+  , _transactionDelegationCount      :: Integer -- ^ Count of the delegations within the transaction
+  , _transactionStakeCertCount       :: Integer -- ^ Count of the stake keys (de)registration and delegation certificates within the transaction
+  , _transactionPoolUpdateCount      :: Integer -- ^ Count of the stake pool registration and update certificates within the transaction
+  , _transactionPoolRetireCount      :: Integer -- ^ Count of the stake pool retirement certificates within the transaction
+  , _transactionAssetMintOrBurnCount :: Integer -- ^ Count of asset mints and burns within the transaction
+  , _transactionRedeemerCount        :: Integer -- ^ Count of redeemers within the transaction
+  , _transactionValidContract        :: Bool    -- ^ True if this is a valid transaction, False in case of contract validation failure
+  }
+  deriving stock (Show, Eq, Generic)
+  deriving (FromJSON, ToJSON)
+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_transaction", CamelToSnake]] TransactionInMempool
+
+data MempoolUTxOInput = MempoolUTxOInput
+   { _address :: Maybe Text -- ^ Address
+   , _txHash :: Text -- ^ Transaction hash
+   , _outputIndex :: Integer -- ^ Output index
+   , _collateral :: Bool -- ^ True if the input is a collateral input
+   , _reference :: Bool -- ^ Is the input a reference input
+   }
+   deriving stock (Show, Eq, Generic)
+   deriving (FromJSON, ToJSON)
+   via CustomJSON '[FieldLabelModifier '[StripPrefix "_", CamelToSnake]] MempoolUTxOInput
+
+data MempoolRedeemer = MempoolRedeemer
+  { _tx_index :: Integer -- ^ Transaction index
+  , _purpose :: Text -- ^ Purpose of the redeemer
+  , _unit_mem :: Text -- ^ Memory unit
+  , _unit_steps :: Text -- ^ Steps unit
+  }
+  deriving stock (Show, Eq, Generic)
+  deriving (FromJSON, ToJSON)
+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_", CamelToSnake]] MempoolRedeemer
diff --git a/src/Blockfrost/Types/Cardano/Pools.hs b/src/Blockfrost/Types/Cardano/Pools.hs
--- a/src/Blockfrost/Types/Cardano/Pools.hs
+++ b/src/Blockfrost/Types/Cardano/Pools.hs
@@ -6,6 +6,7 @@
   , PoolInfo (..)
   , PoolHistory (..)
   , PoolMetadata (..)
+  , PoolMetadataResponse (..)
   , PoolRelay (..)
   , PoolDelegator (..)
   , PoolUpdate (..)
@@ -164,18 +165,6 @@
   deriving (FromJSON, ToJSON)
   via CustomJSON '[FieldLabelModifier '[StripPrefix "_poolMetadata", CamelToSnake]] PoolMetadata
 
--- We need this more specific
--- instance since API returns
--- empty object if there's no metadata
-instance {-# OVERLAPS #-} ToJSON (Maybe PoolMetadata) where
-  toJSON Nothing   = object mempty
-  toJSON (Just pm) = toJSON pm
-  toEncoding Nothing   = pairs mempty
-  toEncoding (Just pm) = toEncoding pm
-instance {-# OVERLAPS #-} FromJSON (Maybe PoolMetadata) where
-  parseJSON x | x == object [] = pure Nothing
-  parseJSON x = Just <$> parseJSON x
-
 instance ToSample PoolMetadata where
   toSamples = pure $ singleSample samplePoolMetadata
 
@@ -191,6 +180,23 @@
     , _poolMetadataDescription = Just "The best pool ever"
     , _poolMetadataHomepage = Just "https://stakentus.com/"
     }
+
+-- | Actual response about stake pool metadata.
+newtype PoolMetadataResponse = PoolMetadataResponse { getMetadata :: Maybe PoolMetadata }
+  deriving stock (Show, Eq, Generic)
+
+-- NOTE: Manual instance to produce empty object if there is no metadata
+instance ToJSON PoolMetadataResponse where
+  toJSON (PoolMetadataResponse Nothing) = object mempty
+  toJSON (PoolMetadataResponse (Just pm)) = toJSON pm
+
+  toEncoding (PoolMetadataResponse Nothing) = pairs mempty
+  toEncoding (PoolMetadataResponse (Just pm)) = toEncoding pm
+
+-- NOTE: Manual instance to accept empty objects as no metadata.
+instance FromJSON PoolMetadataResponse where
+  parseJSON x | x == object [] = pure $ PoolMetadataResponse Nothing
+  parseJSON x = PoolMetadataResponse . Just <$> parseJSON x
 
 -- | Relays of a stake pool
 data PoolRelay = PoolRelay
diff --git a/src/Blockfrost/Types/Cardano/Transactions.hs b/src/Blockfrost/Types/Cardano/Transactions.hs
--- a/src/Blockfrost/Types/Cardano/Transactions.hs
+++ b/src/Blockfrost/Types/Cardano/Transactions.hs
@@ -15,6 +15,7 @@
   , PoolUpdateMetadata (..)
   , TransactionPoolRetiring (..)
   , TransactionMetaJSON (..)
+  , TransactionCBOR (..)
   , TransactionMetaCBOR (..)
   ) where
 
@@ -366,6 +367,17 @@
         "1968"
         (Just $ oracleMeta "0.15409850555139935")
     ]
+
+-- | Transaction in CBOR
+newtype TransactionCBOR = TransactionCBOR { _transactionCBORCbor :: Text }
+  deriving stock (Show, Eq, Generic)
+  deriving (FromJSON, ToJSON)
+  via CustomJSON '[FieldLabelModifier '[StripPrefix "_transactionCBOR", CamelToSnake]] TransactionCBOR
+
+instance ToSample TransactionCBOR where
+  toSamples = pure $ singleSample $
+    TransactionCBOR
+      "a100a16b436f6d62696e6174696f6e8601010101010c"
 
 -- | Transaction metadata in CBOR
 data TransactionMetaCBOR = TransactionMetaCBOR
diff --git a/src/Blockfrost/Types/Shared.hs b/src/Blockfrost/Types/Shared.hs
--- a/src/Blockfrost/Types/Shared.hs
+++ b/src/Blockfrost/Types/Shared.hs
@@ -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
diff --git a/src/Blockfrost/Types/Shared/DRepId.hs b/src/Blockfrost/Types/Shared/DRepId.hs
new file mode 100644
--- /dev/null
+++ b/src/Blockfrost/Types/Shared/DRepId.hs
@@ -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."
diff --git a/src/Blockfrost/Types/Shared/TxHash.hs b/src/Blockfrost/Types/Shared/TxHash.hs
--- a/src/Blockfrost/Types/Shared/TxHash.hs
+++ b/src/Blockfrost/Types/Shared/TxHash.hs
@@ -2,9 +2,10 @@
 
 module Blockfrost.Types.Shared.TxHash
   ( TxHash (..)
+  , TxHashObject (..)
   ) where
 
-import Data.Aeson (FromJSON (..), ToJSON (..))
+import Data.Aeson (FromJSON (..), ToJSON (..), object, (.=), withObject, (.:))
 import Data.String (IsString (..))
 import Data.Text (Text)
 import qualified Data.Text
@@ -35,3 +36,19 @@
 
 instance ToCapture (Capture "hash" TxHash) where
   toCapture _ = DocCapture "hash" "Hash of the requested transaction."
+
+
+-- Temporary until blockfrost server returns proper TxHash
+
+newtype TxHashObject = TxHashObject { unTxHashObject :: Text }
+  deriving stock (Show, Eq, Ord, Generic)
+  deriving newtype (FromHttpApiData, ToHttpApiData)
+
+instance IsString TxHashObject where
+  fromString = TxHashObject . Data.Text.pack
+
+instance ToJSON TxHashObject where
+  toJSON hash = object ["tx_hash" .= unTxHashObject hash]
+
+instance FromJSON TxHashObject where
+  parseJSON = withObject "TxHashObject" $ \o -> TxHashObject <$> o .: "tx_hash"
diff --git a/test/Cardano/Accounts.hs b/test/Cardano/Accounts.hs
--- a/test/Cardano/Accounts.hs
+++ b/test/Cardano/Accounts.hs
@@ -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|
diff --git a/test/Cardano/Blocks.hs b/test/Cardano/Blocks.hs
--- a/test/Cardano/Blocks.hs
+++ b/test/Cardano/Blocks.hs
@@ -22,11 +22,17 @@
     `shouldBe`
     Right blockExpected
 
-  it "parses afftected addresses sample" $ do
+  it "parses affected addresses sample" $ do
     eitherDecode affectedAddrsSample
     `shouldBe`
     Right affectedAddrsExpected
 
+  it "parses transactions with cbor sample" $ do
+    eitherDecode txHashesCBORSample
+    `shouldBe`
+    Right txHashesCBORExpected
+
+
 blockSample = [r|
 {
     "time": 1641338934,
@@ -96,4 +102,45 @@
      [TxHash "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dce628516157f0"])
   , (Address "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz",
      [TxHash "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dce628516157d0"])
+  ]
+
+txHashesCBORSample = [r|
+[
+  {
+    "tx_hash": "6f044565223657acdde3c569d6555b2edbd71bc2bfb4df0b1cce0ef805f606d4",
+    "cbor": "84a300d9010281825820787b3a89b1d32806968b867a4a31f1e33054b573821293a1c915559e34810a3602018282583900bd71b1547ab3ec95725100d0c0fb06da5ffae9cf54fb97e0f52fb9cab51adb784c4997143ba56990c0584111137d02898950245f5db5e2631a05f5e10082583900bd71b1547ab3ec95725100d0c0fb06da5ffae9cf54fb97e0f52fb9cab51adb784c4997143ba56990c0584111137d02898950245f5db5e2631b0000001588345487021a0002922da100818258206a7884092084c018eed71f9df5ff61935ab021f578b2d57d8ffb0b0e8ac0ea285840a2045496acf31996336ef187f9f3c2bd24c24995b540541586cbbc73a1550a50c2fdc3d4b99766c2823eb520866b03a38a60a4eb94f24994f441fb2852447c0ef5f6"
+  },
+  {
+    "tx_hash": "9b9ddb7ee8101e5a2638b5b79fe4dbafafcda56df12eebe2fd456e9862b848ea",
+    "cbor": "84a300d90102818258207df720d99d8323830709439492876005ff752b94dafeb7bec529ab1679ec236901018282583900f2b425e12b7d90128fff6368c9c3cee21e29ae0273dda6f4c21c66f8364d4566878a66fab0bbc596dac020e3188cb58e40f7069e3c6652fa1a00e4e1c082583900c8cbbfc1db08891d2c2ec9f8df43c2904a61c0626c7e1a57627eb0753e9649b2a3596889c539a17e4d4cbefd9ed73a73d4d8f6089e02d1df1b00000004a6558a56021a0002922da10081825820844e231d37f9b76a2b02978d634ec7fa9fa7bc74a4ce3bc403e3091321a672405840c3cebb97014af06991be1a15fbc86adf71c2441dcbf3078edb11d9407306a13694f7ca5d8fc366bf28ea30fda713c2368e648ce7c87bd2981b43e4fecdd05403f5f6"
+  },
+  {
+    "tx_hash": "52aec9ace9b710bc2e662d4fe20e71c1bc3a0c0f3b8076f069af9713963d4559",
+    "cbor": "84a300d9010281825820c8e9b710248220c28f5fbf6fb040b3a392707d19d0bfdaa5474c882d02b0c3ab0101828258390036e0cf1e52e05ef92e52c7bc2a04493d6bae481b8acbab12ec4300d7f9c9e87246d2f0373885896ad2804b7229673204cac9208345c1ea5b1a001e848082583900263bdbb58275ab6396c39a3188b6594bd5d46f54e08b6868c9fb3e498141d8651e0139b3bfc9c31f76d885431f83957329d75e0e53a65c2a1b000000730e797dda021a0002a2ada100d90102818258200909d10ce4850cd340b155d1dceae0bdcd77eba09524296ffe40f061dfc537c7584073a9efedf31dafc428605836d1ce2e2f62c1c6a9e733a5e538de034449b8ade504521e5fff96df5712487d214c83ac69babaa604bec9bc7a278f9f38b58ef70cf5f6"
+  },
+  {
+    "tx_hash": "b49ccb4ee194da2d97bfa5374509b2ed11a3b8265d346287928e6d25b82f48cb",
+    "cbor": "84a300d9010281825820c5952d922ea00bbb4b6be104c647e6e7b8366c290db5173655f871243494d1001818018182581d60da0eb5ed7611482ec5089b69d870e0c56c1c45180256112398e0835b1b00000002540be400021a00030d40a100d90102818258206855ffb8cbde9163c55c2405f93a8cfa063a631d811281d954e16782123956a75840a4208e0e2236b7f04f77f47ba07f3ec40cbf567ddfd7c7562a451cd51b38f58936e233be2a1a4f202c704fc9963215cdfdde19970c7d05d928403ee688e4ac08f5f6"
+  }
+]
+|]
+
+txHashesCBORExpected :: [TxHashCBOR]
+txHashesCBORExpected =
+  [ TxHashCBOR
+      ( TxHash "6f044565223657acdde3c569d6555b2edbd71bc2bfb4df0b1cce0ef805f606d4"
+      , TransactionCBOR "84a300d9010281825820787b3a89b1d32806968b867a4a31f1e33054b573821293a1c915559e34810a3602018282583900bd71b1547ab3ec95725100d0c0fb06da5ffae9cf54fb97e0f52fb9cab51adb784c4997143ba56990c0584111137d02898950245f5db5e2631a05f5e10082583900bd71b1547ab3ec95725100d0c0fb06da5ffae9cf54fb97e0f52fb9cab51adb784c4997143ba56990c0584111137d02898950245f5db5e2631b0000001588345487021a0002922da100818258206a7884092084c018eed71f9df5ff61935ab021f578b2d57d8ffb0b0e8ac0ea285840a2045496acf31996336ef187f9f3c2bd24c24995b540541586cbbc73a1550a50c2fdc3d4b99766c2823eb520866b03a38a60a4eb94f24994f441fb2852447c0ef5f6"
+      )
+  , TxHashCBOR
+      ( TxHash "9b9ddb7ee8101e5a2638b5b79fe4dbafafcda56df12eebe2fd456e9862b848ea"
+      , TransactionCBOR "84a300d90102818258207df720d99d8323830709439492876005ff752b94dafeb7bec529ab1679ec236901018282583900f2b425e12b7d90128fff6368c9c3cee21e29ae0273dda6f4c21c66f8364d4566878a66fab0bbc596dac020e3188cb58e40f7069e3c6652fa1a00e4e1c082583900c8cbbfc1db08891d2c2ec9f8df43c2904a61c0626c7e1a57627eb0753e9649b2a3596889c539a17e4d4cbefd9ed73a73d4d8f6089e02d1df1b00000004a6558a56021a0002922da10081825820844e231d37f9b76a2b02978d634ec7fa9fa7bc74a4ce3bc403e3091321a672405840c3cebb97014af06991be1a15fbc86adf71c2441dcbf3078edb11d9407306a13694f7ca5d8fc366bf28ea30fda713c2368e648ce7c87bd2981b43e4fecdd05403f5f6"
+      )
+  , TxHashCBOR
+      ( TxHash "52aec9ace9b710bc2e662d4fe20e71c1bc3a0c0f3b8076f069af9713963d4559"
+      , TransactionCBOR "84a300d9010281825820c8e9b710248220c28f5fbf6fb040b3a392707d19d0bfdaa5474c882d02b0c3ab0101828258390036e0cf1e52e05ef92e52c7bc2a04493d6bae481b8acbab12ec4300d7f9c9e87246d2f0373885896ad2804b7229673204cac9208345c1ea5b1a001e848082583900263bdbb58275ab6396c39a3188b6594bd5d46f54e08b6868c9fb3e498141d8651e0139b3bfc9c31f76d885431f83957329d75e0e53a65c2a1b000000730e797dda021a0002a2ada100d90102818258200909d10ce4850cd340b155d1dceae0bdcd77eba09524296ffe40f061dfc537c7584073a9efedf31dafc428605836d1ce2e2f62c1c6a9e733a5e538de034449b8ade504521e5fff96df5712487d214c83ac69babaa604bec9bc7a278f9f38b58ef70cf5f6"
+      )
+  , TxHashCBOR
+      ( TxHash "b49ccb4ee194da2d97bfa5374509b2ed11a3b8265d346287928e6d25b82f48cb"
+      , TransactionCBOR "84a300d9010281825820c5952d922ea00bbb4b6be104c647e6e7b8366c290db5173655f871243494d1001818018182581d60da0eb5ed7611482ec5089b69d870e0c56c1c45180256112398e0835b1b00000002540be400021a00030d40a100d90102818258206855ffb8cbde9163c55c2405f93a8cfa063a631d811281d954e16782123956a75840a4208e0e2236b7f04f77f47ba07f3ec40cbf567ddfd7c7562a451cd51b38f58936e233be2a1a4f202c704fc9963215cdfdde19970c7d05d928403ee688e4ac08f5f6"
+      )
   ]
diff --git a/test/Cardano/Epochs.hs b/test/Cardano/Epochs.hs
--- a/test/Cardano/Epochs.hs
+++ b/test/Cardano/Epochs.hs
@@ -100,6 +100,20 @@
         "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",
@@ -110,7 +124,29 @@
     "collateral_percent": 150,
     "max_collateral_inputs": 3,
     "coins_per_utxo_size": "34482",
-    "coins_per_utxo_word": "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
 }
 |]
 
@@ -152,6 +188,25 @@
           ]
         )
       ]
+    , _protocolParamsCostModelsRaw =
+        CostModelsRaw
+      $ Data.Map.fromList
+      [ ( PlutusV1
+        , [ 197209
+          , 0
+          ]
+        )
+      , (PlutusV2
+        , [ 197209
+          , 0
+          ]
+        )
+      , (PlutusV3
+        , [ 197209
+          , 0
+          ]
+        )
+      ]
     , _protocolParamsPriceMem = 0.0577
     , _protocolParamsPriceStep = 0.0000721
     , _protocolParamsMaxTxExMem = 10000000
@@ -164,6 +219,28 @@
     , _protocolParamsCoinsPerUtxoSize = 34482
     -- deprecated
     , _protocolParamsCoinsPerUtxoWord = 34482
+    , _protocolParamsPvtMotionNoConfidence = Just 0.51
+    , _protocolParamsPvtCommitteeNormal = Just 0.51
+    , _protocolParamsPvtCommitteeNoConfidence = Just 0.51
+    , _protocolParamsPvtHardForkInitiation = Just 0.51
+    , _protocolParamsPvtppSecurityGroup = Just 0.51
+    , _protocolParamsDvtMotionNoConfidence = Just 0.67
+    , _protocolParamsDvtCommitteeNormal = Just 0.67
+    , _protocolParamsDvtCommitteeNoConfidence = Just 0.6
+    , _protocolParamsDvtUpdateToConstitution = Just 0.75
+    , _protocolParamsDvtHardForkInitiation = Just 0.6
+    , _protocolParamsDvtPPNetworkGroup = Just 0.67
+    , _protocolParamsDvtPPEconomicGroup = Just 0.67
+    , _protocolParamsDvtPPTechnicalGroup = Just 0.67
+    , _protocolParamsDvtPPGovGroup = Just 0.75
+    , _protocolParamsDvtTreasuryWithdrawal = Just 0.67
+    , _protocolParamsCommitteeMinSize = Just 7
+    , _protocolParamsCommitteeMaxTermLength = Just 146
+    , _protocolParamsGovActionLifetime = Just 6
+    , _protocolParamsGovActionDeposit = Just 100000000000
+    , _protocolParamsDrepDeposit = Just 500000000
+    , _protocolParamsDrepActivity = Just 20
+    , _protocolParamsMinFeeRefScriptCostPerByte = Just 15
     }
 
 stakeDistributionSample = [r|
diff --git a/test/Cardano/Governance.hs b/test/Cardano/Governance.hs
new file mode 100644
--- /dev/null
+++ b/test/Cardano/Governance.hs
@@ -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"
+    }
diff --git a/test/Cardano/Pools.hs b/test/Cardano/Pools.hs
--- a/test/Cardano/Pools.hs
+++ b/test/Cardano/Pools.hs
@@ -45,7 +45,7 @@
   it "parses empty object pool metadata sample" $ do
     eitherDecode "{}"
     `shouldBe`
-    Right (Nothing :: Maybe PoolMetadata)
+    Right (PoolMetadataResponse Nothing)
 
   it "parses pool relay sample" $ do
     eitherDecode poolRelaySample
diff --git a/test/Cardano/Transactions.hs b/test/Cardano/Transactions.hs
--- a/test/Cardano/Transactions.hs
+++ b/test/Cardano/Transactions.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DuplicateRecordFields #-}
 {-# LANGUAGE NumericUnderscores #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
@@ -67,6 +68,11 @@
     `shouldBe`
     Right transactionMetaJSONExpected
 
+  it "parses transaction (CBOR) sample" $ do
+    eitherDecode transactionCBORSample
+    `shouldBe`
+    Right transactionCBORExpected
+  
   it "parses transaction meta (CBOR) sample" $ do
     eitherDecode transactionMetaCBORSample
     `shouldBe`
@@ -428,6 +434,16 @@
         "1968"
         (Just $ oracleMeta "0.15409850555139935")
     ]
+
+transactionCBORSample = [r|
+{
+  "cbor": "a100a16b436f6d62696e6174696f6e8601010101010c"
+}
+|]
+
+transactionCBORExpected =
+    TransactionCBOR
+      "a100a16b436f6d62696e6174696f6e8601010101010c"
 
 transactionMetaCBORSample = [r|
 {
