Any suggestions?
I am not sure if citizen must be part of the arguments in the ledger.exercise or not ?
It is though the key for which the following daml code is executed
The contract simply does not exist. Either it has been archived or it has never been created. How did you obtain curContractId?
The contract is not visible to you. Your contract only has citizen as the signatory and no observer afaik so only citizen can exercise a choice on the contract.
A mismatch between the template id, i.e., your contract id is for a different template. This could happen if you actually did modify your template and recompiled. In that case I recommend going through the documentation I linked above. If you make any change to your template, you get a different template with a different package id. If you want to upgrade an existing contract to the new template you need to do so explicitly by archiving the old one and creating a new one with the same data (+ any extra fields or changes you added).
If we take a look a the choice you are exercising:
The first line attempts to perform a fetch-by-key using the key of the current contract, in otherwords the contract is trying to fetch itself. The second line then tries to archive the current contract retrieved by the first line.
You are in a consuming choice. The current contract is archived before the choice runs. This is why the transaction will fail as you are trying to fetch an archived contract.
Even if you were in a post-consuming or non-consuming choice, you never need to do a fetch like this. The contents of the current contract (ie. oldCitizenRole) is always available as this; and, the contract-id of the current contract is always available as self. So the fetch was redundant.
In consuming choices (both std, and post) the contract is automatically archived if the transaction commits. So the explicit call to archive is redundant, and will result in a similar error to the fetch.
Finally, when creating new records using the with syntax, you have access to punning, so anywhere you would write (var = var) you can just drop the assignment. It makes things much less cluttered that way, especially as the fields of a contract are in scope within that contract’s choices, so you don’t even need this to refer to them, you only need it if referring to the contract record in its entirety.
I mention this last bit as with can also be used as a copy-constructor when creating records of the same type with updated contents. As this is what you are trying to do here, what you wanted is much simpler when you take advantage of these feature:
Using punning:
SetVerifiableCredentials : ContractId CitizenRole
with
newverifiablecredentials : VerifiableCredentials
do
create CitizenRole with citizen; citizendetails; operator; verifiablecredentials = newverifiablecredentials
Even simpler using copy-constructor:
SetVerifiableCredentials : ContractId CitizenRole
with
newverifiablecredentials : VerifiableCredentials
do
create this with verifiablecredentials = newverifiablecredentials