Plutus

From Organic Design wiki
Revision as of 22:16, 8 March 2021 by Saul (talk | contribs) (Script Address and Instance)

Plutus is a language for writing smart contracts in Cardano. Plutus contracts are written in a form of Haskell.

Structure

Plutus contracts are easier to understand if you break it into smaller parts.

Imports

The contract should start by importing all the useful libraries you might use in a contract.

Datum and Redeemer Types

The contract should have Datum and redeemer types.

newtype MyDatum = MyDatum Integer deriving newtype PlutusTx.IsData
PlutusTx.makeLift ''MyDatum

newtype MyRedeemer = MyRedeemer Integer deriving newtype PlutusTx.IsData
PlutusTx.makeLift ''MyRedeemer

This looks a little strange at first, but all it is doing is defining two types called MyRedeemer and MyDatum that has a constructor that takes a single argument - an Integer. It derives from the two types newtype and PlutusTx.IsData which is nessisary so it can be converted into Plutus Core so it can be run on the chain - this is exactly what the second line does PlutusTx.makeLift.

Validator Function

A contract should have a function for validating transactions so that only when a certain criteria is met a transaction will be made to withdraw coin from the contract.


The simplest validator function might look like this:

validateSpend :: MyDatum -> MyRedeemer -> ValidatorCtx -> Bool
validateSpend _myDataValue _myRedeemerValue _ = error ()

The first line gives the definition of the types for the function that takes 3 arguments and returns a Bool. The second line is the function itself which takes the first two arguments and ignores the third because the third argument is for the Plutus Core and not of interest to us. This function just throws an error and returns the unit value. This function isn't very useful because it just throws an error and does not validate the transaction, a more useful one might check that the Datum and Redeemer values are the same (since they are both Integer).

validateSpend :: MyDatum -> MyRedeemer -> ValidatorCtx -> Bool
validateSpend (MyDatum datum) (MyRedeemer redeemer) _ = datum == redeemer

This is a very simple example, your validator function could be much more complicated.

Script Address and Instance

To interact with the contract we need a compiled version of the validator script with our data types, to do this first we will create a type for it that uses our datum and redeemer types:

data Starter
instance Scripts.ScriptType Starter where
    type instance RedeemerType Starter = MyRedeemer
    type instance DatumType Starter = MyDatum

This next part gets a little complicated - it basically uses the data type we created above and creates and instance with the compiled version of validateSpend and wraps and compiles our types.

starterInstance :: Scripts.ScriptInstance Starter
starterInstance = Scripts.validator @Starter
    $$(PlutusTx.compile [|| validateSpend ||])
    $$(PlutusTx.compile [|| wrap ||]) where
        wrap = Scripts.wrapValidator @MyDatum @MyRedeemer

The address of a contract is the hash of it's validator script, so to make any transactions from the contract we need to get this address.

contractAddress :: Address
contractAddress = Ledger.scriptAddress (Scripts.validatorScript starterInstance)

See Also