Make a contract visible to all parties

I have a contract I would like to make visible to all participants.

template Registration
  with 
    admin: Party
    public: Party
  where 
    signatory admin
    observer public

I have created a public party on all participants using a previous post, and I added the readAs right to all the parties that need to see this contract.
When using the navigator, those parties cannot see this contract:

users.ledger_api.acs.of_party(myUser)
res9: Seq[com.digitalasset.canton.admin.api.client.commands.LedgerApiTypeWrappers.WrappedCreatedEvent] = List()
@ users.ledger_api.users.rights.list("myUser")
res10: UserRights = UserRights(
  actAs = Set(
    "collector1::12209ef651220a793b7f0abb80ec8667af95da3dc54629e934c8f3e588916a47877a"
  ),
  readAs = Set(
    "public::12209ef651220a793b7f0abb80ec8667af95da3dc54629e934c8f3e588916a47877a"
  ),
  participantAdmin = false
)

I have two questions:

  • Is it possible to observe this public contract without adding every party as an observer ?
  • If this is possible, what should add to my code / user creation, to make this contract visible ?

Thanks

Your code seems perfectly fine here. The issue in in Navigator. The problem is that it only shows you contracts visible to the primary party of your user even if your user has readAs claims for other parties, see Navigator user login does not reflect the correct access - #2 by cocreature for more details.

That limitation doesn’t apply if you read, e.g., via the JSON API. That’s what create-daml-app does.

3 Likes

thanks for you answer.

I have a similar issue in my test scripts.

test_create_expert = script do 
    ledgerParties <- allocateParties
    -- for debugging
    expertId <- validateUserId $ toUserId "Expert"
    rights <- listUserRights expertId
    debug rights
    registrationCid <- createExpert ledgerParties.admin ledgerParties.public ledgerParties.expert 
    pure()

But I m getting a right error:

Script execution failed on commit at Test.Common:12:30:
  Attempt to fetch or exercise a contract not visible to the reading parties.
  Contract:  #0:0 (Registration:Registration)
  actAs: 'Expert'
  readAs:
  Disclosed to: 'Bank', 'Public'

Trace: 
  [CanActAs 'Expert',CanReadAs 'Public']

The user Expert is created with CanReadAs = Public right and the contract is visible to Public.

I don’t understand what’s missing. Can you help me ?
Thanks

How is createExpert defined?

createExpert: Party -> Party -> Party -> Script (ContractId ExpertAccount)
createExpert admin public expert = do
  registrationCid <- submit admin $ createCmd (Registration admin public)
  expertAccountRequestCid <- submit expert $ exerciseCmd registrationCid SubmitExpertAccountRequest with ..
  submit admin $ exerciseCmd expertAccountRequestCid $ AcceptExpertAccount

With a simpler code where I only do a fetch, it fails too

createExpert admin public expert = do
  registrationCid <- submit admin $ createCmd (Registration admin public)
  Some t <- queryContractId public registrationCid
  debug t
  result <- queryContractId expert registrationCid
  debug result

I m getting the following logs

 Registration {admin = 'Admin', public = 'Public'}
 None

I m using the code provided in create-daml-app to create users with public read access.

getOrCreateUser alias publicM = do
  userId <- validateUserId $ toUserId alias
  try
    getUser userId
  catch
    UserNotFound _ -> do
      p <- allocateParty alias
      let u = User userId (Some p)
      createUser u $ CanActAs p :: [CanReadAs public | Some public <- [publicM]]
      pure u

I think you might have gotten confused by the distinction between users and parties and their relation to each other.

Each party can only ever see contracts that are visible to it. So queryContractId expert … is never going to show contracts expert is not a stakeholder on.

Users build on top of that: Each user has the right to act/read as some parties. This is particularly useful when working with ledgers that require authorization: You give someone a token that allows them to act as a user and you can then dynamically change which parties that user is authorized to act as. However, each request is still scoped to a set of parties not a set of users. The participant then checks that your user has the right to act/read as those parties.

So in your example you need to use submitMulti [expert] [public] and queryContractId public to get contracts visible to public.

1 Like

@Meriam_Lachkar,
As an alternative to submitMulti [expert] [public] you can use submitUser expertId. submitUser is arguably preferable in test scripts for client app workflows centered around users rather than parties, as it allows to test whether user rights have been assigned correctly.

@cocreature,
Since the client app workflows in Daml 2+ are likely to be centered around users rather than parties, do you think it would be possible and useful to introduce into Daml Script queryUser, queryFilterUser, queryContractIdUser and queryContractKeyUser by analogy with submitUser?

3 Likes