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 toPlutusTx.Eq.Eq
instances. -
The LambdaBuffers'
Plutus.V1.PlutusData
instances are mapped to aPlutusTx.ToData
instance and aPlutusTx.FromData
instance. -
The opaque types in LambdaBuffers' Prelude are often mapped to the corresponding
PlutusTx
Prelude type e.g. LambdaBuffers' Prelude's opaquePrelude.Map
type is mapped toPlutusTx.AssocMap
. The full mapping can be found here -
The opaque types in LambdaBuffers'
Plutus.V1
andPlutus.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 moduleLambdaBuffers.<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.