def test_spend_zero_coin(mod_code: Program, coin_checker_for_farmed_coin):
    """
    Test to spend ccs from a farmed coin to a cc genesis coin, then to N outputs,
    then joining back down to two outputs.
    """

    eve_inner_puzzle = ANYONE_CAN_SPEND_PUZZLE
    eve_inner_puzzle_hash = eve_inner_puzzle.get_tree_hash()

    total_minted = 0x111

    genesis_coin_checker, spend_bundle = issue_cc_from_farmed_coin(
        mod_code, coin_checker_for_farmed_coin, 1, eve_inner_puzzle_hash,
        total_minted)

    puzzles_for_db = [
        cc_puzzle_for_inner_puzzle(mod_code, genesis_coin_checker,
                                   eve_inner_puzzle)
    ]
    add_puzzles_to_puzzle_preimage_db(puzzles_for_db)

    eve_cc_list = []
    for _ in spend_bundle.coin_solutions:
        eve_cc_list.extend(
            spendable_cc_list_from_coin_solution(_, hash_to_puzzle_f))
    assert len(eve_cc_list) == 1
    eve_cc_spendable = eve_cc_list[0]

    # farm regular chia

    farmed_coin = generate_farmed_coin(2, eve_inner_puzzle_hash, amount=500)

    # create a zero cc from this farmed coin

    wrapped_cc_puzzle_hash = cc_puzzle_hash_for_inner_puzzle_hash(
        mod_code, genesis_coin_checker, eve_inner_puzzle_hash)

    solution = solution_for_pay_to_any([(wrapped_cc_puzzle_hash, 0)])
    reveal_w_solution = Program.to([ANYONE_CAN_SPEND_PUZZLE, solution])
    coin_solution = CoinSolution(farmed_coin, reveal_w_solution)
    spendable_cc_list = spendable_cc_list_from_coin_solution(
        coin_solution, hash_to_puzzle_f)
    assert len(spendable_cc_list) == 1
    zero_cc_spendable = spendable_cc_list[0]

    # we have our zero coin
    # now try to spend it

    spendable_cc_list = [eve_cc_spendable, zero_cc_spendable]
    inner_solutions = [
        solution_for_pay_to_any([]),
        solution_for_pay_to_any([(wrapped_cc_puzzle_hash,
                                  eve_cc_spendable.coin.amount)]),
    ]
    spend_bundle = spend_bundle_for_spendable_ccs(mod_code,
                                                  genesis_coin_checker,
                                                  spendable_cc_list,
                                                  inner_solutions)
    debug_spend_bundle(spend_bundle)
Beispiel #2
0
def coin_solution_for_lock_coin(
    prev_coin: Coin,
    subtotal: int,
    coin: Coin,
) -> CoinSolution:
    puzzle_reveal = LOCK_INNER_PUZZLE.curry(prev_coin.as_list(), subtotal)
    coin = Coin(coin.name(), puzzle_reveal.get_tree_hash(), uint64(0))
    coin_solution = CoinSolution(coin, Program.to([puzzle_reveal, 0]))
    return coin_solution
Beispiel #3
0
def spendable_cc_list_from_coin_solution(
    coin_solution: CoinSolution, hash_to_puzzle_f
) -> List[SpendableCC]:

    """
    Given a `CoinSolution`, extract out a list of `SpendableCC` objects.

    Since `SpendableCC` needs to track the inner puzzles and a `Coin` only includes
    puzzle hash, we also need a `hash_to_puzzle_f` function that turns puzzle hashes into
    the corresponding puzzles. This is generally either a `dict` or some kind of DB
    (if it's large or persistent).
    """

    spendable_cc_list = []

    coin = coin_solution.coin
    puzzle = coin_solution.solution.first()
    r = uncurry_cc(puzzle)
    if r:
        mod_hash, genesis_coin_checker, inner_puzzle = r
        lineage_proof = lineage_proof_for_cc_parent(coin, inner_puzzle.get_tree_hash())
    else:
        lineage_proof = lineage_proof_for_coin(coin)

    for new_coin in coin_solution.additions():
        puzzle = hash_to_puzzle_f(new_coin.puzzle_hash)
        if puzzle is None:
            # we don't recognize this puzzle hash, skip it
            continue
        r = uncurry_cc(puzzle)
        if r is None:
            # this isn't a cc puzzle
            continue

        mod_hash, genesis_coin_checker, inner_puzzle = r

        genesis_coin_id = genesis_coin_id_for_genesis_coin_checker(genesis_coin_checker)

        cc_spend_info = SpendableCC(
            new_coin, genesis_coin_id, inner_puzzle, lineage_proof
        )
        spendable_cc_list.append(cc_spend_info)

    return spendable_cc_list
