def cc_generate_eve_spend(coin: Coin, full_puzzle: Program): solution = cc_make_eve_solution(coin.parent_coin_info, coin.puzzle_hash, coin.amount) list_of_solutions = [ CoinSolution( coin, Program.to([full_puzzle, solution]), ) ] aggsig = AugSchemeMPL.aggregate([]) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
def solution_with_hidden_puzzle( hidden_public_key: G1Element, hidden_puzzle: Program, solution_to_hidden_puzzle: Program, ) -> Program: synthetic_public_key = calculate_synthetic_public_key( hidden_public_key, hidden_puzzle ) puzzle = puzzle_for_synthetic_public_key(synthetic_public_key) return Program.to( [puzzle, [hidden_public_key, hidden_puzzle, solution_to_hidden_puzzle]] )
def best_solution_program(bundle: SpendBundle) -> Program: """ This could potentially do a lot of clever and complicated compression optimizations in conjunction with choosing the set of SpendBundles to include. For now, we just quote the solutions we know. """ r = [] for coin_solution in bundle.coin_solutions: entry = [coin_solution.coin.name(), coin_solution.solution] r.append(entry) return Program.to([binutils.assemble("#q"), r])
async def create_spend_bundle_relative_amount(self, cc_amount, zero_coin: Coin = None) -> Optional[SpendBundle]: # If we're losing value then get coloured coins with at least that much value # If we're gaining value then our amount doesn't matter if cc_amount < 0: cc_spends = await self.select_coins(abs(cc_amount)) else: if zero_coin is None: return None cc_spends = set() cc_spends.add(zero_coin) if cc_spends is None: return None # Calculate output amount given relative difference and sum of actual values spend_value = sum([coin.amount for coin in cc_spends]) cc_amount = spend_value + cc_amount # Loop through coins and create solution for innerpuzzle list_of_solutions = [] output_created = None sigs: List[G2Element] = [] for coin in cc_spends: if output_created is None: newinnerpuzhash = await self.get_new_inner_hash() innersol = self.standard_wallet.make_solution( primaries=[{"puzzlehash": newinnerpuzhash, "amount": cc_amount}] ) output_created = coin else: innersol = self.standard_wallet.make_solution(consumed=[output_created.name()]) innerpuz: Program = await self.inner_puzzle_for_cc_puzhash(coin.puzzle_hash) sigs = sigs + await self.get_sigs(innerpuz, innersol, coin.name()) lineage_proof = await self.get_lineage_proof_for_coin(coin) puzzle_reveal = cc_puzzle_for_inner_puzzle(CC_MOD, self.cc_info.my_genesis_checker, innerpuz) # Use coin info to create solution and add coin and solution to list of CoinSolutions solution = [ innersol, coin.as_list(), lineage_proof, None, None, None, None, None, ] full_solution = Program.to([puzzle_reveal, solution]) list_of_solutions.append(CoinSolution(coin, full_solution)) aggsig = AugSchemeMPL.aggregate(sigs) return SpendBundle(list_of_solutions, aggsig)
async def get_sigs(self, innerpuz: Program, innersol: Program, coin_name) -> List[G2Element]: puzzle_hash = innerpuz.get_tree_hash() pubkey, private = await self.wallet_state_manager.get_keys(puzzle_hash) synthetic_secret_key = calculate_synthetic_secret_key(private, DEFAULT_HIDDEN_PUZZLE_HASH) sigs: List[G2Element] = [] code_ = [innerpuz, innersol] sexp = Program.to(code_) error, conditions, cost = conditions_dict_for_solution(sexp) if conditions is not None: for _, msg in pkm_pairs_for_conditions_dict(conditions, coin_name): signature = AugSchemeMPL.sign(synthetic_secret_key, msg) sigs.append(signature) return sigs
def conditions_for_solution( solution_program, run_program=clvm.run_program ) -> Tuple[Optional[Err], Optional[List[ConditionVarPair]], uint64]: # get the standard script for a puzzle hash and feed in the solution args = Program.to(solution_program) try: puzzle_sexp = args.first() solution_sexp = args.rest().first() cost, r = run_program(puzzle_sexp, solution_sexp) error, result = parse_sexp_to_conditions(r) return error, result, cost except EvalError: return Err.SEXP_ERROR, None, uint64(0)
def lineage_proof_for_cc_parent( parent_coin: Coin, parent_inner_puzzle_hash: bytes32 ) -> Program: return Program.to( ( 1, [ parent_coin.parent_coin_info, parent_inner_puzzle_hash, parent_coin.amount, ], ) )
async def get_sigs(self, innerpuz: Program, innersol: Program) -> List[G2Element]: puzzle_hash = innerpuz.get_tree_hash() pubkey, private = await self.wallet_state_manager.get_keys(puzzle_hash) sigs: List[G2Element] = [] code_ = [innerpuz, innersol] sexp = Program.to(code_) error, conditions, cost = conditions_dict_for_solution(sexp) if conditions is not None: for _, msg in pkm_pairs_for_conditions_dict(conditions): signature = AugSchemeMPL.sign(private, msg) sigs.append(signature) return sigs
async def get_sigs_for_innerpuz_with_innersol( self, innerpuz: Program, innersol: Program) -> List[BLSSignature]: puzzle_hash = innerpuz.get_tree_hash() pubkey, private = await self.wallet_state_manager.get_keys(puzzle_hash) private = BLSPrivateKey(private) sigs: List[BLSSignature] = [] code_ = [innerpuz, innersol] sexp = Program.to(code_) error, conditions, cost = conditions_dict_for_solution(sexp) if conditions is not None: for _ in hash_key_pairs_for_conditions_dict(conditions): signature = private.sign(_.message_hash) sigs.append(signature) return sigs
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
async def generate_unsigned_transaction( self, amount: uint64, newpuzzlehash: bytes32, fee: uint64 = uint64(0), origin_id: bytes32 = None, coins: Set[Coin] = None, ) -> List[CoinSolution]: """ Generates a unsigned transaction in form of List(Puzzle, Solutions) """ if coins is None: coins = await self.select_coins(amount + fee) assert len(coins) > 0 self.log.info(f"coins is not None {coins}") spend_value = sum([coin.amount for coin in coins]) change = spend_value - amount - fee spends: List[CoinSolution] = [] output_created = False for coin in coins: self.log.info(f"coin from coins {coin}") puzzle: Program = await self.puzzle_for_puzzle_hash( coin.puzzle_hash) # Only one coin creates outputs if not output_created and origin_id in (None, coin.name()): primaries = [{"puzzlehash": newpuzzlehash, "amount": amount}] if change > 0: changepuzzlehash = await self.get_new_puzzlehash() primaries.append({ "puzzlehash": changepuzzlehash, "amount": change }) solution = self.make_solution(primaries=primaries, fee=fee) output_created = True else: solution = self.make_solution() puzzle_solution_pair = Program.to([puzzle, solution]) spends.append(CoinSolution(coin, puzzle_solution_pair)) self.log.info(f"Spends is {spends}") return spends
async def test_agg_sig_condition(self, two_nodes): num_blocks = 2 wallet_a = bt.get_pool_wallet_tool() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"") full_node_1, full_node_2, server_1, server_2 = two_nodes block = blocks[1] async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass unsigned: List[Tuple[ Program, CoinSolution]] = wallet_a.generate_unsigned_transaction( 1000, receiver_puzzlehash, block.get_coinbase(), {}, 0) assert len(unsigned) == 1 puzzle, solution = unsigned[0] code_ = [puzzle, solution.solution] sexp = Program.to(code_) err, con, cost = conditions_for_solution(sexp) assert con is not None conditions_dict = conditions_by_opcode(con) pkm_pairs = pkm_pairs_for_conditions_dict(conditions_dict, solution.coin.name()) assert len(pkm_pairs) == 1 assert pkm_pairs[0][1] == solution.solution.first().get_tree_hash() spend_bundle = wallet_a.sign_transaction(unsigned) assert spend_bundle is not None tx: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle) async for _ in full_node_1.respond_transaction(tx): outbound: OutboundMessage = _ # Maybe transaction means that it's accepted in mempool assert outbound.message.function == "new_transaction" sb = full_node_1.mempool_manager.get_spendbundle(spend_bundle.name()) assert sb is spend_bundle
async def rl_sign_transaction( self, spends: List[Tuple[Program, CoinSolution]]) -> SpendBundle: sigs = [] for puzzle, solution in spends: pubkey, secretkey = await self.get_keys(solution.coin.puzzle_hash) signature = AugSchemeMPL.sign( secretkey, Program(solution.solution).get_tree_hash()) sigs.append(signature) aggsig = AugSchemeMPL.aggregate(sigs) solution_list: List[CoinSolution] = [] for puzzle, coin_solution in spends: solution_list.append( CoinSolution(coin_solution.coin, Program.to([puzzle, coin_solution.solution]))) return SpendBundle(solution_list, aggsig)
async def coin_added(self, coin: Coin, height: int, header_hash: bytes32, removals: List[Coin]): """ Notification from wallet state manager that wallet has been received. """ self.log.info(f"CC wallet has been notified that {coin} was added") search_for_parent: bool = True inner_puzzle = await self.inner_puzzle_for_cc_puzhash(coin.puzzle_hash) lineage_proof = Program.to(( 1, [ coin.parent_coin_info, inner_puzzle.get_tree_hash(), coin.amount, ], )) await self.add_lineage(coin.name(), lineage_proof) for name, lineage_proofs in self.cc_info.lineage_proofs: if coin.parent_coin_info == name: search_for_parent = False break if search_for_parent: data: Dict[str, Any] = { "data": { "action_data": { "api_name": "request_generator", "height": height, "header_hash": header_hash, } } } data_str = dict_to_json_str(data) await self.wallet_state_manager.create_action( name="request_generator", wallet_id=self.wallet_info.id, type=self.wallet_info.type, callback="generator_received", done=False, data=data_str, )
async def create_spend_bundle_relative_chia( self, chia_amount: int, exclude: List[Coin]) -> Optional[SpendBundle]: list_of_solutions = [] utxos = None # If we're losing value then get coins with at least that much value # If we're gaining value then our amount doesn't matter if chia_amount < 0: utxos = await self.select_coins(abs(chia_amount), exclude) else: utxos = await self.select_coins(0, exclude) if utxos is None: return None # Calculate output amount given sum of utxos spend_value = sum([coin.amount for coin in utxos]) chia_amount = spend_value + chia_amount # Create coin solutions for each utxo output_created = None sigs: List[G2Element] = [] for coin in utxos: pubkey, secretkey = await self.wallet_state_manager.get_keys( coin.puzzle_hash) puzzle = self.puzzle_for_pk(bytes(pubkey)) if output_created is None: newpuzhash = await self.get_new_puzzlehash() primaries = [{"puzzlehash": newpuzhash, "amount": chia_amount}] solution = self.make_solution(primaries=primaries) output_created = coin else: solution = self.make_solution(consumed=[output_created.name()]) list_of_solutions.append( CoinSolution(coin, Program.to([puzzle, solution]))) new_sigs = await self.get_sigs_for_innerpuz_with_innersol( puzzle, solution) sigs = sigs + new_sigs aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
async def sign_clawback_transaction( self, spends: List[Tuple[Program, CoinSolution]], clawback_pubkey ): sigs = [] for puzzle, solution in spends: pubkey, secretkey = await self.get_keys_pk(clawback_pubkey) signature = secretkey.sign(Program(solution.solution).get_hash()) sigs.append(signature) aggsig = AugSchemeMPL.aggregate(sigs) solution_list = [] for puzzle, coin_solution in spends: solution_list.append( CoinSolution( coin_solution.coin, Program.to([puzzle, coin_solution.solution]) ) ) spend_bundle = SpendBundle(solution_list, aggsig) return spend_bundle
def make_solution( self, primaries=None, min_time=0, me=None, consumed=None, fee=None ): condition_list = [] if primaries: for primary in primaries: condition_list.append( make_create_coin_condition(primary["puzzlehash"], primary["amount"]) ) if consumed: for coin in consumed: condition_list.append(make_assert_coin_consumed_condition(coin)) if min_time > 0: condition_list.append(make_assert_time_exceeds_condition(min_time)) if me: condition_list.append(make_assert_my_coin_id_condition(me["id"])) if fee: condition_list.append(make_assert_fee_condition(fee)) return Program.to([puzzle_for_conditions(condition_list), []])
def rl_make_aggregation_puzzle(wallet_puzzle): """ If Wallet A wants to send further funds to Wallet B then they can lock them up using this code Solution will be (my_id wallet_coin_primary_input wallet_coin_amount) """ opcode_myid = hexlify(ConditionOpcode.ASSERT_MY_COIN_ID).decode("ascii") opcode_consumed = hexlify(ConditionOpcode.ASSERT_COIN_CONSUMED).decode("ascii") me_is_my_id = make_list(hexstr(opcode_myid), args(0)) # lock_puzzle is the hash of '(r (c (q "merge in ID") (q ())))' lock_puzzle = sha256tree( make_list( quote(7), make_list(quote(5), make_list(quote(1), args(0)), quote(quote(sexp()))), ) ) parent_coin_id = sha256(args(1), hexstr(wallet_puzzle), args(2)) input_of_lock = make_list(hexstr(opcode_consumed), sha256(parent_coin_id, lock_puzzle, quote(0))) puz = make_list(me_is_my_id, input_of_lock) return Program.to(binutils.assemble(puz))
def generate_unsigned_transaction( self, amount: uint64, newpuzzlehash: bytes32, coin: Coin, condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]], fee: int = 0, secretkey=None, ) -> List[CoinSolution]: spends = [] spend_value = coin.amount puzzle_hash = coin.puzzle_hash if secretkey is None: secretkey = self.get_private_key_for_puzzle_hash(puzzle_hash) pubkey = secretkey.get_g1() puzzle = puzzle_for_pk(bytes(pubkey)) if ConditionOpcode.CREATE_COIN not in condition_dic: condition_dic[ConditionOpcode.CREATE_COIN] = [] output = ConditionVarPair(ConditionOpcode.CREATE_COIN, newpuzzlehash, int_to_bytes(amount)) condition_dic[output.opcode].append(output) amount_total = sum( int_from_bytes(cvp.var2) for cvp in condition_dic[ConditionOpcode.CREATE_COIN]) change = spend_value - amount_total - fee if change > 0: changepuzzlehash = self.get_new_puzzlehash() change_output = ConditionVarPair(ConditionOpcode.CREATE_COIN, changepuzzlehash, int_to_bytes(change)) condition_dic[output.opcode].append(change_output) solution = self.make_solution(condition_dic) else: solution = self.make_solution(condition_dic) puzzle_solution_pair = Program.to([puzzle, solution]) spends.append(CoinSolution(coin, puzzle_solution_pair)) return spends
async def generate_new_coloured_coin(self, amount: uint64) -> SpendBundle: coins = await self.standard_wallet.select_coins(amount) origin = coins.copy().pop() origin_id = origin.name() cc_inner_hash = await self.get_new_inner_hash() await self.add_lineage(origin_id, Program.to((0, [origin.as_list(), 0]))) genesis_coin_checker = create_genesis_or_zero_coin_checker(origin_id) minted_cc_puzzle_hash = cc_puzzle_hash_for_inner_puzzle_hash(CC_MOD, genesis_coin_checker, cc_inner_hash) tx_record: TransactionRecord = await self.standard_wallet.generate_signed_transaction( amount, minted_cc_puzzle_hash, uint64(0), origin_id, coins ) assert tx_record.spend_bundle is not None lineage_proof: Optional[Program] = lineage_proof_for_genesis(origin) lineage_proofs = [(origin_id, lineage_proof)] cc_info: CCInfo = CCInfo(genesis_coin_checker, lineage_proofs) await self.save_info(cc_info) return tx_record.spend_bundle
def make_solution(self, condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]]) -> Program: ret = [] for con_list in condition_dic.values(): for cvp in con_list: if cvp.opcode == ConditionOpcode.CREATE_COIN: ret.append(make_create_coin_condition(cvp.vars[0], cvp.vars[1])) if cvp.opcode == ConditionOpcode.AGG_SIG: ret.append(make_assert_aggsig_condition(cvp.vars[0])) if cvp.opcode == ConditionOpcode.ASSERT_COIN_CONSUMED: ret.append(make_assert_coin_consumed_condition(cvp.vars[0])) if cvp.opcode == ConditionOpcode.ASSERT_TIME_EXCEEDS: ret.append(make_assert_time_exceeds_condition(cvp.vars[0])) if cvp.opcode == ConditionOpcode.ASSERT_MY_COIN_ID: ret.append(make_assert_my_coin_id_condition(cvp.vars[0])) if cvp.opcode == ConditionOpcode.ASSERT_BLOCK_INDEX_EXCEEDS: ret.append(make_assert_block_index_exceeds_condition(cvp.vars[0])) if cvp.opcode == ConditionOpcode.ASSERT_BLOCK_AGE_EXCEEDS: ret.append(make_assert_block_age_exceeds_condition(cvp.vars[0])) if cvp.opcode == ConditionOpcode.ASSERT_FEE: ret.append(make_assert_fee_condition(cvp.vars[0])) return solution_for_conditions(Program.to(ret))
async def create_spend_bundle_relative_chia( self, chia_amount: int, exclude: List[Coin] ) -> SpendBundle: list_of_solutions = [] utxos = None # If we're losing value then get coins with at least that much value # If we're gaining value then our amount doesn't matter if chia_amount < 0: utxos = await self.select_coins(abs(chia_amount), exclude) else: utxos = await self.select_coins(0, exclude) assert len(utxos) > 0 # Calculate output amount given sum of utxos spend_value = sum([coin.amount for coin in utxos]) chia_amount = spend_value + chia_amount # Create coin solutions for each utxo output_created = None for coin in utxos: puzzle = await self.puzzle_for_puzzle_hash(coin.puzzle_hash) if output_created is None: newpuzhash = await self.get_new_puzzlehash() primaries = [{"puzzlehash": newpuzhash, "amount": chia_amount}] solution = self.make_solution(primaries=primaries) output_created = coin else: solution = self.make_solution(consumed=[output_created.name()]) list_of_solutions.append(CoinSolution(coin, Program.to([puzzle, solution]))) await self.hack_populate_secret_keys_for_coin_solutions(list_of_solutions) spend_bundle = await sign_coin_solutions( list_of_solutions, self.secret_key_store.secret_key_for_public_key ) return spend_bundle
async def create_spend_bundle_relative_amount(self, cc_amount, zero_coin: Coin = None): # If we're losing value then get coloured coins with at least that much value # If we're gaining value then our amount doesn't matter if cc_amount < 0: cc_spends = await self.select_coins(abs(cc_amount)) else: if zero_coin is None: return None cc_spends = set() cc_spends.add(zero_coin) if cc_spends is None: return None # Calculate output amount given relative difference and sum of actual values spend_value = sum([coin.amount for coin in cc_spends]) cc_amount = spend_value + cc_amount # Loop through coins and create solution for innerpuzzle list_of_solutions = [] output_created = None sigs: List[G2Element] = [] for coin in cc_spends: if output_created is None: newinnerpuzhash = await self.get_new_inner_hash() innersol = self.standard_wallet.make_solution( primaries=[{ "puzzlehash": newinnerpuzhash, "amount": cc_amount }]) output_created = coin else: innersol = self.standard_wallet.make_solution() innerpuz: Program = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) parent_info = await self.get_parent_for_coin(coin) assert parent_info is not None assert self.cc_info.my_core is not None # Use coin info to create solution and add coin and solution to list of CoinSolutions solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), coin.amount, binutils.disassemble(innerpuz), binutils.disassemble(innersol), None, None, ) list_of_solutions.append( CoinSolution( coin, Program.to([ cc_wallet_puzzles.cc_make_puzzle( innerpuz.get_tree_hash(), self.cc_info.my_core), solution, ]), )) sigs = sigs + await self.get_sigs(innerpuz, innersol) aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
async def generate_signed_transaction( self, amount: uint64, to_address: bytes32, fee: uint64 = uint64(0), origin_id: bytes32 = None, coins: Set[Coin] = None, ) -> Optional[TransactionRecord]: sigs: List[G2Element] = [] # Get coins and calculate amount of change required if coins is None: selected_coins: Optional[Set[Coin]] = await self.select_coins( amount) else: selected_coins = coins if selected_coins is None: return None total_amount = sum([x.amount for x in selected_coins]) change = total_amount - amount # first coin becomes the auditor special case auditor = selected_coins.pop() puzzle_hash = auditor.puzzle_hash inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle( puzzle_hash) auditor_info = ( auditor.parent_coin_info, inner_puzzle.get_tree_hash(), auditor.amount, ) list_of_solutions = [] # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount) auditees = [( auditor.parent_coin_info, inner_puzzle.get_tree_hash(), auditor.amount, total_amount, )] for coin in selected_coins: coin_inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) auditees.append(( coin.parent_coin_info, coin_inner_puzzle[coin], coin.amount, 0, )) primaries = [{"puzzlehash": to_address, "amount": amount}] if change > 0: changepuzzlehash = await self.get_new_inner_hash() primaries.append({ "puzzlehash": changepuzzlehash, "amount": change }) innersol = self.standard_wallet.make_solution(primaries=primaries) sigs = sigs + await self.get_sigs(inner_puzzle, innersol) parent_info = await self.get_parent_for_coin(auditor) assert parent_info is not None assert self.cc_info.my_core is not None solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), auditor.amount, binutils.disassemble(inner_puzzle), binutils.disassemble(innersol), auditor_info, auditees, False, ) main_coin_solution = CoinSolution( auditor, Program.to([ cc_wallet_puzzles.cc_make_puzzle( inner_puzzle.get_tree_hash(), self.cc_info.my_core, ), solution, ]), ) list_of_solutions.append(main_coin_solution) # main = SpendBundle([main_coin_solution], ZERO96) ephemeral_coin_solution = create_spend_for_ephemeral( auditor, auditor, total_amount) list_of_solutions.append(ephemeral_coin_solution) # eph = SpendBundle([ephemeral_coin_solution], ZERO96) auditor_coin_colution = create_spend_for_auditor(auditor, auditor) list_of_solutions.append(auditor_coin_colution) # aud = SpendBundle([auditor_coin_colution], ZERO96) # loop through remaining spends, treating them as aggregatees for coin in selected_coins: coin_inner_puzzle = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) innersol = self.standard_wallet.make_solution() parent_info = await self.get_parent_for_coin(coin) assert parent_info is not None sigs = sigs + await self.get_sigs(coin_inner_puzzle, innersol) solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), coin.amount, binutils.disassemble(coin_inner_puzzle), binutils.disassemble(innersol), auditor_info, None, ) list_of_solutions.append( CoinSolution( coin, Program.to([ cc_wallet_puzzles.cc_make_puzzle( coin_inner_puzzle.get_tree_hash(), self.cc_info.my_core, ), solution, ]), )) list_of_solutions.append( create_spend_for_ephemeral(coin, auditor, 0)) list_of_solutions.append(create_spend_for_auditor(auditor, coin)) aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=to_address, amount=uint64(amount), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(0), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=self.wallet_info.id, sent_to=[], trade_id=None, ) return tx_record
def cc_make_puzzle(innerpuzhash, core): # Puzzle runs the core, but stores innerpuzhash commitment puzstring = f"(r (c (q 0x{innerpuzhash}) ((c (q {core}) (a)))))" result = Program.to(binutils.assemble(puzstring)) return result
def solution_for_contract(contract, puzzle_parameters, solution_parameters): cost, r = run_program( contract, Program.to((1, (puzzle_parameters, solution_parameters)))) return r
def puzzle_for_contract(contract, puzzle_parameters): env = Program.to([]).cons(Program.to(puzzle_parameters)) cost, r = run_program(contract, env) return Program.to(r)
def solution_for_delegated_puzzle(delegated_puzzle: Program, delegated_solution: Program) -> Program: return Program.to([delegated_puzzle, delegated_solution])
def solution_for_conditions(conditions) -> Program: delegated_puzzle = p2_conditions.puzzle_for_conditions(conditions) return solution_for_delegated_puzzle(delegated_puzzle, Program.to(0))
def test_spend_through_n(mod_code, coin_checker_for_farmed_coin, n): """ Test to spend ccs from a farmed coin to a cc genesis coin, then to N outputs, then joining back down to two outputs. """ ################################ # spend from a farmed coin to a cc genesis coin # get a farmed coin eve_inner_puzzle = ANYONE_CAN_SPEND_PUZZLE eve_inner_puzzle_hash = eve_inner_puzzle.get_tree_hash() # generate output values [0x100, 0x200, ...] output_values = [0x100 + 0x100 * _ for _ in range(n)] total_minted = sum(output_values) genesis_coin_checker, spend_bundle = issue_cc_from_farmed_coin( mod_code, coin_checker_for_farmed_coin, 1, eve_inner_puzzle_hash, total_minted) # hack the wrapped puzzles into the PUZZLE_TABLE DB 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) debug_spend_bundle(spend_bundle) ################################ # collect up the spendable coins spendable_cc_list = [] for coin_solution in spend_bundle.coin_solutions: spendable_cc_list.extend( spendable_cc_list_from_coin_solution(coin_solution, hash_to_puzzle_f)) # now spend the genesis coin cc to N outputs output_conditions = solution_for_pay_to_any([(eve_inner_puzzle_hash, _) for _ in output_values]) inner_puzzle_solution = Program.to(output_conditions) spend_bundle = spend_bundle_for_spendable_ccs( mod_code, genesis_coin_checker, spendable_cc_list, [inner_puzzle_solution], ) debug_spend_bundle(spend_bundle) ################################ # collect up the spendable coins spendable_cc_list = [] for coin_solution in spend_bundle.coin_solutions: spendable_cc_list.extend( spendable_cc_list_from_coin_solution(coin_solution, hash_to_puzzle_f)) # now spend N inputs to two outputs output_amounts = ([0] * (n - 2)) + [0x1, total_minted - 1] inner_solutions = [ solution_for_pay_to_any([(eve_inner_puzzle_hash, amount)] if amount else []) for amount in output_amounts ] spend_bundle = spend_bundle_for_spendable_ccs( mod_code, genesis_coin_checker, spendable_cc_list, inner_solutions, ) debug_spend_bundle(spend_bundle)