How do I refer to both a contract and its ID without duplicating code?
I have a contract for a Habit, which I want to use to track how often I exercise. It looks something like this:
template Habit
with
owner : Party
name : Text
where
signatory owner
controller owner can
nonconsuming Habit_Record : ContractId Recording
with
dateCompleted : Date
do
validateRecording dateCompleted
create Recording with
habit = this
dateCompleted
Next, I need to create a recording for each day in which I exercise:
template Recording
with
habit : Habit
dateCompleted : Date
where
signatory habit.owner
However, I could easily have two habits with the same name, or I could archive one and create a new one with the same name. It’s important to me to keep a strong reference from Recording to Habit. I can do this by storing the contract ID, but I still need to store the contract data for the signatory.
template Recording
with
habitId : ContractId Habit
habit : Habit
dateCompleted : Date
where
signatory habit.owner
I have 3 issues with this:
- This feels to me like duplication. I wish I could just store one.
- There’s no way to validate (in an
ensureclause or similar) that the contract denoted by the contract ID contains the same data as myhabitfield. I need to do it in the choice constructing it. This brings me to #3. - I don’t see a way to get the contract ID of
thisin a choice. Perhaps I’m missing something. Is there any way to acquire this information, or does it need to be passed in? If I need to pass it in, why? It feels like the sort of thing the participant could figure out at this stage (similar togetTime).
So my question is: how do I store the contract ID of one contract in another without having to resort to duplication and extra validation?
Let me start with the easy one: The Contract ID of this is self.
As for 1. and 2., there is currently no way not to duplicate owner. The relation between Habit and Recording feels relational anyway, in which case I’d use contract keys:
template Habit
with
owner : Party
name : Text
where
signatory owner
key this : Habit
maintainer key.owner
controller owner can
nonconsuming Habit_Record : ContractId Recording
with
dateCompleted : Date
do
validateRecording dateCompleted
create Recording with
habit = this
dateCompleted
template Recording
with
habit : Habit
dateCompleted : Date
where
signatory habit.owner
Whenever you need to get hold of the ContractId of your habit, just use lookupByKey. Whenever you need to exercise, use exerciseByKey.
self. Of course. My brain knew that, but refused to yield the information until you wrote it down.
Keys seem like an elegant approach to this problem that mean I don’t have to think about IDs at all, which is quite nice. If the object is unique, I’m happy. I’ll give it a try, thanks!