Hello,
We have a need for a template that satisfies the following constraints:
- There should be at most one
Child
contract per parent contract
- Which
Child
contract has multiples values that should be unique across all Child
contracts
We’re currently working with something like the following
template Child
with
uniqueValueA: Text
uniqueValueB: Text
parentKey: Text
agent : Party
where
signatory agent
key (agent, parentKey) : (Party, Text)
maintainer key._1
As you can see, the first constraint is satified by key
but we’re stumped on how to implement the second.
Does anyone have any guidance on how we can implement a solution for this?
I see a couple of possible approaches.
- Delegate the uniqueness check to the client application.
In your client application before submitting a command to create a Child contract you could query the ledger for all Child contracts visible to the agent party and check the values of uniqueValueA and uniqueValueB fields in the new contract being created against the values of the same fields in the contracts already on the ledger. This does not make it impossible to create Child contracts on the ledger with non-unique values of uniqueValueA and uniqueValueB fields. E.g. if you have two instances of the client application using credentials that allow them to act as the agent party, those instances could simultaneously submit the command to create a Child contract with the same value for uniqueValueA field. Both of these commands would succeed. You could possibly address this scenario by implementing ODS and checking the uniqueness of the fields values against it rather than against the ledger. But in general this approach is only viable if you can ensure that no client app that can act as the agent party is creating contracts with non unique values.
- If you’re looking for the ledger to guarantee the uniqueness of the values in these fields in the Child contracts, I don’t think you can do this with a single signatory contract. You would need another template to store the list of values of uniqueValueA and uniqueValueB fields in Child contracts on the ledger, with a choice to create a new Child contract, where you can implement the uniqueness check for the fields values. And you would need another party as a signatory on the Child template to ensure that this contract can only be created by exercising a choice on the other template. Here’s a quick example. Since the Child template has two signatories, the authority of both agent and ombudsmen parties is required to create or archive the Child contract. Therefore the agent party can only create the Child contract by exercising the Add_Child choice on the Kindergarten contract, and in this choice we can perform the uniqueness check for uniqueValueA and uniqueValueB fields.
template Child
with
uniqueValueA: Text
uniqueValueB: Text
parentKey: Text
agent : Party
ombudsman : Party
where
signatory agent, ombudsman
key (agent, parentKey) : (Party, Text)
maintainer key._1
ensure agent /= ombudsman
template Kindergarten
with
principal : Party
agent : Party
uniqueValASet : Set Text
uniqueValBSet : Set Text
where
signatory principal
observer agent
key (principal, agent) : (Party, Party)
maintainer key._1
choice Add_Child : ContractId Child
with
uniqueValueA : Text
uniqueValueB : Text
parentKey : Text
controller agent
do
assertMsg "The value of uniqueValueA is not unique" $
Set.notMember uniqueValueA uniqueValASet
assertMsg "The value of uniqueValueB is not unique" $
Set.notMember uniqueValueB uniqueValBSet
create this with
uniqueValASet = Set.insert uniqueValueA uniqueValASet
uniqueValBSet = Set.insert uniqueValueB uniqueValBSet
create Child with
ombudsman = principal
..
choice Remove_Child : ()
with
childCid : ContractId Child
controller agent
do
child <- fetch childCid
create this with
uniqueValASet = Set.delete child.uniqueValueA uniqueValASet
uniqueValBSet = Set.delete child.uniqueValueB uniqueValBSet
archive childCid
1 Like
That’s very helpful! Thank you very much.