Skip to content
Discussions/App Development/Features announced to be deprecated: "controller first" choice syntax, contract key uniqueness - anything else?Forum ↗

Features announced to be deprecated: "controller first" choice syntax, contract key uniqueness - anything else?

App Development24 posts650 views3 likesLast activity May 2022
GY
gyorgybalazsiOP
Mar 2022

Some features were announced to be deprecated together with the announcement of Daml 2.0. I have found two such features, is there anything else I have missed?

"Controller first" choice syntax

  • The syntax controller … can will be deprecated in favor of the choice X controller … syntax. If the deprecated syntax is used then the following warning will be shown in the IDE:
    The syntax 'controller ... can' is deprecated, it will be removed in a future version of Daml. Instead, use 'choice ... with ... controller' syntax. Note that 'choice ... with ... controller' syntax does not implicitly add the controller as an observer, so it must be added explicitly as one (or as a signatory).
daml.com

Release of Daml 2.0

Integrating Canton into Daml - introducing Canton-enabled drivers; Improvements in the developer experience to build and test distributed applications; Addition of the User Management Service; Supporting newer versions of dependencies

Contract key uniqueness

contract key uniqueness will soon be deprecated, as uniqueness can not be enforced among multiple domains. We encourage to build your models already anticipating this change.

https://docs.daml.com/canton/usermanual/contract_keys.html

I guess with the deprecation of key uniqueness, some functions like exerciseByKey (used extensively in React UI examples for Daml) will also be deprecated.

GY
gyorgybalazsi
Apr 2022

Thank you!

ST
stefanobaghino-da
May 2022

I’ve deleted my answer since it contained inaccuracies, I’ll let someone else write down an accurate answer, apologies for the confusion.

CO
cocreature
May 2022

The only deprecations I’m aware off are the controller … can syntax and the ledger identity service.

Note that both of those are deprecated not removed, you can still use them for now and migrate away from them over time.

Contract key uniqueness is not yet deprecated. In fact, it’s the only supported option atm since multi-domain Canton is not yet GA. It may still be useful to consider where you rely on contract key uniqueness to ease the migration later but for now uniqueness is the only option on GA ledgers.

GY
gyorgybalazsi
May 2022

Yes, thank you!

GY
gyorgybalazsi
May 2022

Thank you, Stefano!

NI
Nimra_Fatima
May 2022

Hey I have the same issue but didn’t understand how to fix it. could you please help me?

The syntax ‘controller … can’ is deprecated, it will be removed in a future version of Daml. Instead, use ‘choice … with … controller’ syntax. Note that ‘choice … with … controller’ syntax does not implicitly add the controller as an observer, so it must be added explicitly as one (or as a signatory).

CO
cocreature
May 2022

@Nimra_Fatima can you share the example you’re having trouble adjusting?

NI
Nimra_Fatima
May 2022

I got this error in my .daml files

The syntax ‘controller … can’ is deprecated, it will be removed in a future version of Daml. Instead, use ‘choice … with … controller’ syntax. Note that ‘choice … with … controller’ syntax does not implicitly add the controller as an observer, so it must be added explicitly as one (or as a signatory).

please help me to fix this issue

GA
Gary_Verhaegen
May 2022

Hi @Nimra_Fatima,

It’s difficult to give you more guidance than what’s already said in the error message without having access to your code. Can you share the template that produces that warning?

NI
Nimra_Fatima
May 2022

@Gary_Verhaegen

Payment.daml

module Payment where

template Payable
with
amount: Decimal
currency: Text
from: Party
to: Party
reference: Text
where
signatory from
observer to

controller from can 
  ClaimPaid: ContractId PaymentClaim 
    with 
      transactionId: Text 
    do 
      create PaymentClaim with ..

template PaymentClaim
with
amount: Decimal
currency: Text
from: Party
to: Party
reference: Text
transactionId: Text
where
signatory from

controller to can 
  Receive: ContractId Receipt 
    do 
      received <- getTime
      create Receipt 
        with ..

template Receipt
with
amount: Decimal
currency: Text
from: Party
to: Party
reference: Text
transactionId: Text
received: Time
where
signatory to, from

controller from can 
  Dismiss: () 
    do return ()

here is the code in which I got this error

GA
Gary_Verhaegen
May 2022

Hi @Nimra_Fatima,

As the error message says, the controller ... can syntax is deprecated and needs to be replaced with choice ... controller .... The two syntaxes are explained in the documentation of choices.

As a concrete example, this means replacing:

  controller from can
    ClaimPaid: ContractId PaymentClaim 
      with 
        transactionId: Text 
      do 
        create PaymentClaim with ..

which is in "controller first" form, to the equivalent "choice first" form:

  choice ClaimPaid : ContractId PaymentClaim
    with transactionId: Text
    controller from
    do
      create PaymentClaim with ..

which is the same choice but expressed with the choice keyword first.

