diff --git a/plutus-example/app/create-script-context.hs b/plutus-example/app/create-script-context.hs index 443ba2e5fb..dd4dbe668a 100644 --- a/plutus-example/app/create-script-context.hs +++ b/plutus-example/app/create-script-context.hs @@ -53,8 +53,11 @@ parseScriptContextCmd = parseGenerateDummy <|> parseGenerateTxBody data ScriptContextCmd = GenerateDummyScriptContextRedeemer + --LedgerPlutusVersion TODO: Babbage era. We should + -- parameterize on LedgerPlutusVersion. FilePath | GenerateScriptContextRedeemerTxBody + -- LedgerPlutusVersion FilePath AnyConsensusModeParams NetworkId @@ -62,9 +65,9 @@ data ScriptContextCmd runScriptContextCmd :: ScriptContextCmd -> IO () runScriptContextCmd (GenerateDummyScriptContextRedeemer outFp) = - LB.writeFile outFp sampleTestScriptContextDataJSON + LB.writeFile outFp sampleTestV1ScriptContextDataJSON runScriptContextCmd (GenerateScriptContextRedeemerTxBody txbodyfile cModeParams nid outFp) = do - eTxBodyRedeemer <- runExceptT $ txToRedeemer txbodyfile cModeParams nid + eTxBodyRedeemer <- runExceptT $ createAnyCustomRedeemerBsFromTxFp txbodyfile cModeParams nid case eTxBodyRedeemer of Left err -> error $ "Error creating redeemer from: " <> txbodyfile <> " Error: " <> show err diff --git a/plutus-example/app/plutus-example.hs b/plutus-example/app/plutus-example.hs index e0befb9fae..7445c9f563 100644 --- a/plutus-example/app/plutus-example.hs +++ b/plutus-example/app/plutus-example.hs @@ -6,28 +6,36 @@ import Cardano.Api import System.Directory import System.FilePath.Posix (()) -import PlutusExample.AlwaysFails (alwaysFailsScript) -import PlutusExample.AlwaysSucceeds (alwaysSucceedsScript) -import PlutusExample.CustomDatumRedeemerGuess -import PlutusExample.DatumRedeemerGuess (guessScript, guessScriptStake) -import PlutusExample.Loop (loopScript) -import PlutusExample.MintingScript (apiExamplePlutusMintingScript) -import PlutusExample.ScriptContextChecker -import PlutusExample.Sum (sumScript) +import PlutusExample.PlutusVersion1.AlwaysFails (alwaysFailsScript) +import PlutusExample.PlutusVersion1.AlwaysSucceeds (alwaysSucceedsScript) +import PlutusExample.PlutusVersion1.CustomDatumRedeemerGuess +import PlutusExample.PlutusVersion1.DatumRedeemerGuess (guessScript, guessScriptStake) +import PlutusExample.PlutusVersion1.Loop (loopScript) +import PlutusExample.PlutusVersion1.MintingScript (apiExamplePlutusMintingScript) +import PlutusExample.PlutusVersion1.RedeemerContextScripts +import PlutusExample.PlutusVersion1.Sum (sumScript) + +import PlutusExample.PlutusVersion2.RequireRedeemer (requireRedeemerScript) main :: IO () main = do - let dir = "generated-plutus-scripts" - createDirectory dir - - _ <- writeFileTextEnvelope (dir "always-fails.plutus") Nothing alwaysFailsScript - _ <- writeFileTextEnvelope (dir "always-succeeds-spending.plutus") Nothing alwaysSucceedsScript - _ <- writeFileTextEnvelope (dir "guess-42-datum-42-txin.plutus") Nothing guessScript - _ <- writeFileTextEnvelope (dir "guess-42-stake.plutus") Nothing guessScriptStake - _ <- writeFileTextEnvelope (dir "custom-guess-42-datum-42.plutus") Nothing customGuessScript - _ <- writeFileTextEnvelope (dir "anyone-can-mint.plutus") Nothing apiExamplePlutusMintingScript - _ <- writeFileTextEnvelope (dir "sum.plutus") Nothing sumScript - _ <- writeFileTextEnvelope (dir "loop.plutus") Nothing loopScript - _ <- writeFileTextEnvelope (dir "context-equivalance-test.plutus") Nothing scriptContextCheckScript - _ <- writeFileTextEnvelope (dir "minting-context-equivalance-test.plutus") Nothing customApiExamplePlutusMintingScript + let v1dir = "generated-plutus-scripts/v1" + v2dir = "generated-plutus-scripts/v2" + createDirectoryIfMissing True v1dir + createDirectoryIfMissing True v2dir + + _ <- writeFileTextEnvelope (v1dir "always-fails.plutus") Nothing alwaysFailsScript + _ <- writeFileTextEnvelope (v1dir "always-succeeds-spending.plutus") Nothing alwaysSucceedsScript + _ <- writeFileTextEnvelope (v1dir "guess-42-datum-42-txin.plutus") Nothing guessScript + _ <- writeFileTextEnvelope (v1dir "guess-42-stake.plutus") Nothing guessScriptStake + _ <- writeFileTextEnvelope (v1dir "custom-guess-42-datum-42.plutus") Nothing customGuessScript + _ <- writeFileTextEnvelope (v1dir "anyone-can-mint.plutus") Nothing apiExamplePlutusMintingScript + _ <- writeFileTextEnvelope (v1dir "sum.plutus") Nothing sumScript + _ <- writeFileTextEnvelope (v1dir "loop.plutus") Nothing loopScript + _ <- writeFileTextEnvelope (v1dir "context-equivalance-test.plutus") Nothing scriptContextTextPayingScript + _ <- writeFileTextEnvelope (v1dir "minting-context-equivalance-test.plutus") Nothing scriptContextTestMintingScript + + + _ <- writeFileTextEnvelope (v2dir "required-redeemer.plutus") Nothing requireRedeemerScript + return () diff --git a/plutus-example/plutus-example.cabal b/plutus-example/plutus-example.cabal index 7ea20f5d84..e1226d5af7 100644 --- a/plutus-example/plutus-example.cabal +++ b/plutus-example/plutus-example.cabal @@ -58,14 +58,19 @@ library hs-source-dirs: src - exposed-modules: PlutusExample.AlwaysFails - PlutusExample.AlwaysSucceeds - PlutusExample.CustomDatumRedeemerGuess - PlutusExample.DatumRedeemerGuess - PlutusExample.MintingScript + exposed-modules: PlutusExample.PlutusVersion1.AlwaysFails + PlutusExample.PlutusVersion1.AlwaysSucceeds + PlutusExample.PlutusVersion1.CustomDatumRedeemerGuess + PlutusExample.PlutusVersion1.DatumRedeemerGuess + PlutusExample.PlutusVersion1.Loop + PlutusExample.PlutusVersion1.MintingScript + PlutusExample.PlutusVersion1.RedeemerContextScripts + PlutusExample.PlutusVersion1.Sum + + PlutusExample.PlutusVersion2.RequireRedeemer + PlutusExample.ScriptContextChecker - PlutusExample.Sum - PlutusExample.Loop + build-depends: aeson , bytestring @@ -134,6 +139,7 @@ test-suite plutus-example-test , hedgehog , hedgehog-extras , plutus-example + , plutus-ledger , plutus-ledger-api >= 1.0.0 , tasty , tasty-hedgehog @@ -159,4 +165,3 @@ test-suite plutus-example-test , cardano-cli:cardano-cli , cardano-submit-api:cardano-submit-api , plutus-example:create-script-context - diff --git a/plutus-example/src/PlutusExample/AlwaysFails.hs b/plutus-example/src/PlutusExample/PlutusVersion1/AlwaysFails.hs similarity index 95% rename from plutus-example/src/PlutusExample/AlwaysFails.hs rename to plutus-example/src/PlutusExample/PlutusVersion1/AlwaysFails.hs index af43637fcd..b3549e4e9b 100644 --- a/plutus-example/src/PlutusExample/AlwaysFails.hs +++ b/plutus-example/src/PlutusExample/PlutusVersion1/AlwaysFails.hs @@ -2,7 +2,7 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TemplateHaskell #-} -module PlutusExample.AlwaysFails +module PlutusExample.PlutusVersion1.AlwaysFails ( alwaysFailsScript , alwaysFailsScriptShortBs ) where diff --git a/plutus-example/src/PlutusExample/AlwaysSucceeds.hs b/plutus-example/src/PlutusExample/PlutusVersion1/AlwaysSucceeds.hs similarity index 95% rename from plutus-example/src/PlutusExample/AlwaysSucceeds.hs rename to plutus-example/src/PlutusExample/PlutusVersion1/AlwaysSucceeds.hs index e3c1cd6ed6..fec7574ee0 100644 --- a/plutus-example/src/PlutusExample/AlwaysSucceeds.hs +++ b/plutus-example/src/PlutusExample/PlutusVersion1/AlwaysSucceeds.hs @@ -2,7 +2,7 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TemplateHaskell #-} -module PlutusExample.AlwaysSucceeds +module PlutusExample.PlutusVersion1.AlwaysSucceeds ( alwaysSucceedsScript , alwaysSucceedsScriptShortBs ) where diff --git a/plutus-example/src/PlutusExample/CustomDatumRedeemerGuess.hs b/plutus-example/src/PlutusExample/PlutusVersion1/CustomDatumRedeemerGuess.hs similarity index 96% rename from plutus-example/src/PlutusExample/CustomDatumRedeemerGuess.hs rename to plutus-example/src/PlutusExample/PlutusVersion1/CustomDatumRedeemerGuess.hs index a824d11d03..86b0436178 100644 --- a/plutus-example/src/PlutusExample/CustomDatumRedeemerGuess.hs +++ b/plutus-example/src/PlutusExample/PlutusVersion1/CustomDatumRedeemerGuess.hs @@ -4,7 +4,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -module PlutusExample.CustomDatumRedeemerGuess +module PlutusExample.PlutusVersion1.CustomDatumRedeemerGuess ( MyCustomDatum(..) , MyCustomRedeemer(..) , customGuessScript @@ -50,4 +50,3 @@ customDatumRedeemerGuessScriptAsShortBs = SBS.toShort . LBS.toStrict $ serialise customGuessScript :: PlutusScript PlutusScriptV1 customGuessScript = PlutusScriptSerialised customDatumRedeemerGuessScriptAsShortBs - diff --git a/plutus-example/src/PlutusExample/DatumRedeemerGuess.hs b/plutus-example/src/PlutusExample/PlutusVersion1/DatumRedeemerGuess.hs similarity index 97% rename from plutus-example/src/PlutusExample/DatumRedeemerGuess.hs rename to plutus-example/src/PlutusExample/PlutusVersion1/DatumRedeemerGuess.hs index a2d4392498..a8c39f8293 100644 --- a/plutus-example/src/PlutusExample/DatumRedeemerGuess.hs +++ b/plutus-example/src/PlutusExample/PlutusVersion1/DatumRedeemerGuess.hs @@ -4,7 +4,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -module PlutusExample.DatumRedeemerGuess +module PlutusExample.PlutusVersion1.DatumRedeemerGuess ( guessScript , guessScriptStake , datumRedeemerGuessScriptShortBs diff --git a/plutus-example/src/PlutusExample/Loop.hs b/plutus-example/src/PlutusExample/PlutusVersion1/Loop.hs similarity index 96% rename from plutus-example/src/PlutusExample/Loop.hs rename to plutus-example/src/PlutusExample/PlutusVersion1/Loop.hs index eb5128c84a..0b3de840ab 100644 --- a/plutus-example/src/PlutusExample/Loop.hs +++ b/plutus-example/src/PlutusExample/PlutusVersion1/Loop.hs @@ -4,7 +4,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -module PlutusExample.Loop +module PlutusExample.PlutusVersion1.Loop ( loopScript , loopScriptShortBs ) where diff --git a/plutus-example/src/PlutusExample/MintingScript.hs b/plutus-example/src/PlutusExample/PlutusVersion1/MintingScript.hs similarity index 96% rename from plutus-example/src/PlutusExample/MintingScript.hs rename to plutus-example/src/PlutusExample/PlutusVersion1/MintingScript.hs index df393e8174..375d28e23c 100644 --- a/plutus-example/src/PlutusExample/MintingScript.hs +++ b/plutus-example/src/PlutusExample/PlutusVersion1/MintingScript.hs @@ -5,7 +5,7 @@ {-# LANGUAGE TypeFamilies #-} -module PlutusExample.MintingScript +module PlutusExample.PlutusVersion1.MintingScript ( apiExamplePlutusMintingScript , mintingScriptShortBs ) where @@ -24,7 +24,6 @@ import Plutus.V1.Ledger.Scripts (Script, Validator (Validator), mkMintingPolicyS import PlutusTx qualified import PlutusTx.Prelude hiding (Semigroup (..), unless, (.)) - {- HLINT ignore "Avoid lambda" -} {-# INLINABLE mkPolicy #-} @@ -52,4 +51,3 @@ apiExamplePlutusMintingScript = PlutusScriptSerialised . SBS.toShort $ LB.toStri mintingScriptShortBs :: SBS.ShortByteString mintingScriptShortBs = SBS.toShort . LB.toStrict $ scriptAsCbor - diff --git a/plutus-example/src/PlutusExample/PlutusVersion1/RedeemerContextScripts.hs b/plutus-example/src/PlutusExample/PlutusVersion1/RedeemerContextScripts.hs new file mode 100644 index 0000000000..14a6d9696c --- /dev/null +++ b/plutus-example/src/PlutusExample/PlutusVersion1/RedeemerContextScripts.hs @@ -0,0 +1,207 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module PlutusExample.PlutusVersion1.RedeemerContextScripts + ( PV1CustomRedeemer(..) + , pv1CustomRedeemerFromScriptData + , scriptContextTestMintingScript + , scriptContextTextPayingScript + , testScriptContextToScriptData + ) where + +import Prelude hiding (($)) + +import Cardano.Api +import Cardano.Api.Shelley + +import Codec.Serialise +import Data.ByteString.Lazy qualified as LB +import Data.ByteString.Short qualified as SBS + +import Plutus.Script.Utils.V1.Scripts.MonetaryPolicies as Scripts +import Plutus.Script.Utils.V1.Scripts.Validators as Scripts +import Plutus.V1.Ledger.Api qualified as Plutus +import Plutus.V1.Ledger.Scripts as Scripts +import PlutusTx qualified +import PlutusTx.AssocMap qualified as AMap +import PlutusTx.Prelude hiding (Semigroup (..), unless, (.)) +import PlutusTx.Prelude qualified as P + +-- Description +-- PV1CustomRedeemer mimics the ScriptContext. PV1CustomRedeemer is built via reading +-- the transaction containing the script and the script itself just compares PV1CustomRedeemer +-- to the ScriptContext to be sure they are equivalent. +-- The overall aim is to make sure what is provided via ScriptContext (i.e. the transaction) +-- is what it's supposed to be. We check this by creating PV1CustomRedeemer based on +-- the actual transaction which is created via the create-script-context executable. + + +newtype MyCustomDatum = MyCustomDatum Integer + +data PV1CustomRedeemer + = PV1CustomRedeemer + { mCrOutputs :: [Plutus.TxOut] + , mCrInputs :: [Plutus.TxInInfo] + , mCrMint :: Plutus.Value + , mCrValidRange :: Plutus.POSIXTimeRange + , mCrFee :: Plutus.Value + , mCrDatums :: [(Plutus.DatumHash, Plutus.Datum)] + , mCrCerts :: [Plutus.DCert] + , mCrSignatories :: [Plutus.PubKeyHash] + , mCrScriptPurpose :: Maybe Plutus.ScriptPurpose + } deriving (Prelude.Eq, Show) + +PlutusTx.unstableMakeIsData ''MyCustomDatum +PlutusTx.unstableMakeIsData ''PV1CustomRedeemer + +{-# INLINABLE mkValidator #-} +mkValidator :: MyCustomDatum-> PV1CustomRedeemer -> Plutus.ScriptContext -> Bool +mkValidator _datum (PV1CustomRedeemer txouts txins minted txValidRange _fee datumsAndHashes certs signatories mPurpose) scriptContext = + -- Minted field is equivalent + Plutus.txInfoMint txInfo P.== minted P.&& + -- Validity range is equivalent + Plutus.txInfoValidRange txInfo P.== txValidRange P.&& + -- Datums and datum hashes are equivalent + Plutus.txInfoData txInfo P.== datumsAndHashes P.&& + -- Required tx signers are equivalent + Plutus.txInfoSignatories txInfo P.== signatories P.&& + -- Payment tx out is equivalent + AMap.member paymentOutputFromRedeemer scriptContextOutputsMap P.&& + -- Txins are equivalent + (AMap.member txinA scriptContextTxinsMap P.&& AMap.member txinB scriptContextTxinsMap) P.&& + -- Check if tx inputs are equivalent + AMap.member singleRedeemerCert scriptContextCertsMap P.&& + -- Check if the script purposes are equivalent + case mPurpose of + Just sPurp -> sPurp P.== sPurpose + Nothing -> PlutusTx.Prelude.error () + where + scriptContextCertsMap :: AMap.Map Plutus.DCert Integer + scriptContextCertsMap = AMap.fromList P.$ P.zip (Plutus.txInfoDCert txInfo) [1] + + singleRedeemerCert :: Plutus.DCert + singleRedeemerCert = P.head certs + + txinA :: Plutus.TxInInfo + txinA = P.head redeemerTxins + + txinB :: Plutus.TxInInfo + txinB = P.head $ P.reverse redeemerTxins + + redeemerTxins :: [Plutus.TxInInfo] + redeemerTxins = txins + + scriptContextTxins :: [Plutus.TxInInfo] + scriptContextTxins = Plutus.txInfoInputs txInfo + + scriptContextTxinsMap :: AMap.Map Plutus.TxInInfo Integer + scriptContextTxinsMap = AMap.fromList P.$ P.zip scriptContextTxins [1,2 :: Integer] + + -- This is paid to the dummy address. We can't compute the change address amount + -- because the redeemer we computed is based on an older tx which affects the fee + -- and therefore the change address amount. + paymentOutputFromRedeemer :: Plutus.Value + paymentOutputFromRedeemer = P.head $ P.reverse redeemerValues + + redeemerValues :: [Plutus.Value] + redeemerValues = P.map Plutus.txOutValue txouts + + scriptContextOutputValues :: [Plutus.Value] + scriptContextOutputValues = P.map Plutus.txOutValue $ Plutus.txInfoOutputs txInfo + + scriptContextOutputsMap :: AMap.Map Plutus.Value Integer + scriptContextOutputsMap = AMap.fromList P.$ P.zip scriptContextOutputValues [1,2 :: Integer] + + txInfo :: Plutus.TxInfo + txInfo = Plutus.scriptContextTxInfo scriptContext + + sPurpose :: Plutus.ScriptPurpose + sPurpose = Plutus.scriptContextPurpose scriptContext + +validator :: Plutus.Validator +validator = Plutus.mkValidatorScript + $$(PlutusTx.compile [|| wrap ||]) + where + wrap = Scripts.mkUntypedValidator mkValidator + +plutusV1RedeemerContextTestScript :: Plutus.Script +plutusV1RedeemerContextTestScript = Plutus.unValidatorScript validator + +pv1RedeemerContextTestScriptBs :: SBS.ShortByteString +pv1RedeemerContextTestScriptBs = SBS.toShort . LB.toStrict $ serialise plutusV1RedeemerContextTestScript + +scriptContextTextPayingScript :: PlutusScript PlutusScriptV1 +scriptContextTextPayingScript = PlutusScriptSerialised pv1RedeemerContextTestScriptBs + + +-- Minting script that checks the minting value, validty interval and +-- required signers in the ScriptContext is equivalent to what's in the +-- redeemer. + +{-# INLINABLE mkPolicy #-} +mkPolicy :: PV1CustomRedeemer -> Plutus.ScriptContext -> Bool +mkPolicy (PV1CustomRedeemer _ _ minted txValidRange _fee _ _ signatories mPurpose) scriptContext = + -- Minted value is equivalent + minted P.== Plutus.txInfoMint txInfo P.&& + -- Validity range is equivalent + Plutus.txInfoValidRange txInfo P.== txValidRange P.&& + -- Required signers are equivalent + AMap.member singleSignatory scriptContextSignatoriesMap P.&& + + case mPurpose of + Just sPurp -> sPurp P.== sPurpose + Nothing -> PlutusTx.Prelude.error () + where + sPurpose :: Plutus.ScriptPurpose + sPurpose = Plutus.scriptContextPurpose scriptContext + + scriptContextSignatoriesMap :: AMap.Map Plutus.PubKeyHash Integer + scriptContextSignatoriesMap = AMap.fromList P.$ P.zip (Plutus.txInfoSignatories txInfo) [1] + + singleSignatory :: Plutus.PubKeyHash + singleSignatory = P.head signatories + + txInfo :: Plutus.TxInfo + txInfo = Plutus.scriptContextTxInfo scriptContext + +mintingScriptContextTextPolicy :: Scripts.MintingPolicy +mintingScriptContextTextPolicy = Plutus.mkMintingPolicyScript + $$(PlutusTx.compile [|| wrap ||]) + where + wrap = Scripts.mkUntypedMintingPolicy mkPolicy + +plutusV1RedeemerContextTestMintingScript :: Plutus.Script +plutusV1RedeemerContextTestMintingScript = + Plutus.unMintingPolicyScript mintingScriptContextTextPolicy + +scriptContextTextMintingValidator :: Plutus.Validator +scriptContextTextMintingValidator = + Plutus.Validator plutusV1RedeemerContextTestMintingScript + +scriptContextTextMintingScript :: LB.ByteString +scriptContextTextMintingScript = serialise scriptContextTextMintingValidator + +scriptContextTestMintingScript :: PlutusScript PlutusScriptV1 +scriptContextTestMintingScript = PlutusScriptSerialised . SBS.toShort $ LB.toStrict scriptContextTextMintingScript + +-- Helpers + +testScriptContextToScriptData :: PV1CustomRedeemer -> ScriptData +testScriptContextToScriptData = fromPlutusData . PlutusTx.builtinDataToData . PlutusTx.toBuiltinData + +pv1CustomRedeemerFromScriptData :: ScriptData -> Either String PV1CustomRedeemer +pv1CustomRedeemerFromScriptData sDat = + let bIData = PlutusTx.dataToBuiltinData $ toPlutusData sDat + in case PlutusTx.fromBuiltinData bIData of + Just mCRedeem -> Right mCRedeem + Nothing -> Left "Could not decode PV1CustomRedeemer from ScriptData" diff --git a/plutus-example/src/PlutusExample/Sum.hs b/plutus-example/src/PlutusExample/PlutusVersion1/Sum.hs similarity index 97% rename from plutus-example/src/PlutusExample/Sum.hs rename to plutus-example/src/PlutusExample/PlutusVersion1/Sum.hs index c1b385be22..7ae30157fa 100644 --- a/plutus-example/src/PlutusExample/Sum.hs +++ b/plutus-example/src/PlutusExample/PlutusVersion1/Sum.hs @@ -8,7 +8,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -module PlutusExample.Sum +module PlutusExample.PlutusVersion1.Sum where import Prelude hiding (($), (+), (-), (==)) diff --git a/plutus-example/src/PlutusExample/PlutusVersion2/RequireRedeemer.hs b/plutus-example/src/PlutusExample/PlutusVersion2/RequireRedeemer.hs new file mode 100644 index 0000000000..c63d357d75 --- /dev/null +++ b/plutus-example/src/PlutusExample/PlutusVersion2/RequireRedeemer.hs @@ -0,0 +1,59 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE TemplateHaskell #-} + +module PlutusExample.PlutusVersion2.RequireRedeemer + ( requireRedeemerScript + , requireRedeemerScriptShortBs + ) where + +import Cardano.Api.Shelley (PlutusScript (..), PlutusScriptV2) +import Prelude hiding (($), (&&)) + +import Codec.Serialise +import Data.ByteString.Lazy qualified as LBS +import Data.ByteString.Short qualified as SBS + +import Plutus.Script.Utils.V2.Scripts.Validators as Scripts +import Plutus.V2.Ledger.Api qualified as Plutus +import Plutus.V2.Ledger.Contexts as V2 +import PlutusTx qualified +import PlutusTx.Builtins +import PlutusTx.Eq as PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..), unless, (.)) +import PlutusTx.Prelude qualified as PlutusPrelude + +-- serialiseData is a PlutusV2 builtin + +{-# INLINABLE mkValidator #-} +mkValidator :: BuiltinData -> BuiltinData -> V2.ScriptContext -> Bool +mkValidator _ redeemer sc = + serialiseData redeemer PlutusTx./= emptyByteString && + PlutusPrelude.isJust (PlutusPrelude.find + (PlutusTx.== Plutus.OutputDatum (Plutus.Datum $ PlutusTx.toBuiltinData (42 :: Integer))) + txinsDatums) && + PlutusPrelude.isJust (PlutusPrelude.find + (PlutusTx.== Plutus.OutputDatum (Plutus.Datum $ PlutusTx.toBuiltinData (42 :: Integer))) + referenceInputDatums) + where + txInfo = V2.scriptContextTxInfo sc + txinsDatums = PlutusPrelude.map (txOutDatum . txInInfoResolved) + $ V2.txInfoInputs txInfo + referenceInputDatums = + PlutusPrelude.map (txOutDatum . txInInfoResolved) + $ V2.txInfoReferenceInputs txInfo + +validator :: Plutus.Validator +validator = Plutus.mkValidatorScript + $$(PlutusTx.compile [|| wrap ||]) + where + wrap = Scripts.mkUntypedValidator mkValidator + +script :: Plutus.Script +script = Plutus.unValidatorScript validator + +requireRedeemerScriptShortBs :: SBS.ShortByteString +requireRedeemerScriptShortBs = SBS.toShort . LBS.toStrict $ serialise script + +requireRedeemerScript :: PlutusScript PlutusScriptV2 +requireRedeemerScript = PlutusScriptSerialised requireRedeemerScriptShortBs diff --git a/plutus-example/src/PlutusExample/ScriptContextChecker.hs b/plutus-example/src/PlutusExample/ScriptContextChecker.hs index 31e72b5ec0..1ad7ad34cc 100644 --- a/plutus-example/src/PlutusExample/ScriptContextChecker.hs +++ b/plutus-example/src/PlutusExample/ScriptContextChecker.hs @@ -21,18 +21,15 @@ import Cardano.Api.Byron import Cardano.Api.Shelley import Cardano.Api.Shelley qualified as Api -import Codec.Serialise import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Except.Extra import Data.Aeson qualified as Aeson import Data.Bifunctor (first) import Data.ByteString.Lazy qualified as LB -import Data.ByteString.Short qualified as SBS import Data.Either as E import Data.Map.Strict qualified as Map import Data.Sequence.Strict qualified as Seq import Data.Set qualified as Set -import GHC.Records (HasField (..)) import Cardano.CLI.Environment import Cardano.CLI.Shelley.Run.Query @@ -42,7 +39,6 @@ import Cardano.Ledger.Alonzo.PlutusScriptApi qualified as Alonzo import Cardano.Ledger.Alonzo.Tx qualified as Alonzo import Cardano.Ledger.Alonzo.TxInfo qualified as Alonzo import Cardano.Ledger.Alonzo.TxWitness qualified as Alonzo -import Cardano.Ledger.BaseTypes (ProtVer) import Cardano.Ledger.TxIn qualified as Ledger import Cardano.Ledger.Crypto (StandardCrypto) @@ -52,172 +48,24 @@ import Control.Monad.Trans.Except import Ouroboros.Consensus.HardFork.Combinator.AcrossEras qualified as Consensus import Ouroboros.Consensus.HardFork.History qualified as Consensus import Ouroboros.Network.Protocol.LocalStateQuery.Type (AcquireFailure) -import Plutus.Script.Utils.V1.Scripts qualified as Scripts import Plutus.V1.Ledger.Api qualified as Plutus import PlutusTx qualified -import PlutusTx.AssocMap qualified as AMap import PlutusTx.IsData.Class -import PlutusTx.Prelude hiding (Semigroup (..), unless, (.)) -import PlutusTx.Prelude qualified as P - --- Description --- MyCustomRedeemer mimics the ScriptContext. MyCustomRedeemer is built via reading --- the transaction containing the script and the script itself just compares MyCustomRedeemer --- to the ScriptContext to be sure they are equivalent. --- The overall aim is to make sure what is provided via ScriptContext (i.e. the transaction) --- is what it's supposed to be. We check this by creating MyCustomRedeemer based on --- the actual transaction which is created via the create-script-context executable. - -newtype MyCustomDatum = MyCustomDatum Integer - -data MyCustomRedeemer - = MyCustomRedeemer - { mCrOutputs :: [Plutus.TxOut] - , mCrInputs :: [Plutus.TxInInfo] - , mCrMint :: Plutus.Value - , mCrValidRange :: Plutus.POSIXTimeRange - , mCrFee :: Plutus.Value - , mCrDatums :: [(Plutus.DatumHash, Plutus.Datum)] - , mCrCerts :: [Plutus.DCert] - , mCrSignatories :: [Plutus.PubKeyHash] - , mCrScriptPurpose :: Maybe Plutus.ScriptPurpose - } deriving (Prelude.Eq, Show) - -PlutusTx.unstableMakeIsData ''MyCustomDatum -PlutusTx.unstableMakeIsData ''MyCustomRedeemer - -{-# INLINABLE mkValidator #-} -mkValidator :: MyCustomDatum-> MyCustomRedeemer -> Plutus.ScriptContext -> Bool -mkValidator _datum (MyCustomRedeemer txouts txins minted txValidRange _fee datumsAndHashes certs signatories mPurpose) scriptContext = - -- Minted field is equivalent - Plutus.txInfoMint txInfo P.== minted P.&& - -- Validity range is equivalent - Plutus.txInfoValidRange txInfo P.== txValidRange P.&& - -- Datums and datum hashes are equivalent - Plutus.txInfoData txInfo P.== datumsAndHashes P.&& - -- Required tx signers are equivalent - Plutus.txInfoSignatories txInfo P.== signatories P.&& - -- Payment tx out is equivalent - AMap.member paymentOutputFromRedeemer scriptContextOutputsMap P.&& - -- Txins are equivalent - (AMap.member txinA scriptContextTxinsMap P.&& AMap.member txinB scriptContextTxinsMap) P.&& - -- Check if tx inputs are equivalent - AMap.member singleRedeemerCert scriptContextCertsMap P.&& - -- Check if the script purposes are equivalent - case mPurpose of - Just sPurp -> sPurp P.== sPurpose - Nothing -> PlutusTx.Prelude.error () - where - scriptContextCertsMap :: AMap.Map Plutus.DCert Integer - scriptContextCertsMap = AMap.fromList P.$ P.zip (Plutus.txInfoDCert txInfo) [1] - - singleRedeemerCert :: Plutus.DCert - singleRedeemerCert = P.head certs - - txinA :: Plutus.TxInInfo - txinA = P.head redeemerTxins - - txinB :: Plutus.TxInInfo - txinB = P.head $ P.reverse redeemerTxins - - redeemerTxins :: [Plutus.TxInInfo] - redeemerTxins = txins - - scriptContextTxins :: [Plutus.TxInInfo] - scriptContextTxins = Plutus.txInfoInputs txInfo - - scriptContextTxinsMap :: AMap.Map Plutus.TxInInfo Integer - scriptContextTxinsMap = AMap.fromList P.$ P.zip scriptContextTxins [1,2 :: Integer] - - -- This is paid to the dummy address. We can't compute the change address amount - -- because the redeemer we computed is based on an older tx which affects the fee - -- and therefore the change address amount. - paymentOutputFromRedeemer :: Plutus.Value - paymentOutputFromRedeemer = P.head $ P.reverse redeemerValues - - redeemerValues :: [Plutus.Value] - redeemerValues = P.map Plutus.txOutValue txouts - - scriptContextOutputValues :: [Plutus.Value] - scriptContextOutputValues = P.map Plutus.txOutValue $ Plutus.txInfoOutputs txInfo - - scriptContextOutputsMap :: AMap.Map Plutus.Value Integer - scriptContextOutputsMap = AMap.fromList P.$ P.zip scriptContextOutputValues [1,2 :: Integer] - - txInfo :: Plutus.TxInfo - txInfo = Plutus.scriptContextTxInfo scriptContext +import PlutusTx.Prelude hiding (Eq, Semigroup (..), unless, (.)) - sPurpose :: Plutus.ScriptPurpose - sPurpose = Plutus.scriptContextPurpose scriptContext +import PlutusExample.PlutusVersion1.RedeemerContextScripts -validator :: Plutus.Validator -validator = Plutus.mkValidatorScript - $$(PlutusTx.compile [|| wrap ||]) - where - wrap = Scripts.mkUntypedValidator mkValidator -script :: Plutus.Script -script = Plutus.unValidatorScript validator +data AnyCustomRedeemer + = AnyPV1CustomRedeemer PV1CustomRedeemer + deriving (Show, Eq) -scriptContextCheckAsShortBs :: SBS.ShortByteString -scriptContextCheckAsShortBs = SBS.toShort . LB.toStrict $ serialise script - -scriptContextCheckScript :: PlutusScript PlutusScriptV1 -scriptContextCheckScript = PlutusScriptSerialised scriptContextCheckAsShortBs - ------------------------------------------------------- - -sampleTestScriptContextDataJSON :: LB.ByteString -sampleTestScriptContextDataJSON = - Aeson.encode - . scriptDataToJson ScriptDataJsonDetailedSchema - . customRedeemerToScriptData - $ MyCustomRedeemer - dummyTxOuts - dummyTxIns - dummyLedgerVal - dummyPOSIXTimeRange - dummyLedgerVal - dummyDatumHashes - dummyCerts - dummySignatories - dummyScriptPurpose - -customRedeemerToScriptData :: MyCustomRedeemer -> ScriptData -customRedeemerToScriptData cRedeem = +-- We convert our custom redeemer to ScriptData so we can include it +-- in our transaction. +customRedeemerToScriptData :: AnyCustomRedeemer -> ScriptData +customRedeemerToScriptData (AnyPV1CustomRedeemer cRedeem) = fromPlutusData $ PlutusTx.builtinDataToData $ toBuiltinData cRedeem -customRedeemerFromScriptData :: ScriptData -> Either String MyCustomRedeemer -customRedeemerFromScriptData sDat = - let bIData = PlutusTx.dataToBuiltinData $ toPlutusData sDat - in case fromBuiltinData bIData of - Just mCRedeem -> Right mCRedeem - Nothing -> Left "Could not decode MyCustomRedeemer from ScriptData" - -dummyCerts :: [Plutus.DCert] -dummyCerts = [] - -dummyTxIns :: [Plutus.TxInInfo] -dummyTxIns = [] - -dummySignatories :: [Plutus.PubKeyHash] -dummySignatories = [] - -dummyDatumHashes :: [(Plutus.DatumHash, Plutus.Datum)] -dummyDatumHashes = [] - -dummyLedgerVal :: Plutus.Value -dummyLedgerVal = Alonzo.transValue $ toMaryValue Prelude.mempty - -dummyTxOuts :: [Plutus.TxOut] -dummyTxOuts = [] - -dummyPOSIXTimeRange :: Plutus.POSIXTimeRange -dummyPOSIXTimeRange = Plutus.from $ Plutus.POSIXTime 42 - -dummyScriptPurpose :: Maybe Plutus.ScriptPurpose -dummyScriptPurpose = Nothing - data ScriptContextError = NoScriptsInByronEra | NoScriptsInEra | ReadTxBodyError (FileError TextEnvelopeError) @@ -232,16 +80,16 @@ data ScriptContextError = NoScriptsInByronEra | EraMismatch !Consensus.EraMismatch deriving Show -txToCustomRedeemer +createAnyCustomRedeemer :: ShelleyBasedEra era -> ProtocolParameters -> UTxO era -> EpochInfo (Either TransactionValidityError) -> SystemStart -> Api.Tx era - -> Either ScriptContextError MyCustomRedeemer -txToCustomRedeemer _ _ _ _ _ (ByronTx _) = Left NoScriptsInByronEra -txToCustomRedeemer sbe pparams utxo eInfo sStart (ShelleyTx ShelleyBasedEraAlonzo ledgerTx) = do + -> Either ScriptContextError AnyCustomRedeemer +createAnyCustomRedeemer _ _ _ _ _ (ByronTx _) = Left NoScriptsInByronEra +createAnyCustomRedeemer sbe pparams utxo eInfo sStart (ShelleyTx ShelleyBasedEraAlonzo ledgerTx) = do let txBody = Alonzo.body ledgerTx witness = Alonzo.wits ledgerTx Alonzo.TxWitness _ _ _ _ _rdmrs = witness @@ -257,7 +105,6 @@ txToCustomRedeemer sbe pparams utxo eInfo sStart (ShelleyTx ShelleyBasedEraAlonz txfee = Alonzo.transValue . toMaryValue . lovelaceToValue . fromShelleyLovelace $ Alonzo.txfee txBody Alonzo.TxDats datumHashMap = Alonzo.txdats witness datumHashes = Prelude.map Alonzo.transDataPair $ Map.toList datumHashMap - _txid = Alonzo.txInfoId . toShelleyTxId $ getTxIdShelley ShelleyBasedEraAlonzo txBody txcerts = Prelude.map Alonzo.transDCert . seqToList $ Alonzo.txcerts txBody txsignatories = Prelude.map Alonzo.transKeyHash . Set.toList $ Alonzo.reqSignerHashes txBody valRange <- @@ -270,39 +117,25 @@ txToCustomRedeemer sbe pparams utxo eInfo sStart (ShelleyTx ShelleyBasedEraAlonz txins <- if Prelude.all E.isRight eTxIns then return $ E.rights eTxIns else Prelude.error "Tx Ins not all Right" - Right $ MyCustomRedeemer tOuts txins minted valRange txfee datumHashes txcerts txsignatories (Just sPurpose) + Right . AnyPV1CustomRedeemer $ PV1CustomRedeemer tOuts txins minted valRange txfee datumHashes txcerts txsignatories (Just sPurpose) where seqToList (x Seq.:<| rest) = x : seqToList rest seqToList Seq.Empty = [] -txToCustomRedeemer _ _ _ _ _ (ShelleyTx _ _) = Left NoScriptsInEra - - -obtainLedgerEraClassConstraints - :: ShelleyLedgerEra era ~ ledgerera - => ShelleyBasedEra era - -> ( HasField "_protocolVersion" (Alonzo.PParams ledgerera) ProtVer - => a) -> a -obtainLedgerEraClassConstraints ShelleyBasedEraShelley f = f -obtainLedgerEraClassConstraints ShelleyBasedEraAllegra f = f -obtainLedgerEraClassConstraints ShelleyBasedEraMary f = f -obtainLedgerEraClassConstraints ShelleyBasedEraAlonzo f = f -obtainLedgerEraClassConstraints ShelleyBasedEraBabbage f = f - -testScriptContextToScriptData :: MyCustomRedeemer -> ScriptData -testScriptContextToScriptData = fromPlutusData . PlutusTx.builtinDataToData . toBuiltinData +createAnyCustomRedeemer _ _ _ _ _ (ShelleyTx _ _) = Left NoScriptsInEra -readCustomRedeemerFromTx +createAnyCustomRedeemerFromTxFp :: FilePath -> AnyConsensusModeParams -> NetworkId - -> ExceptT ScriptContextError IO MyCustomRedeemer -readCustomRedeemerFromTx fp (AnyConsensusModeParams cModeParams) network = do + -> ExceptT ScriptContextError IO AnyCustomRedeemer +createAnyCustomRedeemerFromTxFp fp (AnyConsensusModeParams cModeParams) network = do InAnyCardanoEra cEra alonzoTx <- firstExceptT ReadTxBodyError . newExceptT $ readFileTextEnvelopeAnyOf [ FromSomeType (AsTx AsAlonzoEra) (InAnyCardanoEra AlonzoEra) + -- TODO: Babbage Era -- Update with Babbage ] fp @@ -343,17 +176,18 @@ readCustomRedeemerFromTx fp (AnyConsensusModeParams cModeParams) network = do cModeParams localNodeConnInfo utxoQinMode - hoistEither $ txToCustomRedeemer sbe pparams + hoistEither $ createAnyCustomRedeemer sbe pparams utxo eInfo sStart alonzoTx _ -> Prelude.error "Please specify --cardano-mode on cli." -txToRedeemer +createAnyCustomRedeemerBsFromTxFp :: FilePath -> AnyConsensusModeParams -> NetworkId -> ExceptT ScriptContextError IO LB.ByteString -txToRedeemer txFp anyCmodeParams nid = do - testScrContext <- readCustomRedeemerFromTx txFp anyCmodeParams nid +createAnyCustomRedeemerBsFromTxFp txFp anyCmodeParams nid = do + AnyPV1CustomRedeemer testScrContext <- createAnyCustomRedeemerFromTxFp txFp anyCmodeParams nid + return . Aeson.encode . scriptDataToJson ScriptDataJsonDetailedSchema $ testScriptContextToScriptData testScrContext @@ -370,54 +204,46 @@ fromPlutusTxId (Plutus.TxId builtInBs) = Just txidHash -> toShelleyTxId txidHash Nothing -> Prelude.error "Could not derserialize txid" --- Minting script that checks the minting value, validty interval and --- required signers in the ScriptContext is equivalent to what's in the --- redeemer. - -{-# INLINABLE mkPolicy #-} -mkPolicy :: MyCustomRedeemer -> Plutus.ScriptContext -> Bool -mkPolicy (MyCustomRedeemer _ _ minted txValidRange _fee _ _ signatories mPurpose) scriptContext = - -- Minted value is equivalent - minted P.== Plutus.txInfoMint txInfo P.&& - -- Validity range is equivalent - Plutus.txInfoValidRange txInfo P.== txValidRange P.&& - -- Required signers are equivalent - AMap.member singleSignatory scriptContextSignatoriesMap P.&& - - case mPurpose of - Just sPurp -> sPurp P.== sPurpose - Nothing -> PlutusTx.Prelude.error () - where - sPurpose :: Plutus.ScriptPurpose - sPurpose = Plutus.scriptContextPurpose scriptContext - scriptContextSignatoriesMap :: AMap.Map Plutus.PubKeyHash Integer - scriptContextSignatoriesMap = AMap.fromList P.$ P.zip (Plutus.txInfoSignatories txInfo) [1] +sampleTestV1ScriptContextDataJSON :: LB.ByteString +sampleTestV1ScriptContextDataJSON = + Aeson.encode + . scriptDataToJson ScriptDataJsonDetailedSchema + . customRedeemerToScriptData + . AnyPV1CustomRedeemer + $ PV1CustomRedeemer + dummyTxOuts + dummyTxIns + dummyLedgerVal + dummyPOSIXTimeRange + dummyLedgerVal + dummyDatumHashes + dummyCerts + dummySignatories + dummyScriptPurpose + - singleSignatory :: Plutus.PubKeyHash - singleSignatory = P.head signatories +dummyCerts :: [Plutus.DCert] +dummyCerts = [] - txInfo :: Plutus.TxInfo - txInfo = Plutus.scriptContextTxInfo scriptContext +dummyTxIns :: [Plutus.TxInInfo] +dummyTxIns = [] -policy :: Scripts.MintingPolicy -policy = Plutus.mkMintingPolicyScript $$(PlutusTx.compile [|| wrap ||]) - where - wrap = Scripts.mkUntypedMintingPolicy mkPolicy +dummySignatories :: [Plutus.PubKeyHash] +dummySignatories = [] -plutusMintingScript :: Plutus.Script -plutusMintingScript = - Plutus.unMintingPolicyScript policy +dummyDatumHashes :: [(Plutus.DatumHash, Plutus.Datum)] +dummyDatumHashes = [] -mintingValidator :: Plutus.Validator -mintingValidator = - Plutus.Validator $ Plutus.unMintingPolicyScript policy +dummyLedgerVal :: Plutus.Value +dummyLedgerVal = Alonzo.transValue $ toMaryValue Prelude.mempty -scriptAsCbor :: LB.ByteString -scriptAsCbor = serialise mintingValidator +dummyTxOuts :: [Plutus.TxOut] +dummyTxOuts = [] -customApiExamplePlutusMintingScript :: PlutusScript PlutusScriptV1 -customApiExamplePlutusMintingScript = PlutusScriptSerialised . SBS.toShort $ LB.toStrict scriptAsCbor +dummyPOSIXTimeRange :: Plutus.POSIXTimeRange +dummyPOSIXTimeRange = Plutus.from $ Plutus.POSIXTime 42 + +dummyScriptPurpose :: Maybe Plutus.ScriptPurpose +dummyScriptPurpose = Nothing -mintingScriptShortBs :: SBS.ShortByteString -mintingScriptShortBs = SBS.toShort . LB.toStrict $ scriptAsCbor diff --git a/plutus-example/test/Test/PlutusExample/Gen.hs b/plutus-example/test/Test/PlutusExample/Gen.hs index 4f91a4d757..bc9a4cc29d 100644 --- a/plutus-example/test/Test/PlutusExample/Gen.hs +++ b/plutus-example/test/Test/PlutusExample/Gen.hs @@ -16,8 +16,9 @@ import Cardano.Ledger.Era qualified as Ledger import Cardano.Ledger.Shelley.UTxO qualified as Ledger import Cardano.Ledger.TxIn qualified as Ledger import Gen.Cardano.Api.Typed -import Plutus.V1.Ledger.Api qualified as Plutus hiding (singleton) -import Plutus.V1.Ledger.Interval qualified as Plutus +import Ledger qualified as Plutus +import Plutus.V1.Ledger.DCert qualified as Plutus +import PlutusExample.PlutusVersion1.RedeemerContextScripts import PlutusExample.ScriptContextChecker import Hedgehog (Gen) @@ -34,18 +35,20 @@ genPlutusTxOut = do Gen.just . return . \case { Right v -> Just v; _ -> Nothing } . Alonzo.txInfoOut $ toShelleyTxOut ShelleyBasedEraAlonzo (toCtxUTxOTxOut alonzoTxOut) -genMyCustomRedeemer :: Gen MyCustomRedeemer +genMyCustomRedeemer :: Gen AnyCustomRedeemer genMyCustomRedeemer = - MyCustomRedeemer - <$> Gen.list (Range.singleton 1) genPlutusTxOut - <*> return mempty --TODO: Investigate why genTxInfoIn generates Nothing - <*> (Alonzo.transValue . toMaryValue <$> genValueForMinting) - <*> genPOSIXTimeRange - <*> (Alonzo.transValue . toMaryValue <$> genValueForTxOut) - <*> genDatumMap - <*> Gen.list (Range.constant 0 2) genPlutusCert - <*> Gen.list (Range.constant 0 2) genReqSigners - <*> return Nothing + AnyPV1CustomRedeemer + <$> ( PV1CustomRedeemer + <$> Gen.list (Range.singleton 1) genPlutusTxOut + <*> return mempty --TODO: Investigate why genTxInfoIn generates Nothing + <*> (Alonzo.transValue . toMaryValue <$> genValueForMinting) + <*> genPOSIXTimeRange + <*> (Alonzo.transValue . toMaryValue <$> genValueForTxOut) + <*> genDatumMap + <*> Gen.list (Range.constant 0 2) genPlutusCert + <*> Gen.list (Range.constant 0 2) genReqSigners + <*> return Nothing + ) genTxInfoIn :: Gen Plutus.TxInInfo genTxInfoIn = do diff --git a/plutus-example/test/Test/PlutusExample/ScriptData.hs b/plutus-example/test/Test/PlutusExample/ScriptData.hs index 78c7f2894b..b83cc820c9 100644 --- a/plutus-example/test/Test/PlutusExample/ScriptData.hs +++ b/plutus-example/test/Test/PlutusExample/ScriptData.hs @@ -11,6 +11,7 @@ import Data.Aeson qualified as Aeson import Hedgehog (Property, forAll, property, tripping, (===)) import Hedgehog.Internal.Property (failWith) +import PlutusExample.PlutusVersion1.RedeemerContextScripts import PlutusExample.ScriptContextChecker import Test.PlutusExample.Gen @@ -21,7 +22,7 @@ prop_ScriptData_MyCustomRedeemer = myCusRedeem <- forAll genMyCustomRedeemer tripping myCusRedeem customRedeemerToScriptData - customRedeemerFromScriptData + (\v -> AnyPV1CustomRedeemer <$> pv1CustomRedeemerFromScriptData v) prop_ScriptData_MyCustomRedeemer_JSON :: Property prop_ScriptData_MyCustomRedeemer_JSON = @@ -35,9 +36,9 @@ prop_ScriptData_MyCustomRedeemer_JSON = Left err -> failWith Nothing $ "Failed to decode script data (scriptDataFromJson): " ++ displayError err Right sDataDecoded -> - case customRedeemerFromScriptData sDataDecoded of + case AnyPV1CustomRedeemer <$> pv1CustomRedeemerFromScriptData sDataDecoded of Left err -> - failWith Nothing $ "Failed to decode custom redeemer(customRedeemerFromScriptData): " ++ err + failWith Nothing $ "Failed to decode custom redeemer(pv1CustomRedeemerFromScriptData): " ++ err Right cusRedDecoded -> do myCusRedeem === cusRedDecoded sData === Aeson.encode