Implementing a wrapper template

I’d like to implement a template that wraps the choices of another template, where exercising a wrapped choice on the wrapper exercises the underlying choice, together with a hook that updates the wrapper.

I can write the following type-class:

class Choice t c r => WatchesChoice t c r a where
  onExercise : t -> c -> r -> a -> Update a

which lets me define the hook. Then, given the following type:

-- r is here to satisfy the coverage condition
data Watched t c r = Watched with
  id : ContractId t
  choice : c

I’d like to define the following:

instance (Template a, WatchesChoice t c r a) => HasExercise a (Watched t c r) (a, r) where
  exercise aId (Watched tId c) = do
    a <- fetch aId
    r <- Prelude.exercise tId c
    return (a, r)

This compiles, but I don’t think it’s actually usable as there’s no way to declare the controller on the choice via HasExercise, and there’s no way to satisfy the Choice constraints (which are needed to exercise this thing from a script) since I can’t, AFAIK, implement ToAnyChoice and FromAnyChoice myself.

I’m pretty sure this omission is by design, because allowing templates to be open to extension in this way would violate the principle of knowing what you’re signing.

Given that, is there any way to approximate what I want Daml today?

You can’t add new choices to a template after the fact, for the reasons you mentioned yourself. You can write your own function wrappedExercise that does what you want, but you can’t call that directly via the API.

With the Daml Interfaces under development, you may be able to write a template with a choice WrappedExercise that takes a contract id and Watched and then does the magic you want. You could call that via a createAndExercise command via the API.

It would be good to know whether that works, or where Daml Interfaces in their current state fall short for that use case.

Daml interfaces solve this general problem, as I can create a Hook interface with a onExercise : AnyChoice -> Update () choice.

However the lack of parameterization imposes a minor inconvenience in that I now have to unpack the AnyChoice at runtime, and the compiler can’t check my implementation for exhaustiveness.

Returning an arbitrary update is also potentially dangerous, but I know there’s work ongoing to figure out how to mitigate that.

However, with type-parameters you could make this safer, e.g Hook a and onExercise : AnyChoice -> Update a, so by instantiating a at a type whose visibility you control, you can limit the set of potential implementation sites.

One other nice property of the example in my first post is that I can statically mirror the choices of the underlying template if my onExercise doesn’t depend on the particular choice.

So even with interfaces, I think there’s value in having, for example, an open keyword on a template that signals that extensions are allowed. This could be implemented via a compiler-synthesized IsOpen instance that’s required to define your own HasExercise instance.

I don’t think your suggestion works. AnyChoice is not serializable. With interfaces you can write a wrapper for a specific choice but not a generic wrapper.

1 Like

In that case, creating an interface for each set of choices I care about would do the trick. For something simple like a hook that wouldn’t be too burdensome, but it would be annoying for more elaborate use-cases.