# Vesting Example

# Homework

Lecture 3, Part 7

Lecture Video

# Homework 1

Homework 1 is to implement an on-chain validator that allows a wallet to lock ADA in a contract. The contract has beneficiary addresses and a deadline. Before the deadline, only beneficiary 1 should be able to grab the ADA. But after the deadline, only beneficiary 2 should be able to grab the ADA.

Homework code

My solution

My solution uses guards to match 2 cases:

  1. Where beneficiary 1 signed and the deadline not reached
  2. Where beneficiary 2 signed and deadline reached

Otherwise, false.

I use where to define some helper expressions. signedByBeneficiary1 and 2 are modeled after signedByBeneficiary in Vesting.hs. The other expressions are taken right out of Vesting.hs with no changes necessary.

I use deadlineReached with the not function to reverse it when I want to check if the deadline has not been reached.

Here's the fixed validator:

mkValidator :: VestingDatum -> () -> ScriptContext -> Bool
mkValidator dat () ctx
  | signedByBeneficiary1 && not deadlineReached = True
  | signedByBeneficiary2 &&     deadlineReached = True
  | otherwise                                   = False
    where
      info :: TxInfo
      info = scriptContextTxInfo ctx

      signedByBeneficiary1 :: Bool
      signedByBeneficiary1 = txSignedBy info $ unPaymentPubKeyHash $ beneficiary1 dat

      signedByBeneficiary2 :: Bool
      signedByBeneficiary2 = txSignedBy info $ unPaymentPubKeyHash $ beneficiary2 dat

      deadlineReached :: Bool
      deadlineReached = contains (from $ deadline dat) $ txInfoValidRange info

# Homework 2

Homework 2 is to write a validator that parameterizes the Vesting.hs. This time the beneficiary and the datum are split into two separate parameters instead of a single data type.

Homework code

My solution

The type signature looks like this:

mkValidator :: PaymentPubKeyHash -> POSIXTime -> () -> ScriptContext -> Bool

I wrote the validator by copying from Vesting.hs and replacing dat (which was the custom data type containing both parameters) with two separate parameters beneficiary deadline.

mkValidator beneficiary deadline () ctx =

The body of the validator is the same as Vesting.hs, but with the parameters referenced directly instead of through dat.

mkValidator beneficiary deadline () ctx =
  traceIfFalse "beneficiary's signature missing" signedByBeneficiary &&
  traceIfFalse "deadline not reached" deadlineReached
    where
        info :: TxInfo
        info = scriptContextTxInfo ctx

        signedByBeneficiary :: Bool
        signedByBeneficiary = txSignedBy info $ unPaymentPubKeyHash $ beneficiary

        deadlineReached :: Bool
        deadlineReached = contains (from $ deadline) $ txInfoValidRange info

The typedValidator is copied almost exactly from Parameterized.hs. The only change is the parameters passed to Scripts.wrapValidator take into account the deadline POSIXTime parameter.

typedValidator :: PaymentPubKeyHash -> Scripts.TypedValidator Vesting
typedValidator p = Scripts.mkTypedValidator @Vesting
    ($$(PlutusTx.compile [|| mkValidator ||]) `PlutusTx.applyCode` PlutusTx.liftCode p)
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = Scripts.wrapValidator @POSIXTime @()

The validator and scrAddress are copied straight from Parameterized.hs.