What are Plutus Monads?

Off-chain parts do not need to worry about compilation to Plutus Core.

Off-chain code is written in Contract Monad, to deal with side effects and streaming.


EmulatorTrace Monad

  • Define actions which wallets invoke with the endpoints, parameters, waiting periods etc…


Contract Monad

newtype Contract w -- Writer monad, allows us to write log msgs
                 s -- Blockchain capabilities / actions, 
                   -- e.g. waiting for slot, submitting tx, getting wallet pubkey
                   --      containing specific endpoints
                 e -- Type of error msgs
                 = Contract { unContract :: Eff (ContractEffs w s e) a }
      deriving newtype (Functor, Applicative, Monad)

How do we use the type parameter e?

Errors can be thrown with:

Contract.throwError (errorMsg :: e)

And caught with:

import Plutus.Contract.Types (handleError)

How do we use type parameter s?

In most cases we just use s ~ BlockChainActions, but if we want support for specific endpoints, we must use a different type.

We do so using a type synonym:

type MySchema = BlockchainActions .\/ Endpoint "foo" Int

This allows us to declare an extra action: Block until endpoint foo is called:

myContract3 :: Contract () MySchema -- We use MySchema as blockchain capability type
                           Text ()
myContract3 = do
      n <- endpoint @"foo" -- new action not in `BlockchainActions`, but declared in MySchema
      Contract.logInfo n

In the emulator trace we can now do:

myTrace3 :: EmulatorTrace ()
myTrace3 = do
      h <- activateContractWallet (Wallet 1) myContract3
      callEndpoint @"foo" h 42

test3 :: IO ()
test3 = runEmulatorTraceIO myTrace3

Which calls the contract.

How do we use w?

w must be monoidic.

We can use it with observableState.