Can a contract *automatically* create another contract?

:school: Another newbie question here!

Is there a way to define TemplateA such that when a contract of TemplateA is created, it automatically creates a contract of TemplateB? I guess it would be like a choice that automatically runs or a do block that serves as a “constructor.”

My apologies if I overlooked this in the docs. :face_with_diagonal_mouth:

Daml has no “constructor” and a create event has no consequence other than the creation of the contract itself. If you want to construct two contracts atomically you can make it part of exercising a choice on a “constructor” contract. Depending on your situation it might be some sort of “static” contract that only contains the (possibly non-consuming) logic to instantiate these two contracts atomically.

1 Like

Depending on your use case you may also want to consider embedding one template in another, like so:

template A with b : B  ...

template B ...

You must however take into account that the stakeholders are defined in A, not B.

If going that route you have to bear in mind that the b in A is not a contract of Template B but a record of type B. That can get confusing; I’m not sure I’d recommend it.

As Stefano mentioned, there is no way to enforce this.

You can have a third template with a choice that create the two templates, and thus if you go through that choice to create your contracts, both will be created at the same time atomically. But there is no way to prevent someone else from creating either of the two contracts on its own.

Another possible approach would be to have a trigger that tries to enforce “there is a B contract for every instance of A”. You’ll have to decide what to do when the rule is violated: do you archive the orphan contract, create the missing one, etc.

1 Like

This works under the assumption that you don’t need the contracts to be created atomically. It can be achieved with a trigger or with any other kind of off-ledger integration using the Ledger API.

1 Like

Yes, there’s definitely a tradeoff there. The rule approach (whether it’s implemented with a Trigger or a custom Ledger API client) has the disadvantage that it’s not atomic, but the advantage that if contracts get created “directly” (which you cannot prevent) they still get caught.

Depending on use case, you may need to have both: a choice that creates both contracts atomically and a rule that archives “orphan” ones, perhaps?

2 Likes

:slight_smile: Thank you everyone for the discussion!

Here is my attempt to illustrate the suggested approach of a “third template with a choice that creates the other two templates.”

import Daml.Script

template StudentView
  with
    teacher : Party
    student : Party
    question : Text
  where
    signatory teacher
    observer student

template TeacherView
  with
    teacher : Party
    student : Party
    question : Text
    solution : Text -- only teacher can see this
  where
    signatory teacher

template Questions
  with
    teacher : Party
  where
    signatory teacher
    nonconsuming choice Create : (ContractId TeacherView, ContractId StudentView)
      with
        student : Party
        question : Text
        solution : Text
      controller teacher
      do
        studentView <- create StudentView with teacher, student, question
        teacherView <- create TeacherView with teacher, student, question, solution
        return (teacherView, studentView)

test_create = do
  student <- allocateParty "Student"
  teacher <- allocateParty "Teacher"
  questions <- submit teacher do createCmd Questions with teacher
  submit teacher do
    exerciseCmd questions Create with student, question = "What is the answer?", solution = "42"

Does that capture the idea? Comments?

This does not tackle the problem of “orphan” contracts.

1 Like

It captures the idea, yes. Perhaps one thing you can do, if feasible, is to “embed” the StudentView as a ContractId StudentView in TeacherView, so that you have a single reference to the question. Something along these lines:

template Question
  with
    teacher : Party
    student : Party
    question : Text
  where
    signatory teacher
    observer student

template Answer
  with
    question: ContractId Question
    solution : Text -- only signatory of the question (i.e. the teacher) can see this
  where
    signatory (signatory question)

template Questions
  with
    teacher : Party
  where
    signatory teacher
    nonconsuming choice Create : ContractId Question
      with
        student : Party
        question : Text
        solution : Text
      controller teacher
      do
        questionId <- create Question with teacher, student, question
        answerId <- create Answer with questionId, solution
        return questionId
1 Like

:heart_eyes: Ha! When I was initially building my example I tried what you suggest, @stefanobaghino-da. However, I could not get it to work. I could not figure out how to get the teacher out of the other contract.

From your example, this was the skill I was missing:

signatory (signatory question) :heavy_check_mark:

I had tried this:

signatory question.teacher :x:

1 Like