Skip to content

Instantly share code, notes, and snippets.

@ojura
Last active February 22, 2022 21:26
Show Gist options
  • Save ojura/332410ddc8de19205249004b2185da24 to your computer and use it in GitHub Desktop.
Save ojura/332410ddc8de19205249004b2185da24 to your computer and use it in GitHub Desktop.
CAT unwrap excerpt
# Coin with index 0 - "coin 0"; regular CAT coin worth 2 mojos; our value extractor
# Coin with index 6 - "coin 6"; double wrapped CAT worth 1 mojo; we're trying to salvage it
inner_puzzle[0] = puzzle_for_pk(key[0].get_g1())
cat_puzzle[0] = construct_cat_puzzle(CAT_MOD, tail_hash, inner_puzzle[0])
inner_puzzle[6] = puzzle_for_pk(key[6].get_g1())
cat_puzzle[6] = construct_cat_puzzle(CAT_MOD, tail_hash, inner_puzzle[6])
cat_cat_puzzle[6] = construct_cat_puzzle(CAT_MOD, tail_hash, cat_puzzle[6])
coin_spends = []
# We're trying to create a regular CAT worth 2 + 1 = 3 mojos
primaries = [{"puzzlehash": destination_puzzlehash, "amount": 3, "memos": [destination_puzzlehash]}]
# Crucially, the regular CAT, coin 0, is the one which will create the 3 mojo coin and extract value
innersol[0] = Wallet().make_solution(primaries)
# The double wrapped CAT goes to the "great beyond", i.e. is spent without creating outputs
innersol[6] = Wallet().make_solution([])
# We're not minting or melting anything, so these are all empty
extra_delta, limitations_solution = 0, Program.to([])
limitations_program_reveal = Program.to([])
# Coin subtotals:
# Coin 0 = 0 by definition (first coin in the ring must have subtotal 0)
# Coin 6: 1 (coin 0 has an output of 3 mojos and contributes 2 mojos;
# its debt is therefore 1, which is the subtotal for the next coin in the ring, coin 6
# Coin 0 will be the first coin in the ring
cat_solution[0] = [innersol[0],
lineage_proof[0].to_program(),
cat_coin[6].name(), # prev_coin_id: previous coin in the ring is coin 6
cat_coin[0].as_list(), # this_coin_info
# next_coin_proof: notice that coin 6 has a CAT PUZZLE as its inner hash!
[cat_coin[6].parent_coin_info, cat_puzzle[6].get_tree_hash(), cat_coin[6].amount],
1, # PREVIOUS coin's subtotal -- in this case, of coin 6
0 # extra delta]
# Add it to the spend bundle
coin_spends.append(CoinSpend(cat_coin[0], cat_puzzle[0], Program.to(cat_solution[0])))
# Inner CAT solution for the wrapped CAT coin.
cat_solution[6] = [innersol[6],
lineage_proof[6].to_program(),
cat_coin[0].name(), # prev_coin_id
cat_coin[6].as_list(), # this_coin_info
# next_coin_proof: since coin 0 is a regular CAT, its inner puzzle is standard
[cat_coin[0].parent_coin_info, inner_puzzle[0].get_tree_hash(), cat_coin[0].amount],
0, # prev_subtotal: subtotal of coin 0, which is zero by definition
0]
# Now we do the same dance again, for the outer CAT layer!
cat_cat_solution[6] = [
# The solution for the inner CAT layer becomes the inner solution for the outer cat layer!
Program.to(cat_solution[6]),
lineage_proof[6].to_program(),
# All of these are same as for the inner CAT solution
cat_coin[0].name(),
cat_coin[6].as_list(),
[cat_coin[0].parent_coin_info, inner_puzzle[0].get_tree_hash(), cat_coin[0].amount],
0,
0]
# Add the wrapped CAT spend to the unsigned spend bundle
coin_spends.append(CoinSpend(cat_coin[6], cat_cat_puzzle[6], Program.to(cat_cat_solution[6])))
for spend in coin_spends:
error, conditions, cost = conditions_for_solution(
spend.puzzle_reveal.to_program(),
spend.solution.to_program(),
MAX_BLOCK_COST_CLVM)
print('conditions: ')
for c in conditions:
print(c.opcode, [v.hex() for v in c.vars])
# Sign the coin spends
signed_spend_bundle = asyncio.get_event_loop().run_until_complete(
sign_coin_spends(coin_spends, keyf, AGG_SIG_ME_ADDITIONAL_DATA, MAX_BLOCK_COST_CLVM))
f = io.BytesIO()
signed_spend_bundle.stream(f)
print('signed spendbundle: ', f.getvalue().hex())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment