-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

-- | Address in Tezos.

{-# LANGUAGE DeriveLift #-}

module Morley.Tezos.Address
  ( ContractHash
  , KindedAddress (..)
  , TxRollupL2Address (..)
  , mkKeyAddress
  , detGenKeyAddress
  , isImplicitAddress
  , ImplicitAddress
  , ContractAddress
  , TxRollupAddress
  , L1Address
  , L1AddressKind
  , ConstrainAddressKind
  , Address
  , ConstrainedAddress(.., MkAddress)

  , GlobalCounter(..)
  , mkContractHashHack

  -- * Formatting
  , ParseAddressError (..)
  , ParseAddressRawError (..)
  , formatAddress
  , mformatAddress
  , parseAddressRaw
  , parseKindedAddress
  , parseAddress
  , ta

  -- * Utilities
  , addressKindSanity
  , usingImplicitOrContractKind
  ) where

import Control.Monad.Except (mapExceptT, throwError)
import Data.Aeson (FromJSON(..), FromJSONKey, ToJSON(..), ToJSONKey)
import Data.Aeson qualified as Aeson
import Data.Aeson.Encoding qualified as Aeson
import Data.Aeson.Types qualified as AesonTypes
import Data.Binary.Get qualified as Get
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as LBS
import Data.Constraint (Dict(..), (\\))
import Data.Singletons (SingI(..))
import Data.Text (strip)
import Data.Type.Equality ((:~:)(..))
import Fmt (Buildable(build), hexF, pretty)
import Instances.TH.Lift ()
import Language.Haskell.TH.Quote qualified as TH
import Language.Haskell.TH.Syntax (Lift)
import Language.Haskell.TH.Syntax qualified as TH
import Text.PrettyPrint.Leijen.Text (backslash, dquotes, int, (<+>))

import Morley.Michelson.Printer.Util (RenderDoc(..), buildRenderDoc, renderAnyBuildable)
import Morley.Michelson.Text
import Morley.Tezos.Address.Kinds
import Morley.Tezos.Crypto
import Morley.Util.Binary
import Morley.Util.CLI
import Morley.Util.Sing
import Morley.Util.TypeLits

-- | A "kinded" address. This type carries 'AddressKind' on the type-level.
-- Useful in the internal API, not as much when we have to interact with the
-- network. See 'Address' for a type that is isomorphic to a Michelson
-- @address@.
data KindedAddress (kind :: AddressKind) where
  -- | @tz1@, @tz2@ or @tz3@ address which is a hash of a public key.
  ImplicitAddress :: KeyHash -> KindedAddress 'AddressKindImplicit
  -- | @KT1@ address which corresponds to a callable contract.
  ContractAddress :: ContractHash -> KindedAddress 'AddressKindContract
  -- | @txr1@ address which corresponds to a transaction rollup.
  TxRollupAddress :: TxRollupHash -> KindedAddress 'AddressKindTxRollup

deriving stock instance Show (KindedAddress kind)
deriving stock instance Eq (KindedAddress kind)
deriving stock instance Ord (KindedAddress kind)
deriving stock instance Lift (KindedAddress kind)

instance NFData (KindedAddress kind) where
  rnf :: KindedAddress kind -> ()
rnf = \case
    ImplicitAddress KeyHash
x -> KeyHash -> ()
forall a. NFData a => a -> ()
rnf KeyHash
x
    ContractAddress ContractHash
x -> ContractHash -> ()
forall a. NFData a => a -> ()
rnf ContractHash
x
    TxRollupAddress TxRollupHash
x -> TxRollupHash -> ()
forall a. NFData a => a -> ()
rnf TxRollupHash
x

-- | A type only allowing v'ImplicitAddress'
type ImplicitAddress = KindedAddress 'AddressKindImplicit

-- | A type only allowing v'ContractAddress'
type ContractAddress = KindedAddress 'AddressKindContract

-- | A type only allowing v'TxRollupAddress'
type TxRollupAddress = KindedAddress 'AddressKindTxRollup

-- | Data type corresponding to @address@ structure in Tezos.
type Address =
  ConstrainedAddress '[ 'AddressKindImplicit, 'AddressKindContract, 'AddressKindTxRollup ]

