{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RoleAnnotations #-}
{-# OPTIONS_GHC -Wno-orphans #-}

{- | = Note

The 'Value.PValue', 'AssocMap.PMap' and 'Interval.PInterval'-related
functionality can be found in other modules, as these clash with the
Plutarch prelude. These should be imported qualified.
-}
module Plutarch.LedgerApi.V3 (
  -- * Contexts
  Contexts.PScriptContext (..),
  Contexts.PTxInfo (..),
  Contexts.PScriptInfo (..),
  Contexts.PScriptPurpose (..),

  -- * Tx

  -- ** Types
  V3Tx.PTxOutRef (..),
  V2Tx.PTxOut (..),
  V3Tx.PTxId (..),
  Contexts.PTxInInfo (..),
  V2Tx.POutputDatum (..),

  -- * Script

  -- ** Types
  Scripts.PDatum (..),
  Scripts.PDatumHash (..),
  Scripts.PRedeemer (..),
  Scripts.PRedeemerHash (..),
  Scripts.PScriptHash (..),

  -- ** Functions
  scriptHash,
  datumHash,
  redeemerHash,
  dataHash,

  -- * Value
  Value.PRawValue (..),
  Value.PSortedValue,
  Value.PLedgerValue,
  Value.PCurrencySymbol (..),
  Value.PTokenName (..),
  Value.PLovelace (..),
  MintValue.PMintValue,
  MintValue.pemptyMintValue,
  MintValue.psingletonMintValue,
  MintValue.ptoMintValue,

  -- * Assoc map

  -- ** Types
  AssocMap.PAssocMap (..),
  AssocMap.PUnsortedMap (..),
  AssocMap.PSortedMap,

  -- * Address
  Credential.PCredential (..),
  Credential.PStakingCredential (..),
  Address.PAddress (..),

  -- * Time
  Time.PPosixTime (..),
  Time.pposixTime,
  Time.unPPosixTime,

  -- * Interval
  Interval.PInterval (..),
  Interval.PLowerBound (..),
  Interval.PUpperBound (..),
  Interval.PExtended (..),

  -- * CIP-1694
  Contexts.PTxCert (..),
  Contexts.PDelegatee (..),
  Contexts.PDRepCredential (..),
  Contexts.PColdCommitteeCredential (..),
  Contexts.PHotCommitteeCredential (..),
  Contexts.PDRep (..),
  Contexts.PVoter (..),
  Contexts.PGovernanceActionId (..),
  Contexts.PVote (..),
  Contexts.PProtocolVersion (..),
  Contexts.PProposalProcedure (..),
  Contexts.PGovernanceAction (..),
  Contexts.PChangedParameters (..),
  Contexts.PConstitution (..),
  Contexts.PCommittee (..),

  -- * Crypto

  -- ** Types
  PubKey (..),
  Crypto.PPubKeyHash (..),
  pubKeyHash,

  -- * Utilities

  -- ** Types
  Utils.PMaybeData (..),
  Utils.PRationalData (..),

  -- ** Utilities
  Utils.pfromDJust,
  Utils.pisDJust,
  Utils.pmaybeData,
  Utils.pdjust,
  Utils.pdnothing,
  Utils.pmaybeToMaybeData,
  Utils.passertPDJust,
  Utils.prationalFromData,
) where

import Codec.Serialise (serialise)
import Crypto.Hash (
  Blake2b_224 (Blake2b_224),
  Blake2b_256 (Blake2b_256),
  hashWith,
 )
import Data.ByteArray (convert)
import Data.ByteString (ByteString, toStrict)
import Data.ByteString.Short (fromShort)
import Data.Coerce (coerce)
import Data.Kind (Type)
import Plutarch.LedgerApi.AssocMap qualified as AssocMap
import Plutarch.LedgerApi.Interval qualified as Interval
import Plutarch.LedgerApi.Utils qualified as Utils
import Plutarch.LedgerApi.V1.Address qualified as Address
import Plutarch.LedgerApi.V1.Credential qualified as Credential
import Plutarch.LedgerApi.V1.Crypto qualified as Crypto
import Plutarch.LedgerApi.V1.Scripts qualified as Scripts
import Plutarch.LedgerApi.V1.Time qualified as Time
import Plutarch.LedgerApi.V2.Tx qualified as V2Tx
import Plutarch.LedgerApi.V3.Contexts qualified as Contexts
import Plutarch.LedgerApi.V3.MintValue qualified as MintValue
import Plutarch.LedgerApi.V3.Tx qualified as V3Tx
import Plutarch.LedgerApi.Value qualified as Value
import Plutarch.Script (Script (unScript))
import PlutusLedgerApi.Common (serialiseUPLC)
import PlutusLedgerApi.V3 qualified as Plutus
import PlutusTx.Prelude qualified as PlutusTx

{- | Hash a script, appending the Plutus V2 prefix.

@since 2.0.0
-}
scriptHash :: Script -> Plutus.ScriptHash
scriptHash :: Script -> ScriptHash
scriptHash = ByteString -> Script -> ScriptHash
hashScriptWithPrefix ByteString
"\x02"

-- | @since 2.0.0
newtype PubKey = PubKey
  { PubKey -> LedgerBytes
getPubKey :: Plutus.LedgerBytes
  -- ^ @since 2.0.0
  }
  deriving stock
    ( -- | @since 2.0.0
      PubKey -> PubKey -> Bool
(PubKey -> PubKey -> Bool)
-> (PubKey -> PubKey -> Bool) -> Eq PubKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PubKey -> PubKey -> Bool
== :: PubKey -> PubKey -> Bool
$c/= :: PubKey -> PubKey -> Bool
/= :: PubKey -> PubKey -> Bool
Eq
    , -- | @since 2.0.0
      Eq PubKey
Eq PubKey =>
(PubKey -> PubKey -> Ordering)
-> (PubKey -> PubKey -> Bool)
-> (PubKey -> PubKey -> Bool)
-> (PubKey -> PubKey -> Bool)
-> (PubKey -> PubKey -> Bool)
-> (PubKey -> PubKey -> PubKey)
-> (PubKey -> PubKey -> PubKey)
-> Ord PubKey
PubKey -> PubKey -> Bool
PubKey -> PubKey -> Ordering
PubKey -> PubKey -> PubKey
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
$ccompare :: PubKey -> PubKey -> Ordering
compare :: PubKey -> PubKey -> Ordering
$c< :: PubKey -> PubKey -> Bool
< :: PubKey -> PubKey -> Bool
$c<= :: PubKey -> PubKey -> Bool
<= :: PubKey -> PubKey -> Bool
$c> :: PubKey -> PubKey -> Bool
> :: PubKey -> PubKey -> Bool
$c>= :: PubKey -> PubKey -> Bool
>= :: PubKey -> PubKey -> Bool
$cmax :: PubKey -> PubKey -> PubKey
max :: PubKey -> PubKey -> PubKey
$cmin :: PubKey -> PubKey -> PubKey
min :: PubKey -> PubKey -> PubKey
Ord
    )
  deriving stock
    ( -- | @since 2.0.0
      Int -> PubKey -> ShowS
[PubKey] -> ShowS
PubKey -> String
(Int -> PubKey -> ShowS)
-> (PubKey -> String) -> ([PubKey] -> ShowS) -> Show PubKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PubKey -> ShowS
showsPrec :: Int -> PubKey -> ShowS
$cshow :: PubKey -> String
show :: PubKey -> String
$cshowList :: [PubKey] -> ShowS
showList :: [PubKey] -> ShowS
Show
    )

-- | @since 2.0.0
pubKeyHash :: PubKey -> Plutus.PubKeyHash
pubKeyHash :: PubKey -> PubKeyHash
pubKeyHash = (LedgerBytes -> BuiltinByteString) -> PubKey -> PubKeyHash
forall a b. Coercible a b => a -> b
coerce LedgerBytes -> BuiltinByteString
hashLedgerBytes

-- | @since 2.0.0
datumHash :: Plutus.Datum -> Plutus.DatumHash
datumHash :: Datum -> DatumHash
datumHash = BuiltinByteString -> DatumHash
forall a b. Coercible a b => a -> b
coerce (BuiltinByteString -> DatumHash)
-> (Datum -> BuiltinByteString) -> Datum -> DatumHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Datum -> BuiltinByteString
forall a. ToData a => a -> BuiltinByteString
dataHash

-- | @since 2.0.0
dataHash ::
  forall (a :: Type).
  Plutus.ToData a =>
  a ->
  PlutusTx.BuiltinByteString
dataHash :: forall a. ToData a => a -> BuiltinByteString
dataHash = Data -> BuiltinByteString
hashData (Data -> BuiltinByteString)
-> (a -> Data) -> a -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Data
forall a. ToData a => a -> Data
Plutus.toData

-- | @since 2.0.0
redeemerHash :: Plutus.Redeemer -> Plutus.RedeemerHash
redeemerHash :: Redeemer -> RedeemerHash
redeemerHash = BuiltinByteString -> RedeemerHash
forall a b. Coercible a b => a -> b
coerce (BuiltinByteString -> RedeemerHash)
-> (Redeemer -> BuiltinByteString) -> Redeemer -> RedeemerHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Redeemer -> BuiltinByteString
forall a. ToData a => a -> BuiltinByteString
dataHash

-- Helpers

hashScriptWithPrefix :: ByteString -> Script -> Plutus.ScriptHash
hashScriptWithPrefix :: ByteString -> Script -> ScriptHash
hashScriptWithPrefix ByteString
prefix Script
scr =
  BuiltinByteString -> ScriptHash
Plutus.ScriptHash (BuiltinByteString -> ScriptHash)
-> (ByteString -> BuiltinByteString) -> ByteString -> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> BuiltinByteString
hashBlake2b_224 (ByteString -> ScriptHash) -> ByteString -> ScriptHash
forall a b. (a -> b) -> a -> b
$
    ByteString
prefix ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> (ShortByteString -> ByteString
fromShort (ShortByteString -> ByteString)
-> (Script -> ShortByteString) -> Script -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program DeBruijn DefaultUni DefaultFun () -> ShortByteString
serialiseUPLC (Program DeBruijn DefaultUni DefaultFun () -> ShortByteString)
-> (Script -> Program DeBruijn DefaultUni DefaultFun ())
-> Script
-> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Script -> Program DeBruijn DefaultUni DefaultFun ()
unScript (Script -> ByteString) -> Script -> ByteString
forall a b. (a -> b) -> a -> b
$ Script
scr)

hashLedgerBytes :: Plutus.LedgerBytes -> PlutusTx.BuiltinByteString
hashLedgerBytes :: LedgerBytes -> BuiltinByteString
hashLedgerBytes = ByteString -> BuiltinByteString
hashBlake2b_224 (ByteString -> BuiltinByteString)
-> (LedgerBytes -> ByteString) -> LedgerBytes -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuiltinByteString -> ByteString
BuiltinByteString -> FromBuiltin BuiltinByteString
forall arep. HasFromBuiltin arep => arep -> FromBuiltin arep
PlutusTx.fromBuiltin (BuiltinByteString -> ByteString)
-> (LedgerBytes -> BuiltinByteString) -> LedgerBytes -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LedgerBytes -> BuiltinByteString
Plutus.getLedgerBytes

hashBlake2b_224 :: ByteString -> PlutusTx.BuiltinByteString
hashBlake2b_224 :: ByteString -> BuiltinByteString
hashBlake2b_224 = ByteString -> BuiltinByteString
ByteString -> ToBuiltin ByteString
forall a. HasToBuiltin a => a -> ToBuiltin a
PlutusTx.toBuiltin (ByteString -> BuiltinByteString)
-> (ByteString -> ByteString) -> ByteString -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert @_ @ByteString (Digest Blake2b_224 -> ByteString)
-> (ByteString -> Digest Blake2b_224) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Blake2b_224 -> ByteString -> Digest Blake2b_224
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith Blake2b_224
Blake2b_224

hashBlake2b_256 :: ByteString -> PlutusTx.BuiltinByteString
hashBlake2b_256 :: ByteString -> BuiltinByteString
hashBlake2b_256 = ByteString -> BuiltinByteString
ByteString -> ToBuiltin ByteString
forall a. HasToBuiltin a => a -> ToBuiltin a
PlutusTx.toBuiltin (ByteString -> BuiltinByteString)
-> (ByteString -> ByteString) -> ByteString -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert @_ @ByteString (Digest Blake2b_256 -> ByteString)
-> (ByteString -> Digest Blake2b_256) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Blake2b_256 -> ByteString -> Digest Blake2b_256
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith Blake2b_256
Blake2b_256

hashData :: Plutus.Data -> PlutusTx.BuiltinByteString
hashData :: Data -> BuiltinByteString
hashData = ByteString -> BuiltinByteString
hashBlake2b_256 (ByteString -> BuiltinByteString)
-> (Data -> ByteString) -> Data -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LazyByteString -> ByteString
toStrict (LazyByteString -> ByteString)
-> (Data -> LazyByteString) -> Data -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Data -> LazyByteString
forall a. Serialise a => a -> LazyByteString
serialise