184 lines
6.5 KiB
Plaintext
184 lines
6.5 KiB
Plaintext
(mod (MOD_HASH MY_PUBKEY RECOVERY_DID_LIST_HASH NUM_VERIFICATIONS_REQUIRED mode amount message my_id my_puzhash parent_innerpuzhash_amounts_for_recovery_ids pubkey recovery_list_reveal)
|
|
;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.clvm)
|
|
|
|
(defmacro and ARGS
|
|
(if ARGS
|
|
(qq (if (unquote (f ARGS))
|
|
(unquote (c and (r ARGS)))
|
|
()
|
|
))
|
|
1)
|
|
)
|
|
|
|
(defmacro not (ARGS)
|
|
(qq (if (unquote ARGS) 0 1))
|
|
)
|
|
|
|
(defun is-in-list (atom items)
|
|
;; returns 1 iff `atom` is in the list of `items`
|
|
(if items
|
|
(if (= atom (f items))
|
|
1
|
|
(is-in-list atom (r items))
|
|
)
|
|
0
|
|
)
|
|
)
|
|
|
|
; 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)
|
|
)
|
|
)
|
|
|
|
;; utility function used by `curry_args`
|
|
(defun fix_curry_args (items core)
|
|
(if items
|
|
(qq (c (q . (unquote (f items))) (unquote (fix_curry_args (r items) core))))
|
|
core
|
|
)
|
|
)
|
|
|
|
; (curry_args sum (list 50 60)) => returns a function that is like (sum 50 60 ...)
|
|
(defun curry_args (func list_of_args) (qq (a (q . (unquote func)) (unquote (fix_curry_args list_of_args (q . 1))))))
|
|
|
|
;; (curry sum 50 60) => returns a function that is like (sum 50 60 ...)
|
|
(defun curry (func . args) (curry_args func args))
|
|
|
|
;; hash a tree with escape values representing already-hashed subtrees
|
|
;; This optimization can be useful if you know the puzzle hash of a sub-expression.
|
|
;; You probably actually want to use `curry_and_hash` though.
|
|
(defun sha256tree_esc_list
|
|
(TREE LITERALS)
|
|
(if (l TREE)
|
|
(sha256 2 (sha256tree_esc_list (f TREE) LITERALS) (sha256tree_esc_list (r TREE) LITERALS))
|
|
(if (is-in-list TREE LITERALS)
|
|
TREE
|
|
(sha256 1 TREE)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; hash a tree with escape values representing already-hashed subtrees
|
|
;; This optimization can be useful if you know the tree hash of a sub-expression.
|
|
(defun sha256tree_esc
|
|
(TREE . LITERAL)
|
|
(sha256tree_esc_list TREE LITERAL)
|
|
)
|
|
|
|
;recovery message module - gets values curried in to make the puzzle
|
|
;TODO - this should probably be imported
|
|
(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)))))
|
|
)
|
|
|
|
(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))
|
|
)
|
|
|
|
;; return the puzzle hash for a cc with the given `genesis-coin-checker-hash` & `inner-puzzle`
|
|
(defun-inline create_fullpuzhash (mod_hash mod_hash_hash genesis_id inner_puzzle_hash)
|
|
(sha256tree_esc (curry mod_hash mod_hash_hash genesis_id inner_puzzle_hash)
|
|
mod_hash
|
|
mod_hash_hash
|
|
inner_puzzle_hash)
|
|
)
|
|
|
|
(defun-inline create_coin_ID_for_recovery (mod_hash mod_hash_hash did parent innerpuzhash amount)
|
|
(sha256 parent (create_fullpuzhash mod_hash mod_hash_hash did innerpuzhash) amount)
|
|
)
|
|
|
|
(defmacro recreate_self (my_puzhash amount)
|
|
(qq (c CREATE_COIN (c (unquote my_puzhash) (c (unquote amount) ()))))
|
|
)
|
|
|
|
(defmacro create_new_coin (amount new_puz)
|
|
(qq (c CREATE_COIN (c (unquote new_puz) (c (unquote amount) ()))))
|
|
)
|
|
|
|
(defun check_messages_from_identities (mod_hash mod_hash_hash num_verifications_required identities my_id output new_puz parent_innerpuzhash_amounts_for_recovery_ids pubkey num_verifications)
|
|
(if identities
|
|
(if (f parent_innerpuzhash_amounts_for_recovery_ids)
|
|
(check_messages_from_identities
|
|
mod_hash
|
|
mod_hash_hash
|
|
num_verifications_required
|
|
(r identities)
|
|
my_id
|
|
(c
|
|
(create_consume_message
|
|
; create coin_id from DID
|
|
(create_coin_ID_for_recovery
|
|
mod_hash
|
|
mod_hash_hash
|
|
(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)
|
|
output)
|
|
new_puz
|
|
(r parent_innerpuzhash_amounts_for_recovery_ids)
|
|
pubkey
|
|
(+ num_verifications 1)
|
|
)
|
|
(check_messages_from_identities
|
|
mod_hash
|
|
mod_hash_hash
|
|
num_verifications_required
|
|
(r identities)
|
|
my_id
|
|
output
|
|
new_puz
|
|
(r parent_innerpuzhash_amounts_for_recovery_ids)
|
|
pubkey
|
|
num_verifications
|
|
)
|
|
)
|
|
;if we're out of identites to check for, return our output
|
|
(if (> num_verifications num_verifications_required)
|
|
(c (list AGG_SIG_UNSAFE pubkey new_puz) output)
|
|
(if (= num_verifications num_verifications_required)
|
|
(c (list AGG_SIG_UNSAFE pubkey new_puz) output)
|
|
(x "not enough verifications")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;Spend modes:
|
|
;0 = normal spend
|
|
;1 = attest
|
|
;2 (or anything else) = recovery
|
|
|
|
;MAIN
|
|
|
|
(if mode
|
|
(if (= mode 1)
|
|
; mode one - create message
|
|
(list (recreate_self my_puzhash amount) (list CREATE_COIN message 0) (list AGG_SIG_ME MY_PUBKEY (sha256tree1 (list my_puzhash amount message))))
|
|
; mode two - recovery
|
|
; check that recovery list is not empty
|
|
(if recovery_list_reveal
|
|
(if (= (sha256tree1 recovery_list_reveal) RECOVERY_DID_LIST_HASH)
|
|
(check_messages_from_identities MOD_HASH (sha256tree1 MOD_HASH) NUM_VERIFICATIONS_REQUIRED recovery_list_reveal my_id (list (create_new_coin amount message)) message parent_innerpuzhash_amounts_for_recovery_ids pubkey 0)
|
|
(x)
|
|
)
|
|
(x)
|
|
)
|
|
)
|
|
; mode zero - normal spend
|
|
(list (create_new_coin amount message) (list AGG_SIG_ME MY_PUBKEY (sha256tree1 (list amount message))))
|
|
)
|
|
|
|
)
|