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.
(Reference: Updates — Daml SDK 2.5.5 documentation)
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