// Auto-generated Rust file with loaded Chiklisp constants
// This file was created from running generate_chiklisp_constants.py

use hex_literal::hex;

/// ```text
/// ; Coins locked with this puzzle are spendable cats.
/// ;
/// ; Choose a list of n inputs (n>=1), I_1, ... I_n with amounts A_1, ... A_n.
/// ;
/// ; We put them in a ring, so "previous" and "next" have intuitive k-1 and k+1 semantics,
/// ; wrapping so {n} and 0 are the same, ie. all indices are mod n.
/// ;
/// ; Each coin creates 0 or more coins with total output value O_k.
/// ; Let D_k = the "debt" O_k - A_k contribution of coin I_k, ie. how much debt this input accumulates.
/// ; Some coins may spend more than they contribute and some may spend less, ie. D_k need
/// ; not be zero. That's okay. It's enough for the total of all D_k in the ring to be 0.
/// ;
/// ; A coin can calculate its own D_k since it can verify A_k (it's hashed into the coin id)
/// ; and it can sum up `CREATE_COIN` conditions for O_k.
/// ;
/// ; Defines a "subtotal of debts" S_k for each coin as follows:
/// ;
/// ; S_1 = 0
/// ; S_k = S_{k-1} + D_{k-1}
/// ;
/// ; Here's the main trick that shows the ring sums to 0.
/// ; You can prove by induction that S_{k+1} = D_1 + D_2 + ... + D_k.
/// ; But it's a ring, so S_{n+1} is also S_1, which is 0. So D_1 + D_2 + ... + D_k = 0.
/// ; So the total debts must be 0, ie. no coins are created or destroyed.
/// ;
/// ; Each coin's solution includes I_{k-1}, I_k, and I_{k+1} along with proofs that I_{k}, and I_{k+1} are CATs of the same type.
/// ; Each coin's solution includes S_{k-1}. It calculates D_k = O_k - A_k, and then S_k = S_{k-1} + D_{k-1}
/// ;
/// ; Announcements are used to ensure that each S_k follows the pattern is valid.
/// ; Announcements automatically commit to their own coin id.
/// ; Coin I_k creates an announcement that further commits to I_{k-1} and S_{k-1}.
/// ;
/// ; Coin I_k gets a proof that I_{k+1} is a cat, so it knows it must also create an announcement
/// ; when spent. It checks that I_{k+1} creates an announcement committing to I_k and S_k.
/// ;
/// ; So S_{k+1} is correct iff S_k is correct.
/// ;
/// ; Coins also receive proofs that their neighbours are CATs, ensuring the announcements aren't forgeries.
/// ; Inner puzzles and the CAT layer prepend `CREATE_COIN_ANNOUNCEMENT` with different prefixes to avoid forgeries.
/// ; Ring announcements use 0xcb, and inner puzzles are given 0xca
/// ;
/// ; In summary, I_k generates a coin_announcement Y_k ("Y" for "yell") as follows:
/// ;
/// ;  Y_k: hash of I_k (automatically), I_{k-1}, S_k
/// ;
/// ; Each coin creates an assert_coin_announcement to ensure that the next coin's announcement is as expected:
/// ;  Y_{k+1} : hash of I_{k+1}, I_k, S_{k+1}
/// ;
/// ; TLDR:
/// ;  I_k : coins
/// ;  A_k : amount coin k contributes
/// ;  O_k : amount coin k spend
/// ;  D_k : difference/delta that coin k incurs (A - O)
/// ;  S_k : subtotal of debts D_1 + D_2 ... + D_k
/// ;  Y_k : announcements created by coin k committing to I_{k-1}, I_k, S_k
/// ;
/// ; All conditions go through a "transformer" that looks for CREATE_COIN conditions
/// ; generated by the inner solution, and wraps the puzzle hash ensuring the output is a cat.
/// ;
/// ; Three output conditions are prepended to the list of conditions for each I_k:
/// ;  (ASSERT_MY_ID I_k) to ensure that the passed in value for I_k is correct
/// ;  (CREATE_COIN_ANNOUNCEMENT I_{k-1} S_k) to create this coin's announcement
/// ;  (ASSERT_COIN_ANNOUNCEMENT hashed_announcement(Y_{k+1})) to ensure the next coin really is next and
/// ;     the relative values of S_k and S_{k+1} are correct
/// ;
/// ; This is all we need to do to ensure cats exactly balance in the inputs and outputs.
/// ;
/// ; Proof:
/// ;   Consider n, k, I_k values, O_k values, S_k and A_k as above.
/// ;   For the (CREATE_COIN_ANNOUNCEMENT Y_{k+1}) (created by the next coin)
/// ;   and (ASSERT_COIN_ANNOUNCEMENT hashed(Y_{k+1})) to match,
/// ;   we see that I_k can ensure that is has the correct value for S_{k+1}.
/// ;
/// ;   By induction, we see that S_{m+1} = sum(i, 1, m) [O_i - A_i] = sum(i, 1, m) O_i - sum(i, 1, m) A_i
/// ;   So S_{n+1} = sum(i, 1, n) O_i - sum(i, 1, n) A_i. But S_{n+1} is actually S_1 = 0,
/// ;   so thus sum(i, 1, n) O_i = sum (i, 1, n) A_i, ie. output total equals input total.
///
/// ;; GLOSSARY:
/// ;;  MOD_HASH: this code's sha256 tree hash
/// ;;  TAIL_PROGRAM_HASH: the program that determines if a coin can mint new cats, burn cats, and check if its lineage is valid if its parent is not a CAT
/// ;;  INNER_PUZZLE: an independent puzzle protecting the coins. Solutions to this puzzle are expected to generate `AGG_SIG` conditions and possibly `CREATE_COIN` conditions.
/// ;; ---- items above are curried into the puzzle hash ----
/// ;;  inner_puzzle_solution: the solution to the inner puzzle
/// ;;  prev_coin_id: the id for the previous coin
/// ;;  tail_program_reveal: reveal of TAIL_PROGRAM_HASH required to run the program if desired
/// ;;  tail_solution: optional solution passed into tail_program
/// ;;  lineage_proof: optional proof that our coin's parent is a CAT
/// ;;  this_coin_info: (parent_id puzzle_hash amount)
/// ;;  next_coin_proof: (parent_id inner_puzzle_hash amount)
/// ;;  prev_subtotal: the subtotal between prev-coin and this-coin
/// ;;  extra_delta: an amount that is added to our delta and checked by the TAIL program
/// ;;
///
/// (mod (
///     MOD_HASH  ;; curried into puzzle
///     TAIL_PROGRAM_HASH  ;; curried into puzzle
///     INNER_PUZZLE  ;; curried into puzzle
///     inner_puzzle_solution  ;; if invalid, INNER_PUZZLE will fail
///     lineage_proof  ;; This is the parent's coin info, used to check if the parent was a CAT. Optional if using tail_program.
///     prev_coin_id  ;; used in this coin's announcement, prev_coin ASSERT_COIN_ANNOUNCEMENT will fail if wrong
///     this_coin_info  ;; verified with ASSERT_MY_COIN_ID
///     next_coin_proof  ;; used to generate ASSERT_COIN_ANNOUNCEMENT
///     prev_subtotal  ;; included in announcement, prev_coin ASSERT_COIN_ANNOUNCEMENT will fail if wrong
///     extra_delta  ;; this is the "legal discrepancy" between your real delta and what you're announcing your delta is
///   )
///
///   ;;;;; start library code
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include cat_truths.clib)
///   (include utility_macros.clib)
///
///   (defconstant RING_MORPH_BYTE 0xcb)
///
///
///   ; take two lists and merge them into one
///   (defun merge_list (list_a list_b)
///     (if list_a
///         (c (f list_a) (merge_list (r list_a) list_b))
///         list_b
///     )
///   )
///
///   ; cat_mod_struct = (MOD_HASH MOD_HASH_hash GENESIS_COIN_CHECKER GENESIS_COIN_CHECKER_hash)
///
///   (defun-inline mod_hash_from_cat_mod_struct (cat_mod_struct) (f cat_mod_struct))
///   (defun-inline mod_hash_hash_from_cat_mod_struct (cat_mod_struct) (f (r cat_mod_struct)))
///   (defun-inline tail_program_hash_from_cat_mod_struct (cat_mod_struct) (f (r (r cat_mod_struct))))
///
///   ;;;;; end library code
///
///   ;; return the puzzle hash for a cat with the given `GENESIS_COIN_CHECKER_hash` & `INNER_PUZZLE`
///   (defun-inline cat_puzzle_hash (cat_mod_struct inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (mod_hash_from_cat_mod_struct cat_mod_struct)
///       inner_puzzle_hash
///       (sha256 ONE (tail_program_hash_from_cat_mod_struct cat_mod_struct))
///       (mod_hash_hash_from_cat_mod_struct cat_mod_struct)
///     )
///   )
///
///   ;; assert `CREATE_COIN_ANNOUNCEMENT` doesn't contain the RING_MORPH_BYTE bytes so it cannot be used to cheat the coin ring
///
///   (defun-inline morph_condition (condition cat_mod_struct)
///     (if (= (f condition) CREATE_COIN)
///         (c CREATE_COIN
///           (c (cat_puzzle_hash cat_mod_struct (f (r condition)))
///           (r (r condition)))
///         )
///         (if (= (f condition) CREATE_COIN_ANNOUNCEMENT)
///             (assert (not (and
///                 (= 33 (strlen (f (r condition))))
///                 (= (substr (f (r condition)) 0 ONE) RING_MORPH_BYTE)  ; lazy eval
///               ))
///               ; then
///               condition
///             )
///             condition
///         )
///     )
///   )
///
///   ;; given a coin's parent, inner_puzzle and amount, and the cat_mod_struct, calculate the id of the coin
///   (defun-inline coin_id_for_proof (coin cat_mod_struct)
///     (calculate_coin_id (f coin) (cat_puzzle_hash cat_mod_struct (f (r coin))) (f (r (r coin))))
///   )
///
///   ;; utility to fetch coin amount from coin
///   (defun-inline input_amount_for_coin (coin)
///     (f (r (r coin)))
///   )
///
///   ;; calculate the hash of an announcement
///   ;; we add 0xcb so ring announcements exist in a different namespace to announcements from inner_puzzles
///   (defun-inline calculate_annoucement_id (this_coin_id this_subtotal next_coin_id cat_mod_struct)
///     (sha256 next_coin_id RING_MORPH_BYTE (sha256tree (list this_coin_id this_subtotal)))
///   )
///
///   ;; create the `ASSERT_COIN_ANNOUNCEMENT` condition that ensures the next coin's announcement is correct
///   (defun-inline create_assert_next_announcement_condition (this_coin_id this_subtotal next_coin_id cat_mod_struct)
///     (list ASSERT_COIN_ANNOUNCEMENT
///       (calculate_annoucement_id this_coin_id
///         this_subtotal
///         next_coin_id
///         cat_mod_struct
///       )
///     )
///   )
///
///   ;; here we commit to I_{k-1} and S_k
///   ;; we add 0xcb so ring announcements exist in a different namespace to announcements from inner_puzzles
///   (defun-inline create_announcement_condition (prev_coin_id prev_subtotal)
///     (list CREATE_COIN_ANNOUNCEMENT
///       (concat RING_MORPH_BYTE (sha256tree (list prev_coin_id prev_subtotal)))
///     )
///   )
///
///   ;;;;;;;;;;;;;;;;;;;;;;;;;;;
///
///   ;; this function takes a condition and returns an integer indicating
///   ;; the value of all output coins created with CREATE_COIN. If it's not
///   ;; a CREATE_COIN condition, it returns 0.
///
///   (defun-inline output_value_for_condition (condition)
///     (if (= (f condition) CREATE_COIN)
///         (f (r (r condition)))
///         0
///     )
///   )
///
///   ;; add two conditions to the list of morphed conditions:
///   ;; CREATE_COIN_ANNOUNCEMENT for my announcement
///   ;; ASSERT_COIN_ANNOUNCEMENT for the next coin's announcement
///   (defun-inline generate_final_output_conditions
///     (
///       prev_subtotal
///       this_subtotal
///       morphed_conditions
///       prev_coin_id
///       this_coin_id
///       next_coin_id
///       cat_mod_struct
///     )
///     (c (create_announcement_condition prev_coin_id prev_subtotal)
///       (c (create_assert_next_announcement_condition this_coin_id this_subtotal next_coin_id cat_mod_struct)
///       morphed_conditions)
///     )
///   )
///
///
///   ;; This next section of code loops through all of the conditions to do three things:
///   ;;   1) Look for a "magic" value of -113 and, if one exists, filter it, and take note of the tail reveal and solution
///   ;;   2) Morph any CREATE_COIN or CREATE_COIN_ANNOUNCEMENT conditions
///   ;;   3) Sum the total output amount of all of the CREATE_COINs that are output by the inner puzzle
///   ;;
///   ;; After everything return a struct in the format (morphed_conditions . (output_sum . tail_reveal_and_solution))
///   ;; If multiple magic conditions are specified, the later one will take precedence
///
///   (defun-inline condition_tail_reveal (condition) (f (r (r (r condition)))))
///   (defun-inline condition_tail_solution (condition) (f (r (r (r (r condition))))))
///
///   (defun cons_onto_first_and_add_to_second (morphed_condition output_value struct)
///     (c (c morphed_condition (f struct)) (c (+ output_value (f (r struct))) (r (r struct))))
///   )
///
///   (defun find_and_strip_tail_info (inner_conditions cat_mod_struct tail_reveal_and_solution)
///     (if inner_conditions
///         (if (= (output_value_for_condition (f inner_conditions)) -113)  ; Checks this is a CREATE_COIN of value -113
///             (find_and_strip_tail_info
///               (r inner_conditions)
///               cat_mod_struct
///               (c (condition_tail_reveal (f inner_conditions)) (condition_tail_solution (f inner_conditions)))
///             )
///             (cons_onto_first_and_add_to_second
///               (morph_condition (f inner_conditions) cat_mod_struct)
///               (output_value_for_condition (f inner_conditions))
///               (find_and_strip_tail_info
///                 (r inner_conditions)
///                 cat_mod_struct
///                 tail_reveal_and_solution
///               )
///             )
///         )
///         (c () (c 0 tail_reveal_and_solution))
///     )
///   )
///
///   ;;;;;;;;;;;;;;;;;;;;;;;;;;; lineage checking
///
///   ;; return true iff parent of `this_coin_info` is provably a cat
///   ;; A 'lineage proof' consists of (parent_parent_id parent_INNER_puzzle_hash parent_amount)
///   ;; We use this information to construct a coin who's puzzle has been wrapped in this MOD and verify that,
///   ;; once wrapped, it matches our parent coin's ID.
///   (defun-inline is_parent_cat (
///       cat_mod_struct
///       parent_id
///       lineage_proof
///     )
///     (= parent_id
///       (calculate_coin_id (f lineage_proof)
///         (cat_puzzle_hash cat_mod_struct (f (r lineage_proof)))
///         (f (r (r lineage_proof)))
///       )
///     )
///   )
///
///   (defun check_lineage_or_run_tail_program
///     (
///       this_coin_info
///       tail_reveal_and_solution
///       parent_is_cat  ; flag which says whether or not the parent CAT check ran and passed
///       lineage_proof
///       Truths
///       extra_delta
///       inner_conditions
///     )
///     (if tail_reveal_and_solution
///         (assert (= (sha256tree (f tail_reveal_and_solution)) (cat_tail_program_hash_truth Truths))
///           (merge_list
///             (a  (f tail_reveal_and_solution)
///               (list
///                 Truths
///                 parent_is_cat
///                 lineage_proof  ; Lineage proof is only guaranteed to be true if parent_is_cat
///                 extra_delta
///                 inner_conditions
///                 (r tail_reveal_and_solution)
///               )
///             )
///             inner_conditions
///           )
///         )
///         (assert parent_is_cat (not extra_delta)
///           inner_conditions
///         )
///     )
///   )
///
///   ;;;;;;;;;;;;;;;;;;;;;;;;;;;
///
///   (defun stager_two (
///       Truths
///       (inner_conditions . (output_sum . tail_reveal_and_solution))
///       lineage_proof
///       prev_coin_id
///       this_coin_info
///       next_coin_id
///       prev_subtotal
///       extra_delta
///     )
///     (check_lineage_or_run_tail_program
///       this_coin_info
///       tail_reveal_and_solution
///       (if lineage_proof (is_parent_cat (cat_struct_truth Truths) (my_parent_cat_truth Truths) lineage_proof) ())
///       lineage_proof
///       Truths
///       extra_delta
///       (generate_final_output_conditions
///         prev_subtotal
///         ; the expression on the next line calculates `this_subtotal` by adding the delta to `prev_subtotal`
///         (+ prev_subtotal (- (input_amount_for_coin this_coin_info) output_sum) extra_delta)
///         inner_conditions
///         prev_coin_id
///         (my_id_cat_truth Truths)
///         next_coin_id
///         (cat_struct_truth Truths)
///       )
///     )
///   )
///
///   ; CAT TRUTHS struct is: ; CAT Truths is: ((Inner puzzle hash . (MOD hash . (MOD hash hash . TAIL hash))) . (my_id . (my_parent_info my_puzhash my_amount)))
///   ; create truths - this_coin_info verified true because we calculated my ID from it!
///   ; lineage proof is verified later by cat parent check or tail_program
///
///   (defun stager (
///       cat_mod_struct
///       inner_conditions
///       lineage_proof
///       inner_puzzle_hash
///       my_id
///       prev_coin_id
///       this_coin_info
///       next_coin_proof
///       prev_subtotal
///       extra_delta
///     )
///     (c (list ASSERT_MY_COIN_ID my_id) (stager_two
///         (cat_truth_data_to_truth_struct
///           inner_puzzle_hash
///           cat_mod_struct
///           my_id
///           this_coin_info
///         )
///         (find_and_strip_tail_info inner_conditions cat_mod_struct ())
///         lineage_proof
///         prev_coin_id
///         this_coin_info
///         (coin_id_for_proof next_coin_proof cat_mod_struct)
///         prev_subtotal
///         extra_delta
///     ))
///   )
///
///   (stager
///     ;; calculate cat_mod_struct, inner_puzzle_hash, coin_id
///     (list MOD_HASH (sha256 ONE MOD_HASH) TAIL_PROGRAM_HASH)
///     (a INNER_PUZZLE inner_puzzle_solution)
///     lineage_proof
///     (sha256tree INNER_PUZZLE)
///     (calculate_coin_id (f this_coin_info) (f (r this_coin_info)) (f (r (r this_coin_info))))
///     prev_coin_id  ; ID
///     this_coin_info  ; (parent_id puzzle_hash amount)
///     next_coin_proof  ; (parent_id innerpuzhash amount)
///     prev_subtotal
///     extra_delta
///   )
/// )
/// ```
pub const CAT_PUZZLE: [u8; 1672] = hex!("ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff34ff0580ffff04ff0bff80808080ffff04ffff02ff17ff2f80ffff04ff5fffff04ffff02ff2effff04ff02ffff04ff17ff80808080ffff04ffff02ff2affff04ff02ffff04ff82027fffff04ff82057fffff04ff820b7fff808080808080ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffff80808080808080808080808080ffff04ffff01ffffffff3d46ff02ff333cffff0401ff01ff81cb02ffffff20ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff7cffff0bff34ff2480ffff0bff7cffff0bff7cffff0bff34ff2c80ff0980ffff0bff7cff0bffff0bff34ff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ffff22ffff09ffff0dff0580ff2280ffff09ffff0dff0b80ff2280ffff15ff17ffff0181ff8080ffff01ff0bff05ff0bff1780ffff01ff088080ff0180ffff02ffff03ff0bffff01ff02ffff03ffff09ffff02ff2effff04ff02ffff04ff13ff80808080ff820b9f80ffff01ff02ff56ffff04ff02ffff04ffff02ff13ffff04ff5fffff04ff17ffff04ff2fffff04ff81bfffff04ff82017fffff04ff1bff8080808080808080ffff04ff82017fff8080808080ffff01ff088080ff0180ffff01ff02ffff03ff17ffff01ff02ffff03ffff20ff81bf80ffff0182017fffff01ff088080ff0180ffff01ff088080ff018080ff0180ff04ffff04ff05ff2780ffff04ffff10ff0bff5780ff778080ffffff02ffff03ff05ffff01ff02ffff03ffff09ffff02ffff03ffff09ff11ff5880ffff0159ff8080ff0180ffff01818f80ffff01ff02ff26ffff04ff02ffff04ff0dffff04ff0bffff04ffff04ff81b9ff82017980ff808080808080ffff01ff02ff7affff04ff02ffff04ffff02ffff03ffff09ff11ff5880ffff01ff04ff58ffff04ffff02ff76ffff04ff02ffff04ff13ffff04ff29ffff04ffff0bff34ff5b80ffff04ff2bff80808080808080ff398080ffff01ff02ffff03ffff09ff11ff7880ffff01ff02ffff03ffff20ffff02ffff03ffff09ffff0121ffff0dff298080ffff01ff02ffff03ffff09ffff0cff29ff80ff3480ff5c80ffff01ff0101ff8080ff0180ff8080ff018080ffff0109ffff01ff088080ff0180ffff010980ff018080ff0180ffff04ffff02ffff03ffff09ff11ff5880ffff0159ff8080ff0180ffff04ffff02ff26ffff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ff80808080808080ff0180ffff01ff04ff80ffff04ff80ff17808080ff0180ffff02ffff03ff05ffff01ff04ff09ffff02ff56ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff0bff7cffff0bff34ff2880ffff0bff7cffff0bff7cffff0bff34ff2c80ff0580ffff0bff7cffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff34ff3480ff8080808080ffff0bff34ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff04ffff04ff30ffff04ff5fff808080ffff02ff7effff04ff02ffff04ffff04ffff04ff2fff0580ffff04ff5fff82017f8080ffff04ffff02ff26ffff04ff02ffff04ff0bffff04ff05ffff01ff808080808080ffff04ff17ffff04ff81bfffff04ff82017fffff04ffff02ff2affff04ff02ffff04ff8204ffffff04ffff02ff76ffff04ff02ffff04ff09ffff04ff820affffff04ffff0bff34ff2d80ffff04ff15ff80808080808080ffff04ff8216ffff808080808080ffff04ff8205ffffff04ff820bffff808080808080808080808080ff02ff5affff04ff02ffff04ff5fffff04ff3bffff04ffff02ffff03ff17ffff01ff09ff2dffff02ff2affff04ff02ffff04ff27ffff04ffff02ff76ffff04ff02ffff04ff29ffff04ff57ffff04ffff0bff34ff81b980ffff04ff59ff80808080808080ffff04ff81b7ff80808080808080ff8080ff0180ffff04ff17ffff04ff05ffff04ff8202ffffff04ffff04ffff04ff78ffff04ffff0eff5cffff02ff2effff04ff02ffff04ffff04ff2fffff04ff82017fff808080ff8080808080ff808080ffff04ffff04ff20ffff04ffff0bff81bfff5cffff02ff2effff04ff02ffff04ffff04ff15ffff04ffff10ff82017fffff11ff8202dfff2b80ff8202ff80ff808080ff8080808080ff808080ff138080ff80808080808080808080ff018080");
pub const CAT_PUZZLE_HASH: [u8; 32] =
    hex!("37bef360ee858133b69d595a906dc45d01af50379dad515eb9518abb7c1d2a7a");

/// ```text
/// ; This is a "limitations_program" for use with cat.clsp.
/// (mod (
///     PUBKEY
///     Truths
///     parent_is_cat
///     lineage_proof
///     delta
///     inner_conditions
///     (
///       delegated_puzzle
///       delegated_solution
///     )
///   )
///
///   (include condition_codes.clib)
///
///   (defun sha256tree1 (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///   (sha256 1 TREE)))
///
///   (c (list AGG_SIG_UNSAFE PUBKEY (sha256tree1 delegated_puzzle))
///     (a delegated_puzzle (c Truths (c parent_is_cat (c lineage_proof (c delta (c inner_conditions delegated_solution))))))
///   )
/// )
/// ```
pub const DELEGATED_TAIL: [u8; 180] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff82027fff80808080ff80808080ffff02ff82027fffff04ff0bffff04ff17ffff04ff2fffff04ff5fffff04ff81bfff82057f80808080808080ffff04ffff01ff31ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const DELEGATED_TAIL_HASH: [u8; 32] =
    hex!("999c3696e167f8a79d938adc11feba3a3dcb39ccff69a426d570706e7b8ec399");

/// ```text
/// ; This is a "limitations_program" for use with cat.clsp.
/// (mod (
///     PUBKEY
///     Truths
///     parent_is_cat
///     lineage_proof
///     delta
///     inner_conditions
///     _
///   )
///
///   (include condition_codes.clib)
///
///   (list (list AGG_SIG_ME PUBKEY delta))  ; Careful with a delta of zero, the bytecode is 80 not 00
/// )
/// ```
pub const EVERYTHING_WITH_SIGNATURE: [u8; 41] =
    hex!("ff02ffff01ff04ffff04ff02ffff04ff05ffff04ff5fff80808080ff8080ffff04ffff0132ff018080");
pub const EVERYTHING_WITH_SIGNATURE_HASH: [u8; 32] =
    hex!("1720d13250a7c16988eaf530331cefa9dd57a76b2c82236bec8bbbff91499b89");

/// ```text
/// ; This is a "limitations_program" for use with cat.clsp.
/// ; It allows a singleton to both mint and melt this CAT by sending a message.
/// (mod (
///     SINGLETON_MOD_HASH
///     SINGLETON_STRUCT_HASH ; The hash of (SINGLETON_MOD_HASH . (LAUNCHER_ID . SINGLETON_LAUNCHER_HASH))
///     NONCE
///     Truths
///     parent_is_cat
///     lineage_proof
///     delta
///     inner_conditions
///     (  ; solution
///       singleton_inner_puzzle_hash
///     )
///   )
///
///   (include condition_codes.clib)
///   (include curry.clib)
///
///   (defun-inline calculate_full_puzzle_hash (SINGLETON_MOD_HASH SINGLETON_STRUCT_HASH inner_puzzle_hash)
///     (curry_hashes_inline SINGLETON_MOD_HASH
///       SINGLETON_STRUCT_HASH
///       inner_puzzle_hash
///     )
///   )
///
///   (list
///     (list RECEIVE_MESSAGE
///       23 ; = 010 111, mask for puzzle hash to coin ID
///       delta
///       (calculate_full_puzzle_hash SINGLETON_MOD_HASH SINGLETON_STRUCT_HASH singleton_inner_puzzle_hash)
///     )
///   )
/// )
/// ```
pub const EVERYTHING_WITH_SINGLETON: [u8; 283] = hex!("ff02ffff01ff04ffff04ff04ffff04ffff0117ffff04ff82017fffff04ffff0bff2effff0bff0affff0bff0aff36ff0580ffff0bff0affff0bff3effff0bff0affff0bff0aff36ff0b80ffff0bff0affff0bff3effff0bff0affff0bff0aff36ff8209ff80ffff0bff0aff36ff26808080ff26808080ff26808080ff8080808080ff8080ffff04ffff01ff43ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff018080");
pub const EVERYTHING_WITH_SINGLETON_HASH: [u8; 32] =
    hex!("0876da2005fe6262d4504c27a1b6379227aba8adbbad3758cb0e329a4e74c6cc");

/// ```text
/// ; This is a TAIL for use with cat.klvm.
/// ;
/// ; This checker allows new CATs to be created if they have a particular coin id as parent
/// ;
/// ; The genesis_id is curried in, making this lineage_check program unique and giving the CAT it's uniqueness
/// (mod (
///     GENESIS_ID
///     MINT_LAUNCHER_PUZZLE_HASH
///     Truths
///     parent_is_cat
///     lineage_proof
///     delta
///     inner_conditions
///     (  ; solution
///       parent_parent_id
///       parent_amount
///     )
///   )
///
///   (include cat_truths.clib)
///   (include curry-and-treehash.clib)
///
///   (if delta
///       (x)
///       (if (= (my_parent_cat_truth Truths) GENESIS_ID)
///           ()
///           (if
///             (=
///               (my_parent_cat_truth Truths)
///               (sha256
///                 parent_parent_id
///                 MINT_LAUNCHER_PUZZLE_HASH
///                 parent_amount
///               )
///             )
///             ()
///             (x)
///           )
///       )
///   )
///
/// )
/// ```
pub const GENESIS_BY_COIN_ID_OR_SINGLETON: [u8; 79] = hex!("ff02ffff03ff5fffff01ff0880ffff01ff02ffff03ffff09ff5bff0280ff80ffff01ff02ffff03ffff09ff5bffff0bff82027fff05ff82057f8080ff80ffff01ff088080ff018080ff018080ff0180");
pub const GENESIS_BY_COIN_ID_OR_SINGLETON_HASH: [u8; 32] =
    hex!("40170305e3a71c3e7523f37fbcfc3188f9f949da0818a6331f28251e76e8c56f");

/// ```text
/// ; This is a TAIL for use with cat.klvm.
/// ;
/// ; This checker allows new CATs to be created if they have a particular coin id as parent
/// ;
/// ; The genesis_id is curried in, making this lineage_check program unique and giving the CAT it's uniqueness
/// (mod (
///     GENESIS_ID
///     Truths
///     parent_is_cat
///     lineage_proof
///     delta
///     inner_conditions
///     _
///   )
///
///   (include cat_truths.clib)
///
///   (if delta
///       (x)
///       (if (= (my_parent_cat_truth Truths) GENESIS_ID)
///           ()
///           (x)
///       )
///   )
///
/// )
/// ```
pub const GENESIS_BY_COIN_ID: [u8; 45] = hex!(
    "ff02ffff03ff2fffff01ff0880ffff01ff02ffff03ffff09ff2dff0280ff80ffff01ff088080ff018080ff0180"
);
pub const GENESIS_BY_COIN_ID_HASH: [u8; 32] =
    hex!("493afb89eed93ab86741b2aa61b8f5de495d33ff9b781dfc8919e602b2afa150");

/// ```text
/// ; This is a "limitations_program" for use with cat.clsp.
/// ;
/// ; This checker allows new CATs to be created if their parent has a particular puzzle hash
/// (mod (
///     GENESIS_PUZZLE_HASH
///     Truths
///     parent_is_cat
///     lineage_proof
///     delta
///     inner_conditions
///     (parent_parent_id parent_amount)
///   )
///
///   (include cat_truths.clib)
///
///   ; Returns nil since we don't need to add any conditions
///   (if delta
///       (x)
///       (if (= (sha256 parent_parent_id GENESIS_PUZZLE_HASH parent_amount) (my_parent_cat_truth Truths))
///           ()
///           (x)
///       )
///   )
/// )
/// ```
pub const GENESIS_BY_PUZZLE_HASH: [u8; 57] = hex!("ff02ffff03ff2fffff01ff0880ffff01ff02ffff03ffff09ffff0bff82013fff02ff8202bf80ff2d80ff80ffff01ff088080ff018080ff0180");
pub const GENESIS_BY_PUZZLE_HASH_HASH: [u8; 32] =
    hex!("de5a6e06d41518be97ff6365694f4f89475dda773dede267caa33da63b434e36");

/// ```text
/// ; This file is what the first form the CAT takes, and then it gets immediately eve spent out of here.
/// ; This allows the coin to move into its real state already having been eve spent and validated to not be a fake CAT.
/// ; The trick is that we won't know what the real state puzzlehash reveal is, but we will know what this is.
/// ; Mint into this, eve spend out of this
/// (mod (
///     NEW_PUZZLE_HASH  ; this is the CAT inner_puzzle
///     my_amount
///     tail_reveal
///     tail_solution
///   )
///   (include condition_codes.clib)
///   (list
///     (list CREATE_COIN NEW_PUZZLE_HASH my_amount (list NEW_PUZZLE_HASH))
///     (list ASSERT_MY_AMOUNT my_amount)
///     (list CREATE_COIN 0 -113 tail_reveal tail_solution)  ; this is secure because anything but the real values won't work
///   )
/// )
/// ```
pub const DAO_CAT_EVE: [u8; 112] = hex!("ff02ffff01ff04ffff04ff06ffff04ff05ffff04ff0bffff04ffff04ff05ff8080ff8080808080ffff04ffff04ff04ffff04ff0bff808080ffff04ffff04ff06ffff04ff80ffff04ffff01818fffff04ff17ffff04ff2fff808080808080ff80808080ffff04ffff01ff4933ff018080");
pub const DAO_CAT_EVE_HASH: [u8; 32] =
    hex!("488f55bedaca5a599544dfd5ab341e2e5c7e6fca67d9b98a3d856f876c52f53e");

