1

I want to have a minting policy that checks some conditions of another input-utxo of the transaction. Fetching all transaction inputs and iterating over them is possible using txInfoInputs (see plutus-docs). But how do I check which redeemer is handed over to these utxos?

I have the below code. It checks that there is an input utxo with a defined nft. Now I try to check that the redeemer of this storeUtxO is of type BuyTickets. How do I do this?

-- What are we doing here ? We are just checking that the transaction
-- includes a utxo-input with the defined store nft and that the redeemer
-- of the store utxo is 'BuyTickets'. We want that the store takes care
-- of validating the ticket purchase.
{-# INLINABLE mkTicketPolicy #-}
mkTicketPolicy :: Store -> () -> ScriptContext -> Bool
mkTicketPolicy st () ctx =
    traceIfFalse "store nft not found" hasStoreNft
    && traceIfFalse "wrong redeemer" hasCorrectRedeemer
  where
    let (c, t) = storeNft st -- storeNFT :: Store -> AssetClass

    storeUtxO :: TxInInfo
    storeUtxO = find
        (\i -> (valueOf (txOutValue $ txInInfoResolved $ i) c t) == 1)
        (txInfoInputs $ scriptContextTxInfo $ ctx)

    hasStoreNft :: Bool
    hasStoreNft = case storeUtxO of
        Nothing -> False
        Just _ -> True

    hasCorrectRedeemer :: Bool
    -- TODO

1 Answer 1

1

if I got you right, what you want to do is not possible. The spending transaction sends the reedemer for each UTXO the transaction wants to spend. The spending transaction is created by your offline code and the redeemers for the specific scripts send together with that transaction. The redeemer is not carried on the UTXO, so the UTXO holding the NFT does not have that information, just the datumHash (Datum).

You can use the redeemer with the script validating the NFTs UTXO, e.g. if it is allowed to spend it (as for an oracle). If the validator decline, the UTXO is not spend, which leads to a missing input for "mkTicketPolicy".

So you have to check in your "mkTicketPolicy" if the NFTs UTXO will be spend. But you cannot check out of another validator script the redeemer backwards. By submitting your transaction for your "mkTicketPolicy" validator you have to attach another constraint which triggers the validator script for the NFTs UTXO. A good example how to do that is the oracle script from the Plutus Pioneer course. I hope I could explain it in an understandable way.

Edit:

let v       = txOutValue (txOutTxOut o) <> lovelaceValueOf (oFee oracle)
                        p       = assetClassValue (oAsset oracle) $ price (lovelaces $ txOutValue $ txOutTxOut o') x
                        lookups = Constraints.otherScript (swapValidator oracle)                     <>
                                  Constraints.otherScript (oracleValidator oracle)                   <>
                                  Constraints.unspentOutputs (Map.fromList [(oref, o), (oref', o')])
                        tx      = Constraints.mustSpendScriptOutput oref  (Redeemer $ PlutusTx.toBuiltinData Use) <>
                                  Constraints.mustSpendScriptOutput oref' (Redeemer $ PlutusTx.toBuiltinData ())  <>
                                  Constraints.mustPayToOtherScript
                                    (validatorHash $ oracleValidator oracle)
                                    (Datum $ PlutusTx.toBuiltinData x)
                                    v                                                                             <>
                                  Constraints.mustPayToPubKey pkh' p
                    ledgerTx <- submitTxConstraintsWith @Swapping lookups tx
                    awaitTxConfirmed $ txId ledgerTx

This is copied from the Swap.hs of the oracle example from the pioneers course. You see that two scripts with two reedemers are part of the transaction. Maybe this clarifies a bit better.

Here is the link to the complete example: https://github.com/input-output-hk/plutus-pioneer-program/tree/main/code/week06/src/Week06/Oracle

14
  • I understand that constructing the scripts and the redeemers is done off-chain. But the transaction - to be executable and validable by a Cardano node - must (in some form) include all the scripts and their redeemers. If the transaction coming to the node includes all these information, wouldn't they be accessible by the validator scripts of the included input UTxOs? I thought the validators have access to the whole transaction.
    – Jey
    Sep 7, 2021 at 15:33
  • But I see the issue. If every validator has access to all the validator scripts, their redeemers, and the datums, then it could also run any other validator, potentially, causing an infinite loop. So I guess, it is not correct to say that the whole transaction is visible to the validator scripts.
    – Jey
    Sep 7, 2021 at 15:43
  • The whole transaction is visible, but just the transaction which is relevant for the specific UTXO. What you want to achieve is possible but not in the way you are trying it. Your first comment is correct - the transaction contains all the scripts and information validable by the cardano node - it is just split into two scripts. 1. The validator script which checks if the utxo with the NFT can be spend 2. the validator script for mkTicketPolicy which checks if the UTXO is available and additional checks. So your approach is solving 2. already, you still need to do 1.
    – sbcdn
    Sep 7, 2021 at 16:05
  • Thank you for your input. The oracle example of the Plutus Pioneer program is another use case. There, the swap validator just needs the exchange rate of the oracle. This rate is in the datum of the oracle utxo and therefore accessible to all validators. What I want to achieve is a bit different. I can shift the logic into the store, there is no problem. I was just under the impression that my way would be possible. So in conclusion, only the transaction without the scripts and redeemers is visible to the validators. Is this correct?
    – Jey
    Sep 7, 2021 at 17:02
  • I don't know what exactly you want to achieve, but what I described beside the oracle example also does not need the datum. With the example I wanted to point on the Constraints.otherScript and Constraints.mustSpendScriptOutput. This you can validate without the need of redeemer or datum. But what you say is basically correct if you see it from the view of an utxo which does not belong to the actual executed validation script so e.g. an input.
    – sbcdn
    Sep 7, 2021 at 17:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.