Code Monkey home page Code Monkey logo

blockfrost-haskell's Introduction

GitHub Actions Hackage blockfrost-api Hackage blockfrost-client Hackage blockfrost-pretty Made by Five Binaries

blockfrost-haskell


Haskell SDK for Blockfrost.io API.

AboutGetting startedInstallationUsage


About

The repository provides an API definition, data types, client and utilities for working with Blockfrost. We are striving to provide beginner-friendly interface while adding a bit of type safety, especially when working with monetary values.

Packages

Getting started

To use this SDK, you first need to log in to blockfrost.io, create your project and retrieve the API token.


Installation

Packages are available on Hackage, you only need to add blockfrost-client to your package dependencies.

Haddocks available on Hackage:

  • Hackage blockfrost-api
  • Hackage blockfrost-client
  • Hackage blockfrost-pretty

Development setup

You can either work within this repository using plain cabal or in combination with nix.

cabal

If you already have GHC and cabal installed:

git clone https://github.com/blockfrost/blockfrost-haskell
cd blockfrost-haskell
cabal update
cabal build all
cabal repl blockfrost-client

Note: Due to TLS support, you might need to provide zlib headers if compilation of http-client-tls fails. (On NixOS this is nix-shell -p zlib.dev).

nix

Using nix-shell, you can obtain a preconfigured environment with GHC and cabal:

git clone https://github.com/blockfrost/blockfrost-haskell
cd blockfrost-haskell
nix-shell
cabal build all
cabal repl blockfrost-client

Usage

See blockfrost-client for a tutorial and usage examples.

Readme of blockfrost-api contains a short primer for working with Blockfrost types, data samples and monetary values.

blockfrost-haskell's People

Contributors

euonymos avatar mmahut avatar nhenin avatar sorki avatar sourabhxyz avatar totallynotchase avatar unisay avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

blockfrost-haskell's Issues

Specifying count

I see that some API functions have a ' variant which allows setting Ordering and Page. I don't see an option for Count (how many results are displayed on a page) although most endpoints that accept Page/Ordering also support that.

It would be nice to be able to specify that, I need to find out the tx that minted an asset and my approach was to use getAssetHistory with default ordering and take the first result, is there any other way to achieve this without having to get all the extra transactions as well?

Decode failure from getEpochStakeByPool

When calling getEpochStakeByPool, the response fails to decode into a [StakeDistribution]. It looks like the endpoint is actually returning a [PoolStakeDistribution] (which is sensible of it, but not what I was promised):