/// ```text
/// (mod (
///     TREASURY_SINGLETON_STRUCT
///     treasury_inner_puz_hash
///     parent_parent
///     new_puzzle_hash  ; the full CAT puzzle
///     amount
///   )
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   (defun calculate_singleton_puzzle_hash (PROPOSAL_SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (f PROPOSAL_SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree PROPOSAL_SINGLETON_STRUCT)
///     )
///   )
///
///   (defun create_parent_conditions (parent_id new_puzzle_hash amount)
///     (list
///       (list ASSERT_COIN_ANNOUNCEMENT (sha256 parent_id (sha256tree (list 'm' new_puzzle_hash))))
///       (list ASSERT_MY_PARENT_ID parent_id)
///     )
///   )
///
///   (c
///     (list CREATE_COIN new_puzzle_hash amount (list new_puzzle_hash))
///     (c
///       (list ASSERT_MY_AMOUNT amount)
///       (create_parent_conditions
///         (sha256 parent_parent (calculate_singleton_puzzle_hash TREASURY_SINGLETON_STRUCT treasury_inner_puz_hash) ONE)
///         new_puzzle_hash
///         amount
///       )
///     )
///   )
/// )
/// ```
pub const DAO_CAT_LAUNCHER: [u8; 529] = hex!("ff02ffff01ff04ffff04ff34ffff04ff2fffff04ff5fffff04ffff04ff2fff8080ff8080808080ffff04ffff04ff28ffff04ff5fff808080ffff02ff36ffff04ff02ffff04ffff0bff17ffff02ff26ffff04ff02ffff04ff05ffff04ff0bff8080808080ff3c80ffff04ff2fffff04ff5fff8080808080808080ffff04ffff01ffffff3dff4947ffff0233ff0401ffff01ff02ff02ffff03ff05ffff01ff02ff3affff04ff02ffff04ff0dffff04ffff0bff2affff0bff3cff2c80ffff0bff2affff0bff2affff0bff3cff1280ff0980ffff0bff2aff0bffff0bff3cff8080808080ff8080808080ffff010b80ff0180ffffff02ff2effff04ff02ffff04ff09ffff04ff0bffff04ffff02ff3effff04ff02ffff04ff05ff80808080ff808080808080ff04ffff04ff10ffff04ffff0bff05ffff02ff3effff04ff02ffff04ffff04ffff016dffff04ff0bff808080ff8080808080ff808080ffff04ffff04ff38ffff04ff05ff808080ff808080ffff0bff2affff0bff3cff2480ffff0bff2affff0bff2affff0bff3cff1280ff0580ffff0bff2affff02ff3affff04ff02ffff04ff07ffff04ffff0bff3cff3c80ff8080808080ffff0bff3cff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const DAO_CAT_LAUNCHER_HASH: [u8; 32] =
    hex!("a01a838d18d4e031e937c79fa3f80f213fa00a3e64af6c16a1f137770cd3a567");

/// ```text
/// ; This code is the end state of a proposal or a dividend.
/// ; It is an oracle which simply recreates itself and emits an announcement that it has concluded operation
///
/// (mod (SINGLETON_STRUCT DAO_FINISHED_STATE_MOD_HASH my_amount)
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include *standard-cl-21*)
///
///   (defun wrap_in_singleton (SINGLETON_STRUCT my_inner_puzhash)
///     (puzzle-hash-of-curried-function (f SINGLETON_STRUCT)
///       my_inner_puzhash
///       (sha256tree SINGLETON_STRUCT)
///     )
///   )
///
///   (defun recreate_self (SINGLETON_STRUCT DAO_FINISHED_STATE_MOD_HASH)
///     (puzzle-hash-of-curried-function DAO_FINISHED_STATE_MOD_HASH
///       (sha256 ONE DAO_FINISHED_STATE_MOD_HASH)
///       (sha256tree SINGLETON_STRUCT)
///     )
///   )
///
///
///   (let
///     (
///       (my_inner_puzhash (recreate_self SINGLETON_STRUCT DAO_FINISHED_STATE_MOD_HASH))
///     )
///     (list
///       (list ASSERT_MY_PUZZLEHASH (wrap_in_singleton SINGLETON_STRUCT my_inner_puzhash))
///       (list ASSERT_MY_AMOUNT my_amount)
///       (list CREATE_COIN my_inner_puzhash my_amount)
///       (list CREATE_PUZZLE_ANNOUNCEMENT 0)
///     )
///   )
/// )
/// ```
pub const DAO_FINISHED_STATE: [u8; 771] = hex!("ff02ffff01ff04ffff04ffff0148ffff04ffff02ff16ffff04ff02ffff04ffff05ffff06ff018080ffff04ffff02ff1effff04ff02ffff04ff05ffff04ff0bff8080808080ff8080808080ffff01808080ffff04ffff04ffff0149ffff04ffff05ffff06ffff06ffff06ff0180808080ffff01808080ffff04ffff04ffff0133ffff04ffff02ff1effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff05ffff06ffff06ffff06ff0180808080ffff0180808080ffff04ffff04ffff013effff04ffff0180ffff01808080ffff018080808080ffff04ffff01ffffff02ffff03ff05ffff01ff02ffff01ff02ff08ffff04ff02ffff04ffff06ff0580ffff04ffff0bffff0102ffff0bffff0101ffff010480ffff0bffff0102ffff0bffff0102ffff0bffff0101ffff010180ffff05ff058080ffff0bffff0102ff0bffff0bffff0101ffff018080808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0bffff0102ffff01a0a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222ffff0bffff0102ffff0bffff0102ffff01a09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ff0580ffff0bffff0102ffff02ff08ffff04ff02ffff04ff07ffff01ffa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b280808080ffff01a04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff0bffff0102ffff02ff0affff04ff02ffff04ffff05ff0580ff80808080ffff02ff0affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0bffff0101ff0580ff018080ff0180ffff02ff0cffff04ff02ffff04ff09ffff04ff0bffff04ffff02ff0affff04ff02ffff04ff05ff80808080ff808080808080ff02ff0cffff04ff02ffff04ff0bffff04ffff0bffff0101ff0b80ffff04ffff02ff0affff04ff02ffff04ff05ff80808080ff808080808080ff018080");
pub const DAO_FINISHED_STATE_HASH: [u8; 32] =
    hex!("694c99e1fb07671771bbca3d110880693a9ecc37a6529891ec979d0f3e760eba");

/// ```text
/// ; This code is the "voting mode" for a DAO CAT.
/// ; The coin can be spent from this state to vote on a proposal or claim a dividend.
/// ; It locks the CAT in while it has active votes/dividends going on.
/// ; Once a vote or dividend closes, then the coin can spend itself to remove that coin from the "active list"
/// ; If the "active list" is empty the coin can leave the voting mode
///
/// (mod (
///     ; this is the first curry
///     SINGLETON_MOD_HASH
///     SINGLETON_LAUNCHER_PUZHASH
///     DAO_FINISHED_STATE_MOD_HASH
///     CAT_MOD_HASH
///     CAT_TAIL_HASH
///     ; this is the second curry
///     SELF_HASH  ; this is the self_hash Optimization
///     ACTIVE_VOTES  ; "active votes" list
///     INNERPUZ
///     ; this is the solution
///     my_id  ; if my_id is 0 we do the return to return_address (exit voting mode) spend case
///     inner_solution
///     my_amount
///     new_proposal_vote_id_or_removal_id  ; removal_id is a list of removal_ids
///     proposal_innerpuzhash  ; list of singleton innerpuzhashes which should match the order of the new_proposal_vote_id list
///     vote_info
///     vote_amount
///     my_inner_puzhash
///     new_innerpuzhash  ; only include this if we're changing owners - secured because coin is still made from inner_puz
///   )
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include *standard-cl-21*)
///
///   (defun calculate_finished_state (singleton_struct dao_finished_state)
///     (puzzle-hash-of-curried-function dao_finished_state
///       (sha256 ONE dao_finished_state)
///       (sha256tree singleton_struct)
///     )
///   )
///
///   ; take two lists and merge them into one
///   (defun merge_list (list_a list_b)
///     (if list_a
///         (c (f list_a) (merge_list (r list_a) list_b))
///         list_b
///     )
///   )
///
///   (defun wrap_in_cat_layer (CAT_MOD_HASH CAT_TAIL_HASH INNERPUZHASH)
///     (puzzle-hash-of-curried-function CAT_MOD_HASH
///       INNERPUZHASH
///       (sha256 ONE CAT_TAIL_HASH)
///       (sha256 ONE CAT_MOD_HASH)
///     )
///   )
///
///   ; loop through conditions and check that they aren't trying to create anything they shouldn't
///   (defun check_conditions (conditions vote_added_puzhash my_amount message vote_amount my_inner_puzhash seen_vote seen_change)
///     (if conditions
///         (if (= (f (f conditions)) CREATE_COIN)  ; this guarantees that the new coin is obeying the rules - other coins are banned to avoid re-voting
///             (if (= (f (r (f conditions))) vote_added_puzhash)
///                 (if seen_vote  ; assert we haven't already made a coin with the new vote included
///                     (x)
///                     (if (= (f (r (r (f conditions)))) my_amount)  ; we vote with all our value
///                         (if seen_change  ; assert that we haven't already recreated ourself in some fashion
///                             (x)
///                             (c (f conditions) (check_conditions (r conditions) vote_added_puzhash my_amount message vote_amount my_inner_puzhash 1 1))
///                         )
///                         (if (= (f (r (r (f conditions)))) vote_amount)  ; we vote with part of our power
///                             (c (f conditions) (check_conditions (r conditions) vote_added_puzhash my_amount message vote_amount my_inner_puzhash 1 seen_change))
///                             (x)
///                         )
///                     )
///                 )
///                 (if (all
///                       (= (f (r (f conditions))) my_inner_puzhash)
///                       (not seen_change)
///                       (= (f (r (r (f conditions)))) (- my_amount vote_amount))
///                     )  ; we recreate ourselves with unused voting power
///                     (c (f conditions) (check_conditions (r conditions) vote_added_puzhash my_amount message vote_amount my_inner_puzhash seen_vote 1))
///                     (x)
///                 )
///             )
///             (if (= (f (f conditions)) CREATE_PUZZLE_ANNOUNCEMENT)  ; this secures the values used to generate message - other messages are banned in case of LIES
///                 (if (= (f (r (f conditions))) message)
///                     (c (f conditions) (check_conditions (r conditions) vote_added_puzhash my_amount message vote_amount my_inner_puzhash seen_vote seen_change))
///                     (x)
///                 )
///                 (c (f conditions) (check_conditions (r conditions) vote_added_puzhash my_amount message vote_amount my_inner_puzhash seen_vote seen_change))
///             )
///         )
///         (if (all seen_vote seen_change)  ; check all value is accounted for
///             ()
///             (x)
///         )
///     )
///   )
///
///   ; go through our list of active votes and check that we aren't revoting
///   (defun check_not_previously_voted (
///       SINGLETON_MOD_HASH
///       SINGLETON_LAUNCHER_PUZHASH
///       INNERPUZ
///       my_id
///       new_vote_id
///       active_votes
///       proposal_innerpuzhash
///     )
///     (if active_votes
///         (if (= new_vote_id (f active_votes))  ; check new vote id is not equal to an existent vote id
///             (x)
///             (check_not_previously_voted
///               SINGLETON_MOD_HASH
///               SINGLETON_LAUNCHER_PUZHASH
///               INNERPUZ
///               my_id
///               new_vote_id
///               (r active_votes)
///               proposal_innerpuzhash
///             )
///         )
///         (list ASSERT_PUZZLE_ANNOUNCEMENT
///           (sha256
///             (calculate_singleton_puzzle_hash
///               (c SINGLETON_MOD_HASH (c new_vote_id SINGLETON_LAUNCHER_PUZHASH))
///               proposal_innerpuzhash
///             )
///             my_id
///           )
///         )
///     )
///   )
///
///
///   (defun calculate_singleton_puzzle_hash (PROPOSAL_SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (f PROPOSAL_SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree PROPOSAL_SINGLETON_STRUCT)
///     )
///   )
///
///   (defun calculate_lockup_puzzlehash (
///       SELF_HASH
///       active_votes
///       innerpuzhash
///     )
///     (puzzle-hash-of-curried-function SELF_HASH
///       innerpuzhash
///       (sha256tree active_votes)
///       (sha256 ONE SELF_HASH)
///     )
///   )
///
///   (defun for_every_removal_id (
///       SINGLETON_MOD_HASH
///       SINGLETON_LAUNCHER_PUZHASH
///       SELF_HASH
///       DAO_FINISHED_STATE_MOD_HASH
///       CAT_MOD_HASH
///       CAT_TAIL_HASH
///       ACTIVE_VOTES
///       INNERPUZ
///       removal_ids
///       my_amount
///       unused_votes
///     )
///     (if removal_ids
///         (c
///           (list
///             ASSERT_PUZZLE_ANNOUNCEMENT  ; check proposal is actually finished
///             (sha256
///               (calculate_singleton_puzzle_hash
///                 (c SINGLETON_MOD_HASH (c (f removal_ids) SINGLETON_LAUNCHER_PUZHASH))
///                 (calculate_finished_state
///                   (c SINGLETON_MOD_HASH (c (f removal_ids) SINGLETON_LAUNCHER_PUZHASH))
///                   DAO_FINISHED_STATE_MOD_HASH
///                 )
///               )
///               0
///             )
///           )
///           (for_every_removal_id
///             SINGLETON_MOD_HASH
///             SINGLETON_LAUNCHER_PUZHASH
///             SELF_HASH
///             DAO_FINISHED_STATE_MOD_HASH
///             CAT_MOD_HASH
///             CAT_TAIL_HASH
///             ACTIVE_VOTES
///             INNERPUZ
///             (r removal_ids)
///             my_amount
///             (c (f removal_ids) unused_votes)
///           )
///         )
///         (list
///           (list ASSERT_MY_AMOUNT my_amount)  ; assert that we aren't lying about our amount to free up money and re-vote
///           (list
///             CREATE_COIN  ; recreate self with the finished proposal ID removed
///             (calculate_lockup_puzzlehash
///               SELF_HASH
///               (remove_list_one_entries_from_list_two unused_votes ACTIVE_VOTES)
///               (sha256tree INNERPUZ)
///             )
///             my_amount
///           )
///         )
///     )
///   )
///
///   (defun remove_list_one_entries_from_list_two (list_one list_two)
///     (if list_one
///         (remove_item_from_list (f list_one) (remove_list_one_entries_from_list_two (r list_one) list_two))
///         list_two
///     )
///   )
///
///   (defun remove_item_from_list (item list_one)
///     (if list_one
///         (if (= (f list_one) item)
///             (r list_one)  ; assuming there are no duplicates
///             (c (f list_one) (remove_item_from_list item (r list_one)))
///         )
///         ()  ; item was never in list_one, return list_two entirely
///     )
///   )
///
///
///   ; main
///   (if my_id
///       (c (list ASSERT_MY_PUZZLEHASH (wrap_in_cat_layer CAT_MOD_HASH CAT_TAIL_HASH my_inner_puzhash))
///         (c
///           (list ASSERT_MY_AMOUNT my_amount)
///           (c
///             (list ASSERT_MY_COIN_ID my_id)
///             (c
///               (if new_proposal_vote_id_or_removal_id
///                   (check_not_previously_voted  ; this returns a single condition asserting announcement from vote singleton
///                     SINGLETON_MOD_HASH
///                     SINGLETON_LAUNCHER_PUZHASH
///                     INNERPUZ
///                     my_id
///                     new_proposal_vote_id_or_removal_id
///                     ACTIVE_VOTES
///                     proposal_innerpuzhash
///                   )
///                   (list REMARK)
///               )
///
///               ; loop over conditions and check that we aren't trying to leave voting state
///               (check_conditions
///                 (a INNERPUZ inner_solution)
///                 (calculate_lockup_puzzlehash  ; compare created coin to our own calculation on what the next puzzle should be
///                   SELF_HASH
///                   (if new_proposal_vote_id_or_removal_id (c new_proposal_vote_id_or_removal_id ACTIVE_VOTES) ACTIVE_VOTES)
///                   (if new_innerpuzhash new_innerpuzhash (sha256tree INNERPUZ))
///                 )
///                 my_amount
///                 ; TODO: add namespace to this announcement to allow announcements from the innerpuz
///                 (sha256tree (list new_proposal_vote_id_or_removal_id vote_amount vote_info my_id))
///                 vote_amount
///                 my_inner_puzhash
///                 0
///                 0
///               )
///             )
///           )
///         )
///       )
///
///       ; return to return_address or remove something from active list - check if our locked list is empty
///       (if ACTIVE_VOTES
///           (for_every_removal_id  ; locked list is not empty, so we must be trying to remove something from it
///             SINGLETON_MOD_HASH
///             SINGLETON_LAUNCHER_PUZHASH
///             SELF_HASH
///             DAO_FINISHED_STATE_MOD_HASH
///             CAT_MOD_HASH
///             CAT_TAIL_HASH
///             ACTIVE_VOTES
///             INNERPUZ
///             new_proposal_vote_id_or_removal_id
///             my_amount
///             ()
///           )
///           (a INNERPUZ inner_solution)
///       )
///   )
/// )
/// ```
pub const DAO_LOCKUP: [u8; 3140] = hex!(" ");
pub const DAO_LOCKUP_HASH: [u8; 32] =
    hex!("d6215f0916715a69fbbf2d1a679f437fde81787adeb90c666642fb9c2deff7ce");

/// ```text
/// ; This is a persistent timer for a proposal which allows it to have a relative time that survives despite it being recreated.
/// ; The closing time is contained in the timelock and passed in to the solution, and confirmed via an announcement from the Proposal
/// ; It creates/asserts announcements to pair it with the finishing spend of a proposal
///
/// (mod (
///     PROPOSAL_SELF_HASH
///     MY_PARENT_SINGLETON_STRUCT
///     proposal_yes_votes
///     proposal_total_votes
///     proposal_innerpuzhash
///     proposal_timelock
///     parent_parent
///     parent_amount
///   )
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include *standard-cl-21*)
///
///   (defun calculate_singleton_puzzle_hash (PROPOSAL_SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (f PROPOSAL_SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree PROPOSAL_SINGLETON_STRUCT)
///     )
///   )
///
///   (defun calculate_proposal_puzzlehash (
///       PROPOSAL_SINGLETON_STRUCT
///       PROPOSAL_SELF_HASH
///       proposal_yes_votes
///       proposal_total_votes
///       proposal_innerpuzhash
///     )
///     (calculate_singleton_puzzle_hash
///       PROPOSAL_SINGLETON_STRUCT
///       (puzzle-hash-of-curried-function PROPOSAL_SELF_HASH
///         (sha256 ONE proposal_total_votes)
///         (sha256 ONE proposal_yes_votes)
///         (sha256 ONE proposal_innerpuzhash)
///         (sha256 ONE (f (r PROPOSAL_SINGLETON_STRUCT)))
///         (sha256 ONE PROPOSAL_SELF_HASH)
///       )
///     )
///   )
///
///   ; main
///   (list
///     (list ASSERT_HEIGHT_RELATIVE proposal_timelock)
///     (list CREATE_PUZZLE_ANNOUNCEMENT (f (r MY_PARENT_SINGLETON_STRUCT)))
///     (list
///       ASSERT_PUZZLE_ANNOUNCEMENT
///       (sha256
///         (calculate_proposal_puzzlehash
///           MY_PARENT_SINGLETON_STRUCT
///           PROPOSAL_SELF_HASH
///           proposal_yes_votes
///           proposal_total_votes
///           proposal_innerpuzhash
///         )
///         proposal_timelock
///       )
///     )
///     (list
///       ASSERT_MY_PARENT_ID
///       (sha256
///         parent_parent
///         (calculate_proposal_puzzlehash
///           MY_PARENT_SINGLETON_STRUCT
///           PROPOSAL_SELF_HASH
///           0
///           0
///           proposal_innerpuzhash
///         )
///         parent_amount
///       )
///
///     )
///   )
/// )
/// ```
pub const DAO_PROPOSAL_TIMER: [u8; 825] = hex!("ff02ffff01ff04ffff04ffff0152ffff04ff8200bfffff01808080ffff04ffff04ffff013effff04ffff05ffff06ff0b8080ffff01808080ffff04ffff04ffff013fffff04ffff0bffff02ff1effff04ff02ffff04ff0bffff04ff05ffff04ff17ffff04ff2fffff04ff5fff8080808080808080ff8200bf80ffff01808080ffff04ffff04ffff0147ffff04ffff0bff82017fffff02ff1effff04ff02ffff04ff0bffff04ff05ffff04ffff0180ffff04ffff0180ffff04ff5fff8080808080808080ff8202ff80ffff01808080ffff018080808080ffff04ffff01ffffff02ffff03ff05ffff01ff02ffff01ff02ff08ffff04ff02ffff04ffff06ff0580ffff04ffff0bffff0102ffff0bffff0101ffff010480ffff0bffff0102ffff0bffff0102ffff0bffff0101ffff010180ffff05ff058080ffff0bffff0102ff0bffff0bffff0101ffff018080808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0bffff0102ffff01a0a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222ffff0bffff0102ffff0bffff0102ffff01a09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ff0580ffff0bffff0102ffff02ff08ffff04ff02ffff04ff07ffff01ffa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b280808080ffff01a04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff0bffff0102ffff02ff0affff04ff02ffff04ffff05ff0580ff80808080ffff02ff0affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0bffff0101ff0580ff018080ff0180ffff02ff0cffff04ff02ffff04ff09ffff04ff0bffff04ffff02ff0affff04ff02ffff04ff05ff80808080ff808080808080ff02ff16ffff04ff02ffff04ff05ffff04ffff02ff0cffff04ff02ffff04ff0bffff04ffff0bffff0101ff2f80ffff04ffff0bffff0101ff1780ffff04ffff0bffff0101ff5f80ffff04ffff0bffff0101ff1580ffff04ffff0bffff0101ff0b80ff808080808080808080ff8080808080ff018080");
pub const DAO_PROPOSAL_TIMER_HASH: [u8; 32] =
    hex!("1acd912fca662d1474f7a6c762280fc1430875bef518883387086c1125027526");

/// ```text
/// (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
///       )
///     )
///   )
/// )
/// ```
pub const DAO_PROPOSAL_VALIDATOR: [u8; 1170] = hex!("ff02ffff01ff02ffff03ffff15ffff10ff825effffff010180ff1780ffff01ff02ffff01ff02ffff03ffff02ff1effff04ff02ffff04ff820affffff04ff5fff8080808080ffff01ff02ffff01ff02ffff03ffff02ff1effff04ff02ffff04ff8216ffffff04ffff05ffff14ffff12ff820affff8200bf80ffff018227108080ff8080808080ffff01ff02ffff01ff02ffff03ffff09ff82027fffff02ff0affff04ff02ffff04ff822effffff04ffff02ff0cffff04ff02ffff04ffff05ffff04ffff05ff0580ffff04ff8204ffffff06ffff06ff058080808080ffff04ffff02ff0cffff04ff02ffff04ff0bffff04ffff0bffff0101ff820aff80ffff04ffff0bffff0101ff8216ff80ffff04ffff0bffff0101ff82057f80ffff04ffff0bffff0101ff8204ff80ffff04ffff0bffff0101ff0b80ff808080808080808080ffff04ffff02ff16ffff04ff02ffff04ffff04ffff05ff0580ffff04ff8204ffffff06ffff06ff0580808080ff80808080ff808080808080ffff04ff825effff80808080808080ffff01ff02ffff01ff04ffff04ffff013effff04ff8204ffffff01808080ffff02ffff03ffff15ffff11ff825effffff010180ffff018080ffff01ff02ffff01ff04ffff04ffff0133ffff04ff2fffff04ffff11ff825effffff010180ffff04ffff04ffff05ffff06ff058080ffff018080ffff018080808080ff8205ff80ff0180ffff01ff02ffff018205ffff018080ff018080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff01ffffff02ffff03ff05ffff01ff02ffff01ff02ff08ffff04ff02ffff04ffff06ff0580ffff04ffff0bffff0102ffff0bffff0101ffff010480ffff0bffff0102ffff0bffff0102ffff0bffff0101ffff010180ffff05ff058080ffff0bffff0102ff0bffff0bffff0101ffff018080808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0bffff0102ffff01a0a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222ffff0bffff0102ffff0bffff0102ffff01a09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ff0580ffff0bffff0102ffff02ff08ffff04ff02ffff04ff07ffff01ffa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b280808080ffff01a04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a808080ffff02ffff03ffff22ffff09ffff0dff0580ffff012080ffff09ffff0dff0b80ffff012080ffff15ff17ffff0181ff8080ffff01ff02ffff01ff0bff05ff0bff1780ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ffff03ffff07ff0580ffff01ff02ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ffff05ff0580ff80808080ffff02ff16ffff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0bffff0101ff0580ff018080ff0180ff20ffff15ff0bff058080ff018080");
pub const DAO_PROPOSAL_VALIDATOR_HASH: [u8; 32] =
    hex!("92209b0f7efb2dbaaaa3aab94dcadcafa9d008d39661763841c7d92065b3fd34");

/// ```text
/// (mod (
///     ; first hash
///     PROPOSAL_TIMER_MOD_HASH  ; proposal timer needs to know which proposal created it
///     SINGLETON_MOD_HASH
///     LAUNCHER_PUZZLE_HASH
///     CAT_MOD_HASH
///     DAO_FINISHED_STATE_MOD_HASH
///     TREASURY_MOD_HASH
///     LOCKUP_SELF_HASH
///     CAT_TAIL_HASH
///     TREASURY_ID
///     ; second hash
///     SELF_HASH
///     SINGLETON_ID
///     PROPOSED_PUZ_HASH  ; this is what runs if this proposal is successful - the inner puzzle of this proposal
///     YES_VOTES  ; yes votes are +1, no votes don't tally - we compare yes_votes/total_votes at the end
///     TOTAL_VOTES  ; how many people responded
///     ; solution
///     vote_amounts_or_proposal_validator_hash  ; The qty of "votes" to add or subtract. ALWAYS POSITIVE.
///     vote_info  ; vote_info is whether we are voting YES or NO. XXX rename vote_type?
///     vote_coin_ids_or_proposal_timelock_length  ; this is either the coin ID we're taking a vote from
///     previous_votes_or_pass_margin  ; this is the active votes of the lockup we're communicating with
///     ; OR this is what percentage of the total votes must be YES - represented as an integer from 0 to 10,000 - typically this is set at 5100 (51%)
///     lockup_innerpuzhashes_or_attendance_required  ; this is either the innerpuz of the locked up CAT we're taking a vote from OR
///     ; the attendance required - the percentage of the current issuance which must have voted represented as 0 to 10,000 - this is announced by the treasury
///     innerpuz_reveal  ; this is only added during the first vote
///     soft_close_length  ; revealed by the treasury - 0 in add vote case
///     self_destruct_time  ; revealed by the treasury
///     oracle_spend_delay  ; used to recreate the treasury
///     self_destruct_flag  ; if not 0, do the self-destruct spend
///     my_amount
///   )
///   (include condition_codes.clib)
///   (include utility_macros.clib)
///   (include curry-and-treehash.clib)
///   (include *standard-cl-21*)
///
///   (defconstant TEN_THOUSAND 10000)
///
///   (defun is_member (e L)
///     (if L
///         (if (= e (f L))
///             1
///             (is_member e (r L))
///         )
///         0
///     )
///   )
///
///   (defun-inline calculate_win_percentage (TOTAL PERCENTAGE)
///     (f (divmod (* TOTAL PERCENTAGE) TEN_THOUSAND))
///   )
///
///   (defun calculate_finished_state (singleton_struct DAO_FINISHED_STATE_MOD_HASH)
///     (puzzle-hash-of-curried-function DAO_FINISHED_STATE_MOD_HASH
///       (sha256 ONE DAO_FINISHED_STATE_MOD_HASH)
///       (sha256tree singleton_struct)
///     )
///   )
///
///   (defun calculate_timer_puzhash (
///       PROPOSAL_TIMER_MOD_HASH
///       SELF_HASH
///       MY_SINGLETON_STRUCT
///     )
///     (puzzle-hash-of-curried-function PROPOSAL_TIMER_MOD_HASH
///       (sha256tree MY_SINGLETON_STRUCT)
///       (sha256 ONE SELF_HASH)
///     )
///   )
///
///   (defun calculate_lockup_puzzlehash (
///       LOCKUP_SELF_HASH
///       previous_votes
///       lockup_innerpuzhash
///     )
///     (puzzle-hash-of-curried-function LOCKUP_SELF_HASH
///       lockup_innerpuzhash
///       (sha256tree previous_votes)
///       (sha256 ONE LOCKUP_SELF_HASH)
///     )
///   )
///
///   (defun recreate_self (
///       SELF_HASH
///       PROPOSAL_ID
///       PROPOSED_PUZ_HASH
///       YES_VOTES
///       TOTAL_VOTES
///     )
///     (puzzle-hash-of-curried-function SELF_HASH
///       (sha256 ONE TOTAL_VOTES)
///       (sha256 ONE YES_VOTES)
///       (sha256 ONE PROPOSED_PUZ_HASH)
///       (sha256 ONE PROPOSAL_ID)
///       (sha256 ONE SELF_HASH)
///     )
///   )
///
///   (defun wrap_in_cat_layer (CAT_MOD_HASH CAT_TAIL_HASH INNERPUZHASH)
///     (puzzle-hash-of-curried-function CAT_MOD_HASH
///       INNERPUZHASH
///       (sha256 ONE CAT_TAIL_HASH)
///       (sha256 ONE CAT_MOD_HASH)
///     )
///   )
///
///   (defun calculate_singleton_puzzle_hash (PROPOSAL_SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (f PROPOSAL_SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree PROPOSAL_SINGLETON_STRUCT)
///     )
///   )
///
///   (defun calculate_treasury_puzzlehash (
///       treasury_singleton_struct
///       TREASURY_MOD_HASH
///       PROPOSAL_VALIDATOR_HASH
///       PROPOSAL_LENGTH
///       PROPOSAL_SOFTCLOSE_LENGTH
///       attendance_required
///       pass_percentage
///       self_destruct_time
///       oracle_spend_delay
///     )
///
///     (calculate_singleton_puzzle_hash treasury_singleton_struct
///       (puzzle-hash-of-curried-function TREASURY_MOD_HASH
///         (sha256 ONE oracle_spend_delay)
///         (sha256 ONE self_destruct_time)
///         (sha256 ONE pass_percentage)
///         (sha256 ONE attendance_required)
///         (sha256 ONE PROPOSAL_SOFTCLOSE_LENGTH)
///         (sha256 ONE PROPOSAL_LENGTH)
///         PROPOSAL_VALIDATOR_HASH
///         (sha256 ONE TREASURY_MOD_HASH)
///       )
///     )
///   )
///
///   (defun loop_over_vote_coins (
///       SINGLETON_ID
///       LOCKUP_SELF_HASH
///       CAT_MOD_HASH
///       CAT_TAIL_HASH
///       TREASURY_ID
///       SELF_HASH
///       YES_VOTES
///       TOTAL_VOTES
///       PROPOSED_PUZ_HASH
///       coin_id_list
///       vote_amount_list
///       previous_votes
///       lockup_innerpuzhashes
///       vote_info
///       sum
///       output
///       my_amount
///       distinct_ids
///     )
///     (if coin_id_list
///         (if (> (f vote_amount_list) 0)
///             (c
///               (list CREATE_PUZZLE_ANNOUNCEMENT (f coin_id_list))
///               (c
///                 (list
///                   ASSERT_PUZZLE_ANNOUNCEMENT  ; take the vote
///                   (sha256
///                     (wrap_in_cat_layer
///                       CAT_MOD_HASH
///                       CAT_TAIL_HASH
///                       (calculate_lockup_puzzlehash  ; because the message comes from
///                         LOCKUP_SELF_HASH
///                         (f previous_votes)
///                         (f lockup_innerpuzhashes)
///                       )
///                     )
///                     (sha256tree (list SINGLETON_ID (f vote_amount_list) vote_info (f coin_id_list)))
///                   )
///                 )
///                 (loop_over_vote_coins
///                   SINGLETON_ID
///                   LOCKUP_SELF_HASH
///                   CAT_MOD_HASH
///                   CAT_TAIL_HASH
///                   TREASURY_ID
///                   SELF_HASH
///                   YES_VOTES
///                   TOTAL_VOTES
///                   PROPOSED_PUZ_HASH
///                   (r coin_id_list)
///                   (r vote_amount_list)
///                   (r previous_votes)
///                   (r lockup_innerpuzhashes)
///                   vote_info
///                   (+ (f vote_amount_list) sum)
///                   output
///                   my_amount
///                   (if (is_member (f coin_id_list) distinct_ids) (x) (c (f coin_id_list) distinct_ids))
///                 )
///               )
///             )
///             (x)
///         )
///         (c
///           (list
///             CREATE_COIN  ; recreate self with vote information added
///             (recreate_self
///               SELF_HASH
///               SINGLETON_ID
///               PROPOSED_PUZ_HASH
///               (if vote_info (+ YES_VOTES sum) YES_VOTES)
///               (+ TOTAL_VOTES sum)
///             )
///             my_amount
///             (list TREASURY_ID)  ; hint to Treasury ID so people can find it
///           )
///           (c
///             (list ASSERT_MY_AMOUNT my_amount)
///             (if TOTAL_VOTES
///                 (c (list ASSERT_HEIGHT_RELATIVE 1) output)
///                 output
///             )
///           )
///         )
///     )
///
///   )
///
///
///   (if self_destruct_flag
///       ; assert self_destruct_time > proposal_timelock_length
///       ; this is the code path for if we've not been accepted by the treasury for a long time, and we're "bad" for some reason
///       (if (> self_destruct_time vote_coin_ids_or_proposal_timelock_length)
///           (list
///             (list CREATE_COIN (calculate_finished_state (c SINGLETON_MOD_HASH (c SINGLETON_ID LAUNCHER_PUZZLE_HASH)) DAO_FINISHED_STATE_MOD_HASH) ONE (list TREASURY_ID))
///             (list ASSERT_HEIGHT_RELATIVE self_destruct_time)
///             (list ASSERT_PUZZLE_ANNOUNCEMENT  ; make sure that we have a matching treasury oracle spend
///               (sha256
///                 (calculate_treasury_puzzlehash
///                   (c SINGLETON_MOD_HASH (c TREASURY_ID LAUNCHER_PUZZLE_HASH))
///                   TREASURY_MOD_HASH
///                   vote_amounts_or_proposal_validator_hash
///                   vote_coin_ids_or_proposal_timelock_length  ; check the veracity of these values by if the treasury uses them
///                   soft_close_length
///                   lockup_innerpuzhashes_or_attendance_required
///                   previous_votes_or_pass_margin
///                   self_destruct_time
///                   oracle_spend_delay
///                 )
///                 0  ; the arguments are secured implicitly in the puzzle of the treasury
///               )
///             )
///           )
///           (x)
///       )
///       ; We're not trying to self destruct
///       ; Check whether we have a soft close to either try closing the proposal or adding votes
///       ; soft_close_length is used to prevent people from spamming the proposal and preventing others from being able to vote.
///       ; Someone could add 1 'no' vote to the proposal in every block until the proposal timelock has passed and then close the proposal as failed.
///       ; soft_close_length imposes some fixed number of blocks have passed without the proposal being spent before it can be closed.
///       ; This means there will always be some time for people to vote if they want before a proposal is closed.
///       (if soft_close_length
///           ; Add the conditions which apply in both passed and failed cases
///           (c
///             (list ASSERT_HEIGHT_RELATIVE soft_close_length)
///             (c
///               (list CREATE_COIN (calculate_finished_state (c SINGLETON_MOD_HASH (c SINGLETON_ID LAUNCHER_PUZZLE_HASH)) DAO_FINISHED_STATE_MOD_HASH) ONE (list TREASURY_ID))
///               (c
///                 (list
///                   ASSERT_PUZZLE_ANNOUNCEMENT
///                   (sha256  ; external timer
///                     (calculate_timer_puzhash
///                       PROPOSAL_TIMER_MOD_HASH
///                       SELF_HASH
///                       (c SINGLETON_MOD_HASH (c SINGLETON_ID LAUNCHER_PUZZLE_HASH))
///
///                     )
///                     SINGLETON_ID
///                   )
///                 )
///                 (c
///                   (list CREATE_PUZZLE_ANNOUNCEMENT vote_coin_ids_or_proposal_timelock_length)
///                   ; We are trying to close the proposal, so check whether it passed or failed
///                   (if
///                     (all
///                       (gte TOTAL_VOTES lockup_innerpuzhashes_or_attendance_required)
///                       (gte YES_VOTES (calculate_win_percentage TOTAL_VOTES previous_votes_or_pass_margin))
///                     )
///                     ; Passed
///                     (list
///                       (list CREATE_COIN_ANNOUNCEMENT (sha256tree (list PROPOSED_PUZ_HASH 0)))  ; the 0 at the end is announcement_args in proposal_validators
///                       ; the above coin annnouncement lets us validate this coin in the proposal validator
///                       (list ASSERT_PUZZLE_ANNOUNCEMENT  ; make sure that we actually have a matching treasury spend
///                         (sha256
///                           (calculate_treasury_puzzlehash
///                             (c SINGLETON_MOD_HASH (c TREASURY_ID LAUNCHER_PUZZLE_HASH))
///                             TREASURY_MOD_HASH
///                             vote_amounts_or_proposal_validator_hash
///                             vote_coin_ids_or_proposal_timelock_length  ; check the veracity of these values by if the treasury uses them
///                             soft_close_length
///                             lockup_innerpuzhashes_or_attendance_required
///                             previous_votes_or_pass_margin
///                             self_destruct_time
///                             oracle_spend_delay
///                           )
///                           SINGLETON_ID  ; directed at singleton, but most values are implicitly announced in the puzzle
///                         )
///                       )
///                     )
///                     ; Failed
///                     (list
///                       (list ASSERT_PUZZLE_ANNOUNCEMENT  ; make sure that we verify solution values against the treasury's oracle spend
///                         (sha256
///                           (calculate_treasury_puzzlehash
///                             (c SINGLETON_MOD_HASH (c TREASURY_ID LAUNCHER_PUZZLE_HASH))
///                             TREASURY_MOD_HASH
///                             vote_amounts_or_proposal_validator_hash
///                             vote_coin_ids_or_proposal_timelock_length  ; check the veracity of these values by if the treasury uses them
///                             soft_close_length
///                             lockup_innerpuzhashes_or_attendance_required
///                             previous_votes_or_pass_margin
///                             self_destruct_time
///                             oracle_spend_delay
///                           )
///                           0  ; the arguments are secured implicitly in the puzzle of the treasury
///                         )
///                       )
///                     )
///                   )
///                 )
///               )
///             )
///           )
///
///
///           ; no soft_close_length so run the add votes path
///           (loop_over_vote_coins
///             SINGLETON_ID
///             LOCKUP_SELF_HASH
///             CAT_MOD_HASH
///             CAT_TAIL_HASH
///             TREASURY_ID
///             SELF_HASH
///             YES_VOTES
///             TOTAL_VOTES
///             PROPOSED_PUZ_HASH
///             vote_coin_ids_or_proposal_timelock_length
///             vote_amounts_or_proposal_validator_hash
///             previous_votes_or_pass_margin
///             lockup_innerpuzhashes_or_attendance_required
///             vote_info
///             0
///             (if (any YES_VOTES TOTAL_VOTES)  ; this prevents the timer from being created if the coin has been created with fake votes
///                 ()
///                 (c
///                   (list
///                     CREATE_COIN
///                     (calculate_timer_puzhash
///                       PROPOSAL_TIMER_MOD_HASH
///                       SELF_HASH
///                       (c SINGLETON_MOD_HASH (c SINGLETON_ID LAUNCHER_PUZZLE_HASH))  ; SINGLETON_STRUCT
///                     )
///                     0
///                   )
///                   (if (= (sha256tree innerpuz_reveal) PROPOSED_PUZ_HASH)  ; reveal the proposed code on chain with the first vote
///                       ()
///                       (x)
///                   )
///                 )
///             )
///             my_amount
///             ()
///           )
///       )
///   )
/// )
/// ```
pub const DAO_PROPOSAL: [u8; 3270] = hex!(" ");
pub const DAO_PROPOSAL_HASH: [u8; 32] =
    hex!("fe6d5c0373c1750598d137ce50b5b025a203655ccab4ab3329315abad49c3586");

