# Validation Scripts

# High Level, Typed Validation Scripts

Lecture 2, Part 3

Lecture Video

Using BuiltinData works great and it's very performant. However, you can code validators with more descriptive datatypes.

# Typed.hs

Source code

Instead of writing the validator like we did in the FortyTwo example...

mkValidator :: BuiltinData -> BuiltinData -> BuiltinData -> ()
mkValidator = _ r _
  | r == Builtins.mkI 42 = ()
  | otherwise = traceError "Wrong redeemer"

We can use stronger types for each argument. Since we don't care about the datum we can just give it type (). The redeemer should be an Integer. And even though we don't care about the context, it's good practice to use ScriptContext. Finally, the validator either passes or it doesn't so Bool is a much more natural-feeling return type.

mkValidator :: () -> Integer -> ScriptContect -> Bool
mkValidator = _ r _ = traceIfFalse "Wrong redeemer" $ r == 42

Notice traceIfFalse. It takes a string and an expression. If the expression is true, it returns true. If the expression is false, it traces (logs) the string and returns false.

With high level typed validation scripts there is a little more boilerplate needed to compile.

Two new blocks are needed:

data Typed
instance Scripts.ValidatorTypes Typed where
    type instance DatumType Typed = ()
    type instance RedeemerType Typed = Integer

typedValidator :: Scripts.TypedValidator Typed
typedValidator = Scripts.mkTypedValidator @Typed
    $$(PlutusTx.compile [|| mkValidator ||])
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = Scripts.wrapValidator @() @Integer

validator and valHash need to be modified.

validator :: Validator
validator = Scripts.validatorScript typedValidator

valHash :: Ledger.ValidatorHash
valHash = Scripts.validatorHash typedValidator

scrAddress stays the same.

# fromData and toData

In the REPL, you can see how these two functions work.

Turning an integer into data uses the I constructor.

toData (42 :: Integer)
I 42

And the other way around. Notice we use Maybe because the operation can fail.

FromData (I 42) :: Maybe Integer
Just 42

It fails and returns Nothing when you try to go from a list to an integer.

FromData (List []) :: Maybe Integer
Nothing

# Custom Datatype

Source code

My commented code

With this module loaded in the REPL, we can convert the new type to Data.

import PlutusTx
import PlutuxTx.IsData.Class
toData $ MySillyRedeemer 42
Constr 0 [I 42]