Left (ServantClientError
            (DecodeFailure "Error in $[0]: parsing Blockfrost.Types.Cardano.Epochs.StakeDistribution(StakeDistribution) failed, key \"pool_id\" not found"
             (Response {responseStatusCode = Status {statusCode = 200, statusMessage = "OK"}
                       , responseHeaders = fromList [("Date","Thu, 26 May 2022 16:47:22 GMT")
                                                    ,("Content-Type","application/json; charset=utf-8")
                                                    ,("Transfer-Encoding","chunked"),("Connection","keep-alive"),("vary","Origin")
                                                    ,("access-control-allow-origin","*")
                                                    ,("CF-Cache-Status","DYNAMIC")
                                                    ,("Expect-CT","max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"")
                                                    ,("Report-To","{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=9it7DWWhJnzCC7%2B475LUHch6DsIxyinNeGG%2FjSPxEKpbHPqV4fiXq6CSjJXIhBo6W3l9Hajymxb5JNZ7bFW3OhEFg%2F0eSPxG9tTzu19leiH9o8b%2Fsof7wkiZD3FWFpNmSMll4gpvHrOIZBtHFVbz\"}]
                                                     ,\"group\":\"cf-nel\",\"max_age\":604800}")
                                                    ,("NEL","{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}")
                                                    ,("Server","cloudflare")
                                                    ,("CF-RAY","7117fe062d0d59f8-IAD"),("Content-Encoding","gzip")]
                       , responseHttpVersion = HTTP/1.1
                       , responseBody = "[{\"stake_address\":\"stake1uyzrryeqlgqyxa3aznvvu5ltugul50nrdux3qpfzmy3wtysj6afan\",\"amount\":\"385036799\"}
                                         ,{\"stake_address\":\"stake1uyz605x9s0k8tuaduf22t7ykyqzj5x62duhk9fx4xkcd2tqelrume\",\"amount\":\"150739885669\"}
                                         ,{\"stake_address\":\"stake1uyralt48wa8f9eucv6nv54e2e3nl3dwyvxh67pgn9qfcaqsudgp8m\",\"amount\":\"1630642086\"}
                                         ,{\"stake_address\":\"stake1uyyruy4n50anvlfurj9gd5anmmgg7wv0k6xht998y2eq8lgw4whkh\",\"amount\":\"2802274\"}
                                          -- etc
                                         ]"})))

Add missing class instances to the Slot type

From playing around with the API I found that Slot is missing some useful class instances: Ord, Enum, Real, and Integral.

Here are example implementations:

instance Ord Blockfrost.Slot where
  compare (Blockfrost.Slot a) (Blockfrost.Slot b)
    | a < b = LT
    | a == b = EQ
    | otherwise = GT

instance Enum Blockfrost.Slot where
  toEnum = Blockfrost.Slot . toInteger
  fromEnum = fromIntegral . Blockfrost.unSlot

instance Real Blockfrost.Slot where
  toRational = toRational . Blockfrost.unSlot

instance Integral Blockfrost.Slot where
  toInteger = toInteger . Blockfrost.unSlot
  quotRem a b =
    let (l, r) = quotRem (Blockfrost.unSlot a) (Blockfrost.unSlot b)
     in (Blockfrost.Slot l, Blockfrost.Slot r)

Overlapping instances

When compiling my program that uses blockfrost-client I get the following error:

    • Overlapping instances for Aeson.FromJSON [t]
        arising from a use of ‘client’
      Matching instances:
        instance Aeson.FromJSON a => Aeson.FromJSON [a]
          -- Defined in ‘aeson-2.0.2.0:Data.Aeson.Types.FromJSON’
        ...plus one instance involving out-of-scope types
          instance [overlap ok] Aeson.FromJSON
                                  [Blockfrost.Types.Shared.ScriptHash.ScriptHash]
            -- Defined in ‘Blockfrost.Types.Shared.ScriptHash’
      (The choice depends on the instantiation of ‘t’
       To pick the first instance above, use IncoherentInstances
       when compiling the other instance declarations)

I believe this is caused by:
https://github.com/blockfrost/blockfrost-haskell/blob/master/blockfrost-api/src/Blockfrost/Types/Shared/ScriptHash.hs#L30-L38

conflicting with the:
https://hackage.haskell.org/package/aeson-2.0.2.0/docs/src/Data.Aeson.Types.ToJSON.html#local-6989586621679151368

Misleading documentation or type wrt number of returned results.

image

Looking at the doc above I naturally thought that first function returns all available pools in one (potentially slow) request/response, while the second one allows to fetch them page by page.

I was surprised to discover that listPools returns only 100 of pools (first default page).
I had to allPages \paged -> listPools' paged Ascending to retrieve all of them.

Please either fix the behavior or update the doc to eliminate incorrect expectations.
Note: same applies to other functions that allow paging, I just used listPools as an example.

DecodeFailure when calling `getAccount`

I got this error when I tried to call getAccount, it seems that the active_epoch field can be Null

ServantClientError (
  DecodeFailure "Error in $['active_epoch']: parsing Integer failed, expected Number, but encountered Null"
  (Response
    { responseStatusCode = Status
      { statusCode = 200
      , statusMessage = "OK"
      }
    , responseHeaders = fromList [(...)]
    , responseHttpVersion = HTTP/1.1
    , responseBody = 
    "{\"stake_address\":\"stake1u8rf90xklsjejdtehdx5qdq8ycxqr9hyceumfx59pfll27q8dggl6\",
    \"active\":false,
    \"active_epoch\":null,
    \"controlled_amount\":\"11170532\",
    \"rewards_sum\":\"0\",
    \"withdrawals_sum\":\"0\",
    \"reserves_sum\":\"0\",
    \"treasury_sum\":\"0\",
    \"withdrawable_amount\":\"0\",
    \"pool_id\":null}"}))

Orphaned `Arbitrary` instances are brought into scope by the `Blockfrost.Client`

Actual situation

Fact 1:
The quickcheck-instances library has this warning in its documentation:

Since all of these instances are provided as orphans, I recommend that you do not use this library within another library module, so that you don't impose these instances on down-stream consumers of your code.

Fact 2:
Blockfrost API library uses quickcheck-instances

Fact 3:
blockfrost-api is a library that ignores the warning and causes problems associated with the orphaned instances to its users, even transitively, via the blockfrost-client dependency.

Desired situation

blockfrost-api doesn't bring orphaned instances to scope for all its downstream users.

Having a Tagless Final version of the API

Hi, It's quite difficult to compose logic with a rigid datatype like :

type ClientConfig = (ClientEnv, Project)
type BlockfrostClient =
  ExceptT BlockfrostError
    (ReaderT ClientConfig IO)

I would have expected using the API that way :

getTx :: BlockfrostClient m => TxHash -> m Transaction
-- vs
getTx :: TxHash -> BlockfrostClient Transaction

And be able to compose my logic that way :

myOwnLogic ::  (BlockfrostClient m , OtherClient m ) => Hash -> m (Tx,Tx')
myOwnLogic  hash = do 
  tx <- getTx hash
  tx' <- getTxFromOtherClient hash
  return (tx,tx')

what do you think ?

blockfrost-client 0.8.0.0 doesn't build with GHC 9.6.3

Building blockfrost-client 0.8.0.0 seems to be failing when building with GHC 9.6.3 with the following error:

Building library for blockfrost-client-0.8.0.0..
[ 1 of 16] Compiling Blockfrost.Client.Types ( src/Blockfrost/Client/Types.hs, dist/build/Blockfrost/Client/Types.o, dist/build/Blockfrost/Client/Types.dyn_o )
[ 2 of 16] Compiling Blockfrost.Client.NutLink ( src/Blockfrost/Client/NutLink.hs, dist/build/Blockfrost/Client/NutLink.o, dist/build/Blockfrost/Client/NutLink.dyn_o )
[ 3 of 16] Compiling Blockfrost.Client.IPFS ( src/Blockfrost/Client/IPFS.hs, dist/build/Blockfrost/Client/IPFS.o, dist/build/Blockfrost/Client/IPFS.dyn_o )

src/Blockfrost/Client/IPFS.hs:31:14: error: [GHC-88464]
    Variable not in scope: liftIO :: IO Bool -> m Bool
    Suggested fix: Perhaps use 'liftA2' (imported from Prelude)
   |
31 |   hasFile <- liftIO $ System.Directory.doesFileExist fp
   |              ^^^^^^

src/Blockfrost/Client/IPFS.hs:34:7: error: [GHC-88464]
    Variable not in scope: liftIO :: IO () -> m a0
    Suggested fix: Perhaps use 'liftA2' (imported from Prelude)
   |
34 |       liftIO $ putStrLn $ "Uploading: " ++ fp
   |       ^^^^^^

The problem stems from the fact that Control.Monad.Except doesn't reexport Control.Monad.Trans anymore which in turn reexported Control.Monad.IO.Class.

Please repair or adjust dependencies, as https://hackage.haskell.org/package/blockfrost-client reports base (>=4.7 && <5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.