packages feed

blockfrost-client 0.9.2.0 → 0.13.0.0

raw patch · 8 files changed

Files

CHANGELOG.md view
@@ -1,3 +1,56 @@+# Version [0.13.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.12.0.0...client-0.13.0.0) (2026-04-15)++* Changes+  * Retry logic added++    Client will retry most transient errors like connection timeouts,+    up to 5 times with exponential backoff. This can be customized+    via `clientConfigRetryPolicy` field of `ClientConfig`. See [`Control.Retry`](https://hackage.haskell.org/package/retry/docs/Control-Retry.html#g:5)+    for available options.++    * `type ClientConfig = (ClientEnv, Project)` is now++      ```+      data ClientConfig =+        ClientConfig+          { clientConfigClientEnv   :: ClientEnv+          , clientConfigProject     :: Project+          , clientConfigRetryPolicy :: RetryPolicy+          , clientConfigRetryJudge  :: RetryStatus -> BlockfrostError -> RetryAction+          }+      ```+      last two fields are populated with `defaultRetryPolicy` and `defaultRetryJudge`.++  * `ipfsAdd`+    * no longer throws `BlockfrostError "File not found"`+    * no longer checks if the file exists+    * no longer prints `"Uploading: <filename>"` message to stdout++# Version [0.12.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.11.0.0...client-0.12.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.11.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.10.0.0...client-0.11.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.10.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.9.2.0...client-0.10.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.9.2.0](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.9.1.0...client-0.9.2.0) (2025-04-07)  * Additions
blockfrost-client.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                blockfrost-client-version:             0.9.2.0+version:             0.13.0.0 synopsis:            blockfrost.io basic client description:         Simple Blockfrost clients for use with transformers or mtl homepage:            https://github.com/blockfrost/blockfrost-haskell@@ -57,6 +57,7 @@                       , Blockfrost.Client.Cardano.Assets                       , Blockfrost.Client.Cardano.Blocks                       , Blockfrost.Client.Cardano.Epochs+                      , Blockfrost.Client.Cardano.Governance                       , Blockfrost.Client.Cardano.Ledger                       , Blockfrost.Client.Cardano.Mempool                       , Blockfrost.Client.Cardano.Metadata@@ -68,14 +69,14 @@                       , Blockfrost.Client.IPFS                       , Blockfrost.Client.NutLink    build-depends:       base                     >= 4.7 && < 5-                      , blockfrost-api           >= 0.12.2-                      , blockfrost-client-core   ^>= 0.6+                      , blockfrost-api           >= 0.15+                      , blockfrost-client-core   ^>= 0.8                       , bytestring-                      , directory                       , data-default                       , filepath                       , text                       , mtl+                      , retry                    >= 0.9  && < 0.10                       , servant                  >= 0.18 && < 0.21                       , servant-client                       , servant-client-core
example/Main.hs view
@@ -16,20 +16,21 @@     latestBlocks <- getLatestBlock     (ers :: Either BlockfrostError [AccountReward]) <-       tryError $ getAccountRewards "gonnaFail"-    -    allMempoolTxs <- -      getMempoolTransactions prj def def-    -    if null allMempoolTxs ++    -- variant accepting @Paged@ and @SortOrder@ arguments+    -- getAccountRewards' "gonnaFail" (page 10) desc++    allMempoolTxs <-+      allPages $ \p -> getMempoolTransactions' p def++    if null allMempoolTxs     then return $ (latestBlocks, ers, allMempoolTxs, Nothing)     else do let lastTxInMempool = TxHash . unTxHashObject $ last allMempoolTxs-            lastMempoolTx <- getMempoolTransaction prj lastTxInMempool-                +            lastMempoolTx <- getMempoolTransaction lastTxInMempool+             return (latestBlocks, ers, allMempoolTxs, Just lastMempoolTx) -    -  -- variant accepting @Paged@ and @SortOrder@ arguments-  -- getAccountRewards' "gonnaFail" (page 10) desc-  case res of ++  case res of     Left e -> print e     Right ((latestBlocks, ers, allMempoolTxs, lastMempoolTx)) -> do        print "Latest blocks:"@@ -45,16 +46,18 @@       print lastMempoolTx       putStrLn "" -      case lastMempoolTx of +      case lastMempoolTx of         Nothing -> print "No mempool transactions found."         Just mempoolTx -> do-          let inputs = _inputs mempoolTx-          if null inputs -          then print "No mempool transactions found" -- Should be impossible-          else -            do let address = Address . _address $ head inputs-               mempoolTxByAddress <- runBlockfrost prj $ getMempoolTransactionsByAddress prj address def def-               print "Mempool transactions by address:"-               print mempoolTxByAddress-               -  +          case _inputs mempoolTx of+            [] -> print "No mempool transaction inputs found" -- Should be impossible+            (inp:_) -> do+              case _address inp of+                Nothing -> print "Input has no address"+                Just addr -> do+                  mempoolTxByAddress <-+                    runBlockfrost prj+                      $ getMempoolTransactionsByAddress+                          (Address addr)+                  print "Mempool transactions by address:"+                  print mempoolTxByAddress
src/Blockfrost/Client.hs view
@@ -92,6 +92,25 @@   , getEpochBlocksByPool   , getEpochBlocksByPool'   , getEpochProtocolParams+  -- Cardano - Governance+  , getDReps+  , getDReps'+  , getDRep+  , getDRepDelegators+  , getDRepDelegators'+  , getDRepMetadata+  , getDRepUpdates+  , getDRepUpdates'+  , getDRepVotes+  , getDRepVotes'+  , getProposals+  , getProposals'+  , getProposal+  , getParamProposal+  , getWithdrawalProposal+  , getProposalVotes+  , getProposalVotes'+  , getProposalMetadata     -- Cardano - Ledger   , getLedgerGenesis     -- Cardano - Metadata@@ -103,8 +122,10 @@   , getTxMetadataByLabelCBOR'     -- Cardano - Mempool   , getMempoolTransactions+  , getMempoolTransactions'   , getMempoolTransaction   , getMempoolTransactionsByAddress+  , getMempoolTransactionsByAddress'     -- Cardano - Network   , getNetworkInfo   , getNetworkEras@@ -185,6 +206,7 @@ import Blockfrost.Client.Cardano.Assets import Blockfrost.Client.Cardano.Blocks import Blockfrost.Client.Cardano.Epochs+import Blockfrost.Client.Cardano.Governance import Blockfrost.Client.Cardano.Ledger import Blockfrost.Client.Cardano.Mempool import Blockfrost.Client.Cardano.Metadata
+ src/Blockfrost/Client/Cardano/Governance.hs view
@@ -0,0 +1,167 @@+-- | Governance queries++module Blockfrost.Client.Cardano.Governance+  ( getDReps+  , getDReps'+  , getDRep+  , getDRepDelegators+  , getDRepDelegators'+  , getDRepMetadata+  , getDRepUpdates+  , getDRepUpdates'+  , getDRepVotes+  , getDRepVotes'+  , getProposals+  , getProposals'+  , getProposal+  , getParamProposal+  , getWithdrawalProposal+  , getProposalVotes+  , getProposalVotes'+  , getProposalMetadata+  ) where++import Blockfrost.API+import Blockfrost.Client.Types+import Blockfrost.Types++governanceClient :: MonadBlockfrost m => Project -> GovernanceAPI (AsClientT m)+governanceClient = fromServant . _governance . cardanoClient++getDReps_ :: MonadBlockfrost m => Project -> Paged -> SortOrder -> m [DRep]+getDReps_ = _dreps . governanceClient++-- | Return the information about Delegate Representatives (DReps).+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getDReps' :: MonadBlockfrost m => Paged -> SortOrder -> m [DRep]+getDReps' pg s = go (\p -> getDReps_ p pg s)++-- | Return the information about Delegate Representatives (DReps).+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getDReps :: MonadBlockfrost m => m [DRep]+getDReps = getDReps' def def++getDRep_ :: MonadBlockfrost m => Project -> DRepId -> m DRepInfo+getDRep_ = _drep . governanceClient++-- | Return the information about specific Delegate Representative (DRep).+getDRep :: MonadBlockfrost m => DRepId -> m DRepInfo+getDRep d = go (`getDRep_` d)++getDRepDelegators_ :: MonadBlockfrost m => Project -> DRepId -> Paged -> SortOrder -> m [DRepDelegator]+getDRepDelegators_ = _drepDelegators . governanceClient++-- | Get a list of DRep delegators+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getDRepDelegators' :: MonadBlockfrost m => DRepId -> Paged -> SortOrder -> m [DRepDelegator]+getDRepDelegators' d pg s = go (\p -> getDRepDelegators_ p d pg s)++-- | Get a list of DRep delegators+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getDRepDelegators :: MonadBlockfrost m => DRepId -> m [DRepDelegator]+getDRepDelegators d = getDRepDelegators' d def def++getDRepMetadata_ :: MonadBlockfrost m => Project -> DRepId -> m DRepMeta+getDRepMetadata_ = _drepMetadata . governanceClient++-- | Get DRep metadata information.+getDRepMetadata :: MonadBlockfrost m => DRepId -> m DRepMeta+getDRepMetadata d = go (`getDRepMetadata_` d)++getDRepUpdates_ :: MonadBlockfrost m => Project -> DRepId -> Paged -> SortOrder -> m [DRepUpdate]+getDRepUpdates_ = _drepUpdates . governanceClient++-- | Get a list of certificate updates to the DRep.+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getDRepUpdates' :: MonadBlockfrost m => DRepId -> Paged -> SortOrder -> m [DRepUpdate]+getDRepUpdates' d pg s = go (\p -> getDRepUpdates_ p d pg s)++-- | Get a list of certificate updates to the DRep.+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getDRepUpdates :: MonadBlockfrost m => DRepId -> m [DRepUpdate]+getDRepUpdates d = getDRepUpdates' d def def++getDRepVotes_ :: MonadBlockfrost m => Project -> DRepId -> Paged -> SortOrder -> m [DRepVote]+getDRepVotes_ = _drepVotes . governanceClient++-- | Get a history of DReps votes.+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getDRepVotes' :: MonadBlockfrost m => DRepId -> Paged -> SortOrder -> m [DRepVote]+getDRepVotes' d pg s = go (\p -> getDRepVotes_ p d pg s)++-- | Get a history of DReps votes.+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getDRepVotes :: MonadBlockfrost m => DRepId -> m [DRepVote]+getDRepVotes d = getDRepVotes' d def def++getProposals_ :: MonadBlockfrost m => Project -> Paged -> SortOrder -> m [Proposal]+getProposals_ = _proposals . governanceClient++-- | Get a history of DReps proposals.+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getProposals' :: MonadBlockfrost m => Paged -> SortOrder -> m [Proposal]+getProposals' pg s = go (\p -> getProposals_ p pg s)++-- | Get a history of DReps proposals.+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getProposals :: MonadBlockfrost m => m [Proposal]+getProposals = getProposals' def def++getProposal_ :: MonadBlockfrost m => Project -> TxHash -> Integer -> m ProposalInfo+getProposal_ = _proposal . governanceClient++-- | Get a proposal details.+getProposal :: MonadBlockfrost m => TxHash -> Integer -> m ProposalInfo+getProposal txHash certIdx = go (\p -> getProposal_ p txHash certIdx)++getParamProposal_ :: MonadBlockfrost m => Project -> TxHash -> Integer -> m ParamProposal+getParamProposal_ = _paramProposal . governanceClient++-- | Get a parameter proposal details.+getParamProposal :: MonadBlockfrost m => TxHash -> Integer -> m ParamProposal+getParamProposal txHash certIdx = go (\p -> getParamProposal_ p txHash certIdx)++getWithdrawalProposal_ :: MonadBlockfrost m => Project -> TxHash -> Integer -> m [WithdrawalProposal]+getWithdrawalProposal_ = _withdrawalProposal . governanceClient++-- | Get a witdhrawal proposal details.+getWithdrawalProposal :: MonadBlockfrost m => TxHash -> Integer -> m [WithdrawalProposal]+getWithdrawalProposal txHash certIdx = go (\p -> getWithdrawalProposal_ p txHash certIdx)++getProposalVotes_ :: MonadBlockfrost m => Project -> TxHash -> Integer -> Paged -> SortOrder -> m [ProposalVote]+getProposalVotes_ = _proposalVotes . governanceClient++-- | Get a history of DReps proposals.+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getProposalVotes' :: MonadBlockfrost m => TxHash -> Integer -> Paged -> SortOrder -> m [ProposalVote]+getProposalVotes' txHash certIdx pg s = go (\p -> getProposalVotes_ p txHash certIdx pg s)++-- | Get a history of DReps proposals.+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getProposalVotes :: MonadBlockfrost m => TxHash -> Integer -> m [ProposalVote]+getProposalVotes txHash certIdx = getProposalVotes' txHash certIdx def def++getProposalMetadata_ :: MonadBlockfrost m => Project -> TxHash -> Integer -> m ProposalMeta+getProposalMetadata_ = _proposalMeta . governanceClient++-- | Get a parameter proposal details.+getProposalMetadata :: MonadBlockfrost m => TxHash -> Integer -> m ProposalMeta+getProposalMetadata txHash certIdx = go (\p -> getProposalMetadata_ p txHash certIdx)
src/Blockfrost/Client/Cardano/Mempool.hs view
@@ -2,8 +2,10 @@  module Blockfrost.Client.Cardano.Mempool   ( getMempoolTransactions-  , getMempoolTransaction +  , getMempoolTransactions'+  , getMempoolTransaction   , getMempoolTransactionsByAddress+  , getMempoolTransactionsByAddress'   ) where  import Blockfrost.API@@ -13,12 +15,43 @@ mempoolClient :: MonadBlockfrost m => Project -> MempoolAPI (AsClientT m) mempoolClient = fromServant . _mempool . cardanoClient -getMempoolTransactions :: MonadBlockfrost m => Project -> Paged -> SortOrder -> m [TxHashObject]-getMempoolTransactions = _mempoolTransactions . mempoolClient +getMempoolTransactions_ :: MonadBlockfrost m => Project -> Paged -> SortOrder -> m [TxHashObject]+getMempoolTransactions_ = _mempoolTransactions . mempoolClient -getMempoolTransaction :: MonadBlockfrost m => Project -> TxHash -> m MempoolTransaction-getMempoolTransaction = _specificTransaction . mempoolClient  +-- | Get a list of transactions currently in Blockfrost.io mempool+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getMempoolTransactions' :: MonadBlockfrost m => Paged -> SortOrder -> m [TxHashObject]+getMempoolTransactions' pg s = go (\p -> getMempoolTransactions_ p pg s) -getMempoolTransactionsByAddress :: MonadBlockfrost m => Project -> Address -> Paged -> SortOrder -> m [TxHashObject]-getMempoolTransactionsByAddress = _specificAddress . mempoolClient +-- | Get a list of transactions currently in Blockfrost.io mempool+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getMempoolTransactions :: MonadBlockfrost m => m [TxHashObject]+getMempoolTransactions = getMempoolTransactions' def def +getMempoolTransaction_ :: MonadBlockfrost m => Project -> TxHash -> m MempoolTransaction+getMempoolTransaction_ = _specificTransaction . mempoolClient++-- | Get details about a specific @MempoolTransaction@+getMempoolTransaction :: MonadBlockfrost m => TxHash -> m MempoolTransaction+getMempoolTransaction t = go (`getMempoolTransaction_` t)++getMempoolTransactionsByAddress_ :: MonadBlockfrost m => Project -> Address -> Paged -> SortOrder -> m [TxHashObject]+getMempoolTransactionsByAddress_ = _specificAddress . mempoolClient++-- | Get a list of transactions currently in Blockfrost.io mempool+-- where at least one of the transaction inputs or outputs belongs to the address.+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getMempoolTransactionsByAddress' :: MonadBlockfrost m => Address -> Paged -> SortOrder -> m [TxHashObject]+getMempoolTransactionsByAddress' addr pg s = go (\p -> getMempoolTransactionsByAddress_ p addr pg s)++-- | Get a list of transactions currently in Blockfrost.io mempool+-- where at least one of the transaction inputs or outputs belongs to the address.+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getMempoolTransactionsByAddress :: MonadBlockfrost m => Address -> m [TxHashObject]+getMempoolTransactionsByAddress addr = go (\p -> getMempoolTransactionsByAddress_ p addr def def)
src/Blockfrost/Client/IPFS.hs view
@@ -15,28 +15,19 @@ import Blockfrost.API import Blockfrost.Client.Types import Blockfrost.Types-import Control.Monad.Except (MonadError, throwError)-import Control.Monad.IO.Class (liftIO) import Data.ByteString.Lazy (ByteString) import Data.Text (Text) import qualified Data.Text-import qualified System.Directory import qualified System.FilePath  ipfsAdd_ :: MonadBlockfrost m => Project -> (ByteString, Form) -> m IPFSAdd ipfsAdd_ = _add . ipfsClient  -- | Add a file or directory to IPFS-ipfsAdd :: (MonadError BlockfrostError m, MonadBlockfrost m) => FilePath -> m IPFSAdd+ipfsAdd :: MonadBlockfrost m => FilePath -> m IPFSAdd ipfsAdd fp = do-  hasFile <- liftIO $ System.Directory.doesFileExist fp-  if hasFile-    then do-      liftIO $ putStrLn $ "Uploading: " ++ fp-      let fn = Data.Text.pack $ System.FilePath.takeBaseName fp-      go (\proj -> ipfsAdd_ proj ("suchBoundary", (Form fn fp)))-    else-      throwError (BlockfrostError "No such file")+  let fn = Data.Text.pack $ System.FilePath.takeBaseName fp+  go (\proj -> ipfsAdd_ proj ("suchBoundary", (Form fn fp)))  ipfsGateway_ :: MonadBlockfrost m => Project -> Text -> m IPFSData ipfsGateway_ = _gateway . ipfsClient
src/Blockfrost/Client/Types.hs view
@@ -2,11 +2,17 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE Rank2Types #-}  module Blockfrost.Client.Types   ( BlockfrostClient   , BlockfrostError (..)   , ClientConfig+  , defaultRetryPolicy+  , endlessRetryPolicy+  , defaultRetryJudge   , runBlockfrost   , apiClient   , api0Client@@ -30,6 +36,7 @@  import Control.Monad.Except import Control.Monad.Reader+import Control.Retry import Data.Default  import Servant.API.Generic@@ -39,8 +46,26 @@ import Blockfrost.API import Blockfrost.Client.Core -type ClientConfig = (ClientEnv, Project)+data ClientConfig =+  ClientConfig+    { clientConfigClientEnv   :: ClientEnv+    , clientConfigProject     :: Project+    , clientConfigRetryPolicy :: RetryPolicy+    , clientConfigRetryJudge  :: RetryStatus -> BlockfrostError -> RetryAction+    } +defaultRetryPolicy :: RetryPolicy+defaultRetryPolicy = exponentialBackoff (1000 * 1000) <> limitRetries 5++endlessRetryPolicy :: RetryPolicy+endlessRetryPolicy = exponentialBackoff (1000 * 1000)++defaultRetryJudge+  :: RetryStatus+  -> BlockfrostError+  -> RetryAction+defaultRetryJudge _retryStatus err = retriableError err+ newtype BlockfrostClientT m a = BlockfrostClientT {   unBlockfrostClientT     :: ExceptT BlockfrostError@@ -62,13 +87,33 @@  instance MonadIO m => MonadBlockfrost (BlockfrostClientT m) where   liftBlockfrostClient act = BlockfrostClientT $ do-    (env, _proj) <- ask-    liftIO (runClientM act env)-      >>= either-            (throwError . fromServantClientError)-            pure+    clientConfig <- ask+    liftIO+      $ withRetry+          clientConfig+          $ runClientM act (clientConfigClientEnv clientConfig)+    >>= either+          (throwError . fromServantClientError)+          pure   getConf = BlockfrostClientT ask +withRetry+  :: ClientConfig+  -> IO (Either ClientError a)+  -> IO (Either ClientError a)+withRetry ClientConfig{..} act =+  retryingDynamic+    clientConfigRetryPolicy+    (\retryStatus -> \case+        Right{} -> pure DontRetry+        Left err ->+          pure+          $ clientConfigRetryJudge+              retryStatus+              (fromServantClientError err)+    )+    (const act)+ instance MonadBlockfrost ClientM where   liftBlockfrostClient = id   getConf = newClientConfig@@ -76,11 +121,16 @@ instance MonadBlockfrost IO where   liftBlockfrostClient act =     getConf-      >>= \(env, _prj) ->-        runClientM act env-          >>= either-                (error . show)-                pure+      >>= \clientConfig ->+        withRetry+          clientConfig+          ( runClientM+              act+              (clientConfigClientEnv clientConfig)+          )+        >>= either+              (error . show)+              pure   getConf = newClientConfig  apiClient@@ -110,24 +160,37 @@   -> BlockfrostClientT m a   -> m (Either BlockfrostError a) runBlockfrostClientT proj act = do-  env <- liftIO $ newEnvByProject proj-  flip runReaderT (env, proj)+  cc <- liftIO $ mkClientConfig proj+  flip runReaderT cc     $ runExceptT $ unBlockfrostClientT act  -- | Build default `ClientConfig` using BLOCKFROST_TOKEN_PATH environment variable newClientConfig   :: MonadIO m   => m ClientConfig-newClientConfig = liftIO $ do-  prj <- projectFromEnv-  env <- newEnvByProject prj-  pure (env, prj)+newClientConfig =+  liftIO+    $ projectFromEnv >>= mkClientConfig +mkClientConfig+  :: MonadIO m+  => Project+  -> m ClientConfig+mkClientConfig prj = do+  env <- liftIO $ newEnvByProject prj+  pure+    $ ClientConfig+        { clientConfigClientEnv   = env+        , clientConfigProject     = prj+        , clientConfigRetryPolicy = defaultRetryPolicy+        , clientConfigRetryJudge  = defaultRetryJudge+        }+ -- | Helper go :: MonadBlockfrost m    => (Project -> m a)    -> m a-go act = getConf >>= act . snd+go act = getConf >>= act . clientConfigProject  -- Until mtl > 2.2.2 -- https://github.com/haskell/mtl/pull/66