{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE DerivingVia       #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}
{-# OPTIONS_GHC -fno-specialise #-}
{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}
{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}

module Plutus.V1.Ledger.Address (
    Address (..),
    pubKeyHashAddress,
    scriptHashAddress,
    toPubKeyHash,
    toValidatorHash,
    stakingCredential
    ) where

import Codec.Serialise.Class (Serialise)
import Control.DeepSeq (NFData)
import Data.Aeson (FromJSON, FromJSONKey (..), ToJSON, ToJSONKey (..))
import Data.Hashable (Hashable)
import GHC.Generics (Generic)
import PlutusTx qualified
import PlutusTx.Bool qualified as PlutusTx
import PlutusTx.Eq qualified as PlutusTx
import Prettyprinter

import Plutus.V1.Ledger.Credential (Credential (..), StakingCredential)
import Plutus.V1.Ledger.Crypto
import Plutus.V1.Ledger.Orphans ()
import Plutus.V1.Ledger.Scripts

-- | Address with two kinds of credentials, normal and staking.
data Address = Address{ Address -> Credential
addressCredential :: Credential, Address -> Maybe StakingCredential
addressStakingCredential :: Maybe StakingCredential }
    deriving stock (Address -> Address -> Bool
(Address -> Address -> Bool)
-> (Address -> Address -> Bool) -> Eq Address
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Address -> Address -> Bool
$c/= :: Address -> Address -> Bool
== :: Address -> Address -> Bool
$c== :: Address -> Address -> Bool
Eq, Eq Address
Eq Address
-> (Address -> Address -> Ordering)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Address)
-> (Address -> Address -> Address)
-> Ord Address
Address -> Address -> Bool
Address -> Address -> Ordering
Address -> Address -> Address
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 :: Address -> Address -> Address
$cmin :: Address -> Address -> Address
max :: Address -> Address -> Address
$cmax :: Address -> Address -> Address
>= :: Address -> Address -> Bool
$c>= :: Address -> Address -> Bool
> :: Address -> Address -> Bool
$c> :: Address -> Address -> Bool
<= :: Address -> Address -> Bool
$c<= :: Address -> Address -> Bool
< :: Address -> Address -> Bool
$c< :: Address -> Address -> Bool
compare :: Address -> Address -> Ordering
$ccompare :: Address -> Address -> Ordering
$cp1Ord :: Eq Address
Ord, Int -> Address -> ShowS
[Address] -> ShowS
Address -> String
(Int -> Address -> ShowS)
-> (Address -> String) -> ([Address] -> ShowS) -> Show Address
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Address] -> ShowS
$cshowList :: [Address] -> ShowS
show :: Address -> String
$cshow :: Address -> String
showsPrec :: Int -> Address -> ShowS
$cshowsPrec :: Int -> Address -> ShowS
Show, (forall x. Address -> Rep Address x)
-> (forall x. Rep Address x -> Address) -> Generic Address
forall x. Rep Address x -> Address
forall x. Address -> Rep Address x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Address x -> Address
$cfrom :: forall x. Address -> Rep Address x
Generic)
    deriving anyclass ([Address] -> Encoding
[Address] -> Value
Address -> Encoding
Address -> Value
(Address -> Value)
-> (Address -> Encoding)
-> ([Address] -> Value)
-> ([Address] -> Encoding)
-> ToJSON Address
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [Address] -> Encoding
$ctoEncodingList :: [Address] -> Encoding
toJSONList :: [Address] -> Value
$ctoJSONList :: [Address] -> Value
toEncoding :: Address -> Encoding
$ctoEncoding :: Address -> Encoding
toJSON :: Address -> Value
$ctoJSON :: Address -> Value
ToJSON, Value -> Parser [Address]
Value -> Parser Address
(Value -> Parser Address)
-> (Value -> Parser [Address]) -> FromJSON Address
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [Address]
$cparseJSONList :: Value -> Parser [Address]
parseJSON :: Value -> Parser Address
$cparseJSON :: Value -> Parser Address
FromJSON, ToJSONKeyFunction [Address]
ToJSONKeyFunction Address
ToJSONKeyFunction Address
-> ToJSONKeyFunction [Address] -> ToJSONKey Address
forall a.
ToJSONKeyFunction a -> ToJSONKeyFunction [a] -> ToJSONKey a
toJSONKeyList :: ToJSONKeyFunction [Address]
$ctoJSONKeyList :: ToJSONKeyFunction [Address]
toJSONKey :: ToJSONKeyFunction Address
$ctoJSONKey :: ToJSONKeyFunction Address
ToJSONKey, FromJSONKeyFunction [Address]
FromJSONKeyFunction Address
FromJSONKeyFunction Address
-> FromJSONKeyFunction [Address] -> FromJSONKey Address
forall a.
FromJSONKeyFunction a -> FromJSONKeyFunction [a] -> FromJSONKey a
fromJSONKeyList :: FromJSONKeyFunction [Address]
$cfromJSONKeyList :: FromJSONKeyFunction [Address]
fromJSONKey :: FromJSONKeyFunction Address
$cfromJSONKey :: FromJSONKeyFunction Address
FromJSONKey, [Address] -> Encoding
Address -> Encoding
(Address -> Encoding)
-> (forall s. Decoder s Address)
-> ([Address] -> Encoding)
-> (forall s. Decoder s [Address])
-> Serialise Address
forall s. Decoder s [Address]
forall s. Decoder s Address
forall a.
(a -> Encoding)
-> (forall s. Decoder s a)
-> ([a] -> Encoding)
-> (forall s. Decoder s [a])
-> Serialise a
decodeList :: Decoder s [Address]
$cdecodeList :: forall s. Decoder s [Address]
encodeList :: [Address] -> Encoding
$cencodeList :: [Address] -> Encoding
decode :: Decoder s Address
$cdecode :: forall s. Decoder s Address
encode :: Address -> Encoding
$cencode :: Address -> Encoding
Serialise, Int -> Address -> Int
Address -> Int
(Int -> Address -> Int) -> (Address -> Int) -> Hashable Address
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Address -> Int
$chash :: Address -> Int
hashWithSalt :: Int -> Address -> Int
$chashWithSalt :: Int -> Address -> Int
Hashable, Address -> ()
(Address -> ()) -> NFData Address
forall a. (a -> ()) -> NFData a
rnf :: Address -> ()
$crnf :: Address -> ()
NFData)

