diff --git a/ethereum-analyzer-cli.cabal b/ethereum-analyzer-cli.cabal
--- a/ethereum-analyzer-cli.cabal
+++ b/ethereum-analyzer-cli.cabal
@@ -1,5 +1,5 @@
 name:                ethereum-analyzer-cli
-version:             1.2.0
+version:             1.3.0
 synopsis:            A CLI frontend for ethereum-analyzer.
 homepage:            https://github.com/ethereumK/ethereum-analyzer
 license:             Apache-2.0
@@ -21,7 +21,7 @@
 source-repository this
   type:     git
   location: https://github.com/zchn/ethereum-analyzer
-  tag:      v1.2.0
+  tag:      v1.3.0
   subdir:   ethereum-analyzer-cli
 
 library
@@ -29,16 +29,24 @@
                      , aeson
                      , bytestring
                      , conduit-combinators
+                     , directory
+                     , ethereum-analyzer
                      , ethereum-analyzer-deps
                      , exceptions
                      , hexstring
                      , http-conduit
                      , json-rpc
+                     , monad-logger
+                     , mtl
+                     , protolude
                      , text
+                     , tostring
                      , unordered-containers
                      , vector
                        
-  exposed-modules:     Ethereum.Jsonrpc.Client
+  exposed-modules:     Ethereum.Executable.BytecodeVisMain
+                       Ethereum.Executable.DumpCodeMain
+  other-modules:       Ethereum.Jsonrpc.Client                       
   ghc-options:         -Wall
   hs-source-dirs:      src
   buildable:           True
@@ -48,14 +56,23 @@
 executable ea-dump-contract
   main-is:             DumpCodeMain.hs
   build-depends:       base >= 4 && < 5
-                     , directory
-                     , ethereum-analyzer
                      , ethereum-analyzer-cli
                      , ethereum-analyzer-deps
                      , hflags
                      , monad-logger
-                     , mtl
-                     , text
+                     , protolude
+  ghc-options:         -Wall
+  hs-source-dirs:      exec_src
+  buildable:           True
+  default-language:    Haskell98
+
+executable ea-bytecode-vis
+  main-is:             BytecodeVisMain.hs
+  build-depends:       base >= 4 && < 5
+                     , ethereum-analyzer-cli
+                     , hflags
+                     , monad-logger
+                     , protolude
   ghc-options:         -Wall
   hs-source-dirs:      exec_src
   buildable:           True
diff --git a/exec_src/BytecodeVisMain.hs b/exec_src/BytecodeVisMain.hs
new file mode 100644
--- /dev/null
+++ b/exec_src/BytecodeVisMain.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE OverloadedStrings, TemplateHaskell, FlexibleContexts
+  #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- | Dump all contracts.
+module Main
+  ( main
+  ) where
+
+import Control.Monad.Logger
+import Ethereum.Executable.BytecodeVisMain (bytecodeVisMain)
+import HFlags
+import Protolude
+
+defineFlag
+  "bytecode"
+  ("" :: Text)
+  "The bytecode. Will read from STDIN if empty."
+
+defineFlag
+  "outDot"
+  ("" :: Text)
+  "The dot file path. Will print to STDOUT if empty"
+
+defineFlag
+  "dummy"
+  False
+  "dummy flag for https://github.com/nilcons/hflags/issues/14"
+
+main :: IO ()
+main = do
+  s <- $initHFlags "ea-bytecode-vis"
+  putText $ "Flags: " <> show s
+  runStdoutLoggingT (bytecodeVisMain flags_bytecode flags_outDot)
diff --git a/exec_src/DumpCodeMain.hs b/exec_src/DumpCodeMain.hs
--- a/exec_src/DumpCodeMain.hs
+++ b/exec_src/DumpCodeMain.hs
@@ -6,15 +6,10 @@
   ( main
   ) where
 
-import Ethereum.Jsonrpc.Client
 import Blockchain.Output
+import Ethereum.Executable.DumpCodeMain
 import Control.Monad.Logger
-import Control.Monad.Trans
-import Data.Maybe
-import Data.Text as T hiding (map)
 import HFlags
-import Numeric
-import System.Directory as SD
 
 defineFlag
   "jrpcServer"
@@ -25,48 +20,16 @@
 
 defineFlag "contractDir" ("contracts" :: String) "Directory for contact files."
 
--- https://github.com/nilcons/hflags/issues/14
-return []
+defineFlag
+  "dummy"
+  False
+  "dummy flag for https://github.com/nilcons/hflags/issues/14"
 
 main :: IO ()
 main = do
   s <- $initHFlags "ea-dump-contract"
   putStrLn $ "Flags: " ++ show s
