Why do we need explicit authorization when multiple act as?

Consider

template Asset with
    issuer : Party
    owner  : Party
    name   : Text
  where
    signatory issuer
    observer owner

    choice Transfer : ContractId TransferedAsset
      with
        newOwner : Party
      controller owner
      -- need both in order to succeed
      -- controller owner, newOwner  
      do
        create TransferedAsset with
          owner = newOwner
          previousOwner = owner
          ..

template TransferedAsset with
    owner  : Party
    previousOwner : Party
    name   : Text
  where
    signatory owner, previousOwner

setup : Script ()
setup = do
  alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")
  bob <- allocatePartyWithHint "Bob" (PartyIdHint "Bob")

  aliceTV <- submit alice do
    createCmd Asset with
      issuer = alice
      owner = alice
      name = "TV"

  bobTV <- submitMulti [alice, bob] [] do
    exerciseCmd aliceTV Transfer with
      newOwner = bob

  pure ()

I was playing around with some transfer logic and out of laziness used a submitMulti to avoid writing a propose & accept, but to my surprise I needed to add explicit authorization for both parties by adding the second non-signatory to the controller field. Does being a controller explicitly narrow authorization within the choice body?

According to Daml Authorization Rules,

In a Daml ledger, a party can authorize a subaction of a commit in either of the following ways:

  • Every top-level action of the commit is authorized by all requesters of the commit.
  • Every consequence of an exercise action act on a contract c is authorized by all signatories of c and all actors of act.

The way I read this is that the requesters of the commit containing an exercise action do not authorize consequences of this exercise. Applying this to your example, Bob, who authorizes the exercise of the Transfer choice on aliceTV through submitMulti, does not authorize the creation of TransferAsset contract as a consequence of exercising the Transfer choice on aliceTV. To obtain Bob’s authorization for the consequences of the Transfer choice Bob must be either a signatory on the Asset contract or a controller on the Transfer choice.

Don’t we have bob’s authorization when we:

submitMulti [alice, bob] [] do ...

The definition of act_as under Commands says

Set of parties on whose behalf the command should be executed. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to act on behalf of each of the given parties. This field supersedes the party field. The effective set of parties on whose behalf the command should be executed is the union of all parties listed in party and act_as, which must be non-empty. Each element must be a valid PartyIdString (as described in value.proto). Optional

I expected us to act under the authorization of alice and bob.

The way I read the documentation, we do have both Alice’s and Bob’s authorization for the top level action (the exercise of Transfer choice). But not for the consequences of this action (the creation of TransferedAsset contract). For the latter we only have authorization from the signatories of the Asset contract and the controllers of the Transfer choice.

1 Like

Thanks that makes sense.