/// ```text
/// (mod (
///     TREASURY_SINGLETON_STRUCT
///     CAT_MOD_HASH
///     CONDITIONS  ; XCK conditions, to be generated by the treasury
///     LIST_OF_TAILHASH_CONDITIONS  ; the delegated puzzlehash must be curried in to the proposal.
///     ; Puzzlehash is only run in the last coin for that asset
///     ; ((TAIL_HASH CONDITIONS) (TAIL_HASH CONDITIONS)... )
///     P2_SINGLETON_VIA_DELEGATED_PUZZLE_PUZHASH
///     p2_singleton_parent_amount_list  ; for xck this is just a list of (coin_parent coin_amount)
///     p2_singleton_tailhash_parent_amount_list  ; list of ((asset (parent amount) (parent amount)... ) (asset (parent amount)... )... ),
///     ; must match order of curryed asset list
///     ; the last (parent amount) gets given the puzzlehash, the rest get given 0
///     treasury_inner_puzhash
///   )
///   ; we need to track CAT_TYPE and DELEGATED_PUZZLE
///   ; list of (asset_type (parent amount))
///
///   ; If you're writing a proposal you'll want to use this layer
///   ; if you don't, your proposal might be invalidated if the p2_singleton coins get spent
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include utility_macros.clib)
///   (include *standard-cl-21*)
///
///   (defun-inline calculate_singleton_puzzle_hash (PROPOSAL_SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (f PROPOSAL_SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree PROPOSAL_SINGLETON_STRUCT)
///     )
///   )
///
///   (defun loop_through_list (
///       TREASURY_SINGLETON_STRUCT
///       SPEND_AMOUNT
///       P2_SINGLETON_PUZHASH
///       p2_calculated
///       p2_singleton_list
///       total
///       output
///     )
///     (c
///       (list CREATE_PUZZLE_ANNOUNCEMENT (sha256tree (list p2_calculated (sha256tree 0))))
///       (c
///         (list ASSERT_COIN_ANNOUNCEMENT (sha256 p2_calculated '$'))
///         (if p2_singleton_list
///             (loop_through_list
///               TREASURY_SINGLETON_STRUCT
///               SPEND_AMOUNT
///               P2_SINGLETON_PUZHASH
///               (calculate_coin_id (f (f p2_singleton_list)) P2_SINGLETON_PUZHASH (f (r (f p2_singleton_list))))
///               (r p2_singleton_list)
///               (+ total (f (r (f p2_singleton_list))))
///               output
///             )
///             (if (> (- total SPEND_AMOUNT) 0)
///                 (c
///                   (list CREATE_COIN P2_SINGLETON_PUZHASH (- total SPEND_AMOUNT) (list P2_SINGLETON_PUZHASH))
///                   output
///                 )
///                 output
///             )
///         )
///       )
///     )
///   )
///
///   (defun add_announcements_to_result (p2_calculated delegated_puzhash output)
///     (c
///       (list CREATE_PUZZLE_ANNOUNCEMENT (sha256tree (list p2_calculated delegated_puzhash)))
///       (c
///         (list ASSERT_COIN_ANNOUNCEMENT (sha256 p2_calculated '$'))
///         output
///       )
///     )
///   )
///
///   (defun sum_create_coins (conditions)
///     (if conditions
///         (+
///           (if
///             (= (f (f conditions)) CREATE_COIN)
///             (if
///               (> (f (r (r (f conditions)))) 0)  ; make an exception for -113 and other magic conditions
///               (f (r (r (f conditions))))
///               0
///             )
///             0
///           )
///           (sum_create_coins (r conditions))
///         )
///         0
///     )
///   )
///
///   (defun-inline calculate_delegated_puzzlehash (CONDITIONS)
///     (sha256tree (c ONE CONDITIONS))  ; this makes (q . CONDITIONS)
///   )
///
///   (defun wrap_in_cat_layer (CAT_MOD_HASH CAT_TAIL_HASH INNERPUZHASH)
///     (puzzle-hash-of-curried-function CAT_MOD_HASH
///       INNERPUZHASH
///       (sha256 ONE CAT_TAIL_HASH)
///       (sha256 ONE CAT_MOD_HASH)
///     )
///   )
///
///   (defun dedupe ((@ lst ((@ first (parent amount)) . rest)) ids)
///     (if lst
///         (let ((id (sha256 parent amount)))
///           (if (in id ids)
///               (dedupe rest ids)
///               (c first (dedupe rest (c id ids)))
///           )
///         )
///         ()
///     )
///   )
///
///
///   ; for a given asset type, loop through the cat coins and generate the announcements required for each
///   (defun for_each_asset (
///       TREASURY_SINGLETON_STRUCT
///       CAT_MOD_HASH
///       CONDITIONS_FOR_THIS_ASSET_TYPE
///       P2_SINGLETON_PUZHASH
///       p2_singleton_puzzle_hash
///       parent_amount_list
///       total
///       create_coin_sum
///       output
///     )
///     (if parent_amount_list
///         (add_announcements_to_result
///           (calculate_coin_id (f (f parent_amount_list)) p2_singleton_puzzle_hash (f (r (f parent_amount_list))))
///           (if
///             (r parent_amount_list)  ; this is the delegated_puzhash
///             (sha256tree 0)  ; most coins destroy themselves
///             (calculate_delegated_puzzlehash  ; the last coin creates the conditions
///               (let ((coin_sum (- (+ total (f (r (f parent_amount_list)))) create_coin_sum)))
///                 (if (> coin_sum 0)
///                     (c
///                       (list CREATE_COIN P2_SINGLETON_PUZHASH coin_sum (list P2_SINGLETON_PUZHASH))
///                       CONDITIONS_FOR_THIS_ASSET_TYPE
///                     )
///                     CONDITIONS_FOR_THIS_ASSET_TYPE
///               ))
///             )
///           )
///           (for_each_asset
///             TREASURY_SINGLETON_STRUCT
///             CAT_MOD_HASH
///             CONDITIONS_FOR_THIS_ASSET_TYPE
///             P2_SINGLETON_PUZHASH
///             p2_singleton_puzzle_hash
///             (r parent_amount_list)
///             (+ total (f (r (f parent_amount_list))))
///             create_coin_sum
///             output
///           )
///         )
///         output
///     )
///   )
///
///   ; loops through the list of ((tailhash conditions))
///   (defun for_each_asset_type (
///       TREASURY_SINGLETON_STRUCT
///       CAT_MOD_HASH
///       P2_SINGLETON_PUZHASH
///       LIST_OF_TAILHASH_CONDITIONS
///       p2_singleton_tailhash_parent_amount_list  ; ((tailhash ((parent amount) (parent_amount)... ) (tailhash (parent amount))..)
///       output
///     )
///     (if LIST_OF_TAILHASH_CONDITIONS
///         (for_each_asset_type
///           TREASURY_SINGLETON_STRUCT
///           CAT_MOD_HASH
///           P2_SINGLETON_PUZHASH
///           (r LIST_OF_TAILHASH_CONDITIONS)
///           (r p2_singleton_tailhash_parent_amount_list)
///           (for_each_asset
///             TREASURY_SINGLETON_STRUCT
///             CAT_MOD_HASH
///             (if
///               (=
///                 (f (f LIST_OF_TAILHASH_CONDITIONS))
///                 (f (f p2_singleton_tailhash_parent_amount_list))
///               )
///               (f (r (f LIST_OF_TAILHASH_CONDITIONS)))
///               (x)  ; bad solution format
///             )
///             P2_SINGLETON_PUZHASH
///             (wrap_in_cat_layer CAT_MOD_HASH (f (f p2_singleton_tailhash_parent_amount_list)) P2_SINGLETON_PUZHASH)  ; p2_singleton_puzzle_hash
///             (dedupe (f (r (f p2_singleton_tailhash_parent_amount_list))) 0 0)  ; list of ((parent amount) (parent amount)...)
///             0  ; current total - initialise as 0
///             (sum_create_coins (f (r (f LIST_OF_TAILHASH_CONDITIONS))))
///             output  ; add new conditions to previous calculated output conditions
///           )
///         )
///         output  ; at the end of the loop output our calculated conditions
///     )
///   )
///
///
///   ; main
///   (c
///     (list ASSERT_MY_PUZZLEHASH (calculate_singleton_puzzle_hash TREASURY_SINGLETON_STRUCT treasury_inner_puzhash))
///     (c
///       (list CREATE_COIN treasury_inner_puzhash ONE (list (f (r TREASURY_SINGLETON_STRUCT))))
///       (if CONDITIONS
///           (loop_through_list
///             TREASURY_SINGLETON_STRUCT
///             (sum_create_coins CONDITIONS)
///             P2_SINGLETON_VIA_DELEGATED_PUZZLE_PUZHASH
///             (if p2_singleton_parent_amount_list (calculate_coin_id (f (f p2_singleton_parent_amount_list)) P2_SINGLETON_VIA_DELEGATED_PUZZLE_PUZHASH (f (r (f p2_singleton_parent_amount_list)))) ())
///             (if p2_singleton_parent_amount_list (r p2_singleton_parent_amount_list) ())
///             (if p2_singleton_parent_amount_list (f (r (f p2_singleton_parent_amount_list))) ())
///             (for_each_asset_type
///               TREASURY_SINGLETON_STRUCT
///               CAT_MOD_HASH
///               P2_SINGLETON_VIA_DELEGATED_PUZZLE_PUZHASH
///               LIST_OF_TAILHASH_CONDITIONS
///               p2_singleton_tailhash_parent_amount_list  ; ((tailhash ((parent amount) (parent_amount)... ) (tailhash (parent amount))..)
///               CONDITIONS
///             )
///           )
///           (for_each_asset_type
///             TREASURY_SINGLETON_STRUCT
///             CAT_MOD_HASH
///             P2_SINGLETON_VIA_DELEGATED_PUZZLE_PUZHASH
///             LIST_OF_TAILHASH_CONDITIONS
///             p2_singleton_tailhash_parent_amount_list  ; ((tailhash ((parent amount) (parent_amount)... ) (tailhash (parent amount))..)
///             CONDITIONS
///           )
///       )
///     )
///   )
///
/// )
/// ```
pub const DAO_SPEND_P2_SINGLETON: [u8; 2954] = hex!(" ");
pub const DAO_SPEND_P2_SINGLETON_HASH: [u8; 32] =
    hex!("7bc8942159e600f56a87e1d9c059c8705307ec2fb996a949503298dedfed00be");

/// ```text
/// (mod
///   (
///     TREASURY_MOD_HASH
///     PROPOSAL_VALIDATOR  ; this is the curryed proposal validator
///     PROPOSAL_LENGTH
///     PROPOSAL_SOFTCLOSE_LENGTH
///     ATTENDANCE_REQUIRED
///     PASS_MARGIN  ; this is a percentage 0 - 10,000 - 51% would be 5100
///     PROPOSAL_SELF_DESTRUCT_TIME  ; time in seconds after which proposals can be automatically closed
///     ORACLE_SPEND_DELAY  ; timelock delay for oracle spend
///     (@ proposal_announcement (announcement_source delegated_puzzle_hash announcement_args))
///     proposal_validator_solution
///     delegated_puzzle_reveal  ; this is the reveal of the puzzle announced by the proposal
///     delegated_solution  ; this is not secure unless the delegated puzzle secures it
///     my_singleton_struct
///   )
///   (include utility_macros.clib)
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include *standard-cl-21*)
///
///   (defun-inline recreate_self (
///       TREASURY_MOD_HASH
///       PROPOSAL_VALIDATOR
///       PROPOSAL_LENGTH
///       PROPOSAL_SOFTCLOSE_LENGTH
///       ATTENDANCE_REQUIRED
///       PASS_MARGIN
///       PROPOSAL_SELF_DESTRUCT_TIME
///       ORACLE_SPEND_DELAY
///     )
///     (puzzle-hash-of-curried-function TREASURY_MOD_HASH
///       (sha256 ONE ORACLE_SPEND_DELAY)
///       (sha256 ONE PROPOSAL_SELF_DESTRUCT_TIME)
///       (sha256 ONE PASS_MARGIN)
///       (sha256 ONE ATTENDANCE_REQUIRED)
///       (sha256 ONE PROPOSAL_SOFTCLOSE_LENGTH)
///       (sha256 ONE PROPOSAL_LENGTH)
///       (sha256tree PROPOSAL_VALIDATOR)
///       (sha256 ONE TREASURY_MOD_HASH)
///     )
///   )
///
///   (defun calculate_singleton_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (f SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree SINGLETON_STRUCT)
///     )
///   )
///
///   (defun stager (ORACLE_SPEND_DELAY my_inner_puzhash singleton_struct)
///     (c
///       (if singleton_struct
///           (list ASSERT_MY_COIN_ID
///             (calculate_coin_id
///               (f (r singleton_struct))
///               (calculate_singleton_puzzle_hash singleton_struct my_inner_puzhash)
///               ONE
///             )
///             ;; TODO: When the new condition codes are available, use ASSERT_EPHEMERAL to ensure this
///             ;; spend path is only used in the eve spend.
///             ;; (list ASSERT_EPHEMERAL)
///           )
///           (list ASSERT_HEIGHT_RELATIVE ORACLE_SPEND_DELAY)
///       )
///       (list (list CREATE_COIN my_inner_puzhash ONE))
///     )
///   )
///
///   (c
///     (list CREATE_PUZZLE_ANNOUNCEMENT 0)  ; the arguments are secured implicitly in the puzzle of the treasury
///     (if delegated_puzzle_reveal
///         ; if we're checking a proposal (testing if it has passed)
///         (if (= (sha256tree delegated_puzzle_reveal) delegated_puzzle_hash)
///             ; Merge the treasury conditions with the proposal validator conditions
///             ; If the update case then the validator returns the new treasury create coin
///             ; If the spend case then we need to recreate the treasury outselves
///             ; treasury specific conditions
///
///             (c
///               (list ASSERT_COIN_ANNOUNCEMENT (sha256 announcement_source (sha256tree (list delegated_puzzle_hash announcement_args))))  ; announcement source is validated inside the ProposalValidator
///               (c
///                 (list ASSERT_HEIGHT_RELATIVE 1)
///                 (a
///                   PROPOSAL_VALIDATOR
///                   (list
///                     ATTENDANCE_REQUIRED
///                     PASS_MARGIN
///                     proposal_announcement
///                     proposal_validator_solution
///                     (a delegated_puzzle_reveal delegated_solution)
///                   )
///                 )
///               )
///             )
///             (x)
///         )
///         ; no proposal_flag so create the oracle announcement
///         (stager
///           ORACLE_SPEND_DELAY
///           (recreate_self
///             TREASURY_MOD_HASH
///             PROPOSAL_VALIDATOR
///             PROPOSAL_LENGTH
///             PROPOSAL_SOFTCLOSE_LENGTH
///             ATTENDANCE_REQUIRED
///             PASS_MARGIN
///             PROPOSAL_SELF_DESTRUCT_TIME
///             ORACLE_SPEND_DELAY
///           )
///           my_singleton_struct
///         )
///     )
///   )
/// )
/// ```
pub const DAO_TREASURY: [u8; 1200] = hex!("ff02ffff01ff04ffff04ffff013effff04ffff0180ffff01808080ffff02ffff03ff8217ffffff01ff02ffff01ff02ffff03ffff09ffff02ff0affff04ff02ffff04ff8217ffff80808080ff8215ff80ffff01ff02ffff01ff04ffff04ffff013dffff04ffff0bff8209ffffff02ff0affff04ff02ffff04ffff04ff8215ffffff04ff822dffffff01808080ff8080808080ffff01808080ffff04ffff04ffff0152ffff04ffff0101ffff01808080ffff02ff0bffff04ff5fffff04ff8200bfffff04ff8205ffffff04ff820bffffff04ffff02ff8217ffff822fff80ffff01808080808080808080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff02ff1effff04ff02ffff04ff8202ffffff04ffff02ff14ffff04ff02ffff04ff05ffff04ffff0bffff0101ff8202ff80ffff04ffff0bffff0101ff82017f80ffff04ffff0bffff0101ff8200bf80ffff04ffff0bffff0101ff5f80ffff04ffff0bffff0101ff2f80ffff04ffff0bffff0101ff1780ffff04ffff02ff0affff04ff02ffff04ff0bff80808080ffff04ffff0bffff0101ff0580ff808080808080808080808080ffff04ff825fffff808080808080ff018080ff018080ffff04ffff01ffffff02ffff03ff05ffff01ff02ffff01ff02ff08ffff04ff02ffff04ffff06ff0580ffff04ffff0bffff0102ffff0bffff0101ffff010480ffff0bffff0102ffff0bffff0102ffff0bffff0101ffff010180ffff05ff058080ffff0bffff0102ff0bffff0bffff0101ffff018080808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ffff0bffff0102ffff01a0a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222ffff0bffff0102ffff0bffff0102ffff01a09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ff0580ffff0bffff0102ffff02ff08ffff04ff02ffff04ff07ffff01ffa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b280808080ffff01a04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a808080ff02ffff03ffff22ffff09ffff0dff0580ffff012080ffff09ffff0dff0b80ffff012080ffff15ff17ffff0181ff8080ffff01ff02ffff01ff0bff05ff0bff1780ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ffff03ffff07ff0580ffff01ff02ffff01ff0bffff0102ffff02ff0affff04ff02ffff04ffff05ff0580ff80808080ffff02ff0affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0bffff0101ff0580ff018080ff0180ffff02ff14ffff04ff02ffff04ff09ffff04ff0bffff04ffff02ff0affff04ff02ffff04ff05ff80808080ff808080808080ff04ffff02ffff03ff17ffff01ff02ffff01ff04ffff0146ffff04ffff02ff1cffff04ff02ffff04ffff05ffff06ff178080ffff04ffff02ff16ffff04ff02ffff04ff17ffff04ff0bff8080808080ffff04ffff0101ff808080808080ffff01808080ff0180ffff01ff02ffff01ff04ffff0152ffff04ff05ffff01808080ff018080ff0180ffff04ffff04ffff0133ffff04ff0bffff01ff01808080ff808080ff018080");
pub const DAO_TREASURY_HASH: [u8; 32] =
    hex!("637d78acd395b6bb03211bcfc5f5f2e878cba2d62b2f53871d49a8b928411b19");

/// ```text
/// (mod
///   (
///     TREASURY_MOD_HASH
///     VALIDATOR_MOD_HASH
///     SINGLETON_STRUCT  ; (SINGLETON_MOD_HASH (SINGLETON_ID . LAUNCHER_PUZZLE_HASH))
///     PROPOSAL_SELF_HASH
///     PROPOSAL_MINIMUM_AMOUNT
///     PROPOSAL_EXCESS_PAYOUT_PUZHASH
///     PROPOSAL_LENGTH
///     PROPOSAL_SOFTCLOSE_LENGTH
///     ATTENDANCE_REQUIRED
///     PASS_MARGIN
///     PROPOSAL_SELF_DESTRUCT_TIME
///     ORACLE_SPEND_DELAY
///   )
///   ;; This is a proposal to update treasury conditions for a DAO
///
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include *standard-cl-21*)
///   (include utility_macros.clib)
///
///   (list
///     (list CREATE_COIN
///       (puzzle-hash-of-curried-function TREASURY_MOD_HASH
///         (sha256 ONE ORACLE_SPEND_DELAY)
///         (sha256 ONE PROPOSAL_SELF_DESTRUCT_TIME)
///         (sha256 ONE PASS_MARGIN)
///         (sha256 ONE ATTENDANCE_REQUIRED)
///         (sha256 ONE PROPOSAL_SOFTCLOSE_LENGTH)
///         (sha256 ONE PROPOSAL_LENGTH)
///         (puzzle-hash-of-curried-function VALIDATOR_MOD_HASH
///           (sha256 ONE PROPOSAL_EXCESS_PAYOUT_PUZHASH)
///           (sha256 ONE PROPOSAL_MINIMUM_AMOUNT)
///           (sha256 ONE PROPOSAL_SELF_HASH)
///           (sha256tree SINGLETON_STRUCT)
///         )
///         (sha256 ONE TREASURY_MOD_HASH)
///       )
///       ONE
///     )
///   )
/// )
/// ```
pub const DAO_UPDATE_PROPOSAL: [u8; 705] = hex!("ff02ffff01ff04ffff04ffff0133ffff04ffff02ff0affff04ff02ffff04ff05ffff04ffff0bffff0101ff822fff80ffff04ffff0bffff0101ff8217ff80ffff04ffff0bffff0101ff820bff80ffff04ffff0bffff0101ff8205ff80ffff04ffff0bffff0101ff8202ff80ffff04ffff0bffff0101ff82017f80ffff04ffff02ff0affff04ff02ffff04ff0bffff04ffff0bffff0101ff8200bf80ffff04ffff0bffff0101ff5f80ffff04ffff0bffff0101ff2f80ffff04ffff02ff0effff04ff02ffff04ff17ff80808080ff8080808080808080ffff04ffff0bffff0101ff0580ff808080808080808080808080ffff04ffff0101ffff0180808080ffff018080ffff04ffff01ffff02ffff03ff05ffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff06ff0580ffff04ffff0bffff0102ffff0bffff0101ffff010480ffff0bffff0102ffff0bffff0102ffff0bffff0101ffff010180ffff05ff058080ffff0bffff0102ff0bffff0bffff0101ffff018080808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ffff0bffff0102ffff01a0a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222ffff0bffff0102ffff0bffff0102ffff01a09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ff0580ffff0bffff0102ffff02ff04ffff04ff02ffff04ff07ffff01ffa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b280808080ffff01a04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a808080ff02ffff03ffff07ff0580ffff01ff02ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ffff05ff0580ff80808080ffff02ff0effff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0bffff0101ff0580ff018080ff0180ff018080");
pub const DAO_UPDATE_PROPOSAL_HASH: [u8; 32] =
    hex!("fc032384cfece9b542c3e1ea77ba119fb1013a3d74b622302c0b670447e4343d");

/// ```text
/// ; The DID innerpuzzle is designed to sit inside the singleton layer and provide functionality related to being an identity.
/// ; At the moment the two pieces of functionality are recovery and message creation.
/// ; A DID's ID is it's Singleton ID
/// ; Recovery is based around having a list of known other DIDs which can send messages approving you change the innerpuzzle of your DID singleton
///
/// (mod
///   (
///     INNER_PUZZLE  ; Standard P2 inner puzzle, used to record the ownership of the DID.
///     RECOVERY_DID_LIST_HASH  ; the list of DIDs that can send messages to you for recovery we store only the hash so that we don't have to reveal every time we make a message spend
///     NUM_VERIFICATIONS_REQUIRED  ; how many of the above list are required for a recovery
///     SINGLETON_STRUCT  ; my singleton_struct, formerly a Truth - ((SINGLETON_MOD_HASH, (LAUNCHER_ID, LAUNCHER_PUZZLE_HASH)))
///     METADATA  ; Customized metadata, e.g KYC info
///     mode  ; this indicates which spend mode we want. 0. Recovery mode 1. Run INNER_PUZZLE with p2_solution
///     my_amount_or_inner_solution  ; In mode 0, we use this to recover our coin and assert it is our actual amount
///     ; In mode 1 this is the solution of the inner P2 puzzle, only required in the create message mode and transfer mode.
///     new_inner_puzhash  ; In recovery mode, this will be the new wallet DID puzzle hash
///     parent_innerpuzhash_amounts_for_recovery_ids  ; during a recovery we need extra information about our recovery list coins
///     pubkey  ; this is the new pubkey used for a recovery
///     recovery_list_reveal  ; this is the reveal of the stored list of DIDs approved for recovery
///     my_id  ; my coin ID
///   )
///   ;message is the new puzzle in the recovery and standard spend cases
///
///   ;MOD_HASH, MY_PUBKEY, RECOVERY_DID_LIST_HASH are curried into the puzzle
///   ;EXAMPLE SOLUTION (0xcafef00d 0x12341234 0x923bf9a7856b19d335a65f12d68957d497e1f0c16c0e14baf6d120e60753a1ce 2 1 100 (q "source code") 0xdeadbeef 0xcafef00d ((0xdadadada 0xdad5dad5 200) () (0xfafafafa 0xfaf5faf5 200)) 0xfadeddab (0x22222222 0x33333333 0x44444444))
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   ; takes a lisp tree and returns the hash of it
///   (defun sha256tree1 (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   ; recovery message module - gets values curried in to make the puzzle
///   (defun make_message_puzzle (recovering_coin newpuz pubkey)
///     (qq (q . (((unquote CREATE_COIN_ANNOUNCEMENT) (unquote recovering_coin)) ((unquote AGG_SIG_UNSAFE) (unquote pubkey) (unquote newpuz)))))
///   )
///
///   ; this function creates the assert announcement for each message coin approving a recovery
///   (defun-inline create_consume_message (coin_id my_id new_innerpuz pubkey)
///     (list ASSERT_COIN_ANNOUNCEMENT (sha256 (sha256 coin_id (sha256tree1 (make_message_puzzle my_id new_innerpuz pubkey))) my_id))
///   )
///
///   ; this function calculates a coin ID given the inner puzzle and singleton information
///   (defun create_coin_ID_for_recovery (SINGLETON_STRUCT launcher_id parent innerpuzhash amount)
///     (sha256 parent (calculate_full_puzzle_hash (c (f SINGLETON_STRUCT) (c launcher_id (r (r SINGLETON_STRUCT)))) innerpuzhash) amount)
///   )
///
///
///   ; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (defun-inline calculate_full_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (f SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree1 SINGLETON_STRUCT)
///     )
///   )
///
///   ; this loops over our identities to check list, and checks if we have been given parent information for this identity
///   ; the reason for this is because we might only require 3/5 of the IDs give approval messages for a recovery
///   ; if we have the information for an identity then we create a consume message using that information
///
///   (defun check_messages_from_identities (SINGLETON_STRUCT num_verifications_required identities my_id  new_puz parent_innerpuzhash_amounts_for_recovery_ids pubkey num_verifications)
///     (if identities
///         (if (f parent_innerpuzhash_amounts_for_recovery_ids)
///             ; if we have parent information then we should create a consume coin condition
///             (c
///               (create_consume_message
///                 ; create coin_id from DID
///                 (create_coin_ID_for_recovery
///                   SINGLETON_STRUCT
///                   (f identities)
///                   (f (f parent_innerpuzhash_amounts_for_recovery_ids))
///                   (f (r (f parent_innerpuzhash_amounts_for_recovery_ids)))
///                 (f (r (r (f parent_innerpuzhash_amounts_for_recovery_ids)))))
///                 my_id
///                 new_puz
///                 pubkey
///               )
///               (check_messages_from_identities
///                 SINGLETON_STRUCT
///                 num_verifications_required
///                 (r identities)
///                 my_id
///                 new_puz
///                 (r parent_innerpuzhash_amounts_for_recovery_ids)
///                 pubkey
///                 (+ num_verifications 1)
///               )
///             )
///             ; if no parent information found for this identity, move on to next in list
///             (check_messages_from_identities
///               SINGLETON_STRUCT
///               (r identities)
///               my_id
///               new_puz
///               (r parent_innerpuzhash_amounts_for_recovery_ids)
///               pubkey
///               num_verifications
///             )
///         )
///         ;if we're out of identites to check for, check we have enough
///         (if (> num_verifications (- num_verifications_required 1))
///             (list (list AGG_SIG_UNSAFE pubkey new_puz) )
///             (x)
///         )
///     )
///   )
///
///   ;Spend modes:
///   ;0 = recovery
///   ;1 = run the INNER_PUZZLE
///
///   ;MAIN
///   (if mode
///       ; mode 1 - run INNER_PUZZLE
///       (a INNER_PUZZLE my_amount_or_inner_solution)
///
///       ; mode 0 - recovery
///       (if (all (= (sha256tree1 recovery_list_reveal) RECOVERY_DID_LIST_HASH) (> NUM_VERIFICATIONS_REQUIRED 0))
///           (c (list ASSERT_MY_AMOUNT my_amount_or_inner_solution)
///             (c (list CREATE_COIN new_inner_puzhash my_amount_or_inner_solution (list new_inner_puzhash))
///               (c (list ASSERT_MY_COIN_ID my_id)
///                 (check_messages_from_identities SINGLETON_STRUCT NUM_VERIFICATIONS_REQUIRED recovery_list_reveal my_id new_inner_puzhash parent_innerpuzhash_amounts_for_recovery_ids pubkey 0)
///               )
///             )
///           )
///           (x)
///       )
///   )
/// )
/// ```
pub const DID_INNERPUZ: [u8; 1012] = hex!("ff02ffff01ff02ffff03ff81bfffff01ff02ff05ff82017f80ffff01ff02ffff03ffff22ffff09ffff02ff7effff04ff02ffff04ff8217ffff80808080ff0b80ffff15ff17ff808080ffff01ff04ffff04ff28ffff04ff82017fff808080ffff04ffff04ff34ffff04ff8202ffffff04ff82017fffff04ffff04ff8202ffff8080ff8080808080ffff04ffff04ff38ffff04ff822fffff808080ffff02ff26ffff04ff02ffff04ff2fffff04ff17ffff04ff8217ffffff04ff822fffffff04ff8202ffffff04ff8205ffffff04ff820bffffff01ff8080808080808080808080808080ffff01ff088080ff018080ff0180ffff04ffff01ffffffff313dff4946ffff0233ff3c04ffffff0101ff02ff02ffff03ff05ffff01ff02ff3affff04ff02ffff04ff0dffff04ffff0bff2affff0bff22ff3c80ffff0bff2affff0bff2affff0bff22ff3280ff0980ffff0bff2aff0bffff0bff22ff8080808080ff8080808080ffff010b80ff0180ffffff02ffff03ff17ffff01ff02ffff03ff82013fffff01ff04ffff04ff30ffff04ffff0bffff0bffff02ff36ffff04ff02ffff04ff05ffff04ff27ffff04ff82023fffff04ff82053fffff04ff820b3fff8080808080808080ffff02ff7effff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fffff04ff5fffff04ff82017fff808080808080ff8080808080ff2f80ff808080ffff02ff26ffff04ff02ffff04ff05ffff04ff0bffff04ff37ffff04ff2fffff04ff5fffff04ff8201bfffff04ff82017fffff04ffff10ff8202ffffff010180ff808080808080808080808080ffff01ff02ff26ffff04ff02ffff04ff05ffff04ff37ffff04ff2fffff04ff5fffff04ff8201bfffff04ff82017fffff04ff8202ffff8080808080808080808080ff0180ffff01ff02ffff03ffff15ff8202ffffff11ff0bffff01018080ffff01ff04ffff04ff20ffff04ff82017fffff04ff5fff80808080ff8080ffff01ff088080ff018080ff0180ff0bff17ffff02ff5effff04ff02ffff04ff09ffff04ff2fffff04ffff02ff7effff04ff02ffff04ffff04ff09ffff04ff0bff1d8080ff80808080ff808080808080ff5f80ffff04ffff0101ffff04ffff04ff2cffff04ff05ff808080ffff04ffff04ff20ffff04ff17ffff04ff0bff80808080ff80808080ffff0bff2affff0bff22ff2480ffff0bff2affff0bff2affff0bff22ff3280ff0580ffff0bff2affff02ff3affff04ff02ffff04ff07ffff04ffff0bff22ff2280ff8080808080ffff0bff22ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff7effff04ff02ffff04ff09ff80808080ffff02ff7effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const DID_INNERPUZ_HASH: [u8; 32] =
    hex!("33143d2bef64f14036742673afd158126b94284b4530a28c354fac202b0c910e");

/// ```text
/// (mod
///   (
///     INNER_PUZZLE
///     SINGLETON_STRUCTS
///     METADATA_LAYER_HASHES
///     VALUES_TO_PROVE  ; this is a list of BRANCHES in the merkle tree to prove (so as to prove a whole subtree)
///     proofs_of_inclusion
///     new_metadatas  ; (root . etc)
///     new_metadata_updaters
///     new_inner_puzs
///     inner_solution
///   )
///
///   (include condition_codes.clib)
///   (include merkle_utils.clib)
///   (include curry-and-treehash.clib)
///
///   (defmacro assert items
///     (if (r items)
///         (list if (f items) (c assert (r items)) (q . (x)))
///         (f items)
///     )
///   )
///
///   (defun-inline construct_singleton (SINGLETON_STRUCT METADATA_LAYER_HASH new_metadata new_metadata_updater new_inner_puz)
///     (puzzle-hash-of-curried-function (f SINGLETON_STRUCT)
///       (puzzle-hash-of-curried-function METADATA_LAYER_HASH
///         new_inner_puz
///         (sha256tree new_metadata_updater)
///         (sha256tree new_metadata)
///         (sha256tree METADATA_LAYER_HASH)
///       )
///       (sha256tree SINGLETON_STRUCT)
///     )
///   )
///
///   (defun verify_proofs (new_root VALUES_TO_PROVE proofs_of_inclusion)
///     (if proofs_of_inclusion
///         (assert (= new_root (simplify_merkle_proof_after_leaf (f VALUES_TO_PROVE) (f proofs_of_inclusion)))
///           ; then
///           (verify_proofs new_root (r VALUES_TO_PROVE) (r proofs_of_inclusion))
///         )
///         1
///     )
///   )
///
///   (defun loop_over_curried_params
///     (
///       SINGLETON_STRUCTS
///       METADATA_LAYER_HASHES
///       VALUES_TO_PROVE
///       proofs_of_inclusion
///       new_metadatas
///       new_metadata_updaters
///       new_inner_puzs
///       conditions
///     )
///
///     (if SINGLETON_STRUCTS
///         (assert (verify_proofs (f (f new_metadatas)) (f VALUES_TO_PROVE) (f proofs_of_inclusion))
///           ; then
///           (loop_over_curried_params
///             (r SINGLETON_STRUCTS)
///             (r METADATA_LAYER_HASHES)
///             (r VALUES_TO_PROVE)
///             (r proofs_of_inclusion)
///             (r new_metadatas)
///             (r new_metadata_updaters)
///             (r new_inner_puzs)
///             (c
///               (list
///                 ASSERT_PUZZLE_ANNOUNCEMENT
///                 (sha256
///                   (construct_singleton (f SINGLETON_STRUCTS) (f METADATA_LAYER_HASHES) (f new_metadatas) (f new_metadata_updaters) (f new_inner_puzs))
///                   '$'
///                 )
///               )
///               conditions
///             )
///           )
///         )
///         conditions
///     )
///   )
///
///   (if proofs_of_inclusion
///       (loop_over_curried_params
///         SINGLETON_STRUCTS
///         METADATA_LAYER_HASHES
///         VALUES_TO_PROVE
///         proofs_of_inclusion
///         new_metadatas
///         new_metadata_updaters
///         new_inner_puzs
///         (a INNER_PUZZLE inner_solution)
///       )
///       ; You may want to run the puzzle without a raise to examine conditions so we'll make a "blessed" way to fail
///       (c (list ASSERT_MY_AMOUNT -1) (a INNER_PUZZLE inner_solution))
///   )
/// )
/// ```
pub const GRAFTROOT_DL_OFFERS: [u8; 922] = hex!("ff02ffff01ff02ffff03ff5fffff01ff02ff3affff04ff02ffff04ff0bffff04ff17ffff04ff2fffff04ff5fffff04ff81bfffff04ff82017fffff04ff8202ffffff04ffff02ff05ff8205ff80ff8080808080808080808080ffff01ff04ffff04ff10ffff01ff81ff8080ffff02ff05ff8205ff808080ff0180ffff04ffff01ffffff49ff3f02ff04ff0101ffff02ffff02ffff03ff05ffff01ff02ff2affff04ff02ffff04ff0dffff04ffff0bff12ffff0bff2cff1480ffff0bff12ffff0bff12ffff0bff2cff3c80ff0980ffff0bff12ff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ff02ffff03ff05ffff01ff02ffff03ffff02ff3effff04ff02ffff04ff82011fffff04ff27ffff04ff4fff808080808080ffff01ff02ff3affff04ff02ffff04ff0dffff04ff1bffff04ff37ffff04ff6fffff04ff81dfffff04ff8201bfffff04ff82037fffff04ffff04ffff04ff28ffff04ffff0bffff02ff26ffff04ff02ffff04ff11ffff04ffff02ff26ffff04ff02ffff04ff13ffff04ff82027fffff04ffff02ff36ffff04ff02ffff04ff82013fff80808080ffff04ffff02ff36ffff04ff02ffff04ff819fff80808080ffff04ffff02ff36ffff04ff02ffff04ff13ff80808080ff8080808080808080ffff04ffff02ff36ffff04ff02ffff04ff09ff80808080ff808080808080ffff012480ff808080ff8202ff80ff8080808080808080808080ffff01ff088080ff0180ffff018202ff80ff0180ffffff0bff12ffff0bff2cff3880ffff0bff12ffff0bff12ffff0bff2cff3c80ff0580ffff0bff12ffff02ff2affff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff36ffff04ff02ffff04ff09ff80808080ffff02ff36ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff02ffff03ff1bffff01ff02ff2effff04ff02ffff04ffff02ffff03ffff18ffff0101ff1380ffff01ff0bffff0102ff2bff0580ffff01ff0bffff0102ff05ff2b8080ff0180ffff04ffff04ffff17ff13ffff0181ff80ff3b80ff8080808080ffff010580ff0180ff02ffff03ff17ffff01ff02ffff03ffff09ff05ffff02ff2effff04ff02ffff04ff13ffff04ff27ff808080808080ffff01ff02ff3effff04ff02ffff04ff05ffff04ff1bffff04ff37ff808080808080ffff01ff088080ff0180ffff01ff010180ff0180ff018080");
pub const GRAFTROOT_DL_OFFERS_HASH: [u8; 32] =
    hex!("0893e36a88c064fddfa6f8abdb42c044584a98cb4273b80cccc83b4867b701a1");

/// ```text
/// (mod (LAUNCHER_PH MINT_NUMBER MINT_TOTAL)
///   (include condition_codes.clib)
///   (list
///     (list CREATE_COIN LAUNCHER_PH 1)
///   (list CREATE_COIN_ANNOUNCEMENT (sha256 MINT_NUMBER MINT_TOTAL)))
/// )
/// ```
pub const CREATE_NFT_LAUNCHER_FROM_DID: [u8; 65] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff01ff01808080ffff04ffff04ff06ffff04ffff0bff0bff1780ff808080ff808080ffff04ffff01ff333cff018080");
pub const CREATE_NFT_LAUNCHER_FROM_DID_HASH: [u8; 32] =
    hex!("7a32d2d9571d3436791c0ad3d7fcfdb9c43ace2b0f0ff13f98d29f0cc093f445");

/// ```text
/// (mod (LAUNCHER_PH MINT_NUMBER MINT_TOTAL)
///   (include condition_codes.clib)
///   (list
///     (list CREATE_COIN LAUNCHER_PH 1)
///   (list CREATE_COIN_ANNOUNCEMENT (sha256 MINT_NUMBER MINT_TOTAL)))
/// )
/// ```
pub const NFT_INTERMEDIATE_LAUNCHER: [u8; 65] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff01ff01808080ffff04ffff04ff06ffff04ffff0bff0bff1780ff808080ff808080ffff04ffff01ff333cff018080");
pub const NFT_INTERMEDIATE_LAUNCHER_HASH: [u8; 32] =
    hex!("7a32d2d9571d3436791c0ad3d7fcfdb9c43ace2b0f0ff13f98d29f0cc093f445");

/// ```text
/// (mod (CURRENT_METADATA METADATA_UPDATER_PUZZLE_HASH (key . new_url))
///
///   ; METADATA and METADATA_UPDATER_PUZZLE_HASH are passed in as truths from the layer above
///   ; This program returns ((new_metadata new_metadata_updater_puzhash) conditions)
///
///   ; Add uri to a field
///   (defun add_url (METADATA key new_url)
///     (if METADATA
///         (if (= (f (f METADATA)) key)
///             (c (c key (c new_url (r (f METADATA)))) (r METADATA))
///             (c (f METADATA) (add_url (r METADATA) key new_url))
///         )
///         ()
///     )
///   )
///   ; main
///   ; returns ((new_metadata new_metadata_updater_puzhash) conditions)
///   (list
///     (list
///       (if (all key new_url)
///           (if (any (= key "mu") (= key "lu") (= key "u"))
///               (add_url CURRENT_METADATA key new_url)
///               CURRENT_METADATA
///           )
///           CURRENT_METADATA
///       )
///     METADATA_UPDATER_PUZZLE_HASH)
///     0
///   )
/// )
/// ```
pub const NFT_METADATA_UPDATER_DEFAULT: [u8; 241] = hex!("ff02ffff01ff04ffff04ffff02ffff03ffff22ff27ff3780ffff01ff02ffff03ffff21ffff09ff27ffff01826d7580ffff09ff27ffff01826c7580ffff09ff27ffff01758080ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff27ffff04ff37ff808080808080ffff010580ff0180ffff010580ff0180ffff04ff0bff808080ffff01ff808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff03ffff09ff11ff0b80ffff01ff04ffff04ff0bffff04ff17ff198080ff0d80ffff01ff04ff09ffff02ff02ffff04ff02ffff04ff0dffff04ff0bffff04ff17ff8080808080808080ff0180ff8080ff0180ff018080");
pub const NFT_METADATA_UPDATER_DEFAULT_HASH: [u8; 32] =
    hex!("fe8a4b4e27a2e29a4d3fc7ce9d527adbcaccbab6ada3903ccf3ba9a769d2d78b");

/// ```text
/// (mod (CURRENT_METADATA METADATA_UPDATER_PUZZLE_HASH solution)
///
///   ; solution is (new_url new_metadata_updater_puzhash)
///
///   ; METADATA and METADATA_UPDATER_PUZZLE_HASH are passed in as truths from the layer above
///   ; This program returns ((new_metadata new_metadata_updater_puzhash) conditions)
///
///   ; NOTE THIS PROGRAM IS FOR TESTING ONLY - USE IN DEPLOYMENT AT YOUR OWN PERIL
///
///   ; once we find 'u' we don't need to continue looping
///   (defun add_url (METADATA new_url)
///     (if METADATA
///         (if (= (f (f METADATA)) 'u')
///             (c (c 'u' (c new_url (r (f METADATA)))) (r METADATA))
///             (c (f METADATA) (add_url (r METADATA) new_url))
///         )
///         ()
///     )
///   )
///
///   (defun-inline assert_bytes32 (value)
///     (= (strlen value) 32)
///   )
///
///   ; main
///   ; returns ((new_metadata new_metadata_updater_puzhash) conditions)
///   (list (list (if (f solution) (add_url CURRENT_METADATA (f solution)) CURRENT_METADATA) (if (assert_bytes32 (f (r solution))) (f (r solution)) METADATA_UPDATER_PUZZLE_HASH)) 0)
/// )
/// ```
pub const NFT_METADATA_UPDATER_UPDATEABLE: [u8; 203] = hex!("ff02ffff01ff04ffff04ffff02ffff03ff27ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff27ff8080808080ffff010580ff0180ffff04ffff02ffff03ffff09ffff0dff5780ffff012080ffff0157ffff010b80ff0180ff808080ffff01ff808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff03ffff09ff11ffff017580ffff01ff04ffff04ffff0175ffff04ff0bff198080ff0d80ffff01ff04ff09ffff02ff02ffff04ff02ffff04ff0dffff04ff0bff80808080808080ff0180ff8080ff0180ff018080");
pub const NFT_METADATA_UPDATER_UPDATEABLE_HASH: [u8; 32] =
    hex!("0b1ffba1601777c06b78ab38636e9624f2f8da73be9b36e0ce17c8d8ef3bad9f");

/// ```text
/// (mod (
///     NFT_OWNERSHIP_LAYER_MOD_HASH
///     CURRENT_OWNER
///     TRANSFER_PROGRAM
///     INNER_PUZZLE
///     inner_solution
///   )
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include utility_macros.clib)
///
///   (defconstant NEW_OWNER_CONDITION -10)
///   (defconstant ANNOUNCEMENT_PREFIX 0xad4c)  ; first 2 bytes of (sha256 "Ownership Layer")
///
///   (defun-inline nft_ownership_layer_puzzle_hash (NFT_OWNERSHIP_LAYER_MOD_HASH new_owner TRANSFER_PROGRAM inner_puzzle_hash)
///     (puzzle-hash-of-curried-function NFT_OWNERSHIP_LAYER_MOD_HASH
///       inner_puzzle_hash
///       (sha256tree TRANSFER_PROGRAM)
///       (sha256 ONE new_owner)
///       (sha256 ONE NFT_OWNERSHIP_LAYER_MOD_HASH)
///     )
///   )
///
///   (defun construct_end_conditions (NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM odd_args (new_owner new_tp conditions))
///     (c
///       (c
///         CREATE_COIN
///         (c
///           (nft_ownership_layer_puzzle_hash NFT_OWNERSHIP_LAYER_MOD_HASH new_owner (if new_tp new_tp TRANSFER_PROGRAM) (f odd_args))
///           (r odd_args)
///         )
///       )
///       conditions
///     )
///   )
///
///   (defun wrap_odd_create_coins (NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM CURRENT_OWNER all_conditions conditions odd_args tp_output)
///     (if conditions
///         (if (= (f (f conditions)) CREATE_COIN)
///             (if (= (logand (f (r (r (f conditions))))) ONE)
///                 (assert (not odd_args)
///                   ; then
///                   (wrap_odd_create_coins NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM CURRENT_OWNER all_conditions (r conditions) (r (f conditions)) tp_output)
///                 )
///                 (c (f conditions) (wrap_odd_create_coins NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM CURRENT_OWNER all_conditions (r conditions) odd_args tp_output))
///             )
///             (if (= (f (f conditions)) NEW_OWNER_CONDITION)
///                 (assert (not tp_output)
///                   (c
///                     (list CREATE_PUZZLE_ANNOUNCEMENT (concat ANNOUNCEMENT_PREFIX (sha256tree (r (f conditions)))))
///                     (wrap_odd_create_coins NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM CURRENT_OWNER all_conditions (r conditions) odd_args (a TRANSFER_PROGRAM (list CURRENT_OWNER all_conditions (r (f conditions)))))
///                   )
///                 )
///                 (if (= (f (f conditions)) CREATE_PUZZLE_ANNOUNCEMENT)
///                     (assert (not (and
///                         (= 34 (strlen (f (r (f conditions)))))
///                         (= (substr (f (r (f conditions))) 0 2) ANNOUNCEMENT_PREFIX)  ; lazy eval
///                       ))
///                       ; then
///                       (c (f conditions) (wrap_odd_create_coins NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM CURRENT_OWNER all_conditions (r conditions) odd_args tp_output))
///                     )
///                     (c (f conditions) (wrap_odd_create_coins NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM CURRENT_OWNER all_conditions (r conditions) odd_args tp_output))
///                 )
///             )
///         )
///         ; odd_args is guaranteed to not be nil or else we'll have a path into atom error
///         (construct_end_conditions NFT_OWNERSHIP_LAYER_MOD_HASH TRANSFER_PROGRAM odd_args
///           (if tp_output
///               tp_output
///               (a TRANSFER_PROGRAM (list CURRENT_OWNER all_conditions ()))
///           )
///         )
///     )
///   )
///
///   (defun main (
///       NFT_OWNERSHIP_LAYER_MOD_HASH
///       TRANSFER_PROGRAM
///       CURRENT_OWNER
///       conditions
///     )
///     (wrap_odd_create_coins
///       NFT_OWNERSHIP_LAYER_MOD_HASH
///       TRANSFER_PROGRAM
///       CURRENT_OWNER
///       conditions
///       conditions
///       () ()
///     )
///   )
///
///   ; main
///   (main
///     NFT_OWNERSHIP_LAYER_MOD_HASH
///     TRANSFER_PROGRAM
///     CURRENT_OWNER
///     (a INNER_PUZZLE inner_solution)
///   )
/// )
/// ```
pub const NFT_OWNERSHIP_LAYER: [u8; 1226] = hex!("ff02ffff01ff02ff26ffff04ff02ffff04ff05ffff04ff17ffff04ff0bffff04ffff02ff2fff5f80ff80808080808080ffff04ffff01ffffff82ad4cff0233ffff3e04ff81f601ffffff0102ffff02ffff03ff05ffff01ff02ff2affff04ff02ffff04ff0dffff04ffff0bff32ffff0bff3cff3480ffff0bff32ffff0bff32ffff0bff3cff2280ff0980ffff0bff32ff0bffff0bff3cff8080808080ff8080808080ffff010b80ff0180ff04ffff04ff38ffff04ffff02ff36ffff04ff02ffff04ff05ffff04ff27ffff04ffff02ff2effff04ff02ffff04ffff02ffff03ff81afffff0181afffff010b80ff0180ff80808080ffff04ffff0bff3cff4f80ffff04ffff0bff3cff0580ff8080808080808080ff378080ff82016f80ffffff02ff3effff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff2fffff01ff80ff808080808080808080ff0bff32ffff0bff3cff2880ffff0bff32ffff0bff32ffff0bff3cff2280ff0580ffff0bff32ffff02ff2affff04ff02ffff04ff07ffff04ffff0bff3cff3c80ff8080808080ffff0bff3cff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ffff03ff5fffff01ff02ffff03ffff09ff82011fff3880ffff01ff02ffff03ffff09ffff18ff82059f80ff3c80ffff01ff02ffff03ffff20ff81bf80ffff01ff02ff3effff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff81dfffff04ff82019fffff04ff82017fff80808080808080808080ffff01ff088080ff0180ffff01ff04ff819fffff02ff3effff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff81dfffff04ff81bfffff04ff82017fff808080808080808080808080ff0180ffff01ff02ffff03ffff09ff82011fff2c80ffff01ff02ffff03ffff20ff82017f80ffff01ff04ffff04ff24ffff04ffff0eff10ffff02ff2effff04ff02ffff04ff82019fff8080808080ff808080ffff02ff3effff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff81dfffff04ff81bfffff04ffff02ff0bffff04ff17ffff04ff2fffff04ff82019fff8080808080ff8080808080808080808080ffff01ff088080ff0180ffff01ff02ffff03ffff09ff82011fff2480ffff01ff02ffff03ffff20ffff02ffff03ffff09ffff0122ffff0dff82029f8080ffff01ff02ffff03ffff09ffff0cff82029fff80ffff010280ff1080ffff01ff0101ff8080ff0180ff8080ff018080ffff01ff04ff819fffff02ff3effff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff81dfffff04ff81bfffff04ff82017fff8080808080808080808080ffff01ff088080ff0180ffff01ff04ff819fffff02ff3effff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff81dfffff04ff81bfffff04ff82017fff808080808080808080808080ff018080ff018080ff0180ffff01ff02ff3affff04ff02ffff04ff05ffff04ff0bffff04ff81bfffff04ffff02ffff03ff82017fffff0182017fffff01ff02ff0bffff04ff17ffff04ff2fffff01ff808080808080ff0180ff8080808080808080ff0180ff018080");
pub const NFT_OWNERSHIP_LAYER_HASH: [u8; 32] =
    hex!("c5abea79afaa001b5427dfa0c8cf42ca6f38f5841b78f9b3c252733eb2de2726");