type family ConstrainAddressKindHelper (ks :: [AddressKind]) kind where
  ConstrainAddressKindHelper (x ': _) x = 'True
  ConstrainAddressKindHelper (_ ': xs) x = ConstrainAddressKindHelper xs x
  ConstrainAddressKindHelper '[] _ = 'False

type family CheckConstrainAddressKindError k b :: Constraint where
  CheckConstrainAddressKindError _ 'True = ()
  CheckConstrainAddressKindError k 'False =
    TypeError ('ShowType k ':<>: 'Text "is forbidden in this context")

-- | Constrain address kind to be one of the kinds in the list.
type ConstrainAddressKind ks k =
  ( CheckConstrainAddressKindError k (ConstrainAddressKindHelper ks k)
  , ConstrainAddressKindHelper ks k ~ 'True)

-- | An existential of 'KindedAddress' constrained by its type argument.
data ConstrainedAddress (ks :: [AddressKind]) =
  forall kind. ConstrainAddressKind ks kind => MkConstrainedAddress (KindedAddress kind)

-- | A convenience synonym for 'ConstrainedAddress' allowing only implicit and
-- contract addresses.
--
-- 'L1Address' is named as such because in addition to implicit and contract
-- addresses, Michelson's @address@ type can contain @txr1@ addresses,
-- identifying transaction rollups. While @txr1@ are technically also level-1
-- (level-2 being @tx_rollup_l2_address@, i.e. @tz4@), in practice it's a
-- level-1 identifier for a bundle of level-2 operations. Hence, to keep type
-- names concise, we use 'L1Address'.
type L1Address =
  ConstrainedAddress '[ 'AddressKindImplicit, 'AddressKindContract ]

-- | Convenience synonym for 'ConstrainAddressKind' allowing only implicit and
-- contract addresses.
--
-- For a note on the naming convention, refer to 'L1Address'.
type L1AddressKind kind =
  ConstrainAddressKind '[ 'AddressKindImplicit, 'AddressKindContract ] kind

-- | A trick to avoid bogus redundant constraint warnings
usingImplicitOrContractKind :: forall kind a. L1AddressKind kind => a -> a
usingImplicitOrContractKind :: forall (kind :: AddressKind) a. L1AddressKind kind => a -> a
usingImplicitOrContractKind = a -> a
forall a. a -> a
id
  where Dict (L1AddressKind kind)
_ = Dict (L1AddressKind kind)
forall (a :: Constraint). a => Dict a
Dict :: Dict (L1AddressKind kind)

-- | 'MkConstrainedAddress' specialized to 'Address'
pattern MkAddress :: KindedAddress kind -> Address
pattern $bMkAddress :: forall (kind :: AddressKind). KindedAddress kind -> Address
$mMkAddress :: forall {r}.
Address
-> (forall {kind :: AddressKind}. KindedAddress kind -> r)
-> (Void# -> r)
-> r
MkAddress x <- MkConstrainedAddress x
  where MkAddress KindedAddress kind
x = case KindedAddress kind
x of
          ImplicitAddress{} -> KindedAddress kind -> Address
forall (ks :: [AddressKind]) (kind :: AddressKind).
ConstrainAddressKind ks kind =>
KindedAddress kind -> ConstrainedAddress ks
MkConstrainedAddress KindedAddress kind
x
          ContractAddress{} -> KindedAddress kind -> Address
forall (ks :: [AddressKind]) (kind :: AddressKind).
ConstrainAddressKind ks kind =>
KindedAddress kind -> ConstrainedAddress ks
MkConstrainedAddress KindedAddress kind
x
          TxRollupAddress{} -> KindedAddress kind -> Address
forall (ks :: [AddressKind]) (kind :: AddressKind).
ConstrainAddressKind ks kind =>
KindedAddress kind -> ConstrainedAddress ks
MkConstrainedAddress KindedAddress kind
x

{-# COMPLETE MkAddress #-}

deriving stock instance Show (ConstrainedAddress c)
instance Eq (ConstrainedAddress c) where
  MkConstrainedAddress (KindedAddress kind
addr1 :: KindedAddress kind1)
    == :: ConstrainedAddress c -> ConstrainedAddress c -> Bool
== MkConstrainedAddress (KindedAddress kind
addr2 :: KindedAddress kind2) =
    case forall {k} (a :: k) (b :: k).
(SingI a, SingI b, TestEquality Sing) =>
Maybe (a :~: b)
forall (a :: AddressKind) (b :: AddressKind).
(SingI a, SingI b, TestEquality Sing) =>
Maybe (a :~: b)
eqI @kind1 @kind2 (SingI kind => Maybe (kind :~: kind))
-> Dict (SingI kind) -> Maybe (kind :~: kind)
forall (c :: Constraint) e r. HasDict c e => (c => r) -> e -> r
\\ KindedAddress kind -> Dict (SingI kind)
forall (kind :: AddressKind).
KindedAddress kind -> Dict (SingI kind)
addressKindSanity KindedAddress kind
addr1 (SingI kind => Maybe (kind :~: kind))
-> Dict (SingI kind) -> Maybe (kind :~: kind)
forall (c :: Constraint) e r. HasDict c e => (c => r) -> e -> r
\\ KindedAddress kind -> Dict (SingI kind)
forall (kind :: AddressKind).
KindedAddress kind -> Dict (SingI kind)
addressKindSanity KindedAddress kind
addr2 of
      Just kind :~: kind
Refl -> KindedAddress kind
addr1 KindedAddress kind -> KindedAddress kind -> Bool
forall a. Eq a => a -> a -> Bool
== KindedAddress kind
KindedAddress kind
addr2
      Maybe (kind :~: kind)
Nothing -> Bool
False
instance Ord (ConstrainedAddress c) where
  compare :: ConstrainedAddress c -> ConstrainedAddress c -> Ordering
compare (MkConstrainedAddress (KindedAddress kind
a1 :: KindedAddress kind1))
          (MkConstrainedAddress (KindedAddress kind
a2 :: KindedAddress kind2)) =
    case (KindedAddress kind
a1, KindedAddress kind
a2) of
      (KindedAddress kind
k1, KindedAddress kind
k2)
        | Just kind :~: kind
Refl <- forall {k} (a :: k) (b :: k).
(SingI a, SingI b, TestEquality Sing) =>
Maybe (a :~: b)
forall (a :: AddressKind) (b :: AddressKind).
(SingI a, SingI b, TestEquality Sing) =>
Maybe (a :~: b)
eqI @kind1 @kind2 (SingI kind => Maybe (kind :~: kind))
-> Dict (SingI kind) -> Maybe (kind :~: kind)
forall (c :: Constraint) e r. HasDict c e => (c => r) -> e -> r
\\ KindedAddress kind -> Dict (SingI kind)
forall (kind :: AddressKind).
KindedAddress kind -> Dict (SingI kind)
addressKindSanity KindedAddress kind
k1 (SingI kind => Maybe (kind :~: kind))
-> Dict (SingI kind) -> Maybe (kind :~: kind)
forall (c :: Constraint) e r. HasDict c e => (c => r) -> e -> r
\\ KindedAddress kind -> Dict (SingI kind)
forall (kind :: AddressKind).
KindedAddress kind -> Dict (SingI kind)
addressKindSanity KindedAddress kind
k2
        -> KindedAddress kind -> KindedAddress kind -> Ordering
forall a. Ord a => a -> a -> Ordering
compare KindedAddress kind
k1 KindedAddress kind
KindedAddress kind
k2
      (ImplicitAddress{}, KindedAddress kind
_) -> Ordering
LT
      (ContractAddress{}, ImplicitAddress{}) -> Ordering
GT
      (ContractAddress{}, KindedAddress kind
_) -> Ordering
LT
      (TxRollupAddress{}, ImplicitAddress{}) -> Ordering
GT
      (TxRollupAddress{}, ContractAddress{}) -> Ordering
GT
      (TxRollupAddress{}, KindedAddress kind
_) -> Ordering
LT
deriving stock instance Lift (ConstrainedAddress c)

instance NFData (ConstrainedAddress c) where
  rnf :: ConstrainedAddress c -> ()
rnf (MkConstrainedAddress KindedAddress kind
x) = KindedAddress kind -> ()
forall a. NFData a => a -> ()
rnf KindedAddress kind
x

instance Buildable (ConstrainedAddress c) where
  build :: ConstrainedAddress c -> Builder
build (MkConstrainedAddress KindedAddress kind
x) = KindedAddress kind -> Builder
forall p. Buildable p => p -> Builder
build KindedAddress kind
x

-- | Given any (non-bottom) 'KindedAddress', prove that @kind@ is well-defined
-- (i.e. has a 'SingI' instance)
addressKindSanity :: KindedAddress kind -> Dict (SingI kind)
addressKindSanity :: forall (kind :: AddressKind).
KindedAddress kind -> Dict (SingI kind)
addressKindSanity = \case
  ImplicitAddress{} -> Dict (SingI kind)
forall (a :: Constraint). a => Dict a
Dict
  ContractAddress{} -> Dict (SingI kind)
forall (a :: Constraint). a => Dict a
Dict
  TxRollupAddress{} -> Dict (SingI kind)
forall (a :: Constraint). a => Dict a
Dict

-- | @tz4@ level-2 public key hash address, used with transaction rollups, corresponds
-- to @tx_rollup_l2_address@ Michelson type.
newtype TxRollupL2Address = TxRollupL2Address KeyHashL2
  deriving stock (Int -> TxRollupL2Address -> ShowS
[TxRollupL2Address] -> ShowS
TxRollupL2Address -> String
(Int -> TxRollupL2Address -> ShowS)
-> (TxRollupL2Address -> String)
-> ([TxRollupL2Address] -> ShowS)
-> Show TxRollupL2Address
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TxRollupL2Address] -> ShowS
$cshowList :: [TxRollupL2Address] -> ShowS
show :: TxRollupL2Address -> String
$cshow :: TxRollupL2Address -> String
showsPrec :: Int -> TxRollupL2Address -> ShowS
$cshowsPrec :: Int -> TxRollupL2Address -> ShowS
Show, TxRollupL2Address -> TxRollupL2Address -> Bool
(TxRollupL2Address -> TxRollupL2Address -> Bool)
-> (TxRollupL2Address -> TxRollupL2Address -> Bool)
-> Eq TxRollupL2Address
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TxRollupL2Address -> TxRollupL2Address -> Bool
$c/= :: TxRollupL2Address -> TxRollupL2Address -> Bool
== :: TxRollupL2Address -> TxRollupL2Address -> Bool
$c== :: TxRollupL2Address -> TxRollupL2Address -> Bool
Eq, Eq TxRollupL2Address
Eq TxRollupL2Address
-> (TxRollupL2Address -> TxRollupL2Address -> Ordering)
-> (TxRollupL2Address -> TxRollupL2Address -> Bool)
-> (TxRollupL2Address -> TxRollupL2Address -> Bool)
-> (TxRollupL2Address -> TxRollupL2Address -> Bool)
-> (TxRollupL2Address -> TxRollupL2Address -> Bool)
-> (TxRollupL2Address -> TxRollupL2Address -> TxRollupL2Address)
-> (TxRollupL2Address -> TxRollupL2Address -> TxRollupL2Address)
-> Ord TxRollupL2Address
TxRollupL2Address -> TxRollupL2Address -> Bool
TxRollupL2Address -> TxRollupL2Address -> Ordering
TxRollupL2Address -> TxRollupL2Address -> TxRollupL2Address
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: TxRollupL2Address -> TxRollupL2Address -> TxRollupL2Address
$cmin :: TxRollupL2Address -> TxRollupL2Address -> TxRollupL2Address
max :: TxRollupL2Address -> TxRollupL2Address -> TxRollupL2Address
$cmax :: TxRollupL2Address -> TxRollupL2Address -> TxRollupL2Address
>= :: TxRollupL2Address -> TxRollupL2Address -> Bool
$c>= :: TxRollupL2Address -> TxRollupL2Address -> Bool
> :: TxRollupL2Address -> TxRollupL2Address -> Bool
$c> :: TxRollupL2Address -> TxRollupL2Address -> Bool
<= :: TxRollupL2Address -> TxRollupL2Address -> Bool
$c<= :: TxRollupL2Address -> TxRollupL2Address -> Bool
< :: TxRollupL2Address -> TxRollupL2Address -> Bool
$c< :: TxRollupL2Address -> TxRollupL2Address -> Bool
compare :: TxRollupL2Address -> TxRollupL2Address -> Ordering
$ccompare :: TxRollupL2Address -> TxRollupL2Address -> Ordering
Ord, (forall x. TxRollupL2Address -> Rep TxRollupL2Address x)
-> (forall x. Rep TxRollupL2Address x -> TxRollupL2Address)
-> Generic TxRollupL2Address
forall x. Rep TxRollupL2Address x -> TxRollupL2Address
forall x. TxRollupL2Address -> Rep TxRollupL2Address x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep TxRollupL2Address x -> TxRollupL2Address
$cfrom :: forall x. TxRollupL2Address -> Rep TxRollupL2Address x
Generic, (forall (m :: * -> *). Quote m => TxRollupL2Address -> m Exp)
-> (forall (m :: * -> *).
    Quote m =>
    TxRollupL2Address -> Code m TxRollupL2Address)
-> Lift TxRollupL2Address
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => TxRollupL2Address -> m Exp
forall (m :: * -> *).
Quote m =>
TxRollupL2Address -> Code m TxRollupL2Address
liftTyped :: forall (m :: * -> *).
Quote m =>
TxRollupL2Address -> Code m TxRollupL2Address
$cliftTyped :: forall (m :: * -> *).
Quote m =>
TxRollupL2Address -> Code m TxRollupL2Address
lift :: forall (m :: * -> *). Quote m => TxRollupL2Address -> m Exp
$clift :: forall (m :: * -> *). Quote m => TxRollupL2Address -> m Exp
Lift)
  deriving newtype TxRollupL2Address -> ()
(TxRollupL2Address -> ()) -> NFData TxRollupL2Address
forall a. (a -> ()) -> NFData a
rnf :: TxRollupL2Address -> ()
$crnf :: TxRollupL2Address -> ()
NFData

-- | Checks if the provided 'KindedAddress' is an implicit address and returns
-- proof of the fact if it is.
isImplicitAddress :: KindedAddress kind -> Maybe (kind :~: 'AddressKindImplicit)
isImplicitAddress :: forall (kind :: AddressKind).
KindedAddress kind -> Maybe (kind :~: 'AddressKindImplicit)
isImplicitAddress = \case
  ImplicitAddress{} -> (kind :~: kind) -> Maybe (kind :~: kind)
forall a. a -> Maybe a
Just kind :~: kind
forall {k} (a :: k). a :~: a
Refl
  KindedAddress kind
_ -> Maybe (kind :~: 'AddressKindImplicit)
forall a. Maybe a
Nothing

-- | Smart constructor for t'ImplicitAddress'.
mkKeyAddress :: PublicKey -> ImplicitAddress
mkKeyAddress :: PublicKey -> ImplicitAddress
mkKeyAddress = KeyHash -> ImplicitAddress
ImplicitAddress (KeyHash -> ImplicitAddress)
-> (PublicKey -> KeyHash) -> PublicKey -> ImplicitAddress
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PublicKey -> KeyHash
hashKey

-- | Deterministically generate a random t'ImplicitAddress' and discard its
-- secret key.
detGenKeyAddress :: ByteString -> ImplicitAddress
detGenKeyAddress :: ByteString -> ImplicitAddress
detGenKeyAddress = PublicKey -> ImplicitAddress
mkKeyAddress (PublicKey -> ImplicitAddress)
-> (ByteString -> PublicKey) -> ByteString -> ImplicitAddress
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecretKey -> PublicKey
toPublic (SecretKey -> PublicKey)
-> (ByteString -> SecretKey) -> ByteString -> PublicKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ByteString -> SecretKey
ByteString -> SecretKey
detSecretKey

-- | Represents the network's global counter.
--
-- We store the current value of this counter in the operation at the time of its creation
-- for the following reasons:
-- * to guarantee the uniqueness of contract addresses upon origination
--   (see 'Morley.Michelson.Typed.Operation.mkContractAddress)
-- * to prevent replay attacks by checking that an operation with the same counter value
--   con't be performed twice.
--
-- The counter is incremented after every operation execution and interpretation of instructions
-- @CREATE_CONTRACT@ and @TRANSFER_TOKENS@, and thus ensures that these addresses are unique
-- (i.e. origination of identical contracts with identical metadata will result in
-- different addresses.)
--
-- Our counter is represented as 'Word64', while in Tezos it is unbounded. We believe that
-- for our interpreter it should not matter.
newtype GlobalCounter = GlobalCounter { GlobalCounter -> Word64
unGlobalCounter :: Word64 }
  deriving stock (Int -> GlobalCounter -> ShowS
[GlobalCounter] -> ShowS
GlobalCounter -> String
(Int -> GlobalCounter -> ShowS)
-> (GlobalCounter -> String)
-> ([GlobalCounter] -> ShowS)
-> Show GlobalCounter
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GlobalCounter] -> ShowS
$cshowList :: [GlobalCounter] -> ShowS
show :: GlobalCounter -> String
$cshow :: GlobalCounter -> String
showsPrec :: Int -> GlobalCounter -> ShowS
$cshowsPrec :: Int -> GlobalCounter -> ShowS
Show, GlobalCounter -> GlobalCounter -> Bool
(GlobalCounter -> GlobalCounter -> Bool)
-> (GlobalCounter -> GlobalCounter -> Bool) -> Eq GlobalCounter
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GlobalCounter -> GlobalCounter -> Bool
$c/= :: GlobalCounter -> GlobalCounter -> Bool
== :: GlobalCounter -> GlobalCounter -> Bool
$c== :: GlobalCounter -> GlobalCounter -> Bool
Eq, (forall x. GlobalCounter -> Rep GlobalCounter x)
-> (forall x. Rep GlobalCounter x -> GlobalCounter)
-> Generic GlobalCounter
forall x. Rep GlobalCounter x -> GlobalCounter
forall x. GlobalCounter -> Rep GlobalCounter x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep GlobalCounter x -> GlobalCounter
$cfrom :: forall x. GlobalCounter -> Rep GlobalCounter x
Generic)
  deriving anyclass (GlobalCounter -> ()
(GlobalCounter -> ()) -> NFData GlobalCounter
forall a. (a -> ()) -> NFData a
rnf :: GlobalCounter -> ()
$crnf :: GlobalCounter -> ()
NFData)
  deriving newtype ([GlobalCounter] -> Encoding
[GlobalCounter] -> Value
GlobalCounter -> Encoding
GlobalCounter -> Value
(GlobalCounter -> Value)
-> (GlobalCounter -> Encoding)
-> ([GlobalCounter] -> Value)
-> ([GlobalCounter] -> Encoding)
-> ToJSON GlobalCounter
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [GlobalCounter] -> Encoding
$ctoEncodingList :: [GlobalCounter] -> Encoding
toJSONList :: [GlobalCounter] -> Value
$ctoJSONList :: [GlobalCounter] -> Value
toEncoding :: GlobalCounter -> Encoding
$ctoEncoding :: GlobalCounter -> Encoding
toJSON :: GlobalCounter -> Value
$ctoJSON :: GlobalCounter -> Value
ToJSON, Value -> Parser [GlobalCounter]
Value -> Parser GlobalCounter
(Value -> Parser GlobalCounter)
-> (Value -> Parser [GlobalCounter]) -> FromJSON GlobalCounter
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [GlobalCounter]
$cparseJSONList :: Value -> Parser [GlobalCounter]
parseJSON :: Value -> Parser GlobalCounter
$cparseJSON :: Value -> Parser GlobalCounter
FromJSON, Integer -> GlobalCounter
GlobalCounter -> GlobalCounter
GlobalCounter -> GlobalCounter -> GlobalCounter
(GlobalCounter -> GlobalCounter -> GlobalCounter)
-> (GlobalCounter -> GlobalCounter -> GlobalCounter)
-> (GlobalCounter -> GlobalCounter -> GlobalCounter)
-> (GlobalCounter -> GlobalCounter)
-> (GlobalCounter -> GlobalCounter)
-> (GlobalCounter -> GlobalCounter)
-> (Integer -> GlobalCounter)
-> Num GlobalCounter
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> GlobalCounter
$cfromInteger :: Integer -> GlobalCounter
signum :: GlobalCounter -> GlobalCounter
$csignum :: GlobalCounter -> GlobalCounter
abs :: GlobalCounter -> GlobalCounter
$cabs :: GlobalCounter -> GlobalCounter
negate :: GlobalCounter -> GlobalCounter
$cnegate :: GlobalCounter -> GlobalCounter
* :: GlobalCounter -> GlobalCounter -> GlobalCounter
$c* :: GlobalCounter -> GlobalCounter -> GlobalCounter
- :: GlobalCounter -> GlobalCounter -> GlobalCounter
$c- :: GlobalCounter -> GlobalCounter -> GlobalCounter
+ :: GlobalCounter -> GlobalCounter -> GlobalCounter
$c+ :: GlobalCounter -> GlobalCounter -> GlobalCounter
Num, GlobalCounter -> Builder
(GlobalCounter -> Builder) -> Buildable GlobalCounter
forall p. (p -> Builder) -> Buildable p
build :: GlobalCounter -> Builder
$cbuild :: GlobalCounter -> Builder
Buildable, Int -> GlobalCounter -> Int
GlobalCounter -> Int
(Int -> GlobalCounter -> Int)
-> (GlobalCounter -> Int) -> Hashable GlobalCounter
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: GlobalCounter -> Int
$chash :: GlobalCounter -> Int
hashWithSalt :: Int -> GlobalCounter -> Int
$chashWithSalt :: Int -> GlobalCounter -> Int
Hashable)

-- | Create a dummy 'ContractHash' value by hashing given 'ByteString'.
--
-- Use in tests **only**.
mkContractHashHack :: ByteString -> ContractHash
mkContractHashHack :: ByteString -> ContractHash
mkContractHashHack = HashTag 'HashKindContract -> ByteString -> ContractHash
forall (kind :: HashKind). HashTag kind -> ByteString -> Hash kind
Hash HashTag 'HashKindContract
HashContract (ByteString -> ContractHash)
-> (ByteString -> ByteString) -> ByteString -> ContractHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
blake2b160

----------------------------------------------------------------------------
-- Formatting/parsing
----------------------------------------------------------------------------

formatAddress :: KindedAddress kind -> Text
formatAddress :: forall (kind :: AddressKind). KindedAddress kind -> Text
formatAddress =
  \case
    ImplicitAddress KeyHash
h -> KeyHash -> Text
forall (kind :: HashKind). Hash kind -> Text
formatHash KeyHash
h
    ContractAddress ContractHash
h -> ContractHash -> Text
forall (kind :: HashKind). Hash kind -> Text
formatHash ContractHash
h
    TxRollupAddress TxRollupHash
h -> TxRollupHash -> Text
forall (kind :: HashKind). Hash kind -> Text
formatHash TxRollupHash
h

mformatAddress :: KindedAddress kind -> MText
mformatAddress :: forall (kind :: AddressKind). KindedAddress kind -> MText
mformatAddress = Either Text MText -> MText
forall a b. (HasCallStack, Buildable a) => Either a b -> b
unsafe (Either Text MText -> MText)
-> (KindedAddress kind -> Either Text MText)
-> KindedAddress kind
-> MText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either Text MText
mkMText (Text -> Either Text MText)
-> (KindedAddress kind -> Text)
-> KindedAddress kind
-> Either Text MText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KindedAddress kind -> Text
forall (kind :: AddressKind). KindedAddress kind -> Text
formatAddress

instance Buildable (KindedAddress kind) where
  build :: KindedAddress kind -> Builder
build = Text -> Builder
forall p. Buildable p => p -> Builder
build (Text -> Builder)
-> (KindedAddress kind -> Text) -> KindedAddress kind -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KindedAddress kind -> Text
forall (kind :: AddressKind). KindedAddress kind -> Text
formatAddress

instance Buildable TxRollupL2Address where
  build :: TxRollupL2Address -> Builder
build (TxRollupL2Address KeyHashL2
kh) = Text -> Builder
forall p. Buildable p => p -> Builder
build (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ KeyHashL2 -> Text
forall (kind :: HashKind). Hash kind -> Text
formatHash KeyHashL2
kh

-- | Errors that can happen during address parsing.
data ParseAddressError
  = ParseAddressWrongBase58Check
  -- ^ Address is not in Base58Check format.
  | ParseAddressAllFailed (NonEmpty CryptoParseError)
  -- ^ All address parsers failed with some error.
  deriving stock (Int -> ParseAddressError -> ShowS
[ParseAddressError] -> ShowS
ParseAddressError -> String
(Int -> ParseAddressError -> ShowS)
-> (ParseAddressError -> String)
-> ([ParseAddressError] -> ShowS)
-> Show ParseAddressError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ParseAddressError] -> ShowS
$cshowList :: [ParseAddressError] -> ShowS
show :: ParseAddressError -> String
$cshow :: ParseAddressError -> String
showsPrec :: Int -> ParseAddressError -> ShowS
$cshowsPrec :: Int -> ParseAddressError -> ShowS
Show, ParseAddressError -> ParseAddressError -> Bool
(ParseAddressError -> ParseAddressError -> Bool)
-> (ParseAddressError -> ParseAddressError -> Bool)
-> Eq ParseAddressError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ParseAddressError -> ParseAddressError -> Bool
$c/= :: ParseAddressError -> ParseAddressError -> Bool
== :: ParseAddressError -> ParseAddressError -> Bool
$c== :: ParseAddressError -> ParseAddressError -> Bool
Eq, (forall x. ParseAddressError -> Rep ParseAddressError x)
-> (forall x. Rep ParseAddressError x -> ParseAddressError)
-> Generic ParseAddressError
forall x. Rep ParseAddressError x -> ParseAddressError
forall x. ParseAddressError -> Rep ParseAddressError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ParseAddressError x -> ParseAddressError
$cfrom :: forall x. ParseAddressError -> Rep ParseAddressError x
Generic)

instance Semigroup ParseAddressError where
  ParseAddressError
ParseAddressWrongBase58Check <> :: ParseAddressError -> ParseAddressError -> ParseAddressError
<> ParseAddressError
_ =  ParseAddressError
ParseAddressWrongBase58Check
  ParseAddressError
_ <> ParseAddressError
ParseAddressWrongBase58Check =  ParseAddressError
ParseAddressWrongBase58Check
  ParseAddressAllFailed NonEmpty CryptoParseError
xs <> ParseAddressAllFailed NonEmpty CryptoParseError
ys = NonEmpty CryptoParseError -> ParseAddressError
ParseAddressAllFailed (NonEmpty CryptoParseError -> ParseAddressError)
-> NonEmpty CryptoParseError -> ParseAddressError
forall a b. (a -> b) -> a -> b
$ NonEmpty CryptoParseError
xs NonEmpty CryptoParseError
-> NonEmpty CryptoParseError -> NonEmpty CryptoParseError
forall a. Semigroup a => a -> a -> a
<> NonEmpty CryptoParseError
ys

instance NFData ParseAddressError

instance Buildable ParseAddressError where
  build :: ParseAddressError -> Builder
build = ParseAddressError -> Builder
forall a. RenderDoc a => a -> Builder
buildRenderDoc

instance RenderDoc ParseAddressError where
  renderDoc :: RenderContext -> ParseAddressError -> Doc
renderDoc RenderContext
context =
    \case
      ParseAddressError
ParseAddressWrongBase58Check -> Doc
"Wrong base58check format"
      ParseAddressAllFailed NonEmpty CryptoParseError
pkErr ->
        [Doc] -> Doc
forall a. Monoid a => [a] -> a
mconcat ([Doc] -> Doc) -> [Doc] -> Doc
forall a b. (a -> b) -> a -> b
$ Doc
"Address failed to parse: " Doc -> [Doc] -> [Doc]
forall a. a -> [a] -> [a]
: Doc -> [Doc] -> [Doc]
forall a. a -> [a] -> [a]
intersperse Doc
", "
          (NonEmpty Doc -> [Element (NonEmpty Doc)]
forall t. Container t => t -> [Element t]
toList (NonEmpty Doc -> [Element (NonEmpty Doc)])
-> NonEmpty Doc -> [Element (NonEmpty Doc)]
forall a b. (a -> b) -> a -> b
$ RenderContext -> CryptoParseError -> Doc
forall a. RenderDoc a => RenderContext -> a -> Doc
renderDoc RenderContext
context (CryptoParseError -> Doc)
-> NonEmpty CryptoParseError -> NonEmpty Doc
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty CryptoParseError
pkErr)

-- | Parse an address of a particular kind from its human-readable textual
-- representation used by Tezos (e. g. "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU").
-- Or fail if it's invalid.
parseKindedAddress :: forall kind. SingI kind => Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress :: forall (kind :: AddressKind).
SingI kind =>
Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress Text
addressText = case forall {k} (a :: k). SingI a => Sing a
forall (a :: AddressKind). SingI a => Sing a
sing @kind of
  Sing kind
SingAddressKind kind
SAddressKindContract -> (ContractHash -> KindedAddress 'AddressKindContract)
-> Either ParseAddressError (KindedAddress 'AddressKindContract)
forall (hkind :: HashKind) b.
AllHashTags hkind =>
(Hash hkind -> b) -> Either ParseAddressError b
tryParse ContractHash -> KindedAddress 'AddressKindContract
ContractAddress
  Sing kind
SingAddressKind kind
SAddressKindImplicit -> (KeyHash -> ImplicitAddress)
-> Either ParseAddressError ImplicitAddress
forall (hkind :: HashKind) b.
AllHashTags hkind =>
(Hash hkind -> b) -> Either ParseAddressError b
tryParse KeyHash -> ImplicitAddress
ImplicitAddress
  Sing kind
SingAddressKind kind
SAddressKindTxRollup -> (TxRollupHash -> KindedAddress 'AddressKindTxRollup)
-> Either ParseAddressError (KindedAddress 'AddressKindTxRollup)
forall (hkind :: HashKind) b.
AllHashTags hkind =>
(Hash hkind -> b) -> Either ParseAddressError b
tryParse TxRollupHash -> KindedAddress 'AddressKindTxRollup
TxRollupAddress
  where
    handleCrypto :: CryptoParseError -> ParseAddressError
handleCrypto = \case
      CryptoParseError
CryptoParseWrongBase58Check -> ParseAddressError
ParseAddressWrongBase58Check
      CryptoParseError
x -> NonEmpty CryptoParseError -> ParseAddressError
ParseAddressAllFailed (NonEmpty CryptoParseError -> ParseAddressError)
-> NonEmpty CryptoParseError -> ParseAddressError
forall a b. (a -> b) -> a -> b
$ CryptoParseError -> NonEmpty CryptoParseError
forall (f :: * -> *) a. Applicative f => a -> f a
pure CryptoParseError
x
    tryParse :: AllHashTags hkind => (Hash hkind -> b) -> Either ParseAddressError b
    tryParse :: forall (hkind :: HashKind) b.
AllHashTags hkind =>
(Hash hkind -> b) -> Either ParseAddressError b
tryParse Hash hkind -> b
ctor = (CryptoParseError -> ParseAddressError)
-> (Hash hkind -> b)
-> Either CryptoParseError (Hash hkind)
-> Either ParseAddressError b
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap CryptoParseError -> ParseAddressError
handleCrypto Hash hkind -> b
ctor (Either CryptoParseError (Hash hkind)
 -> Either ParseAddressError b)
-> Either CryptoParseError (Hash hkind)
-> Either ParseAddressError b
forall a b. (a -> b) -> a -> b
$ Text -> Either CryptoParseError (Hash hkind)
forall (kind :: HashKind).
AllHashTags kind =>
Text -> Either CryptoParseError (Hash kind)
parseHash Text
addressText

-- | Parse an address of arbitrary kind from its human-readable textual
-- representation, or fail if it's invalid.
parseAddress :: Text -> Either ParseAddressError Address
parseAddress :: Text -> Either ParseAddressError Address
parseAddress Text
x =
          (ImplicitAddress -> Address
forall (kind :: AddressKind). KindedAddress kind -> Address
MkAddress (ImplicitAddress -> Address)
-> Either ParseAddressError ImplicitAddress
-> Either ParseAddressError Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (kind :: AddressKind).
SingI kind =>
Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress @'AddressKindImplicit Text
x)
  Either ParseAddressError Address
-> Either ParseAddressError Address
-> Either ParseAddressError Address
forall a b. Semigroup a => Either a b -> Either a b -> Either a b
`merge` (KindedAddress 'AddressKindContract -> Address
forall (kind :: AddressKind). KindedAddress kind -> Address
MkAddress (KindedAddress 'AddressKindContract -> Address)
-> Either ParseAddressError (KindedAddress 'AddressKindContract)
-> Either ParseAddressError Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (kind :: AddressKind).
SingI kind =>
Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress @'AddressKindContract Text
x)
  Either ParseAddressError Address
-> Either ParseAddressError Address
-> Either ParseAddressError Address
forall a b. Semigroup a => Either a b -> Either a b -> Either a b
`merge` (KindedAddress 'AddressKindTxRollup -> Address
forall (kind :: AddressKind). KindedAddress kind -> Address
MkAddress (KindedAddress 'AddressKindTxRollup -> Address)
-> Either ParseAddressError (KindedAddress 'AddressKindTxRollup)
-> Either ParseAddressError Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (kind :: AddressKind).
SingI kind =>
Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress @'AddressKindTxRollup Text
x)
  where
    merge :: Semigroup a => Either a b -> Either a b -> Either a b
    merge :: forall a b. Semigroup a => Either a b -> Either a b -> Either a b
merge (Left a
xs) (Left a
ys) = a -> Either a b
forall a b. a -> Either a b
Left (a -> Either a b) -> a -> Either a b
forall a b. (a -> b) -> a -> b
$ a
xs a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
ys
    merge r :: Either a b
r@Right{} Either a b
_ = Either a b
r
    merge Either a b
_ r :: Either a b
r@Right{} = Either a b
r

data ParseAddressRawError
  = ParseAddressRawWrongSize ByteString
  -- ^ Raw bytes representation of an address has invalid length.
  | ParseAddressRawInvalidPrefix Word8
  -- ^ Raw bytes representation of an address has incorrect prefix.
  | ParseAddressRawMalformedSeparator Word8
  -- ^ Raw bytes representation of an address does not end with "\00".
  | ParseAddressRawBinaryError Text
  -- ^ General binary decoding error.
  | ParseAddressCryptoError CryptoParseError
  -- ^ Crypto error in parsing key hash.
  deriving stock (ParseAddressRawError -> ParseAddressRawError -> Bool
(ParseAddressRawError -> ParseAddressRawError -> Bool)
-> (ParseAddressRawError -> ParseAddressRawError -> Bool)
-> Eq ParseAddressRawError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ParseAddressRawError -> ParseAddressRawError -> Bool
$c/= :: ParseAddressRawError -> ParseAddressRawError -> Bool
== :: ParseAddressRawError -> ParseAddressRawError -> Bool
$c== :: ParseAddressRawError -> ParseAddressRawError -> Bool
Eq, Int -> ParseAddressRawError -> ShowS
[ParseAddressRawError] -> ShowS
ParseAddressRawError -> String
(Int -> ParseAddressRawError -> ShowS)
-> (ParseAddressRawError -> String)
-> ([ParseAddressRawError] -> ShowS)
-> Show ParseAddressRawError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ParseAddressRawError] -> ShowS
$cshowList :: [ParseAddressRawError] -> ShowS
show :: ParseAddressRawError -> String
$cshow :: ParseAddressRawError -> String
showsPrec :: Int -> ParseAddressRawError -> ShowS
$cshowsPrec :: Int -> ParseAddressRawError -> ShowS
Show, (forall x. ParseAddressRawError -> Rep ParseAddressRawError x)
-> (forall x. Rep ParseAddressRawError x -> ParseAddressRawError)
-> Generic ParseAddressRawError
forall x. Rep ParseAddressRawError x -> ParseAddressRawError
forall x. ParseAddressRawError -> Rep ParseAddressRawError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ParseAddressRawError x -> ParseAddressRawError
$cfrom :: forall x. ParseAddressRawError -> Rep ParseAddressRawError x
Generic)

instance NFData ParseAddressRawError

instance RenderDoc ParseAddressRawError where
  renderDoc :: RenderContext -> ParseAddressRawError -> Doc
renderDoc RenderContext
_ =
    \case
      ParseAddressRawInvalidPrefix Word8
prefix ->
        Doc
"Invalid prefix for raw address" Doc -> Doc -> Doc
<+> (Doc -> Doc
dquotes (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ Builder -> Doc
forall a. Buildable a => a -> Doc
renderAnyBuildable (Builder -> Doc) -> Builder -> Doc
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
forall a. FormatAsHex a => a -> Builder
hexF Word8
prefix) Doc -> Doc -> Doc
<+> Doc
"provided"
      ParseAddressRawWrongSize ByteString
addr -> Doc
"Given raw address+" Doc -> Doc -> Doc
<+>
        (Builder -> Doc
forall a. Buildable a => a -> Doc
renderAnyBuildable (Builder -> Doc) -> Builder -> Doc
forall a b. (a -> b) -> a -> b
$ ByteString -> Builder
forall a. FormatAsHex a => a -> Builder
hexF ByteString
addr) Doc -> Doc -> Doc
<+> Doc
"has invalid length" Doc -> Doc -> Doc
<+> Int -> Doc
int (ByteString -> Int
forall t. Container t => t -> Int
length ByteString
addr)
      ParseAddressRawMalformedSeparator Word8
addr -> Doc
"Given raw address" Doc -> Doc -> Doc
<+> (Builder -> Doc
forall a. Buildable a => a -> Doc
renderAnyBuildable (Builder -> Doc) -> Builder -> Doc
forall a b. (a -> b) -> a -> b
$ Word8 -> Builder
forall a. FormatAsHex a => a -> Builder
hexF Word8
addr) Doc -> Doc -> Doc
<+>
        Doc
"does not end with" Doc -> Doc -> Doc
<+> Doc -> Doc
dquotes (Doc
backslash Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Doc
"00")
      ParseAddressRawBinaryError Text
err -> Doc
"Binary error during decoding address:" Doc -> Doc -> Doc
<+> Text -> Doc
forall a. Buildable a => a -> Doc
renderAnyBuildable Text
err
      ParseAddressCryptoError CryptoParseError
err -> Doc
"Key hash decoding error:" Doc -> Doc -> Doc
<+> CryptoParseError -> Doc
forall a. Buildable a => a -> Doc
renderAnyBuildable CryptoParseError
err

instance Buildable ParseAddressRawError where
  build :: ParseAddressRawError -> Builder
build = ParseAddressRawError -> Builder
forall a. RenderDoc a => a -> Builder
buildRenderDoc

-- | Parse the given address in its raw byte form used by Tezos
-- (e.g "01521139f84791537d54575df0c74a8084cc68861c00")) . Or fail otherwise
-- if it's invalid.
parseAddressRaw :: ByteString -> Either ParseAddressRawError Address
parseAddressRaw :: ByteString -> Either ParseAddressRawError Address
parseAddressRaw ByteString
bytes
  -- NB: conveniently, the byte count is the same for 'KeyAddress',
  -- 'ContractAddress' and 'TransactionRollupAddress'. However, with
  -- 'KeyAddress' it's two tag bytes, while with the other two it's one tag byte
  -- and one separator byte.
  | ByteString -> Int
BS.length ByteString
bytes Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
forall n. Integral n => n
hashLengthBytes Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 = ParseAddressRawError -> Either ParseAddressRawError Address
forall a b. a -> Either a b
Left (ParseAddressRawError -> Either ParseAddressRawError Address)
-> ParseAddressRawError -> Either ParseAddressRawError Address
forall a b. (a -> b) -> a -> b
$ ByteString -> ParseAddressRawError
ParseAddressRawWrongSize ByteString
bytes
  | Bool
otherwise
  = ((ByteString, ByteOffset, String)
 -> Either ParseAddressRawError Address)
-> ((ByteString, ByteOffset, Either ParseAddressRawError Address)
    -> Either ParseAddressRawError Address)
-> Either
     (ByteString, ByteOffset, String)
     (ByteString, ByteOffset, Either ParseAddressRawError Address)
-> Either ParseAddressRawError Address
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (ParseAddressRawError -> Either ParseAddressRawError Address
forall a b. a -> Either a b
Left (ParseAddressRawError -> Either ParseAddressRawError Address)
-> ((ByteString, ByteOffset, String) -> ParseAddressRawError)
-> (ByteString, ByteOffset, String)
-> Either ParseAddressRawError Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ParseAddressRawError
ParseAddressRawBinaryError (Text -> ParseAddressRawError)
-> ((ByteString, ByteOffset, String) -> Text)
-> (ByteString, ByteOffset, String)
-> ParseAddressRawError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. IsString a => String -> a
fromString (String -> Text)
-> ((ByteString, ByteOffset, String) -> String)
-> (ByteString, ByteOffset, String)
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting String (ByteString, ByteOffset, String) String
-> (ByteString, ByteOffset, String) -> String
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting String (ByteString, ByteOffset, String) String
forall s t a b. Field3 s t a b => Lens s t a b
_3) (Getting
  (Either ParseAddressRawError Address)
  (ByteString, ByteOffset, Either ParseAddressRawError Address)
  (Either ParseAddressRawError Address)
-> (ByteString, ByteOffset, Either ParseAddressRawError Address)
-> Either ParseAddressRawError Address
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting
  (Either ParseAddressRawError Address)
  (ByteString, ByteOffset, Either ParseAddressRawError Address)
  (Either ParseAddressRawError Address)
forall s t a b. Field3 s t a b => Lens s t a b
_3)
  (Either
   (ByteString, ByteOffset, String)
   (ByteString, ByteOffset, Either ParseAddressRawError Address)
 -> Either ParseAddressRawError Address)
-> Either
     (ByteString, ByteOffset, String)
     (ByteString, ByteOffset, Either ParseAddressRawError Address)
-> Either ParseAddressRawError Address
forall a b. (a -> b) -> a -> b
$ (Get (Either ParseAddressRawError Address)
 -> ByteString
 -> Either
      (ByteString, ByteOffset, String)
      (ByteString, ByteOffset, Either ParseAddressRawError Address))
-> ByteString
-> Get (Either ParseAddressRawError Address)
-> Either
     (ByteString, ByteOffset, String)
     (ByteString, ByteOffset, Either ParseAddressRawError Address)
forall a b c. (a -> b -> c) -> b -> a -> c
flip Get (Either ParseAddressRawError Address)
-> ByteString
-> Either
     (ByteString, ByteOffset, String)
     (ByteString, ByteOffset, Either ParseAddressRawError Address)
forall a.
Get a
-> ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)
Get.runGetOrFail (ByteString -> ByteString
LBS.fromStrict ByteString
bytes) (Get (Either ParseAddressRawError Address)
 -> Either
      (ByteString, ByteOffset, String)
      (ByteString, ByteOffset, Either ParseAddressRawError Address))
-> Get (Either ParseAddressRawError Address)
-> Either
     (ByteString, ByteOffset, String)
     (ByteString, ByteOffset, Either ParseAddressRawError Address)
forall a b. (a -> b) -> a -> b
$ ExceptT ParseAddressRawError Get Address
-> Get (Either ParseAddressRawError Address)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT
  (ExceptT ParseAddressRawError Get Address
 -> Get (Either ParseAddressRawError Address))
-> ExceptT ParseAddressRawError Get Address
-> Get (Either ParseAddressRawError Address)
forall a b. (a -> b) -> a -> b
$ String
-> (Word8 -> ExceptT ParseAddressRawError Get Address)
-> [TaggedDecoderM (ExceptT ParseAddressRawError) Address]
-> ExceptT ParseAddressRawError Get Address
forall (t :: (* -> *) -> * -> *) a.
(MonadTrans t, Monad (t Get)) =>
String -> (Word8 -> t Get a) -> [TaggedDecoderM t a] -> t Get a
decodeWithTagM String
"address" (ParseAddressRawError -> ExceptT ParseAddressRawError Get Address
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (ParseAddressRawError -> ExceptT ParseAddressRawError Get Address)
-> (Word8 -> ParseAddressRawError)
-> Word8
-> ExceptT ParseAddressRawError Get Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> ParseAddressRawError
ParseAddressRawInvalidPrefix)
      [ Word8
0x00 Word8
-> ExceptT ParseAddressRawError Get Address
-> TaggedDecoderM (ExceptT ParseAddressRawError) Address
forall {k} (t :: (* -> *) -> k -> *) (a :: k).
Word8 -> t Get a -> TaggedDecoderM t a
##: ImplicitAddress -> Address
forall (kind :: AddressKind). KindedAddress kind -> Address
MkAddress (ImplicitAddress -> Address)
-> (KeyHash -> ImplicitAddress) -> KeyHash -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyHash -> ImplicitAddress
ImplicitAddress (KeyHash -> Address)
-> ExceptT ParseAddressRawError Get KeyHash
-> ExceptT ParseAddressRawError Get Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ExceptT ParseAddressRawError Get KeyHash
keyHash
      , Word8
0x01 Word8
-> ExceptT ParseAddressRawError Get Address
-> TaggedDecoderM (ExceptT ParseAddressRawError) Address
forall {k} (t :: (* -> *) -> k -> *) (a :: k).
Word8 -> t Get a -> TaggedDecoderM t a
##: KindedAddress 'AddressKindContract -> Address
forall (kind :: AddressKind). KindedAddress kind -> Address
MkAddress (KindedAddress 'AddressKindContract -> Address)
-> (ContractHash -> KindedAddress 'AddressKindContract)
-> ContractHash
-> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ContractHash -> KindedAddress 'AddressKindContract
ContractAddress (ContractHash -> Address)
-> ExceptT ParseAddressRawError Get ContractHash
-> ExceptT ParseAddressRawError Get Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashTag 'HashKindContract
-> ExceptT ParseAddressRawError Get ContractHash
forall (kind :: HashKind).
HashTag kind -> ExceptT ParseAddressRawError Get (Hash kind)
sepHash HashTag 'HashKindContract
HashContract
      , Word8
0x02 Word8
-> ExceptT ParseAddressRawError Get Address
-> TaggedDecoderM (ExceptT ParseAddressRawError) Address
forall {k} (t :: (* -> *) -> k -> *) (a :: k).
Word8 -> t Get a -> TaggedDecoderM t a
##: KindedAddress 'AddressKindTxRollup -> Address
forall (kind :: AddressKind). KindedAddress kind -> Address
MkAddress (KindedAddress 'AddressKindTxRollup -> Address)
-> (TxRollupHash -> KindedAddress 'AddressKindTxRollup)
-> TxRollupHash
-> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TxRollupHash -> KindedAddress 'AddressKindTxRollup
TxRollupAddress (TxRollupHash -> Address)
-> ExceptT ParseAddressRawError Get TxRollupHash
-> ExceptT ParseAddressRawError Get Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashTag 'HashKindTxRollup
-> ExceptT ParseAddressRawError Get TxRollupHash
forall (kind :: HashKind).
HashTag kind -> ExceptT ParseAddressRawError Get (Hash kind)
sepHash HashTag 'HashKindTxRollup
HashTXR
      ]
  where
    sep :: ExceptT ParseAddressRawError Get ()
sep = Get Word8 -> ExceptT ParseAddressRawError Get Word8
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift Get Word8
Get.getWord8 ExceptT ParseAddressRawError Get Word8
-> (Word8 -> ExceptT ParseAddressRawError Get ())
-> ExceptT ParseAddressRawError Get ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Word8
0x00 -> ExceptT ParseAddressRawError Get ()
forall (f :: * -> *). Applicative f => f ()
pass
      Word8
x -> ParseAddressRawError -> ExceptT ParseAddressRawError Get ()
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (ParseAddressRawError -> ExceptT ParseAddressRawError Get ())
-> ParseAddressRawError -> ExceptT ParseAddressRawError Get ()
forall a b. (a -> b) -> a -> b
$ Word8 -> ParseAddressRawError
ParseAddressRawMalformedSeparator Word8
x
    keyHash :: ExceptT ParseAddressRawError Get KeyHash
keyHash = (Get (Either CryptoParseError KeyHash)
 -> Get (Either ParseAddressRawError KeyHash))
-> ExceptT CryptoParseError Get KeyHash
-> ExceptT ParseAddressRawError Get KeyHash
forall (m :: * -> *) e a (n :: * -> *) e' b.
(m (Either e a) -> n (Either e' b))
-> ExceptT e m a -> ExceptT e' n b
mapExceptT ((Either CryptoParseError KeyHash
 -> Either ParseAddressRawError KeyHash)
-> Get (Either CryptoParseError KeyHash)
-> Get (Either ParseAddressRawError KeyHash)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Either CryptoParseError KeyHash
  -> Either ParseAddressRawError KeyHash)
 -> Get (Either CryptoParseError KeyHash)
 -> Get (Either ParseAddressRawError KeyHash))
-> (Either CryptoParseError KeyHash
    -> Either ParseAddressRawError KeyHash)
-> Get (Either CryptoParseError KeyHash)
-> Get (Either ParseAddressRawError KeyHash)
forall a b. (a -> b) -> a -> b
$ (CryptoParseError -> ParseAddressRawError)
-> Either CryptoParseError KeyHash
-> Either ParseAddressRawError KeyHash
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first CryptoParseError -> ParseAddressRawError
ParseAddressCryptoError) ExceptT CryptoParseError Get KeyHash
decodeKeyHash
    sepHash :: HashTag kind -> ExceptT ParseAddressRawError Get.Get (Hash kind)
    sepHash :: forall (kind :: HashKind).
HashTag kind -> ExceptT ParseAddressRawError Get (Hash kind)
sepHash HashTag kind
kind = HashTag kind -> ByteString -> Hash kind
forall (kind :: HashKind). HashTag kind -> ByteString -> Hash kind
Hash HashTag kind
kind (ByteString -> Hash kind)
-> ExceptT ParseAddressRawError Get ByteString
-> ExceptT ParseAddressRawError Get (Hash kind)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get ByteString -> ExceptT ParseAddressRawError Get ByteString
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Int -> Get ByteString
getByteStringCopy Int
forall n. Integral n => n
hashLengthBytes) ExceptT ParseAddressRawError Get (Hash kind)
-> ExceptT ParseAddressRawError Get ()
-> ExceptT ParseAddressRawError Get (Hash kind)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ExceptT ParseAddressRawError Get ()
sep

-- | QuasiQuoter for constructing Tezos addresses.
--
-- Validity of result will be checked at compile time.
ta :: TH.QuasiQuoter
ta :: QuasiQuoter
ta = QuasiQuoter :: (String -> Q Exp)
-> (String -> Q Pat)
-> (String -> Q Type)
-> (String -> Q [Dec])
-> QuasiQuoter
TH.QuasiQuoter
  { quoteExp :: String -> Q Exp
TH.quoteExp = \String
s ->
      case Text -> Either ParseAddressError Address
parseAddress (Text -> Either ParseAddressError Address)
-> (Text -> Text) -> Text -> Either ParseAddressError Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
strip (Text -> Either ParseAddressError Address)
-> Text -> Either ParseAddressError Address
forall a b. (a -> b) -> a -> b
$ String -> Text
forall a. ToText a => a -> Text
toText String
s of
        Left   ParseAddressError
err -> String -> Q Exp
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Q Exp) -> String -> Q Exp
forall a b. (a -> b) -> a -> b
$ ParseAddressError -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty ParseAddressError
err
        Right (MkAddress KindedAddress kind
addr) -> KindedAddress kind -> Q Exp
forall t (m :: * -> *). (Lift t, Quote m) => t -> m Exp
TH.lift KindedAddress kind
addr
  , quotePat :: String -> Q Pat
TH.quotePat = \String
_ ->
      String -> Q Pat
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot use this QuasiQuotation at pattern position"
  , quoteType :: String -> Q Type
TH.quoteType = \String
_ ->
      String -> Q Type
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot use this QuasiQuotation at type position"
  , quoteDec :: String -> Q [Dec]
TH.quoteDec = \String
_ ->
      String -> Q [Dec]
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot use this QuasiQuotation at declaration position"
  }


instance
    TypeError ('Text "There is no instance defined for (IsString Address)" ':$$:
               'Text "Consider using QuasiQuotes: `[ta|some text...|]`"
              ) =>
    IsString (KindedAddress kind) where
  fromString :: String -> KindedAddress kind
fromString = Text -> String -> KindedAddress kind
forall a. HasCallStack => Text -> a
error Text
"impossible"


----------------------------------------------------------------------------
-- Unsafe
----------------------------------------------------------------------------

instance SingI kind => HasCLReader (KindedAddress kind) where
  getReader :: ReadM (KindedAddress kind)
getReader = (String -> Either String (KindedAddress kind))
-> ReadM (KindedAddress kind)
forall a. (String -> Either String a) -> ReadM a
eitherReader String -> Either String (KindedAddress kind)
forall {b} {kind :: AddressKind} {a}.
(Monoid b, IsString b, FromBuilder b, SingI kind, ToText a) =>
a -> Either b (KindedAddress kind)
parseAddrDo
    where
      parseAddrDo :: a -> Either b (KindedAddress kind)
parseAddrDo a
addr =
        (ParseAddressError -> b)
-> Either ParseAddressError (KindedAddress kind)
-> Either b (KindedAddress kind)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (b -> b -> b
forall a. Monoid a => a -> a -> a
mappend b
"Failed to parse address: " (b -> b) -> (ParseAddressError -> b) -> ParseAddressError -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseAddressError -> b
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) (Either ParseAddressError (KindedAddress kind)
 -> Either b (KindedAddress kind))
-> Either ParseAddressError (KindedAddress kind)
-> Either b (KindedAddress kind)
forall a b. (a -> b) -> a -> b
$
        Text -> Either ParseAddressError (KindedAddress kind)
forall (kind :: AddressKind).
SingI kind =>
Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress (Text -> Either ParseAddressError (KindedAddress kind))
-> Text -> Either ParseAddressError (KindedAddress kind)
forall a b. (a -> b) -> a -> b
$ a -> Text
forall a. ToText a => a -> Text
toText a
addr
  getMetavar :: String
getMetavar = String
"ADDRESS"

----------------------------------------------------------------------------
-- Aeson instances
----------------------------------------------------------------------------

instance ToJSON (KindedAddress kind) where
  toJSON :: KindedAddress kind -> Value
toJSON = Text -> Value
Aeson.String (Text -> Value)
-> (KindedAddress kind -> Text) -> KindedAddress kind -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KindedAddress kind -> Text
forall (kind :: AddressKind). KindedAddress kind -> Text
formatAddress
  toEncoding :: KindedAddress kind -> Encoding
toEncoding = Text -> Encoding
forall a. Text -> Encoding' a
Aeson.text (Text -> Encoding)
-> (KindedAddress kind -> Text) -> KindedAddress kind -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KindedAddress kind -> Text
forall (kind :: AddressKind). KindedAddress kind -> Text
formatAddress

instance ToJSONKey (KindedAddress kind) where
  toJSONKey :: ToJSONKeyFunction (KindedAddress kind)
toJSONKey = (KindedAddress kind -> Text)
-> ToJSONKeyFunction (KindedAddress kind)
forall a. (a -> Text) -> ToJSONKeyFunction a
AesonTypes.toJSONKeyText KindedAddress kind -> Text
forall (kind :: AddressKind). KindedAddress kind -> Text
formatAddress

instance SingI kind => FromJSON (KindedAddress kind) where
  parseJSON :: Value -> Parser (KindedAddress kind)
parseJSON =
    String
-> (Text -> Parser (KindedAddress kind))
-> Value
-> Parser (KindedAddress kind)
forall a. String -> (Text -> Parser a) -> Value -> Parser a
Aeson.withText String
"Address" ((Text -> Parser (KindedAddress kind))
 -> Value -> Parser (KindedAddress kind))
-> (Text -> Parser (KindedAddress kind))
-> Value
-> Parser (KindedAddress kind)
forall a b. (a -> b) -> a -> b
$
    (ParseAddressError -> Parser (KindedAddress kind))
-> (KindedAddress kind -> Parser (KindedAddress kind))
-> Either ParseAddressError (KindedAddress kind)
-> Parser (KindedAddress kind)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Parser (KindedAddress kind)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser (KindedAddress kind))
-> (ParseAddressError -> String)
-> ParseAddressError
-> Parser (KindedAddress kind)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseAddressError -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) KindedAddress kind -> Parser (KindedAddress kind)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseAddressError (KindedAddress kind)
 -> Parser (KindedAddress kind))
-> (Text -> Either ParseAddressError (KindedAddress kind))
-> Text
-> Parser (KindedAddress kind)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either ParseAddressError (KindedAddress kind)
forall (kind :: AddressKind).
SingI kind =>
Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress

instance SingI kind => FromJSONKey (KindedAddress kind) where
  fromJSONKey :: FromJSONKeyFunction (KindedAddress kind)
fromJSONKey =
    (Text -> Parser (KindedAddress kind))
-> FromJSONKeyFunction (KindedAddress kind)
forall a. (Text -> Parser a) -> FromJSONKeyFunction a
AesonTypes.FromJSONKeyTextParser
      ((ParseAddressError -> Parser (KindedAddress kind))
-> (KindedAddress kind -> Parser (KindedAddress kind))
-> Either ParseAddressError (KindedAddress kind)
-> Parser (KindedAddress kind)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Parser (KindedAddress kind)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser (KindedAddress kind))
-> (ParseAddressError -> String)
-> ParseAddressError
-> Parser (KindedAddress kind)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseAddressError -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) KindedAddress kind -> Parser (KindedAddress kind)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseAddressError (KindedAddress kind)
 -> Parser (KindedAddress kind))
-> (Text -> Either ParseAddressError (KindedAddress kind))
-> Text
-> Parser (KindedAddress kind)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either ParseAddressError (KindedAddress kind)
forall (kind :: AddressKind).
SingI kind =>
Text -> Either ParseAddressError (KindedAddress kind)
parseKindedAddress)

instance ToJSON (ConstrainedAddress c) where
  toJSON :: ConstrainedAddress c -> Value
toJSON (MkConstrainedAddress KindedAddress kind
addr) = KindedAddress kind -> Value
forall a. ToJSON a => a -> Value
toJSON KindedAddress kind
addr
  toEncoding :: ConstrainedAddress c -> Encoding
toEncoding (MkConstrainedAddress KindedAddress kind
addr) = KindedAddress kind -> Encoding
forall a. ToJSON a => a -> Encoding
toEncoding KindedAddress kind
addr

instance ToJSONKey (ConstrainedAddress c) where
  toJSONKey :: ToJSONKeyFunction (ConstrainedAddress c)
toJSONKey = (ConstrainedAddress c -> Text)
-> ToJSONKeyFunction (ConstrainedAddress c)
forall a. (a -> Text) -> ToJSONKeyFunction a
AesonTypes.toJSONKeyText \(MkConstrainedAddress KindedAddress kind
addr) -> KindedAddress kind -> Text
forall (kind :: AddressKind). KindedAddress kind -> Text
formatAddress KindedAddress kind
addr

instance FromJSON Address where
  parseJSON :: Value -> Parser Address
parseJSON =
    String -> (Text -> Parser Address) -> Value -> Parser Address
forall a. String -> (Text -> Parser a) -> Value -> Parser a
Aeson.withText String
"Address" ((Text -> Parser Address) -> Value -> Parser Address)
-> (Text -> Parser Address) -> Value -> Parser Address
forall a b. (a -> b) -> a -> b
$
    (ParseAddressError -> Parser Address)
-> (Address -> Parser Address)
-> Either ParseAddressError Address
-> Parser Address
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Parser Address
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser Address)
-> (ParseAddressError -> String)
-> ParseAddressError
-> Parser Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseAddressError -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) Address -> Parser Address
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseAddressError Address -> Parser Address)
-> (Text -> Either ParseAddressError Address)
-> Text
-> Parser Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either ParseAddressError Address
parseAddress

instance FromJSONKey Address where
  fromJSONKey :: FromJSONKeyFunction Address
fromJSONKey =
    (Text -> Parser Address) -> FromJSONKeyFunction Address
forall a. (Text -> Parser a) -> FromJSONKeyFunction a
AesonTypes.FromJSONKeyTextParser
      ((ParseAddressError -> Parser Address)
-> (Address -> Parser Address)
-> Either ParseAddressError Address
-> Parser Address
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Parser Address
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser Address)
-> (ParseAddressError -> String)
-> ParseAddressError
-> Parser Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseAddressError -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) Address -> Parser Address
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseAddressError Address -> Parser Address)
-> (Text -> Either ParseAddressError Address)
-> Text
-> Parser Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either ParseAddressError Address
parseAddress)