Enriched Daml finance Batch by wrapping a daml-finance Batch contract
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
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.
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…
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.
Thanks for the clarification @bernhard
It makes totally sense.