/// ```text
/// (mod
///   (
///     SINGLETON_STRUCT
///     ROYALTY_ADDRESS
///     TRADE_PRICE_PERCENTAGE
///     Current_Owner  ; Truth
///     conditions  ; Truth
///     solution  ; created from the NFT's inner puzzle - solution is (new_owner trade_prices_list new_did_inner_hash)
///   )
///
///   ; This is a transfer program - which must return (new_owner, Optional[new_transfer_program], conditions)
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   (defconstant TEN_THOUSAND 10000)
///
///   ;; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (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)
///     )
///   )
///
///   ; Given a singleton ID, generate the singleton struct
///   (defun-inline get_singleton_struct (SINGLETON_STRUCT singleton_id)
///     (c (f SINGLETON_STRUCT) (c singleton_id (r (r SINGLETON_STRUCT))))
///   )
///
///   (defun-inline calculate_percentage (amount percentage)
///     (f (divmod (* amount percentage) TEN_THOUSAND))
///   )
///
///   ; Loop of the trade prices list and either assert a puzzle announcement or generate xck
///   (defun parse_trade_prices_list (ROYALTY_ADDRESS TRADE_PRICE_PERCENTAGE trade_prices_list my_nft_id)
///     (if trade_prices_list
///         (c
///           (list
///             ASSERT_PUZZLE_ANNOUNCEMENT
///             (sha256
///               (f (r (f trade_prices_list)))
///               (sha256tree (c my_nft_id (list (list ROYALTY_ADDRESS (calculate_percentage (f (f trade_prices_list)) TRADE_PRICE_PERCENTAGE) (list ROYALTY_ADDRESS)))))
///             )
///           )
///           (parse_trade_prices_list ROYALTY_ADDRESS TRADE_PRICE_PERCENTAGE (r trade_prices_list) my_nft_id)
///         )
///         ()
///     )
///   )
///
///   ; main
///   ; Returning (new_owner new_transfer_program conditions)
///   ; solution is (new_owner trade_prices_list new_did_inner_hash)
///   (if solution
///       (list
///         (f solution)
///         0
///         (if (all (f solution) (not (= (f solution) Current_Owner)))
///             (c
///               (list
///                 ASSERT_PUZZLE_ANNOUNCEMENT
///                 (sha256
///                   (calculate_full_puzzle_hash (get_singleton_struct SINGLETON_STRUCT (f solution)) (f (r (r solution))))
///                   (f (r SINGLETON_STRUCT))
///                 )
///               )
///               (parse_trade_prices_list ROYALTY_ADDRESS TRADE_PRICE_PERCENTAGE (f (r solution)) (f (r SINGLETON_STRUCT)))
///             )
///             (parse_trade_prices_list ROYALTY_ADDRESS TRADE_PRICE_PERCENTAGE (f (r solution)) (f (r SINGLETON_STRUCT)))
///         )
///       )
///       (list Current_Owner () ())
///   )
///
///
/// )
/// ```
pub const NFT_OWNERSHIP_TRANSFER_PROGRAM_ONE_WAY_CLAIM_WITH_ROYALTIES: [u8; 687] = hex!("ff02ffff01ff02ffff03ff81bfffff01ff04ff82013fffff04ff80ffff04ffff02ffff03ffff22ff82013fffff20ffff09ff82013fff2f808080ffff01ff04ffff04ff10ffff04ffff0bffff02ff2effff04ff02ffff04ff09ffff04ff8205bfffff04ffff02ff3effff04ff02ffff04ffff04ff09ffff04ff82013fff1d8080ff80808080ff808080808080ff1580ff808080ffff02ff16ffff04ff02ffff04ff0bffff04ff17ffff04ff8202bfffff04ff15ff8080808080808080ffff01ff02ff16ffff04ff02ffff04ff0bffff04ff17ffff04ff8202bfffff04ff15ff8080808080808080ff0180ff80808080ffff01ff04ff2fffff01ff80ff80808080ff0180ffff04ffff01ffffff3f02ff04ff0101ffff822710ff02ff02ffff03ff05ffff01ff02ff3affff04ff02ffff04ff0dffff04ffff0bff2affff0bff2cff1480ffff0bff2affff0bff2affff0bff2cff3c80ff0980ffff0bff2aff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ff17ffff01ff04ffff04ff10ffff04ffff0bff81a7ffff02ff3effff04ff02ffff04ffff04ff2fffff04ffff04ff05ffff04ffff05ffff14ffff12ff47ff0b80ff128080ffff04ffff04ff05ff8080ff80808080ff808080ff8080808080ff808080ffff02ff16ffff04ff02ffff04ff05ffff04ff0bffff04ff37ffff04ff2fff8080808080808080ff8080ff0180ffff0bff2affff0bff2cff1880ffff0bff2affff0bff2affff0bff2cff3c80ff0580ffff0bff2affff02ff3affff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const NFT_OWNERSHIP_TRANSFER_PROGRAM_ONE_WAY_CLAIM_WITH_ROYALTIES_HASH: [u8; 32] =
    hex!("025dee0fb1e9fa110302a7e9bfb6e381ca09618e2778b0184fa5c6b275cfce1f");

/// ```text
/// (mod (
///     NFT_STATE_LAYER_MOD_HASH
///     METADATA
///     METADATA_UPDATER_PUZZLE_HASH
///     INNER_PUZZLE
///     inner_solution
///   )
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include utility_macros.clib)
///
///   (defun-inline nft_state_layer_puzzle_hash (NFT_STATE_LAYER_MOD_HASH METADATA METADATA_UPDATER_PUZZLE_HASH inner_puzzle_hash)
///     (puzzle-hash-of-curried-function NFT_STATE_LAYER_MOD_HASH
///       inner_puzzle_hash
///       (sha256 ONE METADATA_UPDATER_PUZZLE_HASH)
///       (sha256tree METADATA)
///       (sha256 ONE NFT_STATE_LAYER_MOD_HASH)
///     )
///   )
///
///
///   ; this function does two things - it wraps the odd value create coins, and it also filters out all negative conditions
///   ; odd_coin_params is (puzhash amount ...)
///   ; new_metadata_info is ((METADATA METADATA_UPDATER_PUZZLE_HASH) conditions)
///   (defun wrap_odd_create_coins (NFT_STATE_LAYER_MOD_HASH conditions odd_coin_params new_metadata_info metadata_seen)
///     (if conditions
///         (if (= (f (f conditions)) CREATE_COIN)
///             (if (logand (f (r (r (f conditions)))) ONE)
///                 (assert (not odd_coin_params)
///                   (wrap_odd_create_coins NFT_STATE_LAYER_MOD_HASH (r conditions) (r (f conditions)) new_metadata_info metadata_seen)
///                 )
///                 (c (f conditions) (wrap_odd_create_coins NFT_STATE_LAYER_MOD_HASH (r conditions) odd_coin_params new_metadata_info metadata_seen))
///             )
///             (if (= (f (f conditions)) -24)
///                 (wrap_odd_create_coins NFT_STATE_LAYER_MOD_HASH (r conditions) odd_coin_params
///                   (assert (all
///                       (= (sha256tree (f (r (f conditions)))) (f (r (f new_metadata_info))))
///                       (not metadata_seen)
///                     )
///                     ; then
///                     (a (f (r (f conditions))) (list (f (f new_metadata_info)) (f (r (f new_metadata_info))) (f (r (r (f conditions))))))
///                   )
///                   ONE  ; the metadata update has been seen now
///                 )
///                 (c (f conditions) (wrap_odd_create_coins NFT_STATE_LAYER_MOD_HASH (r conditions) odd_coin_params new_metadata_info metadata_seen))
///             )
///         )
///         (c
///           (c CREATE_COIN
///             (c
///               (nft_state_layer_puzzle_hash
///                 NFT_STATE_LAYER_MOD_HASH
///                 (f (f new_metadata_info))
///                 (f (r (f new_metadata_info)))
///                 (f odd_coin_params)  ; metadata updater solution
///               )
///               (r odd_coin_params)
///             )
///           )
///           (f (r new_metadata_info))  ; metadata_updater conditions
///         )
///     )
///   )
///
///   ; main
///   (wrap_odd_create_coins
///     NFT_STATE_LAYER_MOD_HASH
///     (a INNER_PUZZLE inner_solution)
///     ()
///     (list (list METADATA METADATA_UPDATER_PUZZLE_HASH) 0)  ; if the magic condition is never seen, this is the information we us to recurry
///     ()
///   )
/// )
/// ```
pub const NFT_STATE_LAYER: [u8; 827] = hex!("ff02ffff01ff02ff3effff04ff02ffff04ff05ffff04ffff02ff2fff5f80ffff04ff80ffff04ffff04ffff04ff0bffff04ff17ff808080ffff01ff808080ffff01ff8080808080808080ffff04ffff01ffffff0233ff04ff0101ffff02ff02ffff03ff05ffff01ff02ff1affff04ff02ffff04ff0dffff04ffff0bff12ffff0bff2cff1480ffff0bff12ffff0bff12ffff0bff2cff3c80ff0980ffff0bff12ff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ffff0bff12ffff0bff2cff1080ffff0bff12ffff0bff12ffff0bff2cff3c80ff0580ffff0bff12ffff02ff1affff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ffff03ff0bffff01ff02ffff03ffff09ff23ff1880ffff01ff02ffff03ffff18ff81b3ff2c80ffff01ff02ffff03ffff20ff1780ffff01ff02ff3effff04ff02ffff04ff05ffff04ff1bffff04ff33ffff04ff2fffff04ff5fff8080808080808080ffff01ff088080ff0180ffff01ff04ff13ffff02ff3effff04ff02ffff04ff05ffff04ff1bffff04ff17ffff04ff2fffff04ff5fff80808080808080808080ff0180ffff01ff02ffff03ffff09ff23ffff0181e880ffff01ff02ff3effff04ff02ffff04ff05ffff04ff1bffff04ff17ffff04ffff02ffff03ffff22ffff09ffff02ff2effff04ff02ffff04ff53ff80808080ff82014f80ffff20ff5f8080ffff01ff02ff53ffff04ff818fffff04ff82014fffff04ff81b3ff8080808080ffff01ff088080ff0180ffff04ff2cff8080808080808080ffff01ff04ff13ffff02ff3effff04ff02ffff04ff05ffff04ff1bffff04ff17ffff04ff2fffff04ff5fff80808080808080808080ff018080ff0180ffff01ff04ffff04ff18ffff04ffff02ff16ffff04ff02ffff04ff05ffff04ff27ffff04ffff0bff2cff82014f80ffff04ffff02ff2effff04ff02ffff04ff818fff80808080ffff04ffff0bff2cff0580ff8080808080808080ff378080ff81af8080ff0180ff018080");
pub const NFT_STATE_LAYER_HASH: [u8; 32] =
    hex!("a04d9f57764f54a43e4030befb4d80026e870519aaa66334aef8304f5d0393c2");

/// ```text
/// (mod (CONDITIONS nonce)
///   (c (list 60 nonce) CONDITIONS)
/// )
/// ```
pub const CONDITIONS_W_FEE_ANNOUNCE: [u8; 21] = hex!("ff04ffff04ffff013cffff04ff05ff808080ff0280");
pub const CONDITIONS_W_FEE_ANNOUNCE_HASH: [u8; 32] =
    hex!("1a169582dc619f2542f8eb79f02823e1595ba0aca53820f503eda5ff20b47856");

/// ```text
/// ; This is an outer puzzle for a coin that imposes a restriction that the coin can only be spent with an
/// ; announcement from a "verified credential" whose proofs are present due to a DID in a list of authorized providers.
///
/// ; A "verified credential" is defined as the following puzzle stack:
/// ;  - singleton top layer
/// ;    |_exigent metadata layer
/// ;      |_eml transfer program covenant adapter
/// ;      | |_covenant layer
/// ;      |   |_initial puzzle (hashed)
/// ;      |   | |_singleton top layer
/// ;      |   |   |_exigent metadata layer
/// ;      |   |     |_(mod (_ _ (provider tp)) (list (c provider ()) tp ())) (guaranteed metadata to be nil)
/// ;      |   |     |_p2 announced delegated puzzle
/// ;      |   |_eml covenant morpher
/// ;      |   |_eml update metadata with DID
/// ;      |_<inner puzzle>
/// ; The information to construct a VC is contained in a highly optimized way within CREDENTIAL_STRUCT
/// ;
/// ; This puzzle does many things:
/// ;  - Tree hash of a partially revealed tree to come to a proof hash present in the accompanying VC singleton
/// ;  - Validate the revealed proofs with a curried proofs checker
/// ;  - Assert an announcement from a VC with a message of 0xca which signals this spend is ok
/// ;  - Wrap all of its children in this layer
/// ;  - Create an announcement in the 0xcd namespace of each output it is creating (for a VC to assert if it wishes)
/// ;  - Block any announcements coming from the inner puzzle in the 0xcd namespace
/// (mod
///   (
///     ; We curry twice: first, all of the static information we need, then the hash of the program with all of that info
///     ; this allows use to be more efficient when calculating our own hash (a (q . SELF_HASH) (c SELF_HASH (x INNER_PUZZLE 1)))
///     ; curried first
///     CREDENTIAL_STRUCT
///     AUTHORIZED_PROVIDERS
///     PROOFS_CHECKER
///     ; curried second
///     SELF_HASH
///     INNER_PUZZLE
///     proof_of_inclusions  ; Proof that key/value pairs exist in a tree (the root of the tree is implicit from this)
///     proof_checker_solution  ; solution to PROOFS_CHECKER program
///     provider_id  ; the DID that is curried into the metadata of the VC that is authorizing this coin
///     credential_id  ; the launcher ID of the VC that is authorizing this coin
///     credential_inner_puzhash  ; The <inner puzzle> (see above) of the VC that is authorizing this coin
///     my_coin_id  ; This coin's ID
///     inner_solution
///   )
///
///   (include curry.clib)
///   (include condition_codes.clib)
///   (include utility_macros.clib)
///
///   ; take two lists and merge them into one
///   (defun merge_list (list_a list_b)
///     (if list_a
///         (c (f list_a) (merge_list (r list_a) list_b))
///         list_b
///     )
///   )
///
///   (defconstant announcement_namespace 0xcd)
///   (defconstant ONE 1)
///
///   (defun-inline wrap_puzhash
///     (
///       SELF_HASH
///       puzhash
///     )
///
///     (curry_hashes SELF_HASH
///       (sha256 ONE SELF_HASH)
///       puzhash
///     )
///   )
///
///   ; Does three things:
///   ; 1) Wraps create coins with this layer
///   ; 2) Announces those create coins in a namespace
///   ; 3) Raises on announcements from the inner puzzle that could possibly be in the namespace
///   (defun process_conditions
///     (
///       SELF_HASH
///       conditions
///     )
///     (if conditions
///         (if (= (f (f conditions)) CREATE_COIN)
///             (c
///               (list
///                 CREATE_COIN_ANNOUNCEMENT
///                 (concat
///                   announcement_namespace
///                   (sha256 (f (r (f conditions))) (f (r (r (f conditions)))))
///                 )
///               )
///               (c
///                 (c
///                   CREATE_COIN
///                   (c
///                     (wrap_puzhash SELF_HASH (f (r (f conditions))))
///                     (r (r (f conditions)))
///                   )
///                 )
///                 (process_conditions SELF_HASH (r conditions))
///               )
///             )
///             ; else - not a create coin
///             (assert (or
///                 (not (= (f (f conditions)) CREATE_COIN_ANNOUNCEMENT))  ; some coin announcements should be blocked
///                 (not (= 33 (strlen (f (r (f conditions))))))  ; we only care about blocking 0xcd + some_hash
///                 (not (= announcement_namespace (substr (f (r (f conditions))) 0 ONE)))  ; block prefix 0xcd
///               )
///               ; then
///               (c
///                 (f conditions)
///                 (process_conditions SELF_HASH (r conditions))
///               )
///             )
///         )
///         ; else - end of list
///         ()
///     )
///   )
///
///   (defun create_vc_puzhash_stage_2
///     (
///       (
///         (
///           (
///             SINGLETON_MOD_HASH
///             .
///             SINGLETON_LAUNCHER_HASH
///           )
///           .
///           (
///             OWNERSHIP_LAYER_MOD_HASH
///             .
///             ADAPTER_MOD_HASH
///           )
///         )
///         .
///         (
///           INITIAL_SINGLETON_INNER_PUZHASH
///           .
///           (
///             TWO_AND_COVENANT_MOD_HASH  ; (concat 2 COVENANT_MOD_HASH)
///             .
///             REST_COVENANT_ARGS_HASH  ; ((c PARENT_MORPHER (c EML_DID_TP 1)) . ()) hashed
///           )
///         )
///       )
///       provider_id
///       credential_singleton_struct_hash
///       proof_hash
///       credential_inner_puzhash
///       tp_hash
///     )
///
///     (curry_hashes SINGLETON_MOD_HASH
///       credential_singleton_struct_hash
///       (curry_hashes OWNERSHIP_LAYER_MOD_HASH
///         (sha256 ONE OWNERSHIP_LAYER_MOD_HASH)
///         (sha256 TWO
///           (sha256 ONE provider_id)
///           (sha256 ONE proof_hash)
///         )
///         tp_hash
///         (sha256 ONE tp_hash)
///         credential_inner_puzhash
///       )
///     )
///   )
///
///   (defun create_vc_puzhash
///     (
///       CREDENTIAL_STRUCT
///       provider_id
///       credential_singleton_struct_hash
///       proof_hash
///       credential_inner_puzhash
///     )
///
///     (create_vc_puzhash_stage_2
///       CREDENTIAL_STRUCT
///       provider_id
///       credential_singleton_struct_hash
///       proof_hash
///       credential_inner_puzhash
///       (curry_hashes (r (r (f CREDENTIAL_STRUCT)))  ; ADAPTER_MOD_HASH
///         (sha256
///           ; apply
///           (two_sha256_one_a_kw)
///           (sha256
///             ; func
///             (f (r (r CREDENTIAL_STRUCT)))  ; TWO_AND_COVENANT_MOD_HASH
///             (sha256 TWO
///               ; args
///               (sha256
///                 (two_sha256_one_c_kw)
///                 (sha256 TWO
///                   (sha256 TWO
///                     (sha256_one_one)
///                     (sha256 ONE (curry_hashes (f (f (f CREDENTIAL_STRUCT)))  ; SINGLETON_MOD_HASH
///                         credential_singleton_struct_hash
///                         (f (r CREDENTIAL_STRUCT))  ; INITIAL_SINGLETON_INNER_PUZHASH
///                     ))
///                   )
///                   (r (r (r CREDENTIAL_STRUCT)))  ; REST_COVENANT_ARGS_HASH
///                 )
///               )
///               (sha256_one)
///             )
///           )
///         )
///       )
///     )
///   )
///
///   ; utility function that turns the output of two calls to collapse_tree_and_note_leaf_info into a single return value
///   (defun branch_hash_and_merge_info ((TREE1 PROOFS1) (TREE2 PROOFS2))
///     (list
///       (sha256 TWO TREE1 TREE2)
///       (merge_list PROOFS1 PROOFS2)
///     )
///   )
///
///   (defun collapse_tree_and_note_leaf_info (TREE PROOFS)
///     (if (l TREE)
///         (if (or (l (f TREE)) (l (r TREE)))  ; If either side is a cons, we have not reached a leaf pair yet
///             (branch_hash_and_merge_info
///               (collapse_tree_and_note_leaf_info (f TREE) ())
///               ; we favor right because merge_list merges from left
///               (collapse_tree_and_note_leaf_info (r TREE) PROOFS)
///             )
///             ; else - both first and rest are atoms, we are at a key/value pair
///             (branch_hash_and_merge_info
///               (list (sha256 ONE (f TREE)) ())
///               (list (sha256 ONE (r TREE)) (c TREE PROOFS))
///             )
///         )
///         (list TREE PROOFS)  ; All atoms that we reach must be pre-hashed subtrees
///     )
///   )
///
///   (defun main
///     (
///       CREDENTIAL_STRUCT
///       AUTHORIZED_PROVIDERS
///       PROOFS_CHECKER
///       SELF_HASH
///       proof_checker_solution
///       provider_id
///       credential_id
///       credential_inner_puzhash
///       my_coin_id
///       conditions
///       (tree_hash proofs)
///     )
///
///     (assert
///       ; Run proof checker to make sure it doesn't return () (fail)
///       (a PROOFS_CHECKER (list proofs proof_checker_solution))
///       (in provider_id AUTHORIZED_PROVIDERS)  ; VC needs to be in authorized list
///       ; then
///       (c
///         (list ASSERT_MY_COIN_ID my_coin_id)
///         (c
///           (list ASSERT_PUZZLE_ANNOUNCEMENT
///             (sha256
///               (create_vc_puzhash
///                 CREDENTIAL_STRUCT
///                 provider_id
///                 (sha256 TWO
///                   (sha256 ONE (f (f (f CREDENTIAL_STRUCT))))  ; SINGLETON_MOD_HASH
///                   (sha256 TWO
///                     (sha256 ONE credential_id)
///                     (sha256 ONE (r (f (f CREDENTIAL_STRUCT))))  ; SINGLETON_LAUNCHER_HASH
///                   )
///                 )
///                 tree_hash
///                 credential_inner_puzhash
///               )
///               (sha256 my_coin_id 0xca)  ; my_coin_id because VC must announce specifically to us
///             )
///           )
///           (process_conditions
///             SELF_HASH
///             conditions
///           )
///         )
///       )
///     )
///   )
///
///   (main
///     CREDENTIAL_STRUCT
///     AUTHORIZED_PROVIDERS
///     PROOFS_CHECKER
///     SELF_HASH
///     proof_checker_solution
///     provider_id
///     credential_id
///     credential_inner_puzhash
///     my_coin_id
///     (a INNER_PUZZLE inner_solution)
///     (collapse_tree_and_note_leaf_info proof_of_inclusions ())
///   )
/// )
/// ```
pub const CREDENTIAL_RESTRICTION: [u8; 1648] = hex!("ff02ffff01ff02ff2effff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffffff04ff8217ffffff04ffff02ff5fff822fff80ffff04ffff02ff22ffff04ff02ffff04ff81bfffff01ff8080808080ff8080808080808080808080808080ffff04ffff01ffffffff463fff333cffff0102ff81cdffff04ffff0bff34ff09ff1380ffff04ffff02ff5effff04ff02ffff04ff15ffff04ff2bff8080808080ff808080ff02ffff03ff05ffff01ff0bff81f2ffff02ff26ffff04ff02ffff04ff09ffff04ffff02ff7cffff04ff02ffff04ff0dff80808080ff808080808080ffff0181d280ff0180ffffffff02ffff03ffff07ff0580ffff01ff02ffff03ffff02ffff03ffff07ff0980ffff01ff0101ffff01ff02ffff03ffff07ff0d80ffff01ff0101ff8080ff018080ff0180ffff01ff02ff5cffff04ff02ffff04ffff02ff22ffff04ff02ffff04ff09ffff01ff8080808080ffff04ffff02ff22ffff04ff02ffff04ff0dffff04ff0bff8080808080ff8080808080ffff01ff02ff5cffff04ff02ffff04ffff04ffff0bff24ff0980ffff01ff808080ffff04ffff04ffff0bff24ff0d80ffff04ffff04ff05ff0b80ff808080ff808080808080ff0180ffff01ff04ff05ffff04ff0bff80808080ff0180ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff02ff5affff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff5fffff04ffff02ff7affff04ff02ffff04ff39ffff04ffff0bff81b2ffff0bff2dffff0bff34ffff0bff81f2ffff0bff34ffff0bff34ff81d2ffff0bff24ffff02ff7affff04ff02ffff04ff21ffff04ff17ffff04ff15ff8080808080808080ff3d8080ff8192808080ff8080808080ff808080808080808080ffff02ff7affff04ff02ffff04ff21ffff04ff17ffff04ffff02ff7affff04ff02ffff04ff29ffff04ffff0bff24ff2980ffff04ffff0bff34ffff0bff24ff0b80ffff0bff24ff2f8080ffff04ff81bfffff04ffff0bff24ff81bf80ffff04ff5fff808080808080808080ff808080808080ff0bff81b2ffff02ff26ffff04ff02ffff04ff05ffff04ffff02ff7cffff04ff02ffff04ff07ff80808080ff808080808080ffffff0bff34ffff0bff34ff81d2ff0580ffff0bff34ff0bff81928080ff02ffff03ff0bffff01ff03ffff09ff05ff1380ffff0101ffff02ff36ffff04ff02ffff04ff05ffff04ff1bff808080808080ff8080ff0180ffff02ffff03ffff02ff17ffff04ff8257ffffff04ff5fff80808080ffff01ff02ffff03ffff02ff36ffff04ff02ffff04ff81bfffff04ff0bff8080808080ffff01ff04ffff04ff20ffff04ff8205ffff808080ffff04ffff04ff30ffff04ffff0bffff02ff2affff04ff02ffff04ff05ffff04ff81bfffff04ffff0bff34ffff0bff24ff2180ffff0bff34ffff0bff24ff82017f80ffff0bff24ff31808080ffff04ff8227ffffff04ff8202ffff8080808080808080ffff0bff8205ffffff0181ca8080ff808080ffff02ff7effff04ff02ffff04ff2fffff04ff820bffff80808080808080ffff01ff088080ff0180ffff01ff088080ff0180ffff02ffff03ff05ffff01ff04ff09ffff02ff5effff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff02ffff03ff0bffff01ff02ffff03ffff09ff23ff2880ffff01ff04ffff04ff38ffff04ffff0eff2cffff0bff53ff81b38080ff808080ffff04ffff04ff28ffff04ffff02ff7affff04ff02ffff04ff05ffff04ffff0bff24ff0580ffff04ff53ff808080808080ff738080ffff02ff7effff04ff02ffff04ff05ffff04ff1bff80808080808080ffff01ff02ffff03ffff02ffff03ffff20ffff09ff23ff388080ffff01ff0101ffff01ff02ffff03ffff20ffff09ffff0121ffff0dff53808080ffff01ff0101ffff01ff02ffff03ffff20ffff09ff2cffff0cff53ff80ff24808080ffff01ff0101ff8080ff018080ff018080ff0180ffff01ff04ff13ffff02ff7effff04ff02ffff04ff05ffff04ff1bff808080808080ffff01ff088080ff018080ff0180ff8080ff0180ff018080");
pub const CREDENTIAL_RESTRICTION_HASH: [u8; 32] =
    hex!("2fdfc1f058cfd65e7ec4e253bfeb394da163ecd0036f508df8629b0a2b8fde96");

/// ```text
/// ; This is a PROOFS_CHECKER for use with credential_restriction.clsp
/// ;
/// ; In an attempt to be as simple as possible, this puzzle is curried a list of key/value pairs sorted by keys. This sort
/// ; is crucial to the program functioning as the key/value pairs of the proofs will be sorted before being compared to
/// ; the curried list.
/// (mod
///   (
///     FLAGS  ; must be sorted
///     proofs  ; will be sorted
///     solution  ; unused
///   )
///
///   (include utility_macros.clib)
///
///   (defun insertion_sort_by_keys (sorted insertions)
///     (if insertions
///         (if (or (not sorted) (>s (f (f insertions)) (f (f sorted))))
///             (insertion_sort_by_keys (c (f insertions) sorted) (r insertions))
///             (insertion_sort_by_keys (c (f sorted) (insertion_sort_by_keys (r sorted) (list (f insertions)))) (r insertions))
///         )
///         sorted
///     )
///   )
///
///   (defun merge_insertion_sort (proofs)
///     (if (r proofs)
///         (insertion_sort_by_keys (merge_insertion_sort (r proofs)) (merge_insertion_sort (list (f proofs))))
///         proofs
///     )
///   )
///
///   ; This function checks that the revealed proofs START WITH the same key/value pairs as are in FLAGS. This is not for
///   ; any particular reason except optimization. We don't really care if EXTRA proof pairs are revealed.
///   (defun compare_first_pairs_against_flags (subject comp)
///     (if subject
///         (if (logand (= (f (f subject)) (f (f comp))) (= (r (f subject)) (r (f comp))))
///             (compare_first_pairs_against_flags (r subject) (r comp))
///             ()
///         )
///         1
///     )
///   )
///
///   (compare_first_pairs_against_flags FLAGS (merge_insertion_sort proofs))
/// )
/// ```
pub const FLAG_PROOFS_CHECKER: [u8; 399] = hex!("ff02ffff01ff02ff04ffff04ff02ffff04ff05ffff04ffff02ff0effff04ff02ffff04ff0bff80808080ff8080808080ffff04ffff01ffff02ffff03ff05ffff01ff02ffff03ffff18ffff09ff11ff2380ffff09ff19ff338080ffff01ff02ff04ffff04ff02ffff04ff0dffff04ff1bff8080808080ff8080ff0180ffff01ff010180ff0180ffff02ffff03ff0bffff01ff02ffff03ffff02ffff03ffff20ff0580ffff01ff0101ffff01ff02ffff03ffff0aff23ff1180ffff01ff0101ff8080ff018080ff0180ffff01ff02ff0affff04ff02ffff04ffff04ff13ff0580ffff04ff1bff8080808080ffff01ff02ff0affff04ff02ffff04ffff04ff09ffff02ff0affff04ff02ffff04ff0dffff04ffff04ff13ff8080ff808080808080ffff04ff1bff808080808080ff0180ffff010580ff0180ff02ffff03ff0dffff01ff02ff0affff04ff02ffff04ffff02ff0effff04ff02ffff04ff0dff80808080ffff04ffff02ff0effff04ff02ffff04ffff04ff09ff8080ff80808080ff8080808080ffff010580ff0180ff018080");
pub const FLAG_PROOFS_CHECKER_HASH: [u8; 32] =
    hex!("fe2e3c631562fbb9be095297f762bf573705a0197164e9361ad5d50e045ba241");

