Skip to content
Discussions/App Development/Enriched Daml finance Batch by wrapping a daml-finance Batch contractForum ↗

Enriched Daml finance Batch by wrapping a daml-finance Batch contract

App Development5 posts210 views2 likesLast activity Nov 2023
JV
jvelasco.intellecteuOP
Nov 2023

Hello,

We have an use case where we would like to enrich the daml-finance Batch with an aging feature. The logic is simple: if the settler tries to settle the Batch and any of the instructions have not been allocated/approved, we don’t want to fail. Instead, we want to increment an Int field age.

Our initial idea was to create a new interface AgedBatch with a extra field age in the view, and a new Settle' choice with the signature below. So in case something is wrong, a new AgedBatch with age incremented is created.

choice Settle' : Either (ContractId AgedBatch) [ContractId Holding.I]

Regarding the implementation, we basically would copy/paste from daml-finance codebase.
This would work, but we are considering a second approach.

The idea is to have a template which wraps a daml-finance Batch contract like that:

template AgedBatch
  with
    settler : Party
    age : Int
    batchCid : ContractId Batch.I
  where
    signatory settler

    choice Settle' : Either (ContractId AgedBatch) [ContractId Holding.I]
      controller settler
      do
        try
          Right <$> exercise batchCid Batch.Settle with
            actors = singleton settler
        catch
          GeneralError _msg -> Left <$> create this with counter = this.counter + 1          
          -- add more exceptions here

But the downside in the above model is that we cannot prevent the settler to settle using the wrapped batchCid instead of the choice Settle' in the enriched Batch.

Any ideas?

Thanks!
Jose Velasco

BE
bernhard
Nov 2023

Just an idea: Don’t store a ContractId Batch.I, but a Batch - the non-interface version. Then in your try, do a create and an exercise. That way you can also make AgedBatch implement the Batch.I interface and use it interchangeably with the standard Batch.

template AgedBatch
  with
    settler : Party
    age : Int
    batch : Batch
  where
    signatory settler

    interface instance Batch.I for AgedBatch where
      view = view (toInterface @Batch.I batch)
      settle s = 
        try do
          cid <- create batch
          exercise (toInterfaceContractId @Batch.I cid) s
        catch
          GeneralError _msg -> do
            create this with age = age + 1 
            return []         
          -- add more exceptions here
      cancel c = do
        cid <- create batch
        exercise (toInterfaceContractId @Batch.I cid) c

You incur a cost of one extra create, but functionally it’ll do what you want. If you don’t want to incur that, you can copy&paste the settle and cancel implementations from default Batch.

JV
jvelasco.intellecteu
Nov 2023
bernhard:
try do
  cid <- create batch
  exercise (toInterfaceContractId @Batch.I cid) s

Thanks @bernhard
I see your point but if I create a Batch and is settled immediately it will fail because the instructions associated need to be allocated/approved in a separate process. Maybe I’m missing something…

BE
bernhard
Nov 2023

Your AgedBatch takes place of the original Batch here. Because it also implements the Batch.I interface, you can use it interchangeably. The instructions would be created/allocated/approved in a separate process as with a normal Batch. The only difference here is that the Settle choice does something different: if settlement fails, it increments the age.

If this doesn’t make sense, I most likely misunderstood what you are trying to accomplish.

JV
jvelasco.intellecteu
Nov 2023

Thanks for the clarification @bernhard
It makes totally sense.

← Back to Discussions