instance Pretty Address where
    pretty :: Address -> Doc ann
pretty (Address Credential
cred Maybe StakingCredential
stakingCred) =
        let staking :: Doc ann
staking = Doc ann
-> (StakingCredential -> Doc ann)
-> Maybe StakingCredential
-> Doc ann
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Doc ann
"no staking credential" StakingCredential -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Maybe StakingCredential
stakingCred in
        Credential -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Credential
cred Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
parens Doc ann
forall ann. Doc ann
staking

instance PlutusTx.Eq Address where
    {-# INLINABLE (==) #-}
    Address Credential
cred Maybe StakingCredential
stakingCred == :: Address -> Address -> Bool
== Address Credential
cred' Maybe StakingCredential
stakingCred' =
        Credential
cred Credential -> Credential -> Bool
forall a. Eq a => a -> a -> Bool
PlutusTx.== Credential
cred'
        Bool -> Bool -> Bool
PlutusTx.&& Maybe StakingCredential
stakingCred Maybe StakingCredential -> Maybe StakingCredential -> Bool
forall a. Eq a => a -> a -> Bool
PlutusTx.== Maybe StakingCredential
stakingCred'

{-# INLINABLE pubKeyHashAddress #-}
-- | The address that should be targeted by a transaction output locked by the public key with the given hash.
pubKeyHashAddress :: PubKeyHash -> Address
pubKeyHashAddress :: PubKeyHash -> Address
pubKeyHashAddress PubKeyHash
pkh = Credential -> Maybe StakingCredential -> Address
Address (PubKeyHash -> Credential
PubKeyCredential PubKeyHash
pkh) Maybe StakingCredential
forall a. Maybe a
Nothing

{-# INLINABLE toPubKeyHash #-}
-- | The PubKeyHash of the address, if any
toPubKeyHash :: Address -> Maybe PubKeyHash
toPubKeyHash :: Address -> Maybe PubKeyHash
toPubKeyHash (Address (PubKeyCredential PubKeyHash
k) Maybe StakingCredential
_) = PubKeyHash -> Maybe PubKeyHash
forall a. a -> Maybe a
Just PubKeyHash
k
toPubKeyHash Address
_                                = Maybe PubKeyHash
forall a. Maybe a
Nothing

{-# INLINABLE toValidatorHash #-}
-- | The validator hash of the address, if any
toValidatorHash :: Address -> Maybe ValidatorHash
toValidatorHash :: Address -> Maybe ValidatorHash
toValidatorHash (Address (ScriptCredential ValidatorHash
k) Maybe StakingCredential
_) = ValidatorHash -> Maybe ValidatorHash
forall a. a -> Maybe a
Just ValidatorHash
k
toValidatorHash Address
_                                = Maybe ValidatorHash
forall a. Maybe a
Nothing

{-# INLINABLE scriptHashAddress #-}
-- | The address that should be used by a transaction output locked by the given validator script hash.
scriptHashAddress :: ValidatorHash -> Address
scriptHashAddress :: ValidatorHash -> Address
scriptHashAddress ValidatorHash
vh = Credential -> Maybe StakingCredential -> Address
Address (ValidatorHash -> Credential
ScriptCredential ValidatorHash
vh) Maybe StakingCredential
forall a. Maybe a
Nothing

{-# INLINABLE stakingCredential #-}
-- | The staking credential of an address (if any)
stakingCredential :: Address -> Maybe StakingCredential
stakingCredential :: Address -> Maybe StakingCredential
stakingCredential (Address Credential
_ Maybe StakingCredential
s) = Maybe StakingCredential
s

PlutusTx.makeIsDataIndexed ''Address [('Address,0)]
PlutusTx.makeLift ''Address