Skip to content

Commit

Permalink
hopefully fix the tests
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Oct 2, 2024
1 parent 38025fe commit 178b5b9
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 49 deletions.
29 changes: 21 additions & 8 deletions cashu/wallet/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ def determine_output_amounts(
# generate optimal split for outputs to send
send_amounts = amount_split(send_amt)

# we subtract the fee for the entire transaction from the amount to keep
# we subtract the input fee for the entire transaction from the amount to keep
keep_amt -= self.get_fees_for_proofs(proofs)
logger.trace(f"Keep amount: {keep_amt}")

Expand All @@ -638,6 +638,7 @@ async def split(
proofs: List[Proof],
amount: int,
secret_lock: Optional[Secret] = None,
include_fees_to_send: bool = False,
) -> Tuple[List[Proof], List[Proof]]:
"""Calls the swap API to split the proofs into two sets of proofs, one for keeping and one for sending.
Expand All @@ -649,6 +650,9 @@ async def split(
proofs (List[Proof]): Proofs to be split.
amount (int): Amount to be sent.
secret_lock (Optional[Secret], optional): Secret to lock the tokens to be sent. Defaults to None.
include_fees_to_send (bool, optional): If True, the fees are included in the amount to send (output of
this method, to be sent in the future). This is not the fee that is required to swap the
`proofs` (input to this method). Defaults to False.
Returns:
Tuple[List[Proof], List[Proof]]: Two lists of proofs, one for keeping and one for sending.
Expand All @@ -667,7 +671,10 @@ async def split(
# create a suitable amount lists to keep and send based on the proofs
# provided and the state of the wallet
keep_outputs, send_outputs = self.determine_output_amounts(
proofs, amount, include_fees_to_send=True, keyset_id_outputs=self.keyset_id
proofs,
amount,
include_fees_to_send=include_fees_to_send,
keyset_id_outputs=self.keyset_id,
)

amounts = keep_outputs + send_outputs
Expand Down Expand Up @@ -1060,7 +1067,8 @@ async def select_to_send(
amount (int): Amount to split to
set_reserved (bool, optional): If set, the proofs are marked as reserved. Defaults to False.
offline (bool, optional): If set, the coin selection is done offline. Defaults to False.
include_fees (bool, optional): If set, the fees are included in the amount to be selected. Defaults to False.
include_fees (bool, optional): If set, the fees for spending the proofs later are included in the
amount to be selected. Defaults to False.
Returns:
List[Proof]: Proofs to send
Expand All @@ -1085,7 +1093,10 @@ async def select_to_send(
logger.debug("Offline coin selection unsuccessful. Splitting proofs.")
# we set the proofs as reserved later
_, send_proofs = await self.swap_to_send(
proofs, amount, set_reserved=False, include_fees=include_fees
proofs,
amount,
set_reserved=False,
include_fees_to_send=include_fees,
)
else:
raise Exception(
Expand All @@ -1103,7 +1114,7 @@ async def swap_to_send(
*,
secret_lock: Optional[Secret] = None,
set_reserved: bool = False,
include_fees: bool = True,
include_fees_to_send: bool = True,
) -> Tuple[List[Proof], List[Proof]]:
"""
Swaps a set of proofs with the mint to get a set that sums up to a desired amount that can be sent. The remaining
Expand All @@ -1116,8 +1127,8 @@ async def swap_to_send(
amount (int): Amount to split to
secret_lock (Optional[str], optional): If set, a custom secret is used to lock new outputs. Defaults to None.
set_reserved (bool, optional): If set, the proofs are marked as reserved. Should be set to False if a payment attempt
is made with the split that could fail (like a Lightning payment). Should be set to True if the token to be sent is
displayed to the user to be then sent to someone else. Defaults to False.
is made with the split that could fail (like a Lightning payment). Should be set to True if the token to be sent is
displayed to the user to be then sent to someone else. Defaults to False.
Returns:
Tuple[List[Proof], List[Proof]]: Tuple of proofs to keep and proofs to send
Expand All @@ -1142,7 +1153,9 @@ async def swap_to_send(
logger.debug(
f"Amount to send: {self.unit.str(amount)} (+ {self.unit.str(fees)} fees)"
)
keep_proofs, send_proofs = await self.split(swap_proofs, amount, secret_lock)
keep_proofs, send_proofs = await self.split(
swap_proofs, amount, secret_lock, include_fees_to_send
)
if set_reserved:
await self.set_reserved(send_proofs, reserved=True)
return keep_proofs, send_proofs
Expand Down
73 changes: 32 additions & 41 deletions tests/test_mint_fees.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,45 @@ async def test_get_fees_for_proofs(wallet1: Wallet, ledger: Ledger):

@pytest.mark.asyncio
@pytest.mark.skipif(is_regtest, reason="only works with FakeWallet")
async def test_wallet_fee(wallet1: Wallet, ledger: Ledger):
# THIS TEST IS A FAKE, WE SET THE WALLET FEES MANUALLY IN set_ledger_keyset_fees
# It would be better to test if the wallet can get the fees from the mint itself
# but the ledger instance does not update the responses from the `mint` that is running in the background
# so we just pretend here and test really nothing...

async def test_wallet_selection_with_fee(wallet1: Wallet, ledger: Ledger):
# set fees to 100 ppk
set_ledger_keyset_fees(100, ledger, wallet1)

# THIS TEST IS A FAKE, WE SET THE WALLET FEES MANUALLY IN set_ledger_keyset_fees
# check if all wallet keysets have the correct fees
for keyset in wallet1.keysets.values():
assert keyset.input_fee_ppk == 100

invoice = await wallet1.request_mint(64)
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)

send_proofs, _ = await wallet1.select_to_send(wallet1.proofs, 10)
assert sum_proofs(send_proofs) == 10

send_proofs_with_fees, _ = await wallet1.select_to_send(
wallet1.proofs, 10, include_fees=True
)
assert sum_proofs(send_proofs_with_fees) == 11


@pytest.mark.asyncio
@pytest.mark.skipif(is_regtest, reason="only works with FakeWallet")
async def test_wallet_swap_to_send_with_fee(wallet1: Wallet, ledger: Ledger):
# set fees to 100 ppk
set_ledger_keyset_fees(100, ledger, wallet1)
invoice = await wallet1.request_mint(64)
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id, split=[32, 32]) # make sure we need to swap

# quirk: this should call a `/v1/swap` with the mint but the mint will
# throw an error since the fees are only changed in the `ledger` instance, not in the uvicorn API server
# this *should* succeed normally
await assert_err(
wallet1.select_to_send(wallet1.proofs, 10),
"Mint Error: inputs (32) - fees (0) vs outputs (31) are not balanced.",
)


@pytest.mark.asyncio
async def test_split_with_fees(wallet1: Wallet, ledger: Ledger):
Expand Down Expand Up @@ -244,38 +270,3 @@ async def test_melt_external_with_fees(wallet1: Wallet, ledger: Ledger):

melt_quote_post_payment = await ledger.get_melt_quote(melt_quote.quote)
assert melt_quote_post_payment.paid, "melt quote should be paid"


@pytest.mark.asyncio
@pytest.mark.skipif(is_fake, reason="only works with Regtest")
async def test_melt_external_with_fees_with_swap(wallet1: Wallet, ledger: Ledger):
# set fees to 100 ppk
set_ledger_keyset_fees(100, ledger, wallet1)

# mint twice so we have enough to pay the second invoice back
invoice = await wallet1.request_mint(128)
await pay_if_regtest(invoice.bolt11)
# we create a split so that the payment later of 32 sat will require a swap before we can melt
await wallet1.mint(128, id=invoice.id, split=[64, 64])
assert wallet1.balance == 128

invoice_dict = get_real_invoice(32)
invoice_payment_request = invoice_dict["payment_request"]

mint_quote = await wallet1.melt_quote(invoice_payment_request)
total_amount = mint_quote.amount + mint_quote.fee_reserve
send_proofs, fee = await wallet1.select_to_send(
wallet1.proofs, total_amount, include_fees=True
)
melt_quote = await ledger.melt_quote(
PostMeltQuoteRequest(request=invoice_payment_request, unit="sat")
)

melt_quote_pre_payment = await ledger.get_melt_quote(melt_quote.quote)
assert not melt_quote_pre_payment.paid, "melt quote should not be paid"

assert not melt_quote.paid, "melt quote should not be paid"
await ledger.melt(proofs=send_proofs, quote=melt_quote.quote)

melt_quote_post_payment = await ledger.get_melt_quote(melt_quote.quote)
assert melt_quote_post_payment.paid, "melt quote should be paid"

0 comments on commit 178b5b9

Please sign in to comment.