(See code below) Should I include 'groupOfParty1 : [Party]' in the 'with' statement for Party2Invitation? Or should 'groupOfParty1: [Party] be apart of the 'AcceptParty2Invitation' choice's with statement?:

module Onboard where

template OnboardEntityMaster
with
adminParty : Party
where
signatory adminParty

controller adminParty can
  nonconsuming InviteParty1 : ContractId Party1Invitation
    with 
                                            party1 : Party
    do create Party1Invitation with ..

controller adminParty can
  nonconsuming InviteParty2 : ContractId Party2Invitation
    with 
      party2 : Party
      reason : Text
      groupOfParty1 : [Party]
    do create Party2Invitation with ..    

module Party2 where

template Party2Invitation
with
adminParty : Party
party2 : Party
reason : Text
groupOfParty1 : [Party]
where
signatory adminParty

controller party2 can
  AcceptParty2Invitation : ContractId Party2OffDuty
    with 
      party2Name : Text
    do
      create Party2OffDuty with ..

template Party2OffDuty
with
adminParty : Party
party2 : Party
party2Name : Text
groupOfParty1 : [Party]
where
signatory adminParty
signatory party2
observer groupOfParty1

controller party2 can
  PunchIn : ContractId Party2OnDuty
    do
      create Party2OnDuty with ..

controller adminParty can
  UpdateParty1OffDuty : ContractId Party2OffDuty
    with
      newGroupOfParty1 : [Party]
    do
      create this
        with
          groupOfParty1 = newGroupOfParty1

template Party2OnDuty
with
adminParty : Party
party2 : Party
party2Name : Text
groupOfParty1 : [Party]
where
signatory adminParty
signatory party2
observer groupOfParty1
key (party2, adminParty) : (Party, Party)
maintainer key._2

controller party2 can
  PunchOut : ContractId Party2OffDuty
    do
      create Party2OffDuty with ..

controller adminParty can
  UpdateParty1OnDuty : ContractId Party2OnDuty
    with
      newGroupOfParty1 : [Party]
    do
      create this
        with
          groupOfParty1 = newGroupOfParty1

– The goal is to make a group of Party1 parties be the observer for party2 parties.
– My question is: “Should I include ‘groupOfParty1 : [Party]’ in the ‘with’ statement for Party2Invitation? Or should 'groupOfParty1: [Party] be apart of the ‘AcceptParty2Invitation’ choice’s with statement?:”
– I ask this because I am unaware if the adminParty would be able to see groupOfParty1 in Onboard.daml. But my thought is that we don’t want party2 to have to reference groupOfParty1 when exercising ‘AcceptParty2Invitation’

Hi @ClarKent711,

I’m having a bit of trouble following your code, and it does not seem to be complete.

Could you perhaps take a bit of a step back and instead describe what it is you are trying to do?

Hi Gary,

Thanks for reaching out. I had to abstract out all the actual party names and rename them to adminParty, party1 & party2, so it probably is a little hard to fully understand the goal.

I have two .daml modules that I am referencing for this issue (Onboard.daml & Party2.daml).

The goal of Party 2 is to accept the invitation and be able to punch in and out.

While the goal of Party 1 is to be one of the Observers to the Party2OnDuty & Party2OffDutycontracts (hence why we have groupOfParty1 : [Party]). We want Party1 to be able to eventually query the Party2OnDuty contracts (which I have already done successfully in a different module - not necessary to this issue). But to be able to do that, you need to be an observer on those contracts.

But if groupOfParty1 is necessary for Party2OnDuty, then we need it to be apart of the Party2Invitation template. And if it needs to be apart of the Party2Invitation template in Party2.daml, then groupOfParty1 needs to be apart of the OnboardEntityMaster template’s choice InviteParty2 (see code below). My question is will the adminParty be able to successfully create Party2Invitation? Or will they have an issue with groupOfParty1 since we aren’t querying the Party1 contracts and adding them to a groupOfParty1 before creating Party2Invitation.

I may just be thinking too deeply and what I have is right, but I just wanted to double check with someone who knows Daml a little more than I do.

