async def coin_removed(self, coin: Coin, height: uint32, wallet_id: int): """ Called when coin gets spent """ await self.coin_store.set_spent(coin.name(), height) unconfirmed_record: List[ TransactionRecord] = await self.tx_store.unconfirmed_with_removal_coin( coin.name()) for unconfirmed in unconfirmed_record: await self.tx_store.set_confirmed(unconfirmed.name, height) self.state_changed("coin_removed", wallet_id)
async def get_unspent_coins_for_wallet( self, wallet_id: int) -> Set[WalletCoinRecord]: """ Returns set of CoinRecords that have not been spent yet for a wallet. """ async with self.wallet_cache_lock: if wallet_id in self.coin_wallet_record_cache: wallet_coins: Dict[ bytes32, WalletCoinRecord] = self.coin_wallet_record_cache[ wallet_id] return set(wallet_coins.values()) coin_set = set() cursor = await self.db_connection.execute( "SELECT * from coin_record WHERE spent=0 and wallet_id=?", (wallet_id, ), ) rows = await cursor.fetchall() await cursor.close() cache_dict = {} for row in rows: coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), uint64.from_bytes(row[7])) coin_record = WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]) coin_set.add(coin_record) cache_dict[coin.name()] = coin_record self.coin_wallet_record_cache[wallet_id] = cache_dict return coin_set
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, puzzle_reveal, Program.to(0)) return coin_solution
async def check_all_there(): spendable = await cc_wallet.get_cc_spendable_coins() spendable_name_set = set() for record in spendable: spendable_name_set.add(record.coin.name()) puzzle_hash = cc_puzzle_hash_for_inner_puzzle_hash(CC_MOD, cc_wallet.cc_info.my_genesis_checker, cc_2_hash) for i in range(1, 50): coin = Coin(spent_coint.name(), puzzle_hash, i) if coin.name() not in spendable_name_set: return False return True
async def coin_added(self, coin: Coin, header_hash: bytes32, removals: List[Coin], height: uint32): """ 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_puzzle_solution", "height": height, "coin_name": coin.parent_coin_info, "received_coin": coin.name(), } } } data_str = dict_to_json_str(data) await self.wallet_state_manager.create_action( name="request_puzzle_solution", wallet_id=self.id(), wallet_type=self.type(), callback="puzzle_solution_received", done=False, data=data_str, )
async def coin_added( self, coin: Coin, coinbase: bool, fee_reward: bool, wallet_id: uint32, wallet_type: WalletType, height: uint32, ): """ Adding coin to DB """ self.log.info(f"Adding coin: {coin} at {height}") farm_reward = False if coinbase or fee_reward: farm_reward = True now = uint64(int(time.time())) if coinbase: tx_type: int = TransactionType.COINBASE_REWARD.value else: tx_type = TransactionType.FEE_REWARD.value tx_record = TransactionRecord( confirmed_at_height=uint32(height), created_at_time=now, to_puzzle_hash=coin.puzzle_hash, amount=coin.amount, fee_amount=uint64(0), confirmed=True, sent=uint32(0), spend_bundle=None, additions=[coin], removals=[], wallet_id=wallet_id, sent_to=[], trade_id=None, type=uint32(tx_type), name=coin.name(), ) await self.tx_store.add_transaction_record(tx_record) else: records = await self.tx_store.tx_with_addition_coin(coin.name(), wallet_id) if len(records) > 0: # This is the change from this transaction for record in records: if record.confirmed is False: await self.tx_store.set_confirmed(record.name, height) else: now = uint64(int(time.time())) tx_record = TransactionRecord( confirmed_at_height=uint32(height), created_at_time=now, to_puzzle_hash=coin.puzzle_hash, amount=coin.amount, fee_amount=uint64(0), confirmed=True, sent=uint32(0), spend_bundle=None, additions=[coin], removals=[], wallet_id=wallet_id, sent_to=[], trade_id=None, type=uint32(TransactionType.INCOMING_TX.value), name=coin.name(), ) if coin.amount > 0: await self.tx_store.add_transaction_record(tx_record) coin_record: WalletCoinRecord = WalletCoinRecord( coin, height, uint32(0), False, farm_reward, wallet_type, wallet_id ) await self.coin_store.add_coin_record(coin_record) if wallet_type == WalletType.COLOURED_COIN: wallet: CCWallet = self.wallets[wallet_id] header_hash: bytes32 = self.blockchain.height_to_hash(height) block: Optional[HeaderBlockRecord] = await self.block_store.get_header_block_record(header_hash) assert block is not None assert block.removals is not None await wallet.coin_added(coin, header_hash, block.removals, height) self.state_changed("coin_added", wallet_id)
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." ) index = await self.wallet_state_manager.puzzle_store.index_for_pubkey( G1Element.from_bytes(self.rl_info.user_pubkey) ) assert index is not None record = DerivationRecord( index, rl_puzzle_hash, self.rl_info.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, self.rl_info.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) await self.wallet_state_manager.add_new_wallet(self, self.id()) self.wallet_info = new_wallet_info self.rl_info = new_rl_info
def _add_coin_entry(self, coin: Coin, birthday: CoinTimestamp) -> None: name = coin.name() assert name not in self._db self._db[name] = CoinRecord(coin, uint32(birthday.height), uint32(0), False, False, uint64(birthday.seconds)) self._ph_index[coin.puzzle_hash].append(name)
async def generate_zero_val_coin(self, send=True, exclude: List[Coin] = None ) -> SpendBundle: if self.cc_info.my_genesis_checker is None: raise ValueError("My genesis checker is None") if exclude is None: exclude = [] coins = await self.standard_wallet.select_coins(0, exclude) assert coins != set() origin = coins.copy().pop() origin_id = origin.name() cc_inner = await self.get_new_inner_hash() cc_puzzle_hash: Program = cc_puzzle_hash_for_inner_puzzle_hash( CC_MOD, self.cc_info.my_genesis_checker, cc_inner) tx: TransactionRecord = await self.standard_wallet.generate_signed_transaction( uint64(0), cc_puzzle_hash, uint64(0), origin_id, coins) assert tx.spend_bundle is not None full_spend: SpendBundle = tx.spend_bundle self.log.info( f"Generate zero val coin: cc_puzzle_hash is {cc_puzzle_hash}") # generate eve coin so we can add future lineage_proofs even if we don't eve spend eve_coin = Coin(origin_id, cc_puzzle_hash, uint64(0)) await self.add_lineage( eve_coin.name(), Program.to(( 1, [eve_coin.parent_coin_info, cc_inner, eve_coin.amount], )), ) await self.add_lineage(eve_coin.parent_coin_info, Program.to((0, [origin.as_list(), 1]))) if send: regular_record = TransactionRecord( confirmed_at_height=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=cc_puzzle_hash, amount=uint64(0), fee_amount=uint64(0), confirmed=False, sent=uint32(10), spend_bundle=full_spend, additions=full_spend.additions(), removals=full_spend.removals(), wallet_id=uint32(1), sent_to=[], trade_id=None, type=uint32(TransactionType.INCOMING_TX.value), name=token_bytes(), ) cc_record = TransactionRecord( confirmed_at_height=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=cc_puzzle_hash, amount=uint64(0), fee_amount=uint64(0), confirmed=False, sent=uint32(0), spend_bundle=full_spend, additions=full_spend.additions(), removals=full_spend.removals(), wallet_id=self.id(), sent_to=[], trade_id=None, type=uint32(TransactionType.INCOMING_TX.value), name=full_spend.name(), ) await self.wallet_state_manager.add_transaction(regular_record) await self.wallet_state_manager.add_pending_transaction(cc_record) return full_spend
def coin_checker_for_farmed_coin_by_coin_id(coin: Coin): return create_genesis_or_zero_coin_checker(coin.name())