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)
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
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"
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
zero :: Address
zero = Address 0