How to avoid on-ledger contract Service migrations when an Interface contract reference needs to be updated?


Given this simple but wonderful Service:

import Daml.Finance.Interface.Account.Factory qualified as Account (F)

template MyGreatService
    operator : Party
    provider : Party
    customer : Party
    accountFactoryCid : ContractId Account.F

Say we have one MyGreatService active on-ledger and we need to fix the template implementing Account.F because there’s a bug in it :cold_sweat: . In this scenario we would not need to modify the codebase in MyGreatService because we are using Interfaces :sunglasses: . However, we would have to migrate the MyGreatService contract on-ledger because we want MyGreatService contract to reference the fixed factory, accountFactoryCid’. :disappointed:

Any ideas about how to approach a Service without having to migrate on-ledger for the scenario above?



Hello @jvelasco.intellecteu ,

if the MyGreatService instance contains a ContractId reference field that mutates, you indeed need to update that instance to point to the new instance. Otherwise, it will point to an inactive instance, which may cause issues.

In general, if the ContractId mutates frequently, it is advisable to use a contract key as a field on your MyGreatService instance instead of a ContractId reference. This way, your MyGreatService instance will not require updating every time the ContractId mutates since the key of the new contract instance remains the same.

However, in case the referred to instance changes rarely, you might consider updating the ContractId of the MyGreatService instance (maybe it could be done in the same action the referred to instance changes). An alternative approach would be to remove the ContractId field of MyGreateService , and simply pass it in as argument to the choices it is part of + adding some appropriate checks (e.g. that signatories matches).

The use of interfaces has its benefits since it allows you to avoid updating the codebase of your MyGreatService in case the implementation of the instance it refers to/makes use of changes. But in order to also not having to update the MyGreatService instance, you would either need to use a key reference or the alternative approach ^.

For the particular case of referring to an account factory Account.F instance, we believe that such instances typically should be rather stable and rarely mutate (at least our implementation has no consuming choices, and its functionality is limited). Therefore, it might be reasonable to actually let the MyGreatService refer to it by ContractId . However, we recommend to try the alternative approach of removing the ContractId field from MyGreatService , and instead pass it in to the choices where it is needed (thereby also checking that the provider is the right one).

I hope that helps.