blockfrost-client 0.8.0.1 → 0.13.0.0
raw patch · 12 files changed
Files
- CHANGELOG.md +73/−2
- blockfrost-client.cabal +7/−4
- example/Main.hs +44/−3
- src/Blockfrost/Client.hs +32/−0
- src/Blockfrost/Client/Cardano/Blocks.hs +36/−0
- src/Blockfrost/Client/Cardano/Governance.hs +167/−0
- src/Blockfrost/Client/Cardano/Mempool.hs +57/−0
- src/Blockfrost/Client/Cardano/Pools.hs +1/−1
- src/Blockfrost/Client/Cardano/Transactions.hs +9/−1
- src/Blockfrost/Client/IPFS.hs +3/−12
- src/Blockfrost/Client/NutLink.hs +1/−1
- src/Blockfrost/Client/Types.hs +81/−18
CHANGELOG.md view
@@ -1,3 +1,74 @@+# 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+ * `getBlockTxsCBOR` for `/blocks/:hash_or_number/txs/cbor` endpoint [#73](https://github.com/blockfrost/blockfrost-haskell/pull/73) [#75](https://github.com/blockfrost/blockfrost-haskell/pull/75)+ * `getLatestBlockTxsCBOR` for `/blocks/latest/txs/cbor` endpoint [#73](https://github.com/blockfrost/blockfrost-haskell/pull/73) [#75](https://github.com/blockfrost/blockfrost-haskell/pull/75)+++# Version [0.9.1.0](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.9.0.0...client-0.9.1.0) (2024-09-25)++* Fix return type of `getTxCBOR` from `[TransactionCBOR]` to `TransactionCBOR`.++# Version [0.9.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.8.0.1...client-0.9.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)+ * `getTxCBOR` for `/txs/:hash/cbor` [#63](https://github.com/blockfrost/blockfrost-haskell/pull/63)+ # Version [0.8.0.1](https://github.com/blockfrost/blockfrost-haskell/compare/client-0.8.0.0...client-0.8.0.1) (2024-01-16) * GHC 9.6.3 compatibility@@ -11,8 +82,8 @@ * `listPoolsExtended` for `/pools/extended` * `/utils` API * `deriveShelleyAddress` for `/utils/addresses/xpub/:xpub/:role/:index`- * `evaluateTx` for `/utils/txs/evaluate` endpoint- * `evaluateTxUTXOs` for `/utils/txs/evaluate/utxos` endpoint+ * `txEvaluate` for `/utils/txs/evaluate` endpoint+ * `txEvaluateUTXOs` for `/utils/txs/evaluate/utxos` endpoint # Version [0.7.1.1](https://github.com/blockfrost/blockfrost-haskell/compare/v0.7.1.0...client-0.7.1.1) (2023-01-10)
blockfrost-client.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: blockfrost-client-version: 0.8.0.1+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@@ -35,6 +35,7 @@ common libstuff default-language: Haskell2010+ default-extensions: DuplicateRecordFields ghc-options: -Wall -Wunused-packages -fno-specialize -- ^ this helps quite a lot@@ -56,7 +57,9 @@ , 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 , Blockfrost.Client.Cardano.Network , Blockfrost.Client.Cardano.Pools@@ -66,14 +69,14 @@ , Blockfrost.Client.IPFS , Blockfrost.Client.NutLink build-depends: base >= 4.7 && < 5- , blockfrost-api >= 0.9- , 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
@@ -3,7 +3,8 @@ module Main where -import Blockfrost.Client+import Blockfrost.Client hiding (NutLinkAPI(..))+import Control.Monad.IO.Class main = do -- reads token from BLOCKFROST_TOKEN_PATH@@ -18,5 +19,45 @@ -- variant accepting @Paged@ and @SortOrder@ arguments -- getAccountRewards' "gonnaFail" (page 10) desc- pure (latestBlocks, ers)- print res++ 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 lastTxInMempool++ return (latestBlocks, ers, allMempoolTxs, Just lastMempoolTx) ++ case res of+ Left e -> print e+ Right ((latestBlocks, ers, allMempoolTxs, lastMempoolTx)) -> do + print "Latest blocks:"+ print latestBlocks+ putStrLn ""+ print "Account rewards (expected to error):"+ print ers+ putStrLn ""+ print "All mempool transactions (mempool potentially empty):"+ print allMempoolTxs+ putStrLn ""+ print "Last mempool transaction (if any):"+ print lastMempoolTx+ putStrLn ""++ case lastMempoolTx of+ Nothing -> print "No mempool transactions found."+ Just mempoolTx -> do+ 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
@@ -60,6 +60,8 @@ , getLatestBlock , getLatestBlockTxs , getLatestBlockTxs'+ , getLatestBlockTxsCBOR+ , getLatestBlockTxsCBOR' , getBlock , getBlockSlot , getBlockEpochSlot@@ -69,6 +71,8 @@ , getPreviousBlocks' , getBlockTxs , getBlockTxs'+ , getBlockTxsCBOR+ , getBlockTxsCBOR' , getBlockAffectedAddresses' , getBlockAffectedAddresses -- Cardano - Epochs@@ -88,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@@ -97,6 +120,12 @@ , getTxMetadataByLabelJSON' , getTxMetadataByLabelCBOR , getTxMetadataByLabelCBOR'+ -- Cardano - Mempool+ , getMempoolTransactions+ , getMempoolTransactions'+ , getMempoolTransaction+ , getMempoolTransactionsByAddress+ , getMempoolTransactionsByAddress' -- Cardano - Network , getNetworkInfo , getNetworkEras@@ -140,6 +169,7 @@ , getTxPoolUpdates , getTxPoolRetiring , getTxMetadataJSON+ , getTxCBOR , getTxMetadataCBOR , getTxRedeemers , submitTx@@ -176,7 +206,9 @@ 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 import Blockfrost.Client.Cardano.Network import Blockfrost.Client.Cardano.Pools
src/Blockfrost/Client/Cardano/Blocks.hs view
@@ -4,6 +4,8 @@ ( getLatestBlock , getLatestBlockTxs , getLatestBlockTxs'+ , getLatestBlockTxsCBOR+ , getLatestBlockTxsCBOR' , getBlock , getBlockSlot , getBlockEpochSlot@@ -13,6 +15,8 @@ , getPreviousBlocks' , getBlockTxs , getBlockTxs'+ , getBlockTxsCBOR+ , getBlockTxsCBOR' , getBlockAffectedAddresses' , getBlockAffectedAddresses ) where@@ -47,6 +51,22 @@ getLatestBlockTxs :: MonadBlockfrost m => m [TxHash] getLatestBlockTxs = getLatestBlockTxs' def def +getLatestBlockTxsCBOR_ :: MonadBlockfrost m => Project -> Paged -> SortOrder -> m [TxHashCBOR]+getLatestBlockTxsCBOR_ = _latestTxsCBOR . blocksClient++-- | Return the transactions within the block, including CBOR.+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getLatestBlockTxsCBOR' :: MonadBlockfrost m => Paged -> SortOrder -> m [TxHashCBOR]+getLatestBlockTxsCBOR' pg s = go (\p -> getLatestBlockTxsCBOR_ p pg s)++-- | Return the transactions within the block, including CBOR.+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getLatestBlockTxsCBOR :: MonadBlockfrost m => m [TxHashCBOR]+getLatestBlockTxsCBOR = getLatestBlockTxsCBOR' def def+ getBlock_ :: MonadBlockfrost m => Project -> Either Integer BlockHash -> m Block getBlock_ = _block . blocksClient @@ -115,6 +135,22 @@ -- that accepts 'Paged' argument. getBlockTxs :: MonadBlockfrost m => Either Integer BlockHash -> m [TxHash] getBlockTxs a = getBlockTxs' a def def++getBlockTxsCBOR_ :: MonadBlockfrost m => Project -> Either Integer BlockHash -> Paged -> SortOrder -> m [TxHashCBOR]+getBlockTxsCBOR_ = _blockTxsCBOR . blocksClient++-- | Return the transactions within the block, including CBOR.+-- Allows custom paging and ordering using 'Paged' and 'SortOrder'.+getBlockTxsCBOR' :: MonadBlockfrost m => Either Integer BlockHash -> Paged -> SortOrder -> m [TxHashCBOR]+getBlockTxsCBOR' a pg s = go (\p -> getBlockTxsCBOR_ p a pg s)++-- | Return the transactions within the block, including CBOR.+--+-- Queries 100 entries. To query all entries use 'Blockfrost.Client.Core.allPages'+-- with principled variant of this function (suffixed with @'@)+-- that accepts 'Paged' argument.+getBlockTxsCBOR :: MonadBlockfrost m => Either Integer BlockHash -> m [TxHashCBOR]+getBlockTxsCBOR a = getBlockTxsCBOR' a def def getBlockAffectedAddresses_ :: MonadBlockfrost m => Project -> Either Integer BlockHash -> Paged -> m [(Address, [TxHash])] getBlockAffectedAddresses_ = _blockAffectedAddresses . blocksClient
+ 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
@@ -0,0 +1,57 @@+-- | Mempool queries++module Blockfrost.Client.Cardano.Mempool+ ( getMempoolTransactions+ , getMempoolTransactions'+ , getMempoolTransaction+ , getMempoolTransactionsByAddress+ , getMempoolTransactionsByAddress'+ ) where++import Blockfrost.API+import Blockfrost.Client.Types+import Blockfrost.Types++mempoolClient :: MonadBlockfrost m => Project -> MempoolAPI (AsClientT m)+mempoolClient = fromServant . _mempool . cardanoClient++getMempoolTransactions_ :: MonadBlockfrost m => Project -> Paged -> SortOrder -> m [TxHashObject]+getMempoolTransactions_ = _mempoolTransactions . 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)++-- | 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/Cardano/Pools.hs view
@@ -117,7 +117,7 @@ getPoolHistory p = getPoolHistory' p def def getPoolMetadata_ :: MonadBlockfrost m => Project -> PoolId -> m (Maybe PoolMetadata)-getPoolMetadata_ = _getPoolMetadata . poolsClient+getPoolMetadata_ p pid = getMetadata <$> _getPoolMetadata (poolsClient p) pid -- | Get stake pool metadata getPoolMetadata :: MonadBlockfrost m => PoolId -> m (Maybe PoolMetadata)
src/Blockfrost/Client/Cardano/Transactions.hs view
@@ -11,13 +11,14 @@ , getTxPoolUpdates , getTxPoolRetiring , getTxMetadataJSON+ , getTxCBOR , getTxMetadataCBOR , submitTx ) where import Blockfrost.API import Blockfrost.Client.Types-import Blockfrost.Types+import Blockfrost.Types hiding (MempoolTransaction(..)) transactionsClient :: MonadBlockfrost m => Project -> TransactionsAPI (AsClientT m) transactionsClient = fromServant . _transactions . cardanoClient@@ -91,6 +92,13 @@ -- | Get transaction metadata in JSON getTxMetadataJSON :: MonadBlockfrost m => TxHash -> m [TransactionMetaJSON] getTxMetadataJSON t = go (`getTxMetadataJSON_` t)++getTxCBOR_ :: MonadBlockfrost m => Project -> TxHash -> m TransactionCBOR+getTxCBOR_ = _txCBOR . transactionsClient++-- | Get transaction in CBOR+getTxCBOR :: MonadBlockfrost m => TxHash -> m TransactionCBOR+getTxCBOR t = go (`getTxCBOR_` t) getTxMetadataCBOR_ :: MonadBlockfrost m => Project -> TxHash -> m [TransactionMetaCBOR] getTxMetadataCBOR_ = _txMetadataCBOR . transactionsClient
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/NutLink.hs view
@@ -12,7 +12,7 @@ import Blockfrost.API import Blockfrost.Client.Types-import Blockfrost.Types+import Blockfrost.Types hiding (MempoolUTxOInput(..)) import Data.Text (Text) nutlinkListAddress_ :: MonadBlockfrost m => Project -> Address-> m NutlinkAddress
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