Allow arbitrary denominations in wallet minting (#684)

- Update `mint` method to use allowed amounts from the mint
- Add `get_allowed_amounts` method to fetch supported denominations
- Modify `test_mint_amounts_wrong_order` to expect new error message

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
Houdini
2025-03-06 20:15:14 +01:00
committed by GitHub
parent 72ac35405c
commit 7b3f5d01d0
3 changed files with 25 additions and 6 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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}",
)