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