{-# LANGUAGE DeriveGeneric #-} -- | -- Module : Network.Ethereum.Web3.Address -- Copyright : Alexander Krupenkin 2016 -- License : BSD3 -- -- Maintainer : mail@akru.me -- Stability : experimental -- Portability : unknown -- -- Ethereum address type, render and parser. -- module Network.Ethereum.Web3.Address ( Address , fromText , toText , zero ) where import Control.Monad ((<=<)) import Data.Aeson (FromJSON (..), ToJSON (..), Value (..)) import qualified Data.Char as C import Data.Monoid ((<>)) import Data.String (IsString (..)) import Data.Text (Text, pack, unpack) import qualified Data.Text as T import Data.Text.Lazy (toStrict) import Data.Text.Lazy.Builder (toLazyText) import Data.Text.Lazy.Builder.Int as B (hexadecimal) import Data.Text.Read as R (hexadecimal) import GHC.Generics (Generic) -- | Ethereum account address newtype Address = Address { unAddress :: Integer } deriving (Eq, Ord, Generic) instance Show Address where show = unpack . toText instance IsString Address where fromString a = case fromText (pack a) of Right address -> address Left e -> error e instance FromJSON Address where parseJSON (String a) = either fail return (fromText a) parseJSON _ = fail "Address should be a string" instance ToJSON Address where toJSON = toJSON . ("0x" <>) . toText -- | Parse 'Address' from text string fromText :: Text -> Either String Address fromText = fmap (Address . fst) . R.hexadecimal <=< check where check t | T.take 2 t == "0x" = check (T.drop 2 t) | otherwise = do if T.length t == 40 then pure () else lengthError if T.all C.isHexDigit t then pure () else invalidCharError pure t lengthError = Left "Invalid Address: text length not equal to 20" invalidCharError = Left "Invalid Address: contains non-hex character" -- | Render 'Address' to text string toText :: Address -> Text 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 zero = Address 0