Esempio n. 1
0
 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
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
 def get_new_puzzle(self):
     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,
     )
Esempio n. 5
0
 def puzzle_for_pk(self, pk):
     if self.rl_info.initialized is False:
         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,
     )
Esempio n. 6
0
    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)
Esempio n. 7
0
 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,
     )
Esempio n. 8
0
    async def set_user_info(
        self, interval: uint64, limit: uint64, origin_id: str, admin_pubkey: str
    ):

        if admin_pubkey.startswith("0x"):
            admin_pubkey = admin_pubkey[2:]
        admin_pubkey_bytes = bytes.fromhex(admin_pubkey)

        assert self.rl_info.user_pubkey is not None

        rl_puzzle = rl_puzzle_for_pk(
            pubkey=self.rl_info.user_pubkey,
            rate_amount=limit,
            interval_time=interval,
            origin_id=bytes.fromhex(origin_id),
            clawback_pk=admin_pubkey_bytes,
        )

        rl_puzzle_hash = rl_puzzle.get_hash()
        new_rl_info = RLInfo(
            "admin",
            admin_pubkey_bytes,
            self.rl_info.user_pubkey,
            limit,
            interval,
            None,
            origin_id,
            rl_puzzle_hash,
        )
        rl_puzzle_hash = rl_puzzle.get_hash()

        index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(
            self.rl_info.user_pubkey.hex()
        )
        assert index is not None
        record = DerivationRecord(
            index,
            rl_puzzle_hash,
            self.rl_info.user_pubkey,
            WalletType.RATE_LIMITED,
            self.wallet_info.id,
        )
        await self.wallet_state_manager.puzzle_store.add_derivation_paths([record])

        data_str = json.dumps(new_rl_info.to_json_dict())
        new_wallet_info = WalletInfo(
            self.wallet_info.id, self.wallet_info.name, self.wallet_info.type, data_str
        )
        await self.wallet_state_manager.user_store.update_wallet(new_wallet_info)
        self.wallet_info = new_wallet_info
        self.rl_info = new_rl_info
Esempio n. 9
0
 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,
     )
Esempio n. 10
0
 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
Esempio n. 11
0
    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
Esempio n. 12
0
    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,
            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)
        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
Esempio n. 13
0
    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)