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.