def issue_cc_from_farmed_coin(
    mod_code: Program,
    coin_checker_for_farmed_coin,
    block_id: int,
    inner_puzzle_hash: bytes32,
    amount: int,
) -> Tuple[Program, SpendBundle]:
    """
    This is an example of how to issue a cc.
    """
    # get a farmed coin

    farmed_puzzle = ANYONE_CAN_SPEND_PUZZLE
    farmed_puzzle_hash = farmed_puzzle.get_tree_hash()

    # mint a cc

    farmed_coin = generate_farmed_coin(block_id,
                                       farmed_puzzle_hash,
                                       amount=uint64(amount))
    genesis_coin_checker = coin_checker_for_farmed_coin(farmed_coin)

    minted_cc_puzzle_hash = cc_puzzle_hash_for_inner_puzzle_hash(
        mod_code, genesis_coin_checker, inner_puzzle_hash)

    output_conditions = [[
        ConditionOpcode.CREATE_COIN, minted_cc_puzzle_hash, farmed_coin.amount
    ]]

    # for this very simple puzzle, the solution is simply the output conditions
    # this is just a coincidence... for more complicated puzzles, you'll likely have to do some real work

    solution = Program.to(output_conditions)
    coin_solution = CoinSolution(farmed_coin,
                                 Program.to([farmed_puzzle, solution]))
    spend_bundle = SpendBundle([coin_solution], NULL_SIGNATURE)
    return genesis_coin_checker, spend_bundle
Beispiel #5
0
def spend_bundle_for_spendable_ccs(
    mod_code: Program,
    genesis_coin_checker: Program,
    spendable_cc_list: List[SpendableCC],
    inner_solutions: List[Program],
    sigs: Optional[List[G2Element]] = [],
) -> SpendBundle:
    """
    Given a list of `SpendableCC` objects and inner solutions for those objects, create a `SpendBundle`
    that spends all those coins. Note that it the signature is not calculated it, so the caller is responsible
    for fixing it.
    """

    N = len(spendable_cc_list)

    if len(inner_solutions) != N:
        raise ValueError("spendable_cc_list and inner_solutions are different lengths")

    input_coins = [_.coin for _ in spendable_cc_list]

    # figure out what the output amounts are by running the inner puzzles & solutions
    output_amounts = []
    for cc_spend_info, inner_solution in zip(spendable_cc_list, inner_solutions):
        error, conditions, cost = conditions_dict_for_solution(Program.to([cc_spend_info.inner_puzzle, inner_solution]))
        total = 0
        if conditions:
            for _ in conditions.get(ConditionOpcode.CREATE_COIN, []):
                total += Program.to(_.vars[1]).as_int()
        output_amounts.append(total)

    coin_solutions = []

    deltas = [input_coins[_].amount - output_amounts[_] for _ in range(N)]
    subtotals = subtotals_for_deltas(deltas)

    if sum(deltas) != 0:
        raise ValueError("input and output amounts don't match")

    bundles = [bundle_for_spendable_cc_list(_) for _ in spendable_cc_list]

    for index in range(N):
        cc_spend_info = spendable_cc_list[index]

        puzzle_reveal = cc_puzzle_for_inner_puzzle(mod_code, genesis_coin_checker, cc_spend_info.inner_puzzle)

        prev_index = (index - 1) % N
        next_index = (index + 1) % N
        prev_bundle = bundles[prev_index]
        my_bundle = bundles[index]
        next_bundle = bundles[next_index]

        solution = [
            inner_solutions[index],
            prev_bundle,
            my_bundle,
            next_bundle,
            subtotals[index],
        ]
        full_solution = Program.to([puzzle_reveal, solution])

        coin_solution = CoinSolution(input_coins[index], full_solution)
        coin_solutions.append(coin_solution)

    # now add solutions to consume the lock coins

    for _ in range(N):
        prev_index = (_ - 1) % N
        prev_coin = spendable_cc_list[prev_index].coin
        this_coin = spendable_cc_list[_].coin
        subtotal = subtotals[_]
        coin_solution = coin_solution_for_lock_coin(prev_coin, subtotal, this_coin)
        coin_solutions.append(coin_solution)
    if sigs is None or sigs == []:
        return SpendBundle(coin_solutions, NULL_SIGNATURE)
    else:
        return SpendBundle(coin_solutions, AugSchemeMPL.aggregate(sigs))