This project can transform DasContract files into Plutus contracts running on the Cardano Blockchain.
DasContract files can be created and edited on the DasContract editor.
This generator is designed to produce human-readable code.
The project is parts of my Master's Thesis.
DasContract is a format for generating blockchain smart contracts using more intuitive tools, such as BPMN language for processes, easily defined data models, and users.
Use the data tab to create your data models. Data models are entities and enums that are later translated as records into your Plutus contract.
An entity that is marked as IsRootEntity="true"
will be the contract datum. Example with many possible situations:
<DataTypes>
<Entity Id="Root" Name="Datum" IsRootEntity="true">
<Property Id="interestingNumber" Name="interestingNumber" IsMandatory="true" PropertyType="Single" DataType="Int" />
<Property Id="interestingTimeout" Name="interestingTimeout" IsMandatory="true" PropertyType="Single" DataType="DateTime" />
<Property Id="interestingMessages" Name="interestingMessages" IsMandatory="true" PropertyType="Collection" DataType="String" />
<Property Id="prop1" Name="prop" IsMandatory="true" PropertyType="Single" DataType="Int" />
<Property Id="prop2" Name="prop" IsMandatory="true" PropertyType="Single" DataType="Uint" />
<Property Id="prop3" Name="prop" IsMandatory="true" PropertyType="Single" DataType="Bool" />
<Property Id="prop4" Name="prop" IsMandatory="true" PropertyType="Single" DataType="String" />
<Property Id="prop5" Name="prop" IsMandatory="true" PropertyType="Single" DataType="DateTime" />
<Property Id="prop6" Name="prop" IsMandatory="true" PropertyType="Single" DataType="AddressPayable" />
<Property Id="prop7" Name="prop" IsMandatory="true" PropertyType="Single" DataType="Address" />
<Property Id="prop8" Name="prop" IsMandatory="false" PropertyType="Single" DataType="Int" />
<Property Id="prop9" Name="prop" IsMandatory="false" PropertyType="Single" DataType="Uint" />
<Property Id="prop10" Name="prop" IsMandatory="false" PropertyType="Single" DataType="Bool" />
<Property Id="prop11" Name="prop" IsMandatory="false" PropertyType="Single" DataType="String" />
<Property Id="prop12" Name="prop" IsMandatory="false" PropertyType="Single" DataType="DateTime" />
<Property Id="prop13" Name="prop" IsMandatory="false" PropertyType="Single" DataType="AddressPayable" />
<Property Id="prop14" Name="prop" IsMandatory="false" PropertyType="Single" DataType="Address" />
<Property Id="prop15" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="Int" />
<Property Id="prop16" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="Uint" />
<Property Id="prop17" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="Bool" />
<Property Id="prop18" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="String" />
<Property Id="prop19" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="DateTime" />
<Property Id="prop20" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="AddressPayable" />
<Property Id="prop21" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="Address" />
<Property Id="prop22" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="Int" />
<Property Id="prop23" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="Uint" />
<Property Id="prop24" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="Bool" />
<Property Id="prop25" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="String" />
<Property Id="prop26" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="DateTime" />
<Property Id="prop27" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="AddressPayable" />
<Property Id="prop28" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="Address" />
<Property Id="prop29" Name="prop" IsMandatory="true" PropertyType="Single" DataType="Reference" ReferencedDataType="SecondEntity" />
<Property Id="prop30" Name="prop" IsMandatory="false" PropertyType="Single" DataType="Reference" ReferencedDataType="SecondEntity" />
<Property Id="prop31" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="Reference" ReferencedDataType="SecondEntity" />
<Property Id="prop32" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="Reference" ReferencedDataType="SecondEntity" />
<Property Id="prop33" Name="prop" IsMandatory="true" PropertyType="Single" DataType="Enum" ReferencedDataType="Enum1" />
<Property Id="prop34" Name="prop" IsMandatory="false" PropertyType="Single" DataType="Enum" ReferencedDataType="Enum1" />
<Property Id="prop35" Name="prop" IsMandatory="true" PropertyType="Collection" DataType="Enum" ReferencedDataType="Enum1" />
<Property Id="prop36" Name="prop" IsMandatory="false" PropertyType="Collection" DataType="Enum" ReferencedDataType="Enum1" />
<Property Id="prop37" Name="prop" IsMandatory="true" PropertyType="Dictionary" KeyType="Int" DataType="String" />
<Property Id="prop38" Name="prop" IsMandatory="true" PropertyType="Dictionary" KeyType="Int" DataType="Reference" ReferencedDataType="SecondEntity" />
<Property Id="prop39" Name="prop" IsMandatory="true" PropertyType="Dictionary" KeyType="Int" DataType="Enum" ReferencedDataType="Enum1" />
<Property Id="prop40" Name="prop" IsMandatory="false" PropertyType="Dictionary" KeyType="Int" DataType="String" />
<Property Id="prop41" Name="prop" IsMandatory="false" PropertyType="Dictionary" KeyType="Int" DataType="Reference" ReferencedDataType="SecondEntity" />
<Property Id="prop42" Name="prop" IsMandatory="false" PropertyType="Dictionary" KeyType="Int" DataType="Enum" ReferencedDataType="Enum1" />
</Entity>
<Entity Id="SecondEntity" Name="SecondEntity" IsRootEntity="false">
<Property Id="propX1" Name="prop" IsMandatory="true" PropertyType="Single" DataType="Int" />
</Entity>
<Enum Id="Enum1" Name="Enum1">
<Value>Value1</Value>
<Value>Value2</Value>
<Value>Value3</Value>
</Enum>
</DataTypes>
Property Id
is the name of the property in the Plutus contract. Property Name
is just a display name. IsMandatory=true
will make the property a Maybe
type. Data types are converted by the conversion table.
In the editors' tab Users, add appropriate roles and users. These roles and users are later assigned to user tasks (=who should sign the new transaction).
The contract process is defined using the BPMN language. There are several tools at your disposal:
- Script activities
- Call activities
- User tasks
Script activities contain a script that is able to transform a datum into a new datum. The transformation code must be marked with {-# TRANSITION #-}
pragma. The datum
keyword is at your disposal. It refers to the root entity.
Script activities run automatically after each transaction is done. They are non-transactional.
{-# TRANSITION #-}
datum {
interestingNumber = interestingNumber datum + 1
}
Call activities invoke a subprocess. When the subprocess is done, it returns back to the call activity. Subprocesses can contain more call activities. Recursive subprocesses are a possibility.
Call activities run automatically after each transaction is done. They are non-transactional.
User tasks are tasks for users to complete. They are basically forms with inputs. You have to select which users are supposed to fill and submit the form (assignee, candidate users, candidate roles).
The form is defined using an XML. Unfortunately, value binding is currently not supported. See the examples for more specifics.
User tasks are transaction types. They need a new transaction to be submitted.
The behavior is defined using a validation script. Several pragmas are available to define a rich amount of logic. They all should have datum
, param
(contracts parameter with users and roles), and val
(current value of the contract) variables available.
{-# FORM_VALIDATION #-}
- code that validates the form (off-chain and on-chain){-# EXPECTED_VALUE #-}
- how much Value is expected to be in the contract at this point{-# NEW_VALUE #-}
- how much Value is expected to be in the contract after the transaction is done{-# CONSTRAINS #-}
- additional constraints{-# TRANSITION #-}
- how the datum should be transformed – has an extraform
variable accessible
All activities can be sequential multi-instance, which means they can be executed sequentially more times than once. Unfortunately, loop collection binding is currently not supported. The dat
keyword is at your disposal (=datum) if you use an expression instead of a number for loop cardinality: ${expression}
.
User tasks can have a timeout event, which can timeout at a specified amount of time. The datum
keyword is at your disposal if you use an expression instead of a POSIXTime for setting the timeout: ${expression}
.
Lock funds for a time contract, where you lock funds and unlock them after a time.
Playground contract, where many situations and examples are presented in a playground contract.
Stick it in the Plutus convertor and have fun.
This repository provides a .NET CLI project that can do the generation, but the DasContract editor should have built in Plutus conversion soon.
If you want to convert the contract programmatically, use the DasContract.Blockchain.Plutus nuget and DasContract.Blockchain.Plutus.Data nuget. The nugets target netstandard2.1
, making them very portable. The conversion process has two steps:
// 1. Convert DasContract into PlutusContract (DasContract.Blockchain.Plutus.Data nuget)
var plutusContract = PlutusContractConvertor.Default.Convert(contract);
// 2. Convert PlutusContract into IPlutusCode (DasContract.Blockchain.Plutus nuget)
var plutusCode = PlutusContractGenerator.Default(plutusContract).Generate();
// 3. Get the Plutus code in string (DasContract.Blockchain.Plutus nuget)
var plutusCodeString1 = plutusCode.InString();
var plutusCodeString2 = plutusCode.ToString(); //alternative
Thanks to the intermediary data model PlutusContract between DasContract and the final code, you can effortlessly model the Plutus contract directly, without the DasContract format. PlutusContract is somewhat similar tho. Examples and tests of directly modelled PlutusContracts are: