(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)
      )
  )

)
