From 4bd0bd4288c4a963bf9f495fe0fe0d0bbc1405cc Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Wed, 21 Sep 2022 08:38:46 +0200 Subject: [PATCH 01/22] Incremental change for datum --- .../Test/ContractModel/DoubleSatisfaction.hs | 4 +-- plutus-contract/test/Spec/Balancing.hs | 11 +++--- plutus-contract/test/Spec/Contract.hs | 6 ++-- .../test/Spec/Contract/TxConstraints.hs | 8 ++--- plutus-contract/test/Spec/ErrorChecking.hs | 4 +-- .../Spec/TxConstraints/MustIncludeDatum.hs | 15 ++++---- .../TxConstraints/MustPayToOtherScript.hs | 15 ++++---- .../TxConstraints/MustPayToPubKeyAddress.hs | 21 ++++++----- .../src/Ledger/Constraints.hs | 2 ++ .../src/Ledger/Constraints/OffChain.hs | 29 +++++++++------ .../src/Ledger/Constraints/OnChain/V1.hs | 7 ++-- .../src/Ledger/Constraints/OnChain/V2.hs | 11 +++--- .../src/Ledger/Constraints/TxConstraints.hs | 36 +++++++++++++------ plutus-ledger-constraints/test/Spec.hs | 2 +- .../src/Ledger/Tx/CardanoAPI/Internal.hs | 18 +++++----- .../src/Ledger/Tx/Constraints/OffChain.hs | 4 +-- 16 files changed, 111 insertions(+), 82 deletions(-) diff --git a/plutus-contract/src/Plutus/Contract/Test/ContractModel/DoubleSatisfaction.hs b/plutus-contract/src/Plutus/Contract/Test/ContractModel/DoubleSatisfaction.hs index faf7f6e150..224d6561b7 100644 --- a/plutus-contract/src/Plutus/Contract/Test/ContractModel/DoubleSatisfaction.hs +++ b/plutus-contract/src/Plutus/Contract/Test/ContractModel/DoubleSatisfaction.hs @@ -343,13 +343,13 @@ doubleSatisfactionCounterexamples dsc = do datum = Datum . mkB $ "" datumEmpty = Datum . mkB $ "" redeemerEmpty = Redeemer . mkB $ "" - withDatumOut = out & outDatumHash .~ toCardanoTxOutDatumInTx (Just datum) + withDatumOut = out & outDatumHash .~ toCardanoTxOutDatumInTx datum -- Creating TxOut is ugly at the moment because we don't use Cardano addresses, values and datum in the -- emulator yet newFakeTxScriptOut = TxOut $ C.TxOut scriptCardanoAddress (C.TxOutValue C.MultiAssetInBabbageEra $ adaToCardanoValue $ Ada.fromValue $ txOutValue out) - (toCardanoTxOutDatumInline $ Just datumEmpty) + (toCardanoTxOutDatumInline datumEmpty) C.ReferenceScriptNone newFakeTxOutRef = TxOutRef { txOutRefId = TxId "very sha 256 hash I promise" , txOutRefIdx = 1 diff --git a/plutus-contract/test/Spec/Balancing.hs b/plutus-contract/test/Spec/Balancing.hs index 9c1660db43..f2d3d023a8 100644 --- a/plutus-contract/test/Spec/Balancing.hs +++ b/plutus-contract/test/Spec/Balancing.hs @@ -14,7 +14,7 @@ import Test.Tasty (TestTree, testGroup) import Ledger qualified import Ledger.Ada qualified as Ada import Ledger.Constraints qualified as L.Constraints -import Ledger.Scripts (unitDatum, unitRedeemer) +import Ledger.Scripts (unitRedeemer) import Ledger.Test import Ledger.Tx.Constraints qualified as Tx.Constraints import Ledger.Value qualified as Value @@ -30,6 +30,9 @@ import PlutusTx qualified import Prelude hiding (not) import Wallet.Emulator qualified as EM +unitDatum :: L.Constraints.OutDatum +unitDatum = L.Constraints.Hashed Ledger.unitDatum + tests :: TestTree tests = testGroup "balancing" @@ -90,15 +93,15 @@ balanceTxnMinAda2 = wallet2Contract :: Contract () EmptySchema ContractError () wallet2Contract = do utxos <- utxosAt someAddress - let txOutRef = case (Map.keys utxos) of + let txOutRef = case Map.keys utxos of (x:_) -> x [] -> error $ "there's no utxo at the address " <> show someAddress - lookups = L.Constraints.unspentOutputs utxos + lookups = L.Constraints.unspentOutputs utxos <> L.Constraints.plutusV1OtherScript someValidator <> L.Constraints.plutusV1MintingPolicy mps constraints = L.Constraints.mustSpendScriptOutput txOutRef unitRedeemer -- spend utxo1 <> L.Constraints.mustPayToOtherScript vHash unitDatum (vB 1) -- 2 ada and 1 B to script - <> L.Constraints.mustPayToOtherScript vHash (Datum $ PlutusTx.toBuiltinData (0 :: Integer)) (vB 1) -- 2 ada and 1 B to script (different datum) + <> L.Constraints.mustPayToOtherScript vHash (L.Constraints.Hashed $ Datum $ PlutusTx.toBuiltinData (0 :: Integer)) (vB 1) -- 2 ada and 1 B to script (different datum) <> L.Constraints.mustMintValue (vL 1) -- 1 L and 2 ada to wallet2 submitTxConfirmed =<< mkTx lookups constraints diff --git a/plutus-contract/test/Spec/Contract.hs b/plutus-contract/test/Spec/Contract.hs index f6cea14be4..4023dbed01 100644 --- a/plutus-contract/test/Spec/Contract.hs +++ b/plutus-contract/test/Spec/Contract.hs @@ -212,7 +212,7 @@ tests = , let c :: Contract [Maybe DatumHash] Schema ContractError () = do let w2PubKeyHash = mockWalletPaymentPubKeyHash w2 - let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash datum (Ada.adaValueOf 10) + let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash (Constraints.Hashed datum) (Ada.adaValueOf 10) tx <- submitTx payment let txOuts = fmap fst $ Ledger.getCardanoTxOutRefs tx -- tell the tx out' datum hash that was specified by 'mustPayWithDatumToPubKey' @@ -232,11 +232,11 @@ tests = -- in case of two transactions with 'mustPayWithDatumToPubKey' , let c1 :: Contract [Maybe DatumHash] Schema ContractError () = do let w2PubKeyHash = mockWalletPaymentPubKeyHash w2 - let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash datum1 (Ada.adaValueOf 10) + let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash (Constraints.Hashed datum1) (Ada.adaValueOf 10) void $ submitTx payment c2 :: Contract [Maybe DatumHash] Schema ContractError () = do let w3PubKeyHash = mockWalletPaymentPubKeyHash w3 - let payment = Constraints.mustPayWithDatumToPubKey w3PubKeyHash datum2 (Ada.adaValueOf 50) + let payment = Constraints.mustPayWithDatumToPubKey w3PubKeyHash (Constraints.Hashed datum2) (Ada.adaValueOf 50) void $ submitTx payment datum1 = Datum $ PlutusTx.toBuiltinData (23 :: Integer) diff --git a/plutus-contract/test/Spec/Contract/TxConstraints.hs b/plutus-contract/test/Spec/Contract/TxConstraints.hs index b5e78a5441..8a64dab650 100644 --- a/plutus-contract/test/Spec/Contract/TxConstraints.hs +++ b/plutus-contract/test/Spec/Contract/TxConstraints.hs @@ -128,7 +128,7 @@ mustReferenceOutputV1ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV1ValidatorAddress lookups = TC.unspentOutputs utxos - tx = TC.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = TC.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> TC.mustSpendPubKeyOutput utxoRefForBalance1 mkTxConstraints @Void lookups tx >>= submitTxConfirmed @@ -152,7 +152,7 @@ mustReferenceOutputTxV1ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV1ValidatorAddress lookups = Tx.Constraints.unspentOutputs utxos - tx = Tx.Constraints.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = Tx.Constraints.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> Tx.Constraints.mustSpendPubKeyOutput utxoRefForBalance1 <> Tx.Constraints.mustUseOutputAsCollateral utxoRefForBalance1 submitTxConfirmed $ mkTx lookups tx @@ -197,7 +197,7 @@ mustReferenceOutputV2ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress lookups = TC.unspentOutputs utxos - tx = TC.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = TC.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> TC.mustSpendPubKeyOutput utxoRefForBalance1 mkTxConstraints @Void lookups tx >>= submitTxConfirmed @@ -221,7 +221,7 @@ mustReferenceOutputTxV2ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress lookups = Tx.Constraints.unspentOutputs utxos - tx = Tx.Constraints.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = Tx.Constraints.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> Tx.Constraints.mustSpendPubKeyOutput utxoRefForBalance1 <> Tx.Constraints.mustUseOutputAsCollateral utxoRefForBalance1 submitTxConfirmed $ mkTx lookups tx diff --git a/plutus-contract/test/Spec/ErrorChecking.hs b/plutus-contract/test/Spec/ErrorChecking.hs index 7cdd5c7216..0a8ce6673d 100644 --- a/plutus-contract/test/Spec/ErrorChecking.hs +++ b/plutus-contract/test/Spec/ErrorChecking.hs @@ -19,7 +19,7 @@ import Data.Row import Test.Tasty import Ledger.Ada qualified as Ada -import Ledger.Constraints (collectFromTheScript, mustPayToOtherScript) +import Ledger.Constraints (OutDatum (Inline), collectFromTheScript, mustPayToOtherScript) import Ledger.Tx (getCardanoTxId) import Ledger.Typed.Scripts qualified as Scripts hiding (validatorHash) import Plutus.Contract as Contract @@ -141,7 +141,7 @@ contract = selectList [failFalseC, failHeadNilC, divZeroC, divZeroTraceC, succes run validator = void $ do let addr = mkValidatorAddress (validatorScript validator) hash = validatorHash (validatorScript validator) - tx = mustPayToOtherScript hash (Datum $ toBuiltinData ()) (Ada.adaValueOf 10) + tx = mustPayToOtherScript hash (Inline $ Datum $ toBuiltinData ()) (Ada.adaValueOf 10) r <- submitTx tx awaitTxConfirmed (getCardanoTxId r) utxos <- utxosAt addr diff --git a/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs b/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs index 97b3c5de24..610b6fb53b 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs @@ -13,12 +13,11 @@ import Test.Tasty (TestTree, testGroup) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints.OffChain qualified as Constraints (plutusV1MintingPolicy, typedValidatorLookups, - unspentOutputs) +import Ledger.Constraints qualified as Constraints (OutDatum (..), collectFromTheScript, mustIncludeDatum, + mustMintValueWithRedeemer, mustPayToOtherScript, mustPayToTheScript, + mustPayWithDatumToPubKey, plutusV1MintingPolicy, + typedValidatorLookups, unspentOutputs) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) -import Ledger.Constraints.TxConstraints qualified as Constraints (collectFromTheScript, mustIncludeDatum, - mustMintValueWithRedeemer, mustPayToOtherScript, - mustPayToTheScript, mustPayWithDatumToPubKey) import Ledger.Tx qualified as Tx import Ledger.Typed.Scripts qualified as Scripts import Plutus.Contract as Con @@ -75,8 +74,8 @@ mustIncludeDatumWhenPayingToScriptContract offChainDatums onChainDatums = do where mustPayToTheScriptAndIncludeDatumsIfUsingOffChainConstraint = if null offChainDatums - then Constraints.mustPayToOtherScript valHash validatorDatum (Ada.lovelaceValueOf 2_000_000) - else mconcat $ fmap (\datum -> Constraints.mustPayToOtherScript valHash validatorDatum (Ada.lovelaceValueOf 2_000_000) <> Constraints.mustIncludeDatum datum) offChainDatums + then Constraints.mustPayToOtherScript valHash (Constraints.Hashed validatorDatum) (Ada.lovelaceValueOf 2_000_000) + else mconcat $ fmap (\datum -> Constraints.mustPayToOtherScript valHash (Constraints.Hashed validatorDatum) (Ada.lovelaceValueOf 2_000_000) <> Constraints.mustIncludeDatum datum) offChainDatums trace :: Contract () Empty ContractError () -> Trace.EmulatorTrace () trace contract = do @@ -165,7 +164,7 @@ mustIncludeDatumToPubKeyAddress = let onChainConstraintDatumsAsRedeemer = Redeemer $ PlutusTx.dataToBuiltinData $ PlutusTx.toData ([validatorDatum] :: [Datum]) contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustIncludeDatumPolicy - tx1 = Constraints.mustPayWithDatumToPubKey (mockWalletPaymentPubKeyHash w1) validatorDatum (Ada.lovelaceValueOf 25_000_000) + tx1 = Constraints.mustPayWithDatumToPubKey (mockWalletPaymentPubKeyHash w1) (Constraints.Hashed validatorDatum) (Ada.lovelaceValueOf 25_000_000) <> Constraints.mustIncludeDatum validatorDatum <> Constraints.mustMintValueWithRedeemer onChainConstraintDatumsAsRedeemer tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index 900510a907..9a1471da3f 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -14,11 +14,11 @@ import Test.Tasty (TestTree, testGroup) import Control.Lens ((&)) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints.OffChain qualified as Constraints (plutusV1MintingPolicy, plutusV1OtherScript, unspentOutputs) +import Ledger.Constraints qualified as Constraints (OutDatum (Hashed), mustMintValueWithRedeemer, mustPayToOtherScript, + mustPayToOtherScriptAddress, + mustSpendScriptOutputWithMatchingDatumAndValue, + plutusV1MintingPolicy, plutusV1OtherScript, unspentOutputs) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) -import Ledger.Constraints.TxConstraints qualified as Constraints (mustMintValueWithRedeemer, mustPayToOtherScript, - mustPayToOtherScriptAddress, - mustSpendScriptOutputWithMatchingDatumAndValue) import Ledger.Generators (someTokenValue) import Ledger.Scripts (ScriptError (EvaluationError)) import Ledger.Test (asRedeemer, someValidator, someValidatorHash) @@ -84,7 +84,7 @@ trace contract = do mustPayToOtherScriptContract :: Value.Value -> Ledger.Redeemer -> Contract () Empty ContractError () mustPayToOtherScriptContract offChainValue onChainConstraint = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy - tx1 = Constraints.mustPayToOtherScript someValidatorHash someDatum offChainValue + tx1 = Constraints.mustPayToOtherScript someValidatorHash (Constraints.Hashed someDatum) offChainValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -145,7 +145,6 @@ successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance = <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx2 <- submitTxConstraintsWith @UnitTest lookups2 tx2 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx2 - in checkPredicateOptions options "Successful use of offchain and onchain mustPayToOtherScript constraint in combination with mustSpendScriptOutputWithMatchingDatumAndValue to spend script's exact token balance" (assertValidatedTransactionCount 2) @@ -202,8 +201,8 @@ instance Scripts.ValidatorTypes UnitTest {-# INLINEABLE mkMustPayToOtherScriptPolicy #-} mkMustPayToOtherScriptPolicy :: ConstraintParams -> Ledger.ScriptContext -> Bool mkMustPayToOtherScriptPolicy t = case t of - MustPayToOtherScript vh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh d v) - MustPayToOtherScriptAddress vh svh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh d v) + MustPayToOtherScript vh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh (Constraints.Hashed d) v) + MustPayToOtherScriptAddress vh svh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh (Constraints.Hashed d) v) mustPayToOtherScriptPolicy :: Scripts.MintingPolicy mustPayToOtherScriptPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index e6bdb98abd..7be0062980 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -13,11 +13,10 @@ import Test.Tasty (TestTree, testGroup) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints.OffChain qualified as Constraints (plutusV1MintingPolicy) +import Ledger.Constraints qualified as Constraints (OutDatum (Hashed), mustMintValueWithRedeemer, mustPayToPubKey, + mustPayToPubKeyAddress, mustPayWithDatumToPubKey, + mustPayWithDatumToPubKeyAddress, plutusV1MintingPolicy) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) -import Ledger.Constraints.TxConstraints qualified as Constraints (mustMintValueWithRedeemer, mustPayToPubKey, - mustPayToPubKeyAddress, mustPayWithDatumToPubKey, - mustPayWithDatumToPubKeyAddress) import Ledger.Scripts (ScriptError (EvaluationError)) import Ledger.Test (asDatum, asRedeemer) import Ledger.Tx qualified as Tx @@ -169,7 +168,7 @@ successfulUseOfMustPayWithDatumToPubKey = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue + tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash (Constraints.Hashed someDatum) adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -185,7 +184,7 @@ successfulUseOfMustPayWithDatumToPubKeyAddress = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -201,7 +200,7 @@ phase2FailureWhenUsingUnexpectedPaymentPubKeyHash = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w1PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w1PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -217,7 +216,7 @@ phase2FailureWhenUsingUnexpectedDatum = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash otherDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -233,7 +232,7 @@ phase2FailureWhenUsingUnexpectedValue = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum (Ada.lovelaceValueOf $ adaAmount + 1) contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -251,8 +250,8 @@ mkMustPayToPubKeyAddressPolicy :: ConstraintParams -> Ledger.ScriptContext -> Bo mkMustPayToPubKeyAddressPolicy t = case t of MustPayToPubKey ppkh v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKey ppkh v) MustPayToPubKeyAddress ppkh spkh v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKeyAddress ppkh spkh v) - MustPayWithDatumToPubKey ppkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh d v) - MustPayWithDatumToPubKeyAddress ppkh spkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh d v) + MustPayWithDatumToPubKey ppkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh (Constraints.Hashed d) v) + MustPayWithDatumToPubKeyAddress ppkh spkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh (Constraints.Hashed d) v) mustPayToPubKeyAddressPolicy :: Scripts.MintingPolicy mustPayToPubKeyAddressPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) diff --git a/plutus-ledger-constraints/src/Ledger/Constraints.hs b/plutus-ledger-constraints/src/Ledger/Constraints.hs index a23f03cdf3..f3c010d2e2 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints.hs @@ -6,6 +6,8 @@ module Ledger.Constraints( , TC.ScriptInputConstraint(..) , TC.ScriptOutputConstraint(..) -- * Defining constraints + , TC.OutDatum(..) + , TC.getOutDatum , TC.mustPayToTheScript , TC.mustPayToPubKey , TC.mustPayToPubKeyAddress diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs index 1d4ecef11f..46de823969 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs @@ -92,12 +92,14 @@ import Ledger.Ada qualified as Ada import Ledger.Address (PaymentPubKey (PaymentPubKey), PaymentPubKeyHash (PaymentPubKeyHash), StakePubKeyHash, pubKeyHashAddress) import Ledger.Address qualified as Address -import Ledger.Constraints.TxConstraints (ScriptInputConstraint (ScriptInputConstraint, icRedeemer, icTxOutRef), +import Ledger.Constraints.TxConstraints (OutDatum (Hashed, Inline), + ScriptInputConstraint (ScriptInputConstraint, icRedeemer, icTxOutRef), ScriptOutputConstraint (ScriptOutputConstraint, ocDatum, ocReferenceScriptHash, ocValue), TxConstraint (MustBeSignedBy, MustHashDatum, MustIncludeDatum, MustMintValue, MustPayToOtherScript, MustPayToPubKeyAddress, MustProduceAtLeast, MustReferenceOutput, MustSatisfyAnyOf, MustSpendAtLeast, MustSpendPubKeyOutput, MustSpendScriptOutput, MustUseOutputAsCollateral, MustValidateIn), TxConstraintFun (MustSpendScriptOutputWithMatchingDatumAndValue), TxConstraintFuns (TxConstraintFuns), - TxConstraints (TxConstraints, txConstraintFuns, txConstraints, txOwnInputs, txOwnOutputs)) + TxConstraints (TxConstraints, txConstraintFuns, txConstraints, txOwnInputs, txOwnOutputs), + getOutDatum) import Ledger.Crypto (pubKeyHash) import Ledger.Index (minAdaTxOut) import Ledger.Orphans () @@ -562,7 +564,7 @@ addOwnOutput ScriptOutputConstraint{ocDatum, ocValue, ocReferenceScriptHash} = d ScriptLookups{slTypedValidator} <- ask inst <- maybe (throwError TypedValidatorMissing) pure slTypedValidator let dsV = Datum (toBuiltinData ocDatum) - pure $ MustPayToOtherScript (Typed.tvValidatorHash inst) Nothing dsV ocReferenceScriptHash ocValue + pure $ MustPayToOtherScript (Typed.tvValidatorHash inst) Nothing (Hashed dsV) ocReferenceScriptHash ocValue data MkTxError = TypeCheckFailed Typed.ConnectionError @@ -702,23 +704,30 @@ processConstraint = \case -- TODO: implement adding reference script -- if datum is presented, add it to 'datumWitnesses' forM_ mdv $ \dv -> do - unbalancedTx . tx . Tx.datumWitnesses . at (P.datumHash dv) ?= dv + let d = getOutDatum dv -- FIXME + unbalancedTx . tx . Tx.datumWitnesses . at (P.datumHash d) ?= d let pv1TxOut = PV1.TxOut { PV1.txOutAddress=pubKeyHashAddress pk skhM , PV1.txOutValue=vl , PV1.txOutDatumHash=Nothing } - let txInDatum = C.toCardanoTxOutDatumInTx mdv + let txInDatum = case mdv of + Nothing -> C.toCardanoTxOutNoDatum + Just (Hashed d) -> C.toCardanoTxOutDatumInTx d + Just (Inline d) -> C.toCardanoTxOutDatumInline d txOut <- toCardanoTxOutWithHashedDatum pv1TxOut <&> outDatumHash .~ txInDatum unbalancedTx . tx . Tx.outputs %= (txOut :) valueSpentOutputs <>= provided vl MustPayToOtherScript vlh svhM dv _refScript vl -> do -- TODO: implement adding reference script let addr = Address.scriptValidatorHashAddress vlh svhM - theHash = P.datumHash dv - pv1script = scriptAddressTxOut addr vl dv - unbalancedTx . tx . Tx.datumWitnesses . at theHash ?= dv - - let txInDatum = C.toCardanoTxOutDatumInTx (Just dv) + d = getOutDatum dv + theHash = P.datumHash d + pv1script = scriptAddressTxOut addr vl d + unbalancedTx . tx . Tx.datumWitnesses . at theHash ?= d + + let txInDatum = case dv of + Hashed _ -> C.toCardanoTxOutDatumInTx d + Inline _ -> C.toCardanoTxOutDatumInline d txScript <- toCardanoTxOutWithHashedDatum pv1script <&> outDatumHash .~ txInDatum unbalancedTx . tx . Tx.outputs %= (txScript :) valueSpentOutputs <>= provided vl diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs index 8d234b7066..7995e1afbb 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs @@ -27,7 +27,8 @@ import Ledger.Constraints.TxConstraints (ScriptInputConstraint (ScriptInputConst TxConstraint (MustBeSignedBy, MustHashDatum, MustIncludeDatum, MustMintValue, MustPayToOtherScript, MustPayToPubKeyAddress, MustProduceAtLeast, MustReferenceOutput, MustSatisfyAnyOf, MustSpendAtLeast, MustSpendPubKeyOutput, MustSpendScriptOutput, MustUseOutputAsCollateral, MustValidateIn), TxConstraintFun (MustSpendScriptOutputWithMatchingDatumAndValue), TxConstraintFuns (TxConstraintFuns), - TxConstraints (TxConstraints, txConstraintFuns, txConstraints, txOwnInputs, txOwnOutputs)) + TxConstraints (TxConstraints, txConstraintFuns, txConstraints, txOwnInputs, txOwnOutputs), + getOutDatum) import Ledger.Credential (Credential (ScriptCredential)) import Ledger.Value qualified as Value import Plutus.V1.Ledger.Address qualified as Address @@ -113,11 +114,11 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case in traceIfFalse "La" -- "MustPayToPubKey" $ vl `leq` V.valuePaidTo scriptContextTxInfo pk - && maybe True (\dv -> any (checkOutput dv) outs) mdv + && maybe True (\dv -> any (checkOutput dv) outs) (fmap getOutDatum mdv) -- FIXME && isNothing refScript MustPayToOtherScript vlh _ dv refScript vl -> let outs = V.txInfoOutputs scriptContextTxInfo - hsh = V.findDatumHash dv scriptContextTxInfo + hsh = V.findDatumHash (getOutDatum dv) scriptContextTxInfo -- FIXME addr = Address.scriptHashAddress vlh checkOutput TxOut{txOutAddress, txOutValue, txOutDatumHash=Just svh} = Ada.fromValue txOutValue >= Ada.fromValue vl diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs index 753d645af6..552b4b8189 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs @@ -23,7 +23,8 @@ import Ledger.Constraints.TxConstraints (ScriptInputConstraint (ScriptInputConst TxConstraint (MustBeSignedBy, MustHashDatum, MustIncludeDatum, MustMintValue, MustPayToOtherScript, MustPayToPubKeyAddress, MustProduceAtLeast, MustReferenceOutput, MustSatisfyAnyOf, MustSpendAtLeast, MustSpendPubKeyOutput, MustSpendScriptOutput, MustUseOutputAsCollateral, MustValidateIn), TxConstraintFun (MustSpendScriptOutputWithMatchingDatumAndValue), TxConstraintFuns (TxConstraintFuns), - TxConstraints (TxConstraints, txConstraintFuns, txConstraints, txOwnInputs, txOwnOutputs)) + TxConstraints (TxConstraints, txConstraintFuns, txConstraints, txOwnInputs, txOwnOutputs), + getOutDatum) import Ledger.Credential (Credential (ScriptCredential)) import Ledger.Value qualified as Value import Plutus.Script.Utils.V2.Contexts qualified as PV2 hiding (findTxInByTxOutRef) @@ -38,7 +39,7 @@ import Plutus.V2.Ledger.Contexts qualified as PV2 import Plutus.V2.Ledger.Tx (OutputDatum (NoOutputDatum, OutputDatum, OutputDatumHash)) import PlutusTx (ToData (toBuiltinData)) import PlutusTx.AssocMap qualified as AMap -import PlutusTx.Prelude (AdditiveSemigroup ((+)), Bool (False, True), Eq ((==)), Maybe (Just, Nothing), +import PlutusTx.Prelude (AdditiveSemigroup ((+)), Bool (False, True), Eq ((==)), Functor (fmap), Maybe (Just, Nothing), Ord ((<=), (>=)), all, any, elem, isJust, maybe, traceIfFalse, ($), (&&), (.), (>>)) {-# INLINABLE checkScriptContext #-} @@ -124,10 +125,10 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case checkOutput _ _ = True in traceIfFalse "La" -- "MustPayToPubKey" - $ vl `leq` PV2.valuePaidTo scriptContextTxInfo pk && any (checkOutput mdv) outs + $ vl `leq` PV2.valuePaidTo scriptContextTxInfo pk && any (checkOutput $ fmap getOutDatum mdv) outs -- FIXME MustPayToOtherScript vlh _skh dv _refScript vl -> let outs = PV2.txInfoOutputs scriptContextTxInfo - hsh = PV2.findDatumHash dv scriptContextTxInfo + hsh = PV2.findDatumHash (getOutDatum dv) scriptContextTxInfo -- FIXME addr = Address (ScriptCredential vlh) Nothing checkOutput TxOut{txOutAddress, txOutValue, txOutDatum=OutputDatumHash dh} = Ada.fromValue txOutValue >= Ada.fromValue vl @@ -139,7 +140,7 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case Ada.fromValue txOutValue >= Ada.fromValue vl && Ada.fromValue txOutValue <= Ada.fromValue vl + Ledger.maxMinAdaTxOut && Value.noAdaValue txOutValue == Value.noAdaValue vl - && dv == id + && getOutDatum dv == id -- FIXME && txOutAddress == addr checkOutput _ = False in diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs index fba29a288e..dbb04dbcef 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs @@ -52,6 +52,20 @@ import Data.Maybe (fromMaybe) import Prelude qualified as Haskell import Prettyprinter.Render.String (renderShowS) +-- | How tx out datum are embedded in a a Tx +data OutDatum = Inline Datum | Hashed Datum + deriving stock (Haskell.Show, Generic, Haskell.Eq) + deriving anyclass (ToJSON, FromJSON) + +getOutDatum :: OutDatum -> Datum +getOutDatum (Hashed d) = d +getOutDatum (Inline d) = d + +instance Pretty OutDatum where + pretty = \case + Inline d -> "inline datum" <+> pretty d + Hashed d -> "hashed datum" <+> pretty d + -- | Constraints on transactions that want to spend script outputs data TxConstraint = MustHashDatum DatumHash Datum @@ -80,9 +94,9 @@ data TxConstraint = -- ^ The transaction must reference (not spend) the given unspent transaction output. | MustMintValue MintingPolicyHash Redeemer TokenName Integer -- ^ The transaction must mint the given token and amount. - | MustPayToPubKeyAddress PaymentPubKeyHash (Maybe StakePubKeyHash) (Maybe Datum) (Maybe ScriptHash) Value + | MustPayToPubKeyAddress PaymentPubKeyHash (Maybe StakePubKeyHash) (Maybe OutDatum) (Maybe ScriptHash) Value -- ^ The transaction must create a transaction output with a public key address. - | MustPayToOtherScript ValidatorHash (Maybe StakeValidatorHash) Datum (Maybe ScriptHash) Value + | MustPayToOtherScript ValidatorHash (Maybe StakeValidatorHash) OutDatum (Maybe ScriptHash) Value -- ^ The transaction must create a transaction output with a script address. | MustSatisfyAnyOf [[TxConstraint]] -- ^ The transaction must satisfy constraints given as an alternative of conjuctions (DNF), @@ -337,7 +351,7 @@ mustPayToPubKeyAddress pkh skh vl = mustPayWithDatumToPubKey :: forall i o . PaymentPubKeyHash - -> Datum + -> OutDatum -> Value -> TxConstraints i o mustPayWithDatumToPubKey pk datum vl = @@ -358,7 +372,7 @@ mustPayWithDatumToPubKeyAddress :: forall i o . PaymentPubKeyHash -> StakePubKeyHash - -> Datum + -> OutDatum -> Value -> TxConstraints i o mustPayWithDatumToPubKeyAddress pkh skh datum vl = @@ -370,7 +384,7 @@ mustPayToAddressWithReferenceValidator :: forall i o . Address -> ValidatorHash - -> Maybe Datum + -> Maybe OutDatum -> Value -> TxConstraints i o mustPayToAddressWithReferenceValidator addr (ValidatorHash vh) = mustPayToAddressWithReferenceScript addr (ScriptHash vh) @@ -381,7 +395,7 @@ mustPayToAddressWithReferenceMintingPolicy :: forall i o . Address -> MintingPolicyHash - -> Maybe Datum + -> Maybe OutDatum -> Value -> TxConstraints i o mustPayToAddressWithReferenceMintingPolicy addr (MintingPolicyHash vh) = mustPayToAddressWithReferenceScript addr (ScriptHash vh) @@ -401,7 +415,7 @@ mustPayToAddressWithReferenceScript :: forall i o . Address -> ScriptHash - -> Maybe Datum + -> Maybe OutDatum -> Value -> TxConstraints i o mustPayToAddressWithReferenceScript @@ -412,17 +426,17 @@ mustPayToAddressWithReferenceScript singleton (MustPayToPubKeyAddress (PaymentPubKeyHash pkh) Nothing datum (Just scriptHash) value) mustPayToAddressWithReferenceScript (Address (ScriptCredential vh) (Just (StakingHash (ScriptCredential (ValidatorHash sh))))) scriptHash datum value = - singleton (MustPayToOtherScript vh (Just (StakeValidatorHash sh)) (fromMaybe unitDatum datum) (Just scriptHash) value) + singleton (MustPayToOtherScript vh (Just (StakeValidatorHash sh)) (fromMaybe (Inline unitDatum) datum) (Just scriptHash) value) mustPayToAddressWithReferenceScript (Address (ScriptCredential vh) Nothing) scriptHash datum value = - singleton (MustPayToOtherScript vh Nothing (fromMaybe unitDatum datum) (Just scriptHash) value) + singleton (MustPayToOtherScript vh Nothing (fromMaybe (Inline unitDatum) datum) (Just scriptHash) value) mustPayToAddressWithReferenceScript addr _ _ _ = Haskell.error $ "Ledger.Constraints.TxConstraints.mustPayToAddressWithReferenceScript: unsupported address " Haskell.++ Haskell.show addr {-# INLINABLE mustPayToOtherScript #-} -- | @mustPayToOtherScript vh d v@ is the same as -- 'mustPayToOtherScriptAddress', but without the staking key hash. -mustPayToOtherScript :: forall i o. ValidatorHash -> Datum -> Value -> TxConstraints i o +mustPayToOtherScript :: forall i o. ValidatorHash -> OutDatum -> Value -> TxConstraints i o mustPayToOtherScript vh dv vl = singleton (MustPayToOtherScript vh Nothing dv Nothing vl) @@ -437,7 +451,7 @@ mustPayToOtherScript vh dv vl = -- If used in 'Ledger.Constraints.OnChain', this constraint verifies that @d@ is -- part of the datum witness set and that the script transaction output with -- @vh@, @svh@, @d@ and @v@ is part of the transaction's outputs. -mustPayToOtherScriptAddress :: forall i o. ValidatorHash -> StakeValidatorHash -> Datum -> Value -> TxConstraints i o +mustPayToOtherScriptAddress :: forall i o. ValidatorHash -> StakeValidatorHash -> OutDatum -> Value -> TxConstraints i o mustPayToOtherScriptAddress vh svh dv vl = singleton (MustPayToOtherScript vh (Just svh) dv Nothing vl) diff --git a/plutus-ledger-constraints/test/Spec.hs b/plutus-ledger-constraints/test/Spec.hs index ff44c05d0d..0c047f4f66 100644 --- a/plutus-ledger-constraints/test/Spec.hs +++ b/plutus-ledger-constraints/test/Spec.hs @@ -137,7 +137,7 @@ mustPayToOtherScriptAddressStakeValidatorHashNotNothingProp :: Property mustPayToOtherScriptAddressStakeValidatorHashNotNothingProp = property $ do pkh <- forAll $ Ledger.paymentPubKeyHash <$> Gen.element Gen.knownPaymentPublicKeys let svh = Ledger.StakeValidatorHash $ examplePlutusScriptAlwaysSucceedsHash WitCtxStake - txE = Constraints.mkTx @Void mempty (Constraints.mustPayToOtherScriptAddress alwaysSucceedValidatorHash svh Ledger.unitDatum (Ada.toValue Ledger.minAdaTxOut)) + txE = Constraints.mkTx @Void mempty (Constraints.mustPayToOtherScriptAddress alwaysSucceedValidatorHash svh (Constraints.Inline Ledger.unitDatum) (Ada.toValue Ledger.minAdaTxOut)) case txE of Left err -> do Hedgehog.annotateShow err diff --git a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs index 828f3a96e4..366df911bb 100644 --- a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs +++ b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs @@ -48,6 +48,7 @@ module Ledger.Tx.CardanoAPI.Internal( , toCardanoTxOutDatumHash , toCardanoTxOutDatumInline , toCardanoTxOutDatumInTx + , toCardanoTxOutNoDatum , toCardanoTxOutValue , toCardanoAddressInEra , toCardanoValue @@ -516,15 +517,16 @@ fromCardanoTxOutDatum (C.TxOutDatumHash _ h) = PV2.OutputDatumHash $ PV2.DatumHa fromCardanoTxOutDatum (C.TxOutDatumInTx _ d) = PV2.OutputDatum $ PV2.Datum $ fromCardanoScriptData d fromCardanoTxOutDatum (C.TxOutDatumInline _ d) = PV2.OutputDatum $ PV2.Datum $ fromCardanoScriptData d -toCardanoTxOutDatumInTx :: Maybe PV2.Datum -> C.TxOutDatum C.CtxTx C.BabbageEra -toCardanoTxOutDatumInTx Nothing = C.TxOutDatumNone -toCardanoTxOutDatumInTx (Just d) = - C.TxOutDatumInTx C.ScriptDataInBabbageEra . C.fromPlutusData . PV2.builtinDataToData . PV2.getDatum $ d +toCardanoTxOutNoDatum :: C.TxOutDatum C.CtxTx C.BabbageEra +toCardanoTxOutNoDatum = C.TxOutDatumNone -toCardanoTxOutDatumInline :: Maybe PV2.Datum -> C.TxOutDatum C.CtxTx C.BabbageEra -toCardanoTxOutDatumInline Nothing = C.TxOutDatumNone -toCardanoTxOutDatumInline (Just d) = - C.TxOutDatumInline C.ReferenceTxInsScriptsInlineDatumsInBabbageEra . C.fromPlutusData . PV2.builtinDataToData . PV2.getDatum $ d +toCardanoTxOutDatumInTx :: PV2.Datum -> C.TxOutDatum C.CtxTx C.BabbageEra +toCardanoTxOutDatumInTx = + C.TxOutDatumInTx C.ScriptDataInBabbageEra . C.fromPlutusData . PV2.builtinDataToData . PV2.getDatum + +toCardanoTxOutDatumInline :: PV2.Datum -> C.TxOutDatum C.CtxTx C.BabbageEra +toCardanoTxOutDatumInline = + C.TxOutDatumInline C.ReferenceTxInsScriptsInlineDatumsInBabbageEra . C.fromPlutusData . PV2.builtinDataToData . PV2.getDatum toCardanoTxOutDatumHash :: Maybe P.DatumHash -> Either ToCardanoError (C.TxOutDatum ctx C.BabbageEra) toCardanoTxOutDatumHash Nothing = pure C.TxOutDatumNone diff --git a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs index eb00325edf..1d3d2a3398 100644 --- a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs +++ b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs @@ -285,7 +285,7 @@ processConstraint = \case out <- throwLeft ToCardanoError $ C.TxOut <$> C.toCardanoAddressInEra networkId (pubKeyHashAddress pk mskh) <*> C.toCardanoTxOutValue vl - <*> pure (maybe C.TxOutDatumNone (C.TxOutDatumInTx C.ScriptDataInBabbageEra . C.toCardanoScriptData . getDatum) md) + <*> pure (maybe C.TxOutDatumNone (C.TxOutDatumInTx C.ScriptDataInBabbageEra . C.toCardanoScriptData . getDatum) (P.getOutDatum <$> md)) -- FIXME <*> pure refScript unbalancedTx . tx . txOuts <>= [ out ] @@ -296,7 +296,7 @@ processConstraint = \case out <- throwLeft ToCardanoError $ C.TxOut <$> C.toCardanoAddressInEra networkId (scriptValidatorHashAddress vlh svhM) <*> C.toCardanoTxOutValue vl - <*> pure (C.TxOutDatumInTx C.ScriptDataInBabbageEra (C.toCardanoScriptData (getDatum dv))) + <*> pure (C.TxOutDatumInTx C.ScriptDataInBabbageEra (C.toCardanoScriptData (getDatum $ P.getOutDatum dv))) -- FIXME <*> pure refScript unbalancedTx . tx . txOuts <>= [ out ] From abe45452cf0d3e2f2e995e697fbf3f10b68061bf Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Wed, 21 Sep 2022 17:15:50 +0200 Subject: [PATCH 02/22] Work but no inlining --- .../src/Plutus/Contract/StateMachine.hs | 8 +- .../src/Wallet/Emulator/MultiAgent.hs | 7 +- plutus-contract/src/Wallet/Emulator/Wallet.hs | 16 ++-- plutus-contract/test/Spec/Emulator.hs | 7 +- .../src/Ledger/Constraints/OffChain.hs | 60 ++++++------- .../src/Ledger/Constraints/OnChain/V1.hs | 2 +- plutus-ledger-constraints/test/Spec.hs | 7 +- plutus-ledger/src/Ledger/Tx.hs | 26 +++--- .../src/Ledger/Tx/CardanoAPI/Internal.hs | 21 +++-- .../Plutus/Script/Utils/V2/Typed/Scripts.hs | 87 ++++++++++++++++++- 10 files changed, 172 insertions(+), 69 deletions(-) diff --git a/plutus-contract/src/Plutus/Contract/StateMachine.hs b/plutus-contract/src/Plutus/Contract/StateMachine.hs index 9f638254d9..d79d0d082a 100644 --- a/plutus-contract/src/Plutus/Contract/StateMachine.hs +++ b/plutus-contract/src/Plutus/Contract/StateMachine.hs @@ -90,8 +90,8 @@ import Plutus.Contract.StateMachine.OnChain qualified as SM import Plutus.Contract.StateMachine.ThreadToken (ThreadToken (ThreadToken), curPolicy, ttOutRef) import Plutus.Contract.Wallet (getUnspentOutput) import Plutus.Script.Utils.V1.Scripts (scriptCurrencySymbol) -import Plutus.Script.Utils.V1.Typed.Scripts qualified as Typed -import Plutus.V1.Ledger.Tx qualified as V1 +import Plutus.Script.Utils.V2.Typed.Scripts qualified as Typed +import Plutus.V2.Ledger.Tx qualified as V2 import PlutusTx qualified import PlutusTx.Monoid (inv) @@ -199,7 +199,7 @@ threadTokenChooser :: -> [OnChainState state input] -> Either SMContractError (OnChainState state input) threadTokenChooser val states = - let hasToken OnChainState{ocsTxOutRef} = val `Value.leq` (V1.txOutValue $ Typed.tyTxOutTxOut $ Typed.tyTxOutRefOut ocsTxOutRef) in + let hasToken OnChainState{ocsTxOutRef} = val `Value.leq` (V2.txOutValue $ Typed.tyTxOutTxOut $ Typed.tyTxOutRefOut ocsTxOutRef) in case filter hasToken states of [x] -> Right x xs -> @@ -531,7 +531,7 @@ mkStep client@StateMachineClient{scInstance} input = do oldState = State { stateData = getStateData onChainState -- Hide the thread token value from the client code - , stateValue = V1.txOutValue (Typed.tyTxOutTxOut $ Typed.tyTxOutRefOut ocsTxOutRef) <> inv (SM.threadTokenValueOrZero scInstance) + , stateValue = V2.txOutValue (Typed.tyTxOutTxOut $ Typed.tyTxOutRefOut ocsTxOutRef) <> inv (SM.threadTokenValueOrZero scInstance) } inputConstraints = [ScriptInputConstraint{icRedeemer=input, icTxOutRef = Typed.tyTxOutRefRef ocsTxOutRef }] diff --git a/plutus-contract/src/Wallet/Emulator/MultiAgent.hs b/plutus-contract/src/Wallet/Emulator/MultiAgent.hs index 2bb7d35fcd..7e324a2fb6 100644 --- a/plutus-contract/src/Wallet/Emulator/MultiAgent.hs +++ b/plutus-contract/src/Wallet/Emulator/MultiAgent.hs @@ -39,12 +39,13 @@ import Ledger hiding (to, value) import Ledger.Ada qualified as Ada import Ledger.AddressMap qualified as AM import Ledger.Index qualified as Index -import Ledger.Tx.CardanoAPI (toCardanoTxOut, toCardanoTxOutDatumHash) +import Ledger.Tx.CardanoAPI (toCardanoTxOut, toCardanoTxOutDatum) import Ledger.Value qualified as Value import Plutus.ChainIndex.Emulator qualified as ChainIndex import Plutus.Contract.Error (AssertionError (GenericAssertion)) import Plutus.Trace.Emulator.Types (ContractInstanceLog, EmulatedWalletEffects, EmulatedWalletEffects', UserThreadMsg) import Plutus.Trace.Scheduler qualified as Scheduler +import Plutus.V2.Ledger.Tx qualified as V2 import Wallet.API qualified as WAPI import Wallet.Emulator.Chain qualified as Chain import Wallet.Emulator.LogMessages (RequestHandlerLogMsg, TxBalanceMsg) @@ -292,7 +293,7 @@ we create 10 Ada-only outputs per wallet here. -- creates the initial distribution of funds to public key addresses. emulatorStateInitialDist :: NetworkId -> Map PaymentPubKeyHash Value -> Either ToCardanoError EmulatorState emulatorStateInitialDist networkId mp = do - outs <- traverse (toCardanoTxOut networkId toCardanoTxOutDatumHash) $ Map.toList mp >>= mkOutputs + outs <- traverse (toCardanoTxOut networkId toCardanoTxOutDatum) $ Map.toList mp >>= mkOutputs pure $ emulatorStatePool $ pure $ EmulatorTx $ Tx { txInputs = mempty @@ -319,7 +320,7 @@ emulatorStateInitialDist networkId mp = do -- Make sure we don't make the outputs too small count = min 10 $ ada `div` minAdaTxOut remainder = [ vl <> Ada.toValue (-ada) | not (Value.isAdaOnlyValue vl) ] - mkOutput key vl = pubKeyHashTxOut vl (unPaymentPubKeyHash key) + mkOutput key vl = V2.pubKeyHashTxOut vl (unPaymentPubKeyHash key) type MultiAgentEffs = '[ State EmulatorState diff --git a/plutus-contract/src/Wallet/Emulator/Wallet.hs b/plutus-contract/src/Wallet/Emulator/Wallet.hs index cee48191f8..0af6c36ca8 100644 --- a/plutus-contract/src/Wallet/Emulator/Wallet.hs +++ b/plutus-contract/src/Wallet/Emulator/Wallet.hs @@ -57,11 +57,11 @@ import Ledger.Constraints.OffChain (UnbalancedTx) import Ledger.Constraints.OffChain qualified as U import Ledger.Credential (Credential (PubKeyCredential, ScriptCredential)) import Ledger.Fee (estimateTransactionFee, makeAutoBalancedTransaction) -import Ledger.Index (UtxoIndex (UtxoIndex, getIndex)) +import Ledger.Index.Internal (UtxoIndex (UtxoIndex, getIndex)) import Ledger.Params (Params (Params, pNetworkId, pProtocolParams, pSlotConfig)) import Ledger.Tx (CardanoTx, ChainIndexTxOut, SomeCardanoApiTx, Tx (txFee, txMint), TxOut (TxOut)) import Ledger.Tx qualified as Tx -import Ledger.Tx.CardanoAPI (makeTransactionBody, toCardanoTxOut, toCardanoTxOutDatumHash) +import Ledger.Tx.CardanoAPI.Internal (makeTransactionBody, toCardanoTxOut, toCardanoTxOutDatum) import Ledger.Validation (addSignature, fromPlutusIndex, fromPlutusTx, getRequiredSigners) import Ledger.Value qualified as Value import Plutus.ChainIndex (PageQuery) @@ -71,18 +71,18 @@ import Plutus.ChainIndex.Emulator (ChainIndexEmulatorState, ChainIndexQueryEffec import Plutus.Contract.Checkpoint (CheckpointLogMsg) import Plutus.Contract.Wallet (finalize) import Plutus.V1.Ledger.Api (PubKeyHash, TxOutRef, ValidatorHash, Value) -import Plutus.V1.Ledger.Tx qualified as V1 import PlutusTx.Prelude qualified as PlutusTx import Prettyprinter (Pretty (pretty)) import Servant.API (FromHttpApiData (parseUrlPiece), ToHttpApiData (toUrlPiece)) -import Wallet.API (WalletAPIError) import Wallet.Effects qualified as WAPI (getClientParams) -import Wallet.Error qualified as WAPI (WalletAPIError (InsufficientFunds, PaymentPrivateKeyNotFound, ToCardanoError, ValidationError), - throwOtherError) +import Wallet.Emulator.Error qualified as WAPI (WalletAPIError (InsufficientFunds, PaymentPrivateKeyNotFound, ToCardanoError, ValidationError), + throwOtherError) +import Wallet.Error (WalletAPIError) import Data.List.NonEmpty (NonEmpty) import Data.List.NonEmpty qualified as NonEmpty import Ledger qualified +import Plutus.V2.Ledger.Tx qualified as PV2 import Wallet.Effects (NodeClientEffect, WalletEffect (BalanceTx, OwnAddresses, SubmitTxn, TotalFunds, WalletAddSignature, YieldUnbalancedTx), publishTx) @@ -323,7 +323,7 @@ handleBalance utx' = do let utx = finalize pSlotConfig utx' requiredSigners = Set.toList (U.unBalancedTxRequiredSignatories utx) eitherTx = U.unBalancedTxTx utx - plUtxo = traverse (toCardanoTxOut pNetworkId toCardanoTxOutDatumHash . Tx.toTxOut) utxo + plUtxo = traverse (toCardanoTxOut pNetworkId toCardanoTxOutDatum . Tx.toTxOut) utxo mappedUtxo <- either (throwError . WAPI.ToCardanoError) (pure . fmap TxOut) plUtxo cUtxoIndex <- handleError eitherTx $ fromPlutusIndex $ UtxoIndex $ U.unBalancedTxUtxoIndex utx <> mappedUtxo case eitherTx of @@ -500,7 +500,7 @@ calculateTxChanges params addr utxos (neg, pos) = do txOut <- either (throwError . WAPI.ToCardanoError) (pure . TxOut) - $ toCardanoTxOut (pNetworkId params) toCardanoTxOutDatumHash $ V1.TxOut addr pos Nothing + $ toCardanoTxOut (pNetworkId params) toCardanoTxOutDatum $ PV2.TxOut addr pos PV2.NoOutputDatum Nothing (missing, extraTxOut) <- either (throwError . WAPI.ToCardanoError) pure $ U.adjustTxOut params txOut diff --git a/plutus-contract/test/Spec/Emulator.hs b/plutus-contract/test/Spec/Emulator.hs index fd44fd232d..70c3e83cdc 100644 --- a/plutus-contract/test/Spec/Emulator.hs +++ b/plutus-contract/test/Spec/Emulator.hs @@ -35,14 +35,15 @@ import Ledger.Generators (Mockchain (Mockchain), TxInputWitnessed (TxInputWitnes import Ledger.Generators qualified as Gen import Ledger.Index qualified as Index import Ledger.Params (Params (Params, pNetworkId)) -import Ledger.Tx.CardanoAPI (toCardanoTxOut, toCardanoTxOutDatumHash) +import Ledger.Tx.CardanoAPI (toCardanoTxOut, toCardanoTxOutDatum) import Ledger.Value qualified as Value import Plutus.Contract.Test hiding (not) -import Plutus.Script.Utils.V1.Tx (scriptTxOut) +import Plutus.Script.Utils.V1.Address (mkValidatorAddress) import Plutus.Script.Utils.V1.Typed.Scripts (mkUntypedValidator) import Plutus.Trace (EmulatorTrace, PrintEffect (PrintLn)) import Plutus.Trace qualified as Trace import Plutus.V1.Ledger.Contexts (ScriptContext) +import Plutus.V2.Ledger.Api qualified as PV2 import PlutusTx qualified import PlutusTx.Numeric qualified as P import PlutusTx.Prelude qualified as PlutusTx @@ -217,7 +218,7 @@ invalidScript = property $ do index <- forAll $ Gen.int (Range.linear 0 ((length $ getCardanoTxOutputs txn1) - 1)) let emulatorTx = onCardanoTx id (\_ -> error "Unexpected Cardano.Api.Tx") txn1 let setOutputs o = either (const Hedgehog.failure) (pure . TxOut) $ - toCardanoTxOut pNetworkId toCardanoTxOutDatumHash $ scriptTxOut failValidator (txOutValue o) unitDatum + toCardanoTxOut pNetworkId toCardanoTxOutDatum $ PV2.TxOut (mkValidatorAddress failValidator) (txOutValue o) (PV2.OutputDatum unitDatum) Nothing outs <- traverse setOutputs $ emulatorTx ^. outputs let scriptTxn = EmulatorTx $ emulatorTx diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs index 46de823969..1503d7492a 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs @@ -87,7 +87,7 @@ import Data.Set qualified as Set import GHC.Generics (Generic) import Prettyprinter (Pretty (pretty), colon, hang, vsep, (<+>)) -import Ledger (outValue) +import Ledger (Redeemer (Redeemer), outValue) import Ledger.Ada qualified as Ada import Ledger.Address (PaymentPubKey (PaymentPubKey), PaymentPubKeyHash (PaymentPubKeyHash), StakePubKeyHash, pubKeyHashAddress) @@ -108,18 +108,17 @@ import Ledger.Tx (ChainIndexTxOut, Language (PlutusV1, PlutusV2), TxOut (TxOut), outDatumHash, txOutValue) import Ledger.Tx qualified as Tx import Ledger.Tx.CardanoAPI qualified as C -import Ledger.Typed.Scripts (Any, ConnectionError (UnknownRef), TypedValidator, +import Ledger.Typed.Scripts (Any, ConnectionError (UnknownRef), TypedValidator (tvValidator, tvValidatorHash), ValidatorTypes (DatumType, RedeemerType)) -import Ledger.Typed.Scripts qualified as Typed import Ledger.Validation (evaluateMinLovelaceOutput, fromPlutusTxOut) import Plutus.Script.Utils.Scripts qualified as P -import Plutus.Script.Utils.V1.Tx (scriptAddressTxOut) +import Plutus.Script.Utils.V2.Typed.Scripts qualified as Typed import Plutus.V1.Ledger.Api (Datum (Datum), DatumHash, POSIXTimeRange, Validator (getValidator), Value, getMintingPolicy) import Plutus.V1.Ledger.Scripts (MintingPolicy (MintingPolicy), MintingPolicyHash (MintingPolicyHash), Script, ScriptHash (ScriptHash), Validator (Validator), ValidatorHash (ValidatorHash)) -import Plutus.V1.Ledger.Tx qualified as PV1 import Plutus.V1.Ledger.Value qualified as Value +import Plutus.V2.Ledger.Tx qualified as PV2 import PlutusTx (FromData, ToData (toBuiltinData)) import PlutusTx.Lattice (BoundedMeetSemiLattice (top), JoinSemiLattice ((\/)), MeetSemiLattice ((/\))) import PlutusTx.Numeric qualified as N @@ -181,7 +180,7 @@ instance Monoid (ScriptLookups a) where -- @ typedValidatorLookups :: TypedValidator a -> ScriptLookups a typedValidatorLookups inst = - let (ValidatorHash vh, v) = (Typed.tvValidatorHash inst, Typed.tvValidator inst) + let (ValidatorHash vh, v) = (tvValidatorHash inst, tvValidator inst) (MintingPolicyHash mph, mp) = (Typed.forwardingMintingPolicyHash inst, Typed.vForwardingMintingPolicy inst) in mempty { slOtherScripts = @@ -499,11 +498,12 @@ addMissingValueSpent = do -- Step 4 of the process described in [Balance of value spent] pkh <- asks slOwnPaymentPubKeyHash >>= maybe (throwError OwnPubKeyMissing) pure skh <- asks slOwnStakePubKeyHash - let pv1TxOut = PV1.TxOut { PV1.txOutAddress=pubKeyHashAddress pkh skh - , PV1.txOutValue=missing - , PV1.txOutDatumHash=Nothing + let pv2TxOut = PV2.TxOut { PV2.txOutAddress=pubKeyHashAddress pkh skh + , PV2.txOutValue=missing + , PV2.txOutDatum=PV2.NoOutputDatum + , PV2.txOutReferenceScript= Nothing } - txOut <- toCardanoTxOutWithHashedDatum pv1TxOut + txOut <- toCardanoTxOutWithOutputDatum pv2TxOut unbalancedTx . tx . Tx.outputs %= (txOut:) updateUtxoIndex @@ -514,7 +514,7 @@ updateUtxoIndex => m () updateUtxoIndex = do ScriptLookups{slTxOutputs} <- ask - slUtxos <- traverse (toCardanoTxOutWithHashedDatum . Tx.toTxOut) slTxOutputs + slUtxos <- traverse (toCardanoTxOutWithOutputDatum . Tx.toTxOut) slTxOutputs unbalancedTx . utxoIndex <>= slUtxos -- | Add a typed input, checking the type of the output it spends. Return the value @@ -541,14 +541,15 @@ addOwnInput ScriptInputConstraint{icRedeemer, icTxOutRef} = do datum <- ciTxOut ^? Tx.ciTxOutScriptDatum . _2 . _Just pure (Tx.toTxOut ciTxOut, datum) Typed.typeScriptTxOutRef inst icTxOutRef txOut datum - let txIn = Typed.makeTypedScriptTxIn inst icRedeemer typedOutRef - vl = PV1.txOutValue $ Typed.tyTxOutTxOut $ Typed.tyTxOutRefOut typedOutRef + let vl = PV2.txOutValue $ Typed.tyTxOutTxOut $ Typed.tyTxOutRefOut typedOutRef valueSpentInputs <>= provided vl - case Typed.tyTxInTxIn txIn of - -- this is what makeTypedScriptTxIn makes - Tx.TxIn outRef (Just (Tx.ConsumeScriptAddress validator rs dt)) -> do - unbalancedTx . tx %= Tx.addScriptTxInput outRef validator rs dt - _ -> error "Impossible txIn in addOwnInput." + case typedOutRef of + Typed.TypedScriptTxOutRef{Typed.tyTxOutRefRef, Typed.tyTxOutRefOut} -> do + unbalancedTx . tx %= Tx.addScriptTxInput + tyTxOutRefRef + (Typed.vValidatorScript inst) + (Redeemer $ toBuiltinData icRedeemer) + (Datum $ toBuiltinData $ Typed.tyTxOutData tyTxOutRefOut) @@ -564,7 +565,7 @@ addOwnOutput ScriptOutputConstraint{ocDatum, ocValue, ocReferenceScriptHash} = d ScriptLookups{slTypedValidator} <- ask inst <- maybe (throwError TypedValidatorMissing) pure slTypedValidator let dsV = Datum (toBuiltinData ocDatum) - pure $ MustPayToOtherScript (Typed.tvValidatorHash inst) Nothing (Hashed dsV) ocReferenceScriptHash ocValue + pure $ MustPayToOtherScript (tvValidatorHash inst) Nothing (Hashed dsV) ocReferenceScriptHash ocValue data MkTxError = TypeCheckFailed Typed.ConnectionError @@ -706,15 +707,16 @@ processConstraint = \case forM_ mdv $ \dv -> do let d = getOutDatum dv -- FIXME unbalancedTx . tx . Tx.datumWitnesses . at (P.datumHash d) ?= d - let pv1TxOut = PV1.TxOut { PV1.txOutAddress=pubKeyHashAddress pk skhM - , PV1.txOutValue=vl - , PV1.txOutDatumHash=Nothing + let pv2TxOut = PV2.TxOut { PV2.txOutAddress=pubKeyHashAddress pk skhM + , PV2.txOutValue=vl + , PV2.txOutDatum=PV2.NoOutputDatum + , PV2.txOutReferenceScript=Nothing } let txInDatum = case mdv of Nothing -> C.toCardanoTxOutNoDatum Just (Hashed d) -> C.toCardanoTxOutDatumInTx d Just (Inline d) -> C.toCardanoTxOutDatumInline d - txOut <- toCardanoTxOutWithHashedDatum pv1TxOut <&> outDatumHash .~ txInDatum + txOut <- toCardanoTxOutWithOutputDatum pv2TxOut <&> outDatumHash .~ txInDatum unbalancedTx . tx . Tx.outputs %= (txOut :) valueSpentOutputs <>= provided vl MustPayToOtherScript vlh svhM dv _refScript vl -> do @@ -722,13 +724,13 @@ processConstraint = \case let addr = Address.scriptValidatorHashAddress vlh svhM d = getOutDatum dv theHash = P.datumHash d - pv1script = scriptAddressTxOut addr vl d + pv2script = PV2.TxOut addr vl PV2.NoOutputDatum Nothing unbalancedTx . tx . Tx.datumWitnesses . at theHash ?= d let txInDatum = case dv of Hashed _ -> C.toCardanoTxOutDatumInTx d Inline _ -> C.toCardanoTxOutDatumInline d - txScript <- toCardanoTxOutWithHashedDatum pv1script <&> outDatumHash .~ txInDatum + txScript <- toCardanoTxOutWithOutputDatum pv2script <&> outDatumHash .~ txInDatum unbalancedTx . tx . Tx.outputs %= (txScript :) valueSpentOutputs <>= provided vl MustHashDatum dvh dv -> do @@ -791,12 +793,12 @@ resolveScriptTxOut pure $ Just ((vh, validator), (dh, dataValue), _ciTxOutValue) resolveScriptTxOut _ = pure Nothing -toCardanoTxOutWithHashedDatum +toCardanoTxOutWithOutputDatum :: ( MonadState ConstraintProcessingState m, MonadError MkTxError m) - => PV1.TxOut -> m TxOut -toCardanoTxOutWithHashedDatum txout = do + => PV2.TxOut -> m TxOut +toCardanoTxOutWithOutputDatum txout = do networkId <- gets $ pNetworkId . cpsParams - let cardanoTxOut = TxOut <$> C.toCardanoTxOut networkId C.toCardanoTxOutDatumHash txout + let cardanoTxOut = TxOut <$> C.toCardanoTxOut networkId C.toCardanoTxOutDatum txout case cardanoTxOut of Left err -> throwError $ TxOutCardanoError err Right cTxOut -> pure cTxOut diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs index 7995e1afbb..adfdc942b6 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs @@ -114,7 +114,7 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case in traceIfFalse "La" -- "MustPayToPubKey" $ vl `leq` V.valuePaidTo scriptContextTxInfo pk - && maybe True (\dv -> any (checkOutput dv) outs) (fmap getOutDatum mdv) -- FIXME + && maybe True (\dv -> any (checkOutput $ getOutDatum dv) outs) mdv -- FIXME && isNothing refScript MustPayToOtherScript vlh _ dv refScript vl -> let outs = V.txInfoOutputs scriptContextTxInfo diff --git a/plutus-ledger-constraints/test/Spec.hs b/plutus-ledger-constraints/test/Spec.hs index 0c047f4f66..d1c96ea6cb 100644 --- a/plutus-ledger-constraints/test/Spec.hs +++ b/plutus-ledger-constraints/test/Spec.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} @@ -21,6 +22,7 @@ import Hedgehog qualified import Hedgehog.Gen qualified as Gen import Hedgehog.Range qualified as Range import Language.Haskell.TH.Syntax +import Ledger (datumHash) import Ledger qualified (ChainIndexTxOut (ScriptChainIndexTxOut), inputs, paymentPubKeyHash, scriptTxInputs, toTxOut, txInputRef, unitDatum, unitRedeemer) import Ledger.Ada qualified as Ada @@ -36,13 +38,14 @@ import Ledger.Index qualified as Ledger import Ledger.Params (Params (pNetworkId)) import Ledger.Scripts (WitCtx (WitCtxStake), examplePlutusScriptAlwaysSucceedsHash) import Ledger.Tx (Tx (txCollateral, txOutputs), TxOut (TxOut), txOutAddress) -import Ledger.Tx.CardanoAPI (toCardanoTxOut, toCardanoTxOutDatumHash) +import Ledger.Tx.CardanoAPI (toCardanoTxOut, toCardanoTxOutDatum, toCardanoTxOutDatumHash, toCardanoTxOutNoDatum) import Ledger.Value (CurrencySymbol, Value (Value)) import Ledger.Value qualified as Value import Plutus.Script.Utils.V2.Generators qualified as Gen import Plutus.Script.Utils.V2.Scripts qualified as Ledger import Plutus.Script.Utils.V2.Typed.Scripts qualified as Scripts import Plutus.V2.Ledger.Api qualified as Ledger +import Plutus.V2.Ledger.Api qualified as PV2 import PlutusTx qualified import PlutusTx.AssocMap qualified as AMap import PlutusTx.Builtins.Internal (BuiltinByteString (..)) @@ -185,7 +188,7 @@ testScriptInputs lookups txc = property $ do let valM = do Ledger.checkValidInputs (toListOf (Ledger.inputs . Ledger.scriptTxInputs)) tx pure Nothing - txOuts = traverse (toCardanoTxOut (pNetworkId params) toCardanoTxOutDatumHash) + txOuts = traverse (toCardanoTxOut (pNetworkId params) toCardanoTxOutDatum) $ Ledger.toTxOut <$> Constraints.slTxOutputs lookups case txOuts of Left err -> do diff --git a/plutus-ledger/src/Ledger/Tx.hs b/plutus-ledger/src/Ledger/Tx.hs index 54337cfb53..6dfa147c31 100644 --- a/plutus-ledger/src/Ledger/Tx.hs +++ b/plutus-ledger/src/Ledger/Tx.hs @@ -86,9 +86,11 @@ import Ledger.Slot (SlotRange) import Ledger.Tx.CardanoAPI (SomeCardanoApiTx (SomeTx), ToCardanoError (..)) import Ledger.Tx.CardanoAPI qualified as CardanoAPI import Ledger.Validation qualified -import Plutus.Script.Utils.Scripts (datumHash) +import Plutus.Script.Utils.Scripts (datumHash, scriptHash) import Plutus.V1.Ledger.Api qualified as V1 import Plutus.V1.Ledger.Tx qualified as V1.Tx hiding (TxIn (..), TxInType (..)) +import Plutus.V2.Ledger.Api qualified as V2 +import Plutus.V2.Ledger.Tx qualified as V2.Tx hiding (TxIn (..), TxInType (..)) import Prettyprinter (Pretty (pretty), braces, colon, hang, nest, viaShow, vsep, (<+>)) -- for re-export import Control.DeepSeq (NFData) @@ -112,9 +114,9 @@ data ChainIndexTxOut = -- public key hash. _ciTxOutAddress :: Address, -- | Value of the transaction output. - _ciTxOutValue :: V1.Value, + _ciTxOutValue :: V2.Value, -- | Optional datum attached to the transaction output. - _ciTxOutPublicKeyDatum :: Maybe (V1.DatumHash, Maybe V1.Datum), + _ciTxOutPublicKeyDatum :: Maybe (V2.DatumHash, Maybe V2.Datum), -- | Optional reference script attached to the transaction output. _ciTxOutReferenceScript :: Maybe (Versioned V1.Script) } @@ -127,7 +129,7 @@ data ChainIndexTxOut = -- | Datum attached to the transaction output, either in full or as a -- hash reference. A transaction output protected by a Plutus script -- is guardateed to have an associated datum. - _ciTxOutScriptDatum :: (V1.DatumHash, Maybe V1.Datum), + _ciTxOutScriptDatum :: (V2.DatumHash, Maybe V2.Datum), -- | Optional reference script attached to the transaction output. -- The reference script is, in genereal, unrelated to the validator -- script althought it could also be the same. @@ -147,12 +149,16 @@ makePrisms ''ChainIndexTxOut -- Note that 'ChainIndexTxOut' supports features such inline datums and -- reference scripts which are not supported by V1 TxOut. Converting from -- 'ChainIndexTxOut' to 'TxOut' and back is therefore lossy. -toTxOut :: ChainIndexTxOut -> V1.Tx.TxOut -toTxOut (PublicKeyChainIndexTxOut addr v datum _referenceScript) = - V1.Tx.TxOut addr v (fst <$> datum) -toTxOut (ScriptChainIndexTxOut addr v (dh, _) _referenceScript _validator) = - V1.Tx.TxOut addr v (Just dh) --- +toTxOut :: ChainIndexTxOut -> V2.Tx.TxOut +toTxOut (PublicKeyChainIndexTxOut addr v datum referenceScript) = + V2.Tx.TxOut addr v (toPlutuvOutDatum datum) (scriptHash <$> referenceScript) +toTxOut (ScriptChainIndexTxOut addr v datum referenceScript _validator) = + V2.Tx.TxOut addr v (toPlutuvOutDatum $ Just datum) (scriptHash <$> referenceScript) + +toPlutuvOutDatum :: Maybe (V2.DatumHash, Maybe V2.Datum) -> V2.Tx.OutputDatum +toPlutuvOutDatum Nothing = V2.Tx.NoOutputDatum +toPlutuvOutDatum (Just (d, _)) = V2.Tx.OutputDatumHash d + -- | Converts a plutus-ledger-api transaction output to the chain index -- transaction output. fromTxOut :: V1.TxOut -> Maybe ChainIndexTxOut diff --git a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs index 366df911bb..bb51c0eb39 100644 --- a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs +++ b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs @@ -45,6 +45,7 @@ module Ledger.Tx.CardanoAPI.Internal( , makeTransactionBody , toCardanoTxIn , toCardanoTxOut + , toCardanoTxOutDatum , toCardanoTxOutDatumHash , toCardanoTxOutDatumInline , toCardanoTxOutDatumInTx @@ -415,14 +416,14 @@ fromCardanoTxOut (C.TxOut addr value datumHash _) = toCardanoTxOut :: C.NetworkId - -> (Maybe P.DatumHash -> Either ToCardanoError (C.TxOutDatum ctx C.BabbageEra)) - -> PV1.TxOut + -> (PV2.OutputDatum -> Either ToCardanoError (C.TxOutDatum ctx C.BabbageEra)) + -> PV2.TxOut -> Either ToCardanoError (C.TxOut ctx C.BabbageEra) -toCardanoTxOut networkId fromHash (PV1.TxOut addr value datumHash) = +toCardanoTxOut networkId fromHash (PV2.TxOut addr value datum _rs) = C.TxOut <$> toCardanoAddressInEra networkId addr <*> toCardanoTxOutValue value - <*> fromHash datumHash - <*> pure C.ReferenceScriptNone + <*> fromHash datum + <*> pure C.ReferenceScriptNone -- fixme fromCardanoAddressInEra :: C.AddressInEra era -> P.Address fromCardanoAddressInEra (C.AddressInEra C.ByronAddressInAnyEra address) = fromCardanoAddress address @@ -528,9 +529,13 @@ toCardanoTxOutDatumInline :: PV2.Datum -> C.TxOutDatum C.CtxTx C.BabbageEra toCardanoTxOutDatumInline = C.TxOutDatumInline C.ReferenceTxInsScriptsInlineDatumsInBabbageEra . C.fromPlutusData . PV2.builtinDataToData . PV2.getDatum -toCardanoTxOutDatumHash :: Maybe P.DatumHash -> Either ToCardanoError (C.TxOutDatum ctx C.BabbageEra) -toCardanoTxOutDatumHash Nothing = pure C.TxOutDatumNone -toCardanoTxOutDatumHash (Just datumHash) = C.TxOutDatumHash C.ScriptDataInBabbageEra <$> toCardanoScriptDataHash datumHash +toCardanoTxOutDatumHash :: P.DatumHash -> Either ToCardanoError (C.TxOutDatum ctx C.BabbageEra) +toCardanoTxOutDatumHash datumHash = C.TxOutDatumHash C.ScriptDataInBabbageEra <$> toCardanoScriptDataHash datumHash + +toCardanoTxOutDatum :: PV2.OutputDatum -> Either ToCardanoError (C.TxOutDatum C.CtxTx C.BabbageEra) +toCardanoTxOutDatum PV2.NoOutputDatum = pure toCardanoTxOutNoDatum +toCardanoTxOutDatum (PV2.OutputDatum d) = pure $ toCardanoTxOutDatumInTx d +toCardanoTxOutDatum (PV2.OutputDatumHash dh) = toCardanoTxOutDatumHash dh toCardanoScriptDataHash :: P.DatumHash -> Either ToCardanoError (C.Hash C.ScriptData) toCardanoScriptDataHash (P.DatumHash bs) = tag "toCardanoTxOutDatumHash" (deserialiseFromRawBytes (C.AsHash C.AsScriptData) (PlutusTx.fromBuiltin bs)) diff --git a/plutus-script-utils/src/Plutus/Script/Utils/V2/Typed/Scripts.hs b/plutus-script-utils/src/Plutus/Script/Utils/V2/Typed/Scripts.hs index 84e2a52e64..5eaf589001 100644 --- a/plutus-script-utils/src/Plutus/Script/Utils/V2/Typed/Scripts.hs +++ b/plutus-script-utils/src/Plutus/Script/Utils/V2/Typed/Scripts.hs @@ -1,3 +1,7 @@ +{-# LANGUAGE GADTs #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE UndecidableInstances #-} + {-# OPTIONS_GHC -Wno-missing-import-lists #-} module Plutus.Script.Utils.V2.Typed.Scripts @@ -7,11 +11,92 @@ module Plutus.Script.Utils.V2.Typed.Scripts , Validator , MintingPolicy , StakeValidator + , TypedScriptTxOut (..) + , TypedScriptTxOutRef (..) + , typeScriptTxOut + , typeScriptTxOutRef + , ConnectionError (..) ) where +import Control.Monad.Except (MonadError (throwError)) +import Plutus.Script.Utils.Scripts (datumHash) +import Plutus.Script.Utils.V1.Typed.Scripts.Validators (ConnectionError (..)) +import Plutus.Script.Utils.V1.Typed.Scripts.Validators qualified as V1 import Plutus.Script.Utils.V2.Typed.Scripts.MonetaryPolicies hiding (forwardToValidator) import Plutus.Script.Utils.V2.Typed.Scripts.StakeValidators hiding (forwardToValidator) import Plutus.Script.Utils.V2.Typed.Scripts.Validators -import Plutus.V2.Ledger.Api (MintingPolicy, StakeValidator, Validator) +import Plutus.V2.Ledger.Api (Credential (PubKeyCredential, ScriptCredential), Datum, FromData, MintingPolicy, + OutputDatum (OutputDatum, OutputDatumHash), StakeValidator, ToData (..), + TxOut (txOutAddress, txOutDatum), TxOutRef, Validator, addressCredential) + +-- +-- | A 'TxOut' tagged by a phantom type: and the connection type of the output. +data TypedScriptTxOut a = (FromData (DatumType a), ToData (DatumType a)) => + TypedScriptTxOut + { tyTxOutTxOut :: TxOut, + tyTxOutData :: DatumType a + } + +instance Eq (DatumType a) => Eq (TypedScriptTxOut a) where + l == r = + tyTxOutTxOut l == tyTxOutTxOut r + && tyTxOutData l == tyTxOutData r + + +-- | A 'TxOutRef' tagged by a phantom type: and the connection type of the output. +data TypedScriptTxOutRef a = TypedScriptTxOutRef + { tyTxOutRefRef :: TxOutRef, + tyTxOutRefOut :: TypedScriptTxOut a + } + +instance Eq (DatumType a) => Eq (TypedScriptTxOutRef a) where + l == r = + tyTxOutRefRef l == tyTxOutRefRef r + && tyTxOutRefOut l == tyTxOutRefOut r + + +-- | Create a 'TypedScriptTxOut' from an existing 'TxOut' by checking the types of its parts. +typeScriptTxOut :: + forall out m. + ( FromData (DatumType out), + ToData (DatumType out), + MonadError ConnectionError m + ) => + TypedValidator out -> + TxOutRef -> + TxOut -> + Datum -> + m (TypedScriptTxOut out) +typeScriptTxOut tv txOutRef txOut datum = do + case addressCredential (txOutAddress txOut) of + PubKeyCredential _ -> + throwError $ V1.WrongOutType V1.ExpectedScriptGotPubkey + ScriptCredential _vh -> + case txOutDatum txOut of + OutputDatum d | datumHash datum == datumHash d -> do + V1.checkValidatorAddress tv (txOutAddress txOut) + dsVal <- V1.checkDatum tv datum + pure $ TypedScriptTxOut @out txOut dsVal + OutputDatumHash dh | datumHash datum == dh -> do + V1.checkValidatorAddress tv (txOutAddress txOut) + dsVal <- V1.checkDatum tv datum + pure $ TypedScriptTxOut @out txOut dsVal + _ -> throwError $ V1.NoDatum txOutRef (datumHash datum) + +-- | Create a 'TypedScriptTxOut' from an existing 'TxOut' by checking the types of its parts. +typeScriptTxOutRef :: + forall out m. + ( FromData (DatumType out), + ToData (DatumType out), + MonadError ConnectionError m + ) => + TypedValidator out -> + TxOutRef -> + TxOut -> + Datum -> + m (TypedScriptTxOutRef out) +typeScriptTxOutRef tv txOutRef txOut datum = do + tyOut <- typeScriptTxOut tv txOutRef txOut datum + pure $ TypedScriptTxOutRef txOutRef tyOut From e678087b2f619385eb026d51d30efbff3c0d9470 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Thu, 22 Sep 2022 12:59:09 +0200 Subject: [PATCH 03/22] First working inline datum with V2 --- .../TxConstraints/MustPayToPubKeyAddress.hs | 78 +++++++++++++++---- .../src/Ledger/Constraints/OffChain.hs | 3 +- plutus-ledger/src/Ledger/Tx.hs | 4 +- .../src/Ledger/Tx/CardanoAPI/Internal.hs | 2 +- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 7be0062980..29b89c06e2 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -13,20 +13,25 @@ import Test.Tasty (TestTree, testGroup) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints qualified as Constraints (OutDatum (Hashed), mustMintValueWithRedeemer, mustPayToPubKey, - mustPayToPubKeyAddress, mustPayWithDatumToPubKey, - mustPayWithDatumToPubKeyAddress, plutusV1MintingPolicy) +import Ledger.Constraints qualified as Constraints (OutDatum (Hashed, Inline), mustMintValueWithRedeemer, + mustPayToPubKey, mustPayToPubKeyAddress, mustPayWithDatumToPubKey, + mustPayWithDatumToPubKeyAddress, plutusV1MintingPolicy, + plutusV2MintingPolicy) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) +import Ledger.Constraints.OnChain.V2 qualified as V2.Constraints import Ledger.Scripts (ScriptError (EvaluationError)) import Ledger.Test (asDatum, asRedeemer) import Ledger.Tx qualified as Tx import Ledger.Typed.Scripts qualified as Scripts import Plutus.Contract as Con -import Plutus.Contract.Test (assertFailedTransaction, assertValidatedTransactionCount, checkPredicateOptions, - defaultCheckOptions, mockWalletPaymentPubKeyHash, w1, w2) +import Plutus.Contract.Test (assertFailedTransaction, assertValidatedTransactionCount, checkPredicate, + checkPredicateOptions, mockWalletPaymentPubKeyHash, w1, w2) import Plutus.Script.Utils.V1.Scripts qualified as PSU.V1 +import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 +import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Script import Plutus.Trace qualified as Trace import Plutus.V1.Ledger.Value qualified as Value +import Plutus.V2.Ledger.Contexts qualified as V2.Script import PlutusTx qualified import PlutusTx.Prelude qualified as P @@ -40,6 +45,7 @@ tests = , successfulUseOfMustPayToPubKeyExpectingALowerAdaValue , successfulUseOfMustPayToPubKeyAddress , successfulUseOfMustPayWithDatumToPubKey + , successfulUseOfMustPayWithInlineDatumToPubKeyV2 , successfulUseOfMustPayWithDatumToPubKeyAddress , phase2FailureWhenUsingUnexpectedPaymentPubKeyHash --, phase2FailureWhenUsingUnexpectedStakePubKeyHash -- onchain check not implemented @@ -62,6 +68,9 @@ adaValue = Ada.lovelaceValueOf adaAmount tknValue :: Value.Value tknValue = Value.singleton mustPayToPubKeyAddressPolicyCurrencySymbol "mint-me" 1 +tknValueV2 :: Value.Value +tknValueV2 = Value.singleton mustPayToPubKeyAddressPolicyCurrencySymbolV2 "mint-me" 1 + w1PaymentPubKeyHash :: Ledger.PaymentPubKeyHash w1PaymentPubKeyHash = mockWalletPaymentPubKeyHash w1 @@ -91,7 +100,7 @@ successfulUseOfMustPayToPubKeyWithMintedTokenValue = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Successful use of offchain and onchain mustPayToPubKey constraint for native token value" (assertValidatedTransactionCount 1) (void $ trace contract) @@ -108,7 +117,7 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Successful use of mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for token value only" (assertValidatedTransactionCount 1) (void $ trace contract) @@ -125,7 +134,7 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Successful use of mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for ada value only" (assertValidatedTransactionCount 1) (void $ trace contract) @@ -141,7 +150,7 @@ successfulUseOfMustPayToPubKeyExpectingALowerAdaValue = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Successful use of onchain mustPayToPubKey constraint when it expects less ada than the actual value" (assertValidatedTransactionCount 1) (void $ trace contract) @@ -157,7 +166,7 @@ successfulUseOfMustPayToPubKeyAddress = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Successful use of offchain and onchain mustPayToPubKeyAddress constraint for ada-only value" (assertValidatedTransactionCount 1) (void $ trace contract) @@ -173,11 +182,27 @@ successfulUseOfMustPayWithDatumToPubKey = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Successful use of offchain and onchain mustPayWithDatumToPubKey constraint with bytestring datum and ada value" (assertValidatedTransactionCount 1) (void $ trace contract) +-- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with inline bytestring datum and ada value +successfulUseOfMustPayWithInlineDatumToPubKeyV2 :: TestTree +successfulUseOfMustPayWithInlineDatumToPubKeyV2 = + let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue + contract = do + let lookups1 = Constraints.plutusV2MintingPolicy mustPayToPubKeyAddressPolicyV2 + tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash (Constraints.Inline someDatum) adaValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValueV2 + ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + + in checkPredicate + "Successful use of offchain and onchain mustPayWithDatumToPubKey constraint with inline bytestring datum and ada value" + (assertValidatedTransactionCount 1) + (void $ trace contract) + -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKeyAddress with bytestring datum and ada value successfulUseOfMustPayWithDatumToPubKeyAddress :: TestTree successfulUseOfMustPayWithDatumToPubKeyAddress = @@ -189,7 +214,7 @@ successfulUseOfMustPayWithDatumToPubKeyAddress = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Successful use of offchain and onchain mustPayWithDatumToPubKeyAddress constraint with bytestring datum and ada value" (assertValidatedTransactionCount 1) (void $ trace contract) @@ -205,7 +230,7 @@ phase2FailureWhenUsingUnexpectedPaymentPubKeyHash = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Phase-2 validation failure occurs when onchain mustPayWithDatumToPubKeyAddress constraint sees an unexpected PaymentPubkeyHash" (assertFailedTransaction (\_ err _ -> case err of {Ledger.ScriptFailure (EvaluationError ("La":_) _) -> True; _ -> False })) (void $ trace contract) @@ -221,7 +246,7 @@ phase2FailureWhenUsingUnexpectedDatum = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Phase-2 validation failure occurs when onchain mustPayWithDatumToPubKeyAddress constraint sees an unexpected Datum" (assertFailedTransaction (\_ err _ -> case err of {Ledger.ScriptFailure (EvaluationError ("La":_) _) -> True; _ -> False })) (void $ trace contract) @@ -237,7 +262,7 @@ phase2FailureWhenUsingUnexpectedValue = ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - in checkPredicateOptions defaultCheckOptions + in checkPredicate "Phase-2 validation failure occurs when onchain mustPayWithDatumToPubKeyAddress constraint sees an unexpected Value" (assertFailedTransaction (\_ err _ -> case err of {Ledger.ScriptFailure (EvaluationError ("La":_) _) -> True; _ -> False })) (void $ trace contract) @@ -253,16 +278,35 @@ mkMustPayToPubKeyAddressPolicy t = case t of MustPayWithDatumToPubKey ppkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh (Constraints.Hashed d) v) MustPayWithDatumToPubKeyAddress ppkh spkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh (Constraints.Hashed d) v) +{-# INLINEABLE mkMustPayToPubKeyAddressPolicyV2 #-} +mkMustPayToPubKeyAddressPolicyV2 :: ConstraintParams -> V2.Script.ScriptContext -> Bool +mkMustPayToPubKeyAddressPolicyV2 t = case t of + MustPayToPubKey ppkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKey ppkh v) + MustPayToPubKeyAddress ppkh spkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKeyAddress ppkh spkh v) + MustPayWithDatumToPubKey ppkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh (Constraints.Inline d) v) + MustPayWithDatumToPubKeyAddress ppkh spkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh (Constraints.Inline d) v) + mustPayToPubKeyAddressPolicy :: Scripts.MintingPolicy mustPayToPubKeyAddressPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where wrap = Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy +mustPayToPubKeyAddressPolicyV2 :: V2.Script.MintingPolicy +mustPayToPubKeyAddressPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) + where + wrap = V2.Script.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicyV2 + mustPayToPubKeyAddressPolicyHash :: Ledger.MintingPolicyHash mustPayToPubKeyAddressPolicyHash = PSU.V1.mintingPolicyHash mustPayToPubKeyAddressPolicy -mustPayToPubKeyAddressPolicyCurrencySymbol :: Ledger.CurrencySymbol -mustPayToPubKeyAddressPolicyCurrencySymbol = Value.mpsSymbol mustPayToPubKeyAddressPolicyHash +mustPayToPubKeyAddressPolicyHashV2 :: Ledger.MintingPolicyHash +mustPayToPubKeyAddressPolicyHashV2 = PSU.V2.mintingPolicyHash mustPayToPubKeyAddressPolicyV2 + +mustPayToPubKeyAddressPolicyCurrencySymbol :: CurrencySymbol +mustPayToPubKeyAddressPolicyCurrencySymbol = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToPubKeyAddressPolicyHash + +mustPayToPubKeyAddressPolicyCurrencySymbolV2 :: CurrencySymbol +mustPayToPubKeyAddressPolicyCurrencySymbolV2 = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToPubKeyAddressPolicyHashV2 data ConstraintParams = MustPayToPubKey Ledger.PaymentPubKeyHash Value.Value | MustPayToPubKeyAddress Ledger.PaymentPubKeyHash Ledger.StakePubKeyHash Value.Value diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs index 1503d7492a..cd690449c9 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs @@ -626,7 +626,8 @@ lookupMintingPolicy ) => MintingPolicyHash -> m (Versioned MintingPolicy) -lookupMintingPolicy (MintingPolicyHash mph) = fmap MintingPolicy <$> lookupScript (ScriptHash mph) +lookupMintingPolicy (MintingPolicyHash mph) = + fmap MintingPolicy <$> lookupScript (ScriptHash mph) lookupValidator :: ( MonadReader (ScriptLookups a) m diff --git a/plutus-ledger/src/Ledger/Tx.hs b/plutus-ledger/src/Ledger/Tx.hs index 6dfa147c31..171efc3dc5 100644 --- a/plutus-ledger/src/Ledger/Tx.hs +++ b/plutus-ledger/src/Ledger/Tx.hs @@ -115,7 +115,7 @@ data ChainIndexTxOut = _ciTxOutAddress :: Address, -- | Value of the transaction output. _ciTxOutValue :: V2.Value, - -- | Optional datum attached to the transaction output. + -- | Optional datum (inline datum or datum in transaction body) attached to the transaction output. _ciTxOutPublicKeyDatum :: Maybe (V2.DatumHash, Maybe V2.Datum), -- | Optional reference script attached to the transaction output. _ciTxOutReferenceScript :: Maybe (Versioned V1.Script) @@ -126,7 +126,7 @@ data ChainIndexTxOut = _ciTxOutAddress :: Address, -- | Value of the transaction output. _ciTxOutValue :: V1.Value, - -- | Datum attached to the transaction output, either in full or as a + -- | Datum attached to the transaction output, either in full (inline datum or datum in transaction body) or as a -- hash reference. A transaction output protected by a Plutus script -- is guardateed to have an associated datum. _ciTxOutScriptDatum :: (V2.DatumHash, Maybe V2.Datum), diff --git a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs index bb51c0eb39..6ff1a734d6 100644 --- a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs +++ b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs @@ -534,7 +534,7 @@ toCardanoTxOutDatumHash datumHash = C.TxOutDatumHash C.ScriptDataInBabbageEra <$ toCardanoTxOutDatum :: PV2.OutputDatum -> Either ToCardanoError (C.TxOutDatum C.CtxTx C.BabbageEra) toCardanoTxOutDatum PV2.NoOutputDatum = pure toCardanoTxOutNoDatum -toCardanoTxOutDatum (PV2.OutputDatum d) = pure $ toCardanoTxOutDatumInTx d +toCardanoTxOutDatum (PV2.OutputDatum d) = pure $ toCardanoTxOutDatumInline d toCardanoTxOutDatum (PV2.OutputDatumHash dh) = toCardanoTxOutDatumHash dh toCardanoScriptDataHash :: P.DatumHash -> Either ToCardanoError (C.Hash C.ScriptData) From 48f1d65f065369c0682878a766413517c8b4c218 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Fri, 23 Sep 2022 09:58:12 +0200 Subject: [PATCH 04/22] Add tests for inline datum --- .../TxConstraints/MustPayToOtherScript.hs | 82 ++++++++++++++++++- .../TxConstraints/MustPayToPubKeyAddress.hs | 29 +++++-- .../src/Ledger/Constraints/OffChain.hs | 11 ++- .../src/Ledger/Tx/CardanoAPI/Internal.hs | 2 +- plutus-ledger/src/Ledger/Tx/Internal.hs | 10 ++- .../src/Plutus/Contracts/Escrow.hs | 2 +- 6 files changed, 116 insertions(+), 20 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index 9a1471da3f..e7b657036d 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -14,11 +14,13 @@ import Test.Tasty (TestTree, testGroup) import Control.Lens ((&)) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints qualified as Constraints (OutDatum (Hashed), mustMintValueWithRedeemer, mustPayToOtherScript, - mustPayToOtherScriptAddress, +import Ledger.Constraints qualified as Constraints (OutDatum (Hashed, Inline), mustMintValueWithRedeemer, + mustPayToOtherScript, mustPayToOtherScriptAddress, mustSpendScriptOutputWithMatchingDatumAndValue, - plutusV1MintingPolicy, plutusV1OtherScript, unspentOutputs) + plutusV1MintingPolicy, plutusV1OtherScript, plutusV2MintingPolicy, + unspentOutputs) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) +import Ledger.Constraints.OnChain.V2 qualified as V2.Constraints import Ledger.Generators (someTokenValue) import Ledger.Scripts (ScriptError (EvaluationError)) import Ledger.Test (asRedeemer, someValidator, someValidatorHash) @@ -29,10 +31,13 @@ import Plutus.Contract.Test (assertContractError, assertFailedTransaction, asser changeInitialWalletValue, checkPredicateOptions, defaultCheckOptions, w1) import Plutus.Script.Utils.V1.Generators (alwaysSucceedValidatorHash) import Plutus.Script.Utils.V1.Scripts qualified as PSU.V1 +import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 +import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Scripts import Plutus.Trace qualified as Trace import Plutus.V1.Ledger.Api (CurrencySymbol (CurrencySymbol), Datum (Datum), ToData (toBuiltinData), UnsafeFromData (unsafeFromBuiltinData)) import Plutus.V1.Ledger.Value qualified as Value +import Plutus.V2.Ledger.Contexts qualified as V2.Scripts import PlutusTx qualified import PlutusTx.Prelude qualified as P import Wallet (WalletAPIError (InsufficientFunds)) @@ -42,14 +47,16 @@ tests :: TestTree tests = testGroup "MustPayToOtherScript" [ successfulUseOfMustPayToOtherScriptWithMintedToken + , successfulUseOfMustPayToOtherScriptWithMintedTokenV2 , successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken --, successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda -- FAILING when onchain checks for only ada value and token is present -- PLT-885 , successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance , successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue , contractErrorWhenAttemptingToSpendMoreThanAdaBalance , contractErrorWhenAttemptingToSpendMoreThanTokenBalance + , phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum , phase2ErrorWhenExpectingMoreThanValue - ] + ] someDatum :: Datum someDatum = Datum $ PlutusTx.dataToBuiltinData $ PlutusTx.toData ("datum" :: P.BuiltinByteString) @@ -69,9 +76,15 @@ adaValue = Ada.lovelaceValueOf adaAmount tknValue :: Value.Value tknValue = Value.singleton mustPayToOtherScriptPolicyCurrencySymbol "mint-me" 1 +tknValueV2 :: Value.Value +tknValueV2 = Value.singleton mustPayToOtherScriptPolicyCurrencySymbolV2 "mint-me" 1 + adaAndTokenValue :: Value.Value adaAndTokenValue = adaValue <> tknValue +adaAndTokenValueV2 :: Value.Value +adaAndTokenValueV2 = adaValue <> tknValueV2 + otherTokenValue :: Value.Value otherTokenValue = someTokenValue "someToken" 1 @@ -100,6 +113,28 @@ successfulUseOfMustPayToOtherScriptWithMintedToken = (assertValidatedTransactionCount 1) (void $ trace contract) +-- | Contract to a single transaction with mustSpendScriptOutputs offchain constraint and mint with policy using +-- matching onchain constraint, using Plutus V2 script and inline datum +mustPayToOtherScriptInlineContractV2 :: Value.Value -> Redeemer -> Contract () Empty ContractError () +mustPayToOtherScriptInlineContractV2 offChainValue onChainConstraint = do + let lookups1 = Constraints.plutusV2MintingPolicy mustPayToOtherScriptPolicyV2 + tx1 = Constraints.mustPayToOtherScript someValidatorHash (Constraints.Inline someDatum) offChainValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValueV2 + ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + +-- | Valid scenario using offchain and onchain constraint mustPayToOtherScript with exact token value being minted +-- using inline datum +successfulUseOfMustPayToOtherScriptWithMintedTokenV2 :: TestTree +successfulUseOfMustPayToOtherScriptWithMintedTokenV2 = + let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum adaAndTokenValueV2 + contract = mustPayToOtherScriptInlineContractV2 adaAndTokenValueV2 onChainConstraint + + in checkPredicateOptions defaultCheckOptions + "Successful use of offchain and onchain mustPayToOtherScript constraint with wallet's exact ada balance with inline datum" + (assertValidatedTransactionCount 1) + (void $ trace contract) + -- | Valid scenario using mustPayToOtherScript offchain constraint to include ada and token whilst onchain constraint checks for token value only successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: TestTree successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken = @@ -161,6 +196,15 @@ successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue = (assertValidatedTransactionCount 1) (void $ trace contract) +-- | Invalid contract that try to used inline datum in a V1 script +mustPayToOtherScriptInlineContract :: Value.Value -> Redeemer -> Contract () Empty ContractError () +mustPayToOtherScriptInlineContract offChainValue onChainConstraint = do + let lookups1 = Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy + tx1 = Constraints.mustPayToOtherScript someValidatorHash (Constraints.Inline someDatum) offChainValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + -- | Contract error when ada amount to send to other script is greater than wallet balance contractErrorWhenAttemptingToSpendMoreThanAdaBalance :: TestTree contractErrorWhenAttemptingToSpendMoreThanAdaBalance = @@ -184,6 +228,19 @@ contractErrorWhenAttemptingToSpendMoreThanTokenBalance = (assertContractError contract (Trace.walletInstanceTag w1) (\case WalletContractError (InsufficientFunds _) -> True; _ -> False) "failed to throw error") (void $ trace contract) +-- | Phase-1 failure when mustPayToOtherScript in a V1 script use inline datum +phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum :: TestTree +phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum = + let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum adaAndTokenValue + contract = mustPayToOtherScriptInlineContract adaAndTokenValue onChainConstraint + + in checkPredicateOptions defaultCheckOptions + "Phase-1 failure when mustPayToOtherScript in a V1 script use inline datum" + (assertFailedTransaction (\_ err _ -> case err of {Ledger.CardanoLedgerValidationError _ -> True; _ -> False })) + (void $ trace contract) + + + -- | Phase-2 validation failure when onchain mustSpendScriptOutput constraint expects more than actual ada value phase2ErrorWhenExpectingMoreThanValue :: TestTree phase2ErrorWhenExpectingMoreThanValue = @@ -204,17 +261,34 @@ mkMustPayToOtherScriptPolicy t = case t of MustPayToOtherScript vh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh (Constraints.Hashed d) v) MustPayToOtherScriptAddress vh svh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh (Constraints.Hashed d) v) +{-# INLINEABLE mkMustPayToOtherScriptPolicyV2 #-} +mkMustPayToOtherScriptPolicyV2 :: ConstraintParams -> V2.Scripts.ScriptContext -> Bool +mkMustPayToOtherScriptPolicyV2 t = case t of + MustPayToOtherScript vh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh (Constraints.Inline d) v) + MustPayToOtherScriptAddress vh svh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh (Constraints.Inline d) v) + mustPayToOtherScriptPolicy :: Scripts.MintingPolicy mustPayToOtherScriptPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where wrap = Scripts.mkUntypedMintingPolicy mkMustPayToOtherScriptPolicy +mustPayToOtherScriptPolicyV2 :: V2.Scripts.MintingPolicy +mustPayToOtherScriptPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) + where + wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToOtherScriptPolicyV2 + mustPayToOtherScriptPolicyHash :: Ledger.MintingPolicyHash mustPayToOtherScriptPolicyHash = PSU.V1.mintingPolicyHash mustPayToOtherScriptPolicy +mustPayToOtherScriptPolicyHashV2 :: Ledger.MintingPolicyHash +mustPayToOtherScriptPolicyHashV2 = PSU.V2.mintingPolicyHash mustPayToOtherScriptPolicyV2 + mustPayToOtherScriptPolicyCurrencySymbol :: CurrencySymbol mustPayToOtherScriptPolicyCurrencySymbol = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToOtherScriptPolicyHash +mustPayToOtherScriptPolicyCurrencySymbolV2 :: CurrencySymbol +mustPayToOtherScriptPolicyCurrencySymbolV2 = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToOtherScriptPolicyHashV2 + data ConstraintParams = MustPayToOtherScript PSU.V1.ValidatorHash Datum Value.Value | MustPayToOtherScriptAddress PSU.V1.ValidatorHash PSU.V1.StakeValidatorHash Datum Value.Value deriving (Show) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 29b89c06e2..54563b93ac 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -25,13 +25,13 @@ import Ledger.Tx qualified as Tx import Ledger.Typed.Scripts qualified as Scripts import Plutus.Contract as Con import Plutus.Contract.Test (assertFailedTransaction, assertValidatedTransactionCount, checkPredicate, - checkPredicateOptions, mockWalletPaymentPubKeyHash, w1, w2) + mockWalletPaymentPubKeyHash, w1, w2) import Plutus.Script.Utils.V1.Scripts qualified as PSU.V1 import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 -import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Script +import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Scripts import Plutus.Trace qualified as Trace import Plutus.V1.Ledger.Value qualified as Value -import Plutus.V2.Ledger.Contexts qualified as V2.Script +import Plutus.V2.Ledger.Contexts qualified as V2.Scripts import PlutusTx qualified import PlutusTx.Prelude qualified as P @@ -47,6 +47,7 @@ tests = , successfulUseOfMustPayWithDatumToPubKey , successfulUseOfMustPayWithInlineDatumToPubKeyV2 , successfulUseOfMustPayWithDatumToPubKeyAddress + , phase1FailureWhenUsingInlineDatumWithV1 , phase2FailureWhenUsingUnexpectedPaymentPubKeyHash --, phase2FailureWhenUsingUnexpectedStakePubKeyHash -- onchain check not implemented , phase2FailureWhenUsingUnexpectedDatum @@ -219,6 +220,22 @@ successfulUseOfMustPayWithDatumToPubKeyAddress = (assertValidatedTransactionCount 1) (void $ trace contract) +-- | Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum +phase1FailureWhenUsingInlineDatumWithV1 :: TestTree +phase1FailureWhenUsingInlineDatumWithV1 = + let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue + contract = do + let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash (Constraints.Inline someDatum) adaValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + + in checkPredicate + "Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum" + (assertFailedTransaction (\_ err _ -> case err of {Ledger.CardanoLedgerValidationError _ -> True; _ -> False })) + (void $ trace contract) + -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the PaymentPubkeyHash" phase2FailureWhenUsingUnexpectedPaymentPubKeyHash :: TestTree phase2FailureWhenUsingUnexpectedPaymentPubKeyHash = @@ -279,7 +296,7 @@ mkMustPayToPubKeyAddressPolicy t = case t of MustPayWithDatumToPubKeyAddress ppkh spkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh (Constraints.Hashed d) v) {-# INLINEABLE mkMustPayToPubKeyAddressPolicyV2 #-} -mkMustPayToPubKeyAddressPolicyV2 :: ConstraintParams -> V2.Script.ScriptContext -> Bool +mkMustPayToPubKeyAddressPolicyV2 :: ConstraintParams -> V2.Scripts.ScriptContext -> Bool mkMustPayToPubKeyAddressPolicyV2 t = case t of MustPayToPubKey ppkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKey ppkh v) MustPayToPubKeyAddress ppkh spkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKeyAddress ppkh spkh v) @@ -291,10 +308,10 @@ mustPayToPubKeyAddressPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile where wrap = Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy -mustPayToPubKeyAddressPolicyV2 :: V2.Script.MintingPolicy +mustPayToPubKeyAddressPolicyV2 :: V2.Scripts.MintingPolicy mustPayToPubKeyAddressPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where - wrap = V2.Script.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicyV2 + wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicyV2 mustPayToPubKeyAddressPolicyHash :: Ledger.MintingPolicyHash mustPayToPubKeyAddressPolicyHash = PSU.V1.mintingPolicyHash mustPayToPubKeyAddressPolicy diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs index cd690449c9..a470b29abf 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs @@ -626,8 +626,7 @@ lookupMintingPolicy ) => MintingPolicyHash -> m (Versioned MintingPolicy) -lookupMintingPolicy (MintingPolicyHash mph) = - fmap MintingPolicy <$> lookupScript (ScriptHash mph) +lookupMintingPolicy (MintingPolicyHash mph) = fmap MintingPolicy <$> lookupScript (ScriptHash mph) lookupValidator :: ( MonadReader (ScriptLookups a) m @@ -658,6 +657,7 @@ processConstraint => TxConstraint -> m () processConstraint = \case + MustIncludeDatum dv -> let theHash = P.datumHash dv in unbalancedTx . tx . Tx.datumWitnesses . at theHash ?= dv @@ -667,6 +667,7 @@ processConstraint = \case unbalancedTx . requiredSignatories <>= Set.singleton pk MustSpendAtLeast vl -> valueSpentInputs <>= required vl MustProduceAtLeast vl -> valueSpentOutputs <>= required vl + MustSpendPubKeyOutput txo -> do txout <- lookupTxOutRef txo case txout of @@ -675,6 +676,7 @@ processConstraint = \case unbalancedTx . tx . Tx.inputs %= (Tx.pubKeyTxInput txo :) valueSpentInputs <>= provided _ciTxOutValue _ -> throwError (TxOutRefWrongType txo) + MustSpendScriptOutput txo red -> do txout <- lookupTxOutRef txo mscriptTXO <- resolveScriptTxOut txout @@ -698,15 +700,15 @@ processConstraint = \case if i < 0 then valueSpentInputs <>= provided (value (negate i)) else valueSpentOutputs <>= provided (value i) - unbalancedTx . tx . Tx.mintScripts %= Map.insert mpsHash red unbalancedTx . tx . Tx.scriptWitnesses %= Map.insert (ScriptHash mpsHashBytes) (fmap getMintingPolicy mintingPolicyScript) unbalancedTx . tx . Tx.mint <>= value i + MustPayToPubKeyAddress pk skhM mdv _refScript vl -> do -- TODO: implement adding reference script -- if datum is presented, add it to 'datumWitnesses' forM_ mdv $ \dv -> do - let d = getOutDatum dv -- FIXME + let d = getOutDatum dv unbalancedTx . tx . Tx.datumWitnesses . at (P.datumHash d) ?= d let pv2TxOut = PV2.TxOut { PV2.txOutAddress=pubKeyHashAddress pk skhM , PV2.txOutValue=vl @@ -720,6 +722,7 @@ processConstraint = \case txOut <- toCardanoTxOutWithOutputDatum pv2TxOut <&> outDatumHash .~ txInDatum unbalancedTx . tx . Tx.outputs %= (txOut :) valueSpentOutputs <>= provided vl + MustPayToOtherScript vlh svhM dv _refScript vl -> do -- TODO: implement adding reference script let addr = Address.scriptValidatorHashAddress vlh svhM diff --git a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs index 6ff1a734d6..43831e25db 100644 --- a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs +++ b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs @@ -515,7 +515,7 @@ fromCardanoTxOutDatumHash (C.TxOutDatumInline _ d) = Just $ P.DatumHash $ Plutus fromCardanoTxOutDatum :: C.TxOutDatum C.CtxTx era -> PV2.OutputDatum fromCardanoTxOutDatum C.TxOutDatumNone = PV2.NoOutputDatum fromCardanoTxOutDatum (C.TxOutDatumHash _ h) = PV2.OutputDatumHash $ PV2.DatumHash $ PlutusTx.toBuiltin (C.serialiseToRawBytes h) -fromCardanoTxOutDatum (C.TxOutDatumInTx _ d) = PV2.OutputDatum $ PV2.Datum $ fromCardanoScriptData d +fromCardanoTxOutDatum (C.TxOutDatumInTx _ d) = PV2.OutputDatumHash $ PV2.DatumHash $ PlutusTx.toBuiltin (C.serialiseToRawBytes (C.hashScriptData d)) fromCardanoTxOutDatum (C.TxOutDatumInline _ d) = PV2.OutputDatum $ PV2.Datum $ fromCardanoScriptData d toCardanoTxOutNoDatum :: C.TxOutDatum C.CtxTx C.BabbageEra diff --git a/plutus-ledger/src/Ledger/Tx/Internal.hs b/plutus-ledger/src/Ledger/Tx/Internal.hs index 54a9b00709..b690596544 100644 --- a/plutus-ledger/src/Ledger/Tx/Internal.hs +++ b/plutus-ledger/src/Ledger/Tx/Internal.hs @@ -40,7 +40,7 @@ import Ledger.Contexts.Orphans () import Ledger.Crypto import Ledger.DCert.Orphans () import Ledger.Slot -import Ledger.Tx.CardanoAPI.Internal (fromCardanoAddressInEra, fromCardanoTxOutDatumHash, fromCardanoTxOutValue, +import Ledger.Tx.CardanoAPI.Internal (fromCardanoAddressInEra, fromCardanoTxOutDatum, fromCardanoTxOutValue, fromCardanoValue) import Ledger.Tx.CardanoAPITemp qualified as C import Ledger.Tx.Orphans () @@ -53,6 +53,7 @@ import Plutus.V1.Ledger.Scripts import Plutus.V1.Ledger.Tx hiding (TxIn (..), TxInType (..), TxOut (..), inRef, inScripts, inType, pubKeyTxIn, pubKeyTxIns, scriptTxIn, scriptTxIns) import Plutus.V1.Ledger.Value as V +import Plutus.V2.Ledger.Api qualified as PV2 import PlutusTx.Lattice import PlutusTx.Prelude (BuiltinByteString) import PlutusTx.Prelude qualified as PlutusTx @@ -227,9 +228,10 @@ instance Pretty TxOut where hang 2 $ vsep ["-" <+> pretty (fromCardanoTxOutValue v) <+> "addressed to" , pretty (fromCardanoAddressInEra addr) - , "with" <+> case fromCardanoTxOutDatumHash d of - Nothing -> "no datum" - Just dh -> "datum hash" <+> pretty dh + , "with" <+> case fromCardanoTxOutDatum d of + PV2.NoOutputDatum -> "no datum" + PV2.OutputDatum dv -> "inline datum" <+> viaShow dv + PV2.OutputDatumHash dh -> "datum hash" <+> pretty dh , "and with" <+> case rs of C.ReferenceScript _ (C.ScriptInAnyLang _ s) -> "reference script hash" <+> viaShow (C.hashScript s) diff --git a/plutus-use-cases/src/Plutus/Contracts/Escrow.hs b/plutus-use-cases/src/Plutus/Contracts/Escrow.hs index 5680e1aa67..4484afd5c9 100644 --- a/plutus-use-cases/src/Plutus/Contracts/Escrow.hs +++ b/plutus-use-cases/src/Plutus/Contracts/Escrow.hs @@ -166,7 +166,7 @@ mkTx = \case PaymentPubKeyTarget pkh vl -> Constraints.mustPayToPubKey pkh vl ScriptTarget vs ds vl -> - Constraints.mustPayToOtherScript vs ds vl + Constraints.mustPayToOtherScript (Hashed vs) ds vl data Action = Redeem | Refund From 835cd12a1918a0f41808ee438a1d240006a700a9 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Fri, 23 Sep 2022 11:37:27 +0200 Subject: [PATCH 05/22] add smart constructors for inline datum --- plutus-contract/test/Spec/Balancing.hs | 7 +-- plutus-contract/test/Spec/Contract.hs | 6 +- .../test/Spec/Contract/TxConstraints.hs | 8 +-- plutus-contract/test/Spec/ErrorChecking.hs | 4 +- .../Spec/TxConstraints/MustIncludeDatum.hs | 13 ++--- .../TxConstraints/MustPayToOtherScript.hs | 19 ++++--- .../TxConstraints/MustPayToPubKeyAddress.hs | 29 +++++----- .../src/Ledger/Constraints.hs | 6 +- .../src/Ledger/Constraints/TxConstraints.hs | 55 ++++++++++++++++--- plutus-ledger-constraints/test/Spec.hs | 2 +- .../src/Ledger/Tx/Constraints/OffChain.hs | 13 ++++- .../src/Plutus/Contracts/Escrow.hs | 2 +- plutus-use-cases/test/Spec/future.pir | 33 +++++++++-- plutus-use-cases/test/Spec/renderGuess.txt | 8 +-- 14 files changed, 136 insertions(+), 69 deletions(-) diff --git a/plutus-contract/test/Spec/Balancing.hs b/plutus-contract/test/Spec/Balancing.hs index f2d3d023a8..26186a3b7e 100644 --- a/plutus-contract/test/Spec/Balancing.hs +++ b/plutus-contract/test/Spec/Balancing.hs @@ -11,10 +11,10 @@ import Data.Map qualified as Map import Data.Void (Void) import Test.Tasty (TestTree, testGroup) +import Ledger (unitDatum, unitRedeemer) import Ledger qualified import Ledger.Ada qualified as Ada import Ledger.Constraints qualified as L.Constraints -import Ledger.Scripts (unitRedeemer) import Ledger.Test import Ledger.Tx.Constraints qualified as Tx.Constraints import Ledger.Value qualified as Value @@ -30,9 +30,6 @@ import PlutusTx qualified import Prelude hiding (not) import Wallet.Emulator qualified as EM -unitDatum :: L.Constraints.OutDatum -unitDatum = L.Constraints.Hashed Ledger.unitDatum - tests :: TestTree tests = testGroup "balancing" @@ -101,7 +98,7 @@ balanceTxnMinAda2 = <> L.Constraints.plutusV1MintingPolicy mps constraints = L.Constraints.mustSpendScriptOutput txOutRef unitRedeemer -- spend utxo1 <> L.Constraints.mustPayToOtherScript vHash unitDatum (vB 1) -- 2 ada and 1 B to script - <> L.Constraints.mustPayToOtherScript vHash (L.Constraints.Hashed $ Datum $ PlutusTx.toBuiltinData (0 :: Integer)) (vB 1) -- 2 ada and 1 B to script (different datum) + <> L.Constraints.mustPayToOtherScript vHash (Datum $ PlutusTx.toBuiltinData (0 :: Integer)) (vB 1) -- 2 ada and 1 B to script (different datum) <> L.Constraints.mustMintValue (vL 1) -- 1 L and 2 ada to wallet2 submitTxConfirmed =<< mkTx lookups constraints diff --git a/plutus-contract/test/Spec/Contract.hs b/plutus-contract/test/Spec/Contract.hs index 4023dbed01..f6cea14be4 100644 --- a/plutus-contract/test/Spec/Contract.hs +++ b/plutus-contract/test/Spec/Contract.hs @@ -212,7 +212,7 @@ tests = , let c :: Contract [Maybe DatumHash] Schema ContractError () = do let w2PubKeyHash = mockWalletPaymentPubKeyHash w2 - let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash (Constraints.Hashed datum) (Ada.adaValueOf 10) + let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash datum (Ada.adaValueOf 10) tx <- submitTx payment let txOuts = fmap fst $ Ledger.getCardanoTxOutRefs tx -- tell the tx out' datum hash that was specified by 'mustPayWithDatumToPubKey' @@ -232,11 +232,11 @@ tests = -- in case of two transactions with 'mustPayWithDatumToPubKey' , let c1 :: Contract [Maybe DatumHash] Schema ContractError () = do let w2PubKeyHash = mockWalletPaymentPubKeyHash w2 - let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash (Constraints.Hashed datum1) (Ada.adaValueOf 10) + let payment = Constraints.mustPayWithDatumToPubKey w2PubKeyHash datum1 (Ada.adaValueOf 10) void $ submitTx payment c2 :: Contract [Maybe DatumHash] Schema ContractError () = do let w3PubKeyHash = mockWalletPaymentPubKeyHash w3 - let payment = Constraints.mustPayWithDatumToPubKey w3PubKeyHash (Constraints.Hashed datum2) (Ada.adaValueOf 50) + let payment = Constraints.mustPayWithDatumToPubKey w3PubKeyHash datum2 (Ada.adaValueOf 50) void $ submitTx payment datum1 = Datum $ PlutusTx.toBuiltinData (23 :: Integer) diff --git a/plutus-contract/test/Spec/Contract/TxConstraints.hs b/plutus-contract/test/Spec/Contract/TxConstraints.hs index 8a64dab650..b5e78a5441 100644 --- a/plutus-contract/test/Spec/Contract/TxConstraints.hs +++ b/plutus-contract/test/Spec/Contract/TxConstraints.hs @@ -128,7 +128,7 @@ mustReferenceOutputV1ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV1ValidatorAddress lookups = TC.unspentOutputs utxos - tx = TC.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = TC.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> TC.mustSpendPubKeyOutput utxoRefForBalance1 mkTxConstraints @Void lookups tx >>= submitTxConfirmed @@ -152,7 +152,7 @@ mustReferenceOutputTxV1ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV1ValidatorAddress lookups = Tx.Constraints.unspentOutputs utxos - tx = Tx.Constraints.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = Tx.Constraints.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> Tx.Constraints.mustSpendPubKeyOutput utxoRefForBalance1 <> Tx.Constraints.mustUseOutputAsCollateral utxoRefForBalance1 submitTxConfirmed $ mkTx lookups tx @@ -197,7 +197,7 @@ mustReferenceOutputV2ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress lookups = TC.unspentOutputs utxos - tx = TC.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = TC.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> TC.mustSpendPubKeyOutput utxoRefForBalance1 mkTxConstraints @Void lookups tx >>= submitTxConfirmed @@ -221,7 +221,7 @@ mustReferenceOutputTxV2ConTest = do let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress lookups = Tx.Constraints.unspentOutputs utxos - tx = Tx.Constraints.mustPayToOtherScript vh (TC.Hashed $ Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) + tx = Tx.Constraints.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5) <> Tx.Constraints.mustSpendPubKeyOutput utxoRefForBalance1 <> Tx.Constraints.mustUseOutputAsCollateral utxoRefForBalance1 submitTxConfirmed $ mkTx lookups tx diff --git a/plutus-contract/test/Spec/ErrorChecking.hs b/plutus-contract/test/Spec/ErrorChecking.hs index 0a8ce6673d..7cdd5c7216 100644 --- a/plutus-contract/test/Spec/ErrorChecking.hs +++ b/plutus-contract/test/Spec/ErrorChecking.hs @@ -19,7 +19,7 @@ import Data.Row import Test.Tasty import Ledger.Ada qualified as Ada -import Ledger.Constraints (OutDatum (Inline), collectFromTheScript, mustPayToOtherScript) +import Ledger.Constraints (collectFromTheScript, mustPayToOtherScript) import Ledger.Tx (getCardanoTxId) import Ledger.Typed.Scripts qualified as Scripts hiding (validatorHash) import Plutus.Contract as Contract @@ -141,7 +141,7 @@ contract = selectList [failFalseC, failHeadNilC, divZeroC, divZeroTraceC, succes run validator = void $ do let addr = mkValidatorAddress (validatorScript validator) hash = validatorHash (validatorScript validator) - tx = mustPayToOtherScript hash (Inline $ Datum $ toBuiltinData ()) (Ada.adaValueOf 10) + tx = mustPayToOtherScript hash (Datum $ toBuiltinData ()) (Ada.adaValueOf 10) r <- submitTx tx awaitTxConfirmed (getCardanoTxId r) utxos <- utxosAt addr diff --git a/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs b/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs index 610b6fb53b..548b720aa1 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustIncludeDatum.hs @@ -13,10 +13,9 @@ import Test.Tasty (TestTree, testGroup) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints qualified as Constraints (OutDatum (..), collectFromTheScript, mustIncludeDatum, - mustMintValueWithRedeemer, mustPayToOtherScript, mustPayToTheScript, - mustPayWithDatumToPubKey, plutusV1MintingPolicy, - typedValidatorLookups, unspentOutputs) +import Ledger.Constraints qualified as Constraints (collectFromTheScript, mustIncludeDatum, mustMintValueWithRedeemer, + mustPayToOtherScript, mustPayToTheScript, mustPayWithDatumToPubKey, + plutusV1MintingPolicy, typedValidatorLookups, unspentOutputs) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) import Ledger.Tx qualified as Tx import Ledger.Typed.Scripts qualified as Scripts @@ -74,8 +73,8 @@ mustIncludeDatumWhenPayingToScriptContract offChainDatums onChainDatums = do where mustPayToTheScriptAndIncludeDatumsIfUsingOffChainConstraint = if null offChainDatums - then Constraints.mustPayToOtherScript valHash (Constraints.Hashed validatorDatum) (Ada.lovelaceValueOf 2_000_000) - else mconcat $ fmap (\datum -> Constraints.mustPayToOtherScript valHash (Constraints.Hashed validatorDatum) (Ada.lovelaceValueOf 2_000_000) <> Constraints.mustIncludeDatum datum) offChainDatums + then Constraints.mustPayToOtherScript valHash validatorDatum (Ada.lovelaceValueOf 2_000_000) + else mconcat $ fmap (\datum -> Constraints.mustPayToOtherScript valHash validatorDatum (Ada.lovelaceValueOf 2_000_000) <> Constraints.mustIncludeDatum datum) offChainDatums trace :: Contract () Empty ContractError () -> Trace.EmulatorTrace () trace contract = do @@ -164,7 +163,7 @@ mustIncludeDatumToPubKeyAddress = let onChainConstraintDatumsAsRedeemer = Redeemer $ PlutusTx.dataToBuiltinData $ PlutusTx.toData ([validatorDatum] :: [Datum]) contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustIncludeDatumPolicy - tx1 = Constraints.mustPayWithDatumToPubKey (mockWalletPaymentPubKeyHash w1) (Constraints.Hashed validatorDatum) (Ada.lovelaceValueOf 25_000_000) + tx1 = Constraints.mustPayWithDatumToPubKey (mockWalletPaymentPubKeyHash w1) validatorDatum (Ada.lovelaceValueOf 25_000_000) <> Constraints.mustIncludeDatum validatorDatum <> Constraints.mustMintValueWithRedeemer onChainConstraintDatumsAsRedeemer tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index e7b657036d..2773293929 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -14,8 +14,9 @@ import Test.Tasty (TestTree, testGroup) import Control.Lens ((&)) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints qualified as Constraints (OutDatum (Hashed, Inline), mustMintValueWithRedeemer, - mustPayToOtherScript, mustPayToOtherScriptAddress, +import Ledger.Constraints qualified as Constraints (mustMintValueWithRedeemer, mustPayToOtherScript, + mustPayToOtherScriptAddress, mustPayToOtherScriptAddressInlineDatum, + mustPayToOtherScriptInlineDatum, mustSpendScriptOutputWithMatchingDatumAndValue, plutusV1MintingPolicy, plutusV1OtherScript, plutusV2MintingPolicy, unspentOutputs) @@ -97,7 +98,7 @@ trace contract = do mustPayToOtherScriptContract :: Value.Value -> Ledger.Redeemer -> Contract () Empty ContractError () mustPayToOtherScriptContract offChainValue onChainConstraint = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy - tx1 = Constraints.mustPayToOtherScript someValidatorHash (Constraints.Hashed someDatum) offChainValue + tx1 = Constraints.mustPayToOtherScript someValidatorHash someDatum offChainValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -118,7 +119,7 @@ successfulUseOfMustPayToOtherScriptWithMintedToken = mustPayToOtherScriptInlineContractV2 :: Value.Value -> Redeemer -> Contract () Empty ContractError () mustPayToOtherScriptInlineContractV2 offChainValue onChainConstraint = do let lookups1 = Constraints.plutusV2MintingPolicy mustPayToOtherScriptPolicyV2 - tx1 = Constraints.mustPayToOtherScript someValidatorHash (Constraints.Inline someDatum) offChainValue + tx1 = Constraints.mustPayToOtherScriptInlineDatum someValidatorHash someDatum offChainValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValueV2 ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -200,7 +201,7 @@ successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue = mustPayToOtherScriptInlineContract :: Value.Value -> Redeemer -> Contract () Empty ContractError () mustPayToOtherScriptInlineContract offChainValue onChainConstraint = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy - tx1 = Constraints.mustPayToOtherScript someValidatorHash (Constraints.Inline someDatum) offChainValue + tx1 = Constraints.mustPayToOtherScriptInlineDatum someValidatorHash someDatum offChainValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -258,14 +259,14 @@ instance Scripts.ValidatorTypes UnitTest {-# INLINEABLE mkMustPayToOtherScriptPolicy #-} mkMustPayToOtherScriptPolicy :: ConstraintParams -> Ledger.ScriptContext -> Bool mkMustPayToOtherScriptPolicy t = case t of - MustPayToOtherScript vh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh (Constraints.Hashed d) v) - MustPayToOtherScriptAddress vh svh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh (Constraints.Hashed d) v) + MustPayToOtherScript vh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh d v) + MustPayToOtherScriptAddress vh svh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh d v) {-# INLINEABLE mkMustPayToOtherScriptPolicyV2 #-} mkMustPayToOtherScriptPolicyV2 :: ConstraintParams -> V2.Scripts.ScriptContext -> Bool mkMustPayToOtherScriptPolicyV2 t = case t of - MustPayToOtherScript vh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh (Constraints.Inline d) v) - MustPayToOtherScriptAddress vh svh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh (Constraints.Inline d) v) + MustPayToOtherScript vh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptInlineDatum vh d v) + MustPayToOtherScriptAddress vh svh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddressInlineDatum vh svh d v) mustPayToOtherScriptPolicy :: Scripts.MintingPolicy mustPayToOtherScriptPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 54563b93ac..8315b0184c 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -13,9 +13,10 @@ import Test.Tasty (TestTree, testGroup) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints qualified as Constraints (OutDatum (Hashed, Inline), mustMintValueWithRedeemer, - mustPayToPubKey, mustPayToPubKeyAddress, mustPayWithDatumToPubKey, - mustPayWithDatumToPubKeyAddress, plutusV1MintingPolicy, +import Ledger.Constraints qualified as Constraints (mustMintValueWithRedeemer, mustPayToPubKey, mustPayToPubKeyAddress, + mustPayWithDatumToPubKey, mustPayWithDatumToPubKeyAddress, + mustPayWithInlineDatumToPubKey, + mustPayWithInlineDatumToPubKeyAddress, plutusV1MintingPolicy, plutusV2MintingPolicy) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) import Ledger.Constraints.OnChain.V2 qualified as V2.Constraints @@ -178,7 +179,7 @@ successfulUseOfMustPayWithDatumToPubKey = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash (Constraints.Hashed someDatum) adaValue + tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -194,7 +195,7 @@ successfulUseOfMustPayWithInlineDatumToPubKeyV2 = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV2MintingPolicy mustPayToPubKeyAddressPolicyV2 - tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash (Constraints.Inline someDatum) adaValue + tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValueV2 ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -210,7 +211,7 @@ successfulUseOfMustPayWithDatumToPubKeyAddress = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -226,7 +227,7 @@ phase1FailureWhenUsingInlineDatumWithV1 = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash (Constraints.Inline someDatum) adaValue + tx1 = Constraints.mustPayWithInlineDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -242,7 +243,7 @@ phase2FailureWhenUsingUnexpectedPaymentPubKeyHash = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w1PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w1PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -258,7 +259,7 @@ phase2FailureWhenUsingUnexpectedDatum = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash otherDatum adaValue contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -274,7 +275,7 @@ phase2FailureWhenUsingUnexpectedValue = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum (Ada.lovelaceValueOf $ adaAmount + 1) contract = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash (Constraints.Hashed someDatum) adaValue + tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -292,16 +293,16 @@ mkMustPayToPubKeyAddressPolicy :: ConstraintParams -> Ledger.ScriptContext -> Bo mkMustPayToPubKeyAddressPolicy t = case t of MustPayToPubKey ppkh v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKey ppkh v) MustPayToPubKeyAddress ppkh spkh v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKeyAddress ppkh spkh v) - MustPayWithDatumToPubKey ppkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh (Constraints.Hashed d) v) - MustPayWithDatumToPubKeyAddress ppkh spkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh (Constraints.Hashed d) v) + MustPayWithDatumToPubKey ppkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh d v) + MustPayWithDatumToPubKeyAddress ppkh spkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh d v) {-# INLINEABLE mkMustPayToPubKeyAddressPolicyV2 #-} mkMustPayToPubKeyAddressPolicyV2 :: ConstraintParams -> V2.Scripts.ScriptContext -> Bool mkMustPayToPubKeyAddressPolicyV2 t = case t of MustPayToPubKey ppkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKey ppkh v) MustPayToPubKeyAddress ppkh spkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKeyAddress ppkh spkh v) - MustPayWithDatumToPubKey ppkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh (Constraints.Inline d) v) - MustPayWithDatumToPubKeyAddress ppkh spkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh (Constraints.Inline d) v) + MustPayWithDatumToPubKey ppkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithInlineDatumToPubKey ppkh d v) + MustPayWithDatumToPubKeyAddress ppkh spkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithInlineDatumToPubKeyAddress ppkh spkh d v) mustPayToPubKeyAddressPolicy :: Scripts.MintingPolicy mustPayToPubKeyAddressPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) diff --git a/plutus-ledger-constraints/src/Ledger/Constraints.hs b/plutus-ledger-constraints/src/Ledger/Constraints.hs index f3c010d2e2..b801794723 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints.hs @@ -6,13 +6,13 @@ module Ledger.Constraints( , TC.ScriptInputConstraint(..) , TC.ScriptOutputConstraint(..) -- * Defining constraints - , TC.OutDatum(..) - , TC.getOutDatum , TC.mustPayToTheScript , TC.mustPayToPubKey , TC.mustPayToPubKeyAddress , TC.mustPayWithDatumToPubKey , TC.mustPayWithDatumToPubKeyAddress + , TC.mustPayWithInlineDatumToPubKey + , TC.mustPayWithInlineDatumToPubKeyAddress , TC.mustPayToAddressWithReferenceScript , TC.mustPayToAddressWithReferenceValidator , TC.mustPayToAddressWithReferenceMintingPolicy @@ -32,7 +32,9 @@ module Ledger.Constraints( , TC.mustProduceAtLeast , TC.mustIncludeDatum , TC.mustPayToOtherScript + , TC.mustPayToOtherScriptInlineDatum , TC.mustPayToOtherScriptAddress + , TC.mustPayToOtherScriptAddressInlineDatum , TC.mustHashDatum , TC.mustSatisfyAnyOf -- * Defining off-chain only constraints diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs index dbb04dbcef..ea9affedd6 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs @@ -351,11 +351,23 @@ mustPayToPubKeyAddress pkh skh vl = mustPayWithDatumToPubKey :: forall i o . PaymentPubKeyHash - -> OutDatum + -> Datum -> Value -> TxConstraints i o mustPayWithDatumToPubKey pk datum vl = - singleton (MustPayToPubKeyAddress pk Nothing (Just datum) Nothing vl) + singleton (MustPayToPubKeyAddress pk Nothing (Just $ Hashed datum) Nothing vl) + +{-# INLINABLE mustPayWithInlineDatumToPubKey #-} +-- | @mustPayWithInlineDatumToPubKey pkh d v@ is the same as +-- 'mustPayWithDatumToPubKeyAddress', but with an inline datum and without the staking key hash. +mustPayWithInlineDatumToPubKey + :: forall i o + . PaymentPubKeyHash + -> Datum + -> Value + -> TxConstraints i o +mustPayWithInlineDatumToPubKey pk datum vl = + singleton (MustPayToPubKeyAddress pk Nothing (Just $ Inline datum) Nothing vl) {-# INLINABLE mustPayWithDatumToPubKeyAddress #-} -- | @mustPayWithDatumToPubKeyAddress pkh skh d v@ locks a transaction output @@ -372,11 +384,24 @@ mustPayWithDatumToPubKeyAddress :: forall i o . PaymentPubKeyHash -> StakePubKeyHash - -> OutDatum + -> Datum -> Value -> TxConstraints i o mustPayWithDatumToPubKeyAddress pkh skh datum vl = - singleton (MustPayToPubKeyAddress pkh (Just skh) (Just datum) Nothing vl) + singleton (MustPayToPubKeyAddress pkh (Just skh) (Just $ Hashed datum) Nothing vl) + +{-# INLINABLE mustPayWithInlineDatumToPubKeyAddress #-} +-- | @mustPayWithInlineInlineDatumToPubKeyAddress pkh d v@ is the same as +-- 'mustPayWithInlineDatumToPubKeyAddress', but the datum is inline in the Tx. +mustPayWithInlineDatumToPubKeyAddress + :: forall i o + . PaymentPubKeyHash + -> StakePubKeyHash + -> Datum + -> Value + -> TxConstraints i o +mustPayWithInlineDatumToPubKeyAddress pkh skh datum vl = + singleton (MustPayToPubKeyAddress pkh (Just skh) (Just $ Inline datum) Nothing vl) {-# INLINABLE mustPayToAddressWithReferenceValidator #-} -- | @mustPayToAddressWithReferenceValidator@ is a helper that calls @mustPayToAddressWithReferenceScript@. @@ -436,9 +461,23 @@ mustPayToAddressWithReferenceScript {-# INLINABLE mustPayToOtherScript #-} -- | @mustPayToOtherScript vh d v@ is the same as -- 'mustPayToOtherScriptAddress', but without the staking key hash. -mustPayToOtherScript :: forall i o. ValidatorHash -> OutDatum -> Value -> TxConstraints i o +mustPayToOtherScript :: forall i o. ValidatorHash -> Datum -> Value -> TxConstraints i o mustPayToOtherScript vh dv vl = - singleton (MustPayToOtherScript vh Nothing dv Nothing vl) + singleton (MustPayToOtherScript vh Nothing (Hashed dv) Nothing vl) + +{-# INLINABLE mustPayToOtherScriptInlineDatum #-} +-- | @mustPayToOtherScript vh d v@ is the same as +-- 'mustPayToOtherScriptAddress', but with an inline datum and without the staking key hash. +mustPayToOtherScriptInlineDatum :: forall i o. ValidatorHash -> Datum -> Value -> TxConstraints i o +mustPayToOtherScriptInlineDatum vh dv vl = + singleton (MustPayToOtherScript vh Nothing (Inline dv) Nothing vl) + +{-# INLINABLE mustPayToOtherScriptAddressInlineDatum #-} +-- | @mustPayToOtherScriptAddressInlineDatum vh d v@ is the same as +-- 'mustPayToOtherScriptAddress', but with an inline datum. +mustPayToOtherScriptAddressInlineDatum :: forall i o. ValidatorHash -> StakeValidatorHash -> Datum -> Value -> TxConstraints i o +mustPayToOtherScriptAddressInlineDatum vh svh dv vl = + singleton (MustPayToOtherScript vh (Just svh) (Inline dv) Nothing vl) {-# INLINABLE mustPayToOtherScriptAddress #-} -- | @mustPayToOtherScriptAddress vh svh d v@ locks the value @v@ with the given script @@ -451,9 +490,9 @@ mustPayToOtherScript vh dv vl = -- If used in 'Ledger.Constraints.OnChain', this constraint verifies that @d@ is -- part of the datum witness set and that the script transaction output with -- @vh@, @svh@, @d@ and @v@ is part of the transaction's outputs. -mustPayToOtherScriptAddress :: forall i o. ValidatorHash -> StakeValidatorHash -> OutDatum -> Value -> TxConstraints i o +mustPayToOtherScriptAddress :: forall i o. ValidatorHash -> StakeValidatorHash -> Datum -> Value -> TxConstraints i o mustPayToOtherScriptAddress vh svh dv vl = - singleton (MustPayToOtherScript vh (Just svh) dv Nothing vl) + singleton (MustPayToOtherScript vh (Just svh) (Hashed dv) Nothing vl) {-# INLINABLE mustMintValue #-} -- | Same as 'mustMintValueWithRedeemer', but sets the redeemer to the unit diff --git a/plutus-ledger-constraints/test/Spec.hs b/plutus-ledger-constraints/test/Spec.hs index d1c96ea6cb..111cc3189e 100644 --- a/plutus-ledger-constraints/test/Spec.hs +++ b/plutus-ledger-constraints/test/Spec.hs @@ -140,7 +140,7 @@ mustPayToOtherScriptAddressStakeValidatorHashNotNothingProp :: Property mustPayToOtherScriptAddressStakeValidatorHashNotNothingProp = property $ do pkh <- forAll $ Ledger.paymentPubKeyHash <$> Gen.element Gen.knownPaymentPublicKeys let svh = Ledger.StakeValidatorHash $ examplePlutusScriptAlwaysSucceedsHash WitCtxStake - txE = Constraints.mkTx @Void mempty (Constraints.mustPayToOtherScriptAddress alwaysSucceedValidatorHash svh (Constraints.Inline Ledger.unitDatum) (Ada.toValue Ledger.minAdaTxOut)) + txE = Constraints.mkTx @Void mempty (Constraints.mustPayToOtherScriptAddress alwaysSucceedValidatorHash svh Ledger.unitDatum (Ada.toValue Ledger.minAdaTxOut)) case txE of Left err -> do Hedgehog.annotateShow err diff --git a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs index 1d3d2a3398..7bf92f08ca 100644 --- a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs +++ b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs @@ -67,7 +67,7 @@ import Ledger.Address (pubKeyHashAddress, scriptValidatorHashAddress) import Ledger.Constraints qualified as P import Ledger.Constraints.OffChain (UnbalancedTx (..), cpsUnbalancedTx, unBalancedTxTx, unbalancedTx) import Ledger.Constraints.OffChain qualified as P -import Ledger.Constraints.TxConstraints (ScriptOutputConstraint, TxConstraint, +import Ledger.Constraints.TxConstraints (OutDatum (Hashed, Inline), ScriptOutputConstraint, TxConstraint, TxConstraints (TxConstraints, txConstraints, txOwnOutputs)) import Ledger.Interval () import Ledger.Orphans () @@ -282,10 +282,14 @@ processConstraint = \case P.MustPayToPubKeyAddress pk mskh md refScriptHashM vl -> do networkId <- use (P.paramsL . networkIdL) refScript <- lookupScriptAsReferenceScript refScriptHashM + let txInDatum = case md of + Nothing -> C.toCardanoTxOutNoDatum + Just (Hashed d) -> C.toCardanoTxOutDatumInTx d + Just (Inline d) -> C.toCardanoTxOutDatumInline d out <- throwLeft ToCardanoError $ C.TxOut <$> C.toCardanoAddressInEra networkId (pubKeyHashAddress pk mskh) <*> C.toCardanoTxOutValue vl - <*> pure (maybe C.TxOutDatumNone (C.TxOutDatumInTx C.ScriptDataInBabbageEra . C.toCardanoScriptData . getDatum) (P.getOutDatum <$> md)) -- FIXME + <*> pure txInDatum <*> pure refScript unbalancedTx . tx . txOuts <>= [ out ] @@ -293,10 +297,13 @@ processConstraint = \case P.MustPayToOtherScript vlh svhM dv refScriptHashM vl -> do networkId <- use (P.paramsL . networkIdL) refScript <- lookupScriptAsReferenceScript refScriptHashM + let txInDatum = case dv of + Hashed d -> C.toCardanoTxOutDatumInTx d + Inline d -> C.toCardanoTxOutDatumInline d out <- throwLeft ToCardanoError $ C.TxOut <$> C.toCardanoAddressInEra networkId (scriptValidatorHashAddress vlh svhM) <*> C.toCardanoTxOutValue vl - <*> pure (C.TxOutDatumInTx C.ScriptDataInBabbageEra (C.toCardanoScriptData (getDatum $ P.getOutDatum dv))) -- FIXME + <*> pure txInDatum <*> pure refScript unbalancedTx . tx . txOuts <>= [ out ] diff --git a/plutus-use-cases/src/Plutus/Contracts/Escrow.hs b/plutus-use-cases/src/Plutus/Contracts/Escrow.hs index 4484afd5c9..5680e1aa67 100644 --- a/plutus-use-cases/src/Plutus/Contracts/Escrow.hs +++ b/plutus-use-cases/src/Plutus/Contracts/Escrow.hs @@ -166,7 +166,7 @@ mkTx = \case PaymentPubKeyTarget pkh vl -> Constraints.mustPayToPubKey pkh vl ScriptTarget vs ds vl -> - Constraints.mustPayToOtherScript (Hashed vs) ds vl + Constraints.mustPayToOtherScript vs ds vl data Action = Redeem | Refund diff --git a/plutus-use-cases/test/Spec/future.pir b/plutus-use-cases/test/Spec/future.pir index 3d6b78ec30..1f789f60a9 100644 --- a/plutus-use-cases/test/Spec/future.pir +++ b/plutus-use-cases/test/Spec/future.pir @@ -120,6 +120,15 @@ (vardecl Just (fun a [ Maybe a ])) (vardecl Nothing [ Maybe a ]) ) ) + (datatypebind + (datatype + (tyvardecl OutDatum (type)) + + OutDatum_match + (vardecl Hashed (fun (con data) OutDatum)) + (vardecl Inline (fun (con data) OutDatum)) + ) + ) (typebind (tyvardecl TxOutRef (type)) (all a (type) (fun a a))) (let (rec) @@ -151,7 +160,7 @@ (fun [ Maybe (con bytestring) ] (fun - (con data) + OutDatum (fun [ Maybe (con bytestring) ] (fun @@ -190,7 +199,7 @@ (fun [ Maybe (con bytestring) ] (fun - [ Maybe (con data) ] + [ Maybe OutDatum ] (fun [ Maybe (con bytestring) ] (fun @@ -8426,7 +8435,10 @@ ) } ] - unitDatum + [ + Hashed + unitDatum + ] ] { Nothing @@ -8483,7 +8495,10 @@ ) } ] - unitDatum + [ + Hashed + unitDatum + ] ] { Nothing @@ -11177,7 +11192,10 @@ ) } ] - unitDatum + [ + Hashed + unitDatum + ] ] { Nothing @@ -11328,7 +11346,10 @@ ) } ] - unitDatum + [ + Hashed + unitDatum + ] ] { Nothing diff --git a/plutus-use-cases/test/Spec/renderGuess.txt b/plutus-use-cases/test/Spec/renderGuess.txt index 0ea35c1751..e1487a339b 100644 --- a/plutus-use-cases/test/Spec/renderGuess.txt +++ b/plutus-use-cases/test/Spec/renderGuess.txt @@ -551,11 +551,11 @@ Balances Carried Forward: Ada: Lovelace: 100000000 ==== Slot #1, Tx #0 ==== -TxId: 5568796b424a4afb1246eaa957edf9f4ae89ac2f35b11ee74ea5d6f2f58a9563 +TxId: 582535db1b8cfcae53505f6bfcf43400ad131aa533df613f496637db55bef42c Fee: Ada: Lovelace: 184333 Mint: - Signatures PubKey: 8d9de88fbf445b7f6c3875a14daba94caee2ffcb... - Signature: 5840aae5611913f8c960b9a98d394d80226068af... + Signature: 58400c87e799e69f3f780333c07d3de54082491d... Inputs: ---- Input 0 ---- Destination: PaymentPubKeyHash: a2c20c77887ace1cd986193e4e75babd8993cfd5... (Wallet 872cb83b5ee40eb23bfdab1772660c822a48d491) @@ -578,7 +578,7 @@ Inputs: Outputs: ---- Output 0 ---- - Destination: Script: a1d01b1cce628897d6a8764844dfa44ca74fb82696825afe1526986d + Destination: Script: f07e706c35a16c0f3843a07c5741334c90daaffad6a80f54ddc13d50 Value: Ada: Lovelace: 8000000 @@ -629,6 +629,6 @@ Balances Carried Forward: Value: Ada: Lovelace: 100000000 - Script: a1d01b1cce628897d6a8764844dfa44ca74fb82696825afe1526986d + Script: f07e706c35a16c0f3843a07c5741334c90daaffad6a80f54ddc13d50 Value: Ada: Lovelace: 8000000 \ No newline at end of file From 26c6b624cf5c4f9be76e38b68b3f5557595dfde9 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Fri, 23 Sep 2022 16:12:50 +0200 Subject: [PATCH 06/22] fix PAB --- .../src/Ledger/Constraints/OffChain.hs | 35 +++++++++---------- plutus-pab/src/Plutus/PAB/Arbitrary.hs | 10 ++++-- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs index a470b29abf..5538405877 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs @@ -69,7 +69,7 @@ module Ledger.Constraints.OffChain( , resolveScriptTxOut ) where -import Control.Lens (_2, _Just, alaf, at, makeLensesFor, view, (%=), (&), (.~), (<&>), (<>=), (?=), (^?)) +import Control.Lens (_2, _Just, alaf, at, makeLensesFor, view, (%=), (&), (.~), (<&>), (<>=), (?=), (^.), (^?)) import Control.Monad (forM_) import Control.Monad.Except (MonadError (catchError, throwError), runExcept, unless) import Control.Monad.Reader (MonadReader (ask), ReaderT (runReaderT), asks) @@ -87,6 +87,7 @@ import Data.Set qualified as Set import GHC.Generics (Generic) import Prettyprinter (Pretty (pretty), colon, hang, vsep, (<+>)) +import Control.Monad.Trans.Maybe (MaybeT (MaybeT, runMaybeT)) import Ledger (Redeemer (Redeemer), outValue) import Ledger.Ada qualified as Ada import Ledger.Address (PaymentPubKey (PaymentPubKey), PaymentPubKeyHash (PaymentPubKeyHash), StakePubKeyHash, @@ -679,7 +680,7 @@ processConstraint = \case MustSpendScriptOutput txo red -> do txout <- lookupTxOutRef txo - mscriptTXO <- resolveScriptTxOut txout + mscriptTXO <- runMaybeT $ resolveScriptTxOut txout case mscriptTXO of Just ((_, validator), (_, datum), value) -> do unbalancedTx . tx %= Tx.addScriptTxInput txo validator red datum @@ -720,7 +721,7 @@ processConstraint = \case Just (Hashed d) -> C.toCardanoTxOutDatumInTx d Just (Inline d) -> C.toCardanoTxOutDatumInline d txOut <- toCardanoTxOutWithOutputDatum pv2TxOut <&> outDatumHash .~ txInDatum - unbalancedTx . tx . Tx.outputs %= (txOut :) + unbalancedTx . tx . Tx.outputs <>= [txOut] valueSpentOutputs <>= provided vl MustPayToOtherScript vlh svhM dv _refScript vl -> do @@ -735,7 +736,7 @@ processConstraint = \case Hashed _ -> C.toCardanoTxOutDatumInTx d Inline _ -> C.toCardanoTxOutDatumInline d txScript <- toCardanoTxOutWithOutputDatum pv2script <&> outDatumHash .~ txInDatum - unbalancedTx . tx . Tx.outputs %= (txScript :) + unbalancedTx . tx . Tx.outputs <>= [txScript] valueSpentOutputs <>= provided vl MustHashDatum dvh dv -> do unless (P.datumHash dv == dvh) @@ -746,7 +747,7 @@ processConstraint = \case let tryNext [] = throwError CannotSatisfyAny tryNext (hs:qs) = do - traverse_ processConstraint hs `catchError` \_ -> put s >> tryNext qs + traverse_ processConstraint hs `catchError` const (put s >> tryNext qs) tryNext xs processConstraintFun @@ -766,7 +767,7 @@ processConstraintFun = \case validatorHash == vh && datumPred datum && valuePred value matches Nothing = False opts <- filter (matches . snd) - <$> traverse (\(ref, txo) -> (ref,) <$> resolveScriptTxOut txo) + <$> traverse (traverse $ runMaybeT . resolveScriptTxOut) (Map.toList slTxOutputs) case opts of [] -> throwError $ NoMatchingOutputFound vh @@ -779,23 +780,16 @@ resolveScriptTxOut :: ( MonadReader (ScriptLookups a) m , MonadError MkTxError m ) - => ChainIndexTxOut -> m (Maybe ((ValidatorHash, Versioned Validator), (DatumHash, Datum), Value)) -resolveScriptTxOut - Tx.ScriptChainIndexTxOut - { Tx._ciTxOutValidator = (vh, v) - , Tx._ciTxOutScriptDatum = (dh, d) - , Tx._ciTxOutValue - } = do + => ChainIndexTxOut -> MaybeT m ((ValidatorHash, Versioned Validator), (DatumHash, Datum), Value) +resolveScriptTxOut ci = do -- first check in the 'ChainIndexTxOut' for the validator, then -- look for it in the 'slOtherScripts' map. + (vh, v) <- hoistMaybe $ ci ^? Tx.ciTxOutValidator validator <- maybe (lookupValidator vh) pure v - - -- first check in the 'ChainIndexTxOut' for the datum, then - -- look for it in the 'slOtherData' map. + (dh, d) <- hoistMaybe $ ci ^? Tx.ciTxOutScriptDatum dataValue <- maybe (lookupDatum dh) pure d - - pure $ Just ((vh, validator), (dh, dataValue), _ciTxOutValue) -resolveScriptTxOut _ = pure Nothing + let _ciTxOutValue = ci ^. Tx.ciTxOutValue + pure ((vh, validator), (dh, dataValue), _ciTxOutValue) toCardanoTxOutWithOutputDatum :: ( MonadState ConstraintProcessingState m, MonadError MkTxError m) @@ -806,3 +800,6 @@ toCardanoTxOutWithOutputDatum txout = do case cardanoTxOut of Left err -> throwError $ TxOutCardanoError err Right cTxOut -> pure cTxOut + +hoistMaybe :: Applicative m => Maybe a -> MaybeT m a +hoistMaybe = MaybeT . pure diff --git a/plutus-pab/src/Plutus/PAB/Arbitrary.hs b/plutus-pab/src/Plutus/PAB/Arbitrary.hs index 4b10c07f47..c60833ecd8 100644 --- a/plutus-pab/src/Plutus/PAB/Arbitrary.hs +++ b/plutus-pab/src/Plutus/PAB/Arbitrary.hs @@ -23,13 +23,14 @@ import Ledger.Params (testnet) import Ledger.Slot (Slot) import Ledger.Tx (Certificate, RedeemerPtr, ScriptTag, Tx, TxId, TxIn, TxInType, TxInput, TxInputType, TxOutRef, Withdrawal) -import Ledger.Tx.CardanoAPI (ToCardanoError, toCardanoTxOut, toCardanoTxOutDatumHash) +import Ledger.Tx.CardanoAPI (ToCardanoError, toCardanoTxOut, toCardanoTxOutDatum) import Plutus.Contract.Effects (ActiveEndpoint (..), PABReq (..), PABResp (..)) import Plutus.Contract.StateMachine (ThreadToken) import Plutus.Script.Utils.V1.Address (mkValidatorAddress) import Plutus.Script.Utils.V1.Typed.Scripts (ConnectionError, WrongOutTypeError) import Plutus.V1.Ledger.Api (Address (..), LedgerBytes, PubKeyHash, ValidatorHash (ValidatorHash)) import Plutus.V1.Ledger.Bytes qualified as LedgerBytes +import Plutus.V2.Ledger.Api qualified as PV2 import PlutusTx qualified import PlutusTx.AssocMap qualified as AssocMap import PlutusTx.Prelude qualified as PlutusTx @@ -114,8 +115,13 @@ instance Arbitrary TxInput where arbitrary = genericArbitrary shrink = genericShrink +instance Arbitrary PV2.OutputDatum where + arbitrary = genericArbitrary + shrink = genericShrink + + instance Arbitrary TxOut where - arbitrary = fmap (fmap TxOut . toCardanoTxOut testnet toCardanoTxOutDatumHash) genericArbitrary `suchThatMap` rightToMaybe + arbitrary = fmap (fmap TxOut . toCardanoTxOut testnet toCardanoTxOutDatum) genericArbitrary `suchThatMap` rightToMaybe shrink = pure instance Arbitrary TxOutRef where From c27af439ceb76536d41e35300200364809eac5b8 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Fri, 23 Sep 2022 16:28:07 +0200 Subject: [PATCH 07/22] fixing tx-constraints --- plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs index 7bf92f08ca..c437ee8caf 100644 --- a/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs +++ b/plutus-tx-constraints/src/Ledger/Tx/Constraints/OffChain.hs @@ -57,6 +57,7 @@ import Control.Lens (Lens', Traversal', coerced, iso, makeLensesFor, use, (.=), import Control.Monad.Except (Except, MonadError, mapExcept, runExcept, throwError, withExcept) import Control.Monad.Reader (ReaderT (runReaderT), mapReaderT) import Control.Monad.State (MonadState, StateT, execStateT, gets, mapStateT) +import Control.Monad.Trans.Maybe (MaybeT (runMaybeT)) import Data.Aeson (FromJSON, ToJSON) import Data.Bifunctor (first) import Data.Either (partitionEithers) @@ -247,7 +248,7 @@ processConstraint = \case P.MustSpendScriptOutput txo redeemer -> do txout <- lookupTxOutRef txo - mscriptTXO <- mapReaderT (mapStateT (mapExcept (first LedgerMkTxError))) $ P.resolveScriptTxOut txout + mscriptTXO <- mapReaderT (mapStateT (mapExcept (first LedgerMkTxError))) $ runMaybeT $ P.resolveScriptTxOut txout case mscriptTXO of Just ((_, Tx.Versioned validator lang), (_, datum), _) -> do txIn <- throwLeft ToCardanoError $ C.toCardanoTxIn txo From d6f903b33681012b7909126c5c7a4c04e21f5c92 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Sat, 24 Sep 2022 07:13:38 +0200 Subject: [PATCH 08/22] clean up tests --- .../TxConstraints/MustPayToOtherScript.hs | 26 +++++++++---------- .../TxConstraints/MustPayToPubKeyAddress.hs | 8 +++--- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index 2773293929..4b914324d2 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -23,8 +23,8 @@ import Ledger.Constraints qualified as Constraints (mustMintValueWithRedeemer, m import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) import Ledger.Constraints.OnChain.V2 qualified as V2.Constraints import Ledger.Generators (someTokenValue) -import Ledger.Scripts (ScriptError (EvaluationError)) -import Ledger.Test (asRedeemer, someValidator, someValidatorHash) +import Ledger.Scripts (Redeemer, ScriptError (EvaluationError)) +import Ledger.Test (asDatum, asRedeemer, someValidator, someValidatorHash) import Ledger.Tx qualified as Tx import Ledger.Typed.Scripts qualified as Scripts import Plutus.Contract as Con @@ -35,8 +35,6 @@ import Plutus.Script.Utils.V1.Scripts qualified as PSU.V1 import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Scripts import Plutus.Trace qualified as Trace -import Plutus.V1.Ledger.Api (CurrencySymbol (CurrencySymbol), Datum (Datum), ToData (toBuiltinData), - UnsafeFromData (unsafeFromBuiltinData)) import Plutus.V1.Ledger.Value qualified as Value import Plutus.V2.Ledger.Contexts qualified as V2.Scripts import PlutusTx qualified @@ -59,11 +57,11 @@ tests = , phase2ErrorWhenExpectingMoreThanValue ] -someDatum :: Datum -someDatum = Datum $ PlutusTx.dataToBuiltinData $ PlutusTx.toData ("datum" :: P.BuiltinByteString) +someDatum :: Ledger.Datum +someDatum = asDatum @P.BuiltinByteString "datum" -otherDatum :: Datum -otherDatum = Datum $ PlutusTx.dataToBuiltinData $ PlutusTx.toData ("other datum" :: P.BuiltinByteString) +otherDatum :: Ledger.Datum +otherDatum = asDatum @P.BuiltinByteString "other datum" utxoValue :: Value.Value utxoValue = Ada.lovelaceValueOf 10_000_000 @@ -284,14 +282,14 @@ mustPayToOtherScriptPolicyHash = PSU.V1.mintingPolicyHash mustPayToOtherScriptPo mustPayToOtherScriptPolicyHashV2 :: Ledger.MintingPolicyHash mustPayToOtherScriptPolicyHashV2 = PSU.V2.mintingPolicyHash mustPayToOtherScriptPolicyV2 -mustPayToOtherScriptPolicyCurrencySymbol :: CurrencySymbol -mustPayToOtherScriptPolicyCurrencySymbol = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToOtherScriptPolicyHash +mustPayToOtherScriptPolicyCurrencySymbol :: Ledger.CurrencySymbol +mustPayToOtherScriptPolicyCurrencySymbol = Value.mpsSymbol mustPayToOtherScriptPolicyHash -mustPayToOtherScriptPolicyCurrencySymbolV2 :: CurrencySymbol -mustPayToOtherScriptPolicyCurrencySymbolV2 = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToOtherScriptPolicyHashV2 +mustPayToOtherScriptPolicyCurrencySymbolV2 :: Ledger.CurrencySymbol +mustPayToOtherScriptPolicyCurrencySymbolV2 = Value.mpsSymbol mustPayToOtherScriptPolicyHashV2 -data ConstraintParams = MustPayToOtherScript PSU.V1.ValidatorHash Datum Value.Value - | MustPayToOtherScriptAddress PSU.V1.ValidatorHash PSU.V1.StakeValidatorHash Datum Value.Value +data ConstraintParams = MustPayToOtherScript PSU.V1.ValidatorHash Ledger.Datum Value.Value + | MustPayToOtherScriptAddress PSU.V1.ValidatorHash PSU.V1.StakeValidatorHash Ledger.Datum Value.Value deriving (Show) PlutusTx.unstableMakeIsData ''ConstraintParams diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 8315b0184c..d0225a3707 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -320,11 +320,11 @@ mustPayToPubKeyAddressPolicyHash = PSU.V1.mintingPolicyHash mustPayToPubKeyAddre mustPayToPubKeyAddressPolicyHashV2 :: Ledger.MintingPolicyHash mustPayToPubKeyAddressPolicyHashV2 = PSU.V2.mintingPolicyHash mustPayToPubKeyAddressPolicyV2 -mustPayToPubKeyAddressPolicyCurrencySymbol :: CurrencySymbol -mustPayToPubKeyAddressPolicyCurrencySymbol = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToPubKeyAddressPolicyHash +mustPayToPubKeyAddressPolicyCurrencySymbol :: Ledger.CurrencySymbol +mustPayToPubKeyAddressPolicyCurrencySymbol = Value.mpsSymbol mustPayToPubKeyAddressPolicyHash -mustPayToPubKeyAddressPolicyCurrencySymbolV2 :: CurrencySymbol -mustPayToPubKeyAddressPolicyCurrencySymbolV2 = CurrencySymbol $ unsafeFromBuiltinData $ toBuiltinData mustPayToPubKeyAddressPolicyHashV2 +mustPayToPubKeyAddressPolicyCurrencySymbolV2 :: Ledger.CurrencySymbol +mustPayToPubKeyAddressPolicyCurrencySymbolV2 = Value.mpsSymbol mustPayToPubKeyAddressPolicyHashV2 data ConstraintParams = MustPayToPubKey Ledger.PaymentPubKeyHash Value.Value | MustPayToPubKeyAddress Ledger.PaymentPubKeyHash Ledger.StakePubKeyHash Value.Value From 98d98cef82b20c3f750d5af0e894b6a36b54b1dd Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Sun, 25 Sep 2022 23:18:48 +0200 Subject: [PATCH 09/22] Address some of Konstantinos' comments --- .../src/Ledger/Constraints/OnChain/V2.hs | 7 ++++--- .../src/Ledger/Constraints/TxConstraints.hs | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs index 552b4b8189..d8e5f00bda 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs @@ -125,10 +125,11 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case checkOutput _ _ = True in traceIfFalse "La" -- "MustPayToPubKey" - $ vl `leq` PV2.valuePaidTo scriptContextTxInfo pk && any (checkOutput $ fmap getOutDatum mdv) outs -- FIXME + $ vl `leq` PV2.valuePaidTo scriptContextTxInfo pk && any (checkOutput $ fmap getOutDatum mdv) outs MustPayToOtherScript vlh _skh dv _refScript vl -> let outs = PV2.txInfoOutputs scriptContextTxInfo - hsh = PV2.findDatumHash (getOutDatum dv) scriptContextTxInfo -- FIXME + -- We only chek the datum, we do not distinguish how it is paased + hsh = PV2.findDatumHash (getOutDatum dv) scriptContextTxInfo addr = Address (ScriptCredential vlh) Nothing checkOutput TxOut{txOutAddress, txOutValue, txOutDatum=OutputDatumHash dh} = Ada.fromValue txOutValue >= Ada.fromValue vl @@ -140,7 +141,7 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case Ada.fromValue txOutValue >= Ada.fromValue vl && Ada.fromValue txOutValue <= Ada.fromValue vl + Ledger.maxMinAdaTxOut && Value.noAdaValue txOutValue == Value.noAdaValue vl - && getOutDatum dv == id -- FIXME + && getOutDatum dv == id && txOutAddress == addr checkOutput _ = False in diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs index ea9affedd6..f3c2d006a9 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs @@ -53,6 +53,10 @@ import Prelude qualified as Haskell import Prettyprinter.Render.String (renderShowS) -- | How tx out datum are embedded in a a Tx +-- +-- We do not use 'TxOutDatum' from cardano-node as we need to have a distinction at the type leve between constraints +-- that require a Datum and constraints (like 'MustPayToOtherScript') with an optional datum +-- (like 'MustPayToPubKeyAddress'). data OutDatum = Inline Datum | Hashed Datum deriving stock (Haskell.Show, Generic, Haskell.Eq) deriving anyclass (ToJSON, FromJSON) From 41f2708b869d972a96f58baa496f270458d43c3f Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Mon, 26 Sep 2022 09:09:52 +0200 Subject: [PATCH 10/22] Separate test group for plutus v2 --- .../test/Spec/TxConstraints/MustPayToOtherScript.hs | 11 +++++++++-- .../Spec/TxConstraints/MustPayToPubKeyAddress.hs | 13 ++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index 4b914324d2..a315bbafee 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -46,15 +46,22 @@ tests :: TestTree tests = testGroup "MustPayToOtherScript" [ successfulUseOfMustPayToOtherScriptWithMintedToken - , successfulUseOfMustPayToOtherScriptWithMintedTokenV2 , successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken --, successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda -- FAILING when onchain checks for only ada value and token is present -- PLT-885 , successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance , successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue , contractErrorWhenAttemptingToSpendMoreThanAdaBalance , contractErrorWhenAttemptingToSpendMoreThanTokenBalance - , phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum , phase2ErrorWhenExpectingMoreThanValue + -- test Plutus v2 features + , v2Tests + ] + +v2Tests :: TestTree +v2Tests = + testGroup "Test of Plutus V2 features" + [ successfulUseOfMustPayToOtherScriptWithMintedTokenV2 + , phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum ] someDatum :: Ledger.Datum diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index d0225a3707..e39a868004 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -46,14 +46,21 @@ tests = , successfulUseOfMustPayToPubKeyExpectingALowerAdaValue , successfulUseOfMustPayToPubKeyAddress , successfulUseOfMustPayWithDatumToPubKey - , successfulUseOfMustPayWithInlineDatumToPubKeyV2 , successfulUseOfMustPayWithDatumToPubKeyAddress - , phase1FailureWhenUsingInlineDatumWithV1 , phase2FailureWhenUsingUnexpectedPaymentPubKeyHash --, phase2FailureWhenUsingUnexpectedStakePubKeyHash -- onchain check not implemented , phase2FailureWhenUsingUnexpectedDatum , phase2FailureWhenUsingUnexpectedValue - ] + -- test Plutus v2 features + , v2Tests + ] + +v2Tests :: TestTree +v2Tests = + testGroup "Test of Plutus V2 features" + [ successfulUseOfMustPayWithInlineDatumToPubKeyV2 + , phase1FailureWhenUsingInlineDatumWithV1 + ] someDatum :: Ledger.Datum someDatum = asDatum @P.BuiltinByteString "datum" From e75c7635f09b9be899c89ab596f713fad7a7d1b6 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 12:36:53 +0200 Subject: [PATCH 11/22] Refactor tests in MustPayToPubKeyAddress to ease version handling --- .../TxConstraints/MustPayToPubKeyAddress.hs | 323 ++++++++++-------- .../src/Ledger/Constraints/OnChain/V1.hs | 4 +- .../src/Ledger/Constraints/OnChain/V2.hs | 10 +- 3 files changed, 193 insertions(+), 144 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index e39a868004..389746a25f 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -1,21 +1,27 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE NumericUnderscores #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE NumericUnderscores #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} module Spec.TxConstraints.MustPayToPubKeyAddress(tests) where +import Control.Lens ((??)) import Control.Monad (void) import Test.Tasty (TestTree, testGroup) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints qualified as Constraints (mustMintValueWithRedeemer, mustPayToPubKey, mustPayToPubKeyAddress, - mustPayWithDatumToPubKey, mustPayWithDatumToPubKeyAddress, - mustPayWithInlineDatumToPubKey, +import Ledger.Constraints qualified as Constraints (ScriptLookups, TxConstraints, mustMintValueWithRedeemer, + mustPayToPubKey, mustPayToPubKeyAddress, mustPayWithDatumToPubKey, + mustPayWithDatumToPubKeyAddress, mustPayWithInlineDatumToPubKey, mustPayWithInlineDatumToPubKeyAddress, plutusV1MintingPolicy, plutusV2MintingPolicy) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) @@ -40,27 +46,46 @@ import PlutusTx.Prelude qualified as P tests :: TestTree tests = testGroup "MustPayToPubKeyAddress" - [ successfulUseOfMustPayToPubKeyWithMintedTokenValue - , successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken - , successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda - , successfulUseOfMustPayToPubKeyExpectingALowerAdaValue - , successfulUseOfMustPayToPubKeyAddress - , successfulUseOfMustPayWithDatumToPubKey - , successfulUseOfMustPayWithDatumToPubKeyAddress - , phase2FailureWhenUsingUnexpectedPaymentPubKeyHash - --, phase2FailureWhenUsingUnexpectedStakePubKeyHash -- onchain check not implemented - , phase2FailureWhenUsingUnexpectedDatum - , phase2FailureWhenUsingUnexpectedValue - -- test Plutus v2 features + [ v1Tests , v2Tests ] +v1Tests :: TestTree +v1Tests = testGroup "Plutus V1" $ + [ v1FeaturesTests + , v2FeaturesNotAvailableTests + ] ?? testContextV1 + v2Tests :: TestTree -v2Tests = - testGroup "Test of Plutus V2 features" - [ successfulUseOfMustPayWithInlineDatumToPubKeyV2 - , phase1FailureWhenUsingInlineDatumWithV1 - ] +v2Tests = testGroup "Plutus V2" $ + [ v1FeaturesTests + , v2FeaturesTests + ] ?? testContextV2 + +v1FeaturesTests :: MintingPolicySupport sc => TestContext sc -> TestTree +v1FeaturesTests t = testGroup "Plutus V1 features" $ + [ successfulUseOfMustPayToPubKeyWithMintedTokenValue + , successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken + , successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda + , successfulUseOfMustPayToPubKeyExpectingALowerAdaValue + , successfulUseOfMustPayToPubKeyAddress + , successfulUseOfMustPayWithDatumToPubKey + , successfulUseOfMustPayWithDatumToPubKeyAddress + , phase2FailureWhenUsingUnexpectedPaymentPubKeyHash + --, phase2FailureWhenUsingUnexpectedStakePubKeyHash -- onchain check not implemented + , phase2FailureWhenUsingUnexpectedDatum + , phase2FailureWhenUsingUnexpectedValue + ] ?? t + +v2FeaturesTests :: MintingPolicySupport sc => TestContext sc -> TestTree +v2FeaturesTests t = testGroup "Plutus V2 features" $ + [ successfulUseOfMustPayWithInlineDatumToPubKeyV2 + ] ?? t + +v2FeaturesNotAvailableTests :: MintingPolicySupport sc => TestContext sc -> TestTree +v2FeaturesNotAvailableTests t = testGroup "Plutus V2 features" $ + [ phase1FailureWhenUsingInlineDatumWithV1 + ] ?? t someDatum :: Ledger.Datum someDatum = asDatum @P.BuiltinByteString "datum" @@ -74,11 +99,8 @@ adaAmount = 5_000_000 adaValue :: Value.Value adaValue = Ada.lovelaceValueOf adaAmount -tknValue :: Value.Value -tknValue = Value.singleton mustPayToPubKeyAddressPolicyCurrencySymbol "mint-me" 1 - -tknValueV2 :: Value.Value -tknValueV2 = Value.singleton mustPayToPubKeyAddressPolicyCurrencySymbolV2 "mint-me" 1 +tknValue :: MintingPolicySupport sc => TestContext sc -> Value.Value +tknValue tc = Value.singleton (mustPayToPubKeyAddressPolicyCurrencySymbol tc) "mint-me" 1 w1PaymentPubKeyHash :: Ledger.PaymentPubKeyHash w1PaymentPubKeyHash = mockWalletPaymentPubKeyHash w1 @@ -98,14 +120,14 @@ trace contract = do void $ Trace.waitNSlots 1 -- | Valid scenario using offchain and onchain constraint mustPayToPubKey with exact token value being minted -successfulUseOfMustPayToPubKeyWithMintedTokenValue :: TestTree -successfulUseOfMustPayToPubKeyWithMintedTokenValue = - let adaAndTokenValue = adaValue <> tknValue +successfulUseOfMustPayToPubKeyWithMintedTokenValue :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyWithMintedTokenValue tc = + let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc (_mustPayToPubKeyAddressPolicy tc) tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -115,14 +137,14 @@ successfulUseOfMustPayToPubKeyWithMintedTokenValue = (void $ trace contract) -- | Valid scenario using mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for token value only -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: TestTree -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken = - let adaAndTokenValue = adaValue <> tknValue - onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash tknValue +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken tc = + let adaAndTokenValue = adaValue <> tknValue tc + onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash (tknValue tc) contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc (_mustPayToPubKeyAddressPolicy tc) tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -132,14 +154,14 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken (void $ trace contract) -- | Valid scenario using mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for ada value only -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: TestTree -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda = - let adaAndTokenValue = adaValue <> tknValue +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda tc = + let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash adaValue contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -149,13 +171,13 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda = (void $ trace contract) -- | Valid scenario where the onchain mustPayToPubKey constraint expects less ada than the actual value -successfulUseOfMustPayToPubKeyExpectingALowerAdaValue :: TestTree -successfulUseOfMustPayToPubKeyExpectingALowerAdaValue = +successfulUseOfMustPayToPubKeyExpectingALowerAdaValue :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyExpectingALowerAdaValue tc = let onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash (Ada.lovelaceValueOf $ adaAmount - 1) contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -165,13 +187,13 @@ successfulUseOfMustPayToPubKeyExpectingALowerAdaValue = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayToPubKeyAddress with ada-only value -successfulUseOfMustPayToPubKeyAddress :: TestTree -successfulUseOfMustPayToPubKeyAddress = +successfulUseOfMustPayToPubKeyAddress :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyAddress tc = let onChainConstraint = asRedeemer $ MustPayToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash adaValue contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -181,13 +203,13 @@ successfulUseOfMustPayToPubKeyAddress = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with bytestring datum and ada value -successfulUseOfMustPayWithDatumToPubKey :: TestTree -successfulUseOfMustPayWithDatumToPubKey = +successfulUseOfMustPayWithDatumToPubKey :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayWithDatumToPubKey tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -196,30 +218,14 @@ successfulUseOfMustPayWithDatumToPubKey = (assertValidatedTransactionCount 1) (void $ trace contract) --- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with inline bytestring datum and ada value -successfulUseOfMustPayWithInlineDatumToPubKeyV2 :: TestTree -successfulUseOfMustPayWithInlineDatumToPubKeyV2 = - let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue - contract = do - let lookups1 = Constraints.plutusV2MintingPolicy mustPayToPubKeyAddressPolicyV2 - tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValueV2 - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 - awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - - in checkPredicate - "Successful use of offchain and onchain mustPayWithDatumToPubKey constraint with inline bytestring datum and ada value" - (assertValidatedTransactionCount 1) - (void $ trace contract) - -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKeyAddress with bytestring datum and ada value -successfulUseOfMustPayWithDatumToPubKeyAddress :: TestTree -successfulUseOfMustPayWithDatumToPubKeyAddress = +successfulUseOfMustPayWithDatumToPubKeyAddress :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayWithDatumToPubKeyAddress tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -228,30 +234,14 @@ successfulUseOfMustPayWithDatumToPubKeyAddress = (assertValidatedTransactionCount 1) (void $ trace contract) --- | Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum -phase1FailureWhenUsingInlineDatumWithV1 :: TestTree -phase1FailureWhenUsingInlineDatumWithV1 = - let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue - contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy - tx1 = Constraints.mustPayWithInlineDatumToPubKey w2PaymentPubKeyHash someDatum adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 - awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 - - in checkPredicate - "Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum" - (assertFailedTransaction (\_ err _ -> case err of {Ledger.CardanoLedgerValidationError _ -> True; _ -> False })) - (void $ trace contract) - -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the PaymentPubkeyHash" -phase2FailureWhenUsingUnexpectedPaymentPubKeyHash :: TestTree -phase2FailureWhenUsingUnexpectedPaymentPubKeyHash = +phase2FailureWhenUsingUnexpectedPaymentPubKeyHash :: MintingPolicySupport sc => TestContext sc -> TestTree +phase2FailureWhenUsingUnexpectedPaymentPubKeyHash tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w1PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -261,13 +251,13 @@ phase2FailureWhenUsingUnexpectedPaymentPubKeyHash = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the Datum" -phase2FailureWhenUsingUnexpectedDatum :: TestTree -phase2FailureWhenUsingUnexpectedDatum = +phase2FailureWhenUsingUnexpectedDatum :: MintingPolicySupport sc => TestContext sc -> TestTree +phase2FailureWhenUsingUnexpectedDatum tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash otherDatum adaValue contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -277,13 +267,13 @@ phase2FailureWhenUsingUnexpectedDatum = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the Value" -phase2FailureWhenUsingUnexpectedValue :: TestTree -phase2FailureWhenUsingUnexpectedValue = +phase2FailureWhenUsingUnexpectedValue :: MintingPolicySupport sc => TestContext sc -> TestTree +phase2FailureWhenUsingUnexpectedValue tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum (Ada.lovelaceValueOf $ adaAmount + 1) contract = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToPubKeyAddressPolicy + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -292,46 +282,105 @@ phase2FailureWhenUsingUnexpectedValue = (assertFailedTransaction (\_ err _ -> case err of {Ledger.ScriptFailure (EvaluationError ("La":_) _) -> True; _ -> False })) (void $ trace contract) + + +-- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with inline bytestring datum and ada value +successfulUseOfMustPayWithInlineDatumToPubKeyV2 :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayWithInlineDatumToPubKeyV2 tc = + let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue + contract = do + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) + ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + + in checkPredicate + "Successful use of offchain and onchain mustPayWithDatumToPubKey constraint with inline bytestring datum and ada value" + (assertValidatedTransactionCount 1) + (void $ trace contract) + +-- | Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum +phase1FailureWhenUsingInlineDatumWithV1 :: MintingPolicySupport sc => TestContext sc -> TestTree +phase1FailureWhenUsingInlineDatumWithV1 tc = + let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue + contract = do + let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + tx1 = Constraints.mustPayWithInlineDatumToPubKey w2PaymentPubKeyHash someDatum adaValue + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) + ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + + in checkPredicate + "Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum" + (assertFailedTransaction (\_ err _ -> case err of {Ledger.CardanoLedgerValidationError _ -> True; _ -> False })) + (void $ trace contract) + + data UnitTest instance Scripts.ValidatorTypes UnitTest -{-# INLINEABLE mkMustPayToPubKeyAddressPolicy #-} -mkMustPayToPubKeyAddressPolicy :: ConstraintParams -> Ledger.ScriptContext -> Bool -mkMustPayToPubKeyAddressPolicy t = case t of - MustPayToPubKey ppkh v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKey ppkh v) - MustPayToPubKeyAddress ppkh spkh v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKeyAddress ppkh spkh v) - MustPayWithDatumToPubKey ppkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKey ppkh d v) - MustPayWithDatumToPubKeyAddress ppkh spkh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh d v) - -{-# INLINEABLE mkMustPayToPubKeyAddressPolicyV2 #-} -mkMustPayToPubKeyAddressPolicyV2 :: ConstraintParams -> V2.Scripts.ScriptContext -> Bool -mkMustPayToPubKeyAddressPolicyV2 t = case t of - MustPayToPubKey ppkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKey ppkh v) - MustPayToPubKeyAddress ppkh spkh v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToPubKeyAddress ppkh spkh v) - MustPayWithDatumToPubKey ppkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithInlineDatumToPubKey ppkh d v) - MustPayWithDatumToPubKeyAddress ppkh spkh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayWithInlineDatumToPubKeyAddress ppkh spkh d v) - -mustPayToPubKeyAddressPolicy :: Scripts.MintingPolicy -mustPayToPubKeyAddressPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) + +class MintingPolicySupport sc where + checkScriptContext :: forall i o. PlutusTx.ToData o => Constraints.TxConstraints i o -> sc -> Bool + +instance MintingPolicySupport Ledger.ScriptContext where + checkScriptContext = Constraints.checkScriptContext + +instance MintingPolicySupport V2.Scripts.ScriptContext where + checkScriptContext = V2.Constraints.checkScriptContext + + +data TestContext sc + = TestContext + { _mkMustPayToPubKeyAddressPolicy :: ConstraintParams -> sc -> Bool + , _mustPayToPubKeyAddressPolicy :: Ledger.MintingPolicy + , _mintingPolicy :: forall a. Ledger.MintingPolicy -> Constraints.ScriptLookups a + , _mintingPolicyHash :: Ledger.MintingPolicy -> Ledger.MintingPolicyHash + } + +type TestContextV1 = TestContext Ledger.ScriptContext +type TestContextV2 = TestContext V2.Scripts.ScriptContext + +mustPayToPubKeyAddressPolicyV1 :: Ledger.MintingPolicy +mustPayToPubKeyAddressPolicyV1 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where wrap = Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy -mustPayToPubKeyAddressPolicyV2 :: V2.Scripts.MintingPolicy +mustPayToPubKeyAddressPolicyV2 :: Ledger.MintingPolicy mustPayToPubKeyAddressPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where - wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicyV2 + wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy + +testContextV1 :: TestContextV1 +testContextV1 = TestContext + mkMustPayToPubKeyAddressPolicy + mustPayToPubKeyAddressPolicyV1 + Constraints.plutusV1MintingPolicy + PSU.V1.mintingPolicyHash + + +testContextV2 :: TestContextV2 +testContextV2 = TestContext + mkMustPayToPubKeyAddressPolicy + mustPayToPubKeyAddressPolicyV2 + Constraints.plutusV2MintingPolicy + PSU.V2.mintingPolicyHash + -mustPayToPubKeyAddressPolicyHash :: Ledger.MintingPolicyHash -mustPayToPubKeyAddressPolicyHash = PSU.V1.mintingPolicyHash mustPayToPubKeyAddressPolicy +mkMustPayToPubKeyAddressPolicy :: MintingPolicySupport sc => ConstraintParams -> sc -> Bool +mkMustPayToPubKeyAddressPolicy = \case + MustPayToPubKey ppkh v -> checkScriptContext (Constraints.mustPayToPubKey @() @() ppkh v) + MustPayToPubKeyAddress ppkh spkh v -> checkScriptContext (Constraints.mustPayToPubKeyAddress @() @() ppkh spkh v) + MustPayWithDatumToPubKey ppkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKey @() @() ppkh d v) + MustPayWithDatumToPubKeyAddress ppkh spkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKeyAddress @() @() ppkh spkh d v) -mustPayToPubKeyAddressPolicyHashV2 :: Ledger.MintingPolicyHash -mustPayToPubKeyAddressPolicyHashV2 = PSU.V2.mintingPolicyHash mustPayToPubKeyAddressPolicyV2 +mustPayToPubKeyAddressPolicyHash :: TestContext sc -> Ledger.MintingPolicyHash +mustPayToPubKeyAddressPolicyHash tc = _mintingPolicyHash tc $ _mustPayToPubKeyAddressPolicy tc -mustPayToPubKeyAddressPolicyCurrencySymbol :: Ledger.CurrencySymbol -mustPayToPubKeyAddressPolicyCurrencySymbol = Value.mpsSymbol mustPayToPubKeyAddressPolicyHash +mustPayToPubKeyAddressPolicyCurrencySymbol :: MintingPolicySupport sc => TestContext sc -> Ledger.CurrencySymbol +mustPayToPubKeyAddressPolicyCurrencySymbol = Value.mpsSymbol . mustPayToPubKeyAddressPolicyHash -mustPayToPubKeyAddressPolicyCurrencySymbolV2 :: Ledger.CurrencySymbol -mustPayToPubKeyAddressPolicyCurrencySymbolV2 = Value.mpsSymbol mustPayToPubKeyAddressPolicyHashV2 data ConstraintParams = MustPayToPubKey Ledger.PaymentPubKeyHash Value.Value | MustPayToPubKeyAddress Ledger.PaymentPubKeyHash Ledger.StakePubKeyHash Value.Value diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs index adfdc942b6..89e7d9215d 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs @@ -114,11 +114,11 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case in traceIfFalse "La" -- "MustPayToPubKey" $ vl `leq` V.valuePaidTo scriptContextTxInfo pk - && maybe True (\dv -> any (checkOutput $ getOutDatum dv) outs) mdv -- FIXME + && maybe True (\dv -> any (checkOutput $ getOutDatum dv) outs) mdv && isNothing refScript MustPayToOtherScript vlh _ dv refScript vl -> let outs = V.txInfoOutputs scriptContextTxInfo - hsh = V.findDatumHash (getOutDatum dv) scriptContextTxInfo -- FIXME + hsh = V.findDatumHash (getOutDatum dv) scriptContextTxInfo addr = Address.scriptHashAddress vlh checkOutput TxOut{txOutAddress, txOutValue, txOutDatumHash=Just svh} = Ada.fromValue txOutValue >= Ada.fromValue vl diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs index d8e5f00bda..78ca663ab1 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs @@ -119,13 +119,13 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case MustPayToPubKeyAddress (PaymentPubKeyHash pk) _skh mdv _refScript vl -> let outs = PV2.txInfoOutputs scriptContextTxInfo hsh dv = PV2.findDatumHash dv scriptContextTxInfo - checkOutput (Just dv) TxOut{txOutDatum=OutputDatumHash dh} = hsh dv == Just dh - checkOutput (Just dv) TxOut{txOutDatum=OutputDatum d} = dv == d - -- return 'True' by default meaning we fail only when the provided datum is not found - checkOutput _ _ = True + checkOutput dv TxOut{txOutDatum=OutputDatumHash dh} = hsh dv == Just dh + checkOutput dv TxOut{txOutDatum=OutputDatum d} = dv == d + checkOutput _ _ = False in traceIfFalse "La" -- "MustPayToPubKey" - $ vl `leq` PV2.valuePaidTo scriptContextTxInfo pk && any (checkOutput $ fmap getOutDatum mdv) outs + $ vl `leq` PV2.valuePaidTo scriptContextTxInfo pk + && maybe True (\dv -> any (checkOutput $ getOutDatum dv) outs) mdv MustPayToOtherScript vlh _skh dv _refScript vl -> let outs = PV2.txInfoOutputs scriptContextTxInfo -- We only chek the datum, we do not distinguish how it is paased From ab030063b23efc822a4317acc28ba193171fe0c6 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 12:57:45 +0200 Subject: [PATCH 12/22] Code clean up --- .../TxConstraints/MustPayToPubKeyAddress.hs | 87 +++++++++---------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 389746a25f..52bff0d65a 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -62,7 +62,7 @@ v2Tests = testGroup "Plutus V2" $ , v2FeaturesTests ] ?? testContextV2 -v1FeaturesTests :: MintingPolicySupport sc => TestContext sc -> TestTree +v1FeaturesTests :: MintingPolicySupport sc => LanguageContext sc -> TestTree v1FeaturesTests t = testGroup "Plutus V1 features" $ [ successfulUseOfMustPayToPubKeyWithMintedTokenValue , successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken @@ -77,12 +77,12 @@ v1FeaturesTests t = testGroup "Plutus V1 features" $ , phase2FailureWhenUsingUnexpectedValue ] ?? t -v2FeaturesTests :: MintingPolicySupport sc => TestContext sc -> TestTree +v2FeaturesTests :: MintingPolicySupport sc => LanguageContext sc -> TestTree v2FeaturesTests t = testGroup "Plutus V2 features" $ [ successfulUseOfMustPayWithInlineDatumToPubKeyV2 ] ?? t -v2FeaturesNotAvailableTests :: MintingPolicySupport sc => TestContext sc -> TestTree +v2FeaturesNotAvailableTests :: MintingPolicySupport sc => LanguageContext sc -> TestTree v2FeaturesNotAvailableTests t = testGroup "Plutus V2 features" $ [ phase1FailureWhenUsingInlineDatumWithV1 ] ?? t @@ -99,7 +99,7 @@ adaAmount = 5_000_000 adaValue :: Value.Value adaValue = Ada.lovelaceValueOf adaAmount -tknValue :: MintingPolicySupport sc => TestContext sc -> Value.Value +tknValue :: MintingPolicySupport sc => LanguageContext sc -> Value.Value tknValue tc = Value.singleton (mustPayToPubKeyAddressPolicyCurrencySymbol tc) "mint-me" 1 w1PaymentPubKeyHash :: Ledger.PaymentPubKeyHash @@ -120,12 +120,12 @@ trace contract = do void $ Trace.waitNSlots 1 -- | Valid scenario using offchain and onchain constraint mustPayToPubKey with exact token value being minted -successfulUseOfMustPayToPubKeyWithMintedTokenValue :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyWithMintedTokenValue :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayToPubKeyWithMintedTokenValue tc = let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue contract = do - let lookups1 = _mintingPolicy tc (_mustPayToPubKeyAddressPolicy tc) + let lookups1 = mintingPolicy tc (mustPayToPubKeyAddressPolicy tc) tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -137,12 +137,12 @@ successfulUseOfMustPayToPubKeyWithMintedTokenValue tc = (void $ trace contract) -- | Valid scenario using mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for token value only -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken tc = let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash (tknValue tc) contract = do - let lookups1 = _mintingPolicy tc (_mustPayToPubKeyAddressPolicy tc) + let lookups1 = mintingPolicy tc (mustPayToPubKeyAddressPolicy tc) tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -154,12 +154,12 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken (void $ trace contract) -- | Valid scenario using mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for ada value only -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda tc = let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -171,11 +171,11 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda t (void $ trace contract) -- | Valid scenario where the onchain mustPayToPubKey constraint expects less ada than the actual value -successfulUseOfMustPayToPubKeyExpectingALowerAdaValue :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyExpectingALowerAdaValue :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayToPubKeyExpectingALowerAdaValue tc = let onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash (Ada.lovelaceValueOf $ adaAmount - 1) contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -187,11 +187,11 @@ successfulUseOfMustPayToPubKeyExpectingALowerAdaValue tc = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayToPubKeyAddress with ada-only value -successfulUseOfMustPayToPubKeyAddress :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayToPubKeyAddress :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayToPubKeyAddress tc = let onChainConstraint = asRedeemer $ MustPayToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -203,11 +203,11 @@ successfulUseOfMustPayToPubKeyAddress tc = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with bytestring datum and ada value -successfulUseOfMustPayWithDatumToPubKey :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayWithDatumToPubKey :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayWithDatumToPubKey tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -219,11 +219,11 @@ successfulUseOfMustPayWithDatumToPubKey tc = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKeyAddress with bytestring datum and ada value -successfulUseOfMustPayWithDatumToPubKeyAddress :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayWithDatumToPubKeyAddress :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayWithDatumToPubKeyAddress tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -235,11 +235,11 @@ successfulUseOfMustPayWithDatumToPubKeyAddress tc = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the PaymentPubkeyHash" -phase2FailureWhenUsingUnexpectedPaymentPubKeyHash :: MintingPolicySupport sc => TestContext sc -> TestTree +phase2FailureWhenUsingUnexpectedPaymentPubKeyHash :: MintingPolicySupport sc => LanguageContext sc -> TestTree phase2FailureWhenUsingUnexpectedPaymentPubKeyHash tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w1PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -251,11 +251,11 @@ phase2FailureWhenUsingUnexpectedPaymentPubKeyHash tc = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the Datum" -phase2FailureWhenUsingUnexpectedDatum :: MintingPolicySupport sc => TestContext sc -> TestTree +phase2FailureWhenUsingUnexpectedDatum :: MintingPolicySupport sc => LanguageContext sc -> TestTree phase2FailureWhenUsingUnexpectedDatum tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash otherDatum adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -267,11 +267,11 @@ phase2FailureWhenUsingUnexpectedDatum tc = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the Value" -phase2FailureWhenUsingUnexpectedValue :: MintingPolicySupport sc => TestContext sc -> TestTree +phase2FailureWhenUsingUnexpectedValue :: MintingPolicySupport sc => LanguageContext sc -> TestTree phase2FailureWhenUsingUnexpectedValue tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum (Ada.lovelaceValueOf $ adaAmount + 1) contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -285,11 +285,11 @@ phase2FailureWhenUsingUnexpectedValue tc = -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with inline bytestring datum and ada value -successfulUseOfMustPayWithInlineDatumToPubKeyV2 :: MintingPolicySupport sc => TestContext sc -> TestTree +successfulUseOfMustPayWithInlineDatumToPubKeyV2 :: MintingPolicySupport sc => LanguageContext sc -> TestTree successfulUseOfMustPayWithInlineDatumToPubKeyV2 tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -301,11 +301,11 @@ successfulUseOfMustPayWithInlineDatumToPubKeyV2 tc = (void $ trace contract) -- | Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum -phase1FailureWhenUsingInlineDatumWithV1 :: MintingPolicySupport sc => TestContext sc -> TestTree +phase1FailureWhenUsingInlineDatumWithV1 :: MintingPolicySupport sc => LanguageContext sc -> TestTree phase1FailureWhenUsingInlineDatumWithV1 tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do - let lookups1 = _mintingPolicy tc $ _mustPayToPubKeyAddressPolicy tc + let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithInlineDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 @@ -331,16 +331,15 @@ instance MintingPolicySupport V2.Scripts.ScriptContext where checkScriptContext = V2.Constraints.checkScriptContext -data TestContext sc - = TestContext - { _mkMustPayToPubKeyAddressPolicy :: ConstraintParams -> sc -> Bool - , _mustPayToPubKeyAddressPolicy :: Ledger.MintingPolicy - , _mintingPolicy :: forall a. Ledger.MintingPolicy -> Constraints.ScriptLookups a - , _mintingPolicyHash :: Ledger.MintingPolicy -> Ledger.MintingPolicyHash +data LanguageContext sc + = LanguageContext + { mustPayToPubKeyAddressPolicy :: Ledger.MintingPolicy + , mintingPolicy :: forall a. Ledger.MintingPolicy -> Constraints.ScriptLookups a + , mintingPolicyHash :: Ledger.MintingPolicy -> Ledger.MintingPolicyHash } -type TestContextV1 = TestContext Ledger.ScriptContext -type TestContextV2 = TestContext V2.Scripts.ScriptContext +type LanguageContextV1 = LanguageContext Ledger.ScriptContext +type LanguageContextV2 = LanguageContext V2.Scripts.ScriptContext mustPayToPubKeyAddressPolicyV1 :: Ledger.MintingPolicy mustPayToPubKeyAddressPolicyV1 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) @@ -352,17 +351,15 @@ mustPayToPubKeyAddressPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compil where wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy -testContextV1 :: TestContextV1 -testContextV1 = TestContext - mkMustPayToPubKeyAddressPolicy +testContextV1 :: LanguageContextV1 +testContextV1 = LanguageContext mustPayToPubKeyAddressPolicyV1 Constraints.plutusV1MintingPolicy PSU.V1.mintingPolicyHash -testContextV2 :: TestContextV2 -testContextV2 = TestContext - mkMustPayToPubKeyAddressPolicy +testContextV2 :: LanguageContextV2 +testContextV2 = LanguageContext mustPayToPubKeyAddressPolicyV2 Constraints.plutusV2MintingPolicy PSU.V2.mintingPolicyHash @@ -375,10 +372,10 @@ mkMustPayToPubKeyAddressPolicy = \case MustPayWithDatumToPubKey ppkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKey @() @() ppkh d v) MustPayWithDatumToPubKeyAddress ppkh spkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKeyAddress @() @() ppkh spkh d v) -mustPayToPubKeyAddressPolicyHash :: TestContext sc -> Ledger.MintingPolicyHash -mustPayToPubKeyAddressPolicyHash tc = _mintingPolicyHash tc $ _mustPayToPubKeyAddressPolicy tc +mustPayToPubKeyAddressPolicyHash :: LanguageContext sc -> Ledger.MintingPolicyHash +mustPayToPubKeyAddressPolicyHash tc = mintingPolicyHash tc $ mustPayToPubKeyAddressPolicy tc -mustPayToPubKeyAddressPolicyCurrencySymbol :: MintingPolicySupport sc => TestContext sc -> Ledger.CurrencySymbol +mustPayToPubKeyAddressPolicyCurrencySymbol :: MintingPolicySupport sc => LanguageContext sc -> Ledger.CurrencySymbol mustPayToPubKeyAddressPolicyCurrencySymbol = Value.mpsSymbol . mustPayToPubKeyAddressPolicyHash From 5cb0d798e20fc11d9e4e1481bc69b43da03e1376 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 12:58:32 +0200 Subject: [PATCH 13/22] Code clean up --- .../Spec/TxConstraints/MustPayToPubKeyAddress.hs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 52bff0d65a..6c42b5fea7 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -54,13 +54,13 @@ v1Tests :: TestTree v1Tests = testGroup "Plutus V1" $ [ v1FeaturesTests , v2FeaturesNotAvailableTests - ] ?? testContextV1 + ] ?? languageContextV1 v2Tests :: TestTree v2Tests = testGroup "Plutus V2" $ [ v1FeaturesTests , v2FeaturesTests - ] ?? testContextV2 + ] ?? languageContextV2 v1FeaturesTests :: MintingPolicySupport sc => LanguageContext sc -> TestTree v1FeaturesTests t = testGroup "Plutus V1 features" $ @@ -351,15 +351,15 @@ mustPayToPubKeyAddressPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compil where wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy -testContextV1 :: LanguageContextV1 -testContextV1 = LanguageContext +languageContextV1 :: LanguageContextV1 +languageContextV1 = LanguageContext mustPayToPubKeyAddressPolicyV1 Constraints.plutusV1MintingPolicy PSU.V1.mintingPolicyHash -testContextV2 :: LanguageContextV2 -testContextV2 = LanguageContext +languageContextV2 :: LanguageContextV2 +languageContextV2 = LanguageContext mustPayToPubKeyAddressPolicyV2 Constraints.plutusV2MintingPolicy PSU.V2.mintingPolicyHash From d3ebee5f2305ccf3b23c6ae1bca3c0f8c060d992 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 13:27:39 +0200 Subject: [PATCH 14/22] Fix unused imports --- plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs index 78ca663ab1..ded8109f14 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs @@ -39,7 +39,7 @@ import Plutus.V2.Ledger.Contexts qualified as PV2 import Plutus.V2.Ledger.Tx (OutputDatum (NoOutputDatum, OutputDatum, OutputDatumHash)) import PlutusTx (ToData (toBuiltinData)) import PlutusTx.AssocMap qualified as AMap -import PlutusTx.Prelude (AdditiveSemigroup ((+)), Bool (False, True), Eq ((==)), Functor (fmap), Maybe (Just, Nothing), +import PlutusTx.Prelude (AdditiveSemigroup ((+)), Bool (False, True), Eq ((==)), Maybe (Just, Nothing), Ord ((<=), (>=)), all, any, elem, isJust, maybe, traceIfFalse, ($), (&&), (.), (>>)) {-# INLINABLE checkScriptContext #-} From 4964a3f55a65d3c107babac89fb2f8fcf85485ac Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 14:29:04 +0200 Subject: [PATCH 15/22] Add a way to switch to cardano constraints in MustPayToOtherAddress tests --- .../TxConstraints/MustPayToPubKeyAddress.hs | 175 ++++++++++-------- 1 file changed, 97 insertions(+), 78 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 6c42b5fea7..52d346c302 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -1,19 +1,15 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FunctionalDependencies #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE NumericUnderscores #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE NumericUnderscores #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} module Spec.TxConstraints.MustPayToPubKeyAddress(tests) where -import Control.Lens ((??)) +import Control.Lens ((??), (^.)) import Control.Monad (void) import Test.Tasty (TestTree, testGroup) @@ -22,17 +18,17 @@ import Ledger.Ada qualified as Ada import Ledger.Constraints qualified as Constraints (ScriptLookups, TxConstraints, mustMintValueWithRedeemer, mustPayToPubKey, mustPayToPubKeyAddress, mustPayWithDatumToPubKey, mustPayWithDatumToPubKeyAddress, mustPayWithInlineDatumToPubKey, - mustPayWithInlineDatumToPubKeyAddress, plutusV1MintingPolicy, - plutusV2MintingPolicy) + plutusV1MintingPolicy, plutusV2MintingPolicy) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) import Ledger.Constraints.OnChain.V2 qualified as V2.Constraints import Ledger.Scripts (ScriptError (EvaluationError)) import Ledger.Test (asDatum, asRedeemer) import Ledger.Tx qualified as Tx +import Ledger.Tx.Constraints qualified as Tx.Constraints import Ledger.Typed.Scripts qualified as Scripts import Plutus.Contract as Con import Plutus.Contract.Test (assertFailedTransaction, assertValidatedTransactionCount, checkPredicate, - mockWalletPaymentPubKeyHash, w1, w2) + defaultCheckOptions, emulatorConfig, mockWalletPaymentPubKeyHash, w1, w2) import Plutus.Script.Utils.V1.Scripts qualified as PSU.V1 import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Scripts @@ -46,24 +42,31 @@ import PlutusTx.Prelude qualified as P tests :: TestTree tests = testGroup "MustPayToPubKeyAddress" - [ v1Tests - , v2Tests + [ testGroup "ledger constraints" + [ v1Tests ledgerSubmitTx + , v2Tests ledgerSubmitTx ] + {- testGroup "cardano constraints" + [ v1Tests ledgerSubmitTx + , v2Tests ledgerSubmitTx + ] + -} -- uncomment when MustPayToPubKey is implemented for Tx.Constraints + ] -v1Tests :: TestTree -v1Tests = testGroup "Plutus V1" $ +v1Tests :: SubmitTx -> TestTree +v1Tests sub = testGroup "Plutus V1" $ [ v1FeaturesTests , v2FeaturesNotAvailableTests - ] ?? languageContextV1 + ] ?? sub ?? languageContextV1 -v2Tests :: TestTree -v2Tests = testGroup "Plutus V2" $ +v2Tests :: SubmitTx -> TestTree +v2Tests sub = testGroup "Plutus V2" $ [ v1FeaturesTests , v2FeaturesTests - ] ?? languageContextV2 + ] ?? sub ?? languageContextV2 -v1FeaturesTests :: MintingPolicySupport sc => LanguageContext sc -> TestTree -v1FeaturesTests t = testGroup "Plutus V1 features" $ +v1FeaturesTests :: SubmitTx -> LanguageContext -> TestTree +v1FeaturesTests sub t = testGroup "Plutus V1 features" $ [ successfulUseOfMustPayToPubKeyWithMintedTokenValue , successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken , successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda @@ -75,17 +78,17 @@ v1FeaturesTests t = testGroup "Plutus V1 features" $ --, phase2FailureWhenUsingUnexpectedStakePubKeyHash -- onchain check not implemented , phase2FailureWhenUsingUnexpectedDatum , phase2FailureWhenUsingUnexpectedValue - ] ?? t + ] ?? sub ?? t -v2FeaturesTests :: MintingPolicySupport sc => LanguageContext sc -> TestTree -v2FeaturesTests t = testGroup "Plutus V2 features" $ +v2FeaturesTests :: SubmitTx -> LanguageContext -> TestTree +v2FeaturesTests sub t = testGroup "Plutus V2 features" $ [ successfulUseOfMustPayWithInlineDatumToPubKeyV2 - ] ?? t + ] ?? sub ?? t -v2FeaturesNotAvailableTests :: MintingPolicySupport sc => LanguageContext sc -> TestTree -v2FeaturesNotAvailableTests t = testGroup "Plutus V2 features" $ +v2FeaturesNotAvailableTests :: SubmitTx -> LanguageContext -> TestTree +v2FeaturesNotAvailableTests sub t = testGroup "Plutus V2 features" $ [ phase1FailureWhenUsingInlineDatumWithV1 - ] ?? t + ] ?? sub ?? t someDatum :: Ledger.Datum someDatum = asDatum @P.BuiltinByteString "datum" @@ -99,7 +102,7 @@ adaAmount = 5_000_000 adaValue :: Value.Value adaValue = Ada.lovelaceValueOf adaAmount -tknValue :: MintingPolicySupport sc => LanguageContext sc -> Value.Value +tknValue :: LanguageContext -> Value.Value tknValue tc = Value.singleton (mustPayToPubKeyAddressPolicyCurrencySymbol tc) "mint-me" 1 w1PaymentPubKeyHash :: Ledger.PaymentPubKeyHash @@ -120,15 +123,15 @@ trace contract = do void $ Trace.waitNSlots 1 -- | Valid scenario using offchain and onchain constraint mustPayToPubKey with exact token value being minted -successfulUseOfMustPayToPubKeyWithMintedTokenValue :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayToPubKeyWithMintedTokenValue tc = +successfulUseOfMustPayToPubKeyWithMintedTokenValue :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToPubKeyWithMintedTokenValue submitTxFromConstraints tc = let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue contract = do let lookups1 = mintingPolicy tc (mustPayToPubKeyAddressPolicy tc) tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -137,15 +140,15 @@ successfulUseOfMustPayToPubKeyWithMintedTokenValue tc = (void $ trace contract) -- | Valid scenario using mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for token value only -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken tc = +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken submitTxFromConstraints tc = let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash (tknValue tc) contract = do let lookups1 = mintingPolicy tc (mustPayToPubKeyAddressPolicy tc) tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -154,15 +157,15 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyToken (void $ trace contract) -- | Valid scenario using mustPayToPubKey offchain constraint to include ada and token whilst onchain constraint checks for ada value only -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda tc = +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda submitTxFromConstraints tc = let adaAndTokenValue = adaValue <> tknValue tc onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaAndTokenValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -171,14 +174,14 @@ successfulUseOfMustPayToPubKeyWhenOffchainIncludesTokenAndOnchainChecksOnlyAda t (void $ trace contract) -- | Valid scenario where the onchain mustPayToPubKey constraint expects less ada than the actual value -successfulUseOfMustPayToPubKeyExpectingALowerAdaValue :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayToPubKeyExpectingALowerAdaValue tc = +successfulUseOfMustPayToPubKeyExpectingALowerAdaValue :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToPubKeyExpectingALowerAdaValue submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayToPubKey w2PaymentPubKeyHash (Ada.lovelaceValueOf $ adaAmount - 1) contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKey w2PaymentPubKeyHash adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -187,14 +190,14 @@ successfulUseOfMustPayToPubKeyExpectingALowerAdaValue tc = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayToPubKeyAddress with ada-only value -successfulUseOfMustPayToPubKeyAddress :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayToPubKeyAddress tc = +successfulUseOfMustPayToPubKeyAddress :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToPubKeyAddress submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -203,14 +206,14 @@ successfulUseOfMustPayToPubKeyAddress tc = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with bytestring datum and ada value -successfulUseOfMustPayWithDatumToPubKey :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayWithDatumToPubKey tc = +successfulUseOfMustPayWithDatumToPubKey :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayWithDatumToPubKey submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -219,14 +222,14 @@ successfulUseOfMustPayWithDatumToPubKey tc = (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKeyAddress with bytestring datum and ada value -successfulUseOfMustPayWithDatumToPubKeyAddress :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayWithDatumToPubKeyAddress tc = +successfulUseOfMustPayWithDatumToPubKeyAddress :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayWithDatumToPubKeyAddress submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -235,14 +238,14 @@ successfulUseOfMustPayWithDatumToPubKeyAddress tc = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the PaymentPubkeyHash" -phase2FailureWhenUsingUnexpectedPaymentPubKeyHash :: MintingPolicySupport sc => LanguageContext sc -> TestTree -phase2FailureWhenUsingUnexpectedPaymentPubKeyHash tc = +phase2FailureWhenUsingUnexpectedPaymentPubKeyHash :: SubmitTx -> LanguageContext -> TestTree +phase2FailureWhenUsingUnexpectedPaymentPubKeyHash submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w1PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -251,14 +254,14 @@ phase2FailureWhenUsingUnexpectedPaymentPubKeyHash tc = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the Datum" -phase2FailureWhenUsingUnexpectedDatum :: MintingPolicySupport sc => LanguageContext sc -> TestTree -phase2FailureWhenUsingUnexpectedDatum tc = +phase2FailureWhenUsingUnexpectedDatum :: SubmitTx -> LanguageContext -> TestTree +phase2FailureWhenUsingUnexpectedDatum submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash otherDatum adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -267,14 +270,14 @@ phase2FailureWhenUsingUnexpectedDatum tc = (void $ trace contract) -- | Phase-2 failure when onchain mustPayWithDatumToPubKeyAddress constraint cannot verify the Value" -phase2FailureWhenUsingUnexpectedValue :: MintingPolicySupport sc => LanguageContext sc -> TestTree -phase2FailureWhenUsingUnexpectedValue tc = +phase2FailureWhenUsingUnexpectedValue :: SubmitTx -> LanguageContext -> TestTree +phase2FailureWhenUsingUnexpectedValue submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum (Ada.lovelaceValueOf $ adaAmount + 1) contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKeyAddress w2PaymentPubKeyHash w2StakePubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -285,14 +288,14 @@ phase2FailureWhenUsingUnexpectedValue tc = -- | Valid scenario using offchain and onchain constraint mustPayWithDatumToPubKey with inline bytestring datum and ada value -successfulUseOfMustPayWithInlineDatumToPubKeyV2 :: MintingPolicySupport sc => LanguageContext sc -> TestTree -successfulUseOfMustPayWithInlineDatumToPubKeyV2 tc = +successfulUseOfMustPayWithInlineDatumToPubKeyV2 :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayWithInlineDatumToPubKeyV2 submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -301,14 +304,14 @@ successfulUseOfMustPayWithInlineDatumToPubKeyV2 tc = (void $ trace contract) -- | Phase-1 failure when mustPayToPubKeyAddress in a V1 script use inline datum -phase1FailureWhenUsingInlineDatumWithV1 :: MintingPolicySupport sc => LanguageContext sc -> TestTree -phase1FailureWhenUsingInlineDatumWithV1 tc = +phase1FailureWhenUsingInlineDatumWithV1 :: SubmitTx -> LanguageContext -> TestTree +phase1FailureWhenUsingInlineDatumWithV1 submitTxFromConstraints tc = let onChainConstraint = asRedeemer $ MustPayWithDatumToPubKey w2PaymentPubKeyHash someDatum adaValue contract = do let lookups1 = mintingPolicy tc $ mustPayToPubKeyAddressPolicy tc tx1 = Constraints.mustPayWithInlineDatumToPubKey w2PaymentPubKeyHash someDatum adaValue <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue tc) - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 in checkPredicate @@ -331,15 +334,17 @@ instance MintingPolicySupport V2.Scripts.ScriptContext where checkScriptContext = V2.Constraints.checkScriptContext -data LanguageContext sc +data LanguageContext = LanguageContext { mustPayToPubKeyAddressPolicy :: Ledger.MintingPolicy , mintingPolicy :: forall a. Ledger.MintingPolicy -> Constraints.ScriptLookups a , mintingPolicyHash :: Ledger.MintingPolicy -> Ledger.MintingPolicyHash } -type LanguageContextV1 = LanguageContext Ledger.ScriptContext -type LanguageContextV2 = LanguageContext V2.Scripts.ScriptContext +-- ScriptLookups UnbalancedTx +-- submitUnbalancedTx +-- :: forall w (s :: Row *) e. +-- AsContractError e => ScriptLookups UnitTest -> TxConstraints () () -> Contract w s e CardanoTx mustPayToPubKeyAddressPolicyV1 :: Ledger.MintingPolicy mustPayToPubKeyAddressPolicyV1 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) @@ -351,14 +356,14 @@ mustPayToPubKeyAddressPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compil where wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy -languageContextV1 :: LanguageContextV1 +languageContextV1 :: LanguageContext languageContextV1 = LanguageContext mustPayToPubKeyAddressPolicyV1 Constraints.plutusV1MintingPolicy PSU.V1.mintingPolicyHash -languageContextV2 :: LanguageContextV2 +languageContextV2 :: LanguageContext languageContextV2 = LanguageContext mustPayToPubKeyAddressPolicyV2 Constraints.plutusV2MintingPolicy @@ -372,12 +377,26 @@ mkMustPayToPubKeyAddressPolicy = \case MustPayWithDatumToPubKey ppkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKey @() @() ppkh d v) MustPayWithDatumToPubKeyAddress ppkh spkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKeyAddress @() @() ppkh spkh d v) -mustPayToPubKeyAddressPolicyHash :: LanguageContext sc -> Ledger.MintingPolicyHash +mustPayToPubKeyAddressPolicyHash :: LanguageContext -> Ledger.MintingPolicyHash mustPayToPubKeyAddressPolicyHash tc = mintingPolicyHash tc $ mustPayToPubKeyAddressPolicy tc -mustPayToPubKeyAddressPolicyCurrencySymbol :: MintingPolicySupport sc => LanguageContext sc -> Ledger.CurrencySymbol +mustPayToPubKeyAddressPolicyCurrencySymbol :: LanguageContext -> Ledger.CurrencySymbol mustPayToPubKeyAddressPolicyCurrencySymbol = Value.mpsSymbol . mustPayToPubKeyAddressPolicyHash +type SubmitTx + = Constraints.ScriptLookups UnitTest + -> Constraints.TxConstraints (Scripts.RedeemerType UnitTest) (Scripts.DatumType UnitTest) + -> Contract () Empty ContractError Tx.CardanoTx + +cardanoSubmitTx :: SubmitTx +cardanoSubmitTx lookups tx = let + p = defaultCheckOptions ^. emulatorConfig . Trace.params + in submitUnbalancedTx $ either (error . show) id $ Tx.Constraints.mkTx @UnitTest p lookups tx + +ledgerSubmitTx :: SubmitTx +ledgerSubmitTx = submitTxConstraintsWith + + data ConstraintParams = MustPayToPubKey Ledger.PaymentPubKeyHash Value.Value | MustPayToPubKeyAddress Ledger.PaymentPubKeyHash Ledger.StakePubKeyHash Value.Value From c0c364d634532b278783b796158ecc2b303d94ed Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 14:37:21 +0200 Subject: [PATCH 16/22] more clean up --- .../TxConstraints/MustPayToPubKeyAddress.hs | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 52d346c302..2648249a5a 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -324,16 +324,6 @@ data UnitTest instance Scripts.ValidatorTypes UnitTest -class MintingPolicySupport sc where - checkScriptContext :: forall i o. PlutusTx.ToData o => Constraints.TxConstraints i o -> sc -> Bool - -instance MintingPolicySupport Ledger.ScriptContext where - checkScriptContext = Constraints.checkScriptContext - -instance MintingPolicySupport V2.Scripts.ScriptContext where - checkScriptContext = V2.Constraints.checkScriptContext - - data LanguageContext = LanguageContext { mustPayToPubKeyAddressPolicy :: Ledger.MintingPolicy @@ -349,12 +339,14 @@ data LanguageContext mustPayToPubKeyAddressPolicyV1 :: Ledger.MintingPolicy mustPayToPubKeyAddressPolicyV1 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where - wrap = Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy + checkedMkMustPayToPubKeyAddressPolicy = mkMustPayToPubKeyAddressPolicy Constraints.checkScriptContext + wrap = Scripts.mkUntypedMintingPolicy checkedMkMustPayToPubKeyAddressPolicy mustPayToPubKeyAddressPolicyV2 :: Ledger.MintingPolicy mustPayToPubKeyAddressPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where - wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToPubKeyAddressPolicy + checkedMkMustPayToPubKeyAddressPolicy = mkMustPayToPubKeyAddressPolicy V2.Constraints.checkScriptContext + wrap = V2.Scripts.mkUntypedMintingPolicy checkedMkMustPayToPubKeyAddressPolicy languageContextV1 :: LanguageContext languageContextV1 = LanguageContext @@ -370,12 +362,12 @@ languageContextV2 = LanguageContext PSU.V2.mintingPolicyHash -mkMustPayToPubKeyAddressPolicy :: MintingPolicySupport sc => ConstraintParams -> sc -> Bool -mkMustPayToPubKeyAddressPolicy = \case - MustPayToPubKey ppkh v -> checkScriptContext (Constraints.mustPayToPubKey @() @() ppkh v) - MustPayToPubKeyAddress ppkh spkh v -> checkScriptContext (Constraints.mustPayToPubKeyAddress @() @() ppkh spkh v) - MustPayWithDatumToPubKey ppkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKey @() @() ppkh d v) - MustPayWithDatumToPubKeyAddress ppkh spkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKeyAddress @() @() ppkh spkh d v) +mkMustPayToPubKeyAddressPolicy :: (Constraints.TxConstraints () () -> sc -> Bool) -> ConstraintParams -> sc -> Bool +mkMustPayToPubKeyAddressPolicy checkScriptContext = \case + MustPayToPubKey ppkh v -> checkScriptContext (Constraints.mustPayToPubKey ppkh v) + MustPayToPubKeyAddress ppkh spkh v -> checkScriptContext (Constraints.mustPayToPubKeyAddress ppkh spkh v) + MustPayWithDatumToPubKey ppkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKey ppkh d v) + MustPayWithDatumToPubKeyAddress ppkh spkh d v -> checkScriptContext (Constraints.mustPayWithDatumToPubKeyAddress ppkh spkh d v) mustPayToPubKeyAddressPolicyHash :: LanguageContext -> Ledger.MintingPolicyHash mustPayToPubKeyAddressPolicyHash tc = mintingPolicyHash tc $ mustPayToPubKeyAddressPolicy tc From ea6b275cda84b1bd2c1bc92e576d888f369ab029 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 14:51:24 +0200 Subject: [PATCH 17/22] PR feedbacks --- .../test/Spec/TxConstraints/MustPayToOtherScript.hs | 2 +- .../test/Spec/TxConstraints/MustPayToPubKeyAddress.hs | 1 - .../src/Ledger/Constraints/TxConstraints.hs | 6 ++++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index a315bbafee..4e5d040909 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -202,7 +202,7 @@ successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue = (assertValidatedTransactionCount 1) (void $ trace contract) --- | Invalid contract that try to used inline datum in a V1 script +-- | Invalid contract that tries to use inline datum in a V1 script mustPayToOtherScriptInlineContract :: Value.Value -> Redeemer -> Contract () Empty ContractError () mustPayToOtherScriptInlineContract offChainValue onChainConstraint = do let lookups1 = Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 2648249a5a..290ceb07c3 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -34,7 +34,6 @@ import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Scripts import Plutus.Trace qualified as Trace import Plutus.V1.Ledger.Value qualified as Value -import Plutus.V2.Ledger.Contexts qualified as V2.Scripts import PlutusTx qualified import PlutusTx.Prelude qualified as P diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs index f3c2d006a9..a362381a58 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs @@ -52,15 +52,17 @@ import Data.Maybe (fromMaybe) import Prelude qualified as Haskell import Prettyprinter.Render.String (renderShowS) --- | How tx out datum are embedded in a a Tx +-- | How tx outs datum are embedded in a a Tx -- --- We do not use 'TxOutDatum' from cardano-node as we need to have a distinction at the type leve between constraints +-- We do not use 'TxOutDatum' from cardano-node to provide easier to handel type (we don't type witnesses) +-- and to have a distinction at the type leve between constraints -- that require a Datum and constraints (like 'MustPayToOtherScript') with an optional datum -- (like 'MustPayToPubKeyAddress'). data OutDatum = Inline Datum | Hashed Datum deriving stock (Haskell.Show, Generic, Haskell.Eq) deriving anyclass (ToJSON, FromJSON) +{-# INLINABLE getOutDatum #-} getOutDatum :: OutDatum -> Datum getOutDatum (Hashed d) = d getOutDatum (Inline d) = d From 7371e021a1961deec96e0b2eb3ea4911523429b1 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 15:05:20 +0200 Subject: [PATCH 18/22] Remove dead code --- .../test/Spec/TxConstraints/MustPayToPubKeyAddress.hs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index 290ceb07c3..e04fde2b40 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -330,11 +330,6 @@ data LanguageContext , mintingPolicyHash :: Ledger.MintingPolicy -> Ledger.MintingPolicyHash } --- ScriptLookups UnbalancedTx --- submitUnbalancedTx --- :: forall w (s :: Row *) e. --- AsContractError e => ScriptLookups UnitTest -> TxConstraints () () -> Contract w s e CardanoTx - mustPayToPubKeyAddressPolicyV1 :: Ledger.MintingPolicy mustPayToPubKeyAddressPolicyV1 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where From 0cc1a4671511d147335446c274358bc7210ebef6 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 16:25:07 +0200 Subject: [PATCH 19/22] Add refactoring for MustPayToOtherScript tests --- .../TxConstraints/MustPayToOtherScript.hs | 260 +++++++++++------- 1 file changed, 153 insertions(+), 107 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index 4e5d040909..b7bdfb781e 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -2,20 +2,22 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} module Spec.TxConstraints.MustPayToOtherScript(tests) where +import Control.Lens ((&), (??), (^.)) import Control.Monad (void) import Test.Tasty (TestTree, testGroup) -import Control.Lens ((&)) import Ledger qualified import Ledger.Ada qualified as Ada -import Ledger.Constraints qualified as Constraints (mustMintValueWithRedeemer, mustPayToOtherScript, - mustPayToOtherScriptAddress, mustPayToOtherScriptAddressInlineDatum, +import Ledger.Constraints qualified as Constraints (ScriptLookups, TxConstraints, mustMintValueWithRedeemer, + mustPayToOtherScript, mustPayToOtherScriptAddress, + mustPayToOtherScriptAddressInlineDatum, mustPayToOtherScriptInlineDatum, mustSpendScriptOutputWithMatchingDatumAndValue, plutusV1MintingPolicy, plutusV1OtherScript, plutusV2MintingPolicy, @@ -26,17 +28,17 @@ import Ledger.Generators (someTokenValue) import Ledger.Scripts (Redeemer, ScriptError (EvaluationError)) import Ledger.Test (asDatum, asRedeemer, someValidator, someValidatorHash) import Ledger.Tx qualified as Tx +import Ledger.Tx.Constraints qualified as Tx.Constraints import Ledger.Typed.Scripts qualified as Scripts import Plutus.Contract as Con import Plutus.Contract.Test (assertContractError, assertFailedTransaction, assertValidatedTransactionCount, - changeInitialWalletValue, checkPredicateOptions, defaultCheckOptions, w1) + changeInitialWalletValue, checkPredicateOptions, defaultCheckOptions, emulatorConfig, w1) import Plutus.Script.Utils.V1.Generators (alwaysSucceedValidatorHash) import Plutus.Script.Utils.V1.Scripts qualified as PSU.V1 import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 import Plutus.Script.Utils.V2.Typed.Scripts qualified as V2.Scripts import Plutus.Trace qualified as Trace import Plutus.V1.Ledger.Value qualified as Value -import Plutus.V2.Ledger.Contexts qualified as V2.Scripts import PlutusTx qualified import PlutusTx.Prelude qualified as P import Wallet (WalletAPIError (InsufficientFunds)) @@ -45,24 +47,49 @@ import Wallet (WalletAPIError (InsufficientFunds)) tests :: TestTree tests = testGroup "MustPayToOtherScript" - [ successfulUseOfMustPayToOtherScriptWithMintedToken - , successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken - --, successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda -- FAILING when onchain checks for only ada value and token is present -- PLT-885 - , successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance - , successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue - , contractErrorWhenAttemptingToSpendMoreThanAdaBalance - , contractErrorWhenAttemptingToSpendMoreThanTokenBalance - , phase2ErrorWhenExpectingMoreThanValue - -- test Plutus v2 features - , v2Tests + [ testGroup "ledger constraints" + [ v1Tests ledgerSubmitTx + , v2Tests ledgerSubmitTx ] - -v2Tests :: TestTree -v2Tests = - testGroup "Test of Plutus V2 features" - [ successfulUseOfMustPayToOtherScriptWithMintedTokenV2 - , phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum + , testGroup "cardano constraints" + [ v1Tests ledgerSubmitTx + , v2Tests ledgerSubmitTx ] + ] + +v1Tests :: SubmitTx -> TestTree +v1Tests sub = testGroup "Plutus V1" $ + [ v1FeaturesTests + , v2FeaturesNotAvailableTests + ] ?? sub ?? languageContextV1 + +v2Tests :: SubmitTx -> TestTree +v2Tests sub = testGroup "Plutus V2" $ + [ v1FeaturesTests + , v2FeaturesTests + ] ?? sub ?? languageContextV2 + +v1FeaturesTests :: SubmitTx -> LanguageContext -> TestTree +v1FeaturesTests sub t = testGroup "Plutus V1 features" $ + [ successfulUseOfMustPayToOtherScriptWithMintedToken + , successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken + --, successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda -- FAILING when onchain checks for only ada value and token is present -- PLT-885 + , successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance + , successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue + , contractErrorWhenAttemptingToSpendMoreThanAdaBalance + , contractErrorWhenAttemptingToSpendMoreThanTokenBalance + , phase2ErrorWhenExpectingMoreThanValue + ] ?? sub ?? t + +v2FeaturesTests :: SubmitTx -> LanguageContext -> TestTree +v2FeaturesTests sub t = testGroup "Plutus V2 features" $ + [ successfulUseOfMustPayToOtherScriptWithMintedTokenV2 + ] ?? sub ?? t + +v2FeaturesNotAvailableTests :: SubmitTx -> LanguageContext -> TestTree +v2FeaturesNotAvailableTests sub t = testGroup "Plutus V2 features" $ + [ phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum + ] ?? sub ?? t someDatum :: Ledger.Datum someDatum = asDatum @P.BuiltinByteString "datum" @@ -79,17 +106,11 @@ adaAmount = 5_000_000 adaValue :: Value.Value adaValue = Ada.lovelaceValueOf adaAmount -tknValue :: Value.Value -tknValue = Value.singleton mustPayToOtherScriptPolicyCurrencySymbol "mint-me" 1 - -tknValueV2 :: Value.Value -tknValueV2 = Value.singleton mustPayToOtherScriptPolicyCurrencySymbolV2 "mint-me" 1 - -adaAndTokenValue :: Value.Value -adaAndTokenValue = adaValue <> tknValue +tknValue :: LanguageContext -> Value.Value +tknValue tc = Value.singleton (mustPayToOtherScriptPolicyCurrencySymbol tc) "mint-me" 1 -adaAndTokenValueV2 :: Value.Value -adaAndTokenValueV2 = adaValue <> tknValueV2 +adaAndTokenValue :: LanguageContext -> Value.Value +adaAndTokenValue = (adaValue <>) . tknValue otherTokenValue :: Value.Value otherTokenValue = someTokenValue "someToken" 1 @@ -100,19 +121,19 @@ trace contract = do void $ Trace.waitNSlots 1 -- | Contract to a single transaction with mustSpendScriptOutputs offchain constraint and mint with policy using matching onchain constraint -mustPayToOtherScriptContract :: Value.Value -> Ledger.Redeemer -> Contract () Empty ContractError () -mustPayToOtherScriptContract offChainValue onChainConstraint = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy +mustPayToOtherScriptContract :: SubmitTx -> LanguageContext -> Value.Value -> Ledger.Redeemer -> Contract () Empty ContractError () +mustPayToOtherScriptContract submitTxFromConstraints lc offChainValue onChainConstraint = do + let lookups1 = mintingPolicy lc $ mustPayToOtherScriptPolicy lc tx1 = Constraints.mustPayToOtherScript someValidatorHash someDatum offChainValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue lc) + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 -- | Valid scenario using offchain and onchain constraint mustPayToOtherScript with exact token value being minted -successfulUseOfMustPayToOtherScriptWithMintedToken :: TestTree -successfulUseOfMustPayToOtherScriptWithMintedToken = - let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum adaAndTokenValue - contract = mustPayToOtherScriptContract adaAndTokenValue onChainConstraint +successfulUseOfMustPayToOtherScriptWithMintedToken :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToOtherScriptWithMintedToken submitTxFromConstraints lc = + let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum (adaAndTokenValue lc) + contract = mustPayToOtherScriptContract submitTxFromConstraints lc (adaAndTokenValue lc) onChainConstraint in checkPredicateOptions defaultCheckOptions "Successful use of offchain and onchain mustPayToOtherScript constraint with wallet's exact ada balance" @@ -121,20 +142,20 @@ successfulUseOfMustPayToOtherScriptWithMintedToken = -- | Contract to a single transaction with mustSpendScriptOutputs offchain constraint and mint with policy using -- matching onchain constraint, using Plutus V2 script and inline datum -mustPayToOtherScriptInlineContractV2 :: Value.Value -> Redeemer -> Contract () Empty ContractError () -mustPayToOtherScriptInlineContractV2 offChainValue onChainConstraint = do - let lookups1 = Constraints.plutusV2MintingPolicy mustPayToOtherScriptPolicyV2 +mustPayToOtherScriptInlineContractV2 :: SubmitTx -> LanguageContext -> Value.Value -> Redeemer -> Contract () Empty ContractError () +mustPayToOtherScriptInlineContractV2 submitTxFromConstraints lc offChainValue onChainConstraint = do + let lookups1 = mintingPolicy lc $ mustPayToOtherScriptPolicy lc tx1 = Constraints.mustPayToOtherScriptInlineDatum someValidatorHash someDatum offChainValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValueV2 - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue lc) + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 -- | Valid scenario using offchain and onchain constraint mustPayToOtherScript with exact token value being minted -- using inline datum -successfulUseOfMustPayToOtherScriptWithMintedTokenV2 :: TestTree -successfulUseOfMustPayToOtherScriptWithMintedTokenV2 = - let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum adaAndTokenValueV2 - contract = mustPayToOtherScriptInlineContractV2 adaAndTokenValueV2 onChainConstraint +successfulUseOfMustPayToOtherScriptWithMintedTokenV2 :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToOtherScriptWithMintedTokenV2 submitTxFromConstraints lc = + let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum (adaAndTokenValue lc) + contract = mustPayToOtherScriptInlineContractV2 submitTxFromConstraints lc (adaAndTokenValue lc) onChainConstraint in checkPredicateOptions defaultCheckOptions "Successful use of offchain and onchain mustPayToOtherScript constraint with wallet's exact ada balance with inline datum" @@ -142,10 +163,10 @@ successfulUseOfMustPayToOtherScriptWithMintedTokenV2 = (void $ trace contract) -- | Valid scenario using mustPayToOtherScript offchain constraint to include ada and token whilst onchain constraint checks for token value only -successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: TestTree -successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken = - let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum tknValue - contract = mustPayToOtherScriptContract adaAndTokenValue onChainConstraint +successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyToken submitTxFromConstraints lc = + let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum (tknValue lc) + contract = mustPayToOtherScriptContract submitTxFromConstraints lc (adaAndTokenValue lc) onChainConstraint in checkPredicateOptions defaultCheckOptions "Successful use of mustPayToOtherScript offchain constraint to include ada and token whilst onchain constraint checks for token value only" @@ -154,10 +175,10 @@ successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnly -- | Valid scenario using mustPayToOtherScript offchain constraint to include ada and token whilst onchain constraint checks for ada value only -- FAILING when onchain checks for only ada value and token is present -- PLT-885 -successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: TestTree -successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda = +successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnlyAda submitTxFromConstraints lc = let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum adaValue - contract = mustPayToOtherScriptContract adaAndTokenValue onChainConstraint + contract = mustPayToOtherScriptContract submitTxFromConstraints lc (adaAndTokenValue lc) onChainConstraint in checkPredicateOptions defaultCheckOptions "Successful use of mustPayToOtherScript offchain constraint to include ada and token whilst onchain constraint checks for ada value only" @@ -165,8 +186,8 @@ successfulUseOfMustPayToOtherScriptWhenOffchainIncludesTokenAndOnchainChecksOnly (void $ trace contract) -- | Valid scenario using offchain and onchain constraint mustPayToOtherScript in combination with mustSpendScriptOutputWithMatchingDatumAndValue to spend script's exact token balance -successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance :: TestTree -successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance = +successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance submitTxFromConstraints lc = let otherValidatorHash = alwaysSucceedValidatorHash adaAndOtherTokenValue = adaValue <> otherTokenValue onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum otherTokenValue @@ -174,17 +195,17 @@ successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance = contract = do let lookups1 = Constraints.plutusV1OtherScript someValidator tx1 = Constraints.mustPayToOtherScript someValidatorHash someDatum adaAndOtherTokenValue - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 scriptUtxos <- utxosAt $ Ledger.scriptHashAddress someValidatorHash let lookups2 = Constraints.plutusV1OtherScript someValidator <> Constraints.unspentOutputs scriptUtxos - <> Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy + <> mintingPolicy lc (mustPayToOtherScriptPolicy lc) tx2 = Constraints.mustPayToOtherScript otherValidatorHash someDatum adaAndOtherTokenValue <> Constraints.mustSpendScriptOutputWithMatchingDatumAndValue someValidatorHash (\d -> d == someDatum) (\v -> v == adaAndOtherTokenValue) (asRedeemer ()) - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue - ledgerTx2 <- submitTxConstraintsWith @UnitTest lookups2 tx2 + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue lc) + ledgerTx2 <- submitTxFromConstraints lookups2 tx2 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx2 in checkPredicateOptions options "Successful use of offchain and onchain mustPayToOtherScript constraint in combination with mustSpendScriptOutputWithMatchingDatumAndValue to spend script's exact token balance" @@ -192,10 +213,10 @@ successfulUseOfMustPayToOtherScriptWithScriptsExactTokenBalance = (void $ trace contract) -- | Valid scenario where onchain mustPayToOtherScript constraint expects less ada than the actual value -successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue :: TestTree -successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue = +successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue :: SubmitTx -> LanguageContext -> TestTree +successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue submitTxFromConstraints lc = let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum (Ada.lovelaceValueOf $ adaAmount - 1) - contract = mustPayToOtherScriptContract adaValue onChainConstraint + contract = mustPayToOtherScriptContract submitTxFromConstraints lc adaValue onChainConstraint in checkPredicateOptions defaultCheckOptions "Successful use of mustPayToOtherScript onchain constraint when it expects less ada than the actual value" @@ -203,20 +224,20 @@ successfulUseOfMustPayToOtherScriptWhenOnchainExpectsLowerAdaValue = (void $ trace contract) -- | Invalid contract that tries to use inline datum in a V1 script -mustPayToOtherScriptInlineContract :: Value.Value -> Redeemer -> Contract () Empty ContractError () -mustPayToOtherScriptInlineContract offChainValue onChainConstraint = do - let lookups1 = Constraints.plutusV1MintingPolicy mustPayToOtherScriptPolicy +mustPayToOtherScriptInlineContract :: SubmitTx -> LanguageContext -> Value.Value -> Redeemer -> Contract () Empty ContractError () +mustPayToOtherScriptInlineContract submitTxFromConstraints lc offChainValue onChainConstraint = do + let lookups1 = mintingPolicy lc $ mustPayToOtherScriptPolicy lc tx1 = Constraints.mustPayToOtherScriptInlineDatum someValidatorHash someDatum offChainValue - <> Constraints.mustMintValueWithRedeemer onChainConstraint tknValue - ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 + <> Constraints.mustMintValueWithRedeemer onChainConstraint (tknValue lc) + ledgerTx1 <- submitTxFromConstraints lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 -- | Contract error when ada amount to send to other script is greater than wallet balance -contractErrorWhenAttemptingToSpendMoreThanAdaBalance :: TestTree -contractErrorWhenAttemptingToSpendMoreThanAdaBalance = +contractErrorWhenAttemptingToSpendMoreThanAdaBalance :: SubmitTx -> LanguageContext -> TestTree +contractErrorWhenAttemptingToSpendMoreThanAdaBalance submitTxFromConstraints lc = let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum adaValue walletAdaBalance = Value.scale 10 utxoValue -- with fees this exceeds wallet balance - contract = mustPayToOtherScriptContract walletAdaBalance onChainConstraint + contract = mustPayToOtherScriptContract submitTxFromConstraints lc walletAdaBalance onChainConstraint in checkPredicateOptions defaultCheckOptions "Contract error when ada amount to send to other script is greater than wallet balance" @@ -224,10 +245,10 @@ contractErrorWhenAttemptingToSpendMoreThanAdaBalance = (void $ trace contract) -- | Contract error when token amount to send to other script is greater than wallet balance -contractErrorWhenAttemptingToSpendMoreThanTokenBalance :: TestTree -contractErrorWhenAttemptingToSpendMoreThanTokenBalance = +contractErrorWhenAttemptingToSpendMoreThanTokenBalance :: SubmitTx -> LanguageContext -> TestTree +contractErrorWhenAttemptingToSpendMoreThanTokenBalance submitTxFromConstraints lc = let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum otherTokenValue - contract = mustPayToOtherScriptContract otherTokenValue onChainConstraint + contract = mustPayToOtherScriptContract submitTxFromConstraints lc otherTokenValue onChainConstraint in checkPredicateOptions defaultCheckOptions "Contract error when token amount to send to other script is greater than wallet balance" @@ -235,10 +256,10 @@ contractErrorWhenAttemptingToSpendMoreThanTokenBalance = (void $ trace contract) -- | Phase-1 failure when mustPayToOtherScript in a V1 script use inline datum -phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum :: TestTree -phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum = - let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum adaAndTokenValue - contract = mustPayToOtherScriptInlineContract adaAndTokenValue onChainConstraint +phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum :: SubmitTx -> LanguageContext -> TestTree +phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum submitTxFromConstraints lc = + let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum (adaAndTokenValue lc) + contract = mustPayToOtherScriptInlineContract submitTxFromConstraints lc (adaAndTokenValue lc) onChainConstraint in checkPredicateOptions defaultCheckOptions "Phase-1 failure when mustPayToOtherScript in a V1 script use inline datum" @@ -248,52 +269,77 @@ phase1FailureWhenPayToOtherScriptV1ScriptUseInlineDatum = -- | Phase-2 validation failure when onchain mustSpendScriptOutput constraint expects more than actual ada value -phase2ErrorWhenExpectingMoreThanValue :: TestTree -phase2ErrorWhenExpectingMoreThanValue = +phase2ErrorWhenExpectingMoreThanValue :: SubmitTx -> LanguageContext -> TestTree +phase2ErrorWhenExpectingMoreThanValue submitTxFromConstraints lc = let onChainConstraint = asRedeemer $ MustPayToOtherScript someValidatorHash someDatum otherTokenValue - contract = mustPayToOtherScriptContract adaValue onChainConstraint + contract = mustPayToOtherScriptContract submitTxFromConstraints lc adaValue onChainConstraint in checkPredicateOptions defaultCheckOptions "Phase-2 validation failure when when token amount sent to other script is lower than actual value" (assertFailedTransaction (\_ err _ -> case err of {Ledger.ScriptFailure (EvaluationError ("Lb":_) _) -> True; _ -> False })) (void $ trace contract) + data UnitTest instance Scripts.ValidatorTypes UnitTest -{-# INLINEABLE mkMustPayToOtherScriptPolicy #-} -mkMustPayToOtherScriptPolicy :: ConstraintParams -> Ledger.ScriptContext -> Bool -mkMustPayToOtherScriptPolicy t = case t of - MustPayToOtherScript vh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScript vh d v) - MustPayToOtherScriptAddress vh svh d v -> Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddress vh svh d v) - -{-# INLINEABLE mkMustPayToOtherScriptPolicyV2 #-} -mkMustPayToOtherScriptPolicyV2 :: ConstraintParams -> V2.Scripts.ScriptContext -> Bool -mkMustPayToOtherScriptPolicyV2 t = case t of - MustPayToOtherScript vh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptInlineDatum vh d v) - MustPayToOtherScriptAddress vh svh d v -> V2.Constraints.checkScriptContext @() @() (Constraints.mustPayToOtherScriptAddressInlineDatum vh svh d v) +mkMustPayToOtherScriptPolicy :: (Constraints.TxConstraints () () -> sc -> Bool) -> ConstraintParams -> sc -> Bool +mkMustPayToOtherScriptPolicy checkScriptContext t = case t of + MustPayToOtherScript vh d v -> checkScriptContext (Constraints.mustPayToOtherScript vh d v) + MustPayToOtherScriptAddress vh svh d v -> checkScriptContext (Constraints.mustPayToOtherScriptAddress vh svh d v) -mustPayToOtherScriptPolicy :: Scripts.MintingPolicy -mustPayToOtherScriptPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) +mustPayToOtherScriptPolicyV1 :: Ledger.MintingPolicy +mustPayToOtherScriptPolicyV1 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where - wrap = Scripts.mkUntypedMintingPolicy mkMustPayToOtherScriptPolicy + checkedMkMustPayToOtherScriptPolicy = mkMustPayToOtherScriptPolicy Constraints.checkScriptContext + wrap = Scripts.mkUntypedMintingPolicy checkedMkMustPayToOtherScriptPolicy -mustPayToOtherScriptPolicyV2 :: V2.Scripts.MintingPolicy +mustPayToOtherScriptPolicyV2 :: Ledger.MintingPolicy mustPayToOtherScriptPolicyV2 = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where - wrap = V2.Scripts.mkUntypedMintingPolicy mkMustPayToOtherScriptPolicyV2 + checkedMkMustPayToOtherScriptPolicy = mkMustPayToOtherScriptPolicy V2.Constraints.checkScriptContext + wrap = V2.Scripts.mkUntypedMintingPolicy checkedMkMustPayToOtherScriptPolicy + +data LanguageContext + = LanguageContext + { mustPayToOtherScriptPolicy :: Ledger.MintingPolicy + , mintingPolicy :: forall a. Ledger.MintingPolicy -> Constraints.ScriptLookups a + , mintingPolicyHash :: Ledger.MintingPolicy -> Ledger.MintingPolicyHash + } + +languageContextV1 :: LanguageContext +languageContextV1 = LanguageContext + mustPayToOtherScriptPolicyV1 + Constraints.plutusV1MintingPolicy + PSU.V1.mintingPolicyHash + + +languageContextV2 :: LanguageContext +languageContextV2 = LanguageContext + mustPayToOtherScriptPolicyV2 + Constraints.plutusV2MintingPolicy + PSU.V2.mintingPolicyHash + + +type SubmitTx + = Constraints.ScriptLookups UnitTest + -> Constraints.TxConstraints (Scripts.RedeemerType UnitTest) (Scripts.DatumType UnitTest) + -> Contract () Empty ContractError Tx.CardanoTx + +cardanoSubmitTx :: SubmitTx +cardanoSubmitTx lookups tx = let + p = defaultCheckOptions ^. emulatorConfig . Trace.params + in submitUnbalancedTx $ either (error . show) id $ Tx.Constraints.mkTx @UnitTest p lookups tx -mustPayToOtherScriptPolicyHash :: Ledger.MintingPolicyHash -mustPayToOtherScriptPolicyHash = PSU.V1.mintingPolicyHash mustPayToOtherScriptPolicy +ledgerSubmitTx :: SubmitTx +ledgerSubmitTx = submitTxConstraintsWith -mustPayToOtherScriptPolicyHashV2 :: Ledger.MintingPolicyHash -mustPayToOtherScriptPolicyHashV2 = PSU.V2.mintingPolicyHash mustPayToOtherScriptPolicyV2 -mustPayToOtherScriptPolicyCurrencySymbol :: Ledger.CurrencySymbol -mustPayToOtherScriptPolicyCurrencySymbol = Value.mpsSymbol mustPayToOtherScriptPolicyHash +mustPayToOtherScriptPolicyHash :: LanguageContext -> Ledger.MintingPolicyHash +mustPayToOtherScriptPolicyHash lc = mintingPolicyHash lc $ mustPayToOtherScriptPolicy lc -mustPayToOtherScriptPolicyCurrencySymbolV2 :: Ledger.CurrencySymbol -mustPayToOtherScriptPolicyCurrencySymbolV2 = Value.mpsSymbol mustPayToOtherScriptPolicyHashV2 +mustPayToOtherScriptPolicyCurrencySymbol :: LanguageContext -> Ledger.CurrencySymbol +mustPayToOtherScriptPolicyCurrencySymbol = Value.mpsSymbol . mustPayToOtherScriptPolicyHash data ConstraintParams = MustPayToOtherScript PSU.V1.ValidatorHash Ledger.Datum Value.Value | MustPayToOtherScriptAddress PSU.V1.ValidatorHash PSU.V1.StakeValidatorHash Ledger.Datum Value.Value From 6235c3edfb3ff90329b3c5a16ae8c6ce06ca12a5 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 16:40:39 +0200 Subject: [PATCH 20/22] typo --- plutus-ledger/src/Ledger/Tx.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plutus-ledger/src/Ledger/Tx.hs b/plutus-ledger/src/Ledger/Tx.hs index 171efc3dc5..b0e090ebd6 100644 --- a/plutus-ledger/src/Ledger/Tx.hs +++ b/plutus-ledger/src/Ledger/Tx.hs @@ -151,13 +151,13 @@ makePrisms ''ChainIndexTxOut -- 'ChainIndexTxOut' to 'TxOut' and back is therefore lossy. toTxOut :: ChainIndexTxOut -> V2.Tx.TxOut toTxOut (PublicKeyChainIndexTxOut addr v datum referenceScript) = - V2.Tx.TxOut addr v (toPlutuvOutDatum datum) (scriptHash <$> referenceScript) + V2.Tx.TxOut addr v (toPlutusOutDatum datum) (scriptHash <$> referenceScript) toTxOut (ScriptChainIndexTxOut addr v datum referenceScript _validator) = - V2.Tx.TxOut addr v (toPlutuvOutDatum $ Just datum) (scriptHash <$> referenceScript) + V2.Tx.TxOut addr v (toPlutusOutDatum $ Just datum) (scriptHash <$> referenceScript) -toPlutuvOutDatum :: Maybe (V2.DatumHash, Maybe V2.Datum) -> V2.Tx.OutputDatum -toPlutuvOutDatum Nothing = V2.Tx.NoOutputDatum -toPlutuvOutDatum (Just (d, _)) = V2.Tx.OutputDatumHash d +toPlutusOutDatum :: Maybe (V2.DatumHash, Maybe V2.Datum) -> V2.Tx.OutputDatum +toPlutusOutDatum Nothing = V2.Tx.NoOutputDatum +toPlutusOutDatum (Just (d, _)) = V2.Tx.OutputDatumHash d -- | Converts a plutus-ledger-api transaction output to the chain index -- transaction output. From 428d2b65aae7bf6c401bbebb738af80a09dec083 Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 16:49:55 +0200 Subject: [PATCH 21/22] clean test suites --- .../Spec/TxConstraints/MustPayToOtherScript.hs | 10 ++-------- .../Spec/TxConstraints/MustPayToPubKeyAddress.hs | 14 +++----------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index b7bdfb781e..aaf0299e25 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -47,14 +47,8 @@ import Wallet (WalletAPIError (InsufficientFunds)) tests :: TestTree tests = testGroup "MustPayToOtherScript" - [ testGroup "ledger constraints" - [ v1Tests ledgerSubmitTx - , v2Tests ledgerSubmitTx - ] - , testGroup "cardano constraints" - [ v1Tests ledgerSubmitTx - , v2Tests ledgerSubmitTx - ] + [ testGroup "ledger constraints" $ [v1Tests, v2Tests] ?? ledgerSubmitTx + --, testGroup "cardano constraints" $ [v1Tests, v2Tests] ?? cardanoSubmitTx ] v1Tests :: SubmitTx -> TestTree diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs index e04fde2b40..3a5ea5c18b 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToPubKeyAddress.hs @@ -39,17 +39,9 @@ import PlutusTx.Prelude qualified as P -- Constraint's functions should soon be changed to use Address instead of PaymentPubKeyHash and StakeKeyHash tests :: TestTree -tests = - testGroup "MustPayToPubKeyAddress" - [ testGroup "ledger constraints" - [ v1Tests ledgerSubmitTx - , v2Tests ledgerSubmitTx - ] - {- testGroup "cardano constraints" - [ v1Tests ledgerSubmitTx - , v2Tests ledgerSubmitTx - ] - -} -- uncomment when MustPayToPubKey is implemented for Tx.Constraints +tests = testGroup "MustPayToPubKeyAddress" + [ testGroup "ledger constraints" $ [v1Tests, v2Tests] ?? ledgerSubmitTx + --, testGroup "cardano constraints" $ [v1Tests, v2Tests] ?? cardanoSubmitTx ] v1Tests :: SubmitTx -> TestTree From f2ea1b3edd17abe55fda52169982bd80947878ba Mon Sep 17 00:00:00 2001 From: Nicolas B Date: Tue, 27 Sep 2022 19:30:15 +0200 Subject: [PATCH 22/22] Clean up imports --- plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs index aaf0299e25..34242d10c4 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustPayToOtherScript.hs @@ -17,7 +17,6 @@ import Ledger qualified import Ledger.Ada qualified as Ada import Ledger.Constraints qualified as Constraints (ScriptLookups, TxConstraints, mustMintValueWithRedeemer, mustPayToOtherScript, mustPayToOtherScriptAddress, - mustPayToOtherScriptAddressInlineDatum, mustPayToOtherScriptInlineDatum, mustSpendScriptOutputWithMatchingDatumAndValue, plutusV1MintingPolicy, plutusV1OtherScript, plutusV2MintingPolicy,