The "choice first" form has a couple advantages:

  • It can specificy the consuming behaviour of a choice.
  • It can enable flexible controllers by having the controlling Party as an argument to the choice, as explained in this old blog post.
  • It’s not deprecated.

Importantly, while not all "choice first" choices can be translated to controller first" form, all "controller first" choices can easily be transformed to "choice first" by basically moving the controller X words a couple lines down, with the minor exception that when the controller was neither a signatory nor an observer, it needs to be manually added to the observers.

NI
Nimra_Fatima
May 2022

@Gary_Verhaegen Thank you so much Sir

NI
Nimra_Fatima
May 2022

Hey @Gary_Verhaegen
can you tell me how to add controller keyword in nonconsuming choice

controller issuer can 
  nonconsuming MintToken: ContractId Token 
    with 
      description: Text 
      initialPrice: Decimal 
      currency: Text 
      royaltyRate: Decimal 
      thumbnail: Thumbnail
    do 
      issued <- getTime
      create Token
        with 
          lastPrice = initialPrice
          owner = issuer
          ..
A_
a_putkov
May 2022
Nimra_Fatima:
controller issuer can 
  nonconsuming MintToken: ContractId Token 
    with 
      description: Text 
      initialPrice: Decimal 
      currency: Text 
      royaltyRate: Decimal 
      thumbnail: Thumbnail
    do 
      issued <- getTime
      create Token
        with 
          lastPrice = initialPrice
          owner = issuer
          ..

@Nimra_Fatima
Here you go

    nonconsuming choice MintToken: ContractId Token 
       with 
         description: Text 
         InitialPrice: Decimal 
         currency: Text 
         royaltyRate: Decimal 
         thumbnail: Thumbnail
      controller issuer
      do 
         issued <- getTime
         create Token
           with 
             lastPrice = initialPrice
             owner = issuer
             ..
NI
Nimra_Fatima
May 2022

@a_putkov I have already tried this but when I write controller then it gives me the error

nonconsuming choice MintToken: ContractId Token   
    with
      description: Text
      initialPrice: Decimal
      currency: Text
      royaltyRate: Decimal
    
    controller issuer
    do
      issued <- getTime
      create Token
        with
          lastPrice = initialPrice
          owner = issuer
          .. 

error: /home/nimra/private-nft/nft/daml/UserAdmin.daml:27:9: error:
parse error on input ‘controller’parser

CO
cocreature
May 2022

@Nimra_Fatima can you share the full file please?

GA
Gary_Verhaegen
May 2022

That looks like it should work, but as @cocreature implied, it may depend on the rest of the file, particularly the overall indentation.

NI
Nimra_Fatima
May 2022

@cocreature here is the code

module UserAdmin where

import Token
import Payment

template Issuer
with
userAdmin: Party
issuer: Party
where
signatory userAdmin
ensure userAdmin /= issuer

  nonconsuming choice MintToken: ContractId Token 
    with 
      description: Text 
      initialPrice: Decimal 
      currency: Text 
      royaltyRate: Decimal 
      thumbnail: Thumbnail
        
    controller issuer 
    do 
      issued <- getTime
      create Token
        with 
          lastPrice = initialPrice
          owner = issuer
          ..

controller userAdmin can 
  RevokeIssuer: () 
    do return ()

template IssuerRequest
with
userAdmin: Party
issuer: Party
reason: Text
where
signatory issuer

key (userAdmin, issuer): (Party, Party)
maintainer key._2

controller userAdmin can 
  GrantIssuerRights: ContractId Issuer 
    do 
      create Issuer with ..

  RejectIssuerRequest: () 
    do return ()

template Owner
with
userAdmin: Party
owner: Party
where
signatory userAdmin
ensure userAdmin /= owner

key (userAdmin, owner): (Party, Party)
maintainer key._1

controller owner can 
  nonconsuming AcceptTokenAsNewOwner: (ContractId Token, ContractId Payable, Optional (ContractId Payable))
    with 
      offerId: ContractId TokenOffer 
    do 
      exercise offerId AcceptToken 

  nonconsuming AcceptTokenByKey: (ContractId Token, ContractId Payable, Optional (ContractId Payable))
    with 
      issuer: Party 
      currentOwner: Party 
      description: Text 
    do 
      exerciseByKey @TokenOffer (issuer, currentOwner, description) AcceptToken

controller userAdmin can 
  RevokeOwnerRights: () 
    do return ()

template OwnerRequest
with
userAdmin: Party
owner: Party
reason: Text
where
signatory owner

key (userAdmin, owner): (Party, Party)
maintainer key._2

controller userAdmin can 
  GrantOwnerRights: ContractId Owner 
    do 
      create Owner with ..

  RejectOwnerRequest: () 
    do return ()
CO
cocreature
May 2022

Please post this as a code block by wrapping it in triple backticks

```
yourcodehere
```

Otherwise the indentation gets messed up which makes it hard to find issues related to that.

