async def main(): rpc_port = 8555 self_hostname = "localhost" path = DEFAULT_ROOT_PATH config = load_config(path, "config.yaml") client = await FullNodeRpcClient.create(self_hostname, rpc_port, path, config) try: farmer_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[1] pool_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[0] pool_amounts = int(calculate_pool_reward(uint32(0)) / 2) farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2) print(farmer_prefarm.amount, farmer_amounts) assert farmer_amounts == farmer_prefarm.amount // 2 assert pool_amounts == pool_prefarm.amount // 2 address1 = "txch15gx26ndmacfaqlq8m0yajeggzceu7cvmaz4df0hahkukes695rss6lej7h" # Gene wallet (m/12381/8444/2/42): address2 = ( "txch1c2cguswhvmdyz9hr3q6hak2h6p9dw4rz82g4707k2xy2sarv705qcce4pn" # Mariano address (m/12381/8444/2/0) ) ph1 = decode_puzzle_hash(address1) ph2 = decode_puzzle_hash(address2) p_farmer_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {farmer_amounts}) (51 0x{ph2.hex()} {farmer_amounts})))" )) p_pool_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {pool_amounts}) (51 0x{ph2.hex()} {pool_amounts})))" )) p_solution = Program.to(binutils.assemble("()")) sb_farmer = SpendBundle( [CoinSolution(farmer_prefarm, p_farmer_2, p_solution)], G2Element()) sb_pool = SpendBundle( [CoinSolution(pool_prefarm, p_pool_2, p_solution)], G2Element()) print(sb_pool, sb_farmer) # res = await client.push_tx(sb_farmer) res = await client.push_tx(sb_pool) print(res) up = await client.get_coin_records_by_puzzle_hash( farmer_prefarm.puzzle_hash, True) uf = await client.get_coin_records_by_puzzle_hash( pool_prefarm.puzzle_hash, True) print(up) print(uf) finally: client.close()
async def main(): rpc_port = 8555 self_hostname = "localhost" path = DEFAULT_ROOT_PATH config = load_config(path, "config.yaml") client = await FullNodeRpcClient.create(self_hostname, rpc_port, path, config) try: farmer_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[1] pool_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[0] pool_amounts = int(calculate_pool_reward(uint32(0)) / 2) farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2) print(farmer_prefarm.amount, farmer_amounts) assert farmer_amounts == farmer_prefarm.amount // 2 assert pool_amounts == pool_prefarm.amount // 2 address1 = "txch1k50glwkdffp2mrqq64rsgjtxj4waphuf72stqayz4qqk6mj9hd4qp7lrek" # Gene wallet (m/12381/8444/2/51): address2 = "txch1430mtj60hvzyuyz4t45dyxwjdjsvphhl2fgreyry362reca4zpkszhjd3e" # farmer1 key (m/12381/8444/2/51) ph1 = decode_puzzle_hash(address1) ph2 = decode_puzzle_hash(address2) p_farmer_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {farmer_amounts}) (51 0x{ph2.hex()} {farmer_amounts})))" )) p_pool_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {pool_amounts}) (51 0x{ph2.hex()} {pool_amounts})))" )) p_solution = Program.to(binutils.assemble("()")) sb_farmer = SpendBundle( [CoinSolution(farmer_prefarm, p_farmer_2, p_solution)], G2Element()) sb_pool = SpendBundle( [CoinSolution(pool_prefarm, p_pool_2, p_solution)], G2Element()) print(sb_pool, sb_farmer) # res = await client.push_tx(sb_farmer) # res = await client.push_tx(sb_pool) # print(res) up = await client.get_coin_records_by_puzzle_hash( farmer_prefarm.puzzle_hash, True) uf = await client.get_coin_records_by_puzzle_hash( pool_prefarm.puzzle_hash, True) print(up) print(uf) finally: client.close()
async def rl_generate_signed_aggregation_transaction( self, rl_info, consolidating_coin, rl_parent, rl_coin): if (rl_info.limit is None or rl_info.interval is None or rl_info.user_pubkey is None or rl_info.admin_pubkey is None): raise ValueError("One or more of the elements of rl_info is None") if self.rl_coin_record is None: raise ValueError("Rl coin record is None") list_of_coinsolutions = [] self.rl_coin_record = await self._get_rl_coin_record() pubkey, secretkey = await self.get_keys( self.rl_coin_record.coin.puzzle_hash) # Spend wallet coin puzzle = rl_puzzle_for_pk( rl_info.user_pubkey, rl_info.limit, rl_info.interval, rl_info.rl_origin_id, rl_info.admin_pubkey, ) solution = rl_make_solution_mode_2( rl_coin.puzzle_hash, consolidating_coin.parent_coin_info, consolidating_coin.puzzle_hash, consolidating_coin.amount, rl_coin.parent_coin_info, rl_coin.amount, rl_parent.amount, rl_parent.parent_coin_info, ) signature = AugSchemeMPL.sign(secretkey, solution.get_tree_hash()) rl_spend = CoinSolution(self.rl_coin_record.coin, Program.to([puzzle, solution])) list_of_coinsolutions.append(rl_spend) # Spend consolidating coin puzzle = rl_make_aggregation_puzzle( self.rl_coin_record.coin.puzzle_hash) solution = rl_make_aggregation_solution( consolidating_coin.name(), self.rl_coin_record.coin.parent_coin_info, self.rl_coin_record.coin.amount, ) agg_spend = CoinSolution(consolidating_coin, Program.to([puzzle, solution])) list_of_coinsolutions.append(agg_spend) aggsig = AugSchemeMPL.aggregate([signature]) return SpendBundle(list_of_coinsolutions, aggsig)
def create_spend_for_ephemeral(parent_of_e, auditor_coin, spend_amount): puzstring = f"(r (r (c (q 0x{auditor_coin.name()}) (c (q {spend_amount}) (q ())))))" puzzle = Program(binutils.assemble(puzstring)) coin = Coin(parent_of_e.name(), puzzle.get_tree_hash(), uint64(0)) solution = Program(binutils.assemble("()")) coinsol = CoinSolution(coin, Program.to([puzzle, solution])) return coinsol
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)
def generate_unsigned_clawback_transaction( self, clawback_coin: Coin, clawback_puzzle_hash: bytes32, fee ): if ( self.rl_info.limit is None or self.rl_info.interval is None or self.rl_info.user_pubkey is None or self.rl_info.admin_pubkey is None ): raise ValueError("One ore more of the elements of rl_info is None") spends = [] coin = clawback_coin if self.rl_info.rl_origin is None: raise ValueError("Origin not initialized") puzzle = rl_puzzle_for_pk( self.rl_info.user_pubkey, self.rl_info.limit, self.rl_info.interval, self.rl_info.rl_origin.name(), self.rl_info.admin_pubkey, ) solution = make_clawback_solution( clawback_puzzle_hash, clawback_coin.amount, fee ) spends.append((puzzle, CoinSolution(coin, solution))) return spends
async def rl_generate_unsigned_transaction(self, to_puzzlehash, amount): spends = [] coin = self.rl_coin_record.coin puzzle_hash = coin.puzzle_hash pubkey, secretkey = await self.get_keys(puzzle_hash) rl_parent: Coin = await self.get_rl_parent() puzzle = rl_puzzle_for_pk( bytes(pubkey), self.rl_info.interval, self.rl_info.limit, self.rl_info.rl_origin.name(), self.rl_info.rl_clawback_pk, ) solution = solution_for_rl( coin.parent_coin_info, puzzle_hash, coin.amount, to_puzzlehash, amount, rl_parent.parent_coin_info, rl_parent.amount, None, None, ) spends.append((puzzle, CoinSolution(coin, solution))) return spends
async def rl_generate_unsigned_transaction(self, to_puzzlehash, amount, fee): spends = [] coin = self.rl_coin_record.coin puzzle_hash = coin.puzzle_hash pubkey = self.rl_info.user_pubkey rl_parent: Optional[Coin] = await self._get_rl_parent() if rl_parent is None: raise ValueError("No RL parent coin") puzzle = rl_puzzle_for_pk( bytes(pubkey), self.rl_info.limit, self.rl_info.interval, self.rl_info.rl_origin_id, self.rl_info.admin_pubkey, ) solution = solution_for_rl( coin.parent_coin_info, puzzle_hash, coin.amount, to_puzzlehash, amount, rl_parent.parent_coin_info, rl_parent.amount, self.rl_info.interval, self.rl_info.limit, fee, ) spends.append((puzzle, CoinSolution(coin, solution))) return spends
async def generate_unsigned_transaction( self, amount: uint64, newpuzzlehash: bytes32, fee: uint64 = uint64(0), origin_id: bytes32 = None, coins: Set[Coin] = None, primaries: Optional[List[Dict[str, bytes32]]] = None, ignore_max_send_amount: bool = False, ) -> List[CoinSolution]: """ Generates a unsigned transaction in form of List(Puzzle, Solutions) """ if primaries is None: total_amount = amount + fee else: primaries_amount = 0 for prim in primaries: primaries_amount += prim["amount"] total_amount = amount + fee + primaries_amount if not ignore_max_send_amount: max_send = await self.get_max_send_amount() if total_amount > max_send: raise ValueError(f"Can't send more than {max_send} in a single transaction") if coins is None: coins = await self.select_coins(total_amount) 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 - total_amount 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()): if primaries is None: primaries = [{"puzzlehash": newpuzzlehash, "amount": amount}] else: primaries.append({"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
def sign_transaction(self, spends: List[Tuple[Program, CoinSolution]]): sigs = [] solution: Program puzzle: Program for puzzle, solution in spends: # type: ignore # noqa pubkey, secretkey = self.get_keys(solution.coin.puzzle_hash) code_ = [puzzle, solution.solution] sexp = Program.to(code_) err, con, cost = conditions_for_solution(sexp) if not con: return conditions_dict = conditions_by_opcode(con) for _, msg in pkm_pairs_for_conditions_dict( conditions_dict, bytes(solution.coin)): signature = AugSchemeMPL.sign(secretkey, msg) sigs.append(signature) aggsig = AugSchemeMPL.aggregate(sigs) solution_list: List[CoinSolution] = [ CoinSolution(coin_solution.coin, Program.to([puzzle, coin_solution.solution])) for (puzzle, coin_solution) in spends ] spend_bundle = SpendBundle(solution_list, aggsig) return spend_bundle
def create_spend_for_auditor(parent_of_a, auditee): puzstring = f"(r (c (q 0x{auditee.name()}) (q ())))" puzzle = Program(binutils.assemble(puzstring)) coin = Coin(parent_of_a.name(), puzzle.get_tree_hash(), uint64(0)) solution = Program(binutils.assemble("()")) coinsol = CoinSolution(coin, Program.to([puzzle, solution])) return coinsol
def generate_unsigned_transaction( self, amount: uint64, new_puzzle_hash: bytes32, coin: Coin, condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]], fee: int = 0, secret_key=None, ) -> List[CoinSolution]: spends = [] spend_value = coin.amount puzzle_hash = coin.puzzle_hash if secret_key is None: secret_key = self.get_private_key_for_puzzle_hash(puzzle_hash) pubkey = secret_key.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, [new_puzzle_hash, int_to_bytes(amount)]) condition_dic[output.opcode].append(output) amount_total = sum(int_from_bytes(cvp.vars[1]) for cvp in condition_dic[ConditionOpcode.CREATE_COIN]) change = spend_value - amount_total - fee if change > 0: change_puzzle_hash = self.get_new_puzzlehash() change_output = ConditionVarPair(ConditionOpcode.CREATE_COIN, [change_puzzle_hash, 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
def sign_transaction(self, spends: List[Tuple[Program, CoinSolution]]): sigs = [] solution: Program puzzle: Program for puzzle, solution in spends: # type: ignore # noqa pubkey, secretkey = self.get_keys(solution.coin.puzzle_hash) secretkey = BLSPrivateKey(secretkey) code_ = [puzzle, solution.solution] sexp = Program.to(code_) err, con, cost = conditions_for_solution(sexp) if not con: return conditions_dict = conditions_by_opcode(con) for _ in hash_key_pairs_for_conditions_dict( conditions_dict, bytes(solution.coin)): signature = secretkey.sign(_.message_hash) sigs.append(signature) aggsig = BLSSignature.aggregate(sigs) solution_list: List[CoinSolution] = [ CoinSolution(coin_solution.coin, clvm.to_sexp_f([puzzle, coin_solution.solution])) for (puzzle, coin_solution) in spends ] spend_bundle = SpendBundle(solution_list, aggsig) return spend_bundle
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 list_of_solutions.append(CoinSolution(coin, 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
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, clvm.to_sexp_f([full_puzzle, solution]), ) ] aggsig = BLSSignature.aggregate([]) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
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
async def sign_clawback_transaction( self, spends: List[Tuple[Program, CoinSolution]], clawback_pubkey ) -> SpendBundle: sigs = [] for puzzle, solution in spends: pubkey, secretkey = await self.get_keys_pk(clawback_pubkey) signature = AugSchemeMPL.sign(secretkey, Program.to(solution.solution).get_tree_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]))) return SpendBundle(solution_list, aggsig)
def make_block_generator(count: int) -> SerializedProgram: puzzle_hash_db: Dict = dict() coins = [make_fake_coin(_, puzzle_hash_db) for _ in range(count)] coin_solutions = [] for coin in coins: puzzle_reveal = puzzle_hash_db[coin.puzzle_hash] conditions = conditions_for_payment(coin) solution = solution_for_conditions(conditions) coin_solution = CoinSolution(coin, puzzle_reveal, solution) coin_solutions.append(coin_solution) spend_bundle = SpendBundle(coin_solutions, blspy.G2Element()) return best_solution_program(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 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 = BLSSignature.aggregate(sigs) solution_list = [] for puzzle, coin_solution in spends: solution_list.append( CoinSolution(coin_solution.coin, clvm.to_sexp_f([puzzle, coin_solution.solution]))) spend_bundle = SpendBundle(solution_list, aggsig) return spend_bundle
async def sign_transaction( self, spends: List[Tuple[Program, CoinSolution]] ) -> Optional[SpendBundle]: signatures = [] for puzzle, solution in spends: # Get keys keys = await self.wallet_state_manager.get_keys(solution.coin.puzzle_hash) if not keys: self.log.error( f"Sign transaction failed, No Keys for puzzlehash {solution.coin.puzzle_hash}" ) return None pubkey, secretkey = keys secretkey = BLSPrivateKey(secretkey) code_ = [puzzle, solution.solution] sexp = clvm.to_sexp_f(code_) # Get AGGSIG conditions err, con, cost = conditions_for_solution(sexp) if err or not con: self.log.error(f"Sign transcation failed, con:{con}, error: {err}") return None conditions_dict = conditions_by_opcode(con) # Create signature for pk_message in hash_key_pairs_for_conditions_dict( conditions_dict, bytes(solution.coin) ): signature = secretkey.sign(pk_message.message_hash) signatures.append(signature) # Aggregate signatures aggsig = BLSSignature.aggregate(signatures) solution_list: List[CoinSolution] = [ CoinSolution( coin_solution.coin, clvm.to_sexp_f([puzzle, coin_solution.solution]) ) for (puzzle, coin_solution) in spends ] spend_bundle = SpendBundle(solution_list, aggsig) return spend_bundle
async def create_spend_bundle_relative_chia( self, chia_amount: int, exclude: List[Coin] ): 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[BLSSignature] = [] 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, clvm.to_sexp_f([puzzle, solution])) ) new_sigs = await self.get_sigs_for_innerpuz_with_innersol(puzzle, solution) sigs = sigs + new_sigs aggsig = BLSSignature.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) return spend_bundle
def do_test_spend( puzzle_reveal: Program, solution: Program, payments: Iterable[Tuple[bytes32, int]], key_lookup: KeyTool, farm_time: CoinTimestamp = T1, spend_time: CoinTimestamp = T2, ) -> SpendBundle: """ This method will farm a coin paid to the hash of `puzzle_reveal`, then try to spend it with `solution`, and verify that the created coins correspond to `payments`. The `key_lookup` is used to create a signed version of the `SpendBundle`, although at this time, signatures are not verified. """ coin_db = CoinStore() puzzle_hash = puzzle_reveal.get_tree_hash() # farm it coin = coin_db.farm_coin(puzzle_hash, farm_time) # spend it coin_solution = CoinSolution(coin, puzzle_reveal, solution) spend_bundle = SpendBundle([coin_solution], G2Element()) coin_db.update_coin_store_for_spend_bundle(spend_bundle, spend_time) # ensure all outputs are there for puzzle_hash, amount in payments: for coin in coin_db.coins_for_puzzle_hash(puzzle_hash): if coin.amount == amount: break else: assert 0 # make sure we can actually sign the solution signatures = [] for coin_solution in spend_bundle.coin_solutions: signature = key_lookup.signature_for_solution(coin_solution) signatures.append(signature) return SpendBundle(spend_bundle.coin_solutions, AugSchemeMPL.aggregate(signatures))
async def rl_sign_transaction(self, spends: List[Tuple[Program, CoinSolution]]): sigs = [] for puzzle, solution in spends: pubkey, secretkey = await self.get_keys(solution.coin.puzzle_hash) signature = secretkey.sign(Program(solution.solution).get_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]) ) ) spend_bundle = SpendBundle(solution_list, aggsig) return spend_bundle
def generate_unsigned_clawback_transaction(self, clawback_coin: Coin, clawback_puzzle_hash: bytes32): if (self.rl_info.limit is None or self.rl_info.interval is None or self.rl_info.user_pubkey is None or self.rl_info.admin_pubkey is None): raise spends = [] coin = clawback_coin puzzle = rl_puzzle_for_pk( self.rl_info.user_pubkey, self.rl_info.limit, self.rl_info.interval, self.rl_info.rl_origin, self.rl_info.admin_pubkey, ) solution = make_clawback_solution(clawback_puzzle_hash, clawback_coin.amount) spends.append((puzzle, CoinSolution(coin, solution))) return spends
def generate_unsigned_transaction( self, amount, newpuzzlehash, coin: Coin, condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]], fee: int = 0, secretkey=None, ): spends = [] spend_value = coin.amount puzzle_hash = coin.puzzle_hash if secretkey is None: pubkey, secretkey = self.get_keys(puzzle_hash) else: 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) spends.append((puzzle, CoinSolution(coin, solution))) return spends
def build_spend_bundle(coin, solution, keychain=DEFAULT_KEYTOOL): coin_solution = CoinSolution(coin, solution) signature = keychain.signature_for_solution(solution, bytes(coin)) return SpendBundle([coin_solution], signature)
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
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 rl_generate_signed_aggregation_transaction( self, rl_info: RLInfo, consolidating_coin: Coin, rl_parent: Coin, rl_coin: Coin ): if ( rl_info.limit is None or rl_info.interval is None or rl_info.limit is None or rl_info.interval is None or rl_info.user_pubkey is None or rl_info.admin_pubkey is None ): raise Exception("One ore more of the elements of rl_info is None") list_of_coinsolutions = [] pubkey, secretkey = await self.get_keys(self.rl_coin_record.coin.puzzle_hash) # Spend wallet coin puzzle = rl_puzzle_for_pk( rl_info.user_pubkey, rl_info.limit, rl_info.interval, rl_info.rl_origin, rl_info.admin_pubkey, ) solution = rl_make_solution_mode_2( rl_coin.puzzle_hash, consolidating_coin.parent_coin_info, consolidating_coin.puzzle_hash, consolidating_coin.amount, rl_coin.parent_coin_info, rl_coin.amount, rl_parent.amount, rl_parent.parent_coin_info, ) signature = secretkey.sign(solution.get_hash()) list_of_coinsolutions.append( CoinSolution(self.rl_coin_record.coin, Program.to([puzzle, solution])) ) # Spend consolidating coin puzzle = rl_make_aggregation_puzzle(self.rl_coin_record.coin.puzzle_hash) solution = rl_make_aggregation_solution( consolidating_coin.name(), self.rl_coin_record.coin.parent_coin_info, self.rl_coin_record.coin.amount, ) list_of_coinsolutions.append( CoinSolution(consolidating_coin, Program.to([puzzle, solution])) ) # Spend lock puzstring = ( "(r (c (q 0x" + hexlify(consolidating_coin.name()).decode("ascii") + ") (q ())))" ) puzzle = Program(binutils.assemble(puzstring)) solution = Program(binutils.assemble("()")) list_of_coinsolutions.append( CoinSolution( Coin(self.rl_coin_record.coin, puzzle.get_hash(), uint64(0)), Program.to([puzzle, solution]), ) ) aggsig = AugSchemeMPL.aggregate([signature]) return SpendBundle(list_of_coinsolutions, aggsig)