controller adminParty can
nonconsuming InviteParty2 : ContractId Party2Invitation
with
party2 : Party
reason : Text
groupOfParty1 : [Party]
do create Party2Invitation with …

I’m still not sure I understand what you’re trying to achieve. There seems to be some confusion around what parties and templates are and how they relate, so allow me to state how I think about them.

A party is the unit of authorization on a Daml ledger. For most parties, there is a one-to-one correspondence to an external user, but it is reasonably common for a single party to be shared by many users, or for a user to have multiple parties. This potential for n-to-n relationship allows for parties to be used as roles. For example, if you want a group of people to all have access to the exact same set of contract, one way to achieve that is to create a party that they all get readAs claims for. That way, you don’t need to add them individually as observers on the contracts, which can give you a more dynamic way to manage accesses (though one that is no longer recorded on the ledger, so there’s a tradeoff there).

This of course means that whatever system you use to generate tokens is an integral part of your Daml system and needs to know about the meaning of various parties and how they relate to users.

Templates, and by extension contracts, allow users to record data on the ledger in a structured way. Generally speaking, when writing a template, you should think of the parties involved in this template in terms of their role in this current contract. You should not think of specific parties: the entire Daml model is based on the notion that parties are not special by themselves and are instead defined by the set of contracts they have signed.

Now, given your description, here is my attempt to devise a set of templates that I think achieve something close to what you want, in case that helps answer your question.

module Main where

import Daml.Script
import qualified DA.List

template ContractProposal
  with
    hiringManager: Party
    jobId: Text
    supervisor: Party
  where
    signatory hiringManager
    observer supervisor

    nonconsuming choice AcceptContract : ContractId JobContract
      with workers: [Party]
      controller supervisor
      do
        create JobContract with owner = hiringManager
                                supervisor
                                invites = workers
                                jobId

template JobContract
  with
    owner: Party
    supervisor: Party
    invites: [Party]
    jobId: Text
  where
    signatory owner, supervisor
    observer invites
    key (owner, jobId): (Party, Text)
    maintainer key._1

    preconsuming choice AcceptInvitation : ContractId WorkLog
      with worker: Party
      controller worker
      do
        assert (worker `elem` invites)
        create this with invites = (DA.List.delete worker invites)
        create WorkLog with owner
                            supervisor
                            worker
                            log = []
                            started = None
                            jobId

data LogEntry = LogEntry with start: Time, stop: Time
  deriving (Eq, Show)

template WorkLog
  with
    owner: Party
    supervisor: Party
    worker: Party
    log: [LogEntry]
    started: Optional Time
    jobId: Text
  where
    signatory supervisor, worker
    observer owner

    preconsuming choice PunchIn : ContractId WorkLog
      controller worker
      do
        case started of
          None -> do
            now <- getTime
            create this with started = Some now
          Some _ -> fail "already punched in"
    preconsuming choice PunchOut : ContractId WorkLog
      controller worker
      do
        case started of
          None -> fail "cannot punch out if not punched in"
          Some start -> do
            now <- getTime
            create this with started = None
                             log = log <> [LogEntry start now]


setup : Script ()
setup = script do
  alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")
  bob <- allocatePartyWithHint "Bob" (PartyIdHint "Bob")
  carol <- allocatePartyWithHint "Carol" (PartyIdHint "Carol")

  prop <- submit alice do
    createCmd ContractProposal
              with jobId = "1"
                   hiringManager = alice
                   supervisor = bob
  
  contract <- submit bob do
    exerciseCmd prop AcceptContract
                     with workers = [carol]
  
  log <- submit carol do
    exerciseCmd contract AcceptInvitation with worker = carol

  log <- submit carol do
    exerciseCmd log PunchIn
  
  log <- submit carol do
    exerciseCmd log PunchOut
  
  aliceReport <- query @WorkLog alice

  debug $ show aliceReport

Hi Gary thanks for the information. It is hard for me to explain this without the actual use case being presented. After seeing exerciseCmd prop AcceptContract with workers = [carol] I realized I can do the same thing with groupOfParty1 = [party1]. I think this is what I needed, thank you.