Exemplo n.º 1
0
    async def create_wallet_for_cat(wallet_state_manager: Any,
                                    wallet: Wallet,
                                    limitations_program_hash_hex: str,
                                    name="CAT WALLET") -> CATWallet:
        self = CATWallet()
        self.cost_of_single_tx = None
        self.standard_wallet = wallet
        self.log = logging.getLogger(__name__)

        for id, wallet in wallet_state_manager.wallets.items():
            if wallet.type() == CATWallet.type():
                if wallet.get_asset_id(
                ) == limitations_program_hash_hex:  # type: ignore
                    self.log.warning(
                        "Not creating wallet for already existing CAT wallet")
                    raise ValueError("Wallet already exists")

        self.wallet_state_manager = wallet_state_manager
        if limitations_program_hash_hex in DEFAULT_CATS:
            cat_info = DEFAULT_CATS[limitations_program_hash_hex]
            name = cat_info["name"]

        limitations_program_hash = bytes32(
            hexstr_to_bytes(limitations_program_hash_hex))
        self.cat_info = CATInfo(limitations_program_hash, None, [])
        info_as_string = bytes(self.cat_info).hex()
        self.wallet_info = await wallet_state_manager.user_store.create_wallet(
            name, WalletType.CAT, info_as_string)
        if self.wallet_info is None:
            raise Exception("wallet_info is None")

        await self.wallet_state_manager.add_new_wallet(self, self.id())
        return self
Exemplo n.º 2
0
 async def remove_lineage(self, name: bytes32, in_transaction=False):
     self.log.info(
         f"Removing parent {name} (probably had a non-CAT parent)")
     current_list = self.cat_info.lineage_proofs.copy()
     current_list = list(filter(lambda tup: tup[0] != name, current_list))
     cat_info: CATInfo = CATInfo(self.cat_info.limitations_program_hash,
                                 self.cat_info.my_tail, current_list)
     await self.save_info(cat_info, in_transaction)
Exemplo n.º 3
0
 async def set_tail_program(self, tail_program: str):
     assert Program.fromhex(tail_program).get_tree_hash(
     ) == self.cat_info.limitations_program_hash
     await self.save_info(
         CATInfo(self.cat_info.limitations_program_hash,
                 Program.fromhex(tail_program),
                 self.cat_info.lineage_proofs),
         False,
     )
Exemplo n.º 4
0
    async def generate_issuance_bundle(
            cls, wallet, _: Dict,
            amount: uint64) -> Tuple[TransactionRecord, SpendBundle]:
        coins = await wallet.standard_wallet.select_coins(amount)

        origin = coins.copy().pop()
        origin_id = origin.name()

        cc_inner: Program = await wallet.get_new_inner_puzzle()
        await wallet.add_lineage(origin_id, LineageProof())
        genesis_coin_checker: Program = cls.construct([Program.to(origin_id)])

        minted_cc_puzzle_hash: bytes32 = construct_cat_puzzle(
            CAT_MOD, genesis_coin_checker.get_tree_hash(),
            cc_inner).get_tree_hash()

        tx_record: TransactionRecord = await wallet.standard_wallet.generate_signed_transaction(
            amount, minted_cc_puzzle_hash, uint64(0), origin_id, coins)
        assert tx_record.spend_bundle is not None

        inner_solution = wallet.standard_wallet.add_condition_to_solution(
            Program.to([51, 0, -113, genesis_coin_checker, []]),
            wallet.standard_wallet.make_solution(primaries=[{
                "puzzlehash":
                cc_inner.get_tree_hash(),
                "amount":
                amount
            }], ),
        )
        eve_spend = unsigned_spend_bundle_for_spendable_cats(
            CAT_MOD,
            [
                SpendableCAT(
                    list(
                        filter(lambda a: a.amount == amount,
                               tx_record.additions))[0],
                    genesis_coin_checker.get_tree_hash(),
                    cc_inner,
                    inner_solution,
                    limitations_program_reveal=genesis_coin_checker,
                )
            ],
        )
        signed_eve_spend = await wallet.sign(eve_spend)

        if wallet.cat_info.my_tail is None:
            await wallet.save_info(
                CATInfo(genesis_coin_checker.get_tree_hash(),
                        genesis_coin_checker, wallet.cat_info.lineage_proofs),
                False,
            )

        return tx_record, SpendBundle.aggregate(
            [tx_record.spend_bundle, signed_eve_spend])
