content: {-# LANGUAGE DataKinds           #-}
  {-# LANGUAGE DeriveAnyClass      #-}
  {-# LANGUAGE DeriveGeneric       #-}
  {-# LANGUAGE FlexibleContexts    #-}
  {-# LANGUAGE NoImplicitPrelude   #-}
  {-# LANGUAGE OverloadedStrings   #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE TemplateHaskell     #-}
  {-# LANGUAGE TypeApplications    #-}
  {-# LANGUAGE TypeFamilies        #-}
  {-# LANGUAGE TypeOperators       #-}
  
  {-# OPTIONS_GHC -fno-warn-unused-imports #-}
  
  module Example.Vesting where
  
  import           Control.Monad        hiding (fmap)
  import           Data.Aeson           (ToJSON, FromJSON)
  import           Data.Map             as Map
  import           Data.Text            (Text)
  import           Data.Void            (Void)
  import           GHC.Generics         (Generic)
  import           Plutus.Contract
  import           PlutusTx             (Data (..))
  import qualified PlutusTx
  import           PlutusTx.Prelude     hiding (Semigroup(..), unless)
  import           Ledger               hiding (singleton)
  import           Ledger.Constraints   (TxConstraints)
  import qualified Ledger.Constraints   as Constraints
  import qualified Ledger.Typed.Scripts as Scripts
  import           Ledger.Ada           as Ada
  import           Playground.Contract  (printJson, printSchemas, ensureKnownCurrencies, stage, ToSchema)
  import           Playground.TH        (mkKnownCurrencies, mkSchemaDefinitions)
  import           Playground.Types     (KnownCurrency (..))
  import           Prelude              (IO, Semigroup (..), Show (..), String)
  import           Text.Printf          (printf)
  
  data VestingDatum = VestingDatum
      { beneficiary :: PaymentPubKeyHash
      , deadline    :: POSIXTime
      } deriving Show
  
  PlutusTx.unstableMakeIsData ''VestingDatum
  
  {-# INLINABLE mkValidator #-}
  mkValidator :: VestingDatum -> () -> ScriptContext -> Bool
  mkValidator dat () 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 dat
  
      deadlineReached :: Bool
      deadlineReached = contains (from $ deadline dat) $ txInfoValidRange info
  
  data Vesting
  instance Scripts.ValidatorTypes Vesting where
      type instance DatumType Vesting = VestingDatum
      type instance RedeemerType Vesting = ()
  
  typedValidator :: Scripts.TypedValidator Vesting
  typedValidator = Scripts.mkTypedValidator @Vesting
      $$(PlutusTx.compile [|| mkValidator ||])
      $$(PlutusTx.compile [|| wrap ||])
    where
      wrap = Scripts.wrapValidator @VestingDatum @()
  
  validator :: Validator
  validator = Scripts.validatorScript typedValidator
  
  valHash :: Ledger.ValidatorHash
  valHash = Scripts.validatorHash typedValidator
  
  scrAddress :: Ledger.Address
  scrAddress = scriptAddress validator