diff --git a/cashu/wallet/transactions.py b/cashu/wallet/transactions.py index bb7464b..3cde2c4 100644 --- a/cashu/wallet/transactions.py +++ b/cashu/wallet/transactions.py @@ -111,6 +111,21 @@ class WalletTransactions(SupportsDb, SupportsKeysets): proofs_send = self.coinselect(proofs, amount, include_fees=True) return self.get_fees_for_proofs(proofs_send) + def get_allowed_amounts(self): + """ + Infer the allowed amounts from the current keyset's public keys. + + Returns: + List[int]: A sorted list of allowed token amounts for the current keyset. + + Raises: + Exception: If no active keyset is set. + """ + + if not self.keyset_id or self.keyset_id not in self.keysets: + raise Exception("No active keyset") + return sorted(list(self.keysets[self.keyset_id].public_keys.keys())) + def split_wallet_state(self, amount: int) -> List[int]: """This function produces an amount split for outputs based on the current state of the wallet. Its objective is to fill up the wallet so that it reaches `n_target` coins of each amount. @@ -125,8 +140,9 @@ class WalletTransactions(SupportsDb, SupportsKeysets): n_target = settings.wallet_target_amount_count amounts_we_have = [p.amount for p in self.proofs if p.reserved is not True] amounts_we_have.sort() - # NOTE: Do not assume 2^n here - all_possible_amounts: list[int] = [2**i for i in range(settings.max_order)] + + all_possible_amounts = self.get_allowed_amounts() + amounts_we_want_ll = [ [a] * max(0, n_target - amounts_we_have.count(a)) for a in all_possible_amounts diff --git a/cashu/wallet/wallet.py b/cashu/wallet/wallet.py index dac05dc..0a2809f 100644 --- a/cashu/wallet/wallet.py +++ b/cashu/wallet/wallet.py @@ -519,6 +519,8 @@ class Wallet( await store_bolt11_mint_quote(db=self.db, quote=quote) return quote + + async def mint( self, amount: int, @@ -529,7 +531,7 @@ class Wallet( Args: amount (int): Total amount of tokens to be minted - id (str): Id for looking up the paid Lightning invoice. + quote_id (str): Id for looking up the paid Lightning invoice. split (Optional[List[str]], optional): List of desired amount splits to be minted. Total must sum to `amount`. Raises: @@ -543,11 +545,11 @@ class Wallet( if split: logger.trace(f"Mint with split: {split}") assert sum(split) == amount, "split must sum to amount" - allowed_amounts = [2**i for i in range(settings.max_order)] + allowed_amounts = self.get_allowed_amounts() # Get allowed amounts from the mint for a in split: if a not in allowed_amounts: raise Exception( - f"Can only mint amounts with 2^n up to {2**settings.max_order}." + f"Can only mint amounts supported by the mint: {allowed_amounts}" ) # split based on our wallet state diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 0e0aba7..63f84de 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -221,9 +221,10 @@ async def test_mint_amounts_wrong_order(wallet1: Wallet): """Mint amount that is not part in 2^n""" amts = [1, 2, 3] mint_quote = await wallet1.request_mint(sum(amts)) + allowed_amounts = wallet1.get_allowed_amounts() await assert_err( wallet1.mint(amount=sum(amts), split=[1, 2, 3], quote_id=mint_quote.quote), - f"Can only mint amounts with 2^n up to {2**settings.max_order}.", + f"Can only mint amounts supported by the mint: {allowed_amounts}", )