(mod
  (
    SINGLETON_STRUCT  ; (SINGLETON_MOD_HASH (SINGLETON_ID . LAUNCHER_PUZZLE_HASH))
    PROPOSAL_SELF_HASH
    PROPOSAL_MINIMUM_AMOUNT
    PROPOSAL_EXCESS_PAYOUT_PUZ_HASH  ; this is where the excess money gets paid out to
    Attendance_Required  ; this is passed in as a Truth from above
    Pass_Margin  ; this is a pass in as a Truth from above
    (announcement_source delegated_puzzle_hash announcement_args)
    (
      proposal_id
      total_votes
      yes_votes
      coin_parent
      coin_amount
    )
    conditions
  )

  (include condition_codes.clib)
  (include curry-and-treehash.clib)
  (include utility_macros.clib)
  (include *standard-cl-21*)

  (defconstant TEN_THOUSAND 10000)

  (defun-inline calculate_win_percentage (TOTAL PERCENTAGE)
    (f (divmod (* TOTAL PERCENTAGE) TEN_THOUSAND))
  )

  (defun-inline calculate_full_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash)
    (puzzle-hash-of-curried-function (f SINGLETON_STRUCT)
      inner_puzzle_hash
      (sha256tree SINGLETON_STRUCT)
    )
  )

  (defun-inline calculate_proposal_puzzle (
      PROPOSAL_SELF_HASH
      proposal_singleton_id
      proposal_yes_votes
      proposal_total_votes
      proposal_innerpuz_hash
    )
    (puzzle-hash-of-curried-function PROPOSAL_SELF_HASH
      (sha256 ONE proposal_total_votes)
      (sha256 ONE proposal_yes_votes)
      (sha256 ONE proposal_innerpuz_hash)
      (sha256 ONE proposal_singleton_id)
      (sha256 ONE PROPOSAL_SELF_HASH)
    )
  )

  (assert
    ; (= (sha256tree my_solution) announcement_args) - quex suggested this. We don't need to check it now. Can be used for future functionality.
    (> (+ coin_amount ONE) PROPOSAL_MINIMUM_AMOUNT)  ; >=
    (gte total_votes Attendance_Required)  ; TODO: we might want to change this to storing total cats and calculating like with yes votes
    (gte yes_votes (calculate_win_percentage total_votes Pass_Margin))
    (=
      announcement_source
      (calculate_coin_id
        coin_parent
        (calculate_full_puzzle_hash
          (c (f SINGLETON_STRUCT) (c proposal_id (r (r SINGLETON_STRUCT))))
          (calculate_proposal_puzzle
            PROPOSAL_SELF_HASH
            proposal_id
            yes_votes  ; this is where we validate the yes votes and total votes
            total_votes
            delegated_puzzle_hash
          )
        )
        coin_amount
      )
    )
    (c
      (list CREATE_PUZZLE_ANNOUNCEMENT proposal_id)  ; specify the proposal we're talking about
      (if (> (- coin_amount 1) 0)
          (c
            (list CREATE_COIN PROPOSAL_EXCESS_PAYOUT_PUZ_HASH (- coin_amount 1) (list (f (r SINGLETON_STRUCT))))
            conditions
          )
          conditions
      )
    )
  )
)