/// ```text
/// ; This is a utility layer for a coin that allows it to prove that it came from some INITIAL_PUZZLE_HASH
/// (mod
///   (
///     INITIAL_PUZZLE_HASH  ; The ancestor's puzzle hash this layer is evidence of
///     PARENT_MORPHER  ; Defines how to wrap a parent inner puzzle hash to prove that it had this layer running inside it
///     INNER_PUZZLE
///     lineage_proof  ; parent id, parent inner puzzle hash (wrapped with PARENT_MORPHER), parent amount
///     morpher_solution  ; solution to PARENT_MORPHER
///     inner_solution
///   )
///
///   (include condition_codes.clib)
///
///   (c
///     (list ASSERT_MY_PARENT_ID
///       (sha256
///         (f lineage_proof)
///         (if (r (r lineage_proof))  ; different logic based on whether the lineage proof is 2 or 3 elements long
///             (a PARENT_MORPHER (c INITIAL_PUZZLE_HASH (c (f (r lineage_proof)) morpher_solution)))
///             INITIAL_PUZZLE_HASH
///         )
///         (if (r (r lineage_proof))  ; different logic based on whether the lineage proof is 2 or 3 elements long
///             (f (r (r lineage_proof)))
///             (f (r lineage_proof))
///         )
///       )
///     )
///     (a INNER_PUZZLE inner_solution)
///   )
/// )
/// ```
pub const COVENANT_LAYER: [u8; 110] = hex!("ff02ffff01ff04ffff04ff02ffff04ffff0bff4fffff02ffff03ff81efffff01ff02ff0bffff04ff05ffff04ff81afff5f808080ffff010580ff0180ffff02ffff03ff81efffff0182016fffff0181af80ff018080ff808080ffff02ff17ff81bf8080ffff04ffff0147ff018080");
pub const COVENANT_LAYER_HASH: [u8; 32] =
    hex!("b982796850336aabf9ab17c3f21e299f0c633444117ab5e9ebeafadf1860d9fc");

/// ```text
/// ; This is a PARENT_MORPHER for use with covenant_layer.clsp
///
/// ; It is used to prove that the parent was a singleton -> exigent metadata layer (w/ covenant_layer in TP) puzzle stack
/// (mod
///   (
///     ; We curry twice: first, all of the static information we need, then the hash of the program with all of that info
///     ; this allows use to be more efficient when calculating our own hash (a (q . SELF_HASH) (c SELF_HASH 1))
///     ; curried first - a bunch of info to create a singleton -> ownership layer puzzle stack
///     COVENANT_MOD_HASH
///     EML_MOD_HASH
///     ADAPTER_MOD_HASH
///     SINGLETON_MOD_HASH
///     SINGLETON_LAUNCHER_HASH_HASH
///     TP_HASH
///     ; curried second
///     SELF_HASH  ; tree hash of all the other hashes above
///     ; Truths
///     COVENANT_INITIAL_PUZZLE_HASH
///     PREVIOUS_INNER_PUZHASH
///     ; solution
///     previous_metadata_hash  ; pre-treehashed METADATA from our parent's EML
///     my_singleton_id  ; no need to commit to this, our parent is guaranteed to be a singleton with the same ID as ours
///   )
///
///   (include curry.clib)
///
///   (defconstant ONE 1)
///
///   (defun main
///     (
///       EML_MOD_HASH
///       SINGLETON_MOD_HASH
///       SINGLETON_LAUNCHER_HASH_HASH
///       PREVIOUS_INNER_PUZHASH
///       previous_metadata_hash
///       my_singleton_id
///       tp_hash
///     )
///
///     (curry_hashes SINGLETON_MOD_HASH
///       (sha256 TWO
///         (sha256 ONE SINGLETON_MOD_HASH)
///         (sha256 TWO
///           (sha256 ONE my_singleton_id)
///           SINGLETON_LAUNCHER_HASH_HASH
///         )
///       )
///       (curry_hashes EML_MOD_HASH
///         (sha256 ONE EML_MOD_HASH)
///         previous_metadata_hash
///         tp_hash
///         (sha256 ONE tp_hash)
///         PREVIOUS_INNER_PUZHASH
///       )
///     )
///   )
///
///   (main
///     EML_MOD_HASH
///     SINGLETON_MOD_HASH
///     SINGLETON_LAUNCHER_HASH_HASH
///     PREVIOUS_INNER_PUZHASH
///     previous_metadata_hash
///     my_singleton_id
///     (curry_hashes ADAPTER_MOD_HASH
///       (curry_hashes COVENANT_MOD_HASH
///         (sha256 ONE COVENANT_INITIAL_PUZZLE_HASH)
///         (curry_hashes SELF_HASH
///           (sha256 ONE SELF_HASH)
///         )
///         TP_HASH
///       )
///     )
///   )
/// )
/// ```
pub const EML_COVENANT_MORPHER: [u8; 589] = hex!("ff02ffff01ff02ff1effff04ff02ffff04ff0bffff04ff2fffff04ff5fffff04ff8205ffffff04ff820bffffff04ff8217ffffff04ffff02ff1affff04ff02ffff04ff17ffff04ffff02ff1affff04ff02ffff04ff05ffff04ffff0bff08ff8202ff80ffff04ffff02ff1affff04ff02ffff04ff82017fffff04ffff0bff08ff82017f80ff8080808080ffff04ff81bfff80808080808080ff8080808080ff80808080808080808080ffff04ffff01ffff01ff02ff02ffff03ff05ffff01ff0bff72ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff1cffff04ff02ffff04ff0dff80808080ff808080808080ffff016280ff0180ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff0bff52ffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff1cffff04ff02ffff04ff07ff80808080ff808080808080ffff0bff14ffff0bff14ff62ff0580ffff0bff14ff0bff428080ff02ff1affff04ff02ffff04ff0bffff04ffff0bff14ffff0bff08ff0b80ffff0bff14ffff0bff08ff81bf80ff178080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ffff0bff08ff0580ffff04ff5fffff04ff82017fffff04ffff0bff08ff82017f80ffff04ff2fff808080808080808080ff808080808080ff018080");
pub const EML_COVENANT_MORPHER_HASH: [u8; 32] =
    hex!("6a87946257f555ae82aca6a11b5205058b844f634ecb6c7dc6b0c54eb2996308");

/// ```text
/// ; This is a layer that adapts the API between an ownership layer and its transfer program when the transfer program is
/// ; wrapped with a covenant layer.
/// (mod
///   (
///     COVENANT_LAYER
///     METADATA  ; Truth
///     CONDITIONS  ; Truth
///     ; covenant layer solution
///     (
///       lineage_proof
///       morpher_solution
///       inner_solution
///     )
///   )
///
///   ; Solution from covenant layer comes back like so:
///   ; ((ASSERT_MY_PARENT_ID 0x...) new_metadata new_tp conditions)
///   ; so we need to move that ASSERT_MY_PARENT_ID to the returned conditions from the TP
///   (defun fix_condition ((parent_assertion . (new_owner new_tp conditions)))
///     (list new_owner new_tp (c parent_assertion conditions))
///   )
///
///   (fix_condition (a
///       COVENANT_LAYER
///       (list
///         lineage_proof
///         morpher_solution
///         ; Covenant layer doesn't know about truths so we need to pass those down to the inner tp solution
///         (list METADATA CONDITIONS inner_solution)
///       )
///   ))
/// )
/// ```
pub const EML_TRANSFER_PROGRAM_COVENANT_ADAPTER: [u8; 104] = hex!("ff02ffff01ff02ff02ffff04ff02ffff04ffff02ff05ffff04ff4fffff04ff81afffff04ffff04ff0bffff04ff17ffff04ff82016fff80808080ff8080808080ff80808080ffff04ffff01ff04ff15ffff04ff2dffff04ffff04ff09ff5d80ff80808080ff018080");
pub const EML_TRANSFER_PROGRAM_COVENANT_ADAPTER_HASH: [u8; 32] =
    hex!("4218fbebbb6f3c0907ebe8a672fa5d1e4bc655645a3a0073601e6c9b50b07c47");

