Idiomatic way to fetch a "public" observed Template

Hi,

Say we have an Instrument template which will be observed by a “PublicParty”.

template Instrument
  with
    id : Text
    issuer : Party
    observers : [Party]
  where
    signatory issuer
    observer observers
    key (issuer, id) : (Party, Text)
    maintainer key._1

Also let’s say that we want to fetchByKey the Instrument from another template Test like the following one:

template Test 
  with 
    a : Party
  where 
    signatory a

    -- It does not work
    nonconsuming choice TestFetchByKey1 : () 
      with instKey : (Party, Text)
      controller a
      do
        fetchByKey @Instrument instKey
        pure ()    
    
    -- It works
    nonconsuming choice TestFetchByKey2 : ()
      with 
        instKey : (Party, Text)
        actors : [Party]
      controller actors
      do
        fetchByKey @Instrument instKey
        pure ()    

    -- It works
    nonconsuming choice TestFetchByKey3 : ()
      with 
        instKey : (Party, Text)
        public : Party
      controller a, public
      do
        fetchByKey @Instrument instKey
        pure ()        

test = script do
  a <- allocateParty "A"  
  issuer <- allocateParty "Issuer"
  public <- allocateParty "PublicParty" 

  let instKey = (issuer, "123")

  instCid <- submit issuer $ createCmd Instrument with 
    id = "123"
    observers = [public]
    issuer  
  
  testCid <- submit a $ createCmd Test with a

  submitMustFail a do  -- (1)
    exerciseCmd testCid TestFetchByKey1 with instKey
  submitMultiMustFail [a] [public] do  -- (2)
    exerciseCmd testCid TestFetchByKey1 with instKey

  submitMulti [a, public] [] do 
    exerciseCmd testCid TestFetchByKey2 with 
      actors = [a, public]
      instKey

  submitMulti [public, a] [] do 
    exerciseCmd testCid TestFetchByKey3 with 
      public
      instKey

As far as I understand TestFetchByKey1 in the tests does not work because:

  • In test (1) the Instrument is not visible to party a.
  • In test (2): even though the submitter is acting as party a and reading as “PublicParty”, the authorisation only comes from the parties actingAs.

I’ve found 2 ways for fetching the Instrument, TestFetchByKey2 (not proud about that) and TestFetchByKey3 . However I’m not sure whether these approaches are idiomatic ways to fetchByKey a “public” observed template like Instrument.

I’d appreciate any input on this.
Thanks!
Jose

1 Like

Hi @jvelasco.intellecteu ,

Performing a fetchByKey requires the submitting party to be a stakeholder or have authorization from a stakeholder. That’s why only TestFetchByKey2 and TestFetchByKey3 will work.

An exerciseByKey has weaker authorization. If you add a (non-consuming) GetInstrument choice to your Instrument with a flexible controller, as shown in the example below, any party with readAs rights of a stakeholder of the contract can exercise the choice.

I hope that helps.

Johan

template Instrument
  with
    id : Text
    issuer : Party
    observers : [Party]
  where
    signatory issuer
    observer observers
    key (issuer, id) : (Party, Text)
    maintainer key._1

    nonconsuming choice GetInstrument : Instrument
      with
        actor : Party -- flexible controller
      controller actor
      do
        return this

test = script do
  a <- allocateParty "A"
  issuer <- allocateParty "Issuer"
  public <- allocateParty "PublicParty"

  let instKey = (issuer, "123")

  instCid <- submit issuer $ createCmd Instrument with
    id = "123"
    observers = [public]
    issuer

  -- Any party with readAs right of public can exercise.
  submitMulti [a] [public] do
    exerciseByKeyCmd @Instrument instKey GetInstrument with actor = a

  pure ()
1 Like

Thanks @Johan_Sjodin
I see. However I would like to fetch from the template Test. I’ve tried this but it does not work.

template Instrument
  with
    id : Text
    issuer : Party
    observers : [Party]
  where
    signatory issuer
    observer observers
    key (issuer, id) : (Party, Text)
    maintainer key._1

    nonconsuming choice GetInstrument : Instrument
      with
        actor : Party -- flexible controller
      controller actor
      do
        return this

template Test 
  with 
    a : Party
  where 
    signatory a

    -- It does not work
    nonconsuming choice TestFetchByKey4 : () 
      with instKey : (Party, Text)
      controller a
      do
        exerciseByKey @Instrument instKey GetInstrument with actor = a
        pure ()  


test = script do
  a <- allocateParty "A"
  issuer <- allocateParty "Issuer"
  public <- allocateParty "PublicParty"

  let instKey = (issuer, "123")

  instCid <- submit issuer $ createCmd Instrument with
    id = "123"
    observers = [public]
    issuer

  testCid <- submit a $ createCmd Test with a  

  submitMultiMustFail [a] [public] do 
    exerciseCmd testCid TestFetchByKey4 with 
      instKey

  pure ()

BTW, Daml docs says that exerciseByKey :

Requires authorization from the controller(s) of the choice and from at least one of the maintainers of the key. If the authorization is not given, the transaction fails.

(https://docs.daml.com/daml/reference/updates.html#exercisebykey)

Hi @jvelasco.intellecteu,

that exerciseByKey also works, you just need to use submitMulti instead of the submitMultiMustFail:

The documentation of exerciseByKey seems to be misleading (as the maintainer of the key does not authorize), I will check it with our language team.

Johan

@Johan_Sjodin you are right.
Something weird with VSCode results.

Thanks for your help!
Jose

@jvelasco.intellecteu fyi, the documentation regarding exerciseByKey will be updated to:

Use exerciseByKey to exercise a choice on a contract identified by its key (compared to exercise, which lets you exercise a contract identified by its ContractId). Just like exercise, running exerciseByKey requires visibility of the contract (either through divulgence, readAs or being a stakeholder) and authorization from the controllers of the choice.

2 Likes