Exemplo n.º 5
0
 async def add_lineage(self,
                       name: bytes32,
                       lineage: Optional[LineageProof],
                       in_transaction=False):
     """
     Lineage proofs are stored as a list of parent coins and the lineage proof you will need if they are the
     parent of the coin you are trying to spend. 'If I'm your parent, here's the info you need to spend yourself'
     """
     self.log.info(f"Adding parent {name}: {lineage}")
     current_list = self.cat_info.lineage_proofs.copy()
     if (name, lineage) not in current_list:
         current_list.append((name, lineage))
     cat_info: CATInfo = CATInfo(self.cat_info.limitations_program_hash,
                                 self.cat_info.my_tail, current_list)
     await self.save_info(cat_info, in_transaction)
Exemplo n.º 6
0
    async def create(
        wallet_state_manager: Any,
        wallet: Wallet,
        wallet_info: WalletInfo,
    ) -> CATWallet:
        self = CATWallet()

        self.log = logging.getLogger(__name__)

        self.cost_of_single_tx = None
        self.wallet_state_manager = wallet_state_manager
        self.wallet_info = wallet_info
        self.standard_wallet = wallet
        self.cat_info = CATInfo.from_bytes(
            hexstr_to_bytes(self.wallet_info.data))
        return self
Exemplo n.º 7
0
    async def create_new_cat_wallet(wallet_state_manager: Any,
                                    wallet: Wallet,
                                    cat_tail_info: Dict[str, Any],
                                    amount: uint64,
                                    name="CAT WALLET"):
        self = CATWallet()
        self.cost_of_single_tx = None
        self.standard_wallet = wallet
        self.log = logging.getLogger(__name__)
        std_wallet_id = self.standard_wallet.wallet_id
        bal = await wallet_state_manager.get_confirmed_balance_for_wallet_already_locked(
            std_wallet_id)
        if amount > bal:
            raise ValueError("Not enough balance")
        self.wallet_state_manager = wallet_state_manager

        # We use 00 bytes because it's not optional. We must check this is overidden during issuance.
        empty_bytes = bytes32(32 * b"\0")
        self.cat_info = CATInfo(empty_bytes, None, [])
        info_as_string = bytes(self.cat_info).hex()
        self.wallet_info = await wallet_state_manager.user_store.create_wallet(
            name, WalletType.CAT, info_as_string)
        if self.wallet_info is None:
            raise ValueError("Internal Error")

        try:
            chia_tx, spend_bundle = await ALL_LIMITATIONS_PROGRAMS[
                cat_tail_info["identifier"]].generate_issuance_bundle(
                    self,
                    cat_tail_info,
                    amount,
                )
            assert self.cat_info.limitations_program_hash != empty_bytes
            assert self.cat_info.lineage_proofs != []
        except Exception:
            await wallet_state_manager.user_store.delete_wallet(
                self.id(), False)
            raise
        if spend_bundle is None:
            await wallet_state_manager.user_store.delete_wallet(self.id())
            raise ValueError("Failed to create spend.")

        await self.wallet_state_manager.add_new_wallet(self, self.id())

        # Change and actual CAT coin
        non_ephemeral_coins: List[Coin] = spend_bundle.not_ephemeral_additions(
        )
        cc_coin = None
        puzzle_store = self.wallet_state_manager.puzzle_store
        for c in non_ephemeral_coins:
            info = await puzzle_store.wallet_info_for_puzzle_hash(c.puzzle_hash
                                                                  )
            if info is None:
                raise ValueError("Internal Error")
            id, wallet_type = info
            if id == self.id():
                cc_coin = c

        if cc_coin is None:
            raise ValueError("Internal Error, unable to generate new CAT coin")
        cc_pid: bytes32 = cc_coin.parent_coin_info

        cc_record = TransactionRecord(
            confirmed_at_height=uint32(0),
            created_at_time=uint64(int(time.time())),
            to_puzzle_hash=cc_coin.puzzle_hash,
            amount=uint64(cc_coin.amount),
            fee_amount=uint64(0),
            confirmed=False,
            sent=uint32(10),
            spend_bundle=None,
            additions=[cc_coin],
            removals=list(
                filter(lambda rem: rem.name() == cc_pid,
                       spend_bundle.removals())),
            wallet_id=self.id(),
            sent_to=[],
            trade_id=None,
            type=uint32(TransactionType.INCOMING_TX.value),
            name=bytes32(token_bytes()),
            memos=[],
        )
        chia_tx = dataclasses.replace(chia_tx, spend_bundle=spend_bundle)
        await self.standard_wallet.push_transaction(chia_tx)
        await self.standard_wallet.push_transaction(cc_record)
        return self