Here are a bunch of changes you can make for humans only. None of these changes should change how it compiles, so you should be able to change anything in this section and compare the resultant compile. It should be identical.
I've really love an automated pretty-printer akin to "black" for python or "cargo fmt" for rust so you can write whatever mess you want and have a computer indent it so it looks nice, but I haven't been able to find one yet.
For now, use emacs. Enter lisp-mode (press "escape" then type "lisp-mode" and hit return). Use ";;" for comments as ";" get indented really far. Go to each line and hit to auto-tab, adding line breaks where it seems judicious for clarity.
Instead of 3, 5, 7, use #c, #f, etc.
Comment every function.
What does it expect as an input? If you have standard data types like "inner puzzle", describe those types at the top of the file and use consistent names like "inner-puzzle" everywhere.
What does it return? Describe clearly.
What are the large magic constants? Like 51, 53. Remind us locally.
Name functions very clearly, with verbs as the first word.
Name parameters very clearly. If a particular parameter makes its way through the call stack unchanged, use the exact same name everywhere to emphasize that (although if you do an "if" test to determine what the parameter means, you can change the name to clarify that you now know it means X instead of Y).
Try to figure out how to use "list" instead of a mess of nested (c X Y). Any time you use (q ())
at the end of a large
sequence of (c ...) expressions, there's a good chance you could actually use "list" to make it more legible.
Experiment with changing some macros to functions so that you don't have to obscure things with qq and unquote. These functions can eventually be replaced with (defun-inline) (and then these changes will become idempotent). For now, you can write the (defun-inline) version as a comment.
Right now, the "contract parameter" is a magic string in the middle. This makes it very hard to find and very hard to change. If you pass it in as a parameter at the very top, you can still make this work! You also require the entire compiled script ("self") to be passed into the solution.
Then you verify that the puzzle is of the correct form by currying contract-parameter and the inner puzzle hash to "self". That proves that self and contract-parameter are correct. You can now use this information to ensure that coins created by CREATE_COIN also match it (or transform them, as you do).