Is it possible to define a template Daily
, which can only be created once per day in the sense that if Alice
creates one, Bob
no longer can, and if Bob
creates one, Alice
no longer can?
2 Answers
When asking about constraints like "one per day" in DAML, one has to think about the scope of that constraint and who guarantees it.
The simplest possible template in DAML is
template Daily
with
holder : Party
where
signatory holder
An instance of this template is only known to holder
. There is no party, or set of parties that could ensure that there is only one such contract instance between Alice
and Bob
. In certain ledger topologies, Alice
and Bob
may not even know about each other, nor is there any party that knows about both.
A set of parties that guarantees the uniqueness is needed:
template Daily
with
holder : Party
uniquenessGuarantors : [Party]
...
The uniqueness guarantors need to be able to enable or block the creation of a Daily
. In other words, they need to be signatories.
template Daily
with
holder : Party
uniquenessGuarantors : [Party]
where
signatory holder, uniquenessGuarantors
Now the easiest way to guarantee any sort of uniqueness in DAML is by using contract keys. Since we want one per day, we need a Date
field.
template Daily
with
holder : Party
uniquenessGuarantors : [Party]
date : Date
where
signatory holder, uniquenessGuarantors
key (uniquenessGuarantors, date) : ([Party], Date)
maintainer key._1
What this says is that there is a unique copy of Daily
for each key, and the guarantors in key._1
are responsible for making it so.
Finally you need a mechanism for actually creating these things, a sort of DailyFactory
provided by the guarantors. That factory can also take care of making sure that date
is always set to the current date on the ledger.
template DailyFactory
with
uniquenessGuarantors : [Party]
holder : Party
where
signatory uniquenessGuarantors
controller holder can
nonconsuming FabricateDaily
: ContractId Daily
do
now <- getTime
let date = toDateUTC now
create Daily with ..
A simple test shows how it works, with uniqueness being guaranteed by a single party Charlie
:
test_daily = scenario do
[alice, bob, charlie] <- mapA getParty ["Alice", "Bob", "Charlie"]
fAlice <- submit charlie do
create DailyFactory with
holder = alice
uniquenessGuarantors = [charlie]
fBob <- submit charlie do
create DailyFactory with
holder = bob
uniquenessGuarantors = [charlie]
-- Alice can get hold of a `Daily`
submit alice do
exercise fAlice FabricateDaily
-- Neither can create a second
submitMustFail alice do
exercise fAlice FabricateDaily
submitMustFail bob do
exercise fBob FabricateDaily
-- The next day bob can create one
pass (days 1)
submit bob do
exercise fBob FabricateDaily
-- But neither can create a second
submitMustFail alice do
exercise fAlice FabricateDaily
submitMustFail bob do
exercise fBob FabricateDaily
Note that in terms of privacy, Alice
and Bob
don't know about each other or the other's Daily
or DailyFactory
, but the uniquenessGuarantors
know all parties for which uniqueness is maintained, and know of all Daily
instances for which they guarantee uniqueness. They have to!
To run the above snippets, you need to import DA.Time
and DA.Date
.

- 960
- 5
- 7
Beware that getTime
returns UTC - and consequently the code would guarantee uniqueness, one per day, according to UTC, but not for example according to local calendar (which could be, say, Auckland NZ).

- 11
- 1