def get_new_puzzle(self) -> Program: 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 or self.rl_info.rl_origin_id is None): raise ValueError("One or more of the RL info fields is None") return rl_puzzle_for_pk( pubkey=self.rl_info.user_pubkey, rate_amount=self.rl_info.limit, interval_time=self.rl_info.interval, origin_id=self.rl_info.rl_origin_id, clawback_pk=self.rl_info.admin_pubkey, )
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_coin_solutions = [] 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, puzzle, solution) list_of_coin_solutions.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, puzzle, solution) list_of_coin_solutions.append(agg_spend) aggsig = AugSchemeMPL.aggregate([signature]) return SpendBundle(list_of_coin_solutions, aggsig)
def puzzle_for_pk(self, pk) -> Optional[Program]: if self.rl_info.initialized is False: return None 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 or self.rl_info.rl_origin_id is None): return None return rl_puzzle_for_pk( pubkey=self.rl_info.user_pubkey, rate_amount=self.rl_info.limit, interval_time=self.rl_info.interval, origin_id=self.rl_info.rl_origin_id, clawback_pk=self.rl_info.admin_pubkey, )
async def rl_generate_unsigned_transaction(self, to_puzzlehash, amount, fee) -> List[CoinSolution]: spends = [] assert self.rl_coin_record is not None 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") # these lines make mypy happy assert pubkey is not None assert self.rl_info.limit is not None assert self.rl_info.interval is not None assert self.rl_info.rl_origin_id is not None assert self.rl_info.admin_pubkey is not None 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(CoinSolution(coin, puzzle, solution)) return spends
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, puzzle, solution))) return spends
async def set_user_info( self, interval: uint64, limit: uint64, origin_parent_id: str, origin_puzzle_hash: str, origin_amount: uint64, admin_pubkey: str, ) -> None: admin_pubkey_bytes = hexstr_to_bytes(admin_pubkey) assert self.rl_info.user_pubkey is not None origin = Coin( hexstr_to_bytes(origin_parent_id), hexstr_to_bytes(origin_puzzle_hash), origin_amount, ) rl_puzzle = rl_puzzle_for_pk( pubkey=self.rl_info.user_pubkey, rate_amount=limit, interval_time=interval, origin_id=origin.name(), clawback_pk=admin_pubkey_bytes, ) rl_puzzle_hash = rl_puzzle.get_tree_hash() new_rl_info = RLInfo( "user", admin_pubkey_bytes, self.rl_info.user_pubkey, limit, interval, origin, origin.name(), rl_puzzle_hash, True, ) rl_puzzle_hash = rl_puzzle.get_tree_hash() if await self.wallet_state_manager.puzzle_store.puzzle_hash_exists( rl_puzzle_hash): raise ValueError( "Cannot create multiple Rate Limited wallets under the same keys. This will change in a future release." ) user_pubkey: G1Element = G1Element.from_bytes(self.rl_info.user_pubkey) index = await self.wallet_state_manager.puzzle_store.index_for_pubkey( user_pubkey) assert index is not None record = DerivationRecord( index, rl_puzzle_hash, user_pubkey, WalletType.RATE_LIMITED, self.id(), ) aggregation_puzzlehash = self.rl_get_aggregation_puzzlehash( new_rl_info.rl_puzzle_hash) record2 = DerivationRecord( index + 1, aggregation_puzzlehash, user_pubkey, WalletType.RATE_LIMITED, self.id(), ) await self.wallet_state_manager.puzzle_store.add_derivation_paths( [record, record2]) self.wallet_state_manager.set_coin_with_puzzlehash_created_callback( aggregation_puzzlehash, self.aggregate_this_coin) data_str = json.dumps(new_rl_info.to_json_dict()) new_wallet_info = WalletInfo(self.id(), self.wallet_info.name, self.type(), data_str) await self.wallet_state_manager.user_store.update_wallet( new_wallet_info, False) await self.wallet_state_manager.add_new_wallet(self, self.id()) self.wallet_info = new_wallet_info self.rl_info = new_rl_info
async def admin_create_coin( self, interval: uint64, limit: uint64, user_pubkey: str, amount: uint64, fee: uint64, ) -> bool: coins = await self.wallet_state_manager.main_wallet.select_coins(amount ) if coins is None: return False origin = coins.copy().pop() origin_id = origin.name() user_pubkey_bytes = hexstr_to_bytes(user_pubkey) assert self.rl_info.admin_pubkey is not None rl_puzzle = rl_puzzle_for_pk( pubkey=user_pubkey_bytes, rate_amount=limit, interval_time=interval, origin_id=origin_id, clawback_pk=self.rl_info.admin_pubkey, ) rl_puzzle_hash = rl_puzzle.get_tree_hash() index = await self.wallet_state_manager.puzzle_store.index_for_pubkey( G1Element.from_bytes(self.rl_info.admin_pubkey)) assert index is not None record = DerivationRecord( index, rl_puzzle_hash, G1Element.from_bytes(self.rl_info.admin_pubkey), WalletType.RATE_LIMITED, self.id(), ) await self.wallet_state_manager.puzzle_store.add_derivation_paths( [record]) spend_bundle = await self.main_wallet.generate_signed_transaction( amount, rl_puzzle_hash, fee, origin_id, coins) if spend_bundle is None: return False await self.main_wallet.push_transaction(spend_bundle) new_rl_info = RLInfo( "admin", self.rl_info.admin_pubkey, user_pubkey_bytes, limit, interval, origin, origin.name(), rl_puzzle_hash, True, ) data_str = json.dumps(new_rl_info.to_json_dict()) new_wallet_info = WalletInfo(self.id(), self.wallet_info.name, self.type(), data_str) await self.wallet_state_manager.user_store.update_wallet( new_wallet_info, False) await self.wallet_state_manager.add_new_wallet(self, self.id()) self.wallet_info = new_wallet_info self.rl_info = new_rl_info return True