diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -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"
 ```
diff --git a/src/Network/Ethereum/Web3.hs b/src/Network/Ethereum/Web3.hs
--- a/src/Network/Ethereum/Web3.hs
+++ b/src/Network/Ethereum/Web3.hs
@@ -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(..)
diff --git a/src/Network/Ethereum/Web3/Address.hs b/src/Network/Ethereum/Web3/Address.hs
--- a/src/Network/Ethereum/Web3/Address.hs
+++ b/src/Network/Ethereum/Web3/Address.hs
@@ -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
diff --git a/src/Network/Ethereum/Web3/Api.hs b/src/Network/Ethereum/Web3/Api.hs
--- a/src/Network/Ethereum/Web3/Api.hs
+++ b/src/Network/Ethereum/Web3/Api.hs
@@ -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
diff --git a/src/Network/Ethereum/Web3/Contract.hs b/src/Network/Ethereum/Web3/Contract.hs
--- a/src/Network/Ethereum/Web3/Contract.hs
+++ b/src/Network/Ethereum/Web3/Contract.hs
@@ -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))
diff --git a/src/Network/Ethereum/Web3/JsonRpc.hs b/src/Network/Ethereum/Web3/JsonRpc.hs
--- a/src/Network/Ethereum/Web3/JsonRpc.hs
+++ b/src/Network/Ethereum/Web3/JsonRpc.hs
@@ -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
diff --git a/src/Network/Ethereum/Web3/TH.hs b/src/Network/Ethereum/Web3/TH.hs
--- a/src/Network/Ethereum/Web3/TH.hs
+++ b/src/Network/Ethereum/Web3/TH.hs
@@ -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]
diff --git a/src/Network/Ethereum/Web3/Types.hs b/src/Network/Ethereum/Web3/Types.hs
--- a/src/Network/Ethereum/Web3/Types.hs
+++ b/src/Network/Ethereum/Web3/Types.hs
@@ -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
diff --git a/web3.cabal b/web3.cabal
--- a/web3.cabal
+++ b/web3.cabal
@@ -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
