Must controllers be signatories?

“the controller must be a signatory”. Is that right? Because I see on many examples that the controller usually a signatory.

Thank you :slight_smile:

Observers (and any party to a contract; see below) can also be controllers on a choice in a contract.

1 Like

They don’t need to be observers either. Any party works. However, note that the submitting party must have seen that contract before (either by virtue of being a stakeholder or via divulgence, the latter being deprecated).

It is also worth noting that the controller … can syntax implicitly makes a party an observer, see What's the difference between controller first and choice first? - #2 by cocreature for details

Here is an example of exercising a choice C with controller b who is neither an observer nor a signatory:

module Main where

import Daml.Script

template T
  with
    a : Party
    b : Party
  where
    signatory a
    choice C : ()
      controller b
      do pure ()

template Auth
  with
    a : Party
    b : Party
  where
    signatory a, b
    choice ExC : ()
      with
        cid : ContractId T
      controller a
      do exercise cid C

test = do
  a <- allocateParty "a"
  b <- allocateParty "b"
  auth <- submitMulti [a, b] [] $ createCmd (Auth a b)
  cid <- submit a $ createCmd (T a b)
  submit a $ exerciseCmd auth (ExC cid)
3 Likes

You can even have a controller who is not mentioned on the contract at all using multiparty submissions and flexible controllers:

module Main where

import Daml.Script

template Product
  with
    public: Party
    supplier: Party
    name: Text
  where
    signatory supplier
    observer public
    nonconsuming choice CreateReservation : ContractId Reservation
      with customer: Party
      controller customer
      do
        create Reservation with ..

template Reservation
  with
    supplier: Party
    name: Text
    customer: Party
  where
    signatory supplier, customer

setup : Script ()
setup = script do
  alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")
  bob <- allocatePartyWithHint "Bob" (PartyIdHint "Bob")
  public <- allocatePartyWithHint "public" (PartyIdHint "public")
  p1 <- submit alice do
    createCmd Product with supplier = alice, public, name = "product"
  submitMulti [bob] [public] do
    exerciseCmd p1 CreateReservation with customer = bob
  return ()
1 Like