Question about understanding the authorizations

G-d willing

I am trying to do something similar to the delegations pattern which is explained here: (The Delegation Pattern — Daml SDK 2.6.4 documentation).
I have the 2 following templates:

template Product
  with
    id: Text
    owner: Party
    responsible: Party
  where
    signatory owner, responsible

    choice ChangeResponsible : ContractId Product
      with
        newRespobsible : Party
      controller responsible
        do
          create this with responsible = newRespobsible

template RentAgreement
  with
    lessor: Party
    lessee: Party
    product: ContractId Product
  where
    signatory lessor, lessee

    choice ChangeResponsibility : ContractId Product
      controller lessor
        do
          exercise product ChangeResponsible with newRespobsible = lessee

Let’s create a script where Alice wants to rent a pen to Bob,

setup : Script ()
setup = script do

  alice <- allocateParty "alice"
  bob <- allocateParty "bob"

  pen <- submit alice do
    createCmd Product with owner = alice, responsible = alice, id ="1"

  agreementId <- submitMulti [alice, bob] [] do
    createCmd RentAgreement with
      lessor = alice
      lessee = bob
      product = pen

  submit alice do
    exerciseCmd agreementId ChangeResponsibility

  pure ()

This fails on authorization saying:

Script execution failed on commit at C1L2:63:3:
  2: create of C1L2:Product at DA.Internal.Prelude:379:26
     failed due to a missing authorization from 'bob'

Bob is a signatory on the rent agreement, so why when exercising the choice it says that it is missing?
Can I resolve it without adding another contract in the middle?

The authority of a contract signatory that’s available in a choice on a contract does not propagate to the consequences of the choice. In your example Bob’s authority is available in the ChangeResponsibility choice on the RentAgreement contract. But it does not propagate to the ChangeResponsible choice on the Product contract that is called from the ChangeResponsibility choice. In the ChangeResponsible choice on the Product contract you only have the authority of the signatories of the Product contract and of the controller of the ChangeResponsible choice.
Instead of calling ChangeResponsible choice on the Product contract, in ChangeResponsibility choice on the RentAgreement contract you could fetch the Product contract, archive it and create a new one with updated value for the responsible field.

template Product
  with
    id: Text
    owner: Party
    responsible: Party
  where
    signatory owner, responsible

template RentAgreement
  with
    lessor: Party
    lessee: Party
    productId: ContractId Product
  where
    signatory lessor, lessee

    choice ChangeResponsibility : ContractId Product
      controller lessor
        do
          product <- fetch productId
          archive productId
          create product with responsible = lessee

testRent = script do

  alice <- allocateParty "alice"
  bob <- allocateParty "bob"

  pen <- submit alice do
    createCmd Product with owner = alice, responsible = alice, id ="1"

  agreementId <- submitMulti [alice, bob] [] do
    createCmd RentAgreement with
      lessor = alice
      lessee = bob
      productId = pen

  submit alice do
    exerciseCmd agreementId ChangeResponsibility

  pure ()
1 Like

Thank you @a_putkov for your response.
Is there a way to do it without archiving and re-creating the Product contract?

@cohen.avraham
I’m not sure I understand the question. The workflow in your original example archives the Product contract (by exercising a consuming choice on it) and recreates the contract with a new value for the field named responsible. The example that I provided is no different in this sense.

Is there a way to do it without archiving and re-creating the Product contract?

To answer this question I need to understand what you’re looking to achieve here. In other words what specifically the word “it” in the question refers to.
Assuming what you’re looking to do is to mutate the state of a Product contract, there’s no way to achieve it without archiving and recreating the Product contract.
Daml contracts are immutable. The only way to simulate mutated state is to archive an existing contract and create another one in its stead with updated values for some fields.

@a_putkov, by it I mean to be able to change the responsible of the product using a choice inside the Product template.
And in the meantime, during my experiments, I succeeded to do it by adding the newRespobsible party as an additional controller to the ChangeResponsible choice.