LambdaBuffers to PlutusTx

Let's take a look at how LambdaBuffers modules map into PlutusTx modules, and how LambdaBuffers type definitions map into PlutusTx type definitions.

We'll use the lbf-plutus-to-plutustx CLI tool which is just a convenient wrapper over the raw lbf CLI. One can get this tool by either loading the LambdaBuffers Nix environment that comes packaged with all the CLI tools:

$ nix develop github:mlabs-haskell/lambda-buffers#lb
$ lbf<tab>
lbf                          lbf-plutus-to-haskell        lbf-plutus-to-purescript     lbf-plutus-to-typescript     lbf-prelude-to-purescript    lbf-prelude-to-typescript
lbf-list-modules-typescript  lbf-plutus-to-plutustx       lbf-plutus-to-rust           lbf-prelude-to-haskell       lbf-prelude-to-rust

Alternatively, one can simply refer directly to the lbf-plutus-to-plutustx CLI by executing nix run github:mlabs-haskell/lambda-buffers#lbf-plutus-to-plutustx; or for a more interactive experience, one can enter the development shell nix develop github:mlabs-haskell/lambda-buffers#dev-plutus-haskell which includes the lbf-plutus-to-plutustx executable along with a version of GHC with the required package set to compile the autogenerated PlutusTx projects.

Code generation

Owing to the fact that PlutusTx is a GHC plug-in, the mapping from LambdaBuffers modules to PlutusTx modules closely mirrors the LambdaBuffers to Haskell mapping described in the Haskell chapter. The key points are as follows.

  • LambdaBuffers' data types (sums, products, and records) are mapped similarly to the Haskell backend.

  • The LambdaBuffers' Prelude.Eq instances are mapped to PlutusTx.Eq.Eq instances.

  • The LambdaBuffers' Plutus.V1.PlutusData instances are mapped to a PlutusTx.ToData instance and a PlutusTx.FromData instance.

  • The opaque types in LambdaBuffers' Prelude are often mapped to the corresponding PlutusTx Prelude type e.g. LambdaBuffers' Prelude's opaque Prelude.Map type is mapped to PlutusTx.AssocMap. The full mapping can be found here

  • The opaque types in LambdaBuffers' Plutus.V1 and Plutus.V2 modules are mapped to the obvious corresponding Plutus Ledger API types. The full mapping can be found here.

  • A LambdaBuffers module, say <lb-module>, is translated to the PlutusTx module LambdaBuffers.<lb-module>.PlutusTx

Example code generation

In the following example, we'll enter a development shell with the lbf-plutus-to-plutustx executable, create an example LambdaBuffers schema file, use the PlutusTx backend to compile it, inspect the generated code and files, and compile the autogenerated code with GHCi.

$ nix develop github:mlabs-haskell/lambda-buffers#dev-plutus-haskell
$ cat > Example.lbf
module Example

import Prelude
import Plutus.V1 (PlutusData, AssetClass)

record Example a = {
  foo : AssetClass,
  bar : a
  }

derive Eq (Example a)
derive PlutusData (Example a)

$ lbf-plutus-to-plutustx Example.lbf
Success from: /nix/store/dcwir06wiq7pd3g8dfljhfxscm8yss94-lambda-buffers-compiler-exe-lbc-0.1.0.0/bin/lbc compile --input-file .work/compiler-input.pb --output-file .work/compiler-output.pb [INFO]
Compilation OK [INFO]
Success from: /nix/store/sqqsg2jx871saxfxj2mly5g4pd6qsb64-lbg-plutustx/bin/lbg-plutustx --input .work/codegen-input.pb --output .work/codegen-output.pb --gen-dir autogen --gen-class Prelude.Eq --gen-class Plutus.V1.PlutusData '--config=/nix/store/x5f8a22dwx008wlv24xf8a6mdm65flil-codegen-configs/plutustx-prelude.json' '--config=/nix/store/x5f8a22dwx008wlv24xf8a6mdm65flil-codegen-configs/plutustx-plutus.json' Example [INFO]
Codegen OK [INFO]

$ find autogen
autogen/
autogen/LambdaBuffers
autogen/LambdaBuffers/Example
autogen/LambdaBuffers/Example/PlutusTx.hs
autogen/build.json

$ cat autogen/LambdaBuffers/Example/PlutusTx.hs

{-# LANGUAGE NoImplicitPrelude,NoPolyKinds #-}
{-# OPTIONS_GHC -fno-ignore-interface-pragmas -fno-omit-interface-pragmas -fno-specialise -fno-strictness -fobject-code #-}
module LambdaBuffers.Example.PlutusTx (Example(..)) where

import qualified LambdaBuffers.Plutus.V1.PlutusTx
import qualified LambdaBuffers.Prelude.PlutusTx
import qualified LambdaBuffers.Runtime.PlutusTx.LamVal
import qualified PlutusTx
import qualified PlutusTx.Bool
import qualified PlutusTx.Builtins
import qualified PlutusTx.Eq
import qualified PlutusTx.Maybe
import qualified PlutusTx.Prelude
import qualified Prelude


data Example a = Example { example'foo :: LambdaBuffers.Plutus.V1.PlutusTx.AssetClass
                         , example'bar :: a} deriving Prelude.Show


instance (PlutusTx.Eq.Eq a) => PlutusTx.Eq.Eq (Example a) where
  {-# INLINABLE (==) #-}
  (==) = (\x0 -> (\x1 -> (PlutusTx.Bool.&&) ((PlutusTx.Eq.==) (example'foo x0) (example'foo x1)) ((PlutusTx.Eq.==) (example'bar x0) (example'bar x1)) ) )

instance (PlutusTx.ToData a) => PlutusTx.ToData (Example a) where
  {-# INLINABLE toBuiltinData #-}
  toBuiltinData = (\x0 -> PlutusTx.Builtins.mkList ([PlutusTx.toBuiltinData (example'foo x0)
                                                     , PlutusTx.toBuiltinData (example'bar x0)]) )

instance (PlutusTx.FromData a) => PlutusTx.FromData (Example a) where
  {-# INLINABLE fromBuiltinData #-}
  fromBuiltinData = (\x0 -> LambdaBuffers.Runtime.PlutusTx.LamVal.casePlutusData ((\x1 -> (\x2 -> PlutusTx.Maybe.Nothing ) )) ((\x3 -> case x3 of
                                                                                                                                         [x4
                                                                                                                                          , x5] -> (PlutusTx.Prelude.>>=) (PlutusTx.fromBuiltinData (x4)) ((\x6 -> (PlutusTx.Prelude.>>=) (PlutusTx.fromBuiltinData (x5)) ((\x7 -> PlutusTx.Maybe.Just (Example { example'foo = x6
                                                                                                                                                                                                                                                                                                                , example'bar = x7 }) )) ))
                                                                                                                                         x8 -> PlutusTx.Maybe.Nothing )) ((\x9 -> PlutusTx.Maybe.Nothing )) ((\x10 -> PlutusTx.Maybe.Nothing )) (x0) )[10:19 PM] [jared@pletbjerg ~/Documents/Work/lambda-buffers]$

$ ghci autogen/LambdaBuffers/Example/PlutusTx.hs
...

Example project

A complete example project using the generated PlutusTx modules can be found here.