packages feed

web3-0.7.0.0: test/Network/Ethereum/Web3/Test/Utils.hs

{-# LANGUAGE LambdaCase #-}
module Network.Ethereum.Web3.Test.Utils
  ( injectExportedEnvironmentVariables
  , runWeb3Configured
  , runWeb3Configured'
  , withAccounts
  , withPrimaryEthereumAccount
  , callFromTo
  , sleepSeconds
  , microtime
  , awaitBlock
  ) where

import           Control.Concurrent                (MVar, threadDelay,
                                                    tryTakeMVar)
import           Control.Monad.IO.Class            (liftIO)
import           Data.Default
import           Data.Either                       (isRight)
import           Data.List.Split                   (splitOn)
import           Data.Maybe                        (fromMaybe)
import           Data.Ratio                        (numerator)
import           Data.String                       (IsString, fromString)
import qualified Data.Text                         as T
import           Data.Time.Clock.POSIX             (getPOSIXTime)
import           Data.Traversable                  (for)

import           Network.Ethereum.ABI.Prim.Address (Address)
import           Network.Ethereum.Web3.Eth         (accounts, blockNumber)
import           Network.Ethereum.Web3.Provider    (Provider (..), Web3,
                                                    Web3Error, runWeb3')
import           Network.Ethereum.Web3.Types       (BlockNumber, Call (..))
import           System.Environment                (lookupEnv, setEnv)
import           Test.Hspec.Expectations           (shouldSatisfy)

rpcUri :: IO String
rpcUri =  liftIO (fromMaybe "http://localhost:8545" <$> lookupEnv "WEB3_PROVIDER")

exportStore :: String
exportStore = "./test-support/.detected-contract-addresses"

loadExportedEnvironmentVariables :: IO [(String, String)]
loadExportedEnvironmentVariables = do
    exportables <- lines <$> readFile exportStore
    detecteds <- for exportables $ \line -> case words line of
        ["export", e] -> case splitOn "=" e of
            [x]    -> detectedEnv x ""
            [k, v] -> detectedEnv k v
            _      -> warnMalformation $ "oddly structured export statement " ++ line
        _ -> warnMalformation $ "no export in line " ++ line
    return $ concat detecteds

    where warnMalformation m = do
            putStrLn $ m ++ ". are you sure you're using the right inject-contract-addresses.sh?"
            pure []
          detectedEnv k v = do
              -- putStrLn $ "detected " ++ k ++ "=" ++ v
              pure [(k, v)]

injectExportedEnvironmentVariables :: IO ()
injectExportedEnvironmentVariables = do
    detectedEnvs <- loadExportedEnvironmentVariables
    sequence_ (uncurry setEnv <$> detectedEnvs)

runWeb3Configured :: Show a => Web3 a -> IO a
runWeb3Configured f = do
    provider <- HttpProvider <$> rpcUri
    v <- runWeb3' provider f
    v `shouldSatisfy` isRight
    let Right a = v in return a

runWeb3Configured' :: Web3 a -> IO a
runWeb3Configured' f = do
    provider <- HttpProvider <$> rpcUri
    Right v <- runWeb3' provider f
    return v

withAccounts :: ([Address] -> IO a) -> IO a
withAccounts f = runWeb3Configured accounts >>= f

withPrimaryEthereumAccount :: IO Address
withPrimaryEthereumAccount = withAccounts (pure . head)

callFromTo :: Address -> Address -> Call
callFromTo from to =
    def { callFrom = Just from
        , callTo   = Just to
        , callGasPrice = Just 4000000000
        }

sleepSeconds :: Int -> IO ()
sleepSeconds = threadDelay . (* 1000000)

microtime :: IO Integer
microtime = numerator . toRational . (* 1000000) <$> getPOSIXTime

awaitBlock :: BlockNumber -> IO ()
awaitBlock bn = do
    bn' <- runWeb3Configured blockNumber
    putStrLn $ "awaiting block " ++ show bn ++ ", currently " ++ show bn'
    if bn' >= bn
        then return ()
        else threadDelay 1000000 >> awaitBlock bn