-- | Things related to the Hydra smart contracts / script validators.
module Hydra.Contract where

import Hydra.Prelude

import Codec.Serialise (serialise)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as BSL
import Hydra.Cardano.Api (
  PlutusScriptVersion (PlutusScriptV3),
  ScriptHash,
  fromPlutusScript,
  hashScript,
  pattern PlutusScript,
 )
import Hydra.Cardano.Api.Prelude qualified as Api
import Hydra.Contract.Deposit qualified as Deposit
import Hydra.Contract.Head qualified as Head
import Hydra.Contract.HeadTokens qualified as HeadTokens
import Hydra.Plutus (commitValidatorScript, initialValidatorScript)
import PlutusLedgerApi.V3 (TxId (..), TxOutRef (..), toBuiltin)

-- | Information about relevant Hydra scripts.
data ScriptInfo = ScriptInfo
  { ScriptInfo -> ScriptHash
mintingScriptHash :: ScriptHash
  -- ^ Hash of the μHead minting script given some default parameters.
  , ScriptInfo -> Int64
mintingScriptSize :: Int64
  -- ^ Size of the μHead minting script given some default parameters.
  , ScriptInfo -> ScriptHash
initialScriptHash :: ScriptHash
  , ScriptInfo -> Int64
initialScriptSize :: Int64
  , ScriptInfo -> ScriptHash
commitScriptHash :: ScriptHash
  , ScriptInfo -> Int64
commitScriptSize :: Int64
  , ScriptInfo -> ScriptHash
headScriptHash :: ScriptHash
  , ScriptInfo -> Int64
headScriptSize :: Int64
  , ScriptInfo -> ScriptHash
depositScriptHash :: ScriptHash
  , ScriptInfo -> Int64
depositScriptSize :: Int64
  }
  deriving stock (ScriptInfo -> ScriptInfo -> Bool
(ScriptInfo -> ScriptInfo -> Bool)
-> (ScriptInfo -> ScriptInfo -> Bool) -> Eq ScriptInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ScriptInfo -> ScriptInfo -> Bool
== :: ScriptInfo -> ScriptInfo -> Bool
$c/= :: ScriptInfo -> ScriptInfo -> Bool
/= :: ScriptInfo -> ScriptInfo -> Bool
Eq, Int -> ScriptInfo -> ShowS
[ScriptInfo] -> ShowS
ScriptInfo -> String
(Int -> ScriptInfo -> ShowS)
-> (ScriptInfo -> String)
-> ([ScriptInfo] -> ShowS)
-> Show ScriptInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ScriptInfo -> ShowS
showsPrec :: Int -> ScriptInfo -> ShowS
$cshow :: ScriptInfo -> String
show :: ScriptInfo -> String
$cshowList :: [ScriptInfo] -> ShowS
showList :: [ScriptInfo] -> ShowS
Show, (forall x. ScriptInfo -> Rep ScriptInfo x)
-> (forall x. Rep ScriptInfo x -> ScriptInfo) -> Generic ScriptInfo
forall x. Rep ScriptInfo x -> ScriptInfo
forall x. ScriptInfo -> Rep ScriptInfo x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ScriptInfo -> Rep ScriptInfo x
from :: forall x. ScriptInfo -> Rep ScriptInfo x
$cto :: forall x. Rep ScriptInfo x -> ScriptInfo
to :: forall x. Rep ScriptInfo x -> ScriptInfo
Generic)
  deriving anyclass ([ScriptInfo] -> Value
[ScriptInfo] -> Encoding
ScriptInfo -> Bool
ScriptInfo -> Value
ScriptInfo -> Encoding
(ScriptInfo -> Value)
-> (ScriptInfo -> Encoding)
-> ([ScriptInfo] -> Value)
-> ([ScriptInfo] -> Encoding)
-> (ScriptInfo -> Bool)
-> ToJSON ScriptInfo
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: ScriptInfo -> Value
toJSON :: ScriptInfo -> Value
$ctoEncoding :: ScriptInfo -> Encoding
toEncoding :: ScriptInfo -> Encoding
$ctoJSONList :: [ScriptInfo] -> Value
toJSONList :: [ScriptInfo] -> Value
$ctoEncodingList :: [ScriptInfo] -> Encoding
toEncodingList :: [ScriptInfo] -> Encoding
$comitField :: ScriptInfo -> Bool
omitField :: ScriptInfo -> Bool
ToJSON)

