diff --git a/plutus-contract/test/Spec/Contract/TxConstraints.hs b/plutus-contract/test/Spec/Contract/TxConstraints.hs index d0de473e44..c44271dfb6 100644 --- a/plutus-contract/test/Spec/Contract/TxConstraints.hs +++ b/plutus-contract/test/Spec/Contract/TxConstraints.hs @@ -41,6 +41,7 @@ import Plutus.Contract.Test (TracePredicate, assertValidatedTransactionCount, as minLogLevel, valueAtAddress, w1, walletFundsChange, (.&&.)) import Plutus.Script.Utils.Typed (Any) import Plutus.Script.Utils.V1.Address qualified as PV1 +import Plutus.Script.Utils.V1.Scripts qualified as PV1 import Plutus.Script.Utils.V1.Typed.Scripts qualified as PV1 import Plutus.Script.Utils.V2.Address qualified as PV2 import Plutus.Script.Utils.V2.Typed.Scripts qualified as PV2 diff --git a/plutus-contract/test/Spec/TxConstraints/MustMint.hs b/plutus-contract/test/Spec/TxConstraints/MustMint.hs index b6c07ab981..d75dcb5ce9 100644 --- a/plutus-contract/test/Spec/TxConstraints/MustMint.hs +++ b/plutus-contract/test/Spec/TxConstraints/MustMint.hs @@ -12,16 +12,22 @@ import Control.Monad (void) import Test.Tasty (TestTree, testGroup) import Control.Lens ((&)) +import Data.Map qualified as Map +import Data.Maybe (isJust) +import Data.Text qualified as Text import Data.Void (Void) import Ledger qualified import Ledger.Ada qualified as Ada +import Ledger.Constraints qualified as TC import Ledger.Constraints.OffChain qualified as Constraints (MkTxError (ScriptHashNotFound), plutusV1MintingPolicy, - typedValidatorLookups, unspentOutputs) + plutusV2MintingPolicy, typedValidatorLookups, + unspentOutputs) import Ledger.Constraints.OnChain.V1 qualified as Constraints (checkScriptContext) -import Ledger.Constraints.TxConstraints qualified as Constraints (collectFromTheScript, mustMintCurrency, - mustMintCurrencyWithRedeemer, mustMintValue, - mustMintValueWithRedeemer, mustPayToTheScript) -import Ledger.Test (asRedeemer, coinMintingPolicy, coinMintingPolicyCurrencySymbol, coinMintingPolicyHash) +import Ledger.Constraints.OnChain.V2 qualified as TCV2 +import Ledger.Constraints.TxConstraints qualified as Constraints +import Ledger.Scripts (ScriptHash (ScriptHash), unitRedeemer) +import Ledger.Test (asRedeemer, coinMintingPolicy, coinMintingPolicyCurrencySymbol, coinMintingPolicyCurrencySymbolV2, + coinMintingPolicyHash, coinMintingPolicyHashV2, coinMintingPolicyV2) import Ledger.Tx qualified as Tx import Ledger.Typed.Scripts qualified as Scripts import Ledger.Value (TokenName (TokenName)) @@ -29,11 +35,17 @@ import Plutus.Contract as Con import Plutus.Contract.Test (assertContractError, assertFailedTransaction, assertValidatedTransactionCount, changeInitialWalletValue, checkPredicate, checkPredicateOptions, defaultCheckOptions, w1, walletFundsChange, (.&&.)) +import Plutus.Script.Utils.Typed (Any) import Plutus.Script.Utils.V1.Scripts qualified as PSU.V1 +import Plutus.Script.Utils.V2.Address qualified as PV2 +import Plutus.Script.Utils.V2.Scripts qualified as PSU.V2 +import Plutus.Script.Utils.V2.Typed.Scripts qualified as PV2 +import Plutus.Script.Utils.V2.Typed.Scripts.MonetaryPolicies qualified as MPS2 import Plutus.Trace qualified as Trace -import Plutus.V1.Ledger.Api (MintingPolicyHash (MintingPolicyHash), Redeemer) -import Plutus.V1.Ledger.Scripts (ScriptError (EvaluationError), ScriptHash (ScriptHash), unitRedeemer) +import Plutus.V1.Ledger.Api (Address, MintingPolicyHash (MintingPolicyHash), Redeemer, TxOutRef) +import Plutus.V1.Ledger.Scripts (ScriptError (EvaluationError)) import Plutus.V1.Ledger.Value qualified as Value +import Plutus.V2.Ledger.Api qualified as PV2 import PlutusTx qualified import Prelude hiding (not) import Wallet (WalletAPIError (InsufficientFunds)) @@ -50,6 +62,9 @@ tests = , mustMintValueWithRedeemerSuccessfulMint , mustMintValueWithRedeemerSuccessfulBurn , mustMintValueSuccessfulMint + , mustMintWithReferenceV1Failure + , mustMintWithReferencePhase2Failure + , mustMintWithReferenceSuccessful ] trace :: Contract () Empty ContractError () -> Trace.EmulatorTrace () @@ -60,17 +75,26 @@ trace contract = do data UnitTest instance Scripts.ValidatorTypes UnitTest +nonExistentTxoRef :: TxOutRef +nonExistentTxoRef = Tx.TxOutRef "abcd" 123 + tknName :: TokenName tknName = "A" tknAmount :: Integer tknAmount = 21_000_000 -tknValue :: Value.Value -tknValue = tknValue' tknAmount +tknValueV1 :: Value.Value +tknValueV1 = tknValueV1' tknAmount + +tknValueV1' :: Integer -> Value.Value +tknValueV1' = Value.singleton coinMintingPolicyCurrencySymbol tknName + +tknValueV2 :: Value.Value +tknValueV2 = tknValueV2' tknAmount -tknValue' :: Integer -> Value.Value -tknValue' = Value.singleton coinMintingPolicyCurrencySymbol tknName +tknValueV2' :: Integer -> Value.Value +tknValueV2' = Value.singleton coinMintingPolicyCurrencySymbolV2 tknName -- | Valid Contract using a minting policy with mustMintCurrencyWithRedeemer onchain constraint to check that tokens are correctly minted with the other policy mustMintCurrencyWithRedeemerContract :: Integer -> TokenName -> Contract () Empty ContractError () @@ -94,6 +118,71 @@ mustMintCurrencyContract = do ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 +{-# INLINABLE mkMustReferenceOutputV2Validator #-} +mkMustReferenceOutputV2Validator :: TxOutRef -> () -> PV2.ScriptContext -> Bool +mkMustReferenceOutputV2Validator txOutRef _ = + TCV2.checkScriptContext @Void @Void (TC.mustReferenceOutput txOutRef) + +{-# INLINABLE mustReferenceOutputV2Validator #-} +mustReferenceOutputV2Validator :: PV2.Validator +mustReferenceOutputV2Validator = PV2.mkValidatorScript + $$(PlutusTx.compile [|| wrap ||]) + where + wrap = PV2.mkUntypedValidator mkMustReferenceOutputV2Validator + +mustReferenceOutputV2ValidatorAddress :: Address +mustReferenceOutputV2ValidatorAddress = + PV2.mkValidatorAddress mustReferenceOutputV2Validator + +mustMintValueWithReferenceContract :: Bool -> Contract () Empty ContractError () +mustMintValueWithReferenceContract failPhase2 = do + utxos <- ownUtxos + myAddr <- Con.ownAddress + let (utxoRef, utxo) = head $ drop 5 $ Map.toList utxos + MintingPolicyHash mph = coinMintingPolicyHashV2 + lookups0 = Constraints.plutusV2MintingPolicy coinMintingPolicyV2 + tx0 = Constraints.mustPayToAddressWithReferenceScript + myAddr + (ScriptHash mph) + Nothing + (Ada.adaValueOf 35) + ledgerTx0 <- submitTxConstraintsWith @UnitTest lookups0 tx0 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx0 + + utxos' <- ownUtxos + let refScriptUtxo = fst . head . filter (isJust . Tx._ciTxOutReferenceScript . snd) . Map.toList $ utxos' + redeemerRefUtxo = if failPhase2 then nonExistentTxoRef else refScriptUtxo + redeemer = asRedeemer $ MustMintValueWithReference redeemerRefUtxo tknValueV2 + lookups1 = Constraints.unspentOutputs (Map.singleton utxoRef utxo <> utxos') + <> Constraints.plutusV2MintingPolicy mustMintPolicyV2 + tx1 = Constraints.mustMintCurrencyWithRedeemer mustMintPolicyHashV2 redeemer tknName 1 + <> Constraints.mustMintValueWithReference refScriptUtxo tknValueV2 + ledgerTx1 <- submitTxConstraintsWith @Any lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + +mustMintValueWithReferenceContractV1Failure :: Contract () Empty ContractError () +mustMintValueWithReferenceContractV1Failure = do + utxos <- ownUtxos + myAddr <- Con.ownAddress + let (utxoRef, utxo) = head $ drop 5 $ Map.toList utxos + MintingPolicyHash mph = coinMintingPolicyHash + lookups0 = Constraints.plutusV1MintingPolicy coinMintingPolicy + tx0 = Constraints.mustPayToAddressWithReferenceScript + myAddr + (ScriptHash mph) + Nothing + (Ada.adaValueOf 30) + ledgerTx0 <- submitTxConstraintsWith @UnitTest lookups0 tx0 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx0 + + utxos' <- ownUtxos + let + refScriptUtxo = fst . head . filter (isJust . Tx._ciTxOutReferenceScript . snd) . Map.toList $ utxos' + lookups1 = Constraints.unspentOutputs (Map.singleton utxoRef utxo <> utxos') + tx1 = Constraints.mustMintCurrencyWithReference refScriptUtxo coinMintingPolicyHash tknName tknAmount + ledgerTx1 <- submitTxConstraintsWith @Any lookups1 tx1 + awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 + -- | Valid Contract using a minting policy with mustMintValueWithRedeemer onchain constraint to check that tokens are correctly minted with the other policy mustMintValueWithRedeemerContract :: Value.Value -> Contract () Empty ContractError () mustMintValueWithRedeemerContract mintValue = do @@ -108,11 +197,11 @@ mustMintValueWithRedeemerContract mintValue = do -- | Valid Contract using a minting policy with mustMintValue onchain constraint to check that tokens are correctly minted with the other policy mustMintValueContract :: Contract () Empty ContractError () mustMintValueContract = do - let redeemer = asRedeemer $ MustMintValue tknValue + let redeemer = asRedeemer $ MustMintValue tknValueV1 lookups1 = Constraints.plutusV1MintingPolicy mustMintPolicy <> Constraints.plutusV1MintingPolicy coinMintingPolicy tx1 = Constraints.mustMintCurrencyWithRedeemer mustMintPolicyHash redeemer tknName 1 - <> Constraints.mustMintValue tknValue + <> Constraints.mustMintValue tknValueV1 ledgerTx1 <- submitTxConstraintsWith @UnitTest lookups1 tx1 awaitTxConfirmed $ Tx.getCardanoTxId ledgerTx1 @@ -129,11 +218,11 @@ mustMintCurrencyWithRedeemerSuccessfulMint = mustMintCurrencyWithRedeemerSuccessfulBurn :: TestTree mustMintCurrencyWithRedeemerSuccessfulBurn = let tknBurnAmount = (-1000) - options = defaultCheckOptions & changeInitialWalletValue w1 (tknValue <>) + options = defaultCheckOptions & changeInitialWalletValue w1 (tknValueV1 <>) in checkPredicateOptions options "Successful token burn using mustMintCurrencyWithRedeemer" - (walletFundsChange w1 (tknValue' tknBurnAmount <> Value.singleton mustMintPolicyCurrencySymbol tknName 1) -- including mustMintPolicyCurrencySymbol is a workaround, test only cares about tknBurnAmount -- Fixed by PLT-909 + (walletFundsChange w1 (tknValueV1' tknBurnAmount <> Value.singleton mustMintPolicyCurrencySymbol tknName 1) -- including mustMintPolicyCurrencySymbol is a workaround, test only cares about tknBurnAmount -- Fixed by PLT-909 .&&. assertValidatedTransactionCount 1) (void $ trace $ mustMintCurrencyWithRedeemerContract tknBurnAmount tknName) @@ -141,7 +230,7 @@ mustMintCurrencyWithRedeemerSuccessfulBurn = mustMintCurrencyWithRedeemerBurnTooMuch :: TestTree mustMintCurrencyWithRedeemerBurnTooMuch = let tknBurnAmount = negate (tknAmount + 1) - options = defaultCheckOptions & changeInitialWalletValue w1 (tknValue <>) + options = defaultCheckOptions & changeInitialWalletValue w1 (tknValueV1 <>) contract = mustMintCurrencyWithRedeemerContract tknBurnAmount tknName in checkPredicateOptions options @@ -229,13 +318,13 @@ mustMintValueWithRedeemerSuccessfulMint = defaultCheckOptions "Successful spend of tokens using mustMintValueWithRedeemer" (assertValidatedTransactionCount 1) - (void $ trace $ mustMintValueWithRedeemerContract tknValue) + (void $ trace $ mustMintValueWithRedeemerContract tknValueV1) -- | Uses onchain and offchain constraint mustMintValueWithRedeemer to burn tokens mustMintValueWithRedeemerSuccessfulBurn :: TestTree mustMintValueWithRedeemerSuccessfulBurn = - let tknBurnValue = tknValue' (-1000) - options = defaultCheckOptions & changeInitialWalletValue w1 (tknValue <>) + let tknBurnValue = tknValueV1' (-1000) + options = defaultCheckOptions & changeInitialWalletValue w1 (tknValueV1 <>) in checkPredicateOptions options "Successful token burn using mustMintValueWithRedeemer" @@ -252,6 +341,30 @@ mustMintValueSuccessfulMint = (assertValidatedTransactionCount 1) (void $ trace mustMintValueContract) +mustMintWithReferenceV1Failure :: TestTree +mustMintWithReferenceV1Failure = + checkPredicateOptions + defaultCheckOptions + "MustMintValue with reference fails because v1 is not supported" + (assertFailedTransaction (\_ err -> case err of {Ledger.CardanoLedgerValidationError msg -> Text.isPrefixOf "ReferenceInputsNotSupported" msg; _ -> False })) + (void $ trace mustMintValueWithReferenceContractV1Failure) + +mustMintWithReferencePhase2Failure :: TestTree +mustMintWithReferencePhase2Failure = + checkPredicateOptions + defaultCheckOptions + "MustMintValue with reference fails phase 2 validation error" + (assertFailedTransaction (\_ err -> case err of {Ledger.ScriptFailure (EvaluationError ("L9":_) _) -> True; _ -> False })) + (void $ trace $ mustMintValueWithReferenceContract True) + +mustMintWithReferenceSuccessful :: TestTree +mustMintWithReferenceSuccessful = + checkPredicateOptions + defaultCheckOptions + "Successful mustMintValue with reference" + (assertValidatedTransactionCount 2) + (void $ trace $ mustMintValueWithReferenceContract False) + {-# INLINEABLE mkMustMintPolicy #-} mkMustMintPolicy :: ConstraintParams -> Ledger.ScriptContext -> Bool mkMustMintPolicy t = case t of @@ -259,15 +372,40 @@ mkMustMintPolicy t = case t of MustMintCurrency mph tn i -> Constraints.checkScriptContext @() @() (Constraints.mustMintCurrency mph tn i) MustMintValueWithRedeemer r v -> Constraints.checkScriptContext @() @() (Constraints.mustMintValueWithRedeemer r v) MustMintValue v -> Constraints.checkScriptContext @() @() (Constraints.mustMintValue v) + MustMintCurrencyWithReference ref mph tn i -> Constraints.checkScriptContext @() @() (Constraints.mustMintCurrencyWithReference ref mph tn i) + MustMintValueWithReference ref v -> Constraints.checkScriptContext @() @() (Constraints.mustMintValueWithReference ref v) + MustMintValueWithRedeemerAndReference r mref v -> Constraints.checkScriptContext @() @() (Constraints.mustMintValueWithRedeemerAndReference r mref v) + MustMintCurrencyWithRedeemerAndReference mref mph r tn i -> Constraints.checkScriptContext @() @() (Constraints.mustMintCurrencyWithRedeemerAndReference mref mph r tn i) + +{-# INLINEABLE mkMustMintPolicyV2 #-} +mkMustMintPolicyV2 :: ConstraintParams -> PV2.ScriptContext -> Bool +mkMustMintPolicyV2 t = case t of + MustMintCurrencyWithRedeemer mph r tn i -> TCV2.checkScriptContext @() @() (Constraints.mustMintCurrencyWithRedeemer mph r tn i) + MustMintCurrency mph tn i -> TCV2.checkScriptContext @() @() (Constraints.mustMintCurrency mph tn i) + MustMintValueWithRedeemer r v -> TCV2.checkScriptContext @() @() (Constraints.mustMintValueWithRedeemer r v) + MustMintValue v -> TCV2.checkScriptContext @() @() (Constraints.mustMintValue v) + MustMintCurrencyWithReference ref mph tn i -> TCV2.checkScriptContext @() @() (Constraints.mustMintCurrencyWithReference ref mph tn i) + MustMintValueWithReference ref v -> TCV2.checkScriptContext @() @() (Constraints.mustMintValueWithReference ref v) + MustMintValueWithRedeemerAndReference r mref v -> TCV2.checkScriptContext @() @() (Constraints.mustMintValueWithRedeemerAndReference r mref v) + MustMintCurrencyWithRedeemerAndReference mref mph r tn i -> TCV2.checkScriptContext @() @() (Constraints.mustMintCurrencyWithRedeemerAndReference mref mph r tn i) + mustMintPolicy :: Scripts.MintingPolicy mustMintPolicy = Ledger.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) where wrap = Scripts.mkUntypedMintingPolicy mkMustMintPolicy +mustMintPolicyV2 :: Scripts.MintingPolicy +mustMintPolicyV2 = PV2.mkMintingPolicyScript $$(PlutusTx.compile [||wrap||]) + where + wrap = MPS2.mkUntypedMintingPolicy mkMustMintPolicyV2 + mustMintPolicyHash :: Ledger.MintingPolicyHash mustMintPolicyHash = PSU.V1.mintingPolicyHash mustMintPolicy +mustMintPolicyHashV2 :: Ledger.MintingPolicyHash +mustMintPolicyHashV2 = PSU.V2.mintingPolicyHash mustMintPolicyV2 + mustMintPolicyCurrencySymbol :: Value.CurrencySymbol mustMintPolicyCurrencySymbol = Value.mpsSymbol mustMintPolicyHash @@ -275,6 +413,10 @@ data ConstraintParams = MustMintCurrencyWithRedeemer Ledger.MintingPolicyHash Re | MustMintCurrency Ledger.MintingPolicyHash TokenName Integer | MustMintValueWithRedeemer Redeemer Value.Value | MustMintValue Value.Value + | MustMintCurrencyWithReference TxOutRef Ledger.MintingPolicyHash TokenName Integer + | MustMintValueWithReference TxOutRef Value.Value + | MustMintValueWithRedeemerAndReference Redeemer (Maybe TxOutRef) Value.Value + | MustMintCurrencyWithRedeemerAndReference (Maybe TxOutRef) Ledger.MintingPolicyHash Redeemer TokenName Integer deriving (Show) PlutusTx.unstableMakeIsData ''ConstraintParams diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs index e59a5804ee..ddb421e341 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OffChain.hs @@ -765,8 +765,7 @@ processConstraint = \case MustReferenceOutput txo -> do unbalancedTx . tx . Tx.referenceInputs <>= [Tx.pubKeyTxInput txo] - MustMintValue mpsHash@(MintingPolicyHash mpsHashBytes) red tn i -> do - mintingPolicyScript <- lookupMintingPolicy mpsHash + MustMintValue mpsHash@(MintingPolicyHash mpsHashBytes) red tn i mref -> do -- See note [Mint and Fee fields must have ada symbol]. let value = (<>) (Ada.lovelaceValueOf 0) . Value.singleton (Value.mpsSymbol mpsHash) tn -- If i is negative we are burning tokens. The tokens burned must @@ -777,10 +776,21 @@ processConstraint = \case 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.mintScripts %= Map.insert mpsHash (red, flip Versioned PlutusV2 <$> mref) unbalancedTx . tx . Tx.mint <>= value i + case mref of + Just ref -> do + refTxOut <- lookupTxOutRef ref + case _ciTxOutReferenceScript refTxOut of + Just _ -> do + unbalancedTx . tx . Tx.referenceInputs <>= [Tx.pubKeyTxInput ref] + _ -> throwError (TxOutRefNoReferenceScript ref) + Nothing -> do + mintingPolicyScript <- lookupMintingPolicy mpsHash + unbalancedTx . tx . Tx.scriptWitnesses %= Map.insert (ScriptHash mpsHashBytes) (fmap getMintingPolicy mintingPolicyScript) + + MustPayToPubKeyAddress pk skhM mdv refScriptHashM vl -> do forM_ mdv $ \case TxOutDatumInTx d -> do diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs index aec358373b..34917e5dff 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V1.hs @@ -111,7 +111,7 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case -- gives us the redeemer's hash, but 'MustSpendScriptOutput' gives -- us the full redeemer $ isJust (V.findTxInByTxOutRef txOutRef scriptContextTxInfo) - MustMintValue mps _ tn v -> + MustMintValue mps _ tn v _ -> traceIfFalse "L9" -- "Value minted not OK" $ Value.valueOf (txInfoMint scriptContextTxInfo) (Value.mpsSymbol mps) tn == v MustPayToPubKeyAddress (PaymentPubKeyHash pk) _ mdv refScript vl -> diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs index 87e3c360d3..fd0fd9c2b1 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/OnChain/V2.hs @@ -122,9 +122,10 @@ checkTxConstraint ctx@ScriptContext{scriptContextTxInfo} = \case $ Just rdmr == AMap.lookup (Spending txOutRef) (txInfoRedeemers scriptContextTxInfo) && isJust (PV2.findTxInByTxOutRef txOutRef scriptContextTxInfo) && maybe True (\ref -> isJust (PV2.findTxRefInByTxOutRef ref scriptContextTxInfo)) mRefTxOutRef - MustMintValue mps _ tn v -> + MustMintValue mps _ tn v mRefTxOutRef -> traceIfFalse "L9" -- "Value minted not OK" $ Value.valueOf (txInfoMint scriptContextTxInfo) (Value.mpsSymbol mps) tn == v + && maybe True (\ref -> isJust (PV2.findTxRefInByTxOutRef ref scriptContextTxInfo)) mRefTxOutRef MustPayToPubKeyAddress (PaymentPubKeyHash pk) _skh mdv _refScript vl -> let outs = PV2.txInfoOutputs scriptContextTxInfo hsh dv = PV2.findDatumHash dv scriptContextTxInfo diff --git a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs index 02b368e63b..893dee24a6 100644 --- a/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs +++ b/plutus-ledger-constraints/src/Ledger/Constraints/TxConstraints.hs @@ -133,7 +133,7 @@ data TxConstraint = -- ^ The transaction must include the utxo as collateral input. | MustReferenceOutput TxOutRef -- ^ The transaction must reference (not spend) the given unspent transaction output. - | MustMintValue MintingPolicyHash Redeemer TokenName Integer + | MustMintValue MintingPolicyHash Redeemer TokenName Integer (Maybe TxOutRef) -- ^ The transaction must mint the given token and amount. | MustPayToPubKeyAddress PaymentPubKeyHash (Maybe StakePubKeyHash) (Maybe (TxOutDatum Datum)) (Maybe ScriptHash) Value -- ^ The transaction must create a transaction output with a public key address. @@ -165,8 +165,8 @@ instance Pretty TxConstraint where hang 2 $ vsep ["must spend script output:", pretty ref, pretty red, pretty mref] MustReferenceOutput ref -> hang 2 $ vsep ["must reference output:", pretty ref] - MustMintValue mps red tn i -> - hang 2 $ vsep ["must mint value:", pretty mps, pretty red, pretty tn <+> pretty i] + MustMintValue mps red tn i mref -> + hang 2 $ vsep ["must mint value:", pretty mps, pretty red, pretty tn <+> pretty i, pretty mref] MustPayToPubKeyAddress pkh skh datum refScript v -> hang 2 $ vsep ["must pay to pubkey address:", pretty pkh, pretty skh, pretty datum, pretty refScript, pretty v] MustPayToOtherScript vlh skh dv refScript vl -> @@ -609,19 +609,30 @@ mustPayToOtherScriptAddressWithInlineDatum vh svh dv vl = mustMintValue :: forall i o. Value -> TxConstraints i o mustMintValue = mustMintValueWithRedeemer unitRedeemer +{-# INLINABLE mustMintValueWithReference #-} +-- | Same as 'mustMintValueWithRedeemerAndReference', but sets the redeemer to the unit +-- redeemer. +mustMintValueWithReference :: forall i o. TxOutRef -> Value -> TxConstraints i o +mustMintValueWithReference = mustMintValueWithRedeemerAndReference unitRedeemer . Just + {-# INLINABLE mustMintValueWithRedeemer #-} --- | Same as 'mustMintCurrencyWithRedeemer', but uses the minting policy hash, +-- | Same as 'mustMintValueWithRedeemerAndReference', but sets the reference to 'Nothing'. +mustMintValueWithRedeemer :: forall i o. Redeemer -> Value -> TxConstraints i o +mustMintValueWithRedeemer red = mustMintValueWithRedeemerAndReference red Nothing + +{-# INLINABLE mustMintValueWithRedeemerAndReference #-} +-- | Same as 'mustMintCurrencyWithRedeemerAndReference', but uses the minting policy hash, -- token name and amount provided by 'Value'. -- -- Note that we can derive the 'MintingPolicyHash' from the 'Value'\'s currency -- symbol. -mustMintValueWithRedeemer :: forall i o. Redeemer -> Value -> TxConstraints i o -mustMintValueWithRedeemer red = +mustMintValueWithRedeemerAndReference :: forall i o. Redeemer -> (Maybe TxOutRef) -> Value -> TxConstraints i o +mustMintValueWithRedeemerAndReference red mref = foldMap valueConstraint . (AssocMap.toList . Value.getValue) where valueConstraint (currencySymbol, mp) = let hs = Value.currencyMPSHash currencySymbol in - foldMap (Haskell.uncurry (mustMintCurrencyWithRedeemer hs red)) + foldMap (Haskell.uncurry (mustMintCurrencyWithRedeemerAndReference mref hs red)) (AssocMap.toList mp) {-# INLINABLE mustMintCurrency #-} @@ -635,12 +646,36 @@ mustMintCurrency -> TxConstraints i o mustMintCurrency mps = mustMintCurrencyWithRedeemer mps unitRedeemer +{-# INLINABLE mustMintCurrencyWithReference #-} +-- | Same as 'mustMintCurrencyWithRedeemerAndReference', but sets the redeemer to the unit +-- redeemer. +mustMintCurrencyWithReference + :: forall i o + . TxOutRef + -> MintingPolicyHash + -> TokenName + -> Integer + -> TxConstraints i o +mustMintCurrencyWithReference ref mps = mustMintCurrencyWithRedeemerAndReference (Just ref) mps unitRedeemer + {-# INLINABLE mustMintCurrencyWithRedeemer #-} --- | @mustMintCurrencyWithRedeemer mph r tn a@ creates the given amount @a@ of --- the currency specified with @mph@, @r@ and @tn@. +-- | Same as 'mustMintCurrencyWithRedeemerAndReference', but sets the reference to 'Nothing'. +mustMintCurrencyWithRedeemer + :: forall i o + . MintingPolicyHash + -> Redeemer + -> TokenName + -> Integer + -> TxConstraints i o +mustMintCurrencyWithRedeemer = mustMintCurrencyWithRedeemerAndReference Nothing + +{-# INLINABLE mustMintCurrencyWithRedeemerAndReference #-} +-- | @mustMintCurrencyWithRedeemerAndReference mref mph r tn a@ creates the given amount @a@ of +-- the currency specified with @mph@, @r@ and @tn@. The minting policy script can be specified +-- with a reference script @mref@. -- -- If used in 'Ledger.Constraints.OffChain', this constraint mints a currency --- using @mph@, @r@, @tn@ and @a@, adds @mph@ in the transaction's minting +-- using @mref@, @mph@, @r@, @tn@ and @a@, adds @mph@ in the transaction's minting -- policy witness set and adds @r@ in the transaction's redeemer witness set. -- The minting policy must be provided in the -- 'Ledger.Constraints.OffChain.ScriptLookups' with @@ -648,16 +683,17 @@ mustMintCurrency mps = mustMintCurrencyWithRedeemer mps unitRedeemer -- 'Ledger.Constraints.OffChain.plutusV1MintingPolicy'. -- -- If used in 'Ledger.Constraints.OnChain', this constraint verifies that the --- minted currenty @mph@, @tn@ and @a@ is part of the transaction's minting +-- minted currenty @mref@, @mph@, @tn@ and @a@ is part of the transaction's minting -- information. -mustMintCurrencyWithRedeemer +mustMintCurrencyWithRedeemerAndReference :: forall i o - . MintingPolicyHash + . (Maybe TxOutRef) + -> MintingPolicyHash -> Redeemer -> TokenName -> Integer -> TxConstraints i o -mustMintCurrencyWithRedeemer mps red tn a = if a == 0 then mempty else singleton $ MustMintValue mps red tn a +mustMintCurrencyWithRedeemerAndReference mref mph red tn a = if a == 0 then mempty else singleton $ MustMintValue mph red tn a mref {-# INLINABLE mustSpendAtLeast #-} -- | @mustSpendAtLeast v@ requires the sum of the transaction's inputs value to @@ -846,8 +882,8 @@ requiredSignatories = foldMap f . txConstraints where {-# INLINABLE requiredMonetaryPolicies #-} requiredMonetaryPolicies :: forall i o. TxConstraints i o -> [MintingPolicyHash] requiredMonetaryPolicies = foldMap f . txConstraints where - f (MustMintValue mps _ _ _) = [mps] - f _ = [] + f (MustMintValue mps _ _ _ _) = [mps] + f _ = [] {-# INLINABLE requiredDatums #-} requiredDatums :: forall i o. TxConstraints i o -> [Datum] diff --git a/plutus-ledger/src/Ledger/Generators.hs b/plutus-ledger/src/Ledger/Generators.hs index 8702874821..a73c848f20 100644 --- a/plutus-ledger/src/Ledger/Generators.hs +++ b/plutus-ledger/src/Ledger/Generators.hs @@ -263,7 +263,7 @@ genValidTransactionSpending' g ins totalVal = do , txData = Map.fromList (map (\d -> (datumHash d, d)) datums) , txScripts = Map.fromList (map ((\s -> (scriptHash s, s)) . fmap getValidator) scripts) } - & addMintingPolicy (Versioned ScriptGen.alwaysSucceedPolicy PlutusV1) Script.unitRedeemer + & addMintingPolicy (Versioned ScriptGen.alwaysSucceedPolicy PlutusV1) (Script.unitRedeemer, Nothing) & EmulatorTx -- sign the transaction with all known wallets diff --git a/plutus-ledger/src/Ledger/Test.hs b/plutus-ledger/src/Ledger/Test.hs index 26c72bf1e7..eeaf00d36c 100644 --- a/plutus-ledger/src/Ledger/Test.hs +++ b/plutus-ledger/src/Ledger/Test.hs @@ -10,8 +10,9 @@ import Ledger qualified import Ledger.Typed.Scripts qualified as Scripts import Plutus.Script.Utils.Typed as PSU import Plutus.Script.Utils.V1.Scripts qualified as PV1 -import Plutus.Script.Utils.V1.Typed.Scripts.MonetaryPolicies qualified as MPS +import Plutus.Script.Utils.V1.Typed.Scripts.MonetaryPolicies qualified as MPS1 import Plutus.Script.Utils.V2.Scripts qualified as PV2 +import Plutus.Script.Utils.V2.Typed.Scripts.MonetaryPolicies qualified as MPS2 import Plutus.V1.Ledger.Api (Address, Validator) import Plutus.V1.Ledger.Api qualified as PV1 import Plutus.V1.Ledger.Value qualified as Value @@ -50,16 +51,30 @@ someAddressV2 = Ledger.scriptValidatorHashAddress someValidatorHashV2 Nothing mkPolicy :: () -> Ledger.ScriptContext -> Bool mkPolicy _ _ = True +{-# INLINABLE mkPolicyV2 #-} +mkPolicyV2 :: () -> PV2.ScriptContext -> Bool +mkPolicyV2 _ _ = True + coinMintingPolicy :: Ledger.MintingPolicy coinMintingPolicy = Ledger.mkMintingPolicyScript - $$(PlutusTx.compile [|| MPS.mkUntypedMintingPolicy mkPolicy ||]) + $$(PlutusTx.compile [|| MPS1.mkUntypedMintingPolicy mkPolicy ||]) coinMintingPolicyHash :: Ledger.MintingPolicyHash coinMintingPolicyHash = PV1.mintingPolicyHash coinMintingPolicy +coinMintingPolicyV2 :: Ledger.MintingPolicy +coinMintingPolicyV2 = Ledger.mkMintingPolicyScript + $$(PlutusTx.compile [|| MPS2.mkUntypedMintingPolicy mkPolicyV2 ||]) + +coinMintingPolicyHashV2 :: Ledger.MintingPolicyHash +coinMintingPolicyHashV2 = PV2.mintingPolicyHash coinMintingPolicyV2 + coinMintingPolicyCurrencySymbol :: Ledger.CurrencySymbol coinMintingPolicyCurrencySymbol = Value.mpsSymbol coinMintingPolicyHash +coinMintingPolicyCurrencySymbolV2 :: Ledger.CurrencySymbol +coinMintingPolicyCurrencySymbolV2 = Value.mpsSymbol coinMintingPolicyHashV2 + someToken :: Ledger.Value someToken = Value.singleton coinMintingPolicyCurrencySymbol "someToken" 1 diff --git a/plutus-ledger/src/Ledger/Tx.hs b/plutus-ledger/src/Ledger/Tx.hs index bd5925e4b4..d69d42c531 100644 --- a/plutus-ledger/src/Ledger/Tx.hs +++ b/plutus-ledger/src/Ledger/Tx.hs @@ -244,7 +244,7 @@ instance Pretty CardanoTx where ++ [ "mint:" <+> pretty (getCardanoTxMint tx) , "fee:" <+> pretty (getCardanoTxFee tx) ] ++ onCardanoTx (\tx' -> - [ hang 2 (vsep ("mps:": fmap pretty (Map.toList (txMintingScripts tx')))) + [ hang 2 (vsep ("mps:": fmap pretty (Map.toList (txMintingWitnesses tx')))) , hang 2 (vsep ("signatures:": fmap (pretty . fst) (Map.toList (txSignatures tx')))) ]) (const []) tx ++ [ "validity range:" <+> viaShow (getCardanoTxValidityRange tx) diff --git a/plutus-ledger/src/Ledger/Tx/CardanoAPI.hs b/plutus-ledger/src/Ledger/Tx/CardanoAPI.hs index cf0ffef392..95d264c439 100644 --- a/plutus-ledger/src/Ledger/Tx/CardanoAPI.hs +++ b/plutus-ledger/src/Ledger/Tx/CardanoAPI.hs @@ -34,7 +34,6 @@ module Ledger.Tx.CardanoAPI( import Cardano.Api qualified as C import Cardano.Api.Shelley qualified as C import Data.Bitraversable (bisequence) -import Data.Map (Map) import Data.Map qualified as Map import Ledger.Address qualified as P import Ledger.Params qualified as P @@ -87,7 +86,7 @@ toCardanoTxBodyContent P.Params{P.pProtocolParams, P.pNetworkId} sigs tx@P.Tx{.. , txUpdateProposal = C.TxUpdateProposalNone } -toWithdrawals :: Map P.ScriptHash (P.Versioned P.Script) +toWithdrawals :: P.ScriptsMap -> C.NetworkId -> [P.Withdrawal] -> Either ToCardanoError (C.TxWithdrawals C.BuildTx C.BabbageEra) @@ -104,29 +103,39 @@ toWithdrawals txScripts networkId = \case toStakeWitness withdrawalRedeemer cred = case cred of PV1.PubKeyCredential _pkh -> pure $ C.BuildTxWith $ C.KeyWitness C.KeyWitnessForStakeAddr PV1.ScriptCredential _vh -> case (,) <$> withdrawalRedeemer <*> P.lookupValidator txScripts _vh of - Just (redeemer, script) -> C.BuildTxWith . C.ScriptWitness C.ScriptWitnessForStakeAddr <$> toCardanoScriptWitness C.NoScriptDatumForStake redeemer (fmap P.getValidator script) + Just (redeemer, script) -> C.BuildTxWith . C.ScriptWitness C.ScriptWitnessForStakeAddr <$> toCardanoScriptWitness C.NoScriptDatumForStake redeemer (Left $ fmap P.getValidator script) Nothing -> Left MissingStakeValidator -toCardanoMintWitness :: PV1.Redeemer -> Maybe (P.Versioned PV1.MintingPolicy) -> Either ToCardanoError (C.ScriptWitness C.WitCtxMint C.BabbageEra) -toCardanoMintWitness _ Nothing = Left MissingMintingPolicy -toCardanoMintWitness redeemer (Just script) = - toCardanoScriptWitness C.NoScriptDatumForMint redeemer (fmap P.getMintingPolicy script) +toCardanoMintWitness :: PV1.Redeemer -> Maybe (P.Versioned PV1.TxOutRef) -> Maybe (P.Versioned PV1.MintingPolicy) -> Either ToCardanoError (C.ScriptWitness C.WitCtxMint C.BabbageEra) +toCardanoMintWitness _ Nothing Nothing = Left MissingMintingPolicy +toCardanoMintWitness redeemer (Just ref) _ = + toCardanoScriptWitness C.NoScriptDatumForMint redeemer (Right ref) +toCardanoMintWitness redeemer _ (Just script) = + toCardanoScriptWitness C.NoScriptDatumForMint redeemer (Left (fmap P.getMintingPolicy script)) toCardanoScriptWitness :: PV1.ToData a => C.ScriptDatum witctx -> a - -> P.Versioned PV1.Script + -> Either (P.Versioned PV1.Script) (P.Versioned PV1.TxOutRef) -> Either ToCardanoError (C.ScriptWitness witctx C.BabbageEra) -toCardanoScriptWitness datum redeemer (P.Versioned script lang) = (case lang of +toCardanoScriptWitness datum redeemer scriptOrRef = (case lang of P.PlutusV1 -> C.PlutusScriptWitness C.PlutusScriptV1InBabbage C.PlutusScriptV1 - <$> fmap C.PScript (toCardanoPlutusScript (C.AsPlutusScript C.AsPlutusScriptV1) script) + <$> (case scriptOrRef of + Left (P.Versioned script _) -> fmap C.PScript (toCardanoPlutusScript (C.AsPlutusScript C.AsPlutusScriptV1) script) + Right (P.Versioned ref _) -> flip C.PReferenceScript Nothing <$> (toCardanoTxIn ref) + ) P.PlutusV2 -> C.PlutusScriptWitness C.PlutusScriptV2InBabbage C.PlutusScriptV2 - <$> fmap C.PScript (toCardanoPlutusScript (C.AsPlutusScript C.AsPlutusScriptV2) script) + <$> (case scriptOrRef of + Left (P.Versioned script _) -> fmap C.PScript (toCardanoPlutusScript (C.AsPlutusScript C.AsPlutusScriptV2) script) + Right (P.Versioned ref _) -> flip C.PReferenceScript Nothing <$> (toCardanoTxIn ref) + ) ) <*> pure datum <*> pure (C.fromPlutusData $ PV1.toData redeemer) <*> pure zeroExecutionUnits + where + lang = either P.version P.version scriptOrRef toCardanoStakeAddress :: C.NetworkId -> PV1.Credential -> Either ToCardanoError C.StakeAddress toCardanoStakeAddress networkId credential = @@ -203,10 +212,10 @@ toCardanoTxInScriptWitnessHeader (P.Versioned script lang) = toCardanoMintValue :: P.Tx -> Either ToCardanoError (C.TxMintValue C.BuildTx C.BabbageEra) toCardanoMintValue tx@P.Tx{..} = - let indexedMps = Map.assocs txMintingScripts + let indexedMps = Map.assocs txMintingWitnesses in C.TxMintValue C.MultiAssetInBabbageEra <$> toCardanoValue txMint <*> fmap (C.BuildTxWith . Map.fromList) - (traverse (\(mph, rd) -> - bisequence (toCardanoPolicyId mph, toCardanoMintWitness rd (P.lookupMintingPolicy (P.txScripts tx) mph))) + (traverse (\(mph, (rd, mTxOutRef)) -> + bisequence (toCardanoPolicyId mph, toCardanoMintWitness rd mTxOutRef (P.lookupMintingPolicy (P.txScripts tx) mph))) indexedMps) diff --git a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs index 972eda5fa7..5edf2fdeaa 100644 --- a/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs +++ b/plutus-ledger/src/Ledger/Tx/CardanoAPI/Internal.hs @@ -89,7 +89,6 @@ import Cardano.Api.Shelley qualified as C import Cardano.BM.Data.Tracer (ToObject) import Cardano.Chain.Common (addrToBase58) import Cardano.Ledger.Alonzo.Language qualified as Alonzo -import Cardano.Ledger.Alonzo.Language qualified as P import Cardano.Ledger.Alonzo.Scripts qualified as Alonzo import Cardano.Ledger.Alonzo.TxWitness qualified as Alonzo import Cardano.Ledger.Core qualified as Ledger diff --git a/plutus-ledger/src/Ledger/Tx/Internal.hs b/plutus-ledger/src/Ledger/Tx/Internal.hs index 03475d33c7..95fcf33dea 100644 --- a/plutus-ledger/src/Ledger/Tx/Internal.hs +++ b/plutus-ledger/src/Ledger/Tx/Internal.hs @@ -27,6 +27,7 @@ import Codec.Serialise (Serialise, decode, encode) import Control.Applicative (empty, (<|>)) import Control.DeepSeq (NFData, rnf) import Control.Lens ((&), (.~), (?~)) + import Control.Lens qualified as L import Control.Monad.State.Strict (execState, modify') import Data.Aeson (FromJSON, ToJSON) @@ -250,6 +251,9 @@ instance Pretty TxOut where ["with reference script hash" <+> viaShow (C.hashScript s)] C.ReferenceScriptNone -> [] +type ScriptsMap = Map ScriptHash (Versioned Script) +type MintingWitnessesMap = Map MintingPolicyHash (Redeemer, Maybe (Versioned TxOutRef)) + -- | A Babbage-era transaction, including witnesses for its inputs. data Tx = Tx { txInputs :: [TxInput], @@ -270,15 +274,15 @@ data Tx = Tx { -- ^ The fee for this transaction. txValidRange :: !SlotRange, -- ^ The 'SlotRange' during which this transaction may be validated. - txMintingScripts :: Map MintingPolicyHash Redeemer, - -- ^ The scripts that must be run to check minting conditions matched with their redeemers. + txMintingWitnesses :: MintingWitnessesMap, + -- ^ The witnesses that must be present to check minting conditions matched with their redeemers. txWithdrawals :: [Withdrawal], -- ^ Withdrawals, contains redeemers. txCertificates :: [Certificate], -- ^ Certificates, contains redeemers. txSignatures :: Map PubKey Signature, -- ^ Signatures of this transaction. - txScripts :: Map.Map ScriptHash (Versioned Script), + txScripts :: ScriptsMap, -- ^ Scripts for all script credentials mentioned in this tx. txData :: Map DatumHash Datum, -- ^ Datum objects recorded on this transaction. @@ -299,7 +303,7 @@ instance Semigroup Tx where txMint = txMint tx1 <> txMint tx2, txFee = txFee tx1 <> txFee tx2, txValidRange = txValidRange tx1 /\ txValidRange tx2, - txMintingScripts = txMintingScripts tx1 <> txMintingScripts tx2, + txMintingWitnesses = txMintingWitnesses tx1 <> txMintingWitnesses tx2, txSignatures = txSignatures tx1 <> txSignatures tx2, txData = txData tx1 <> txData tx2, txScripts = txScripts tx1 <> txScripts tx2, @@ -370,12 +374,12 @@ mint = L.lens g s where g = txMint s tx v = tx { txMint = v } -mintScripts :: L.Lens' Tx (Map MintingPolicyHash Redeemer) +mintScripts :: L.Lens' Tx MintingWitnessesMap mintScripts = L.lens g s where - g = txMintingScripts - s tx fs = tx { txMintingScripts = fs } + g = txMintingWitnesses + s tx fs = tx { txMintingWitnesses = fs } -scriptWitnesses :: L.Lens' Tx (Map ScriptHash (Versioned Script)) +scriptWitnesses :: L.Lens' Tx ScriptsMap scriptWitnesses = L.lens g s where g = txScripts s tx fs = tx { txScripts = fs } @@ -494,10 +498,10 @@ outReferenceScript = L.lens txOutReferenceScript (\(TxOut (C.TxOut aie tov tod _)) rs -> TxOut (C.TxOut aie tov tod rs)) -lookupScript :: Map ScriptHash (Versioned Script) -> ScriptHash -> Maybe (Versioned Script) -lookupScript txScripts hash = Map.lookup hash txScripts +lookupScript :: ScriptsMap -> ScriptHash -> Maybe (Versioned Script) +lookupScript txScripts hash = Map.lookup hash txScripts -lookupValidator :: Map ScriptHash (Versioned Script) -> ValidatorHash -> Maybe (Versioned Validator) +lookupValidator :: ScriptsMap -> ValidatorHash -> Maybe (Versioned Validator) lookupValidator txScripts = (fmap . fmap) Validator . lookupScript txScripts . toScriptHash where toScriptHash (ValidatorHash b) = ScriptHash b @@ -510,7 +514,7 @@ spentOutputs = map txInputRef . txInputs referencedOutputs :: Tx -> [TxOutRef] referencedOutputs = map txInputRef . txReferenceInputs -lookupMintingPolicy :: Map ScriptHash (Versioned Script) -> MintingPolicyHash -> Maybe (Versioned MintingPolicy) +lookupMintingPolicy :: ScriptsMap -> MintingPolicyHash -> Maybe (Versioned MintingPolicy) lookupMintingPolicy txScripts = (fmap . fmap) MintingPolicy . lookupScript txScripts . toScriptHash where toScriptHash (MintingPolicyHash b) = ScriptHash b @@ -521,7 +525,7 @@ deriving instance OpenApi.ToSchema TxInput deriving instance OpenApi.ToSchema Withdrawal deriving instance OpenApi.ToSchema Certificate -lookupStakeValidator :: Map ScriptHash (Versioned Script) -> StakeValidatorHash -> Maybe (Versioned StakeValidator) +lookupStakeValidator :: ScriptsMap -> StakeValidatorHash -> Maybe (Versioned StakeValidator) lookupStakeValidator txScripts = (fmap . fmap) StakeValidator . lookupScript txScripts . toScriptHash where toScriptHash (StakeValidatorHash b) = ScriptHash b @@ -542,10 +546,10 @@ fillTxInputWitnesses tx (TxInput outRef _inType) = case _inType of pubKeyTxInput :: TxOutRef -> TxInput pubKeyTxInput outRef = TxInput outRef TxConsumePublicKeyAddress --- | Add minting policy together with the redeemer into txMintingScripts and txScripts accordingly. Doesn't alter txMint. -addMintingPolicy :: Versioned MintingPolicy -> Redeemer -> Tx -> Tx -addMintingPolicy vvl rd tx@Tx{txMintingScripts, txScripts} = tx - {txMintingScripts = Map.insert mph rd txMintingScripts, +-- | Add minting policy together with the redeemer into txMintingWitnesses and txScripts accordingly. Doesn't alter txMint. +addMintingPolicy :: Versioned MintingPolicy -> (Redeemer, Maybe (Versioned TxOutRef)) -> Tx -> Tx +addMintingPolicy vvl rdWithRef tx@Tx{txMintingWitnesses, txScripts} = tx + {txMintingWitnesses = Map.insert mph rdWithRef txMintingWitnesses, txScripts = Map.insert (ScriptHash b) (fmap getMintingPolicy vvl) txScripts} where mph@(MintingPolicyHash b) = mintingPolicyHash vvl @@ -583,7 +587,7 @@ txSpendingRedeemers Tx{txInputs} = flip execState Map.empty $ traverse_ extract extract _ = return () txMintingRedeemers :: Tx -> Map MintingPolicyHash Redeemer -txMintingRedeemers Tx{txMintingScripts} = txMintingScripts +txMintingRedeemers Tx{txMintingWitnesses} = Map.map fst txMintingWitnesses txRewardingRedeemers :: Tx -> Map Credential Redeemer txRewardingRedeemers Tx{txWithdrawals} = flip execState Map.empty $ traverse_ f txWithdrawals where diff --git a/plutus-ledger/test/Ledger/Tx/CardanoAPISpec.hs b/plutus-ledger/test/Ledger/Tx/CardanoAPISpec.hs index 98aac71292..b8ce6e62f0 100644 --- a/plutus-ledger/test/Ledger/Tx/CardanoAPISpec.hs +++ b/plutus-ledger/test/Ledger/Tx/CardanoAPISpec.hs @@ -161,7 +161,7 @@ convertMintingTx = property $ do mpsHash = PV1.mintingPolicyHash mps vL n = Value.singleton (Value.mpsSymbol mpsHash) "L" n tx = mempty { txMint = vL 1 } - & addMintingPolicy (Versioned mps PlutusV1) unitRedeemer + & addMintingPolicy (Versioned mps PlutusV1) (unitRedeemer, Nothing) ectx = toCardanoTxBodyContent def [] tx >>= makeTransactionBody mempty case ectx of -- Check that the converted tx contains exactly one script diff --git a/plutus-use-cases/test/Spec.hs b/plutus-use-cases/test/Spec.hs index ca37e373c1..e359563f00 100644 --- a/plutus-use-cases/test/Spec.hs +++ b/plutus-use-cases/test/Spec.hs @@ -34,7 +34,7 @@ main = defaultMain tests -- You can override this number for a specific property test by using -- 'Test.Tasty.Quickcheck.withMaxSuccess'. limit :: Int -limit = 100 +limit = 50 tests :: TestTree tests = diff --git a/plutus-use-cases/test/Spec/future.pir b/plutus-use-cases/test/Spec/future.pir index aa3b1fe854..62acb64473 100644 --- a/plutus-use-cases/test/Spec/future.pir +++ b/plutus-use-cases/test/Spec/future.pir @@ -150,7 +150,10 @@ (con bytestring) (fun (con data) - (fun (con bytestring) (fun (con integer) TxConstraint)) + (fun + (con bytestring) + (fun (con integer) (fun [ Maybe TxOutRef ] TxConstraint)) + ) ) ) ) diff --git a/plutus-use-cases/test/Spec/renderGuess.txt b/plutus-use-cases/test/Spec/renderGuess.txt index c88018eb08..6e02a7131c 100644 --- a/plutus-use-cases/test/Spec/renderGuess.txt +++ b/plutus-use-cases/test/Spec/renderGuess.txt @@ -550,7 +550,7 @@ Balances Carried Forward: Ada: Lovelace: 100000000 ==== Slot #1, Tx #0 ==== -TxId: 7c640d804be92ae912ae31d806692faa924bb8b81589f475932ce98df6c287bd +TxId: 59cce8a906cb07debcd8d67f7501d2429befc1e31cf8c4519fa93200220160a9 Fee: Ada: Lovelace: 178173 Mint: - Inputs: @@ -573,7 +573,7 @@ Inputs: Outputs: ---- Output 0 ---- - Destination: Script: aff07c7a538723f95ceae8701a19922d1e27722aa73c8b5cfc63be41 + Destination: Script: b88ccc3d7f4979e08dff26423096527d0dc7e82bec20a379463b3cc4 Value: Ada: Lovelace: 8000000 @@ -624,6 +624,6 @@ Balances Carried Forward: Value: Ada: Lovelace: 100000000 - Script: aff07c7a538723f95ceae8701a19922d1e27722aa73c8b5cfc63be41 + Script: b88ccc3d7f4979e08dff26423096527d0dc7e82bec20a379463b3cc4 Value: Ada: Lovelace: 8000000 \ No newline at end of file