/// ```text
/// ; This is a TRANSFER_PROGRAM for use with exigent_metadata_layer.clsp
///
/// ; Given a DID's singleton struct, assert its announcement of any changes. If no DID's innerpuz is provided, then just
/// ; return the same metadata and transfer program with no conditions
///
/// ; This TP also allows metadata to be cleared and transfer program to be reset simultaneously, no DID required
/// (mod
///   (
///     SINGLETON_MOD_HASH
///     SINGLETON_LAUNCHER_HASH
///     (provider_id . metadata)  ; Truth
///     conditions  ; Truth
///     ; tp_solution looks like this in the case of a DID update
///     (
///       provider_innerpuzhash
///       my_coin_id
///       new_metadata
///       new_transfer_program_hash
///     )
///     ; tp_solution could also be () or new_transfer_program_hash for two other cases:
///     ;  - () == continue with the same metadata we currently have
///     ;  - new_transfer_program_hash == update the transfer program to whatever, but clear the metadata
///   )
///
///   (include condition_codes.clib)
///   (include curry.clib)
///   (include sha256tree.clib)
///   (include utility_macros.clib)
///
///   (defconstant ONE 1)
///
///   (defun-inline create_did_puzhash
///     (
///       SINGLETON_MOD_HASH
///       SINGLETON_LAUNCHER_HASH
///       provider_id
///       provider_innerpuzhash
///     )
///
///     (curry_hashes_inline SINGLETON_MOD_HASH
///       ; calculate the singleton struct
///       (sha256 TWO
///         (sha256 ONE SINGLETON_MOD_HASH)
///         (sha256 TWO
///           (sha256 ONE provider_id)
///           (sha256 ONE SINGLETON_LAUNCHER_HASH)
///         )
///       )
///       provider_innerpuzhash
///     )
///   )
///
///   ; Returning (new_metadata new_transfer_program_hash conditions)
///   (if (l (f (r (r (r (r (r @)))))))  ; If a tp solution was provided
///       (list
///         (i new_metadata (c provider_id new_metadata) ())
///         new_transfer_program_hash
///         (list
///           (list ASSERT_MY_COIN_ID my_coin_id)
///           ; get an announcement from the DID in the EML's metadata to update to a new metadata and transfer program
///           (list ASSERT_PUZZLE_ANNOUNCEMENT
///             (sha256
///               (create_did_puzhash SINGLETON_MOD_HASH SINGLETON_LAUNCHER_HASH provider_id provider_innerpuzhash)
///               (sha256
///                 my_coin_id
///                 (sha256tree new_metadata)
///                 new_transfer_program_hash
///               )
///             )
///           )
///         )
///       )
///       ; else - the tp_solution is an atom
///       (if (f (r (r (r (r (r @))))))  ; If a new_transfer_program_hash was provided
///           (list () (f (r (r (r (r (r @)))))) ())
///           ; else - No new TP was provided, continue with current metadata
///           (list (c provider_id metadata) () ())
///       )
///   )
/// )
/// ```
pub const EML_UPDATE_METADATA_WITH_DID: [u8; 552] = hex!("ff02ffff01ff02ffff03ffff07ff5f80ffff01ff04ffff03ff8202dfffff04ff27ff8202df80ff8080ffff04ff8205dfffff04ffff04ffff04ff08ffff04ff82015fff808080ffff04ffff04ff14ffff04ffff0bffff0bff56ffff0bff0affff0bff0aff66ff0580ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ffff0bff0affff0bff1cff0580ffff0bff0affff0bff1cff2780ffff0bff1cff0b80808080ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff819f80ffff0bff0aff66ff46808080ff46808080ff46808080ffff0bff82015fffff02ff1effff04ff02ffff04ff8202dfff80808080ff8205df8080ff808080ff808080ff80808080ffff01ff02ffff03ff5fffff01ff04ff80ffff04ff5fffff01ff80808080ffff01ff04ffff04ff27ff3780ffff01ff80ff80808080ff018080ff0180ffff04ffff01ffff46ff3f01ff02ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const EML_UPDATE_METADATA_WITH_DID_HASH: [u8; 32] =
    hex!("d3a9a1fc20f247d009b4b0e941707d50b91885c99d0b27ef882e1294e771139d");

/// ```text
/// ; This layer is an outer puzzle that keeps some metadata that must be reaffirmed by a "transfer program" on every spend.
/// ;
/// ; In a way, this puzzle acts as a p2_merkle_tree puzzle where there are always two leaves and BOTH must run every spend.
/// ;
/// ; The inner puzzle runs first and actually supplies the solution to the transfer program.
/// ;
/// ; Likely, the transfer program is placed into the EML by a party who does not currently control the coin, to enforce
/// ; that certain behaviors regarding the curried metadata are followed.
/// (mod
///   (
///     THIS_MOD_HASH
///     METADATA  ; The metadata can be anything. It is passed to the transfer program and new metadata is returned.
///     TRANSFER_PROGRAM  ; Runs every spend, solution supplied by the inner puzzle
///     TRANSFER_PROGRAM_HASH  ; we also include the hash for efficiency's sake when re-calculating our own hash
///     INNER_PUZZLE
///     inner_solution
///   )
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include utility_macros.clib)
///
///   (defun-inline nft_ownership_layer_puzzle_hash
///     (
///       THIS_MOD_HASH
///       new_owner
///       TRANSFER_PROGRAM_HASH
///       inner_puzzle_hash
///     )
///     (puzzle-hash-of-curried-function THIS_MOD_HASH
///       inner_puzzle_hash
///       (sha256 ONE TRANSFER_PROGRAM_HASH)
///       TRANSFER_PROGRAM_HASH
///       (sha256tree new_owner)
///       (sha256 ONE THIS_MOD_HASH)
///     )
///   )
///
///   (defun-inline construct_end_conditions
///     (
///       THIS_MOD_HASH
///       TRANSFER_PROGRAM
///       TRANSFER_PROGRAM_HASH
///       odd_args
///       (new_owner new_tp_hash conditions)
///     )
///     (c
///       (c
///         CREATE_COIN
///         (c
///           (nft_ownership_layer_puzzle_hash
///             THIS_MOD_HASH
///             new_owner
///             (if new_tp_hash new_tp_hash TRANSFER_PROGRAM_HASH)
///             (f odd_args)
///           )
///           (r odd_args)
///         )
///       )
///       conditions
///     )
///   )
///
///   (defun process_conditions
///     (
///       THIS_MOD_HASH
///       TRANSFER_PROGRAM
///       TRANSFER_PROGRAM_HASH
///       METADATA
///       all_conditions
///       conditions
///       ; These args all start at ()
///       (
///         odd_args
///         tp_output
///         condition_to_prepend
///       )
///     )
///     ; This loop works a bit differently than most condition wrapping loops
///     ;
///     ; We expect an invalid condition (-10) that we must strip out, but we must also wrap the odd create coin based on
///     ; information from that condition.
///     ;
///     ; To facilitate this, each iteration of the loop calls the next iteration with the condition it wishes to prepend
///     ; to the list. If we want to strip out a condition, we call the next iteration with () as condition_to_prepend
///     ; which will cause an empty REMARK condition to be prepended as a no-op instead. The two conditions that will
///     ; trigger this are the magic condition (-10) and the odd create coin condition. The magic condition never makes it
///     ; back into the list, but the CREATE_COIN is re-created wrapped by construct_end_conditions.
///     (c
///       (i condition_to_prepend condition_to_prepend (list REMARK))
///       (if conditions
///           (process_conditions
///             THIS_MOD_HASH
///             TRANSFER_PROGRAM
///             TRANSFER_PROGRAM_HASH
///             METADATA
///             all_conditions
///             (r conditions)
///             (if (= (f (f conditions)) CREATE_COIN)
///                 (if (logand (f (r (r (f conditions)))) 1)
///                     (assert (not odd_args)
///                       ; then
///                       (list (r (f conditions)) tp_output ())
///                     )
///                     ; else - amount is not odd
///                     (list odd_args tp_output (f conditions))
///                 )
///                 ; else - condition is not a create coin
///                 (if (= (f (f conditions)) -10)  ; -10 is "magic" opcode for running transfer program
///                     (assert (not tp_output)
///                       ; then
///                       (list
///                         odd_args
///                         (a TRANSFER_PROGRAM (list METADATA all_conditions (r (f conditions))))
///                         ()
///                       )
///                     )
///                     ; else - condition is not a create coin nor a NEW_OWNER_CONDITION
///                     (list odd_args tp_output (f conditions))
///                 )
///             )
///           )
///           ; else - we have no more conditions
///           ; odd_args and tp_solution are guaranteed to not be nil or else we'll have a path into atom error
///           (construct_end_conditions
///             THIS_MOD_HASH
///             TRANSFER_PROGRAM
///             TRANSFER_PROGRAM_HASH
///             odd_args
///             tp_output
///           )
///       )
///     )
///   )
///
///   (defun main
///     (
///       THIS_MOD_HASH
///       TRANSFER_PROGRAM
///       TRANSFER_PROGRAM_HASH
///       METADATA
///       conditions
///     )
///     (process_conditions
///       THIS_MOD_HASH
///       TRANSFER_PROGRAM
///       TRANSFER_PROGRAM_HASH
///       METADATA
///       conditions
///       conditions
///       (list () () ())
///     )
///   )
///
///   ; main
///   (main
///     THIS_MOD_HASH
///     TRANSFER_PROGRAM
///     TRANSFER_PROGRAM_HASH
///     METADATA
///     (a INNER_PUZZLE inner_solution)
///   )
/// )
/// ```
pub const EXIGENT_METADATA_LAYER: [u8; 888] = hex!("ff02ffff01ff02ff3affff04ff02ffff04ff05ffff04ff17ffff04ff2fffff04ff0bffff04ffff02ff5fff81bf80ff8080808080808080ffff04ffff01ffffff02ff3304ff01ff0101ffff02ffff02ffff03ff05ffff01ff02ff2affff04ff02ffff04ff0dffff04ffff0bff12ffff0bff14ff3880ffff0bff12ffff0bff12ffff0bff14ff2c80ff0980ffff0bff12ff0bffff0bff14ff8080808080ff8080808080ffff010b80ff0180ff02ff16ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff5fffff04ff5fffff01ffff80ff80ff8080808080808080808080ffff04ffff03ff820b7fff820b7fffff04ff3cff808080ffff02ffff03ff81bfffff01ff02ff16ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff2fffff04ff5fffff04ff8201bfffff04ffff02ffff03ffff09ff82023fff2880ffff01ff02ffff03ffff18ff820b3fffff010180ffff01ff02ffff03ffff20ff82027f80ffff01ff04ff82033fffff04ff82057fffff01ff80808080ffff01ff088080ff0180ffff01ff04ff82027fffff04ff82057fffff04ff82013fff8080808080ff0180ffff01ff02ffff03ffff09ff82023fffff0181f680ffff01ff02ffff03ffff20ff82057f80ffff01ff04ff82027fffff04ffff02ff0bffff04ff2fffff04ff5fffff04ff82033fff8080808080ffff01ff80808080ffff01ff088080ff0180ffff01ff04ff82027fffff04ff82057fffff04ff82013fff8080808080ff018080ff0180ff80808080808080808080ffff01ff04ffff04ff28ffff04ffff02ff2effff04ff02ffff04ff05ffff04ff82047fffff04ffff0bff14ffff02ffff03ff82157fffff0182157fffff011780ff018080ffff04ffff02ffff03ff82157fffff0182157fffff011780ff0180ffff04ffff02ff3effff04ff02ffff04ff82097fff80808080ffff04ffff0bff14ff0580ff808080808080808080ff82067f8080ff822d7f8080ff018080ffff0bff12ffff0bff14ff1080ffff0bff12ffff0bff12ffff0bff14ff2c80ff0580ffff0bff12ffff02ff2affff04ff02ffff04ff07ffff04ffff0bff14ff1480ff8080808080ffff0bff14ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const EXIGENT_METADATA_LAYER_HASH: [u8; 32] =
    hex!("d5fd32e069fda83e230ccd8f6a7c4f652231aed5c755514b3d996cbeff4182b8");

/// ```text
/// ; This is a generalization of the idea behind singleton_launcher.clsp
///
/// ; Given a delegated puzzle and solution, just run them and announce the hash of the delegated puzzle.
/// ; A parent can rely on this announcement so if the exact delegated_puzzle it is expecting is not run, the whole bundle
/// ; fails due to a grandparent paradox.
/// (mod
///   (
///     delegated_puzzle
///     delegated_solution
///   )
///
///   (include condition_codes.clib)
///   (include sha256tree.clib)
///
///   (c (list CREATE_COIN_ANNOUNCEMENT (sha256tree delegated_puzzle)) (a delegated_puzzle delegated_solution))
/// )
/// ```
pub const P2_ANNOUNCED_DELEGATED_PUZZLE: [u8; 137] = hex!("ff02ffff01ff04ffff04ff04ffff04ffff02ff06ffff04ff02ffff04ff05ff80808080ff808080ffff02ff05ff0b8080ffff04ffff01ff3cff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_ANNOUNCED_DELEGATED_PUZZLE_HASH: [u8; 32] =
    hex!("c4d24c3c5349376f3e8f3aba202972091713b4ec4915f0f26192ae4ace0bd04d");

/// ```text
/// ; This is the standard puzzle that a VerifiedCredential provider will put into the revocation layer slot of revocation_layer.clsp
///
/// ; The goal of this puzzle is to recreate the VC exactly as it is except for three things:
/// ; 1) There is no longer a revocation layer
/// ; 2) The metadata in the ownership layer becomes ()
/// ; 3) The transfer program in the ownership layer becomes a curried default
/// (mod
///   (
///     SINGLETON_MOD_HASH
///     SINGLETON_LAUNCHER_HASH_HASH
///     OWNERSHIP_LAYER_MOD_HASH
///     REVOCATION_LAYER_MOD_HASH
///     DEFAULT_TRANSFER_PROGRAM_HASH
///     ; most of the specific information is solved rather than curried in because we don't care about committing to it
///     launcher_id  ; of the singleton this is inside of
///     metadata_hash  ; of the EML this is inside of
///     tp_hash  ; of the EML this is inside of
///     this_hash_hash  ; the hash of this puzzle with all of its curried arguments hashed AGAIN with (sha256 1 this_hash)
///     inner_puzzle_hash  ; that determines ownership of this coin
///     my_amount  ; this coin's amount
///     ownership_lineage_proof  ; need to solve the covenant layer one last time
///     previous_metadata_hash  ; like metadata_hash above but for the previous coin
///     announcement_nonce  ; Anything to announce (for fees/DID to hook onto)
///     (
///       provider_innerpuzhash  ; DID needs to authorize the transfer program (and therefore this revocation layer)
///       my_coin_id
///     )
///   )
///
///   (include condition_codes.clib)
///   (include curry.clib)
///
///   (defconstant ONE 1)
///
///   (list
///     ; The purpose of this condition is just to make sure we're telling the truth about the current inner puzzle hash
///     (list ASSERT_MY_PUZZLEHASH
///       (curry_hashes SINGLETON_MOD_HASH
///         (sha256 TWO
///           (sha256 ONE SINGLETON_MOD_HASH)
///           (sha256 TWO
///             (sha256 ONE launcher_id)
///             SINGLETON_LAUNCHER_HASH_HASH
///           )
///         )
///         (curry_hashes OWNERSHIP_LAYER_MOD_HASH
///           (sha256 ONE OWNERSHIP_LAYER_MOD_HASH)
///           metadata_hash
///           tp_hash
///           (sha256 ONE tp_hash)
///           (curry_hashes REVOCATION_LAYER_MOD_HASH
///             (sha256 ONE REVOCATION_LAYER_MOD_HASH)
///             this_hash_hash
///             (sha256 ONE inner_puzzle_hash)
///           )
///         )
///       )
///     )
///     (list ASSERT_MY_AMOUNT my_amount)
///     (list CREATE_COIN inner_puzzle_hash my_amount)
///     (list CREATE_COIN_ANNOUNCEMENT announcement_nonce)  ; For fee hooks
///     (list
///       -10
///       ownership_lineage_proof  ; for covenant layer
///       (list previous_metadata_hash launcher_id)  ; for covenant layer parent morpher
///       (list  ; for transfer program
///         provider_innerpuzhash
///         my_coin_id
///         ()
///         DEFAULT_TRANSFER_PROGRAM_HASH
///       )
///     )
///   )
/// )
/// ```
pub const STANDARD_VC_REVOCATION_PUZZLE: [u8; 652] = hex!("ff02ffff01ff04ffff04ff18ffff04ffff02ff2effff04ff02ffff04ff05ffff04ffff0bff12ffff0bff3cff0580ffff0bff12ffff0bff3cff81bf80ff0b8080ffff04ffff02ff2effff04ff02ffff04ff17ffff04ffff0bff3cff1780ffff04ff82017fffff04ff8202ffffff04ffff0bff3cff8202ff80ffff04ffff02ff2effff04ff02ffff04ff2fffff04ffff0bff3cff2f80ffff04ff8205ffffff04ffff0bff3cff820bff80ff80808080808080ff808080808080808080ff808080808080ff808080ffff04ffff04ff10ffff04ff8217ffff808080ffff04ffff04ff14ffff04ff820bffffff04ff8217ffff80808080ffff04ffff04ff2cffff04ff82bfffff808080ffff04ffff04ffff0181f6ffff04ff822fffffff04ffff04ff825fffffff04ff81bfff808080ffff04ffff04ff83027fffffff04ff83057fffffff04ff80ffff04ff5fff8080808080ff8080808080ff808080808080ffff04ffff01ffffff4948ff33ff3c01ffff02ff02ffff03ff05ffff01ff0bff76ffff02ff3effff04ff02ffff04ff09ffff04ffff02ff1affff04ff02ffff04ff0dff80808080ff808080808080ffff016680ff0180ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff0bff56ffff02ff3effff04ff02ffff04ff05ffff04ffff02ff1affff04ff02ffff04ff07ff80808080ff808080808080ff0bff12ffff0bff12ff66ff0580ffff0bff12ff0bff468080ff018080");
pub const STANDARD_VC_REVOCATION_PUZZLE_HASH: [u8; 32] =
    hex!("fbce76408ebaf9b3d0b8cd90cc68607755eeca67cd7432d5eea85f3f498cc002");

/// ```text
/// ; This is a PARENT_MORPHER for use with covenant_layer.clsp
///
/// ; You would use this morpher when the covenant layer is the outermost layer of the coin
/// (mod
///   (
///     THIS_MOD_HASH
///     COVENANT_MOD_HASH
///     COVENANT_INITIAL_PUZZLE_HASH
///     inner_puzhash
///   )
///
///   (include curry.clib)
///
///   (curry_hashes_inline COVENANT_MOD_HASH
///     (sha256 1 COVENANT_INITIAL_PUZZLE_HASH)
///     (curry_hashes_inline THIS_MOD_HASH
///       (sha256 1 THIS_MOD_HASH)
///       (sha256 1 COVENANT_MOD_HASH)
///       (sha256 1 COVENANT_INITIAL_PUZZLE_HASH)
///     )
///     inner_puzhash
///   )
/// )
/// ```
pub const STD_PARENT_MORPHER: [u8; 427] = hex!("ff02ffff01ff0bff16ffff0bff04ffff0bff04ff1aff0b80ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff178080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bff16ffff0bff04ffff0bff04ff1aff0580ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff058080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff0b8080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff178080ffff0bff04ff1aff12808080ff12808080ff12808080ff1280808080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1aff2f80ffff0bff04ff1aff12808080ff12808080ff12808080ff12808080ffff04ffff01ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff018080");
pub const STD_PARENT_MORPHER_HASH: [u8; 32] =
    hex!("8c3f1dc2e46c0d7ec4c2cbd007e23c0368ff8f80c5bc0101647a5c27626ebce6");

/// ```text
/// ; This layer ensures that a second puzzle hash or "revocation layer" that can be used without the inner puzzle's permission
/// ; travels with each generation of a coin.
///
/// ; The hidden puzzle is responsible for recreating this layer if it wishes, this layer will not wrap its outputs.
/// (mod
///   (
///     THIS_MOD_HASH
///     HIDDEN_PUZZLE_HASH
///     INNER_PUZZLE_HASH  ; must be a hash so that the revocation layer has enough info to create a puzzle reveal to spend the coin
///     hidden  ; bool for whether or not to run the hidden puzzle
///     inner_or_hidden_puzzle_reveal
///     inner_or_hidden_solution
///   )
///
///   (include condition_codes.clib)
///   (include curry.clib)
///   (include sha256tree.clib)
///   (include utility_macros.clib)
///
///   (defconstant ONE 1)
///
///   (defun-inline wrap_puzhash
///     (
///       THIS_MOD_HASH
///       HIDDEN_PUZZLE_HASH
///       new_inner_puzzle_hash
///     )
///
///     (curry_hashes_inline THIS_MOD_HASH
///       (sha256 ONE THIS_MOD_HASH)
///       (sha256 ONE HIDDEN_PUZZLE_HASH)
///       (sha256 ONE new_inner_puzzle_hash)
///     )
///   )
///
///   (defun wrap_create_coins
///     (
///       THIS_MOD_HASH
///       HIDDEN_PUZZLE_HASH
///       conditions
///     )
///     (if conditions
///         (if (= (f (f conditions)) CREATE_COIN)
///             (c
///               (c CREATE_COIN (c (wrap_puzhash THIS_MOD_HASH HIDDEN_PUZZLE_HASH (f (r (f conditions)))) (r (r (f conditions)))))
///               (wrap_create_coins THIS_MOD_HASH HIDDEN_PUZZLE_HASH (r conditions))
///             )
///             (c (f conditions) (wrap_create_coins THIS_MOD_HASH HIDDEN_PUZZLE_HASH (r conditions)))
///         )
///         ()
///     )
///   )
///
///   (if hidden
///       (assert (= HIDDEN_PUZZLE_HASH (sha256tree inner_or_hidden_puzzle_reveal))
///         ; then
///         (a inner_or_hidden_puzzle_reveal inner_or_hidden_solution)
///       )
///       (assert (= INNER_PUZZLE_HASH (sha256tree inner_or_hidden_puzzle_reveal))
///         ; then
///         (wrap_create_coins THIS_MOD_HASH HIDDEN_PUZZLE_HASH (a inner_or_hidden_puzzle_reveal inner_or_hidden_solution))
///       )
///   )
/// )
/// ```
pub const REVOCATION_LAYER: [u8; 653] = hex!("ff02ffff01ff02ffff03ff2fffff01ff02ffff03ffff09ff0bffff02ff16ffff04ff02ffff04ff5fff8080808080ffff01ff02ff5fff81bf80ffff01ff088080ff0180ffff01ff02ffff03ffff09ff17ffff02ff16ffff04ff02ffff04ff5fff8080808080ffff01ff02ff1effff04ff02ffff04ff05ffff04ff0bffff04ffff02ff5fff81bf80ff808080808080ffff01ff088080ff018080ff0180ffff04ffff01ffff33ff0102ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ffff03ff17ffff01ff02ffff03ffff09ff47ff0880ffff01ff04ffff04ff08ffff04ffff0bff2affff0bff1cffff0bff1cff32ff0580ffff0bff1cffff0bff3affff0bff1cffff0bff1cff32ffff0bff14ff058080ffff0bff1cffff0bff3affff0bff1cffff0bff1cff32ffff0bff14ff0b8080ffff0bff1cffff0bff3affff0bff1cffff0bff1cff32ffff0bff14ff81a78080ffff0bff1cff32ff22808080ff22808080ff22808080ff22808080ff81e78080ffff02ff1effff04ff02ffff04ff05ffff04ff0bffff04ff37ff80808080808080ffff01ff04ff27ffff02ff1effff04ff02ffff04ff05ffff04ff0bffff04ff37ff8080808080808080ff0180ff8080ff0180ff018080");
pub const REVOCATION_LAYER_HASH: [u8; 32] =
    hex!("00848115554ea674131f89f311707a959ad3f4647482648f3fe91ba289131f51");

/// ```text
/// (mod (METADATA conditions . solution) (if solution solution (list METADATA () ())))
/// ```
pub const ACS_TRANSFER_PROGRAM: [u8; 31] =
    hex!("ff02ffff03ff07ffff0107ffff01ff04ff02ffff01ff80ff80808080ff0180");
pub const ACS_TRANSFER_PROGRAM_HASH: [u8; 32] =
    hex!("664e6e57ac6a184334a3e743c446c5d28c0dd2ae6f84bad6dacec29ab7a0bd43");

/// ```text
/// (mod
///   (
///     CONDITION
///     INNER_PUZZLE
///     inner_solution
///   )
///
///   (c
///     CONDITION
///     (a INNER_PUZZLE inner_solution)
///   )
///
/// )
/// ```
pub const AUGMENTED_CONDITION: [u8; 13] = hex!("ff04ff02ffff02ff05ff0b8080");
pub const AUGMENTED_CONDITION_HASH: [u8; 32] =
    hex!("d303eafa617bedf0bc05850dd014e10fbddf622187dc07891a2aacba9d8a93f6");

/// ```text
/// (mod (
///     TARGET
///     AMOUNT
///   )
///   (include condition_codes.clib)
///   (list (list CREATE_COIN TARGET AMOUNT) (list CREATE_COIN_ANNOUNCEMENT ()))
/// )
/// ```
pub const NOTIFICATION: [u8; 59] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff04ff0bff80808080ffff04ffff04ff06ffff01ff808080ff808080ffff04ffff01ff333cff018080");
pub const NOTIFICATION_HASH: [u8; 32] =
    hex!("b8b9d8ffca6d5cba5422ead7f477ecfc8f6aaaa1c024b8c3aeb1956b24a0ab1e");

/// ```text
/// (mod
///   (
///     MERKLE_ROOT
///     merkle_proof
///     puzzle_to_execute
///     inner_solution
///   )
///
///   (include utility_macros.clib)
///   (include merkle_utils.clib)
///
///   ; takes a lisp tree and returns the hash of it
///   (defun sha256tree (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE)))
///   (sha256 1 TREE)))
///
///   (assert (= MERKLE_ROOT (simplify_merkle_proof (sha256tree puzzle_to_execute) merkle_proof))
///     (a puzzle_to_execute inner_solution)
///   )
///
/// )
/// ```
pub const P2_1_OF_N: [u8; 280] = hex!("ff02ffff01ff02ffff03ffff09ff05ffff02ff06ffff04ff02ffff04ffff0bffff0101ffff02ff04ffff04ff02ffff04ff17ff8080808080ffff04ff0bff808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff04ffff01ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff04ffff04ff02ffff04ff09ff80808080ffff02ff04ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ffff03ff1bffff01ff02ff06ffff04ff02ffff04ffff02ffff03ffff18ffff0101ff1380ffff01ff0bffff0102ff2bff0580ffff01ff0bffff0102ff05ff2b8080ff0180ffff04ffff04ffff17ff13ffff0181ff80ff3b80ff8080808080ffff010580ff0180ff018080");
pub const P2_1_OF_N_HASH: [u8; 32] =
    hex!("46b29fd87fbeb6737600c4543931222a6c1ed3db6fa5601a3ca284a9f4efe780");

/// ```text
/// (mod (conditions)
///   (qq (q . (unquote conditions)))
/// )
/// ```
pub const P2_CONDITIONS: [u8; 9] = hex!("ff04ffff0101ff0280");
pub const P2_CONDITIONS_HASH: [u8; 32] =
    hex!("1c77d7d5efde60a7a1d2d27db6d746bc8e568aea1ef8586ca967a0d60b83cc36");

/// ```text
/// (mod
///   (public_key conditions)
///
///   (include condition_codes.clib)
///
///   ;; hash a tree
///   ;; This is used to calculate a puzzle hash given a puzzle program.
///   (defun sha256tree1
///     (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   (c (list AGG_SIG_ME public_key (sha256tree1 conditions)) conditions)
///
/// )
/// ```
pub const P2_DELEGATED_CONDITIONS: [u8; 137] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff0bff80808080ff80808080ff0b80ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_DELEGATED_CONDITIONS_HASH: [u8; 32] =
    hex!("0ff94726f1a8dea5c3f70d3121945190778d3b2b3fcda3735a1f290977e98341");

/// ```text
/// ; build a pay-to delegated puzzle or hidden puzzle
/// ; coins can be unlocked by signing a delegated puzzle and its solution
/// ; OR by revealing the hidden puzzle and the underlying original key
///
/// ; glossary of parameter names:
///
/// ; hidden_puzzle: a "hidden puzzle" that can be revealed and used as an alternate
/// ;   way to unlock the underlying funds
/// ;
/// ; synthetic_key_offset: a private key cryptographically generated using the hidden
/// ;   puzzle and as inputs `original_public_key`
/// ;
/// ; SYNTHETIC_PUBLIC_KEY: the public key that is the sum of `original_public_key` and the
/// ;   public key corresponding to `synthetic_key_offset`
/// ;
/// ; original_public_key: a public key, where knowledge of the corresponding private key
/// ;   represents ownership of the file
/// ;
/// ; delegated_puzzle: a delegated puzzle, as in "graftroot", which should return the
/// ;   desired conditions.
/// ;
/// ; solution: the solution to the delegated puzzle
///
///
/// (mod
///   ; A puzzle should commit to `SYNTHETIC_PUBLIC_KEY`
///   ;
///   ; The solution should pass in 0 for `original_public_key` if it wants to use
///   ; an arbitrary `delegated_puzzle` (and `solution`) signed by the
///   ; `SYNTHETIC_PUBLIC_KEY` (whose corresponding private key can be calculated
///   ; if you know the private key for `original_public_key`)
///   ;
///   ; Or you can solve the hidden puzzle by revealing the `original_public_key`,
///   ; the hidden puzzle in `delegated_puzzle`, and a solution to the hidden puzzle.
///
///   (SYNTHETIC_PUBLIC_KEY original_public_key delegated_puzzle solution)
///
///   ; "assert" is a macro that wraps repeated instances of "if"
///   ; usage: (assert A0 A1 ... An R)
///   ; all of A0, A1, ... An must evaluate to non-null, or an exception is raised
///   ; return the value of R (if we get that far)
///
///   (defmacro assert items
///     (if (r items)
///         (list if (f items) (c assert (r items)) (q . (x)))
///         (f items)
///     )
///   )
///
///   (include condition_codes.clib)
///
///   ;; hash a tree
///   ;; This is used to calculate a puzzle hash given a puzzle program.
///   (defun sha256tree1
///     (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   ; "is_hidden_puzzle_correct" returns true iff the hidden puzzle is correctly encoded
///
///   (defun-inline is_hidden_puzzle_correct (SYNTHETIC_PUBLIC_KEY original_public_key delegated_puzzle)
///     (=
///       SYNTHETIC_PUBLIC_KEY
///       (point_add
///         original_public_key
///         (pubkey_for_exp (sha256 original_public_key (sha256tree1 delegated_puzzle)))
///       )
///     )
///   )
///
///   ; "possibly_prepend_aggsig" is the main entry point
///
///   (defun-inline possibly_prepend_aggsig (SYNTHETIC_PUBLIC_KEY original_public_key delegated_puzzle conditions)
///     (if original_public_key
///         (assert
///           (is_hidden_puzzle_correct SYNTHETIC_PUBLIC_KEY original_public_key delegated_puzzle)
///           conditions
///         )
///         (c (list AGG_SIG_ME SYNTHETIC_PUBLIC_KEY (sha256tree1 delegated_puzzle)) conditions)
///     )
///   )
///
///   ; main entry point
///
///   (possibly_prepend_aggsig
///     SYNTHETIC_PUBLIC_KEY original_public_key delegated_puzzle
///   (a delegated_puzzle solution))
/// )
/// ```
pub const P2_DELEGATED_PUZZLE_OR_HIDDEN_PUZZLE: [u8; 227] = hex!("ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_DELEGATED_PUZZLE_OR_HIDDEN_PUZZLE_HASH: [u8; 32] =
    hex!("e9aaa49f45bad5c889b86ee3341550c155cfdd10c3a6757de618d20612fffd52");

/// ```text
/// (mod
///
///   (public_key delegated_puzzle delegated_puzzle_solution)
///
///   (include condition_codes.clib)
///
///   ;; hash a tree
///   ;; This is used to calculate a puzzle hash given a puzzle program.
///   (defun sha256tree1
///     (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   (c (list AGG_SIG_ME public_key (sha256tree1 delegated_puzzle))
///   (a delegated_puzzle delegated_puzzle_solution))
/// )
/// ```
pub const P2_DELEGATED_PUZZLE: [u8; 143] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff0bff80808080ff80808080ffff02ff0bff178080ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_DELEGATED_PUZZLE_HASH: [u8; 32] =
    hex!("542cde70d1102cd1b763220990873efc8ab15625ded7eae22cc11e21ef2e2f7c");

/// ```text
/// ; build an M of N multisig puzzle
/// ; coins are locked by N public keys, any M of which can delegate a sub-puzzle
///
///
/// ; glossary of parameter names:
///
/// ;  public_key_list: a list of N public keys
///
/// ;  M: the M in "M of N"
///
/// ;  selectors: a list up of 0s and 1s up to size N where exactly M are 1s
/// ;     It's used to select public keys from public_key_list
///
/// ;  delegated_puzzle: the puzzle signed by the M public keys
/// ;     This puzzle must return a list of conditions
///
/// ;  solution: the solution to the delegated puzzle
///
///
/// (mod
///   (M public_key_list selectors delegated_puzzle solution)
///
///   (include condition_codes.clib)
///
///   ;; hash a tree
///   ;; This is used to calculate a puzzle hash given a puzzle program.
///   (defun sha256tree1
///     (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   ; "assert" is a macro that wraps repeated instances of "if"
///   ; usage: (assert A0 A1 ... An R)
///   ; all of A0, A1, ... An must evaluate to non-null, or an exception is raised
///   ; return the value of R (if we get that far)
///
///   (defmacro assert items
///     (if (r items)
///         (list if (f items) (c assert (r items)) (q . (x)))
///         (f items)
///     )
///   )
///
///   ; add_aggsig returns a list of conditions. It includes M AGG_SIG conditions
///   ;   corresponding to the given list of public keys (with the given hash)
///   ;   plus the conditions that come out of the delegated puzzle.
///   ;
///   ; hash is the hash of delegated_puzzle.
///   ;  Yes it's redundant since we include the delegated_puzzle itself,
///   ;  but we don't want to recalculate the hash multiple times as its expensive to do so
///
///   (defun add_aggsig (public_key_list hash delegated_puzzle solution)
///     (if public_key_list
///         (c (list AGG_SIG_UNSAFE (f public_key_list) hash)
///           (add_aggsig (r public_key_list) hash delegated_puzzle solution)
///         )
///         (a delegated_puzzle solution)
///     )
///   )
///
///   ; choose_keys takes a list of selectors and the N public keys and
///   ; returns a list of the M public keys chosen by the selectors
///
///   (defun choose_keys (selectors public_key_list)
///     (if selectors
///         (if (f selectors)
///             (c (f public_key_list) (choose_keys (r selectors) (r public_key_list)))
///         (choose_keys (r selectors) (r public_key_list)))
///         ()
///     )
///   )
///
///
///   ; count the number of non-0 values in the list of selectors and return it as an integer
///
///   (defun count_selectors (selectors)
///     (if selectors
///         (+
///           (count_selectors (r selectors))
///           (if (f selectors) 1 0)
///         )
///         0
///     )
///   )
///
///   ; "solve_puzzle" is the main entry point
///
///   (defun-inline solve_puzzle (M public_key_list selectors delegated_puzzle solution)
///     ; make sure we have exactly M selectors
///     (assert (= M (count_selectors selectors))
///       ; return the AGG_SIG conditions plus the conditions from the delegated_puzzle
///       (add_aggsig (choose_keys selectors public_key_list)
///         (sha256tree1 delegated_puzzle)
///         delegated_puzzle
///       solution)
///     )
///   )
///
///   ; main entry point
///
///   (solve_puzzle
///     M public_key_list
///     selectors delegated_puzzle solution
///   )
/// )
/// ```
pub const P2_M_OF_N_DELEGATE_DIRECT: [u8; 453] = hex!("ff02ffff01ff02ffff03ffff09ff05ffff02ff16ffff04ff02ffff04ff17ff8080808080ffff01ff02ff0cffff04ff02ffff04ffff02ff0affff04ff02ffff04ff17ffff04ff0bff8080808080ffff04ffff02ff1effff04ff02ffff04ff2fff80808080ffff04ff2fffff04ff5fff80808080808080ffff01ff088080ff0180ffff04ffff01ffff31ff02ffff03ff05ffff01ff04ffff04ff08ffff04ff09ffff04ff0bff80808080ffff02ff0cffff04ff02ffff04ff0dffff04ff0bffff04ff17ffff04ff2fff8080808080808080ffff01ff02ff17ff2f8080ff0180ffff02ffff03ff05ffff01ff02ffff03ff09ffff01ff04ff13ffff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ffff01ff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ff0180ff8080ff0180ffff02ffff03ff05ffff01ff10ffff02ff16ffff04ff02ffff04ff0dff80808080ffff02ffff03ff09ffff01ff0101ff8080ff018080ff8080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_M_OF_N_DELEGATE_DIRECT_HASH: [u8; 32] =
    hex!("0f199d5263ac1a62b077c159404a71abd3f9691cc57520bf1d4c5cb501504457");

/// ```text
/// (mod
///   (
///     MORPHER  ; For no morphing, 1
///     parent_parent_id
///     parent_inner_puz
///     parent_amount
///     parent_solution
///   )
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   (c
///     (list ASSERT_MY_PARENT_ID
///       (calculate_coin_id parent_parent_id (a MORPHER (sha256tree parent_inner_puz)) parent_amount)
///     )
///     (a parent_inner_puz parent_solution)
///   )
/// )
/// ```
pub const P2_PARENT: [u8; 242] = hex!("ff02ffff01ff04ffff04ff08ffff04ffff02ff0affff04ff02ffff04ff0bffff04ffff02ff05ffff02ff0effff04ff02ffff04ff17ff8080808080ffff04ff2fff808080808080ff808080ffff02ff17ff5f8080ffff04ffff01ffff4720ffff02ffff03ffff22ffff09ffff0dff0580ff0c80ffff09ffff0dff0b80ff0c80ffff15ff17ffff0181ff8080ffff01ff0bff05ff0bff1780ffff01ff088080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_PARENT_HASH: [u8; 32] =
    hex!("b10ce2d0b18dcf8c21ddfaf55d9b9f0adcbf1e0beb55b1a8b9cad9bbff4e5f22");

/// ```text
/// ;; Works with p2_singleton_via_delegated_puzzle
/// ;; When we have many p2_singleton coins and want to aggregate them together
///
/// ;; all coins make announcements of their puzhash, amount, and ID
/// ;; the aggregator coin (the one creating the output) creates an announcement of the ID of each merge coin
/// ;; each merge coin asserts that the aggregator has an announcement of their (the merge coin's) ID
/// ;; The merge coins each create an announcement of 0 (equivalent to announcing their coin ID)
/// ;; The aggregator asserts that there is a 0 announcement from each of the merge coins
///
/// ;; merge coin announces 0 <-> aggregator asserts that merge coin ID announces 0
/// ;; aggregator announces merge coin ID <-> merge coin asserts that aggregator announces my_id
///
/// (mod
///   (
///     my_id
///     my_puzhash
///     my_amount
///     list_of_parent_puzhash_amounts  ; list of (parent_id puzhash amount) for the merge
///     output_parent_amount  ; (parent_id amount) of the coin creating the output
///   )
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include *standard-cl-21*)
///
///   (defun cons_announcements_to_output (coin_id output)
///     (c
///       (list ASSERT_COIN_ANNOUNCEMENT (sha256 coin_id 0))
///       (c
///         (list CREATE_COIN_ANNOUNCEMENT coin_id)
///         output
///       )
///     )
///   )
///
///   (defun for_parent_puzhash_amounts
///     (
///       my_puzhash
///       (@ coin_info_list ((@ first (parent puzhash amount)) . rest))
///       total
///     )
///     (if coin_info_list
///         (cons_announcements_to_output
///           (calculate_coin_id parent puzhash amount)
///           (for_parent_puzhash_amounts my_puzhash rest (+ total amount))
///         )
///         (list
///           (list ASSERT_HEIGHT_RELATIVE 5)  ; TODO: should this be higher or lower?
///           (list CREATE_COIN my_puzhash total (list my_puzhash))
///         )
///     )
///   )
///
///   (defun-inline give_self_to_merge (my_id my_puzhash (@ output_info (parent amount)))
///     ;; Coins being merged are asserting the output coin id, and insisting it has the same puzhash as them
///     ;; This ensures that the puzzle which issues the CREATE_COIN condition is the same as this puzzle.
///     (list
///       (list CREATE_COIN_ANNOUNCEMENT 0)
///       (list ASSERT_COIN_ANNOUNCEMENT (sha256 (calculate_coin_id parent my_puzhash amount) my_id))
///     )
///   )
///
///
///
///   (c
///     (list ASSERT_MY_AMOUNT my_amount)
///     (c
///       (list ASSERT_MY_PUZZLEHASH my_puzhash)
///       (c
///         (list ASSERT_MY_COIN_ID my_id)
///         (if list_of_parent_puzhash_amounts
///             ; we are making the output
///             (for_parent_puzhash_amounts my_puzhash list_of_parent_puzhash_amounts my_amount)
///             ; we are letting another coin make the output
///             (give_self_to_merge my_id my_puzhash output_parent_amount)
///         )
///       )
///     )
///   )
///
/// )
/// ```
pub const P2_SINGLETON_AGGREGATOR: [u8; 574] = hex!("ff02ffff01ff04ffff04ffff0149ffff04ff17ffff01808080ffff04ffff04ffff0148ffff04ff0bffff01808080ffff04ffff04ffff0146ffff04ff05ffff01808080ffff02ffff03ff2fffff01ff02ffff01ff02ff0effff04ff02ffff04ff0bffff04ff2fffff04ff17ff808080808080ff0180ffff01ff02ffff01ff04ffff04ffff013cffff04ffff0180ffff01808080ffff04ffff04ffff013dffff04ffff0bffff02ff04ffff04ff02ffff04ffff05ff5f80ffff04ff0bffff04ffff05ffff06ff5f8080ff808080808080ff0580ffff01808080ffff01808080ff018080ff0180808080ffff04ffff01ffff02ffff03ffff22ffff09ffff0dff0580ffff012080ffff09ffff0dff0b80ffff012080ffff15ff17ffff0181ff8080ffff01ff02ffff01ff0bff05ff0bff1780ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff04ffff013dffff04ffff0bff05ff8080ff808080ffff04ffff04ffff013cffff04ff05ff808080ff0b8080ff02ffff03ff0bffff01ff02ffff01ff02ff0affff04ff02ffff04ffff02ff04ffff04ff02ffff04ff23ffff04ff53ffff04ff8200b3ff808080808080ffff04ffff02ff0effff04ff02ffff04ff05ffff04ff1bffff04ffff10ff17ff8200b380ff808080808080ff8080808080ff0180ffff01ff02ffff01ff04ffff04ffff0152ffff04ffff0105ffff01808080ffff04ffff04ffff0133ffff04ff05ffff04ff17ffff04ffff04ff05ffff018080ffff018080808080ffff01808080ff018080ff0180ff018080");
pub const P2_SINGLETON_AGGREGATOR_HASH: [u8; 32] =
    hex!("f79a31fcfe3736cc75720617b4cdcb4376b4b8f8f71108617710612b909a4924");

/// ```text
/// (mod (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH SECONDS_DELAY DELAYED_PUZZLE_HASH p1 my_id)
///
///   ;; This puzzle has two escape conditions: the regular "claim via singleton", and the
///   ;; delayed "claim via puzzle hash", delayed by a fixed number of seconds.
///
///   ; SINGLETON_MOD_HASH is the mod-hash for the singleton_top_layer puzzle
///   ; LAUNCHER_ID is the ID of the singleton we are committed to paying to
///   ; LAUNCHER_PUZZLE_HASH is the puzzle hash of the launcher
///   ; SECONDS_DELAY is the number of seconds before the coin can be spent with `DELAYED_PUZZLE_HASH`
///   ; DELAYED_PUZZLE_HASH is the puzzle hash of the delayed puzzle
///   ; if my_id is passed in as () then this signals that we are trying to do a delayed spend case
///   ; p1's meaning changes depending upon which case we're using
///   ; if we are paying to singleton then p1 is singleton_inner_puzzle_hash
///   ; if we are running the delayed case then p1 is the amount to output
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   ;; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (defun-inline delayed_spend (SECONDS_DELAY DELAYED_PUZZLE_HASH amount)
///     (list
///       (list ASSERT_SECONDS_RELATIVE SECONDS_DELAY)
///       (list CREATE_COIN DELAYED_PUZZLE_HASH amount)
///       (list ASSERT_MY_AMOUNT amount)
///     )
///   )
///
///   ;; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (defun-inline calculate_full_puzzle_hash (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH inner_puzzle_hash)
///     (puzzle-hash-of-curried-function SINGLETON_MOD_HASH
///       inner_puzzle_hash
///       (sha256tree (c SINGLETON_MOD_HASH (c LAUNCHER_ID LAUNCHER_PUZZLE_HASH)))
///     )
///   )
///
///   (defun-inline claim_rewards (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash my_id)
///     (list
///       (list ASSERT_PUZZLE_ANNOUNCEMENT (sha256 (calculate_full_puzzle_hash SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash) my_id))
///       (list CREATE_COIN_ANNOUNCEMENT '$')
///     (list ASSERT_MY_COIN_ID my_id))
///   )
///
///   ; main
///   (if my_id
///       (claim_rewards SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH p1 my_id)
///       (delayed_spend SECONDS_DELAY DELAYED_PUZZLE_HASH p1)
///   )
/// )
/// ```
pub const P2_SINGLETON_OR_DELAYED_PUZHASH: [u8; 496] = hex!("ff02ffff01ff02ffff03ff82017fffff01ff04ffff04ff38ffff04ffff0bffff02ff2effff04ff02ffff04ff05ffff04ff81bfffff04ffff02ff3effff04ff02ffff04ffff04ff05ffff04ff0bff178080ff80808080ff808080808080ff82017f80ff808080ffff04ffff04ff3cffff01ff248080ffff04ffff04ff28ffff04ff82017fff808080ff80808080ffff01ff04ffff04ff24ffff04ff2fff808080ffff04ffff04ff2cffff04ff5fffff04ff81bfff80808080ffff04ffff04ff10ffff04ff81bfff808080ff8080808080ff0180ffff04ffff01ffffff49ff463fffff5002ff333cffff04ff0101ffff02ff02ffff03ff05ffff01ff02ff36ffff04ff02ffff04ff0dffff04ffff0bff26ffff0bff2aff1280ffff0bff26ffff0bff26ffff0bff2aff3a80ff0980ffff0bff26ff0bffff0bff2aff8080808080ff8080808080ffff010b80ff0180ffff0bff26ffff0bff2aff3480ffff0bff26ffff0bff26ffff0bff2aff3a80ff0580ffff0bff26ffff02ff36ffff04ff02ffff04ff07ffff04ffff0bff2aff2a80ff8080808080ffff0bff2aff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_SINGLETON_OR_DELAYED_PUZHASH_HASH: [u8; 32] =
    hex!("adb656e0211e2ab4f42069a4c5efc80dc907e7062be08bf1628c8e5b6d94d25b");

/// ```text
/// ;; This puzzle holds an amount which can be spent via two spend paths:
/// ;; 1. to a delegated puzzle provided our owner singleton creates a puzzle announcement of this coin's id and the delegated puzzle.
/// ;; 2. coins of this puzzle type can be merged together without the owner singleton's permission. This spend type is useful for DAOs which use this puzzle to custody funds and want to keep a reasonable limit on the number of coins tracked by DAO wallets.
/// ;; The AGGREGATOR_PUZZLE is curried in to preserve generality and so its logic can be updated without requiring any change to the spend to delegated path. Optionally the Aggregator puzzle can be `(x)` to close off this spend path
///
/// (mod (
///     SINGLETON_STRUCT
///     AGGREGATOR_PUZZLE
///     aggregator_solution  ; (my_id my_puzhash list_of_parent_puzhash_amounts my_amount)
///     singleton_inner_puzhash
///     delegated_puzzle
///     delegated_solution
///     my_id
///   )
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   (defun-inline calculate_full_puzzle_hash (SINGLETON_STRUCT singleton_inner_puzhash)
///     (puzzle-hash-of-curried-function (f SINGLETON_STRUCT)
///       singleton_inner_puzhash
///       (sha256tree SINGLETON_STRUCT)
///     )
///   )
///
///   (if aggregator_solution
///       ; we are merging coins to make a larger coin
///       (a AGGREGATOR_PUZZLE aggregator_solution)
///       ; we are being spent by our singleton
///       (c
///         (list
///           ASSERT_PUZZLE_ANNOUNCEMENT
///           (sha256
///             (calculate_full_puzzle_hash SINGLETON_STRUCT singleton_inner_puzhash)
///             (sha256tree (list my_id (sha256tree delegated_puzzle)))
///           )
///         )
///         (c
///           (list CREATE_COIN_ANNOUNCEMENT '$')
///           (c
///             (list ASSERT_MY_COIN_ID my_id)
///             (a delegated_puzzle delegated_solution)
///           )
///         )
///       )
///   )
/// )
/// ```
pub const P2_SINGLETON_VIA_DELEGATED_PUZZLE: [u8; 474] = hex!("ff02ffff01ff02ffff03ff17ffff01ff02ff0bff1780ffff01ff04ffff04ff18ffff04ffff0bffff02ff2effff04ff02ffff04ff09ffff04ff2fffff04ffff02ff3effff04ff02ffff04ff05ff80808080ff808080808080ffff02ff3effff04ff02ffff04ffff04ff82017fffff04ffff02ff3effff04ff02ffff04ff5fff80808080ff808080ff8080808080ff808080ffff04ffff04ff2cffff01ff248080ffff04ffff04ff10ffff04ff82017fff808080ffff02ff5fff81bf8080808080ff0180ffff04ffff01ffffff463fff02ff3c04ffff01ff0102ffff02ffff03ff05ffff01ff02ff16ffff04ff02ffff04ff0dffff04ffff0bff3affff0bff12ff3c80ffff0bff3affff0bff3affff0bff12ff2a80ff0980ffff0bff3aff0bffff0bff12ff8080808080ff8080808080ffff010b80ff0180ffff0bff3affff0bff12ff1480ffff0bff3affff0bff3affff0bff12ff2a80ff0580ffff0bff3affff02ff16ffff04ff02ffff04ff07ffff04ffff0bff12ff1280ff8080808080ffff0bff12ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_SINGLETON_VIA_DELEGATED_PUZZLE_HASH: [u8; 32] =
    hex!("9590eaa169e45b655a31d3c06bbd355a3e2b2e3e410d3829748ce08ab249c39e");

/// ```text
/// (mod (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash my_id)
///
///   ; SINGLETON_MOD_HASH is the mod-hash for the singleton_top_layer puzzle
///   ; LAUNCHER_ID is the ID of the singleton we are committed to paying to
///   ; LAUNCHER_PUZZLE_HASH is the puzzle hash of the launcher
///   ; singleton_inner_puzzle_hash is the innerpuzzlehash for our singleton at the current time
///   ; my_id is the coin_id of the coin that this puzzle is locked into
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   ;; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (defun-inline calculate_full_puzzle_hash (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH inner_puzzle_hash)
///     (puzzle-hash-of-curried-function SINGLETON_MOD_HASH
///       inner_puzzle_hash
///       (sha256tree (c SINGLETON_MOD_HASH (c LAUNCHER_ID LAUNCHER_PUZZLE_HASH)))
///     )
///   )
///
///   (defun-inline claim_rewards (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash my_id)
///     (list
///       (list ASSERT_PUZZLE_ANNOUNCEMENT (sha256 (calculate_full_puzzle_hash SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash) my_id))
///       (list CREATE_COIN_ANNOUNCEMENT '$')
///     (list ASSERT_MY_COIN_ID my_id))
///   )
///
///   ; main
///   (claim_rewards SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash my_id)
/// )
/// ```
pub const P2_SINGLETON: [u8; 403] = hex!("ff02ffff01ff04ffff04ff18ffff04ffff0bffff02ff2effff04ff02ffff04ff05ffff04ff2fffff04ffff02ff3effff04ff02ffff04ffff04ff05ffff04ff0bff178080ff80808080ff808080808080ff5f80ff808080ffff04ffff04ff2cffff01ff248080ffff04ffff04ff10ffff04ff5fff808080ff80808080ffff04ffff01ffffff463fff02ff3c04ffff01ff0102ffff02ffff03ff05ffff01ff02ff16ffff04ff02ffff04ff0dffff04ffff0bff3affff0bff12ff3c80ffff0bff3affff0bff3affff0bff12ff2a80ff0980ffff0bff3aff0bffff0bff12ff8080808080ff8080808080ffff010b80ff0180ffff0bff3affff0bff12ff1480ffff0bff3affff0bff3affff0bff12ff2a80ff0580ffff0bff3affff02ff16ffff04ff02ffff04ff07ffff04ffff0bff12ff1280ff8080808080ffff0bff12ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_SINGLETON_HASH: [u8; 32] =
    hex!("40f828d8dd55603f4ff9fbf6b73271e904e69406982f4fbefae2c8dcceaf9834");

/// ```text
/// (mod
///   (inner_puzzle_hash inner_puzzle inner_puzzle_solution)
///
///   ;; hash a tree
///   ;; This is used to calculate a puzzle hash given a puzzle program.
///   (defun sha256tree1
///     (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   (if (= inner_puzzle_hash (sha256tree1 inner_puzzle))
///       (a inner_puzzle inner_puzzle_solution)
///       (x)
///   )
/// )
/// ```
pub const P2_PUZZLE_HASH: [u8; 143] = hex!("ff02ffff01ff02ffff03ffff09ff05ffff02ff02ffff04ff02ffff04ff0bff8080808080ffff01ff02ff0bff1780ffff01ff088080ff0180ffff04ffff01ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff02ffff04ff02ffff04ff09ff80808080ffff02ff02ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const P2_PUZZLE_HASH_HASH: [u8; 32] =
    hex!("13e29a62b42cd2ef72a79e4bacdc59733ca6310d65af83d349360d36ec622363");

/// ```text
/// (mod notarized_payments
///   ;; `notarized_payments` is a list of notarized coin payments
///   ;; a notarized coin payment is `(nonce . ((puzzle_hash amount ...) (puzzle_hash amount ...) ...))`
///   ;; Each notarized coin payment creates some `(CREATE_COIN puzzle_hash amount ...)` payments
///   ;; and a `(CREATE_PUZZLE_ANNOUNCEMENT (sha256tree notarized_coin_payment))` announcement
///   ;; The idea is the other side of this trade requires observing the announcement from a
///   ;; `settlement_payments` puzzle hash as a condition of one or more coin spends.
///
///   (include condition_codes.clib)
///   (include utility_macros.clib)
///
///   (defun sha256tree (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   (defun create_coins_for_payment (payment_params so_far)
///     (if payment_params
///         (assert (> (f (r (f payment_params))) 0)  ; assert the amount is positive
///           ; then
///           (c (c CREATE_COIN (f payment_params)) (create_coins_for_payment (r payment_params) so_far))
///         )
///         so_far
///     )
///   )
///
///   (defun-inline create_announcement_for_payment (notarized_payment)
///     (list CREATE_PUZZLE_ANNOUNCEMENT
///     (sha256tree notarized_payment))
///   )
///
///   (defun-inline augment_condition_list (notarized_payment so_far)
///     (c
///       (create_announcement_for_payment notarized_payment)
///       (create_coins_for_payment (r notarized_payment) so_far)
///     )
///   )
///
///   (defun construct_condition_list (notarized_payments)
///     (if notarized_payments
///         (augment_condition_list (f notarized_payments) (construct_condition_list (r notarized_payments)))
///         ()
///     )
///   )
///
///   (construct_condition_list notarized_payments)
/// )
/// ```
pub const SETTLEMENT_PAYMENT: [u8; 293] = hex!("ff02ffff01ff02ff0affff04ff02ffff04ff03ff80808080ffff04ffff01ffff333effff02ffff03ff05ffff01ff04ffff04ff0cffff04ffff02ff1effff04ff02ffff04ff09ff80808080ff808080ffff02ff16ffff04ff02ffff04ff19ffff04ffff02ff0affff04ff02ffff04ff0dff80808080ff808080808080ff8080ff0180ffff02ffff03ff05ffff01ff02ffff03ffff15ff29ff8080ffff01ff04ffff04ff08ff0980ffff02ff16ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff01ff088080ff0180ffff010b80ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const SETTLEMENT_PAYMENT_HASH: [u8; 32] =
    hex!("cfbfdeed5c4ca2de3d0bf520b9cb4bb7743a359bd2e6a188d19ce7dffc21d3e7");

/// ```text
/// (mod (singleton_full_puzzle_hash amount key_value_list)
///
///   (include condition_codes.clib)
///
///   ; takes a lisp tree and returns the hash of it
///   (defun sha256tree1 (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   ; main
///   (list (list CREATE_COIN singleton_full_puzzle_hash amount)
///   (list CREATE_COIN_ANNOUNCEMENT (sha256tree1 (list singleton_full_puzzle_hash amount key_value_list))))
/// )
/// ```
pub const SINGLETON_LAUNCHER: [u8; 175] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff04ff0bff80808080ffff04ffff04ff0affff04ffff02ff0effff04ff02ffff04ffff04ff05ffff04ff0bffff04ff17ff80808080ff80808080ff808080ff808080ffff04ffff01ff33ff3cff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const SINGLETON_LAUNCHER_HASH: [u8; 32] =
    hex!("eff07522495060c066f66f32acc2a77e3a3e737aca8baea4d1a64ea4cdc13da9");

/// ```text
/// (mod (SINGLETON_STRUCT INNER_PUZZLE lineage_proof my_amount inner_solution)
///
///   ;; SINGLETON_STRUCT = (MOD_HASH . (LAUNCHER_ID . LAUNCHER_PUZZLE_HASH))
///
///   ; SINGLETON_STRUCT, INNER_PUZZLE are curried in by the wallet
///
///   ; EXAMPLE SOLUTION '(0xfadeddab 0xdeadbeef 1 (0xdeadbeef 200) 50 ((51 0xfadeddab 100) (60 "trash") (51 deadbeef 0)))'
///
///
///   ; This puzzle is a wrapper around an inner smart puzzle which guarantees uniqueness.
///   ; It takes its singleton identity from a coin with a launcher puzzle which guarantees that it is unique.
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)  ; also imports the constant ONE == 1
///   (include singleton_truths.clib)
///   (include utility_macros.clib)
///
///   (defun-inline mod_hash_for_singleton_struct (SINGLETON_STRUCT) (f SINGLETON_STRUCT))
///   (defun-inline launcher_id_for_singleton_struct (SINGLETON_STRUCT) (f (r SINGLETON_STRUCT)))
///   (defun-inline launcher_puzzle_hash_for_singleton_struct (SINGLETON_STRUCT) (r (r SINGLETON_STRUCT)))
///
///   ;; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (defun-inline calculate_full_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (mod_hash_for_singleton_struct SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree SINGLETON_STRUCT)
///     )
///   )
///
///   (defun-inline morph_condition (condition SINGLETON_STRUCT)
///     (c (f condition) (c (calculate_full_puzzle_hash SINGLETON_STRUCT (f (r condition))) (r (r condition))))
///   )
///
///   (defun is_odd_create_coin (condition)
///     (and (= (f condition) CREATE_COIN) (logand (f (r (r condition))) 1))
///   )
///
///   ; Assert exactly one output with odd value exists - ignore it if value is -113
///
///   ;; this function iterates over the output conditions from the inner puzzle & solution
///   ;; and both checks that exactly one unique singleton child is created (with odd valued output),
///   ;; and wraps the inner puzzle with this same singleton wrapper puzzle
///   ;;
///   ;; The special case where the output value is -113 means a child singleton is intentionally
///   ;; *NOT* being created, thus forever ending this singleton's existence
///
///   (defun check_and_morph_conditions_for_singleton (SINGLETON_STRUCT conditions has_odd_output_been_found)
///     (if conditions
///         ; check if it's an odd create coin
///         (if (is_odd_create_coin (f conditions))
///             ; check that we haven't already found one
///             (assert (not has_odd_output_been_found)
///               ; then
///               (if (= (f (r (r (f conditions)))) -113)
///                   ; If it's the melt condition we don't bother prepending this condition
///                   (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (r conditions) ONE)
///                   ; If it isn't the melt condition, we morph it and prepend it
///                   (c (morph_condition (f conditions) SINGLETON_STRUCT) (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (r conditions) ONE))
///               )
///             )
///             (c (f conditions) (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (r conditions) has_odd_output_been_found))
///         )
///         (assert has_odd_output_been_found ())
///     )
///   )
///
///   ; assert that either the lineage proof is for a parent singleton, or, if it's for the launcher, verify it matched our launcher ID
///   ; then return a condition asserting it actually is our parent ID
///   (defun verify_lineage_proof (SINGLETON_STRUCT parent_id is_not_launcher)
///     (assert (any is_not_launcher (= parent_id (launcher_id_for_singleton_struct SINGLETON_STRUCT)))
///       ; then
///       (list ASSERT_MY_PARENT_ID parent_id)
///     )
///   )
///
///   ; main
///
///   ; if our value is not an odd amount then we are invalid
///   (assert (logand my_amount ONE)
///     ; then
///     (c
///       (list ASSERT_MY_AMOUNT my_amount)
///       (c
///         ; Verify the lineage proof by asserting our parent's ID
///         (verify_lineage_proof
///           SINGLETON_STRUCT
///           ; calculate our parent's ID
///           (calculate_coin_id
///             (parent_info_for_lineage_proof lineage_proof)
///             (if (is_not_eve_proof lineage_proof)  ; The PH calculation changes based on the lineage proof
///                 (calculate_full_puzzle_hash SINGLETON_STRUCT (puzzle_hash_for_lineage_proof lineage_proof))  ; wrap the innerpuz in a singleton
///                 (launcher_puzzle_hash_for_singleton_struct SINGLETON_STRUCT)  ; Use the static launcher puzzle hash
///             )
///             (if (is_not_eve_proof lineage_proof)  ; The position of "amount" changes based on the type on lineage proof
///                 (amount_for_lineage_proof lineage_proof)
///                 (amount_for_eve_proof lineage_proof)
///             )
///           )
///           (is_not_eve_proof lineage_proof)
///         )
///         ; finally check all of the conditions for a single odd output to wrap
///         (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (a INNER_PUZZLE inner_solution) 0)
///       )
///     )
///   )
/// )
/// ```
pub const SINGLETON_TOP_LAYER_V1_1: [u8; 967] = hex!("ff02ffff01ff02ffff03ffff18ff2fff3480ffff01ff04ffff04ff20ffff04ff2fff808080ffff04ffff02ff3effff04ff02ffff04ff05ffff04ffff02ff2affff04ff02ffff04ff27ffff04ffff02ffff03ff77ffff01ff02ff36ffff04ff02ffff04ff09ffff04ff57ffff04ffff02ff2effff04ff02ffff04ff05ff80808080ff808080808080ffff011d80ff0180ffff04ffff02ffff03ff77ffff0181b7ffff015780ff0180ff808080808080ffff04ff77ff808080808080ffff02ff3affff04ff02ffff04ff05ffff04ffff02ff0bff5f80ffff01ff8080808080808080ffff01ff088080ff0180ffff04ffff01ffffffff4947ff0233ffff0401ff0102ffffff20ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff3cffff0bff34ff2480ffff0bff3cffff0bff3cffff0bff34ff2c80ff0980ffff0bff3cff0bffff0bff34ff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ffff22ffff09ffff0dff0580ff2280ffff09ffff0dff0b80ff2280ffff15ff17ffff0181ff8080ffff01ff0bff05ff0bff1780ffff01ff088080ff0180ff02ffff03ff0bffff01ff02ffff03ffff02ff26ffff04ff02ffff04ff13ff80808080ffff01ff02ffff03ffff20ff1780ffff01ff02ffff03ffff09ff81b3ffff01818f80ffff01ff02ff3affff04ff02ffff04ff05ffff04ff1bffff04ff34ff808080808080ffff01ff04ffff04ff23ffff04ffff02ff36ffff04ff02ffff04ff09ffff04ff53ffff04ffff02ff2effff04ff02ffff04ff05ff80808080ff808080808080ff738080ffff02ff3affff04ff02ffff04ff05ffff04ff1bffff04ff34ff8080808080808080ff0180ffff01ff088080ff0180ffff01ff04ff13ffff02ff3affff04ff02ffff04ff05ffff04ff1bffff04ff17ff8080808080808080ff0180ffff01ff02ffff03ff17ff80ffff01ff088080ff018080ff0180ffffff02ffff03ffff09ff09ff3880ffff01ff02ffff03ffff18ff2dffff010180ffff01ff0101ff8080ff0180ff8080ff0180ff0bff3cffff0bff34ff2880ffff0bff3cffff0bff3cffff0bff34ff2c80ff0580ffff0bff3cffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff34ff3480ff8080808080ffff0bff34ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ffff03ffff21ff17ffff09ff0bff158080ffff01ff04ff30ffff04ff0bff808080ffff01ff088080ff0180ff018080");
pub const SINGLETON_TOP_LAYER_V1_1_HASH: [u8; 32] =
    hex!("7faa3253bfddd1e0decb0906b2dc6247bbc4cf608f58345d173adb63e8b47c9f");

/// ```text
/// (mod (SINGLETON_STRUCT INNER_PUZZLE lineage_proof my_amount inner_solution)
///
///   ;; SINGLETON_STRUCT = (MOD_HASH . (LAUNCHER_ID . LAUNCHER_PUZZLE_HASH))
///
///   ; SINGLETON_STRUCT, INNER_PUZZLE are curried in by the wallet
///
///   ; EXAMPLE SOLUTION '(0xfadeddab 0xdeadbeef 1 (0xdeadbeef 200) 50 ((51 0xfadeddab 100) (60 "trash") (51 deadbeef 0)))'
///
///
///   ; This puzzle is a wrapper around an inner smart puzzle which guarantees uniqueness.
///   ; It takes its singleton identity from a coin with a launcher puzzle which guarantees that it is unique.
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///   (include singleton_truths.clib)
///
///   ; takes a lisp tree and returns the hash of it
///   (defun sha256tree1 (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   ; "assert" is a macro that wraps repeated instances of "if"
///   ; usage: (assert A0 A1 ... An R)
///   ; all of A0, A1, ... An must evaluate to non-null, or an exception is raised
///   ; return the value of R (if we get that far)
///
///   (defmacro assert items
///     (if (r items)
///         (list if (f items) (c assert (r items)) (q . (x)))
///         (f items)
///     )
///   )
///
///   (defun-inline mod_hash_for_singleton_struct (SINGLETON_STRUCT) (f SINGLETON_STRUCT))
///   (defun-inline launcher_id_for_singleton_struct (SINGLETON_STRUCT) (f (r SINGLETON_STRUCT)))
///   (defun-inline launcher_puzzle_hash_for_singleton_struct (SINGLETON_STRUCT) (r (r SINGLETON_STRUCT)))
///
///   ;; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (defun-inline calculate_full_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash)
///     (puzzle-hash-of-curried-function (mod_hash_for_singleton_struct SINGLETON_STRUCT)
///       inner_puzzle_hash
///       (sha256tree1 SINGLETON_STRUCT)
///     )
///   )
///
///   ; assembles information from the solution to create our own full ID including asserting our parent is a singleton
///   (defun create_my_ID (SINGLETON_STRUCT full_puzzle_hash parent_parent parent_inner_puzzle_hash parent_amount my_amount)
///     (sha256 (sha256 parent_parent (calculate_full_puzzle_hash SINGLETON_STRUCT parent_inner_puzzle_hash) parent_amount)
///       full_puzzle_hash
///     my_amount)
///   )
///
///   ;; take a boolean and a non-empty list of conditions
///   ;; strip off the first condition if a boolean is set
///   ;; this is used to remove `(CREATE_COIN xxx -113)`
///   ;; pretty sneaky, eh?
///   (defun strip_first_condition_if (boolean condition_list)
///     (if boolean
///         (r condition_list)
///         condition_list
///     )
///   )
///
///   (defun-inline morph_condition (condition SINGLETON_STRUCT)
///     (list (f condition) (calculate_full_puzzle_hash SINGLETON_STRUCT (f (r condition))) (f (r (r condition))))
///   )
///
///   ;; return the value of the coin created if this is a `CREATE_COIN` condition, or 0 otherwise
///   (defun-inline created_coin_value_or_0 (condition)
///     (if (= (f condition) CREATE_COIN)
///         (f (r (r condition)))
///         0
///     )
///   )
///
///   ;; Returns a (bool . bool)
///   (defun odd_cons_m113 (output_amount)
///     (c
///       (= (logand output_amount 1) 1)  ;; is it odd?
///       (= output_amount -113)  ;; is it the escape value?
///     )
///   )
///
///   ; Assert exactly one output with odd value exists - ignore it if value is -113
///
///   ;; this function iterates over the output conditions from the inner puzzle & solution
///   ;; and both checks that exactly one unique singleton child is created (with odd valued output),
///   ;; and wraps the inner puzzle with this same singleton wrapper puzzle
///   ;;
///   ;; The special case where the output value is -113 means a child singleton is intentionally
///   ;; *NOT* being created, thus forever ending this singleton's existence
///
///   (defun check_and_morph_conditions_for_singleton (SINGLETON_STRUCT conditions has_odd_output_been_found)
///     (if conditions
///         (morph_next_condition SINGLETON_STRUCT conditions has_odd_output_been_found (odd_cons_m113 (created_coin_value_or_0 (f conditions))))
///         (if has_odd_output_been_found
///             0
///             (x)  ;; no odd output found
///         )
///     )
///   )
///
///   ;; a continuation of `check_and_morph_conditions_for_singleton` with booleans `is_output_odd` and `is_output_m113`
///   ;; precalculated
///   (defun morph_next_condition (SINGLETON_STRUCT conditions has_odd_output_been_found (is_output_odd . is_output_m113))
///     (assert
///       (not (all is_output_odd has_odd_output_been_found))
///       (strip_first_condition_if
///         is_output_m113
///         (c (if is_output_odd
///                (morph_condition (f conditions) SINGLETON_STRUCT)
///                (f conditions)
///           )
///           (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (r conditions) (any is_output_odd has_odd_output_been_found))
///         )
///       )
///     )
///   )
///
///   ; this final stager asserts our ID
///   ; it also runs the innerpuz with the innersolution with the "truths" added
///   ; it then passes that output conditions from the innerpuz to the morph conditions function
///   (defun stager_three (SINGLETON_STRUCT lineage_proof my_id full_puzhash innerpuzhash my_amount INNER_PUZZLE inner_solution)
///     (c (list ASSERT_MY_COIN_ID my_id) (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (a INNER_PUZZLE (c (truth_data_to_truth_struct my_id full_puzhash innerpuzhash my_amount lineage_proof SINGLETON_STRUCT) inner_solution)) 0))
///   )
///
///   ; this checks whether we are an eve spend or not and calculates our full coin ID appropriately and passes it on to the final stager
///   ; if we are the eve spend it also adds the additional checks that our parent's puzzle is the standard launcher format and that out parent ID is the same as our singleton ID
///
///   (defun stager_two (SINGLETON_STRUCT lineage_proof full_puzhash innerpuzhash my_amount INNER_PUZZLE inner_solution)
///     (stager_three
///       SINGLETON_STRUCT
///       lineage_proof
///       (if (is_not_eve_proof lineage_proof)
///           (create_my_ID
///             SINGLETON_STRUCT
///             full_puzhash
///             (parent_info_for_lineage_proof lineage_proof)
///             (puzzle_hash_for_lineage_proof lineage_proof)
///             (amount_for_lineage_proof lineage_proof)
///             my_amount
///           )
///           (if (=
///                 (launcher_id_for_singleton_struct SINGLETON_STRUCT)
///                 (sha256 (parent_info_for_eve_proof lineage_proof) (launcher_puzzle_hash_for_singleton_struct SINGLETON_STRUCT) (amount_for_eve_proof lineage_proof))
///               )
///               (sha256 (launcher_id_for_singleton_struct SINGLETON_STRUCT) full_puzhash my_amount)
///               (x)
///           )
///       )
///       full_puzhash
///       innerpuzhash
///       my_amount
///       INNER_PUZZLE
///       inner_solution
///     )
///   )
///
///   ; this calculates our current full puzzle hash and passes it to stager two
///   (defun stager_one (SINGLETON_STRUCT lineage_proof my_innerpuzhash my_amount INNER_PUZZLE inner_solution)
///     (stager_two SINGLETON_STRUCT lineage_proof (calculate_full_puzzle_hash SINGLETON_STRUCT my_innerpuzhash) my_innerpuzhash my_amount INNER_PUZZLE inner_solution)
///   )
///
///
///   ; main
///
///   ; if our value is not an odd amount then we are invalid
///   ; this calculates my_innerpuzhash and passes all values to stager_one
///   (if (logand my_amount 1)
///       (stager_one SINGLETON_STRUCT lineage_proof (sha256tree1 INNER_PUZZLE) my_amount INNER_PUZZLE inner_solution)
///       (x)
///   )
/// )
/// ```
pub const SINGLETON_TOP_LAYER: [u8; 1168] = hex!("ff02ffff01ff02ffff03ffff18ff2fffff010180ffff01ff02ff36ffff04ff02ffff04ff05ffff04ff17ffff04ffff02ff26ffff04ff02ffff04ff0bff80808080ffff04ff2fffff04ff0bffff04ff5fff808080808080808080ffff01ff088080ff0180ffff04ffff01ffffffff4602ff3304ffff0101ff02ffff02ffff03ff05ffff01ff02ff5cffff04ff02ffff04ff0dffff04ffff0bff2cffff0bff24ff3880ffff0bff2cffff0bff2cffff0bff24ff3480ff0980ffff0bff2cff0bffff0bff24ff8080808080ff8080808080ffff010b80ff0180ff02ffff03ff0bffff01ff02ff32ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ffff02ff2affff04ff02ffff04ffff02ffff03ffff09ff23ff2880ffff0181b3ff8080ff0180ff80808080ff80808080808080ffff01ff02ffff03ff17ff80ffff01ff088080ff018080ff0180ffffffff0bffff0bff17ffff02ff3affff04ff02ffff04ff09ffff04ff2fffff04ffff02ff26ffff04ff02ffff04ff05ff80808080ff808080808080ff5f80ff0bff81bf80ff02ffff03ffff20ffff22ff4fff178080ffff01ff02ff7effff04ff02ffff04ff6fffff04ffff04ffff02ffff03ff4fffff01ff04ff23ffff04ffff02ff3affff04ff02ffff04ff09ffff04ff53ffff04ffff02ff26ffff04ff02ffff04ff05ff80808080ff808080808080ffff04ff81b3ff80808080ffff011380ff0180ffff02ff7cffff04ff02ffff04ff05ffff04ff1bffff04ffff21ff4fff1780ff80808080808080ff8080808080ffff01ff088080ff0180ffff04ffff09ffff18ff05ffff010180ffff010180ffff09ff05ffff01818f8080ff0bff2cffff0bff24ff3080ffff0bff2cffff0bff2cffff0bff24ff3480ff0580ffff0bff2cffff02ff5cffff04ff02ffff04ff07ffff04ffff0bff24ff2480ff8080808080ffff0bff24ff8080808080ffffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff26ffff04ff02ffff04ff09ff80808080ffff02ff26ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ff5effff04ff02ffff04ff05ffff04ff0bffff04ffff02ff3affff04ff02ffff04ff09ffff04ff17ffff04ffff02ff26ffff04ff02ffff04ff05ff80808080ff808080808080ffff04ff17ffff04ff2fffff04ff5fffff04ff81bfff80808080808080808080ffff04ffff04ff20ffff04ff17ff808080ffff02ff7cffff04ff02ffff04ff05ffff04ffff02ff82017fffff04ffff04ffff04ff17ff2f80ffff04ffff04ff5fff81bf80ffff04ff0bff05808080ff8202ff8080ffff01ff80808080808080ffff02ff2effff04ff02ffff04ff05ffff04ff0bffff04ffff02ffff03ff3bffff01ff02ff22ffff04ff02ffff04ff05ffff04ff17ffff04ff13ffff04ff2bffff04ff5bffff04ff5fff808080808080808080ffff01ff02ffff03ffff09ff15ffff0bff13ff1dff2b8080ffff01ff0bff15ff17ff5f80ffff01ff088080ff018080ff0180ffff04ff17ffff04ff2fffff04ff5fffff04ff81bfffff04ff82017fff8080808080808080808080ff02ffff03ff05ffff011bffff010b80ff0180ff018080");
pub const SINGLETON_TOP_LAYER_HASH: [u8; 32] =
    hex!("24e044101e57b3d8c908b8a38ad57848afd29d3eecc439dba45f4412df4954fd");

/// ```text
/// (mod
///   (
///     MERKLE_ROOT
///     delegated_puzzle_hash
///     merkle_proof
///     member_puzzle
///     member_solution
///   )
///
///   (include merkle_utils.clib)
///
///   ; takes a lisp tree and returns the hash of it
///   (defun sha256tree (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE)))
///   (sha256 1 TREE)))
///
///   (if (= MERKLE_ROOT (simplify_merkle_proof (sha256tree member_puzzle) merkle_proof))
///       (a member_puzzle (c delegated_puzzle_hash member_solution))
///       (x)
///   )
///
/// )
/// ```
pub const ONE_OF_N: [u8; 286] = hex!("ff02ffff01ff02ffff03ffff09ff05ffff02ff06ffff04ff02ffff04ffff0bffff0101ffff02ff04ffff04ff02ffff04ff2fff8080808080ffff04ff17ff808080808080ffff01ff02ff2fffff04ff0bff5f8080ffff01ff088080ff0180ffff04ffff01ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff04ffff04ff02ffff04ff09ff80808080ffff02ff04ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ffff03ff1bffff01ff02ff06ffff04ff02ffff04ffff02ffff03ffff18ffff0101ff1380ffff01ff0bffff0102ff2bff0580ffff01ff0bffff0102ff05ff2b8080ff0180ffff04ffff04ffff17ff13ffff0181ff80ff3b80ff8080808080ffff010580ff0180ff018080");
pub const ONE_OF_N_HASH: [u8; 32] =
    hex!("bcb9aa74893bebcfa2da87271b0330bf2773b6391144ae72262b6824d9c55939");

/// ```text
/// (mod
///   (
///     M  ; the number of necessary puzzles to execute
///     MERKLE_ROOT  ; A root of all available puzzles
///     delegated_puzzle_hash  ; A puzzle hash to run that all members must agree to
///     member_proof  ; A partially revealed merkle tree with only the leaves being used fully revealed
///   )
///
///   (include sha256tree.clib)
///
///   ; utility
///   (defun merge_list (list_a list_b)
///     (if list_a
///         (c (f list_a) (merge_list (r list_a) list_b))
///         list_b
///     )
///   )
///
///   ; delegated puzzle validation
///   (defun-inline branch_hash_and_merge_info ((tree1 conditions1 total1) (tree2 conditions2 total2))
///     (list
///       (sha256 2 tree1 tree2)
///       (merge_list conditions1 conditions2)
///       (+ total1 total2)
///     )
///   )
///
///   (defun handle_branch (branch delegated_puzzle_hash)
///     (if (l branch)
///         (hash_and_run branch delegated_puzzle_hash)
///         (list branch () 0)
///     )
///   )
///
///   (defun hash_and_run (tree delegated_puzzle_hash)
///     (if (f tree)
///         (branch_hash_and_merge_info (handle_branch (f tree) delegated_puzzle_hash) (handle_branch (r tree) delegated_puzzle_hash))
///         (list
///           (sha256 1 (sha256tree (f (r tree))))
///           (a (f (r tree)) (c delegated_puzzle_hash (r (r tree))))
///           1
///         )
///     )
///   )
///
///   ; main checks
///   (defun run_delegated_puzzle
///     (
///       M
///       MERKLE_ROOT
///       (
///         proven_root
///         conditions
///         total_validations
///       )
///     )
///
///     (if (all (= M total_validations) (= MERKLE_ROOT proven_root))
///         conditions
///         (x)
///     )
///   )
///
///   ; enter main
///   (run_delegated_puzzle
///     M
///     MERKLE_ROOT
///     (hash_and_run member_proof delegated_puzzle_hash)
///   )
/// )
/// ```
pub const M_OF_N: [u8; 622] = hex!("ff02ffff01ff02ff16ffff04ff02ffff04ff05ffff04ff0bffff04ffff02ff0cffff04ff02ffff04ff2fffff04ff17ff8080808080ff808080808080ffff04ffff01ffffff02ffff03ffff07ff0580ffff01ff02ff0cffff04ff02ffff04ff05ffff04ff0bff8080808080ffff01ff04ff05ffff01ff80ff80808080ff0180ff02ffff03ff09ffff01ff04ffff0bffff0102ffff05ffff02ff08ffff04ff02ffff04ff09ffff04ff0bff808080808080ffff05ffff02ff08ffff04ff02ffff04ff0dffff04ff0bff80808080808080ffff04ffff02ff0affff04ff02ffff04ffff05ffff06ffff02ff08ffff04ff02ffff04ff09ffff04ff0bff80808080808080ffff04ffff05ffff06ffff02ff08ffff04ff02ffff04ff0dffff04ff0bff80808080808080ff8080808080ffff04ffff10ffff05ffff06ffff06ffff02ff08ffff04ff02ffff04ff09ffff04ff0bff8080808080808080ffff05ffff06ffff06ffff02ff08ffff04ff02ffff04ff0dffff04ff0bff808080808080808080ff80808080ffff01ff04ffff0bffff0101ffff02ff1effff04ff02ffff04ff15ff8080808080ffff04ffff02ff15ffff04ff0bff1d8080ffff01ff0180808080ff0180ffff02ffff03ff05ffff01ff04ff09ffff02ff0affff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ffff02ffff03ffff22ffff09ff05ff81b780ffff09ff0bff278080ffff0157ffff01ff088080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const M_OF_N_HASH: [u8; 32] =
    hex!("de27deb2ebc7f1e1b77e1d38cc2f9d90fbd54d4b13dd4e6fa1f659177e36ed4f");

/// ```text
/// (mod
///   (
///     MEMBERS
///     delegated_puzzle_hash
///     member_solutions
///   )
///
///   ; utility
///   (include sha256tree.clib)
///   (defun merge_list (list_a list_b)
///     (if list_a
///         (c (f list_a) (merge_list (r list_a) list_b))
///         list_b
///     )
///   )
///
///   ; streamlined M of N
///   (defun run_member (MEMBER member_solution delegated_puzzle_hash)
///     (a MEMBER (c delegated_puzzle_hash member_solution))
///   )
///
///   (defun approve_delegated_puzzle (MEMBERS member_solutions delegated_puzzle_hash)
///     (if (r MEMBERS)  ; assumes at least 1 member at start
///         (merge_list
///           (run_member (f MEMBERS) (f member_solutions) delegated_puzzle_hash)
///           (approve_delegated_puzzle (r MEMBERS) (r member_solutions) delegated_puzzle_hash)
///         )
///         (run_member (f MEMBERS) (f member_solutions) delegated_puzzle_hash)
///     )
///   )
///
///   ; main
///   (approve_delegated_puzzle MEMBERS member_solutions delegated_puzzle_hash)
/// )
/// ```
pub const N_OF_N: [u8; 243] = hex!("ff02ffff01ff02ff04ffff04ff02ffff04ff05ffff04ff17ffff04ff0bff808080808080ffff04ffff01ffff02ffff03ff0dffff01ff02ff0affff04ff02ffff04ffff02ff0effff04ff02ffff04ff09ffff04ff13ffff04ff17ff808080808080ffff04ffff02ff04ffff04ff02ffff04ff0dffff04ff1bffff04ff17ff808080808080ff8080808080ffff01ff02ff0effff04ff02ffff04ff09ffff04ff13ffff04ff17ff80808080808080ff0180ffff02ffff03ff05ffff01ff04ff09ffff02ff0affff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff02ff05ffff04ff17ff0b8080ff018080");
pub const N_OF_N_HASH: [u8; 32] =
    hex!("d4394f50cb1d6ef130788db2e69ab0087ef79b0737179f201c1d1d2a52df1e59");

/// ```text
/// (mod
///   (
///     INNER_PUZZLE
///     delegated_puzzle
///     delegated_solution
///     .
///     inner_solution
///   )
///
///   (include sha256tree.clib)
///
///   (defun merge_list (list_a list_b)
///     (if list_a
///         (c (f list_a) (merge_list (r list_a) list_b))
///         list_b
///     )
///   )
///
///   (merge_list (a INNER_PUZZLE (c (sha256tree delegated_puzzle) inner_solution)) (a delegated_puzzle delegated_solution))
/// )
/// ```
pub const DELEGATED_PUZZLE_FEEDER: [u8; 203] = hex!("ff02ffff01ff02ff04ffff04ff02ffff04ffff02ff05ffff04ffff02ff06ffff04ff02ffff04ff0bff80808080ff1f8080ffff04ffff02ff0bff1780ff8080808080ffff04ffff01ffff02ffff03ff05ffff01ff04ff09ffff02ff04ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const DELEGATED_PUZZLE_FEEDER_HASH: [u8; 32] =
    hex!("9db33d93853179903d4dd272a00345ee6630dc94907dbcdd96368df6931060fd");

/// ```text
/// (mod
///   (
///     MEMBER_VALIDATORS  ; programs that look at the conditions allowed OUT
///     DPUZ_VALIDATORS  ; programs that validate the delegated puzzle allowed IN
///     INNER_PUZZLE  ; the program that generates the conditions
///     delegated_puzzle_hash
///     member_val_solutions
///     dpuz_val_solutions
///     inner_solution
///   )
///
///   (defun run_validators (VALIDATORS val_solutions thing_to_check)
///     (if VALIDATORS
///         (i  ()  ; just using this as a hook to evaluate all children
///           (a (f VALIDATORS) (c thing_to_check (f val_solutions)))
///           (run_validators (r VALIDATORS) (r val_solutions) thing_to_check)
///         )
///         ; else
///         ()
///     )
///   )
///
///   (defun run_member_validators_and_return (MEMBER_VALIDATORS member_val_solutions inner_conditions)
///     (i  ()  ; just using this as a hook to evaluate all children
///       (run_validators MEMBER_VALIDATORS member_val_solutions inner_conditions)
///       inner_conditions  ; actually returned
///     )
///   )
///
///   (run_member_validators_and_return
///     MEMBER_VALIDATORS
///     member_val_solutions
///     (a INNER_PUZZLE (c delegated_puzzle_hash inner_solution))
///     ; not part of the function call but needs to run
///     (run_validators DPUZ_VALIDATORS dpuz_val_solutions delegated_puzzle_hash)
///   )
/// )
/// ```
pub const RESTRICTIONS: [u8; 204] = hex!("ff02ffff01ff02ff04ffff04ff02ffff04ff05ffff04ff5fffff04ffff02ff17ffff04ff2fff82017f8080ffff04ffff02ff06ffff04ff02ffff04ff0bffff04ff81bfffff04ff2fff808080808080ff80808080808080ffff04ffff01ffff03ff80ffff02ff06ffff04ff02ffff04ff05ffff04ff0bffff04ff17ff808080808080ff1780ff02ffff03ff05ffff01ff03ff80ffff02ff09ffff04ff17ff138080ffff02ff06ffff04ff02ffff04ff0dffff04ff1bffff04ff17ff80808080808080ff8080ff0180ff018080");
pub const RESTRICTIONS_HASH: [u8; 32] =
    hex!("a28d59d39f964a93159c986b1914694f6f2f1c9901178f91e8b0ba4045980eef");

/// ```text
/// ; this puzzle follows the Managed Inner Puzzle Spec MIPS01 as a Member Puzzle
/// ; this code offers a secure approval of a delegated puzzle passed in as a Truth to be run elsewhere
///
/// (mod (PUBLIC_KEY Delegated_Puzzle)  ; delegated puzzle is passed in from the above M of N layer
///   (include condition_codes.clib)
///
///   (list (list AGG_SIG_ME PUBLIC_KEY Delegated_Puzzle))
/// )
/// ```
pub const BLS_MEMBER: [u8; 41] =
    hex!("ff02ffff01ff04ffff04ff02ffff04ff05ffff04ff0bff80808080ff8080ffff04ffff0132ff018080");
pub const BLS_MEMBER_HASH: [u8; 32] =
    hex!("21a3ae8b3ce64d41ca98d6d8df8f465c9e1bfb19ab40284a5da8479ba7fade78");

/// ```text
/// ; this puzzle follows the Managed Inner Puzzle Spec MIPS01 as a Member Puzzle
/// ; this code offers a secure approval of a delegated puzzle passed in as a Truth to be run elsewhere
///
/// ; Delegated_Puzzle_Hash is added to the solution in the above layer
/// ; original_public_key, hidden_puzzle and solution are only for use in the taproot case
/// ; set original_public_key to 0 for non-taproot case
/// (mod (SYNTHETIC_PUBLIC_KEY Delegated_Puzzle_Hash original_public_key hidden_puzzle)
///   (include condition_codes.clib)
///
///   (defmacro assert items
///     (if (r items)
///         (list if (f items) (c assert (r items)) (q . (x)))
///         (f items)
///     )
///   )
///
///   ; "is_hidden_puzzle_correct" returns true iff the hidden puzzle is correctly encoded
///
///   (defun-inline is_hidden_puzzle_correct (SYNTHETIC_PUBLIC_KEY original_public_key hidden_puzzle_hash)
///     (=
///       SYNTHETIC_PUBLIC_KEY
///       (point_add
///         original_public_key
///         (pubkey_for_exp (sha256 original_public_key hidden_puzzle_hash))
///       )
///     )
///   )
///
///   ; "possibly_prepend_aggsig" is the main entry point
///
///   (if original_public_key
///       (assert
///         (is_hidden_puzzle_correct SYNTHETIC_PUBLIC_KEY original_public_key Delegated_Puzzle_Hash)
///         ()
///       )
///       (list (list AGG_SIG_ME SYNTHETIC_PUBLIC_KEY Delegated_Puzzle_Hash))
///   )
/// )
/// ```
pub const BLS_WITH_TAPROOT_MEMBER: [u8; 99] = hex!("ff02ffff01ff02ffff03ff17ffff01ff02ffff03ffff09ff05ffff1dff17ffff1effff0bff17ff0b80808080ff80ffff01ff088080ff0180ffff01ff04ffff04ff02ffff04ff05ffff04ff0bff80808080ff808080ff0180ffff04ffff0132ff018080");
pub const BLS_WITH_TAPROOT_MEMBER_HASH: [u8; 32] =
    hex!("35d2ad31aaf0df91c965909e5112294c57a18354ee4a5aae80572080ec3b6842");

/// ```text
/// (mod (FIXED_PUZZLE_HASH Delegated_Puzzle_Hash)
///   (if (= FIXED_PUZZLE_HASH Delegated_Puzzle_Hash)
///       ()
///       (x)
///   )
/// )
/// ```
pub const FIXED_PUZZLE_MEMBER: [u8; 25] =
    hex!("ff02ffff03ffff09ff02ff0580ff80ffff01ff088080ff0180");
pub const FIXED_PUZZLE_MEMBER_HASH: [u8; 32] =
    hex!("34ede3eadc52ed750e405f2b9dea9891506547f651290bb606356d997c64f219");

/// ```text
/// ; member puzzle with SECP256-R1 signature provided by a passkey (ie Yubikey)
///
/// (mod (SECP_PK
///     Delegated_Puzzle_Hash
///     ; The WebAuthn authenticator data.
///     ; See https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata.
///     authenticator_data
///     ; The WebAuthn client data JSON.
///     ; See https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson.
///     client_data_json
///     ; The index at which "challenge":"..." occurs in `clientDataJSON`.
///     challenge_index
///     ; the signature returned by the authenticator
///     signature
///     ; my puzzle hash
///     puzzle_hash
///   )
///
///   (include *standard-cl-23*)
///   (include condition_codes.clib)
///   (include sha256tree.clib)
///
///   (defconstant b64-charset "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")
///
///   (defun map-triples (fun n blob)
///     (if (any (= n (strlen blob)) (> n (strlen blob)))
///         ()
///         (c (a fun (list (substr blob n (+ n 3)))) (map-triples fun (+ n 3) blob))
///     )
///   )
///
///   (defun flat-map (fun lst)
///     (if lst
///         (if (f lst)
///             (c (a fun (list (f (f lst)))) (flat-map fun (c (r (f lst)) (r lst))))
///             (flat-map fun (r lst))
///         )
///         ()
///     )
///   )
///
///   (defun lookup-b64 (byte)
///     (substr b64-charset byte (+ byte 1))
///   )
///
///   (defun-inline trim-padding (plen output)
///     (substr output 0 (- (strlen output) plen))
///   )
///
///   (defun-inline convert (int)
///     (if (> int -1) int (+ int 256))
///   )
///
///   (defun b64-encode-blob (blob)
///     (assign
///       pad_mod (r (divmod (strlen blob) 3))
///       padding (if pad_mod (- 3 pad_mod) 0)
///       bytes (concat blob (substr 0x000000 0 padding))
///       sextets
///       (map-triples (lambda ((& padding) bytes)
///           (assign
///             (fb_upper . fb_lower) (divmod (convert (substr bytes 0 1)) 4)
///             (sb_upper . sb_lower) (divmod (convert (substr bytes 1 2)) 16)
///             (tb_upper . tb_lower) (divmod (convert (substr bytes 2 3)) 64)
///             (list
///               fb_upper
///               (logior (ash fb_lower 4) sb_upper)
///               (logior (ash sb_lower 2) tb_upper)
///               tb_lower
///             )
///           )
///         )
///         0
///         bytes
///       )
///       (trim-padding padding (a (c (list 14) (flat-map lookup-b64 sextets)) ()))
///     )
///   )
///
///   (assign
///     message (b64-encode-blob (sha256 Delegated_Puzzle_Hash puzzle_hash))
///     challenge (concat '"challenge":"' message '"')
///     (if (= (substr client_data_json challenge_index (+ challenge_index (strlen challenge))) challenge)
///         (c
///           (list ASSERT_MY_PUZZLEHASH puzzle_hash)
///           (secp256r1_verify SECP_PK (sha256 authenticator_data (sha256 client_data_json)) signature)
///         )
///         (x)
///     )
///   )
/// )
/// ```
pub const PASSKEY_MEMBER_PUZZLE_ASSERT: [u8; 1418] = hex!("ff02ffff01ff02ff3effff04ff02ffff04ff03ffff04ffff02ff2cffff04ff02ffff04ffff0bff0bff82017f80ff80808080ff8080808080ffff04ffff01ffffffff02ffff03ffff21ffff09ff0bffff0dff178080ffff15ff0bffff0dff17808080ffff01ff0180ffff01ff04ffff02ff05ffff04ffff0cff17ff0bffff10ff0bffff01038080ff808080ffff02ff10ffff04ff02ffff04ff05ffff04ffff10ff0bffff010380ffff04ff17ff8080808080808080ff0180ff02ffff03ff0bffff01ff02ffff03ff13ffff01ff04ffff02ff05ffff04ff23ff808080ffff02ff18ffff04ff02ffff04ff05ffff04ffff04ff33ff1b80ff808080808080ffff01ff02ff18ffff04ff02ffff04ff05ffff04ff1bff808080808080ff0180ffff01ff018080ff0180ffff0cffff01c0404142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5fff05ffff10ff05ffff01018080ffff02ff3cffff04ff02ffff04ff03ffff04ffff06ffff14ffff0dff0580ffff01038080ff8080808080ff02ff12ffff04ff02ffff04ff03ffff04ffff02ffff03ff0bffff01ff11ffff0103ff0b80ffff01ff018080ff0180ff8080808080ffffff02ff2affff04ff02ffff04ff03ffff04ffff0eff11ffff0cffff0183000000ff80ff0b8080ff8080808080ffff02ff2effff04ff02ffff04ff03ffff04ffff02ff10ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff15ff808080ffff04ffff0101ff80808080ff80808080ffff04ff80ffff04ff0bff808080808080ff8080808080ff04ff4fffff04ffff19ffff16ff6fffff010480ff2780ffff04ffff19ffff16ff37ffff010280ff1380ffff04ff1bff8080808080ffff02ff3affff04ff02ffff04ffff04ffff04ff09ff8080ffff04ff0bff808080ffff04ffff14ffff02ffff03ffff15ffff0cff0bffff0102ffff010380ffff0181ff80ffff01ff0cff0bffff0102ffff010380ffff01ff10ffff0cff0bffff0102ffff010380ffff018201008080ff0180ffff014080ffff04ffff14ffff02ffff03ffff15ffff0cff0bffff0101ffff010280ffff0181ff80ffff01ff0cff0bffff0101ffff010280ffff01ff10ffff0cff0bffff0101ffff010280ffff018201008080ff0180ffff011080ffff04ffff14ffff02ffff03ffff15ffff0cff0bff80ffff010180ffff0181ff80ffff01ff0cff0bff80ffff010180ffff01ff10ffff0cff0bff80ffff010180ffff018201008080ff0180ffff010480ff80808080808080ffff0cffff02ffff04ffff04ffff010eff8080ffff02ff18ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff1480ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ff0bff808080808080ff8080ff80ffff11ffff0dffff02ffff04ffff04ffff010eff8080ffff02ff18ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff1480ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ff0bff808080808080ff808080ff298080ff02ffff03ffff09ffff0cff5dff8200bdffff10ff8200bdffff0dffff0effff018d226368616c6c656e6765223a22ff0bffff012280808080ffff0effff018d226368616c6c656e6765223a22ff0bffff01228080ffff01ff04ffff04ffff0148ffff04ff8202fdff808080ffff841c3a8f00ff09ffff0bff2dffff0bff5d8080ff82017d8080ffff01ff088080ff0180ff018080");
pub const PASSKEY_MEMBER_PUZZLE_ASSERT_HASH: [u8; 32] =
    hex!("e6db5ba2eeded13c47216512a7a4662b95121c145580db6312cb711aaadcec32");

/// ```text
/// ; member puzzle with SECP256-R1 signature provided by a passkey (ie Yubikey)
///
/// (mod (SECP_PK
///     Delegated_Puzzle_Hash
///     ; The WebAuthn authenticator data.
///     ; See https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata.
///     authenticator_data
///     ; The WebAuthn client data JSON.
///     ; See https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson.
///     client_data_json
///     ; The index at which "challenge":"..." occurs in `clientDataJSON`.
///     challenge_index
///     ; the signature returned by the authenticator
///     signature
///     ; my coin id
///     coin_id
///   )
///
///   (include *standard-cl-23*)
///   (include condition_codes.clib)
///   (include sha256tree.clib)
///
///   (defconstant b64-charset "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")
///
///   (defun map-triples (fun n blob)
///     (if (any (= n (strlen blob)) (> n (strlen blob)))
///         ()
///         (c (a fun (list (substr blob n (+ n 3)))) (map-triples fun (+ n 3) blob))
///     )
///   )
///
///   (defun flat-map (fun lst)
///     (if lst
///         (if (f lst)
///             (c (a fun (list (f (f lst)))) (flat-map fun (c (r (f lst)) (r lst))))
///             (flat-map fun (r lst))
///         )
///         ()
///     )
///   )
///
///   (defun lookup-b64 (byte)
///     (substr b64-charset byte (+ byte 1))
///   )
///
///   (defun-inline trim-padding (plen output)
///     (substr output 0 (- (strlen output) plen))
///   )
///
///   (defun-inline convert (int)
///     (if (> int -1) int (+ int 256))
///   )
///
///   (defun b64-encode-blob (blob)
///     (assign
///       pad_mod (r (divmod (strlen blob) 3))
///       padding (if pad_mod (- 3 pad_mod) 0)
///       bytes (concat blob (substr 0x000000 0 padding))
///       sextets
///       (map-triples (lambda ((& padding) bytes)
///           (assign
///             (fb_upper . fb_lower) (divmod (convert (substr bytes 0 1)) 4)
///             (sb_upper . sb_lower) (divmod (convert (substr bytes 1 2)) 16)
///             (tb_upper . tb_lower) (divmod (convert (substr bytes 2 3)) 64)
///             (list
///               fb_upper
///               (logior (ash fb_lower 4) sb_upper)
///               (logior (ash sb_lower 2) tb_upper)
///               tb_lower
///             )
///           )
///         )
///         0
///         bytes
///       )
///       (trim-padding padding (a (c (list 14) (flat-map lookup-b64 sextets)) ()))
///     )
///   )
///
///   (assign
///     message (b64-encode-blob (sha256 Delegated_Puzzle_Hash coin_id))
///     challenge (concat '"challenge":"' message '"')
///     (if (= (substr client_data_json challenge_index (+ challenge_index (strlen challenge))) challenge)
///         (c
///           (list ASSERT_MY_COIN_ID coin_id)
///           (secp256r1_verify SECP_PK (sha256 authenticator_data (sha256 client_data_json)) signature)
///         )
///         (x)
///     )
///   )
/// )
/// ```
pub const PASSKEY_MEMBER: [u8; 1418] = hex!("ff02ffff01ff02ff3effff04ff02ffff04ff03ffff04ffff02ff2cffff04ff02ffff04ffff0bff0bff82017f80ff80808080ff8080808080ffff04ffff01ffffffff02ffff03ffff21ffff09ff0bffff0dff178080ffff15ff0bffff0dff17808080ffff01ff0180ffff01ff04ffff02ff05ffff04ffff0cff17ff0bffff10ff0bffff01038080ff808080ffff02ff10ffff04ff02ffff04ff05ffff04ffff10ff0bffff010380ffff04ff17ff8080808080808080ff0180ff02ffff03ff0bffff01ff02ffff03ff13ffff01ff04ffff02ff05ffff04ff23ff808080ffff02ff18ffff04ff02ffff04ff05ffff04ffff04ff33ff1b80ff808080808080ffff01ff02ff18ffff04ff02ffff04ff05ffff04ff1bff808080808080ff0180ffff01ff018080ff0180ffff0cffff01c0404142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5fff05ffff10ff05ffff01018080ffff02ff3cffff04ff02ffff04ff03ffff04ffff06ffff14ffff0dff0580ffff01038080ff8080808080ff02ff12ffff04ff02ffff04ff03ffff04ffff02ffff03ff0bffff01ff11ffff0103ff0b80ffff01ff018080ff0180ff8080808080ffffff02ff2affff04ff02ffff04ff03ffff04ffff0eff11ffff0cffff0183000000ff80ff0b8080ff8080808080ffff02ff2effff04ff02ffff04ff03ffff04ffff02ff10ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff15ff808080ffff04ffff0101ff80808080ff80808080ffff04ff80ffff04ff0bff808080808080ff8080808080ff04ff4fffff04ffff19ffff16ff6fffff010480ff2780ffff04ffff19ffff16ff37ffff010280ff1380ffff04ff1bff8080808080ffff02ff3affff04ff02ffff04ffff04ffff04ff09ff8080ffff04ff0bff808080ffff04ffff14ffff02ffff03ffff15ffff0cff0bffff0102ffff010380ffff0181ff80ffff01ff0cff0bffff0102ffff010380ffff01ff10ffff0cff0bffff0102ffff010380ffff018201008080ff0180ffff014080ffff04ffff14ffff02ffff03ffff15ffff0cff0bffff0101ffff010280ffff0181ff80ffff01ff0cff0bffff0101ffff010280ffff01ff10ffff0cff0bffff0101ffff010280ffff018201008080ff0180ffff011080ffff04ffff14ffff02ffff03ffff15ffff0cff0bff80ffff010180ffff0181ff80ffff01ff0cff0bff80ffff010180ffff01ff10ffff0cff0bff80ffff010180ffff018201008080ff0180ffff010480ff80808080808080ffff0cffff02ffff04ffff04ffff010eff8080ffff02ff18ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff1480ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ff0bff808080808080ff8080ff80ffff11ffff0dffff02ffff04ffff04ffff010eff8080ffff02ff18ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff1480ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ff0bff808080808080ff808080ff298080ff02ffff03ffff09ffff0cff5dff8200bdffff10ff8200bdffff0dffff0effff018d226368616c6c656e6765223a22ff0bffff012280808080ffff0effff018d226368616c6c656e6765223a22ff0bffff01228080ffff01ff04ffff04ffff0146ffff04ff8202fdff808080ffff841c3a8f00ff09ffff0bff2dffff0bff5d8080ff82017d8080ffff01ff088080ff0180ff018080");
pub const PASSKEY_MEMBER_HASH: [u8; 32] =
    hex!("1d66225b71ec6caf33e3771ebaa7fcd50826fd31844dc8258116b37b3ff3c7ae");

/// ```text
/// ; this puzzle follows the Managed Inner Puzzle Spec MIPS01 as a Member Puzzle
/// ; this code offers a secure approval of a delegated puzzle passed in as a Truth to be run elsewhere
///
/// ; this code requires a signature including the coin's puzzle rather than the default which is the coin's id
/// ; this enables the signature to be used later, however users must be aware of replayability
///
/// (mod (SECP_PK Delegated_Puzzle_Hash my_puzhash signature)  ; delegated puzzle is passed in from the above M of N layer
///   (include condition_codes.clib)
///
///   (c
///     (list ASSERT_MY_PUZZLEHASH my_puzhash)
///     (secp256k1_verify SECP_PK (sha256 Delegated_Puzzle_Hash my_puzhash) signature)
///   )
/// )
/// ```
pub const SECP256K1_MEMBER_PUZZLE_ASSERT: [u8; 53] = hex!("ff02ffff01ff04ffff04ff02ffff04ff17ff808080ffff8413d61f00ff05ffff0bff0bff1780ff2f8080ffff04ffff0148ff018080");
pub const SECP256K1_MEMBER_PUZZLE_ASSERT_HASH: [u8; 32] =
    hex!("67d591ffeb00571269d401f41a6a43ceb927b5087074ad4446ff22400a010e87");

/// ```text
/// ; this puzzle follows the Managed Inner Puzzle Spec MIPS01 as a Member Puzzle
/// ; this code offers a secure approval of a delegated puzzle passed in as a Truth to be run elsewhere
///
/// (mod (SECP_PK Delegated_Puzzle_Hash my_id signature)  ; delegated puzzle is passed in from the above M of N layer
///   (include condition_codes.clib)
///
///   (c
///     (list ASSERT_MY_COIN_ID my_id)
///     (secp256k1_verify SECP_PK (sha256 Delegated_Puzzle_Hash my_id) signature)
///   )
/// )
/// ```
pub const SECP256K1_MEMBER: [u8; 53] = hex!("ff02ffff01ff04ffff04ff02ffff04ff17ff808080ffff8413d61f00ff05ffff0bff0bff1780ff2f8080ffff04ffff0146ff018080");
pub const SECP256K1_MEMBER_HASH: [u8; 32] =
    hex!("2b05daf134c9163acc8f2ac05b61f7d8328fca3dcc963154a28e89bcfc4dbfca");

/// ```text
/// ; this puzzle follows the Managed Inner Puzzle Spec MIPS01 as a Member Puzzle
/// ; this code offers a secure approval of a delegated puzzle passed in as a Truth to be run elsewhere
///
/// ; this code requires a signature including the coin's puzzle rather than the default which is the coin's id
/// ; this enables the signature to be used later, however users must be aware of replayability
///
/// (mod (SECP_PK Delegated_Puzzle_Hash my_puzhash signature)  ; delegated puzzle is passed in from the above M of N layer
///   (include condition_codes.clib)
///
///   (c
///     (list ASSERT_MY_PUZZLEHASH my_puzhash)
///     (secp256r1_verify SECP_PK (sha256 Delegated_Puzzle_Hash my_puzhash) signature)
///   )
/// )
/// ```
pub const SECP256R1_MEMBER_PUZZLE_ASSERT: [u8; 53] = hex!("ff02ffff01ff04ffff04ff02ffff04ff17ff808080ffff841c3a8f00ff05ffff0bff0bff1780ff2f8080ffff04ffff0148ff018080");
pub const SECP256R1_MEMBER_PUZZLE_ASSERT_HASH: [u8; 32] =
    hex!("d77bbc050bff8dfe4eb4544fa2bf0d0fd0463b96801bf6445687bd35985e71db");

/// ```text
/// ; this puzzle follows the Managed Inner Puzzle Spec MIPS01 as a Member Puzzle
/// ; this code offers a secure approval of a delegated puzzle passed in as a Truth to be run elsewhere
///
/// (mod (SECP_PK Delegated_Puzzle_Hash my_id signature)  ; delegated puzzle is passed in from the above M of N layer
///   (include condition_codes.clib)
///
///   (c
///     (list ASSERT_MY_COIN_ID my_id)
///     (secp256r1_verify SECP_PK (sha256 Delegated_Puzzle_Hash my_id) signature)
///   )
/// )
/// ```
pub const SECP256R1_MEMBER: [u8; 53] = hex!("ff02ffff01ff04ffff04ff02ffff04ff17ff808080ffff841c3a8f00ff05ffff0bff0bff1780ff2f8080ffff04ffff0146ff018080");
pub const SECP256R1_MEMBER_HASH: [u8; 32] =
    hex!("05aaa1f2fb6c48b5bce952b09f3da99afa4241989878a9919aafb7d74b70ac54");

/// ```text
/// (mod (SINGLETON_STRUCT Delegated_Puzzle singleton_innerpuzhash singleton_amount)
///   ; SINGLETON_STRUCT is ((SINGLETON_MOD_HASH, (LAUNCHER_ID, LAUNCHER_PUZZLE_HASH)))
///
///   (include condition_codes.clib)
///   (include curry-and-treehash.clib)
///
///   ; return the full puzzlehash for a singleton with the innerpuzzle curried in
///   ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib
///   (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)
///     )
///   )
///
///   (list (list
///       RECEIVE_MESSAGE
///       0x17  ; mode = puzzle sender, coin receiver -> 0x00 010 111
///       Delegated_Puzzle
///       (calculate_full_puzzle_hash SINGLETON_STRUCT singleton_innerpuzhash)
///   ))
/// )
/// ```
pub const SINGLETON_MEMBER: [u8; 361] = hex!("ff02ffff01ff04ffff04ff12ffff04ffff0117ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff09ffff04ff17ffff04ffff02ff3effff04ff02ffff04ff05ff80808080ff808080808080ff8080808080ff8080ffff04ffff01ffffff0204ff0101ffff4302ffff02ffff03ff05ffff01ff02ff16ffff04ff02ffff04ff0dffff04ffff0bff1affff0bff14ff1880ffff0bff1affff0bff1affff0bff14ff1c80ff0980ffff0bff1aff0bffff0bff14ff8080808080ff8080808080ffff010b80ff0180ffff0bff1affff0bff14ff1080ffff0bff1affff0bff1affff0bff14ff1c80ff0580ffff0bff1affff02ff16ffff04ff02ffff04ff07ffff04ffff0bff14ff1480ff8080808080ffff0bff14ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const SINGLETON_MEMBER_HASH: [u8; 32] =
    hex!("6f1cebc5a6d3661ad87d3558146259ca580729b244b7662757f8d1c34a6a9ad9");

/// ```text
/// ; This is a highly specific puzzle that enforces that any new create coins are a 1of2 w/ a fixed left side
/// ; and a variable right side that is put under pre-committed restrictions.
/// ;
/// ; The framework this is designed to fit in doesn't really support subtree behavior like this, so the specificity and
/// ; limited flexibility of this puzzle is due to the fact that it's sort of a hack to support an existing feature with
/// ; a framework poorly designed for it.
/// (mod
///   (
///     DELEGATED_PUZZLE_FEEDER_MOD_HASH
///     1_OF_N_MOD_HASH
///     LEFT_SIDE_SUBTREE_HASH_HASH
///     INDEX_WRAPPER_HASH
///     NONCE
///     RESTRICTION_MOD_HASH
///     MEMBER_VALIDATOR_LIST_HASH
///     DPUZ_VALIDATOR_LIST_HASH
///     Conditions
///     new_right_side_member_hash
///   )
///
///   (include curry.clib)
///   (include utility_macros.clib)
///   (include condition_codes.clib)
///   (defconstant ONE 1)
///
///   (defun check_coins (conditions fixed_puzzle_hash)
///     (if conditions
///         (if (and (= (f (f conditions)) CREATE_COIN) (not (= (f (r (f conditions))) fixed_puzzle_hash)))
///             (x)
///             (check_coins (r conditions) fixed_puzzle_hash)
///         )
///         1  ; this will pass assert
///     )
///   )
///
///   (defun-inline calculate_fixed_puzzle_hash
///     (
///       DELEGATED_PUZZLE_FEEDER_MOD_HASH
///       1_OF_N_MOD_HASH
///       LEFT_SIDE_SUBTREE_HASH_HASH
///       INDEX_WRAPPER_HASH
///       NONCE
///       RESTRICTION_MOD_HASH
///       MEMBER_VALIDATOR_LIST_HASH
///       DPUZ_VALIDATOR_LIST_HASH
///       new_right_side_member_hash
///     )
///
///
///     (curry_hashes INDEX_WRAPPER_HASH
///       (sha256 ONE NONCE)
///       (curry_hashes DELEGATED_PUZZLE_FEEDER_MOD_HASH
///         (curry_hashes 1_OF_N_MOD_HASH
///           (sha256 ONE (sha256 TWO
///               LEFT_SIDE_SUBTREE_HASH_HASH
///               ; right side calculation
///               (sha256 ONE (curry_hashes INDEX_WRAPPER_HASH
///                   (sha256 ONE NONCE)
///                   (curry_hashes RESTRICTION_MOD_HASH
///                     MEMBER_VALIDATOR_LIST_HASH
///                     DPUZ_VALIDATOR_LIST_HASH
///                     new_right_side_member_hash
///                   )
///               ))
///           ))
///         )
///       )
///     )
///   )
///
///   (assert
///     (check_coins
///       Conditions
///       (calculate_fixed_puzzle_hash
///         DELEGATED_PUZZLE_FEEDER_MOD_HASH
///         1_OF_N_MOD_HASH
///         LEFT_SIDE_SUBTREE_HASH_HASH
///         INDEX_WRAPPER_HASH
///         NONCE
///         RESTRICTION_MOD_HASH
///         MEMBER_VALIDATOR_LIST_HASH
///         DPUZ_VALIDATOR_LIST_HASH
///         new_right_side_member_hash
///       )
///     )
///     ; then
///     Conditions
///   )
/// )
/// ```
pub const FORCE_1_OF_2_W_RESTRICTED_VARIABLE: [u8; 650] = hex!("ff02ffff01ff02ffff03ffff02ff12ffff04ff02ffff04ff8205ffffff04ffff02ff16ffff04ff02ffff04ff2fffff04ffff0bff18ff5f80ffff04ffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff0bff18ffff0bff14ff17ffff0bff18ffff02ff16ffff04ff02ffff04ff2fffff04ffff0bff18ff5f80ffff04ffff02ff16ffff04ff02ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff820bffff80808080808080ff808080808080808080ff8080808080ff8080808080ff808080808080ff8080808080ffff018205ffffff01ff088080ff0180ffff04ffff01ffffff3301ff02ff02ffff03ff05ffff01ff0bff7affff02ff1effff04ff02ffff04ff09ffff04ffff02ff1cffff04ff02ffff04ff0dff80808080ff808080808080ffff016a80ff0180ffffff02ffff03ff05ffff01ff02ffff03ffff02ffff03ffff09ff11ff1080ffff01ff02ffff03ffff20ffff09ff29ff0b8080ffff01ff0101ff8080ff0180ff8080ff0180ffff01ff0880ffff01ff02ff12ffff04ff02ffff04ff0dffff04ff0bff808080808080ff0180ffff01ff010180ff0180ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff0bff5affff02ff1effff04ff02ffff04ff05ffff04ffff02ff1cffff04ff02ffff04ff07ff80808080ff808080808080ff0bff14ffff0bff14ff6aff0580ffff0bff14ff0bff4a8080ff018080");
pub const FORCE_1_OF_2_W_RESTRICTED_VARIABLE_HASH: [u8; 32] =
    hex!("4f7bc8f30deb6dad75a1e29ceacb67fd0fe0eda79173e45295ff2cfbb8de53c6");

/// ```text
/// ; This is a restriction on delegated puzzles intended to force a coin announcement
/// ;
/// ; The idea behind enforcing this is that it makes the current coin spend non-replayable since it will be implictly
/// ; asserting that a specific coin ID is spent in tandem.
/// (mod
///   (
///     Conditions
///   )
///
///   (include condition_codes.clib)
///
///   (defun check_conditions (conditions)
///     ; If we run out of conditions without finding an assertion, this will raise with "path into atom"
///     (if (= (f (f conditions)) ASSERT_COIN_ANNOUNCEMENT)
///         conditions
///         (c (f conditions) (check_conditions (r conditions)))
///     )
///   )
///
///   (check_conditions Conditions)
/// )
/// ```
pub const FORCE_ASSERT_COIN_ANNOUNCEMENT: [u8; 85] = hex!("ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ff3dff02ffff03ffff09ff11ff0480ffff0105ffff01ff04ff09ffff02ff06ffff04ff02ffff04ff0dff808080808080ff0180ff018080");
pub const FORCE_ASSERT_COIN_ANNOUNCEMENT_HASH: [u8; 32] =
    hex!("ca0daca027e5ebd4a61fad7e32cfe1e984ad5b561c2fc08dea30accf3a191fab");

/// ```text
/// ; This is a restriction on delegated puzzles intended to force a message that asserts the recipient's coin ID
/// ;
/// ; The idea behind enforcing this is that it makes the current coin spend non-replayable since it will be implictly
/// ; asserting that a specific coin ID is spent in tandem.
/// (mod
///   (
///     Conditions
///   )
///
///   (include condition_codes.clib)
///   (include utility_macros.clib)
///
///   (defun check_conditions (conditions)
///     ; If we run out of conditions without finding an assertion, this will raise with "path into atom"
///     (if (and
///           (= (f (f conditions)) SEND_MESSAGE)
///           ; This message filter will make sure that the last three bits of the bitmask are set.
///           ; The reason we do this is to make sure that there will be a RECIPIENT whose coin ID must be spent
///           ; in order for this spend to happen.
///           (logand (f (r (f conditions))) 0x07)  ; 0x07 == 00 000 111
///         )
///         conditions
///         (c (f conditions) (check_conditions (r conditions)))
///     )
///   )
///
///   (check_conditions Conditions)
/// )
/// ```
pub const FORCE_COIN_MESSAGE: [u8; 127] = hex!("ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ff42ff02ffff03ffff02ffff03ffff09ff11ff0480ffff01ff02ffff03ffff18ff29ffff010780ffff01ff0101ff8080ff0180ff8080ff0180ffff0105ffff01ff04ff09ffff02ff06ffff04ff02ffff04ff0dff808080808080ff0180ff018080");
pub const FORCE_COIN_MESSAGE_HASH: [u8; 32] =
    hex!("9618c96b30b96362f6c01716a11f76c630a786697d5bac92345f5ff90b882268");

/// ```text
/// (mod (CONDITION_OPCODE Conditions)
///   (include utility_macros.clib)
///
///   (defun check_coins (CONDITION_OPCODE conditions)
///     (if conditions
///       (if (= (f (f conditions)) CONDITION_OPCODE)
///         (x)
///         (check_coins CONDITION_OPCODE (r conditions))
///       )
///       1
///     )
///   )
///
///   (assert (check_coins CONDITION_OPCODE Conditions) Conditions)
/// )
/// ```
pub const PREVENT_CONDITION_OPCODE: [u8; 131] = hex!("ff02ffff01ff02ffff03ffff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff010bffff01ff088080ff0180ffff04ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff23ff0580ffff01ff0880ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff1bff808080808080ff0180ffff01ff010180ff0180ff018080");
pub const PREVENT_CONDITION_OPCODE_HASH: [u8; 32] =
    hex!("046dfa794bb1df14d5dc891b23764a0e31f119546d2c56cdc8df0d31daaa555f");

/// ```text
/// (mod (Conditions)
///   (include utility_macros.clib)
///   (include condition_codes.clib)
///
///   (defun check_coins (conditions count)
///     (if conditions
///       (check_coins
///         (r conditions)
///         (if (= (f (f conditions)) CREATE_COIN)
///           (+ count 1)
///           count
///         )
///       )
///       count
///     )
///   )
///
///   (assert (= (check_coins Conditions 0) 1) Conditions)
/// )
/// ```
pub const PREVENT_MULTIPLE_CREATE_COINS: [u8; 143] = hex!("ff02ffff01ff02ffff03ffff09ffff02ff06ffff04ff02ffff04ff05ffff01ff8080808080ffff010180ffff0105ffff01ff088080ff0180ffff04ffff01ff33ff02ffff03ff05ffff01ff02ff06ffff04ff02ffff04ff0dffff04ffff02ffff03ffff09ff11ff0480ffff01ff10ff0bffff010180ffff010b80ff0180ff8080808080ffff010b80ff0180ff018080");
pub const PREVENT_MULTIPLE_CREATE_COINS_HASH: [u8; 32] =
    hex!("93b8c8abeab8f6bdba4acb49ed49362ecba94b703a48b15c8784f966547b7846");

/// ```text
/// (mod
///   (
///     TIMELOCK
///     Conditions
///   )
///
///   (include condition_codes.clib)
///   (include utility_macros.clib)
///
///   (defun check_conditions (TIMELOCK conditions)
///     (if (and (= (f (f conditions)) ASSERT_SECONDS_RELATIVE) (= (f (r (f conditions))) TIMELOCK))
///         conditions
///         (c (f conditions) (check_conditions TIMELOCK (r conditions)))
///     )
///   )
///
///   (check_conditions TIMELOCK Conditions)
/// )
/// ```
pub const TIMELOCK: [u8; 137] = hex!("ff02ffff01ff02ff06ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff50ff02ffff03ffff02ffff03ffff09ff23ff0480ffff01ff02ffff03ffff09ff53ff0580ffff01ff0101ff8080ff0180ff8080ff0180ffff010bffff01ff04ff13ffff02ff06ffff04ff02ffff04ff05ffff04ff1bff80808080808080ff0180ff018080");
pub const TIMELOCK_HASH: [u8; 32] =
    hex!("a6f96d8ecf9bd29e8c41822d231408823707b587bc0d372e5db4ac9733cbea3c");

/// ```text
/// (mod
///   (
///     WRAPPER
///     DELEGATED_PUZZLE
///     wrapper_solution
///     delegated_solution
///   )
///
///   (a WRAPPER (c (a DELEGATED_PUZZLE delegated_solution) wrapper_solution))
/// )
/// ```
pub const ADD_DPUZ_WRAPPER: [u8; 19] = hex!("ff02ff02ffff04ffff02ff05ff1780ff0b8080");
pub const ADD_DPUZ_WRAPPER_HASH: [u8; 32] =
    hex!("6427724905f2dcf8187300ef9a0436a3c96198e4fcd17101d1ded9bc61c3f3bf");

/// ```text
/// ; This apparent monstrosity of a chiklisp file really does a very simple thing and gets it relative ugliness from
/// ; special attention paid to optimizing it.
/// ;
/// ; The goal of the function is to make sure that some delegated puzzle (inner_most_puzzle_hash) is wrapped by a number
/// ; of wrappers (WRAPPER_STACK) that use a specific base puzzle (ADD_WRAPPER_MOD). It uses the information in its solution
/// ; to calculate the hash of the following and assert it matches the delegated puzzle being validated:
/// ;
/// ; (a (q . WRAPPER_MOD) (c (q . WRAPPER) (c delegated_puzzle 1)))
/// (mod
///   (
///     QUOTED_ADD_WRAPPER_MOD_HASH  ; The mod hash of the quoted wrapper add-er i.e. (q . ADD_WRAPPER_MOD)
///     WRAPPER_STACK  ; The list of wrapper hashes (pre-quoted like above) to be run on the delegated puzzle
///     delegated_puzzle_hash  ; The hash of the delegated puzzle to validate
///     inner_most_puzzle_hash  ; hash of the thing being wrapped by all of these puzzles
///   )
///
///   (defconstant TWO 2)
///   (defconstant SHA_1_NIL 0x4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a)
///   (defconstant SHA_1_1 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2)
///   (defconstant SHA_1_C 0xa8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5)
///   (defconstant SHA_1_A 0xa12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222)
///   (defconstant SHA_1_&_NIL 0xba4484b961b7a2369d948d06c55b64bdbfaffb326bc13b490ab1215dd33d8d46)
///
///   (defun-inline branch_hash (left right)
///     (sha256 TWO left right)
///   )
///
///   (defun wrap_inner_most_puzzle_hash (QUOTED_ADD_WRAPPER_MOD_HASH WRAPPER_STACK inner_most_puzzle_hash)
///     (if WRAPPER_STACK
///         (branch_hash
///           SHA_1_A
///           (branch_hash
///             QUOTED_ADD_WRAPPER_MOD_HASH
///             (branch_hash
///               (branch_hash
///                 SHA_1_C
///                 (branch_hash
///                   (f WRAPPER_STACK)
///                   (branch_hash
///                     (branch_hash
///                       SHA_1_C
///                       (branch_hash
///                         (branch_hash
///                           SHA_1_1
///                           (wrap_inner_most_puzzle_hash QUOTED_ADD_WRAPPER_MOD_HASH (r WRAPPER_STACK) inner_most_puzzle_hash)
///                         )
///                         SHA_1_&_NIL
///                       )
///                     )
///                     SHA_1_NIL
///                   )
///                 )
///               )
///               SHA_1_NIL
///             )
///           )
///         )
///         inner_most_puzzle_hash
///     )
///   )
///
///   (if (= delegated_puzzle_hash (wrap_inner_most_puzzle_hash QUOTED_ADD_WRAPPER_MOD_HASH WRAPPER_STACK inner_most_puzzle_hash))
///       ()
///       (x)
///   )
/// )
/// ```
pub const ENFORCE_DPUZ_WRAPPERS: [u8; 363] = hex!("ff02ffff01ff02ffff03ffff09ff17ffff02ff1effff04ff02ffff04ff05ffff04ff0bffff04ff2fff80808080808080ff80ffff01ff088080ff0180ffff04ffff01ffffa0ba4484b961b7a2369d948d06c55b64bdbfaffb326bc13b490ab1215dd33d8d46ffa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2a0a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222ffffa0a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5a04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aff02ff02ffff03ff0bffff01ff0bff16ff1cffff0bff16ff05ffff0bff16ffff0bff16ff12ffff0bff16ff13ffff0bff16ffff0bff16ff12ffff0bff16ffff0bff16ff14ffff02ff1effff04ff02ffff04ff05ffff04ff1bffff04ff17ff80808080808080ff088080ff1a808080ff1a808080ffff011780ff0180ff018080");
pub const ENFORCE_DPUZ_WRAPPERS_HASH: [u8; 32] =
    hex!("1f94aa2381c1c02fec90687c0b045ef3cad4b458f8eac5bd90695b4d89624f09");

/// ```text
/// (mod (POOL_PUZZLE_HASH
///     P2_SINGLETON_PUZZLE_HASH
///     OWNER_PUBKEY
///     POOL_REWARD_PREFIX
///     WAITINGROOM_PUZHASH
///     Truths
///     p1
///     pool_reward_height
///   )
///
///
///   ; POOL_PUZZLE_HASH is commitment to the pool's puzzle hash
///   ; P2_SINGLETON_PUZZLE_HASH is the puzzle hash for your pay to singleton puzzle
///   ; OWNER_PUBKEY is the farmer pubkey which authorises a travel
///   ; POOL_REWARD_PREFIX is network-specific data (mainnet vs testnet) that helps determine if a coin is a pool reward
///   ; WAITINGROOM_PUZHASH is the puzzle_hash you'll go to when you initiate the leaving process
///
///   ; Absorbing money if pool_reward_height is an atom
///   ; Escaping if pool_reward_height is ()
///
///   ; p1 is pool_reward_amount if absorbing money
///   ; p1 is extra_data key_value_list if escaping
///
///   ; pool_reward_amount is the value of the coin reward - this is passed in so that this puzzle will still work after halvenings
///   ; pool_reward_height is the block height that the reward was generated at. This is used to calculate the coin ID.
///   ; key_value_list is signed extra data that the wallet may want to publicly announce for syncing purposes
///
///   (include condition_codes.clib)
///   (include singleton_truths.clib)
///
///   ; takes a lisp tree and returns the hash of it
///   (defun sha256tree (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   (defun-inline calculate_pool_reward (pool_reward_height P2_SINGLETON_PUZZLE_HASH POOL_REWARD_PREFIX pool_reward_amount)
///     (sha256 (logior POOL_REWARD_PREFIX (logand (- (lsh (q . 1) (q . 128)) (q . 1)) pool_reward_height)) P2_SINGLETON_PUZZLE_HASH pool_reward_amount)
///   )
///
///   (defun absorb_pool_reward (POOL_PUZZLE_HASH my_inner_puzzle_hash my_amount pool_reward_amount pool_reward_id)
///     (list
///       (list CREATE_COIN my_inner_puzzle_hash my_amount)
///       (list CREATE_COIN POOL_PUZZLE_HASH pool_reward_amount)
///       (list CREATE_PUZZLE_ANNOUNCEMENT pool_reward_id)
///       (list ASSERT_COIN_ANNOUNCEMENT (sha256 pool_reward_id '$'))
///     )
///   )
///
///   (defun-inline travel_to_waitingroom (OWNER_PUBKEY WAITINGROOM_PUZHASH my_amount extra_data)
///     (list (list AGG_SIG_ME OWNER_PUBKEY (sha256tree extra_data))
///       (list CREATE_COIN WAITINGROOM_PUZHASH my_amount)
///     )
///   )
///
///   ; main
///
///   (if pool_reward_height
///       (absorb_pool_reward POOL_PUZZLE_HASH
///         (my_inner_puzzle_hash_truth Truths)
///         (my_amount_truth Truths)
///         p1
///         (calculate_pool_reward pool_reward_height P2_SINGLETON_PUZZLE_HASH POOL_REWARD_PREFIX p1)
///       )
///       (travel_to_waitingroom OWNER_PUBKEY WAITINGROOM_PUZHASH (my_amount_truth Truths) p1)
///   )
/// )
/// )
/// ```
pub const POOL_MEMBER_INNERPUZ: [u8; 376] = hex!("ff02ffff01ff02ffff03ff8202ffffff01ff02ff16ffff04ff02ffff04ff05ffff04ff8204bfffff04ff8206bfffff04ff82017fffff04ffff0bffff19ff2fffff18ffff019100ffffffffffffffffffffffffffffffffff8202ff8080ff0bff82017f80ff8080808080808080ffff01ff04ffff04ff08ffff04ff17ffff04ffff02ff1effff04ff02ffff04ff82017fff80808080ff80808080ffff04ffff04ff1cffff04ff5fffff04ff8206bfff80808080ff80808080ff0180ffff04ffff01ffff32ff3d33ff3effff04ffff04ff1cffff04ff0bffff04ff17ff80808080ffff04ffff04ff1cffff04ff05ffff04ff2fff80808080ffff04ffff04ff0affff04ff5fff808080ffff04ffff04ff14ffff04ffff0bff5fffff012480ff808080ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const POOL_MEMBER_INNERPUZ_HASH: [u8; 32] =
    hex!("a8490702e333ddd831a3ac9c22d0fa26d2bfeaf2d33608deb22f0e0123eb0494");

/// ```text
/// (mod (POOL_PUZZLE_HASH
///     P2_SINGLETON_PUZZLE_HASH
///     OWNER_PUBKEY
///     POOL_REWARD_PREFIX
///     RELATIVE_LOCK_HEIGHT
///     Truths
///     spend_type
///     p1
///     p2
///   )
///
///   ; POOL_PUZZLE_HASH is commitment to the pool's puzzle hash
///   ; P2_SINGLETON_PUZZLE_HASH is the puzzlehash for your pay_to_singleton puzzle
///   ; OWNER_PUBKEY is the farmer pubkey which signs the exit puzzle_hash
///   ; POOL_REWARD_PREFIX is network-specific data (mainnet vs testnet) that helps determine if a coin is a pool reward
///   ; RELATIVE_LOCK_HEIGHT is how long it takes to leave
///
///   ; spend_type is: 0 for absorbing money, 1 to escape
///   ; if spend_type is 0
///   ; p1 is pool_reward_amount - the value of the coin reward - this is passed in so that this puzzle will still work after halvenings
///   ; p2 is pool_reward_height - the block height that the reward was generated at. This is used to calculate the coin ID.
///   ; if spend_type is 1
///   ; p1 is extra_data key_value_list - signed extra data that the wallet may want to publicly announce for syncing purposes
///   ; p2 is destination_puzhash - the location that the escape spend wants to create itself to
///
///   (include condition_codes.clib)
///   (include singleton_truths.clib)
///
///   ; takes a lisp tree and returns the hash of it
///   (defun sha256tree (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   (defun-inline calculate_pool_reward (pool_reward_height P2_SINGLETON_PUZZLE_HASH POOL_REWARD_PREFIX pool_reward_amount)
///     (sha256 (logior POOL_REWARD_PREFIX (logand (- (lsh (q . 1) (q . 128)) (q . 1)) pool_reward_height)) P2_SINGLETON_PUZZLE_HASH pool_reward_amount)
///   )
///
///   (defun absorb_pool_reward (POOL_PUZZLE_HASH my_inner_puzzle_hash my_amount pool_reward_amount pool_reward_id)
///     (list
///       (list CREATE_COIN my_inner_puzzle_hash my_amount)
///       (list CREATE_COIN POOL_PUZZLE_HASH pool_reward_amount)
///       (list CREATE_PUZZLE_ANNOUNCEMENT pool_reward_id)
///       (list ASSERT_COIN_ANNOUNCEMENT (sha256 pool_reward_id '$'))
///     )
///   )
///
///   (defun-inline travel_spend (RELATIVE_LOCK_HEIGHT new_puzzle_hash my_amount extra_data)
///     (list (list ASSERT_HEIGHT_RELATIVE RELATIVE_LOCK_HEIGHT)
///       (list CREATE_COIN new_puzzle_hash my_amount)
///       (list AGG_SIG_ME OWNER_PUBKEY (sha256tree (list new_puzzle_hash extra_data)))
///     )
///   )
///
///   ; main
///
///   (if spend_type
///       (travel_spend RELATIVE_LOCK_HEIGHT p2 (my_amount_truth Truths) p1)
///       (absorb_pool_reward POOL_PUZZLE_HASH
///         (my_inner_puzzle_hash_truth Truths)
///         (my_amount_truth Truths)
///         p1
///         (calculate_pool_reward p2 P2_SINGLETON_PUZZLE_HASH POOL_REWARD_PREFIX p1)
///       )
///   )
///
/// )
/// ```
pub const POOL_WAITINGROOM_INNERPUZ: [u8; 412] = hex!("ff02ffff01ff02ffff03ff82017fffff01ff04ffff04ff1cffff04ff5fff808080ffff04ffff04ff12ffff04ff8205ffffff04ff8206bfff80808080ffff04ffff04ff08ffff04ff17ffff04ffff02ff1effff04ff02ffff04ffff04ff8205ffffff04ff8202ffff808080ff80808080ff80808080ff80808080ffff01ff02ff16ffff04ff02ffff04ff05ffff04ff8204bfffff04ff8206bfffff04ff8202ffffff04ffff0bffff19ff2fffff18ffff019100ffffffffffffffffffffffffffffffffff8205ff8080ff0bff8202ff80ff808080808080808080ff0180ffff04ffff01ffff32ff3d52ffff333effff04ffff04ff12ffff04ff0bffff04ff17ff80808080ffff04ffff04ff12ffff04ff05ffff04ff2fff80808080ffff04ffff04ff1affff04ff5fff808080ffff04ffff04ff14ffff04ffff0bff5fffff012480ff808080ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const POOL_WAITINGROOM_INNERPUZ_HASH: [u8; 32] =
    hex!("a317541a765bf8375e1c6e7c13503d0d2cbf56cacad5182befe947e78e2c0307");

/// ```text
/// ;; this code is included in the ROM. Unfortunately, it has a problem that limits
/// ;; its usefulness: it is incapable of deserializing atoms with length longer than
/// ;; 8191 = 0x1fff.
/// ;;
/// ;; Because this code is included in the ROM, fixing the bug would be a hard fork
/// ;; so we're rather stuck with this bug. We recommend simply using a local version
/// ;; of this code when necessary.
///
/// (mod (input)
///
///   (defconstant MAX_SINGLE_BYTE 0x7F)
///   (defconstant MAX_TWO_BYTE 0xbf)
///   (defconstant MAX_THREE_BYTE 0xdf)
///   (defconstant MAX_FOUR_BYTE 0xef)
///   (defconstant MAX_FIVE_BYTE 0xf7)
///   (defconstant MAX_SIX_BYTE 0xfb)
///   (defconstant CONS_BOX_MARKER 0xFF)
///
///   (defun sexp_from_stream (input_stream)
///     (if (= (substr input_stream 0 1) CONS_BOX_MARKER)
///         (cons_sexp_from_stream (sexp_from_stream (substr input_stream 1)))
///         (atom_from_stream (substr input_stream 1) (substr input_stream 0 1))
///     )
///   )
///
///   (defun cons_sexp_from_stream (left_sexp_with_input)
///     (cons_return (f left_sexp_with_input) (sexp_from_stream (f (r left_sexp_with_input))))
///   )
///
///   (defun cons_return (left_sexp right_sexp_with_input)
///     (list (c left_sexp (f right_sexp_with_input)) (f (r right_sexp_with_input)))
///   )
///
///   (defun atom_from_stream (input_file input_bits)
///     (if (= input_bits (quote 0x80))
///         (list () input_file)
///         (if (>s input_bits MAX_SINGLE_BYTE)
///             (atom_from_stream_part_two (get_bitcount input_bits input_file))
///             (list input_bits input_file)
///         )
///     )
///   )
///
///   ; Note that we reject any serialized atom here with more than 3 bytes of
///   ; encoded length prefix, even though the Rust and Python KLVM interpreters
///   ; and deserializers support more.
///   ; This allows 5 + 8 = 13 bits = 8191-byte atoms
///   ; Also note that this does not limit intermediate atom length. Those limits
///   ; are implemented in the klvm interpreters theselves
///   (defun-inline get_bitcount (input_bits input_file)
///     (if (>s input_bits MAX_TWO_BYTE)
///         (if (>s input_bits MAX_THREE_BYTE)
///             (x)
///             ;three byte length prefix
///             (list (concat (logand (quote 0x1f) input_bits) (substr input_file 0 1)) (substr input_file 1))
///         )
///         ;two byte length prefix
///         (list (logand (quote 0x3f) input_bits) input_file)
///     )
///   )
///
///   (defun atom_from_stream_part_two ((size_to_read input_file))
///     (list (substr input_file 0 size_to_read) (substr input_file size_to_read))
///   )
///
///   ; main
///   (f (sexp_from_stream input))
///
/// )
/// ```
pub const CHIKLISP_DESERIALISATION: [u8; 471] = hex!("ff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080");
pub const CHIKLISP_DESERIALISATION_HASH: [u8; 32] =
    hex!("94ec19077f9a34e0b11ad2456af0170f4cc03f11230ca42e3f82e6e644ac4f5d");

/// ```text
/// (mod (block_decompresser_program (historical_blocks_tree))
///
///   (defconstant local_deserialize_mod
///     ;; this monstrosity is the assembly output of `chiklisp_deserialisation.clsp`
///     ;; it's pasted in here because the compiler doesn't yet support nested `mod`
///     ;; my apologies -- RK
///
///     (a (q 5 (a 62 (c 2 (c 5 ()))))
///       (c (q ((-1 . 127) -33 . -65) ((a (i (= 11 (q . -128)) (q 4 () (c 5 ())) (q 2 (i (>s 11 24) (q 2 26 (c 2 (c (a (i (>s 11 28) (q 2 (i (>s 11 20) (q 8) (q 4 (concat (logand (q . 31) 11) (substr 5 () (q . 1))) (c (substr 5 (q . 1)) ()))) 1) (q 4 (logand (q . 63) 11) (c 5 ()))) 1) ()))) (q 4 11 (c 5 ()))) 1)) 1) 4 (substr 21 () 9) (c (substr 21 9) ())) (c (c 5 19) (c 43 ())) (a 22 (c 2 (c 9 (c (a 62 (c 2 (c 21 ()))) ())))) 2 (i (= (substr 5 () (q . 1)) 16) (q 2 46 (c 2 (c (a 62 (c 2 (c (substr 5 (q . 1)) ()))) ()))) (q 2 18 (c 2 (c (substr 5 (q . 1)) (c (substr 5 () (q . 1)) ()))))) 1)
///     1))
///   )
///
///   (defun sha256tree
///     (TREE)
///     (if (l TREE)
///         (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE)))
///         (sha256 1 TREE)
///     )
///   )
///
///   (defun process_coin_spend ((parent puzzle amount solution . spend_level_extras))
///     (c parent (c (sha256tree puzzle) (c amount (c (a puzzle solution) spend_level_extras))))
///   )
///
///   (defun recurse (coin_spends)
///     (if coin_spends
///         (c (process_coin_spend (f coin_spends)) (recurse (r coin_spends)))
///         0
///     )
///   )
///
///   (defun process-decompressor ((coin_spends . block-level-extras))
///     (c (recurse coin_spends) block-level-extras)
///   )
///
/// (process-decompressor (a block_decompresser_program (list local_deserialize_mod historical_blocks_tree))))
/// )
/// ```
pub const ROM_BOOTSTRAP_GENERATOR: [u8; 737] = hex!("ff02ffff01ff02ff0cffff04ff02ffff04ffff02ff05ffff04ff08ffff04ff13ff80808080ff80808080ffff04ffff01ffffff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080ff04ffff02ff16ffff04ff02ffff04ff09ff80808080ff0d80ffff04ff09ffff04ffff02ff1effff04ff02ffff04ff15ff80808080ffff04ff2dffff04ffff02ff15ff5d80ff7d80808080ffff02ffff03ff05ffff01ff04ffff02ff0affff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ff8080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080");
pub const ROM_BOOTSTRAP_GENERATOR_HASH: [u8; 32] =
    hex!("161bade1f822dcd62ab712ebaf30f3922a301e48a639e4295c5685f8bece7bd9");

/// ```text
/// ; TODO convert generators arg to list of generators
///
/// (mod (decompress_puzzle decompress_coin_spend_entry start end compressed_cses deserialize gen_list reserved_arg)
///
///   (defun decompress_cses (decompress_puzzle decompress_coin_spend_entry cses deserialize puzzle_prefix)
///     (if cses
///         (c (a decompress_coin_spend_entry (list deserialize decompress_puzzle puzzle_prefix (f cses)))
///         (decompress_cses decompress_puzzle decompress_coin_spend_entry (r cses) deserialize puzzle_prefix ))
///   ()) )
///
///   (list (decompress_cses decompress_puzzle decompress_coin_spend_entry compressed_cses deserialize (substr (f gen_list) start end)))
///
/// )
/// ```
pub const BLOCK_PROGRAM_ZERO: [u8; 170] = hex!("ff02ffff01ff04ffff02ff02ffff04ff02ffff04ff05ffff04ff0bffff04ff5fffff04ff81bfffff04ffff0cff82027fff17ff2f80ff8080808080808080ff8080ffff04ffff01ff02ffff03ff17ffff01ff04ffff02ff0bffff04ff2fffff04ff05ffff04ff5fffff04ff27ff808080808080ffff02ff02ffff04ff02ffff04ff05ffff04ff0bffff04ff37ffff04ff2fffff04ff5fff808080808080808080ff8080ff0180ff018080");
pub const BLOCK_PROGRAM_ZERO_HASH: [u8; 32] =
    hex!("f0a38c8efe58895ae527c65c37f700a4238504691b83990e5dd91bd8b3c30eae");

/// ```text
/// (mod (deserialize decompress_puzzle puzzle_prefix cse)
///
///   ; decompress a single compressed standard transaction
///
///   (c (f (f cse)) (c (a decompress_puzzle (list deserialize puzzle_prefix (f (f (r cse))) (q . 0xff018080))) (c (f (r (f cse))) (r (f (r cse))))))
///
/// )
/// ```
pub const DECOMPRESS_COIN_SPEND_ENTRY_WITH_PREFIX: [u8; 54] = hex!("ff04ff47ffff04ffff02ff05ffff04ff02ffff04ff0bffff04ff8197ffff01ff84ff0180808080808080ffff04ff81a7ff81d7808080");
pub const DECOMPRESS_COIN_SPEND_ENTRY_WITH_PREFIX_HASH: [u8; 32] =
    hex!("92aa4bc8060a8836355a1884075141b4791ce1b67ae6092bb166b2845954bc89");

/// ```text
/// (mod (deserialize decompress_puzzle puzzle_prefix suffix cse)
///
///   ; decompress a single compressed standard transaction
///   (c (f cse) (c (a decompress_puzzle (list deserialize puzzle_prefix (f (f (r cse))) suffix)) (c (f (r (f cse))) (r (f (r cse))))))
/// )
/// ```
pub const DECOMPRESS_COIN_SPEND_ENTRY: [u8; 55] = hex!("ff04ff4fffff04ffff02ff05ffff04ff02ffff04ff0bffff04ff82012fffff04ff17ff808080808080ffff04ff82014fff8201af808080");
pub const DECOMPRESS_COIN_SPEND_ENTRY_HASH: [u8; 32] =
    hex!("9d98ed08770d31be4bd1bde4705dab388db5e7e9c349f5a76fc3c347aa3a0b79");

/// ```text
/// (mod (deserialize puzzle_prefix pubkey suffix)
///
///   (a deserialize (list (concat puzzle_prefix pubkey suffix)))
///
/// )
/// ```
pub const DECOMPRESS_PUZZLE: [u8; 21] = hex!("ff02ff02ffff04ffff0eff05ff0bff1780ff808080");
pub const DECOMPRESS_PUZZLE_HASH: [u8; 32] =
    hex!("fe94c58f1117afe315e0450daca1c62460ec1a1c439cd4018d79967a5d7d1370");
