Sjoerd1234
Sjoerd1234

Reputation: 148

DAML: Reference and set conditions to a pre-defined list in a seperate template

I'm new to DAML and have been scratching my head over this for two solid days. In this voting system specified in "template Voting", an actor has the ability to add a voter party to a list of voters specified as "choice Add". This voters list (I presume a list) is defined as "voters : Set Party", (of which I can't seem to find the definition), and some conditions are defined in "Choice Vote" and "Choice Decide".

I'm trying to remove the "Choice Add" ability and instead pre-define all voters in a list defined in a separate template. If I understand correctly these predefined voters must be declared as a list: [Party] I created a template called "Creation" containing some variables in conjunction with a custom type called "CreationRights" containing the to be voters list which must be referenced from the voting template. However, I can't seem to refer to this list in any way. Changing the voters data type to [Party] also gives an error for "voters" in Choice Decide and Choice Vote. rendering the conditions specified unusable:

Couldn't match expected type 'Set a1' with actual type '[Party]'

How can I reference to the predefined voters (votingRight) list while still applying the condition set? Any tips are very welcome!

Code:

data CreationRights = CreationRights
  with 
    votingRight : [Party]
  deriving (Eq, Show)

template Creation
  with 
    actor       : Party
    creationId  : Text
    title       : Text
    votingRight : CreationRights
  where
    signatory actor

template Voting
  with
    actor : Party
    claim : Claim
    voters : Set Party
    voted : Set Party
    votes : [Bool]

  where
    signatory actor, voted
    observer voters

    key (actor, claim) : VotingKey
    maintainer key._1

    ---choice Add : ()
      ---with voter : Party
      ---controller actor
      ---do
        ---create this with voters = S.insert voter voters
        ---pure ()

    choice Decide : ContractId Decision
      controller actor
      do
        assertMsg "At least 60% must have voted" $ ((size voters / 100) * 60) <= length votes
        let approvals = length $ L.filter (\v -> v) votes
        let disapprovals = length $ L.filter (\v -> not v) votes
        let accept = approvals > disapprovals
        create Decision with ..

    choice Vote : ()
      with
        voter : Party
        accept : Bool
      controller voter
      do
        assertMsg "Voter not added" $ member voter voters
        assertMsg "Voter already voted" $ not $ member voter voted
        create this with voted = S.insert voter voted; votes = accept :: votes
        pure ()

template Decision
  with
    actor : Party
    claim : Claim
    voters : Set Party
    accept : Bool
  where
    signatory actor, voters

Upvotes: 1

Views: 184

Answers (1)

Recurse
Recurse

Reputation: 3585

You don't have to do any of this to create a Voting instance without using Add. Voting defines its signatories to be actor, voted, so if voted is either empty or a singleton containing the same party, then the initial Voting instance only has one signatory. That means it can be created directly by actor without further interactions. I have included a simplified demonstration of this at the end of this answer.

Given you have created an instance of the Creation, you will have a copy of your list of voters on the ledger. At that point, if you want to use that list, you will have to either exercise a choice on that contract or read that contract off the ledger. You can do the latter with fetch, fetchByKey, lookup, and lookupByKey within a choice on another contract (although you will need to provide either the key or contractId). However as this template instance represents an authority to create Voting instances, representing this authority directly as a choice on Creation is recommended.

Finally, if you change the datatype of voters from a Set to a List then you will also have to change the corresponding functions that use that parameter. So, for instance, S.insert voter voted would have to become voter :: voted or similar.

daml 1.2
module Voting where

import DA.Next.Set as S
import DA.List as L

type Claim = Text

type VotingKey = (Party, Claim)

template Voting
  with
    actor : Party
    claim : Claim
    voters : Set Party
    voted : Set Party
    votes : [Bool]

  where
    signatory actor, voted
    observer voters

    key (actor, claim) : VotingKey
    maintainer key._1

    choice Decide : ContractId Decision
      controller actor
      do
        assertMsg "At least 60% must have voted" $ ((size voters / 100) * 60) <= length votes
        let approvals = length $ L.filter identity votes
        let disapprovals = length $ L.filter not votes
        let accept = approvals > disapprovals
        create Decision with actor; claim; voters; accept

    choice Vote : ContractId Voting
      with
        voter : Party
        accept : Bool
      controller voter
      do
        assertMsg "Voter not added" $ member voter voters
        assertMsg "Voter already voted" . not $ member voter voted
        create this with voted = S.insert voter voted; votes = accept :: votes

template Decision
  with
    actor : Party
    claim : Claim
    voters : Set Party
    accept : Bool
  where
    signatory actor, voters

test = scenario do
    alice <- getParty "Alice"
    bob <- getParty "Bob"
    charlie <- getParty "Charlie"

    alice `submit` create
        Voting with
            actor = alice
            claim = "Pizza"
            voters = fromList [ alice, bob, charlie ]
            voted = empty
            votes = []

Upvotes: 2

Related Questions