packages feed

web3 0.4.1.0 → 0.5.0.0

raw patch · 9 files changed

+236/−182 lines, 9 filesdep +http-client-tlsdep −data-default-classdep −mtldep ~aesondep ~attoparsecdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: http-client-tls

Dependencies removed: data-default-class, mtl

Dependency ranges changed: aeson, attoparsec, base, base16-bytestring, bytestring, cryptonite, http-client, memory, template-haskell, text, transformers, vector, web3

API changes (from Hackage documentation)

- Network.Ethereum.Web3: Config :: String -> Config
- Network.Ethereum.Web3: [rpcUri] :: Config -> String
- Network.Ethereum.Web3: data Config
- Network.Ethereum.Web3: data Error
- Network.Ethereum.Web3: type Web3 = ReaderT Config (ExceptT Error IO)
- Network.Ethereum.Web3.Address: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Address.Address
- Network.Ethereum.Web3.Address: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Address.Address
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.JsonAbi.ContractABI
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.JsonAbi.Declaration
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.JsonAbi.EventArg
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.JsonAbi.FunctionArg
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.JsonAbi.ContractABI
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.JsonAbi.Declaration
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.JsonAbi.EventArg
- Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.JsonAbi.FunctionArg
- Network.Ethereum.Web3.Types: Config :: String -> Config
- Network.Ethereum.Web3.Types: [rpcUri] :: Config -> String
- Network.Ethereum.Web3.Types: data Config
- Network.Ethereum.Web3.Types: data Error
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Types.Block
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Types.Call
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Types.Change
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Types.Filter
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Types.FilterId
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Types.RpcError
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Ethereum.Web3.Types.Transaction
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.Block
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.Call
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.CallMode
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.Change
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.Filter
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.FilterId
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.RpcError
- Network.Ethereum.Web3.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Ethereum.Web3.Types.Transaction
- Network.Ethereum.Web3.Types: instance Data.Default.Class.Default Network.Ethereum.Web3.Types.Config
- Network.Ethereum.Web3.Types: instance GHC.Classes.Eq Network.Ethereum.Web3.Types.Config
- Network.Ethereum.Web3.Types: instance GHC.Classes.Eq Network.Ethereum.Web3.Types.Error
- Network.Ethereum.Web3.Types: instance GHC.Show.Show Network.Ethereum.Web3.Types.Config
- Network.Ethereum.Web3.Types: instance GHC.Show.Show Network.Ethereum.Web3.Types.Error
- Network.Ethereum.Web3.Types: type Web3 = ReaderT Config (ExceptT Error IO)
+ Network.Ethereum.Web3: class Provider a where runWeb3' = liftIO . try . unWeb3 forkWeb3 = Web3 . forkIO . unWeb3
+ Network.Ethereum.Web3: data DefaultProvider
+ Network.Ethereum.Web3: data Web3 a b
+ Network.Ethereum.Web3: data Web3Error
+ Network.Ethereum.Web3: forkWeb3 :: Provider a => Web3 a () -> Web3 a ThreadId
+ Network.Ethereum.Web3: rpcUri :: Provider a => Web3 a String
+ Network.Ethereum.Web3.Address: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Address.Address
+ Network.Ethereum.Web3.Address: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Address.Address
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.JsonAbi.ContractABI
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.JsonAbi.Declaration
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.JsonAbi.EventArg
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.JsonAbi.FunctionArg
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.JsonAbi.ContractABI
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.JsonAbi.Declaration
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.JsonAbi.EventArg
+ Network.Ethereum.Web3.JsonAbi: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.JsonAbi.FunctionArg
+ Network.Ethereum.Web3.Types: Web3 :: IO b -> Web3 a b
+ Network.Ethereum.Web3.Types: [unWeb3] :: Web3 a b -> IO b
+ Network.Ethereum.Web3.Types: class Provider a where runWeb3' = liftIO . try . unWeb3 forkWeb3 = Web3 . forkIO . unWeb3
+ Network.Ethereum.Web3.Types: data DefaultProvider
+ Network.Ethereum.Web3.Types: data Web3Error
+ Network.Ethereum.Web3.Types: forkWeb3 :: Provider a => Web3 a () -> Web3 a ThreadId
+ Network.Ethereum.Web3.Types: instance Control.Monad.IO.Class.MonadIO (Network.Ethereum.Web3.Types.Web3 a)
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Types.Block
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Types.Call
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Types.Change
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Types.Filter
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Types.FilterId
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Types.RpcError
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.FromJSON Network.Ethereum.Web3.Types.Transaction
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.Block
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.Call
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.CallMode
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.Change
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.Filter
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.FilterId
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.RpcError
+ Network.Ethereum.Web3.Types: instance Data.Aeson.Types.Class.ToJSON Network.Ethereum.Web3.Types.Transaction
+ Network.Ethereum.Web3.Types: instance GHC.Base.Applicative (Network.Ethereum.Web3.Types.Web3 a)
+ Network.Ethereum.Web3.Types: instance GHC.Base.Functor (Network.Ethereum.Web3.Types.Web3 a)
+ Network.Ethereum.Web3.Types: instance GHC.Base.Monad (Network.Ethereum.Web3.Types.Web3 a)
+ Network.Ethereum.Web3.Types: instance GHC.Classes.Eq Network.Ethereum.Web3.Types.Web3Error
+ Network.Ethereum.Web3.Types: instance GHC.Exception.Exception Network.Ethereum.Web3.Types.Web3Error
+ Network.Ethereum.Web3.Types: instance GHC.Show.Show Network.Ethereum.Web3.Types.Web3Error
+ Network.Ethereum.Web3.Types: instance Network.Ethereum.Web3.Types.Provider Network.Ethereum.Web3.Types.DefaultProvider
+ Network.Ethereum.Web3.Types: newtype Web3 a b
+ Network.Ethereum.Web3.Types: rpcUri :: Provider a => Web3 a String
- Network.Ethereum.Web3: JsonRpcFail :: RpcError -> Error
+ Network.Ethereum.Web3: JsonRpcFail :: RpcError -> Web3Error
- Network.Ethereum.Web3: ParserFail :: String -> Error
+ Network.Ethereum.Web3: ParserFail :: String -> Web3Error
- Network.Ethereum.Web3: UserFail :: String -> Error
+ Network.Ethereum.Web3: UserFail :: String -> Web3Error
- Network.Ethereum.Web3: call :: (Method a, ABIEncoding b) => Address -> CallMode -> a -> Web3 b
+ Network.Ethereum.Web3: call :: (Method a, Provider p, ABIEncoding b) => Address -> CallMode -> a -> Web3 p b
- Network.Ethereum.Web3: event :: Event a => Address -> (a -> IO EventAction) -> Web3 ThreadId
+ Network.Ethereum.Web3: event :: (Event a, Provider p) => Address -> (a -> IO EventAction) -> Web3 p ThreadId
- Network.Ethereum.Web3: runWeb3 :: MonadIO m => Web3 a -> m (Either Error a)
+ Network.Ethereum.Web3: runWeb3 :: MonadIO m => Web3 DefaultProvider b -> m (Either Web3Error b)
- Network.Ethereum.Web3: runWeb3' :: MonadIO m => Config -> Web3 a -> m (Either Error a)
+ Network.Ethereum.Web3: runWeb3' :: (Provider a, MonadIO m) => Web3 a b -> m (Either Web3Error b)
- Network.Ethereum.Web3: sendTx :: (Method a, Unit b) => Address -> b -> a -> Web3 TxHash
+ Network.Ethereum.Web3: sendTx :: (Method a, Provider p, Unit b) => Address -> b -> a -> Web3 p TxHash
- Network.Ethereum.Web3.Api: eth_accounts :: Web3 [Address]
+ Network.Ethereum.Web3.Api: eth_accounts :: Provider a => Web3 a [Address]
- Network.Ethereum.Web3.Api: eth_call :: Call -> CallMode -> Web3 Text
+ Network.Ethereum.Web3.Api: eth_call :: Provider a => Call -> CallMode -> Web3 a Text
- Network.Ethereum.Web3.Api: eth_getBalance :: Address -> CallMode -> Web3 Text
+ Network.Ethereum.Web3.Api: eth_getBalance :: Provider a => Address -> CallMode -> Web3 a Text
- Network.Ethereum.Web3.Api: eth_getBlockByHash :: Text -> Web3 Block
+ Network.Ethereum.Web3.Api: eth_getBlockByHash :: Provider a => Text -> Web3 a Block
- Network.Ethereum.Web3.Api: eth_getBlockFilterChanges :: Text -> Web3 [Text]
+ Network.Ethereum.Web3.Api: eth_getBlockFilterChanges :: Provider a => Text -> Web3 a [Text]
- Network.Ethereum.Web3.Api: eth_getFilterChanges :: FilterId -> Web3 [Change]
+ Network.Ethereum.Web3.Api: eth_getFilterChanges :: Provider a => FilterId -> Web3 a [Change]
- Network.Ethereum.Web3.Api: eth_newBlockFilter :: Web3 Text
+ Network.Ethereum.Web3.Api: eth_newBlockFilter :: Provider a => Web3 a Text
- Network.Ethereum.Web3.Api: eth_newFilter :: Filter -> Web3 FilterId
+ Network.Ethereum.Web3.Api: eth_newFilter :: Provider a => Filter -> Web3 a FilterId
- Network.Ethereum.Web3.Api: eth_sendTransaction :: Call -> Web3 Text
+ Network.Ethereum.Web3.Api: eth_sendTransaction :: Provider a => Call -> Web3 a Text
- Network.Ethereum.Web3.Api: eth_uninstallFilter :: FilterId -> Web3 Bool
+ Network.Ethereum.Web3.Api: eth_uninstallFilter :: Provider a => FilterId -> Web3 a Bool
- Network.Ethereum.Web3.Api: web3_clientVersion :: Web3 Text
+ Network.Ethereum.Web3.Api: web3_clientVersion :: Provider a => Web3 a Text
- Network.Ethereum.Web3.Api: web3_sha3 :: Text -> Web3 Text
+ Network.Ethereum.Web3.Api: web3_sha3 :: Provider a => Text -> Web3 a Text
- Network.Ethereum.Web3.Contract: call :: (Method a, ABIEncoding b) => Address -> CallMode -> a -> Web3 b
+ Network.Ethereum.Web3.Contract: call :: (Method a, Provider p, ABIEncoding b) => Address -> CallMode -> a -> Web3 p b
- Network.Ethereum.Web3.Contract: event :: Event a => Address -> (a -> IO EventAction) -> Web3 ThreadId
+ Network.Ethereum.Web3.Contract: event :: (Event a, Provider p) => Address -> (a -> IO EventAction) -> Web3 p ThreadId
- Network.Ethereum.Web3.Contract: sendTx :: (Method a, Unit b) => Address -> b -> a -> Web3 TxHash
+ Network.Ethereum.Web3.Contract: sendTx :: (Method a, Provider p, Unit b) => Address -> b -> a -> Web3 p TxHash
- Network.Ethereum.Web3.Types: JsonRpcFail :: RpcError -> Error
+ Network.Ethereum.Web3.Types: JsonRpcFail :: RpcError -> Web3Error
- Network.Ethereum.Web3.Types: ParserFail :: String -> Error
+ Network.Ethereum.Web3.Types: ParserFail :: String -> Web3Error
- Network.Ethereum.Web3.Types: UserFail :: String -> Error
+ Network.Ethereum.Web3.Types: UserFail :: String -> Web3Error
- Network.Ethereum.Web3.Types: runWeb3 :: MonadIO m => Web3 a -> m (Either Error a)
+ Network.Ethereum.Web3.Types: runWeb3 :: MonadIO m => Web3 DefaultProvider b -> m (Either Web3Error b)
- Network.Ethereum.Web3.Types: runWeb3' :: MonadIO m => Config -> Web3 a -> m (Either Error a)
+ Network.Ethereum.Web3.Types: runWeb3' :: (Provider a, MonadIO m) => Web3 a b -> m (Either Web3Error b)