-- | Gather 'ScriptInfo' from the current Hydra scripts. This is useful to
-- determine changes in between version of 'hydra-plutus'.
scriptInfo :: ScriptInfo
scriptInfo :: ScriptInfo
scriptInfo =
  ScriptInfo
    { mintingScriptHash :: ScriptHash
mintingScriptHash = SerialisedScript -> ScriptHash
plutusScriptHash (SerialisedScript -> ScriptHash) -> SerialisedScript -> ScriptHash
forall a b. (a -> b) -> a -> b
$ TxOutRef -> SerialisedScript
HeadTokens.mintingPolicyScript TxOutRef
defaultOutRef
    , mintingScriptSize :: Int64
mintingScriptSize = SerialisedScript -> Int64
scriptSize (SerialisedScript -> Int64) -> SerialisedScript -> Int64
forall a b. (a -> b) -> a -> b
$ TxOutRef -> SerialisedScript
HeadTokens.mintingPolicyScript TxOutRef
defaultOutRef
    , initialScriptHash :: ScriptHash
initialScriptHash = Script PlutusScriptV3 -> ScriptHash
forall lang. Script lang -> ScriptHash
hashScript (Script PlutusScriptV3 -> ScriptHash)
-> Script PlutusScriptV3 -> ScriptHash
forall a b. (a -> b) -> a -> b
$ PlutusScriptVersion PlutusScriptV3
-> PlutusScript PlutusScriptV3 -> Script PlutusScriptV3
forall lang.
PlutusScriptVersion lang -> PlutusScript lang -> Script lang
Api.PlutusScript PlutusScriptVersion PlutusScriptV3
PlutusScriptV3 (PlutusScript PlutusScriptV3 -> Script PlutusScriptV3)
-> PlutusScript PlutusScriptV3 -> Script PlutusScriptV3
forall a b. (a -> b) -> a -> b
$ SerialisedScript -> PlutusScript PlutusScriptV3
forall lang. SerialisedScript -> PlutusScript lang
fromPlutusScript SerialisedScript
initialValidatorScript
    , initialScriptSize :: Int64
initialScriptSize = SerialisedScript -> Int64
scriptSize SerialisedScript
initialValidatorScript
    , commitScriptHash :: ScriptHash
commitScriptHash = Script PlutusScriptV3 -> ScriptHash
forall lang. Script lang -> ScriptHash
hashScript (Script PlutusScriptV3 -> ScriptHash)
-> Script PlutusScriptV3 -> ScriptHash
forall a b. (a -> b) -> a -> b
$ PlutusScriptVersion PlutusScriptV3
-> PlutusScript PlutusScriptV3 -> Script PlutusScriptV3
forall lang.
PlutusScriptVersion lang -> PlutusScript lang -> Script lang
Api.PlutusScript PlutusScriptVersion PlutusScriptV3
PlutusScriptV3 (PlutusScript PlutusScriptV3 -> Script PlutusScriptV3)
-> PlutusScript PlutusScriptV3 -> Script PlutusScriptV3
forall a b. (a -> b) -> a -> b
$ SerialisedScript -> PlutusScript PlutusScriptV3
forall lang. SerialisedScript -> PlutusScript lang
fromPlutusScript SerialisedScript
commitValidatorScript
    , commitScriptSize :: Int64
commitScriptSize = SerialisedScript -> Int64
scriptSize SerialisedScript
commitValidatorScript
    , headScriptHash :: ScriptHash
headScriptHash = SerialisedScript -> ScriptHash
plutusScriptHash SerialisedScript
Head.validatorScript
    , headScriptSize :: Int64
headScriptSize = SerialisedScript -> Int64
scriptSize SerialisedScript
Head.validatorScript
    , depositScriptHash :: ScriptHash
depositScriptHash = SerialisedScript -> ScriptHash
plutusScriptHash SerialisedScript
Deposit.validatorScript
    , depositScriptSize :: Int64
depositScriptSize = SerialisedScript -> Int64
scriptSize SerialisedScript
Deposit.validatorScript
    }
 where
  plutusScriptHash :: SerialisedScript -> ScriptHash
plutusScriptHash =
    Script PlutusScriptV3 -> ScriptHash
forall lang. Script lang -> ScriptHash
hashScript (Script PlutusScriptV3 -> ScriptHash)
-> (SerialisedScript -> Script PlutusScriptV3)
-> SerialisedScript
-> ScriptHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PlutusScript PlutusScriptV3 -> Script PlutusScriptV3
PlutusScript (PlutusScript PlutusScriptV3 -> Script PlutusScriptV3)
-> (SerialisedScript -> PlutusScript PlutusScriptV3)
-> SerialisedScript
-> Script PlutusScriptV3
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SerialisedScript -> PlutusScript PlutusScriptV3
forall lang. SerialisedScript -> PlutusScript lang
fromPlutusScript

  scriptSize :: SerialisedScript -> Int64
scriptSize = ByteString -> Int64
BSL.length (ByteString -> Int64)
-> (SerialisedScript -> ByteString) -> SerialisedScript -> Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SerialisedScript -> ByteString
forall a. Serialise a => a -> ByteString
serialise

  defaultOutRef :: TxOutRef
defaultOutRef =
    TxOutRef
      { txOutRefId :: TxId
txOutRefId = BuiltinByteString -> TxId
TxId (ByteString -> BuiltinByteString
ByteString -> ToBuiltin ByteString
forall a. HasToBuiltin a => a -> ToBuiltin a
toBuiltin (ByteString -> BuiltinByteString)
-> ([Word8] -> ByteString) -> [Word8] -> BuiltinByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
BS.pack ([Word8] -> BuiltinByteString) -> [Word8] -> BuiltinByteString
forall a b. (a -> b) -> a -> b
$ Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
replicate Int
32 Word8
0)
      , txOutRefIdx :: Integer
txOutRefIdx = Integer
0
      }