Advice on creating a mutable flag

Hi, I’m trying to use a mutable flag template (create/archived by bigUser) to control what another relatively immutable template can do (I prefer not to put the flag on TestLookup as this can happen frequently).

I want smolUser to be able to call the ChangeUserIfNoFlag function, while being permissioned by a mutable flag set by bigUser. I’m not sure which maintainer to use as visibleByKey seem to require authorization by bigUser. What’s the best way to achieve this?

module Test.TestLookup where

import Daml.Script

template LookupFlag
  with
    bigUser: Party
    smolUser: Party
    smolUserId: Text
  where   
    signatory bigUser
    observer smolUser
    key (bigUser, smolUser): (Party, Party)
    maintainer [key._1]

template TestLookup
  with
    bigUser: Party
    smolUser: Party
    smolUserId: Text
  where
    signatory smolUser
    observer bigUser
    choice ChangeUserIfNoFlag
        :  ContractId TestLookup
          with
              newSmol : Party
              newSmolId : Text
          controller smolUser
          do
            isDisabled <- visibleByKey @LookupFlag (bigUser, smolUser)
            assertMsg "Disabled by bigUser" (not isDisabled)
            create this with
              smolUser = newSmol
              smolUserId = newSmolId

testChangeLookup = do 
  big <- allocateParty "BIG"
  smol1 <- allocateParty "SMOL1"
  smol2 <- allocateParty "SMOL2"

  testLookupCid <- submit smol1 do
            createCmd TestLookup with
              bigUser = big
              smolUser = smol1
              smolUserId = "user1"
  smol2LookupCid <- submit smol1 do
          exerciseCmd testLookupCid ChangeUserIfNoFlag with 
            newSmol = smol2
            newSmolId = "user2"
  pure ()

You need to get authorization from the maintainers somehow. In your example, one option could be to get the authorization by making bigUser a signatory on the contract. For test purposes, we can create the contract via submitMulti but in a real system you probably want some propose accept or something similar.

The second issue once you fixed that is the issue on the create in ChangeUserIfNoFlag. newSmol is a signatory on the new contract so you need to get their authorization somehow. This is a relatively standard problem on transfers. Usually, you solve this by making both smolUser and newSmol controllers of the choice so they both need to agree. You could wrap it in a propose-accept to actually get that exercise but for testing purposes let’s also use submitMulti here.

That leaves us with this example:

import Daml.Script

template LookupFlag
  with
    bigUser: Party
    smolUser: Party
    smolUserId: Text
  where
    signatory bigUser
    observer smolUser
    key (bigUser, smolUser): (Party, Party)
    maintainer [key._1]

template TestLookup
  with
    bigUser: Party
    smolUser: Party
    smolUserId: Text
  where
    signatory smolUser, bigUser
    choice ChangeUserIfNoFlag
        :  ContractId TestLookup
          with
              newSmol : Party
              newSmolId : Text
          controller smolUser, newSmol
          do
            isDisabled <- visibleByKey @LookupFlag (bigUser, smolUser)
            assertMsg "Disabled by bigUser" (not isDisabled)
            create this with
              smolUser = newSmol
              smolUserId = newSmolId

testChangeLookup = do
  big <- allocateParty "BIG"
  smol1 <- allocateParty "SMOL1"
  smol2 <- allocateParty "SMOL2"

  testLookupCid <- submitMulti [smol1, big] [] do
            createCmd TestLookup with
              bigUser = big
              smolUser = smol1
              smolUserId = "user1"
  smol2LookupCid <- submitMulti [smol1, smol2] [] do
          exerciseCmd testLookupCid ChangeUserIfNoFlag with
            newSmol = smol2
            newSmolId = "user2"
  pure ()