Files

README.md view
@@ -3,7 +3,7 @@ This is the Ethereum compatible Haskell API which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec.  [![Build Status](https://travis-ci.org/airalab/hs-web3.svg?branch=master)](https://travis-ci.org/airalab/hs-web3)-[![Build status](https://ci.appveyor.com/api/projects/status/ly40a39ojsxpv24w?svg=true)](https://ci.appveyor.com/project/akru/hs-web3)+[![Build status](https://ci.appveyor.com/api/projects/status/8ljq93nar8kobk75?svg=true)](https://ci.appveyor.com/project/akru/hs-web3) [![Hackage](https://img.shields.io/hackage/v/web3.svg)](http://hackage.haskell.org/package/web3) ![Hackage Dependencies](https://img.shields.io/hackage-deps/v/web3.svg) ![Haskell Programming Language](https://img.shields.io/badge/language-Haskell-blue.svg)@@ -24,13 +24,19 @@ Any Ethereum node communication wrapped with `Web3` monadic type.      > :t web3_clientVersion-    web3_clientVersion :: Web3 Text+    web3_clientVersion :: Provider a => Web3 a Text  To run this computation used `runWeb3'` or `runWeb3` functions.      > runWeb3 web3_clientVersion     Right "Parity//v1.4.5-beta-a028d04-20161126/x86_64-linux-gnu/rustc1.13.0" +Function `runWeb3` use default `Web3` provider at `localhost:8545`.++    > :t runWeb3+    runWeb3+      :: MonadIO m => Web3 DefaultProvider b -> m (Either Web3Error b)+ ### TemplateHaskell generator  [Quasiquotation](https://wiki.haskell.org/Quasiquotation) is used to parse@@ -50,14 +56,19 @@ See example of usage.  ```haskell-import Data.ByteArray (Bytes)-import Data.Text (Text)+import Data.Text (unpack)+import Text.Printf -[abiFrom|data/sample.json|]+[abiFrom|data/ERC20.json|]  main :: IO () main = do-    tx <- runWeb3 (runA2 addr nopay "Hello!" 42)-    print tx-  where addr = "0x19EE7966474b31225F71Ef8e36A71378a58a20E1"+    Right s <- runWeb3 $ do+        n <- name token+        s <- symbol token+        d <- decimals token+        return $ printf "Token %s with symbol %s and decimals %d"+                        (unpack n) (unpack s) d+    putStrLn s+  where token = "0x237D60A8b41aFD2a335305ed458B609D7667D789" ```
src/Network/Ethereum/Web3.hs view
@@ -17,11 +17,11 @@ -- Web3 Haskell library currently use JSON-RPC over HTTP to access node functionality. -- module Network.Ethereum.Web3 (-  -- ** Web3 monad & runners+  -- ** Web3 monad and service provider     Web3-  , Config(..)-  , Error(..)-  , runWeb3'+  , Provider(..)+  , DefaultProvider+  , Web3Error(..)   , runWeb3   -- ** Contract actions   , EventAction(..)
src/Network/Ethereum/Web3/Address.hs view
@@ -57,7 +57,9 @@  -- | Render 'Address' to text string toText :: Address -> Text-toText = toStrict . toLazyText . B.hexadecimal . unAddress+toText = wFix . toStrict . toLazyText . B.hexadecimal . unAddress+  where wFix x | T.length x < 40 = T.replicate (40 - T.length x) "0" <> x+               | otherwise       = x  -- | Null address zero :: Address
src/Network/Ethereum/Web3/Api.hs view
@@ -17,55 +17,55 @@ import Data.Text (Text)  -- | Returns current node version string.-web3_clientVersion :: Web3 Text+web3_clientVersion :: Provider a => Web3 a Text web3_clientVersion = remote "web3_clientVersion"  -- | Returns Keccak-256 (not the standardized SHA3-256) of the given data.-web3_sha3 :: Text -> Web3 Text+web3_sha3 :: Provider a => Text -> Web3 a Text web3_sha3 = remote "web3_sha3"  -- | Returns the balance of the account of given address.-eth_getBalance :: Address -> CallMode -> Web3 Text+eth_getBalance :: Provider a => Address -> CallMode -> Web3 a Text eth_getBalance = remote "eth_getBalance"  -- | Creates a filter object, based on filter options, to notify when the -- state changes (logs). To check if the state has changed, call -- 'getFilterChanges'.-eth_newFilter :: Filter -> Web3 FilterId+eth_newFilter :: Provider a => Filter -> Web3 a FilterId eth_newFilter = remote "eth_newFilter"  -- | Polling method for a filter, which returns an array of logs which -- occurred since last poll.-eth_getFilterChanges :: FilterId -> Web3 [Change]+eth_getFilterChanges :: Provider a => FilterId -> Web3 a [Change] eth_getFilterChanges = remote "eth_getFilterChanges"  -- | Uninstalls a filter with given id. -- Should always be called when watch is no longer needed.-eth_uninstallFilter :: FilterId -> Web3 Bool+eth_uninstallFilter :: Provider a => FilterId -> Web3 a Bool eth_uninstallFilter = remote "eth_uninstallFilter"  -- | Executes a new message call immediately without creating a -- transaction on the block chain.-eth_call :: Call -> CallMode -> Web3 Text+eth_call :: Provider a => Call -> CallMode -> Web3 a Text eth_call = remote "eth_call"  -- | Creates new message call transaction or a contract creation, -- if the data field contains code.-eth_sendTransaction :: Call -> Web3 Text+eth_sendTransaction :: Provider a => Call -> Web3 a Text eth_sendTransaction = remote "eth_sendTransaction"  -- | Returns a list of addresses owned by client.-eth_accounts :: Web3 [Address]+eth_accounts :: Provider a => Web3 a [Address] eth_accounts = remote "eth_accounts" -eth_newBlockFilter :: Web3 Text+eth_newBlockFilter :: Provider a => Web3 a Text eth_newBlockFilter = remote "eth_newBlockFilter"  -- | Polling method for a block filter, which returns an array of block hashes -- occurred since last poll.-eth_getBlockFilterChanges :: Text -> Web3 [Text]+eth_getBlockFilterChanges :: Provider a => Text -> Web3 a [Text] eth_getBlockFilterChanges = remote "eth_getFilterChanges"  -- | Returns information about a block by hash.-eth_getBlockByHash :: Text -> Web3 Block+eth_getBlockByHash :: Provider a => Text -> Web3 a Block eth_getBlockByHash = flip (remote "eth_getBlockByHash") True
src/Network/Ethereum/Web3/Contract.hs view
@@ -34,8 +34,7 @@  import qualified Data.Text.Lazy.Builder.Int as B import qualified Data.Text.Lazy.Builder     as B-import Control.Concurrent (ThreadId, threadDelay, forkIO)-import Control.Monad.Trans.Reader (ask)+import Control.Concurrent (ThreadId, threadDelay) import Control.Monad.IO.Class (liftIO) import Data.Text.Lazy (toStrict) import qualified Data.Text as T@@ -61,30 +60,33 @@     eventFilter :: a -> Address -> Filter      -- | Start an event listener for given contract 'Address' and callback-    event :: Address -> (a -> IO EventAction) -> Web3 ThreadId+    event :: Provider p+          => Address+          -- ^ Contract address+          -> (a -> IO EventAction)+          -- ^ 'Event' handler+          -> Web3 p ThreadId+          -- ^ 'Web3' wrapped event handler spawn ident     event = _event -_event :: Event a => Address -> (a -> IO EventAction) -> Web3 ThreadId+_event :: (Provider p, Event a)+       => Address+       -> (a -> IO EventAction)+       -> Web3 p ThreadId _event a f = do     fid <- let ftyp = snd $ let x = undefined :: Event a => a                             in  (f x, x)            in  eth_newFilter (eventFilter ftyp a) -    cfg <- ask-    liftIO $ forkIO $-        let loop = do threadDelay 1000000-                      res <- runWeb3' cfg (eth_getFilterChanges fid)-                      case res of-                          Left e -> print e-                          Right [] -> loop-                          Right changes -> do-                              acts <- mapM f $-                                  catMaybes $ fmap parseChange changes-                              if any (== TerminateEvent) acts-                              then return ()-                              else loop+    forkWeb3 $+        let loop = do liftIO (threadDelay 1000000)+                      changes <- fmap parseChange <$> eth_getFilterChanges fid+                      acts <- mapM (liftIO . f) (catMaybes changes)+                      if any (== TerminateEvent) acts+                      then return ()+                      else loop         in do loop-              runWeb3' cfg (eth_uninstallFilter fid)+              eth_uninstallFilter fid               return ()   where     prepareTopics = fmap (T.drop 2) . drop 1@@ -95,29 +97,45 @@ -- | Contract method caller class ABIEncoding a => Method a where     -- | Send a transaction for given contract 'Address', value and input data-    sendTx :: Unit b => Address -> b -> a -> Web3 TxHash+    sendTx :: (Provider p, Unit b)+           => Address+           -- ^ Contract address+           -> b+           -- ^ Payment value (set 'nopay' to empty value)+           -> a+           -- ^ Method data+           -> Web3 p TxHash+           -- ^ 'Web3' wrapped result     sendTx = _sendTransaction      -- | Constant call given contract 'Address' in mode and given input data-    call :: ABIEncoding b => Address -> CallMode -> a -> Web3 b+    call :: (Provider p, ABIEncoding b)+         => Address+         -- ^ Contract address+         -> CallMode+         -- ^ State mode for constant call (latest or pending)+         -> a+         -- ^ Method data+         -> Web3 p b+         -- ^ 'Web3' wrapped result     call = _call -_sendTransaction :: (Method a, Unit b)-                 => Address -> b -> a -> Web3 TxHash+_sendTransaction :: (Provider p, Method a, Unit b)+                 => Address -> b -> a -> Web3 p TxHash _sendTransaction to value dat = do     primeAddress <- head <$> eth_accounts     eth_sendTransaction (txdata primeAddress $ Just $ toData dat)   where txdata from = Call (Just from) to Nothing Nothing (Just $ toWeiText value)         toWeiText = ("0x" <>) . toStrict . B.toLazyText . B.hexadecimal . toWei --- TODO: Correct dynamic type parsing-_call :: (Method a, ABIEncoding b)-      => Address -> CallMode -> a -> Web3 b+_call :: (Provider p, Method a, ABIEncoding b)+      => Address -> CallMode -> a -> Web3 p b _call to mode dat = do     res <- eth_call txdata mode     case fromData (T.drop 2 res) of         Nothing -> fail $-            "Unable to parse result on `" ++ T.unpack res ++ "`"+            "Unable to parse result on `" ++ T.unpack res+            ++ "` from `" ++ show to ++ "`"         Just x -> return x   where     txdata = Call Nothing to Nothing Nothing Nothing (Just (toData dat))
src/Network/Ethereum/Web3/JsonRpc.hs view
@@ -12,20 +12,21 @@ -- Functions for implementing the client side of JSON-RPC 2.0. -- See <http://www.jsonrpc.org/specification>. ---module Network.Ethereum.Web3.JsonRpc (remote, MethodName) where+module Network.Ethereum.Web3.JsonRpc (+    remote+  , MethodName+  , ServerUri+  ) where  import Network.Ethereum.Web3.Types -import Network.HTTP.Client (httpLbs, newManager, defaultManagerSettings,-                            requestBody, responseBody, method,-                            requestHeaders, parseRequest,-                            RequestBody(RequestBodyLBS))-import Control.Monad.Error.Class (throwError)+import Network.HTTP.Client (httpLbs, newManager, requestBody,+                            responseBody, method, requestHeaders,+                            parseRequest, RequestBody(RequestBodyLBS))+import Network.HTTP.Client.TLS (tlsManagerSettings) import Data.ByteString.Lazy (ByteString)-import Control.Monad.Trans.Reader (ask)-import Control.Monad.IO.Class (liftIO) import Control.Applicative ((<|>))-import Control.Monad.Trans (lift)+import Control.Exception (throwIO) import Data.Vector (fromList) import Control.Monad ((>=>)) import Data.Text (Text)@@ -34,41 +35,41 @@ -- | Name of called method. type MethodName = Text +-- | JSON-RPC server URI+type ServerUri  = String+ -- | Remote call of JSON-RPC method. -- Arguments of function are stored into @params@ request array. remote :: Remote a => MethodName -> a-remote n = remote_ (call . Array . fromList)-  where connection body = do-            conf <- ask-            liftIO $ do-                manager <- newManager defaultManagerSettings-                request <- parseRequest (rpcUri conf)-                let request' = request-                             { requestBody = RequestBodyLBS body-                             , requestHeaders = [("Content-Type", "application/json")]-                             , method = "POST" }-                responseBody <$> httpLbs request' manager-        call = connection . encode . Request n 1--class Remote a where-    remote_ :: ([Value] -> Web3 ByteString) -> a--instance (ToJSON a, Remote b) => Remote (a -> b) where-    remote_ f x = remote_ (\xs -> f (toJSON x : xs))+remote n = remote_ (\uri -> call uri . Array . fromList)+  where+    call uri = connection uri . encode . Request n 1+    connection uri body = do+        manager <- newManager tlsManagerSettings+        request <- parseRequest uri+        let request' = request+                     { requestBody = RequestBodyLBS body+                     , requestHeaders = [("Content-Type", "application/json")]+                     , method = "POST" }+        responseBody <$> httpLbs request' manager -decodeResponse :: FromJSON a => ByteString -> Web3 a+decodeResponse :: FromJSON a => ByteString -> IO a decodeResponse = tryParse . eitherDecode              >=> tryJsonRpc . rsResult              >=> tryParse . eitherDecode . encode-  where tryJsonRpc :: Either RpcError a -> Web3 a-        tryJsonRpc (Right a) = return a-        tryJsonRpc (Left e)  = lift $ throwError (JsonRpcFail e)-        tryParse :: Either String a -> Web3 a-        tryParse   (Right a) = return a-        tryParse   (Left e)  = lift $ throwError (ParserFail e)+  where tryJsonRpc :: Either RpcError a -> IO a+        tryJsonRpc = either (throwIO . JsonRpcFail) return+        tryParse :: Either String a -> IO a+        tryParse = either (throwIO . ParserFail) return -instance FromJSON a => Remote (Web3 a) where-    remote_ f = decodeResponse =<< f []+class Remote a where+    remote_ :: (ServerUri -> [Value] -> IO ByteString) -> a++instance (ToJSON a, Remote b) => Remote (a -> b) where+    remote_ f x = remote_ (\u xs -> f u (toJSON x : xs))++instance (Provider p, FromJSON a) => Remote (Web3 p a) where+    remote_ f = (\u -> Web3 (decodeResponse =<< f u [])) =<< rpcUri  -- | JSON-RPC request. data Request = Request { rqMethod :: Text
src/Network/Ethereum/Web3/TH.hs view
@@ -193,7 +193,9 @@      sequence $ case c of         True ->-          [ sigD name $ arrowing $ [t|Address|] : inputT ++ [outputT]+          [ sigD name $ [t|Provider $p =>+                            $(arrowing $ [t|Address|] : inputT ++ [outputT])+                          |]           , funD' name (varP <$> a : vars) $               case result of                 Just [_] -> [|unSingleton <$> call $(varE a) Latest $(params)|]@@ -201,20 +203,21 @@           ]          False ->-          [ sigD name $ [t|Unit $(varT b) =>-                            $(arrowing $ [t|Address|] : varT b : inputT ++ [[t|Web3 TxHash|]])+          [ sigD name $ [t|(Provider $p, Unit $(varT b)) =>+                            $(arrowing $ [t|Address|] : varT b : inputT ++ [[t|Web3 $p TxHash|]])                           |]           , funD' name (varP <$> a : b : vars) $                 [|sendTx $(varE a) $(varE b) $(params)|] ]   where-    arrowing [x]  = x+    p = varT (mkName "p")+    arrowing [x] = x     arrowing (x : xs) = [t|$x -> $(arrowing xs)|]     inputT  = fmap (typeQ . funArgType) args     outputT = case result of-        Nothing  -> [t|Web3 ()|]-        Just [x] -> [t|Web3 $(typeQ $ funArgType x)|]+        Nothing  -> [t|Web3 $p ()|]+        Just [x] -> [t|Web3 $p $(typeQ $ funArgType x)|]         Just xs  -> let outs = fmap (typeQ . funArgType) xs-                    in  [t|Web3 $(foldl appT (tupleT (length xs)) outs)|]+                    in  [t|Web3 $p $(foldl appT (tupleT (length xs)) outs)|]  -- | Event declarations maker mkEvent :: Declaration -> Q [Dec]
src/Network/Ethereum/Web3/Types.hs view
@@ -1,4 +1,7 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE DefaultSignatures          #-}+{-# LANGUAGE TemplateHaskell            #-} -- | -- Module      :  Network.Ethereum.Web3.Types -- Copyright   :  Alexander Krupenkin 2016@@ -13,48 +16,59 @@ module Network.Ethereum.Web3.Types where  import Network.Ethereum.Web3.Internal (toLowerFirst)-import Control.Monad.Trans.Reader (ReaderT, runReaderT)-import Control.Monad.Trans.Except (ExceptT, runExceptT)-import Network.Ethereum.Web3.Address (Address)-import Control.Monad.IO.Class (MonadIO(..))-import Data.Default.Class (Default(..)) import qualified Data.Text.Lazy.Builder.Int as B import qualified Data.Text.Lazy.Builder     as B-import qualified Data.Text.Read as R-import Data.Default.Class (def)+import qualified Data.Text.Read             as R+import Network.Ethereum.Web3.Address (Address)+import Control.Monad.IO.Class (MonadIO(..))+import Control.Concurrent (forkIO, ThreadId)+import Control.Exception (Exception, try)+import Data.Typeable (Typeable) import Data.Monoid ((<>)) import Data.Text (Text) import Data.Aeson.TH import Data.Aeson  -- | Any communication with Ethereum node wrapped with 'Web3' monad-type Web3 = ReaderT Config (ExceptT Error IO)+newtype Web3 a b = Web3 { unWeb3 :: IO b }+  deriving (Functor, Applicative, Monad, MonadIO) --- | Ethereum node params-data Config = Config-  { rpcUri :: String-  -- ^ JSON-RPC node URI-  } deriving (Show, Eq)+-- | Ethereum node service provider+class Provider a where+    -- | JSON-RPC provider URI, default: localhost:8545+    rpcUri :: Web3 a String -instance Default Config where-    def = Config "http://localhost:8545"+    -- | 'Web3' monad runner+    runWeb3' :: MonadIO m => Web3 a b -> m (Either Web3Error b)+    {-# INLINE runWeb3' #-}+    runWeb3' = liftIO . try . unWeb3 --- | Some peace of error response-data Error = JsonRpcFail RpcError-           -- ^ JSON-RPC communication error-           | ParserFail  String-           -- ^ Error in parser state-           | UserFail    String-           -- ^ Common head for user errors-  deriving (Show, Eq)+    -- | Fork 'Web3' with the same 'Provider'+    forkWeb3 :: Web3 a () -> Web3 a ThreadId+    {-# INLINE forkWeb3 #-}+    forkWeb3 = Web3 . forkIO . unWeb3 --- | Run 'Web3' monad with default config-runWeb3 :: MonadIO m => Web3 a -> m (Either Error a)-runWeb3 = runWeb3' def+-- | Default 'Web3' service provider+data DefaultProvider+instance Provider DefaultProvider where+    rpcUri = return "http://localhost:8545" --- | Run 'Web3' monad with given configuration-runWeb3' :: MonadIO m => Config -> Web3 a -> m (Either Error a)-runWeb3' c = liftIO . runExceptT . flip runReaderT c+-- | 'Web3' runner for default provider+runWeb3 :: MonadIO m => Web3 DefaultProvider b -> m (Either Web3Error b)+{-# INLINE runWeb3 #-}+runWeb3 = runWeb3'++-- | Some peace of error response+data Web3Error+  = JsonRpcFail RpcError+  -- ^ JSON-RPC communication error+  | ParserFail  String+  -- ^ Error in parser state+  | UserFail    String+  -- ^ Common head for user errors+  deriving (Typeable, Show, Eq)++instance Exception Web3Error  -- | JSON-RPC error message data RpcError = RpcError
web3.cabal view
@@ -1,65 +1,70 @@-name:                web3-version:             0.4.1.0-synopsis:            Ethereum API for Haskell-description:         Web3 is a Haskell client library for Ethereum-homepage:            https://github.com/airalab/hs-web3#readme-license:             BSD3-license-file:        LICENSE-author:              Alexander Krupenkin-maintainer:          mail@akru.me-copyright:           Alexander Krupenkin-category:            Network-build-type:          Simple-cabal-version:       >=1.10-+name: web3+version: 0.5.0.0+cabal-version: >=1.10+build-type: Simple+license: BSD3+license-file: LICENSE+copyright: Alexander Krupenkin+maintainer: mail@akru.me+homepage: https://github.com/airalab/hs-web3#readme+synopsis: Ethereum API for Haskell+description:+    Web3 is a Haskell client library for Ethereum+category: Network+author: Alexander Krupenkin extra-source-files:-  README.md-  data/ERC20.json+    README.md+    data/ERC20.json  source-repository head-  type:     git-  location: https://github.com/airalab/hs-web3+    type: git+    location: https://github.com/airalab/hs-web3  library-  hs-source-dirs:      src-  exposed-modules:     Network.Ethereum.Web3-                     , Network.Ethereum.Unit-                     , Network.Ethereum.Web3.TH-                     , Network.Ethereum.Web3.Api-                     , Network.Ethereum.Web3.Types-                     , Network.Ethereum.Web3.Address-                     , Network.Ethereum.Web3.JsonAbi-                     , Network.Ethereum.Web3.Encoding-                     , Network.Ethereum.Web3.Contract-                     , Network.Ethereum.Web3.Encoding.Bytes-                     , Network.Ethereum.Web3.Encoding.Tuple-  other-modules:       Network.Ethereum.Web3.JsonRpc-                     , Network.Ethereum.Web3.Internal-                     , Network.Ethereum.Web3.Encoding.TupleTH-                     , Network.Ethereum.Web3.Encoding.Internal-  build-depends:       base >4.8 && <4.11-                     , data-default-class-                     , base16-bytestring-                     , template-haskell-                     , transformers-                     , http-client-                     , attoparsec-                     , bytestring-                     , cryptonite-                     , vector-                     , memory-                     , aeson-                     , text-                     , mtl-  default-extensions:  OverloadedStrings-  default-language:    Haskell2010+    exposed-modules:+        Network.Ethereum.Web3+        Network.Ethereum.Unit+        Network.Ethereum.Web3.TH+        Network.Ethereum.Web3.Api+        Network.Ethereum.Web3.Types+        Network.Ethereum.Web3.Address+        Network.Ethereum.Web3.JsonAbi+        Network.Ethereum.Web3.Encoding+        Network.Ethereum.Web3.Contract+        Network.Ethereum.Web3.Encoding.Bytes+        Network.Ethereum.Web3.Encoding.Tuple+    build-depends:+        base >4.8 && <4.11,+        base16-bytestring >=0.1.1.6 && <0.2,+        template-haskell >=2.11.0.0 && <2.12,+        http-client-tls >=0.2.4.1 && <0.3,+        transformers >=0.5.2.0 && <0.6,+        http-client >=0.4.31.2 && <0.5,+        attoparsec >=0.13.1.0 && <0.14,+        bytestring >=0.10.8.1 && <0.11,+        cryptonite ==0.19.*,+        vector >=0.11.0.0 && <0.12,+        memory ==0.13.*,+        aeson >=0.11.2.1 && <0.12,+        text >=1.2.2.1 && <1.3+    default-language: Haskell2010+    default-extensions: OverloadedStrings+    hs-source-dirs: src+    other-modules:+        Network.Ethereum.Web3.JsonRpc+        Network.Ethereum.Web3.Internal+        Network.Ethereum.Web3.Encoding.TupleTH+        Network.Ethereum.Web3.Encoding.Internal  test-suite web3-test-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             Spec.hs-  build-depends:       base, memory, text, web3-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N-  --ghc-options:         -ddump-splices -threaded -rtsopts -with-rtsopts=-N-  default-extensions:  OverloadedStrings-  default-language:    Haskell2010+    type: exitcode-stdio-1.0+    main-is: Spec.hs+    build-depends:+        base >=4.9.0.0 && <4.10,+        memory ==0.13.*,+        text >=1.2.2.1 && <1.3,+        web3 >=0.5.0.0 && <0.6+    default-language: Haskell2010+    default-extensions: OverloadedStrings+    hs-source-dirs: test+    ghc-options: -threaded -rtsopts -with-rtsopts=-N