A_
a_putkov
May 2022

@Nimra_Fatima
I’m guessing you’re missing indentation for the choice RevokeIssuer in the Issuer template (and/or possibly elsewhere). I get similar error to the one you mentioned (error: parse error on input ‘controller’) for example if I make the choice RevokeIssuer of the Issuer template insufficiently indented (e.g. if I place it on the same indentation level with the “where” keyword). Choice declarations and bodies are part of a template body and therefore must be indented from the “where” keyword, which declares the template body.
If my guess is incorrect, then please, as @cocreature suggested, post your code in a preformatted text block by wrapping it with triple backticks on both ends. Alternatively you can upload the Daml file for your module in your post.

NI
Nimra_Fatima
May 2022
module UserAdmin where

import Token
import Payment

template Issuer 
with
userAdmin: Party
issuer: Party
where
signatory userAdmin

nonconsuming choice MintToken: ContractId Token   
    with
      description: Text
      initialPrice: Decimal
      currency: Text
      royaltyRate: Decimal
    
    
    controller issuer

    do
      issued <- getTime
      create Token
        with
          lastPrice = initialPrice
          owner = issuer
          ..  
choice   

  RevokeIssuer: ()

  controller userAdmin
    do return ()
template IssuerRequest
with
userAdmin: Party
issuer: Party
reason: Text

where
signatory issuer

choice  
  GrantIssuerRights: ContractId Issuer

  controller userAdmin
    do 
      create Issuer with ..  
  
  RejectIssuerRequest: ()

    do return()
template Owner
with

 userAdmin: Party
 owner: Party
where
signatory userAdmin

  nonconsuming choice AcceptTokenAsNewOwner: (ContractId Token, ContractId Payable, ContractId Payable)
    with
      offerId: ContractId TokenOffer  
    controller owner 
    do
      exercise offerId AcceptToken   

  nonconsuming AcceptTokenByKey: (ContractId Token, ContractId Payable, ContractId Payable) 
    with                
      issuer: Party
      currentOwner: Party  
      description: Text
    do
      exerciseByKey @TokenOffer (issuer, currentOwner, description) AcceptToken  

controller userAdmin can
  RevokeOwnerRights: ()
    do return()
template OwnerRequest
with
userAdmin: Party
owner: Party
reason: Text
where
signatory owner

choice
  GrantOwnerRights: ContractId Owner

  controller userAdmin
    do
      create Owner with ..

  RejectOwnerRequest: ()
    do return()

it shows me the error of RejectIssuerRequest() in IssuerRequest Template

CO
cocreature
May 2022

There are a few issues in there:

  1. The indentation still seems messed up. I suspect this is probably breaking during copy paste somewhere and your actual code is fine in that regard.
  2. RejectIssuerRequest is missing the controller.
  3. AcceptTokenByKeyis missing the choice keyword and the controller.
  4. RevokeOwnerRights still uses controller … can.
  5. RejectOwnerRequest is missing the choice keyword and the controller.

Here is the fixed up version

module UserAdmin where

import Token
import Payment

template Issuer
  with
    userAdmin: Party
    issuer: Party
  where
  signatory userAdmin

  nonconsuming choice MintToken: ContractId Token
    with
      description: Text
      initialPrice: Decimal
      currency: Text
      royaltyRate: Decimal


    controller issuer

    do
      issued <- getTime
      create Token
        with
          lastPrice = initialPrice
          owner = issuer
          ..
  choice RevokeIssuer: ()
    controller userAdmin
    do return ()

template IssuerRequest
  with
    userAdmin: Party
    issuer: Party
    reason: Text
  where
    signatory issuer
    choice GrantIssuerRights: ContractId Issuer
      controller userAdmin
      do create Issuer with ..

    choice RejectIssuerRequest: ()
      controller userAdmin
      do return ()

template Owner
  with
    userAdmin: Party
    owner: Party
  where
    signatory userAdmin
    nonconsuming choice AcceptTokenAsNewOwner: (ContractId Token, ContractId Payable, ContractId Payable)
      with
        offerId: ContractId TokenOffer
      controller owner
      do exercise offerId AcceptToken

    nonconsuming choice AcceptTokenByKey: (ContractId Token, ContractId Payable, ContractId Payable)
      with
        issuer: Party
        currentOwner: Party
        description: Text
      controller owner
      do exerciseByKey @TokenOffer (issuer, currentOwner, description) AcceptToken

    choice RevokeOwnerRights : ()
      controller userAdmin
      do return ()

template OwnerRequest
  with
    userAdmin: Party
    owner: Party
    reason: Text
  where
    signatory owner

    choice GrantOwnerRights: ContractId Owner
      controller userAdmin
      do create Owner with ..

    choice RejectOwnerRequest: ()
      controller owner
      do return()
NI
Nimra_Fatima
May 2022

@cocreature
@a_putkov
@Gary_Verhaegen
thank you so much

← Back to Discussions