Creating your own bindings

This page gets you started with creating custom bindings for a Daml Ledger.

Bindings for a language consist of two main components:

  • Ledger API
    Client “stubs” for the programming language, – the remote API that allows sending ledger commands and receiving ledger transactions. You have to generate Ledger API from the gRPC protobuf definitions in the daml repository on GitHub. Ledger API is documented on this page: gRPC. The gRPC tutorial explains how to generate client “stubs”.
  • Codegen
    A code generator is a program that generates classes representing Daml contract templates in the language. These classes incorporate all boilerplate code for constructing: CreateCommand and ExerciseCommand corresponding for each Daml contract template.

Technically codegen is optional. You can construct the commands manually from the auto-generated Ledger API classes. However, it is very tedious and error-prone. If you are creating ad hoc bindings for a project with a few contract templates, writing a proper codegen may be overkill. On the other hand, if you have hundreds of contract templates in your project or are planning to build language bindings that you will share across multiple projects, we recommend including a codegen in your bindings. It will save you and your users time in the long run.

Note that for different reasons we chose codegen, but that is not the only option. There is really a broad category of metaprogramming features that can solve this problem just as well or even better than codegen; they are language-specific, but often much easier to maintain (i.e. no need to add a build step). Some examples are:

Building Ledger Commands

No matter what approach you take, either manually building commands or writing a codegen to do this, you need to understand how ledger commands are structured. This section demonstrates how to build create and exercise commands manually and how it can be done using contract classes generated by Scala codegen.

Create Command

Let’s recall an IOU example from the Quickstart guide, where Iou template is defined like this:

template Iou
  with
    issuer : Party
    owner : Party
    currency : Text
    amount : Decimal
    observers : [Party]

Here is how to manually build a CreateCommand for the above contract template in Scala:

  def iouCreateCommand(
      templateId: Identifier,
      issuer: String,
      owner: String,
      currency: String,
      amount: BigDecimal,
  ): Command.Create = {
    val fields = Seq(
      RecordField("issuer", Some(Value(Value.Sum.Party(issuer)))),
      RecordField("owner", Some(Value(Value.Sum.Party(owner)))),
      RecordField("currency", Some(Value(Value.Sum.Text(currency)))),
      RecordField("amount", Some(Value(Value.Sum.Numeric(amount.toString)))),
      RecordField("observers", Some(Value(Value.Sum.List(List())))),
    )
    Command.Create(
      CreateCommand(
        templateId = Some(templateId),
        createArguments = Some(Record(Some(templateId), fields)),
      )
    )
  }

If you do not specify any of the above fields or type their names or values incorrectly, or do not order them exactly as they are in the Daml template, the above code will compile but fail at run-time because you did not structure your create command correctly.

Codegen should simplify the command construction by providing auto-generated utilities to help you construct commands. For example, when you use Scala codegen to generate contract classes, a similar contract instantiation would look like this:

  val iou = M.Iou(
    issuer = issuer,
    owner = issuer,
    currency = "USD",
    amount = BigDecimal("1000.00"),
    observers = List(),
  )

Exercise Command

To build ExerciseCommand for Iou_Transfer:

    controller owner can
      Iou_Transfer : ContractId IouTransfer
        with
          newOwner : Party
        do create IouTransfer with iou = this; newOwner

manually in Scala:

  def iouTransferExerciseCommand(
      templateId: Identifier,
      contractId: String,
      newOwner: String,
  ): Command.Exercise = {
    val transferTemplateId = Identifier(
      packageId = templateId.packageId,
      moduleName = templateId.moduleName,
      entityName = "Iou_Transfer",
    )
    val fields = Seq(RecordField("newOwner", Some(Value(Value.Sum.Party(newOwner)))))
    Command.Exercise(
      ExerciseCommand(
        templateId = Some(templateId),
        contractId = contractId,
        choice = "Iou_Transfer",
        choiceArgument = Some(Value(Value.Sum.Record(Record(Some(transferTemplateId), fields)))),
      )
    )
  }

versus creating the same command using a value class generated by Scala codegen:

    exerciseCmd = iouContract.contractId.exerciseIou_Transfer(actor = issuer, newOwner = newOwner)

Summary

When creating custom bindings for Daml Ledgers, you will need to:

  • generate Ledger API from the gRPC definitions
  • decide whether to write a codegen to generate ledger commands or manually build them for all contracts defined in your Daml model.

The above examples should help you get started. If you are creating custom binding or have any questions, see the Getting Help page for how to get in touch with us.