-  flip runLoggingT printLogMsg (dumpContracts flags_jrpcServer flags_jrpcPort)
-
-dumpContracts :: String -> Int -> LoggingT IO ()
-dumpContracts server port = do
-  $logInfo "Dumping eth contracts."
-  ver <- web3ClientVersion server port
-  $logInfo $ T.append "version is " ver
-  latest_bNum <- ethBlockNumber server port
-  let parsed_bns = readHex $ Prelude.drop 2 $ T.unpack latest_bNum
-  $logInfo $ T.pack $ "parsing block number: " ++ show parsed_bns
-  let latest_bn = fst $ Prelude.head $ parsed_bns
-  $logInfo $ T.pack $ "block number is " ++ show latest_bn
-  enumerateContractAt server port latest_bn
-  return ()
-
-enumerateContractAt :: String -> Int -> Int -> LoggingT IO ()
-enumerateContractAt _ _ 0 = return ()
-enumerateContractAt s p bn = do
-  $logInfo $ T.pack $ "processing block " ++ show bn
-  transactions <- ethGetTransactionsByBlockNumber s p (T.pack $ show bn)
-  -- $logInfo $ T.pack $ "transactions: " ++ show transactions
-  addresses <- catMaybes <$> mapM (ethGetContractAddrByTxHash s p) transactions
-  -- $logInfo $ T.pack $ "addresses: " ++ show addresses
-  mapM_
-    (\addr -> do
-       let fpath = flags_contractDir ++ "/" ++ T.unpack addr ++ ".contract"
-       fileExists <- lift $ doesFileExist fpath
-       if fileExists
-         then $logInfo $ T.pack $ "skipping: " ++ show addr
-         else do
-           textCode <- ethGetCode s p addr
-           lift $ writeFile fpath $ T.unpack $ T.drop 2 textCode
-     -- $logInfo $ T.append "textCode is " textCode
-     )
-    addresses
-  -- code <- getCode server port "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe"
-  -- $logInfo $ T.pack $ "decompiled code is " ++ formatCode code
-  enumerateContractAt s p (bn - 1)
+  flip
+    runLoggingT
+    printLogMsg
+    (dumpContracts flags_jrpcServer flags_jrpcPort flags_contractDir)
diff --git a/src/Ethereum/Executable/BytecodeVisMain.hs b/src/Ethereum/Executable/BytecodeVisMain.hs
new file mode 100644
--- /dev/null
+++ b/src/Ethereum/Executable/BytecodeVisMain.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Ethereum.Executable.BytecodeVisMain
+  ( bytecodeVisMain
+  ) where
+
+import Control.Monad.Logger
+import Data.String.ToString
+import Data.Text (null)
+import Ethereum.Analyzer.Disasm
+import Ethereum.Analyzer.Util
+import Protolude hiding (null)
+
+bytecodeVisMain :: Text -> Text -> LoggingT IO ()
+bytecodeVisMain hexstring dotFilepath = do
+  hs <-
+    if null hexstring
+      then lift getLine
+      else return hexstring
+  let (ctorDot, dispDot) = disasmToDotText2 $ EvmHexString hs
+  if null dotFilepath
+    then putText dispDot
+    else do
+      lift $ writeFile (toString dotFilepath) dispDot
+      lift $ writeFile (toString $ dotFilepath <> "ctor.dot") ctorDot
diff --git a/src/Ethereum/Executable/DumpCodeMain.hs b/src/Ethereum/Executable/DumpCodeMain.hs
new file mode 100644
--- /dev/null
+++ b/src/Ethereum/Executable/DumpCodeMain.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE OverloadedStrings, TemplateHaskell, FlexibleContexts
+  #-}
+
+-- | Dump all contracts.
+module Ethereum.Executable.DumpCodeMain
+  ( dumpContracts
+  ) where
+
+import Ethereum.Jsonrpc.Client
+import Control.Monad.Logger
+import Control.Monad.Trans
+import Data.Maybe
+import Data.Text as T hiding (map)
+import Numeric
+import System.Directory as SD
+
+dumpContracts :: String -> Int -> String -> LoggingT IO ()
+dumpContracts server port contractDir = do
+  $logInfo "Dumping eth contracts."
+  ver <- web3ClientVersion server port
+  $logInfo $ T.append "version is " ver
+  latest_bNum <- ethBlockNumber server port
+  let parsed_bns = readHex $ Prelude.drop 2 $ T.unpack latest_bNum
+  $logInfo $ T.pack $ "parsing block number: " ++ show parsed_bns
+  let latest_bn = fst $ Prelude.head $ parsed_bns
+  $logInfo $ T.pack $ "block number is " ++ show latest_bn
+  enumerateContractAt server port contractDir latest_bn
+  return ()
+
+enumerateContractAt :: String -> Int -> String -> Int -> LoggingT IO ()
+enumerateContractAt _ _ _ 0 = return ()
+enumerateContractAt s p contractDir bn = do
+  $logInfo $ T.pack $ "processing block " ++ show bn
+  transactions <- ethGetTransactionsByBlockNumber s p (T.pack $ show bn)
+  -- $logInfo $ T.pack $ "transactions: " ++ show transactions
+  addresses <- catMaybes <$> mapM (ethGetContractAddrByTxHash s p) transactions
+  -- $logInfo $ T.pack $ "addresses: " ++ show addresses
+  mapM_
+    (\addr -> do
+       let fpath = contractDir ++ "/" ++ T.unpack addr ++ ".contract"
+       fileExists <- lift $ doesFileExist fpath
+       if fileExists
+         then $logInfo $ T.pack $ "skipping: " ++ show addr
+         else do
+           textCode <- ethGetCode s p addr
+           lift $ writeFile fpath $ T.unpack $ T.drop 2 textCode
+     -- $logInfo $ T.append "textCode is " textCode
+     )
+    addresses
+  -- code <- getCode server port "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe"
+  -- $logInfo $ T.pack $ "disasmd code is " ++ formatCode code
+  enumerateContractAt s p contractDir (bn - 1)
