0

I am trying to transact with UTxO from a script address on the pre-production testnet.

I locked the fund ok with Datum, now I get an error when trying to consume that UTxO, it seem that the script is failing. But I am not sure how to get more information on where the problem is coming from, here is the off chain plutus code.

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass        #-}
{-# LANGUAGE DeriveGeneric         #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE NoImplicitPrelude #-}


module FaucetValidatorScript
  ( FaucetParams (..)
  , validator
  ) where


import              Data.Aeson                (ToJSON, FromJSON)
import              GHC.Generics              (Generic)
import              Schema                    (ToSchema)
import              Ledger              hiding (singleton)
import              Ledger.Address
import              Ledger.Typed.Scripts
import              Ledger.Value        as Value
import              Ledger.Ada
import qualified    PlutusTx
import              PlutusTx.Prelude    hiding (Semigroup (..), unless)
import              Prelude             (Show (..))
import qualified    Prelude                   as Pr

-- Simple Faucet validator script

-- Usage:
-- Expect one utxo at each contract.
-- Take that utxo as input
-- Create a new utxo with the "change" as output

-- This contract provides an example of using Validator Parameters.

-- For now, the Datum and Redeemer are not used in contract logic
-- Transactions will still have to match the type Integer for Datum and Redeemer
-- The context matters: we want to see that the PPBLSummer2022 token is in the transaction inputs and outputs.

data FaucetParams = FaucetParams
  { accessTokenSymbol   :: !CurrencySymbol
  , accessTokenName     :: !TokenName
  , faucetTokenSymbol   :: !CurrencySymbol
  , faucetTokenName     :: !TokenName
  , withdrawalAmount    :: !Integer
  } deriving (Pr.Eq, Pr.Ord, Show, Generic, ToJSON, FromJSON, ToSchema)

PlutusTx.makeLift ''FaucetParams

{-# INLINEABLE faucetValidator #-}
faucetValidator :: FaucetParams -> Integer -> Integer -> ScriptContext -> Bool
faucetValidator faucet _ _ ctx =   traceIfFalse "Input needs PPBLSummer2022 token"    inputHasAccessToken &&
                            traceIfFalse "PPBLSummer2022 token must return to sender" outputHasAccessToken &&
                            traceIfFalse "Faucet token must be distributed to sender" outputHasFaucetToken &&
                            traceIfFalse "Must return remaining tokens to contract"   faucetContractGetsRemainingTokens &&
                            traceIfFalse "Do we need to check datum"                  checkDatumIsOk
  where
    info :: TxInfo
    info = scriptContextTxInfo ctx

    receiverPkh :: PubKeyHash
    receiverPkh = head $ txInfoSignatories info

    allTokens :: [CurrencySymbol]
    allTokens = symbols $ valueSpent info

    inputHasAccessToken :: Bool
    inputHasAccessToken = (accessTokenSymbol faucet) `elem` allTokens

    valueToReceiver :: Value
    valueToReceiver = valuePaidTo info receiverPkh

    outputHasAccessToken :: Bool
    outputHasAccessToken = (valueOf valueToReceiver (accessTokenSymbol faucet) (accessTokenName faucet)) >= 1

    outputHasFaucetToken :: Bool
    outputHasFaucetToken = (valueOf valueToReceiver (faucetTokenSymbol faucet) (faucetTokenName faucet)) >= (withdrawalAmount faucet)

    -- The UTXO input from Faucet
    ownInput :: TxOut
    ownInput = case findOwnInput ctx of
        Nothing -> traceError "faucet input missing"
        Just i  -> txInInfoResolved i

    -- The UTXO output back to Faucet
    ownOutput :: TxOut
    ownOutput = case getContinuingOutputs ctx of
        [o] -> o -- There must be exactly ONE output UTXO
        _   -> traceError "expected exactly one faucet output"

    faucetInputValue :: Value
    faucetInputValue = txOutValue ownInput

    faucetOutputValue :: Value
    faucetOutputValue = txOutValue ownOutput

    faucetContractGetsRemainingTokens :: Bool
    faucetContractGetsRemainingTokens = (valueOf faucetInputValue (faucetTokenSymbol faucet) (faucetTokenName faucet)) - (withdrawalAmount faucet) <= (valueOf faucetOutputValue (faucetTokenSymbol faucet) (faucetTokenName faucet))

    checkDatumIsOk :: Bool
    checkDatumIsOk = True

data FaucetTypes

instance ValidatorTypes FaucetTypes where
    type DatumType FaucetTypes = Integer
    type RedeemerType FaucetTypes = Integer

typedValidator :: FaucetParams -> TypedValidator FaucetTypes
typedValidator faucet =
  mkTypedValidator @FaucetTypes
    ($$(PlutusTx.compile [||faucetValidator||]) `PlutusTx.applyCode` PlutusTx.liftCode faucet)
    $$(PlutusTx.compile [||wrap||])
  where
    wrap = wrapValidator @Integer @Integer


validator :: FaucetParams -> Validator
validator = validatorScript . typedValidator

As you can see both Datum and Redeemer are given as integers, while Datum has to be exactly the one used to get the datum-hash I guess that the redeemer integer can be any? here is the transaction used to unlock it but which fails

CONTRACT_TXIN="7325518aff0270f7ef019236977baa8c301e8213a632996e0852480d5df196eb#1"
AUTH_TOKEN_TXIN="95b5308a55dd1648ea6e8f2325c0a7e307240aef1998777bb3ec860a3c32e55c#1"
FEE_TXIN="95b5308a55dd1648ea6e8f2325c0a7e307240aef1998777bb3ec860a3c32e55c#3"
COLLATERAL="95b5308a55dd1648ea6e8f2325c0a7e307240aef1998777bb3ec860a3c32e55c#2"
PLUTUS_SCRIPT_FILE=output/faucet.plutus
ASSET="fb45417ab92a155da3b31a8928c873eb9fd36c62184c736f189d334c.7467696d62616c"
AUTH_TOKEN="07fd9522f3ea6179415f8934ce0aa71b67fac6aa6024a59013bde6d8.506f72636f526f73736f466175636574546f6b656e"
TOKENS_BACK_TO_CONTRACT=267
CONTRACTADDR="addr_test1wrd5y9tudjkdcaxfy0cnuf042xlx4s9xm4xlq8pqdcyyxxsfr38fl"
DATUMHASH="db2b9e43ba6771c834279febfd091fd8cae78dec7ebe86fd9d729d3ba61e38e4"
SENDER="addr_test1vpjkdcxaxvt04vezk6r7vsdn22w40z094wggnpvvp47sy0cauqn90"

cardano-cli transaction build \
--tx-in $FEE_TXIN \
--tx-in $AUTH_TOKEN_TXIN \
--tx-in $CONTRACT_TXIN \
--tx-in-script-file $PLUTUS_SCRIPT_FILE \
--tx-in-datum-value 168 \
--tx-in-redeemer-value 21 \
--tx-in-collateral $COLLATERAL \
--tx-out $SENDER+"2000000 + 33 $ASSET" \
--tx-out $SENDER+"2000000 + 1 $AUTH_TOKEN" \
--tx-out $CONTRACTADDR+"2000000 + $TOKENS_BACK_TO_CONTRACT $ASSET" \
--tx-out-datum-hash $DATUMHASH \
--change-address $SENDER \
--protocol-params-file protocol.json \
--testnet-magic 1 \
--out-file unlock.raw
Command failed: transaction build  Error: The following scripts have execution failures:
the script for transaction input 0 (in the order of the TxIds) failed with: 
The Plutus script evaluation failed: An error has occurred:  User error:
The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'.
Script debugging logs: PT8

I would appreciate any help on understanding where the problem comes from or direction on how to debug a plutus script.

1 Answer 1

1

See here, PT8 means PlutusTx.List.head: empty list

Perhaps it's because you're using head on an empty txInfoSignatories. You must use --required-signer or --required-signer-hash flags when building the transaction to embed the required signer pubkey in txbody.

Your Answer

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

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