Wallet: add CLI flag --force-swap flag and force swapping all inactive keysets (#580)

* Wallet: add flag --force-swap to send command

* Reame split to swap across codebase

* rename remaining splits to swap

* fix restore index with multiple keysets

* fix wallet api restore
This commit is contained in:
callebtc
2024-07-11 23:08:36 +02:00
committed by GitHub
parent 77697c52ee
commit 3077ca4c7d
26 changed files with 226 additions and 170 deletions

View File

@@ -222,19 +222,19 @@ class PostMeltRequest_deprecated(BaseModel):
# ------- API: SPLIT -------
class PostSplitRequest(BaseModel):
class PostSwapRequest(BaseModel):
inputs: List[Proof] = Field(..., max_items=settings.mint_max_request_length)
outputs: List[BlindedMessage] = Field(
..., max_items=settings.mint_max_request_length
)
class PostSplitResponse(BaseModel):
class PostSwapResponse(BaseModel):
signatures: List[BlindedSignature]
# deprecated since 0.13.0
class PostSplitRequest_Deprecated(BaseModel):
class PostSwapRequest_Deprecated(BaseModel):
proofs: List[Proof] = Field(..., max_items=settings.mint_max_request_length)
amount: Optional[int] = None
outputs: List[BlindedMessage_Deprecated] = Field(
@@ -242,11 +242,11 @@ class PostSplitRequest_Deprecated(BaseModel):
)
class PostSplitResponse_Deprecated(BaseModel):
class PostSwapResponse_Deprecated(BaseModel):
promises: List[BlindedSignature] = []
class PostSplitResponse_Very_Deprecated(BaseModel):
class PostSwapResponse_Very_Deprecated(BaseModel):
fst: List[BlindedSignature] = []
snd: List[BlindedSignature] = []
deprecated: str = "The amount field is deprecated since 0.13.0"

View File

@@ -961,18 +961,18 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
return PostMeltQuoteResponse.from_melt_quote(melt_quote)
async def split(
async def swap(
self,
*,
proofs: List[Proof],
outputs: List[BlindedMessage],
keyset: Optional[MintKeyset] = None,
):
"""Consumes proofs and prepares new promises based on the amount split. Used for splitting tokens
"""Consumes proofs and prepares new promises based on the amount swap. Used for swapping tokens
Before sending or for redeeming tokens for new ones that have been received by another wallet.
Args:
proofs (List[Proof]): Proofs to be invalidated for the split.
proofs (List[Proof]): Proofs to be invalidated for the swap.
outputs (List[BlindedMessage]): New outputs that should be signed in return.
keyset (Optional[MintKeyset], optional): Keyset to use. Uses default keyset if not given. Defaults to None.
@@ -980,9 +980,9 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
Exception: Validation of proofs or outputs failed
Returns:
Tuple[List[BlindSignature],List[BlindSignature]]: Promises on both sides of the split.
List[BlindedSignature]: New promises (signatures) for the outputs.
"""
logger.trace("split called")
logger.trace("swap called")
# verify spending inputs, outputs, and spending conditions
await self.verify_inputs_and_outputs(proofs=proofs, outputs=outputs)
await self.db_write._set_proofs_pending(proofs)
@@ -991,13 +991,13 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
await self._invalidate_proofs(proofs=proofs, conn=conn)
promises = await self._generate_promises(outputs, keyset, conn)
except Exception as e:
logger.trace(f"split failed: {e}")
logger.trace(f"swap failed: {e}")
raise e
finally:
# delete proofs from pending list
await self.db_write._unset_proofs_pending(proofs)
logger.trace("split successful")
logger.trace("swap successful")
return promises
async def restore(

View File

@@ -21,8 +21,8 @@ from ..core.models import (
PostMintResponse,
PostRestoreRequest,
PostRestoreResponse,
PostSplitRequest,
PostSplitResponse,
PostSwapRequest,
PostSwapResponse,
)
from ..core.settings import settings
from ..mint.startup import ledger
@@ -312,7 +312,7 @@ async def melt(request: Request, payload: PostMeltRequest) -> PostMeltQuoteRespo
"/v1/swap",
name="Swap tokens",
summary="Swap inputs for outputs of the same value",
response_model=PostSplitResponse,
response_model=PostSwapResponse,
response_description=(
"An array of blinded signatures that can be used to create proofs."
),
@@ -320,20 +320,20 @@ async def melt(request: Request, payload: PostMeltRequest) -> PostMeltQuoteRespo
@limiter.limit(f"{settings.mint_transaction_rate_limit_per_minute}/minute")
async def swap(
request: Request,
payload: PostSplitRequest,
) -> PostSplitResponse:
payload: PostSwapRequest,
) -> PostSwapResponse:
"""
Requests a set of Proofs to be split into two a new set of BlindedSignatures.
Requests a set of Proofs to be swapped for another set of BlindSignatures.
This endpoint is used by Alice to split a set of proofs before making a payment to Carol.
It is then used by Carol (by setting split=total) to redeem the tokens.
This endpoint can be used by Alice to swap a set of proofs before making a payment to Carol.
It can then used by Carol to redeem the tokens for new proofs.
"""
logger.trace(f"> POST /v1/swap: {payload}")
assert payload.outputs, Exception("no outputs provided.")
signatures = await ledger.split(proofs=payload.inputs, outputs=payload.outputs)
signatures = await ledger.swap(proofs=payload.inputs, outputs=payload.outputs)
return PostSplitResponse(signatures=signatures)
return PostSwapResponse(signatures=signatures)
@router.post(

View File

@@ -22,9 +22,9 @@ from ..core.models import (
PostMintResponse_deprecated,
PostRestoreRequest_Deprecated,
PostRestoreResponse,
PostSplitRequest_Deprecated,
PostSplitResponse_Deprecated,
PostSplitResponse_Very_Deprecated,
PostSwapRequest_Deprecated,
PostSwapResponse_Deprecated,
PostSwapResponse_Very_Deprecated,
)
from ..core.settings import settings
from .limit import limiter
@@ -270,7 +270,7 @@ async def check_fees(
name="Split",
summary="Split proofs at a specified amount",
# response_model=Union[
# PostSplitResponse_Very_Deprecated, PostSplitResponse_Deprecated
# PostSwapResponse_Very_Deprecated, PostSwapResponse_Deprecated
# ],
response_description=(
"A list of blinded signatures that can be used to create proofs."
@@ -280,8 +280,8 @@ async def check_fees(
@limiter.limit(f"{settings.mint_transaction_rate_limit_per_minute}/minute")
async def split_deprecated(
request: Request,
payload: PostSplitRequest_Deprecated,
# ) -> Union[PostSplitResponse_Very_Deprecated, PostSplitResponse_Deprecated]:
payload: PostSwapRequest_Deprecated,
# ) -> Union[PostSwapResponse_Very_Deprecated, PostSwapResponse_Deprecated]:
):
"""
Requests a set of Proofs to be split into two a new set of BlindedSignatures.
@@ -297,7 +297,7 @@ async def split_deprecated(
for o in payload.outputs
]
# END BACKWARDS COMPATIBILITY < 0.14
promises = await ledger.split(proofs=payload.proofs, outputs=outputs)
promises = await ledger.swap(proofs=payload.proofs, outputs=outputs)
if payload.amount:
# BEGIN backwards compatibility < 0.13
@@ -319,10 +319,10 @@ async def split_deprecated(
f" {sum([p.amount for p in frst_promises])} sat and send:"
f" {len(scnd_promises)}: {sum([p.amount for p in scnd_promises])} sat"
)
return PostSplitResponse_Very_Deprecated(fst=frst_promises, snd=scnd_promises)
return PostSwapResponse_Very_Deprecated(fst=frst_promises, snd=scnd_promises)
# END backwards compatibility < 0.13
else:
return PostSplitResponse_Deprecated(promises=promises)
return PostSwapResponse_Deprecated(promises=promises)
@router_deprecated.post(

View File

@@ -194,7 +194,7 @@ async def swap(
if outgoing_wallet.available_balance < total_amount:
raise Exception("balance too low")
_, send_proofs = await outgoing_wallet.split_to_send(
_, send_proofs = await outgoing_wallet.swap_to_send(
outgoing_wallet.proofs, total_amount, set_reserved=True
)
await outgoing_wallet.melt(
@@ -433,7 +433,7 @@ async def restore(
if to < 0:
raise Exception("Counter must be positive")
await wallet.load_mint()
await wallet.restore_promises_from_to(0, to)
await wallet.restore_promises_from_to(wallet.keyset_id, 0, to)
await wallet.invalidate(wallet.proofs, check_spendable=True)
return RestoreResponse(balance=wallet.available_balance)

View File

@@ -548,6 +548,14 @@ async def balance(ctx: Context, verbose):
help="Include fees for receiving token.",
type=bool,
)
@click.option(
"--force-swap",
"-s",
default=False,
is_flag=True,
help="Force swap token.",
type=bool,
)
@click.pass_context
@coro
async def send_command(
@@ -562,6 +570,7 @@ async def send_command(
yes: bool,
offline: bool,
include_fees: bool,
force_swap: bool,
):
wallet: Wallet = ctx.obj["WALLET"]
amount = int(amount * 100) if wallet.unit in [Unit.usd, Unit.eur] else int(amount)
@@ -575,6 +584,7 @@ async def send_command(
include_dleq=dleq,
include_fees=include_fees,
memo=memo,
force_swap=force_swap,
)
else:
await send_nostr(wallet, amount=amount, pubkey=nostr, verbose=verbose, yes=yes)

View File

@@ -116,6 +116,7 @@ async def send(
include_dleq: bool = False,
include_fees: bool = False,
memo: Optional[str] = None,
force_swap: bool = False,
):
"""
Prints token to send to stdout.
@@ -144,13 +145,12 @@ async def send(
await wallet.load_proofs()
await wallet.load_mint()
if secret_lock:
_, send_proofs = await wallet.split_to_send(
if secret_lock or force_swap:
_, send_proofs = await wallet.swap_to_send(
wallet.proofs,
amount,
set_reserved=False, # we set reserved later
secret_lock=secret_lock,
include_fees=include_fees,
)
else:
send_proofs, fees = await wallet.select_to_send(

View File

@@ -61,7 +61,7 @@ class LightningWallet(Wallet):
if self.available_balance < total_amount:
print("Error: Balance too low.")
return PaymentResponse(ok=False)
_, send_proofs = await self.split_to_send(self.proofs, total_amount)
_, send_proofs = await self.swap_to_send(self.proofs, total_amount)
try:
resp = await self.melt(send_proofs, pr, quote.fee_reserve, quote.quote)
if resp.change:

View File

@@ -62,7 +62,7 @@ async def send_nostr(
pubkey = await nip5_to_pubkey(wallet, pubkey)
await wallet.load_mint()
await wallet.load_proofs()
_, send_proofs = await wallet.split_to_send(
_, send_proofs = await wallet.swap_to_send(
wallet.proofs, amount, set_reserved=True, include_fees=False
)
token = await wallet.serialize_proofs(send_proofs, include_dleq=include_dleq)

View File

@@ -148,6 +148,7 @@ class WalletProofs(SupportsDb, SupportsKeysets):
try:
_ = [bytes.fromhex(p.id) for p in proofs]
except ValueError:
logger.debug("Proof with base64 keyset, using legacy token serialization")
legacy = True
if legacy:

View File

@@ -105,27 +105,28 @@ class WalletSecrets(SupportsDb, SupportsKeysets):
return hashlib.sha256(os.urandom(32)).hexdigest()
async def generate_determinstic_secret(
self, counter: int
self, counter: int, keyset_id: Optional[str] = None
) -> Tuple[bytes, bytes, str]:
"""
Determinstically generates two secrets (one as the secret message,
one as the blinding factor).
"""
assert self.bip32, "BIP32 not initialized yet."
keyset_id = keyset_id or self.keyset_id
# integer keyset id modulo max number of bip32 child keys
try:
keyest_id_int = int.from_bytes(bytes.fromhex(self.keyset_id), "big") % (
keyest_id_int = int.from_bytes(bytes.fromhex(keyset_id), "big") % (
2**31 - 1
)
except ValueError:
# BEGIN: BACKWARDS COMPATIBILITY < 0.15.0 keyset id is not hex
# calculate an integer keyset id from the base64 encoded keyset id
keyest_id_int = int.from_bytes(base64.b64decode(self.keyset_id), "big") % (
keyest_id_int = int.from_bytes(base64.b64decode(keyset_id), "big") % (
2**31 - 1
)
# END: BACKWARDS COMPATIBILITY < 0.15.0 keyset id is not hex
logger.trace(f"keyset id: {self.keyset_id} becomes {keyest_id_int}")
logger.trace(f"keyset id: {keyset_id} becomes {keyest_id_int}")
token_derivation_path = f"m/129372'/0'/{keyest_id_int}'/{counter}'"
# for secret
secret_derivation_path = f"{token_derivation_path}/0"
@@ -177,13 +178,14 @@ class WalletSecrets(SupportsDb, SupportsKeysets):
return secrets, rs, derivation_paths
async def generate_secrets_from_to(
self, from_counter: int, to_counter: int
self, from_counter: int, to_counter: int, keyset_id: Optional[str] = None
) -> Tuple[List[str], List[PrivateKey], List[str]]:
"""Generates secrets and blinding factors from `from_counter` to `to_counter`
Args:
from_counter (int): Start counter
to_counter (int): End counter
keyset_id (Optional[str], optional): Keyset id. Defaults to None.
Returns:
Tuple[List[str], List[PrivateKey], List[str]]: Secrets, blinding factors, derivation paths
@@ -196,7 +198,8 @@ class WalletSecrets(SupportsDb, SupportsKeysets):
), "from_counter must be smaller than to_counter"
secret_counters = [c for c in range(from_counter, to_counter + 1)]
secrets_rs_derivationpaths = [
await self.generate_determinstic_secret(s) for s in secret_counters
await self.generate_determinstic_secret(s, keyset_id)
for s in secret_counters
]
# secrets are supplied as str
secrets = [s[0].hex() for s in secrets_rs_derivationpaths]

View File

@@ -36,7 +36,7 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
def get_fees_for_proofs_ppk(self, proofs: List[Proof]) -> int:
return sum([self.keysets[p.id].input_fee_ppk for p in proofs])
async def _select_proofs_to_send_(
async def _select_proofs_to_send_legacy(
self, proofs: List[Proof], amount_to_send: int, tolerance: int = 0
) -> List[Proof]:
send_proofs: List[Proof] = []
@@ -63,9 +63,6 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
# compose the target amount from the remaining_proofs
logger.debug(f"sorted_proofs: {[p.amount for p in sorted_proofs]}")
for p in sorted_proofs:
# logger.debug(f"send_proofs: {[p.amount for p in send_proofs]}")
# logger.debug(f"target_amount: {target_amount}")
# logger.debug(f"p.amount: {p.amount}")
if sum_proofs(send_proofs) + p.amount <= target_amount + tolerance:
send_proofs.append(p)
target_amount = amount_to_send + self.get_fees_for_proofs(send_proofs)
@@ -83,8 +80,19 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
proofs: List[Proof],
amount_to_send: Union[int, float],
*,
include_fees: bool = True,
include_fees: bool = False,
) -> List[Proof]:
"""Select proofs to send based on the amount to send and the proofs available. Implements a simple coin selection algorithm.
Can be used for selecting proofs to send an offline transaction.
Args:
proofs (List[Proof]): List of proofs to select from
amount_to_send (Union[int, float]): Amount to select proofs for
include_fees (bool, optional): Whether to include fees necessary to redeem the tokens in the selection. Defaults to False.
Returns:
List[Proof]: _description_
"""
# check that enough spendable proofs exist
if sum_proofs(proofs) < amount_to_send:
return []
@@ -136,7 +144,7 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
)
return selected_proofs
async def _select_proofs_to_split(
async def _select_proofs_to_swap(
self, proofs: List[Proof], amount_to_send: int
) -> Tuple[List[Proof], int]:
"""
@@ -147,9 +155,8 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
Rules:
1) Proofs that are not marked as reserved
2) Proofs that have a different keyset than the activated keyset_id of the mint
3) Include all proofs that have an older keyset than the current keyset of the mint (to get rid of old epochs).
4) If the target amount is not reached, add proofs of the current keyset until it is.
2) Include all proofs from inactive keysets (old epochs) to get rid of them
3) If the target amount is not reached, add proofs of the current keyset until it is.
Args:
proofs (List[Proof]): List of proofs to select from
@@ -163,7 +170,7 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
Exception: If the balance is too low to send the amount
"""
logger.debug(
f"_select_proofs_to_split - amounts we have: {amount_summary(proofs, self.unit)}"
f"_select_proofs_to_swap - amounts we have: {amount_summary(proofs, self.unit)}"
)
send_proofs: List[Proof] = []
@@ -171,11 +178,9 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
if sum_proofs(proofs) < amount_to_send:
raise Exception("balance too low.")
# add all proofs that have an older keyset than the current keyset of the mint
proofs_old_epochs = [
p for p in proofs if p.id != self.keysets[self.keyset_id].id
]
send_proofs += proofs_old_epochs
# add all proofs from inactive keysets
proofs_inactive_keysets = [p for p in proofs if not self.keysets[p.id].active]
send_proofs += proofs_inactive_keysets
# coinselect based on amount only from the current keyset
# start with the proofs with the largest amount and add them until the target amount is reached
@@ -193,7 +198,7 @@ class WalletTransactions(SupportsDb, SupportsKeysets):
send_proofs.append(proof_to_add)
logger.trace(
f"_select_proofs_to_split  selected proof amounts: {[p.amount for p in send_proofs]}"
f"_select_proofs_to_swap  selected proof amounts: {[p.amount for p in send_proofs]}"
)
fees = self.get_fees_for_proofs(send_proofs)
return send_proofs, fees

View File

@@ -39,8 +39,8 @@ from ..core.models import (
PostMintRequest,
PostMintResponse,
PostRestoreResponse,
PostSplitRequest,
PostSplitResponse,
PostSwapRequest,
PostSwapResponse,
)
from ..core.settings import settings
from ..tor.tor import TorProxy
@@ -465,7 +465,7 @@ class LedgerAPI(LedgerAPIDeprecated, object):
) -> List[BlindedSignature]:
"""Consume proofs and create new promises based on amount split."""
logger.debug("Calling split. POST /v1/swap")
split_payload = PostSplitRequest(inputs=proofs, outputs=outputs)
split_payload = PostSwapRequest(inputs=proofs, outputs=outputs)
# construct payload
def _splitrequest_include_fields(proofs: List[Proof]):
@@ -494,7 +494,7 @@ class LedgerAPI(LedgerAPIDeprecated, object):
# END backwards compatibility < 0.15.0
self.raise_on_error_request(resp)
promises_dict = resp.json()
mint_response = PostSplitResponse.parse_obj(promises_dict)
mint_response = PostSwapResponse.parse_obj(promises_dict)
promises = [BlindedSignature(**p.dict()) for p in mint_response.signatures]
if len(promises) == 0:

View File

@@ -85,7 +85,7 @@ class Wallet(
"""
keyset_id: str # holds current keyset id
keysets: Dict[str, WalletKeyset] # holds keysets
keysets: Dict[str, WalletKeyset] = {} # holds keysets
# mint_keyset_ids: List[str] # holds active keyset ids of the mint
unit: Unit
mint_info: MintInfo # holds info about mint
@@ -178,7 +178,7 @@ class Wallet(
logger.debug(f"Mint info: {self.mint_info}")
return self.mint_info
async def load_mint_keysets(self):
async def load_mint_keysets(self, force_old_keysets=False):
"""Loads all keyset of the mint and makes sure we have them all in the database.
Then loads all keysets from the database for the active mint and active unit into self.keysets.
@@ -237,7 +237,7 @@ class Wallet(
)
# BEGIN backwards compatibility: phase out keysets with base64 ID by treating them as inactive
if settings.wallet_inactivate_legacy_keysets:
if settings.wallet_inactivate_legacy_keysets and not force_old_keysets:
keysets_in_db = await get_keysets(mint_url=self.url, db=self.db)
for keyset in keysets_in_db:
if not keyset.active:
@@ -306,14 +306,19 @@ class Wallet(
logger.debug(f"Activated keyset {self.keyset_id}")
async def load_mint(self, keyset_id: str = "") -> None:
async def load_mint(self, keyset_id: str = "", force_old_keysets=False) -> None:
"""
Loads the public keys of the mint. Either gets the keys for the specified
`keyset_id` or gets the keys of the active keyset from the mint.
Gets the active keyset ids of the mint and stores in `self.mint_keyset_ids`.
Args:
keyset_id (str, optional): Keyset id to load. Defaults to "".
force_old_keysets (bool, optional): If true, old deprecated base64 keysets are not ignored. This is necessary for restoring tokens from old base64 keysets.
Defaults to False.
"""
logger.trace("Loading mint.")
await self.load_mint_keysets()
await self.load_mint_keysets(force_old_keysets)
await self.activate_keyset(keyset_id)
try:
await self.load_mint_info()
@@ -902,6 +907,7 @@ class Wallet(
amounts: List[int],
secrets: List[str],
rs: List[PrivateKey] = [],
keyset_id: Optional[str] = None,
) -> Tuple[List[BlindedMessage], List[PrivateKey]]:
"""Takes a list of amounts and secrets and returns outputs.
Outputs are blinded messages `outputs` and blinding factors `rs`
@@ -921,8 +927,8 @@ class Wallet(
assert len(amounts) == len(
secrets
), f"len(amounts)={len(amounts)} not equal to len(secrets)={len(secrets)}"
keyset_id = keyset_id or self.keyset_id
outputs: List[BlindedMessage] = []
rs_ = [None] * len(amounts) if not rs else rs
rs_return: List[PrivateKey] = []
for secret, amount, r in zip(secrets, amounts, rs_):
@@ -935,7 +941,7 @@ class Wallet(
rs_return.append(r)
output = BlindedMessage(
amount=amount, B_=B_.serialize().hex(), id=self.keyset_id
amount=amount, B_=B_.serialize().hex(), id=keyset_id
)
outputs.append(output)
logger.trace(f"Constructing output: {output}, r: {r.serialize()}")
@@ -1049,7 +1055,7 @@ class Wallet(
if not offline:
logger.debug("Offline coin selection unsuccessful. Splitting proofs.")
# we set the proofs as reserved later
_, send_proofs = await self.split_to_send(
_, send_proofs = await self.swap_to_send(
proofs, amount, set_reserved=False
)
else:
@@ -1061,7 +1067,7 @@ class Wallet(
await self.set_reserved(send_proofs, reserved=True)
return send_proofs, fees
async def split_to_send(
async def swap_to_send(
self,
proofs: List[Proof],
amount: int,
@@ -1093,7 +1099,7 @@ class Wallet(
raise Exception("balance too low.")
# coin selection for swapping
# spendable_proofs, fees = await self._select_proofs_to_split(proofs, amount)
# spendable_proofs, fees = await self._select_proofs_to_swap(proofs, amount)
swap_proofs = await self._select_proofs_to_send(
proofs, amount, include_fees=True
)
@@ -1195,31 +1201,41 @@ class Wallet(
to (int, optional): The number of consecutive empty responses to stop restoring. Defaults to 2.
batch (int, optional): The number of proofs to restore in one batch. Defaults to 25.
"""
stop_counter = 0
empty_batches = 0
# we get the current secret counter and restore from there on
spendable_proofs = []
counter_before = await bump_secret_derivation(
db=self.db, keyset_id=keyset_id, by=0
)
if counter_before != 0:
print("Keyset has already been used. Restoring from it's last state.")
print("Keyset has already been used. Restoring from its last state.")
i = counter_before
n_last_restored_proofs = 0
while stop_counter < to:
print(f"Restoring token {i} to {i + batch}...")
restored_proofs = await self.restore_promises_from_to(i, i + batch - 1)
last_restore_count = 0
while empty_batches < to:
print(f"Restoring counter {i} to {i + batch} for keyset {keyset_id} ...")
(
next_restored_output_index,
restored_proofs,
) = await self.restore_promises_from_to(keyset_id, i, i + batch - 1)
last_restore_count += next_restored_output_index
i += batch
if len(restored_proofs) == 0:
stop_counter += 1
empty_batches += 1
continue
spendable_proofs = await self.invalidate(
restored_proofs, check_spendable=True
)
if len(spendable_proofs):
n_last_restored_proofs = len(spendable_proofs)
print(f"Restored {sum_proofs(restored_proofs)} sat")
i += batch
print(
f"Restored {sum_proofs(spendable_proofs)} sat for keyset {keyset_id}."
)
else:
logger.debug(
f"None of the {len(restored_proofs)} restored proofs are spendable."
)
# restore the secret counter to its previous value for the last round
revert_counter_by = batch * to + n_last_restored_proofs
revert_counter_by = i - last_restore_count
logger.debug(f"Reverting secret counter by {revert_counter_by}")
before = await bump_secret_derivation(
db=self.db,
@@ -1229,8 +1245,8 @@ class Wallet(
logger.debug(
f"Secret counter reverted from {before} to {before - revert_counter_by}"
)
if n_last_restored_proofs == 0:
print("No tokens restored for keyset.")
if last_restore_count == 0:
print(f"No tokens restored for keyset {keyset_id}.")
return
async def restore_wallet_from_mnemonic(
@@ -1245,14 +1261,14 @@ class Wallet(
batch (int, optional): The number of proofs to restore in one batch. Defaults to 25.
"""
await self._init_private_key(mnemonic)
await self.load_mint()
await self.load_mint(force_old_keysets=False)
print("Restoring tokens...")
for keyset_id in self.keysets.keys():
await self.restore_tokens_for_keyset(keyset_id, to, batch)
async def restore_promises_from_to(
self, from_counter: int, to_counter: int
) -> List[Proof]:
self, keyset_id: str, from_counter: int, to_counter: int
) -> Tuple[int, List[Proof]]:
"""Restores promises from a given range of counters. This is for restoring a wallet from a mnemonic.
Args:
@@ -1260,18 +1276,20 @@ class Wallet(
to_counter (int): Counter for the secret derivation to end at
Returns:
List[Proof]: List of restored proofs
Tuple[int, List[Proof]]: Index of the last restored output and list of restored proofs
"""
# we regenerate the secrets and rs for the given range
secrets, rs, derivation_paths = await self.generate_secrets_from_to(
from_counter, to_counter
from_counter, to_counter, keyset_id=keyset_id
)
# we don't know the amount but luckily the mint will tell us so we use a dummy amount here
amounts_dummy = [1] * len(secrets)
# we generate outputs from deterministic secrets and rs
regenerated_outputs, _ = self._construct_outputs(amounts_dummy, secrets, rs)
regenerated_outputs, _ = self._construct_outputs(
amounts_dummy, secrets, rs, keyset_id=keyset_id
)
# we ask the mint to reissue the promises
proofs = await self.restore_promises(
next_restored_output_index, proofs = await self.restore_promises(
outputs=regenerated_outputs,
secrets=secrets,
rs=rs,
@@ -1279,9 +1297,9 @@ class Wallet(
)
await set_secret_derivation(
db=self.db, keyset_id=self.keyset_id, counter=to_counter + 1
db=self.db, keyset_id=keyset_id, counter=to_counter + 1
)
return proofs
return next_restored_output_index, proofs
async def restore_promises(
self,
@@ -1289,7 +1307,7 @@ class Wallet(
secrets: List[str],
rs: List[PrivateKey],
derivation_paths: List[str],
) -> List[Proof]:
) -> Tuple[int, List[Proof]]:
"""Restores proofs from a list of outputs, secrets, rs and derivation paths.
Args:
@@ -1299,10 +1317,26 @@ class Wallet(
derivation_paths (List[str]): Derivation paths used for the secrets necessary to unblind the promises
Returns:
List[Proof]: List of restored proofs
Tuple[int, List[Proof]]: Index of the last restored output and list of restored proofs
"""
# restored_outputs is there so we can match the promises to the secrets and rs
restored_outputs, restored_promises = await super().restore_promises(outputs)
# determine the index in `outputs` of the last restored output from restored_outputs[-1].B_
if not restored_outputs:
next_restored_output_index = 0
else:
next_restored_output_index = (
next(
(
idx
for idx, val in enumerate(outputs)
if val.B_ == restored_outputs[-1].B_
),
0,
)
+ 1
)
logger.trace(f"Last restored output index: {next_restored_output_index}")
# now we need to filter out the secrets and rs that had a match
matching_indices = [
idx
@@ -1311,9 +1345,12 @@ class Wallet(
]
secrets = [secrets[i] for i in matching_indices]
rs = [rs[i] for i in matching_indices]
logger.debug(
f"Restored {len(restored_promises)} promises. Constructing proofs."
)
# now we can construct the proofs with the secrets and rs
proofs = await self._construct_proofs(
restored_promises, secrets, rs, derivation_paths
)
logger.debug(f"Restored {len(restored_promises)} promises")
return proofs
return next_restored_output_index, proofs

View File

@@ -31,8 +31,8 @@ from ..core.models import (
PostMintRequest_deprecated,
PostMintResponse_deprecated,
PostRestoreResponse,
PostSplitRequest_Deprecated,
PostSplitResponse_Deprecated,
PostSwapRequest_Deprecated,
PostSwapResponse_Deprecated,
)
from ..core.settings import settings
from ..tor.tor import TorProxy
@@ -348,7 +348,7 @@ class LedgerAPIDeprecated(SupportsHttpxClient, SupportsMintURL):
"""Consume proofs and create new promises based on amount split."""
logger.warning("Using deprecated API call: Calling split. POST /split")
outputs_deprecated = [BlindedMessage_Deprecated(**o.dict()) for o in outputs]
split_payload = PostSplitRequest_Deprecated(
split_payload = PostSwapRequest_Deprecated(
proofs=proofs, outputs=outputs_deprecated
)
@@ -373,7 +373,7 @@ class LedgerAPIDeprecated(SupportsHttpxClient, SupportsMintURL):
)
self.raise_on_error(resp)
promises_dict = resp.json()
mint_response = PostSplitResponse_Deprecated.parse_obj(promises_dict)
mint_response = PostSwapResponse_Deprecated.parse_obj(promises_dict)
promises = [BlindedSignature(**p.dict()) for p in mint_response.promises]
if len(promises) == 0:

View File

@@ -422,7 +422,7 @@ async def test_melt_external(ledger: Ledger, wallet: Wallet):
assert quote.amount == 62
assert quote.fee_reserve == 2
keep, send = await wallet.split_to_send(wallet.proofs, 64)
keep, send = await wallet.swap_to_send(wallet.proofs, 64)
inputs_payload = [p.to_dict() for p in send]
# outputs for change

View File

@@ -123,7 +123,7 @@ async def test_split_with_fees(wallet1: Wallet, ledger: Ledger):
assert fees == 1
outputs = await wallet1.construct_outputs(amount_split(9))
promises = await ledger.split(proofs=send_proofs, outputs=outputs)
promises = await ledger.swap(proofs=send_proofs, outputs=outputs)
assert len(promises) == len(outputs)
assert [p.amount for p in promises] == [p.amount for p in outputs]
@@ -141,7 +141,7 @@ async def test_split_with_high_fees(wallet1: Wallet, ledger: Ledger):
assert fees == 3
outputs = await wallet1.construct_outputs(amount_split(7))
promises = await ledger.split(proofs=send_proofs, outputs=outputs)
promises = await ledger.swap(proofs=send_proofs, outputs=outputs)
assert len(promises) == len(outputs)
assert [p.amount for p in promises] == [p.amount for p in outputs]
@@ -161,7 +161,7 @@ async def test_split_not_enough_fees(wallet1: Wallet, ledger: Ledger):
outputs = await wallet1.construct_outputs(amount_split(10))
await assert_err(
ledger.split(proofs=send_proofs, outputs=outputs), "are not balanced"
ledger.swap(proofs=send_proofs, outputs=outputs), "are not balanced"
)

View File

@@ -252,7 +252,7 @@ async def test_startup_regtest_pending_quote_pending(wallet: Wallet, ledger: Led
# wallet pays the invoice
quote = await wallet.melt_quote(invoice_payment_request)
total_amount = quote.amount + quote.fee_reserve
_, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount)
_, send_proofs = await wallet.swap_to_send(wallet.proofs, total_amount)
asyncio.create_task(
wallet.melt(
proofs=send_proofs,
@@ -297,7 +297,7 @@ async def test_startup_regtest_pending_quote_success(wallet: Wallet, ledger: Led
# wallet pays the invoice
quote = await wallet.melt_quote(invoice_payment_request)
total_amount = quote.amount + quote.fee_reserve
_, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount)
_, send_proofs = await wallet.swap_to_send(wallet.proofs, total_amount)
asyncio.create_task(
wallet.melt(
proofs=send_proofs,
@@ -347,7 +347,7 @@ async def test_startup_regtest_pending_quote_failure(wallet: Wallet, ledger: Led
# wallet pays the invoice
quote = await wallet.melt_quote(invoice_payment_request)
total_amount = quote.amount + quote.fee_reserve
_, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount)
_, send_proofs = await wallet.swap_to_send(wallet.proofs, total_amount)
asyncio.create_task(
wallet.melt(
proofs=send_proofs,

View File

@@ -60,7 +60,7 @@ async def test_melt_internal(wallet1: Wallet, ledger: Ledger):
assert not melt_quote_pre_payment.paid, "melt quote should not be paid"
assert melt_quote_pre_payment.state == MeltQuoteState.unpaid
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, 64)
keep_proofs, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 64)
await ledger.melt(proofs=send_proofs, quote=melt_quote.quote)
melt_quote_post_payment = await ledger.get_melt_quote(melt_quote.quote)
@@ -85,7 +85,7 @@ async def test_melt_external(wallet1: Wallet, ledger: Ledger):
assert mint_quote.state == MeltQuoteState.unpaid.value
total_amount = mint_quote.amount + mint_quote.fee_reserve
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, total_amount)
keep_proofs, send_proofs = await wallet1.swap_to_send(wallet1.proofs, total_amount)
melt_quote = await ledger.melt_quote(
PostMeltQuoteRequest(request=invoice_payment_request, unit="sat")
)
@@ -169,13 +169,13 @@ async def test_split(wallet1: Wallet, ledger: Ledger):
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, 10)
keep_proofs, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 10)
secrets, rs, derivation_paths = await wallet1.generate_n_secrets(len(send_proofs))
outputs, rs = wallet1._construct_outputs(
[p.amount for p in send_proofs], secrets, rs
)
promises = await ledger.split(proofs=send_proofs, outputs=outputs)
promises = await ledger.swap(proofs=send_proofs, outputs=outputs)
assert len(promises) == len(outputs)
assert [p.amount for p in promises] == [p.amount for p in outputs]
@@ -185,9 +185,9 @@ async def test_split_with_no_outputs(wallet1: Wallet, ledger: Ledger):
invoice = await wallet1.request_mint(64)
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 10, set_reserved=False)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 10, set_reserved=False)
await assert_err(
ledger.split(proofs=send_proofs, outputs=[]),
ledger.swap(proofs=send_proofs, outputs=[]),
"no outputs provided",
)
@@ -198,7 +198,7 @@ async def test_split_with_input_less_than_outputs(wallet1: Wallet, ledger: Ledge
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)
keep_proofs, send_proofs = await wallet1.split_to_send(
keep_proofs, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 10, set_reserved=False
)
@@ -213,7 +213,7 @@ async def test_split_with_input_less_than_outputs(wallet1: Wallet, ledger: Ledge
)
await assert_err(
ledger.split(proofs=send_proofs, outputs=outputs),
ledger.swap(proofs=send_proofs, outputs=outputs),
"are not balanced",
)
@@ -237,7 +237,7 @@ async def test_split_with_input_more_than_outputs(wallet1: Wallet, ledger: Ledge
outputs, rs = wallet1._construct_outputs(output_amounts, secrets, rs)
await assert_err(
ledger.split(proofs=inputs, outputs=outputs),
ledger.swap(proofs=inputs, outputs=outputs),
"are not balanced",
)
@@ -262,11 +262,11 @@ async def test_split_twice_with_same_outputs(wallet1: Wallet, ledger: Ledger):
)
outputs, rs = wallet1._construct_outputs(output_amounts, secrets, rs)
await ledger.split(proofs=inputs1, outputs=outputs)
await ledger.swap(proofs=inputs1, outputs=outputs)
# try to spend other proofs with the same outputs again
await assert_err(
ledger.split(proofs=inputs2, outputs=outputs),
ledger.swap(proofs=inputs2, outputs=outputs),
"outputs have already been signed before.",
)
@@ -277,7 +277,7 @@ async def test_split_twice_with_same_outputs(wallet1: Wallet, ledger: Ledger):
)
outputs, rs = wallet1._construct_outputs(output_amounts, secrets, rs)
await ledger.split(proofs=inputs2, outputs=outputs)
await ledger.swap(proofs=inputs2, outputs=outputs)
@pytest.mark.asyncio
@@ -396,7 +396,7 @@ async def test_check_proof_state(wallet1: Wallet, ledger: Ledger):
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)
keep_proofs, send_proofs = await wallet1.split_to_send(wallet1.proofs, 10)
keep_proofs, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 10)
proof_states = await ledger.db_read.get_proofs_states(Ys=[p.Y for p in send_proofs])
assert all([p.state.value == "UNSPENT" for p in proof_states])

View File

@@ -43,7 +43,7 @@ async def test_regtest_pending_quote(wallet: Wallet, ledger: Ledger):
# wallet pays the invoice
quote = await wallet.melt_quote(invoice_payment_request)
total_amount = quote.amount + quote.fee_reserve
_, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount)
_, send_proofs = await wallet.swap_to_send(wallet.proofs, total_amount)
asyncio.create_task(ledger.melt(proofs=send_proofs, quote=quote.quote))
# asyncio.create_task(
# wallet.melt(

View File

@@ -241,14 +241,14 @@ async def test_split(wallet1: Wallet):
@pytest.mark.asyncio
async def test_split_to_send(wallet1: Wallet):
async def test_swap_to_send(wallet1: Wallet):
invoice = await wallet1.request_mint(64)
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)
assert wallet1.balance == 64
# this will select 32 sats and them (nothing to keep)
keep_proofs, send_proofs = await wallet1.split_to_send(
keep_proofs, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 32, set_reserved=True
)
assert_amt(send_proofs, 32)
@@ -307,7 +307,7 @@ async def test_melt(wallet1: Wallet):
assert total_amount == 64
assert quote.fee_reserve == 0
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, total_amount)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, total_amount)
melt_response = await wallet1.melt(
proofs=send_proofs,
@@ -343,12 +343,12 @@ async def test_melt(wallet1: Wallet):
@pytest.mark.asyncio
async def test_split_to_send_more_than_balance(wallet1: Wallet):
async def test_swap_to_send_more_than_balance(wallet1: Wallet):
invoice = await wallet1.request_mint(64)
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)
await assert_err(
wallet1.split_to_send(wallet1.proofs, 128, set_reserved=True),
wallet1.swap_to_send(wallet1.proofs, 128, set_reserved=True),
"balance too low.",
)
assert wallet1.balance == 64
@@ -405,7 +405,7 @@ async def test_send_and_redeem(wallet1: Wallet, wallet2: Wallet):
invoice = await wallet1.request_mint(64)
await pay_if_regtest(invoice.bolt11)
await wallet1.mint(64, id=invoice.id)
_, spendable_proofs = await wallet1.split_to_send(
_, spendable_proofs = await wallet1.swap_to_send(
wallet1.proofs, 32, set_reserved=True
)
await wallet2.redeem(spendable_proofs)

View File

@@ -74,7 +74,7 @@ async def test_htlc_split(wallet1: Wallet, wallet2: Wallet):
preimage = "00000000000000000000000000000000"
preimage_hash = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
secret = await wallet1.create_htlc_lock(preimage=preimage)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
for p in send_proofs:
assert HTLCSecret.deserialize(p.secret).data == preimage_hash
@@ -87,7 +87,7 @@ async def test_htlc_redeem_with_preimage(wallet1: Wallet, wallet2: Wallet):
preimage = "00000000000000000000000000000000"
# preimage_hash = hashlib.sha256(bytes.fromhex(preimage)).hexdigest()
secret = await wallet1.create_htlc_lock(preimage=preimage)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
for p in send_proofs:
p.witness = HTLCWitness(preimage=preimage).json()
await wallet2.redeem(send_proofs)
@@ -103,7 +103,7 @@ async def test_htlc_redeem_with_wrong_preimage(wallet1: Wallet, wallet2: Wallet)
secret = await wallet1.create_htlc_lock(
preimage=preimage[:-5] + "11111"
) # wrong preimage
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
for p in send_proofs:
p.witness = HTLCWitness(preimage=preimage).json()
await assert_err(
@@ -122,7 +122,7 @@ async def test_htlc_redeem_with_no_signature(wallet1: Wallet, wallet2: Wallet):
secret = await wallet1.create_htlc_lock(
preimage=preimage, hashlock_pubkey=pubkey_wallet1
)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
for p in send_proofs:
p.witness = HTLCWitness(preimage=preimage).json()
await assert_err(
@@ -142,7 +142,7 @@ async def test_htlc_redeem_with_wrong_signature(wallet1: Wallet, wallet2: Wallet
secret = await wallet1.create_htlc_lock(
preimage=preimage, hashlock_pubkey=pubkey_wallet1
)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
signatures = await wallet1.sign_p2pk_proofs(send_proofs)
for p, s in zip(send_proofs, signatures):
p.witness = HTLCWitness(
@@ -166,7 +166,7 @@ async def test_htlc_redeem_with_correct_signature(wallet1: Wallet, wallet2: Wall
secret = await wallet1.create_htlc_lock(
preimage=preimage, hashlock_pubkey=pubkey_wallet1
)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
signatures = await wallet1.sign_p2pk_proofs(send_proofs)
for p, s in zip(send_proofs, signatures):
@@ -192,7 +192,7 @@ async def test_htlc_redeem_hashlock_wrong_signature_timelock_correct_signature(
locktime_seconds=2,
locktime_pubkey=pubkey_wallet1,
)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
signatures = await wallet1.sign_p2pk_proofs(send_proofs)
for p, s in zip(send_proofs, signatures):
@@ -226,7 +226,7 @@ async def test_htlc_redeem_hashlock_wrong_signature_timelock_wrong_signature(
locktime_seconds=2,
locktime_pubkey=pubkey_wallet1,
)
_, send_proofs = await wallet1.split_to_send(wallet1.proofs, 8, secret_lock=secret)
_, send_proofs = await wallet1.swap_to_send(wallet1.proofs, 8, secret_lock=secret)
signatures = await wallet1.sign_p2pk_proofs(send_proofs)
for p, s in zip(send_proofs, signatures):

View File

@@ -74,7 +74,7 @@ async def test_p2pk(wallet1: Wallet, wallet2: Wallet):
pubkey_wallet2 = await wallet2.create_p2pk_pubkey()
# p2pk test
secret_lock = await wallet1.create_p2pk_lock(pubkey_wallet2) # sender side
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
await wallet2.redeem(send_proofs)
@@ -100,7 +100,7 @@ async def test_p2pk_sig_all(wallet1: Wallet, wallet2: Wallet):
secret_lock = await wallet1.create_p2pk_lock(
pubkey_wallet2, sig_all=True
) # sender side
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
await wallet2.redeem(send_proofs)
@@ -114,7 +114,7 @@ async def test_p2pk_receive_with_wrong_private_key(wallet1: Wallet, wallet2: Wal
pubkey_wallet2 = await wallet2.create_p2pk_pubkey() # receiver side
# sender side
secret_lock = await wallet1.create_p2pk_lock(pubkey_wallet2) # sender side
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
# receiver side: wrong private key
@@ -137,7 +137,7 @@ async def test_p2pk_short_locktime_receive_with_wrong_private_key(
secret_lock = await wallet1.create_p2pk_lock(
pubkey_wallet2, locktime_seconds=2
) # sender side
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
# receiver side: wrong private key
@@ -167,7 +167,7 @@ async def test_p2pk_locktime_with_refund_pubkey(wallet1: Wallet, wallet2: Wallet
locktime_seconds=2, # locktime
tags=Tags([["refund", pubkey_wallet2]]), # refund pubkey
) # sender side
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
send_proofs_copy = copy.deepcopy(send_proofs)
@@ -198,7 +198,7 @@ async def test_p2pk_locktime_with_wrong_refund_pubkey(wallet1: Wallet, wallet2:
locktime_seconds=2, # locktime
tags=Tags([["refund", garbage_pubkey_2.serialize().hex()]]), # refund pubkey
) # sender side
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
send_proofs_copy = copy.deepcopy(send_proofs)
@@ -235,7 +235,7 @@ async def test_p2pk_locktime_with_second_refund_pubkey(
[["refund", pubkey_wallet2, pubkey_wallet1]]
), # multiple refund pubkeys
) # sender side
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
send_proofs_copy = copy.deepcopy(send_proofs)
@@ -263,7 +263,7 @@ async def test_p2pk_multisig_2_of_2(wallet1: Wallet, wallet2: Wallet):
pubkey_wallet2, tags=Tags([["pubkeys", pubkey_wallet1]]), n_sigs=2
)
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
# add signatures of wallet1
@@ -285,7 +285,7 @@ async def test_p2pk_multisig_duplicate_signature(wallet1: Wallet, wallet2: Walle
pubkey_wallet2, tags=Tags([["pubkeys", pubkey_wallet1]]), n_sigs=2
)
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
# add signatures of wallet2 this is a duplicate signature
@@ -308,7 +308,7 @@ async def test_p2pk_multisig_quorum_not_met_1_of_2(wallet1: Wallet, wallet2: Wal
secret_lock = await wallet1.create_p2pk_lock(
pubkey_wallet2, tags=Tags([["pubkeys", pubkey_wallet1]]), n_sigs=2
)
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
await assert_err(
@@ -330,7 +330,7 @@ async def test_p2pk_multisig_quorum_not_met_2_of_3(wallet1: Wallet, wallet2: Wal
pubkey_wallet2, tags=Tags([["pubkeys", pubkey_wallet1]]), n_sigs=3
)
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
# add signatures of wallet1
@@ -352,7 +352,7 @@ async def test_p2pk_multisig_with_duplicate_publickey(wallet1: Wallet, wallet2:
secret_lock = await wallet1.create_p2pk_lock(
pubkey_wallet2, tags=Tags([["pubkeys", pubkey_wallet2]]), n_sigs=2
)
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
await assert_err(wallet2.redeem(send_proofs), "Mint Error: pubkeys must be unique.")
@@ -377,7 +377,7 @@ async def test_p2pk_multisig_with_wrong_first_private_key(
secret_lock = await wallet1.create_p2pk_lock(
pubkey_wallet2, tags=Tags([["pubkeys", wrong_public_key_hex]]), n_sigs=2
)
_, send_proofs = await wallet1.split_to_send(
_, send_proofs = await wallet1.swap_to_send(
wallet1.proofs, 8, secret_lock=secret_lock
)
# add signatures of wallet1

View File

@@ -45,7 +45,7 @@ async def test_regtest_pending_quote(wallet: Wallet, ledger: Ledger):
# wallet pays the invoice
quote = await wallet.melt_quote(invoice_payment_request)
total_amount = quote.amount + quote.fee_reserve
_, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount)
_, send_proofs = await wallet.swap_to_send(wallet.proofs, total_amount)
asyncio.create_task(
wallet.melt(
proofs=send_proofs,
@@ -85,7 +85,7 @@ async def test_regtest_failed_quote(wallet: Wallet, ledger: Ledger):
# wallet pays the invoice
quote = await wallet.melt_quote(invoice_payment_request)
total_amount = quote.amount + quote.fee_reserve
_, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount)
_, send_proofs = await wallet.swap_to_send(wallet.proofs, total_amount)
asyncio.create_task(
wallet.melt(
proofs=send_proofs,

View File

@@ -164,7 +164,7 @@ async def test_restore_wallet_after_mint(wallet3: Wallet):
await wallet3.load_proofs()
wallet3.proofs = []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 20)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 20)
assert wallet3.balance == 64
# expect that DLEQ proofs are restored
@@ -185,7 +185,7 @@ async def test_restore_wallet_with_invalid_mnemonic(wallet3: Wallet):
@pytest.mark.asyncio
async def test_restore_wallet_after_split_to_send(wallet3: Wallet):
async def test_restore_wallet_after_swap_to_send(wallet3: Wallet):
await wallet3._init_private_key(
"half depart obvious quality work element tank gorilla view sugar picture"
" humble"
@@ -197,7 +197,7 @@ async def test_restore_wallet_after_split_to_send(wallet3: Wallet):
await wallet3.mint(64, id=invoice.id)
assert wallet3.balance == 64
_, spendable_proofs = await wallet3.split_to_send(
_, spendable_proofs = await wallet3.swap_to_send(
wallet3.proofs, 32, set_reserved=True
) # type: ignore
@@ -205,7 +205,7 @@ async def test_restore_wallet_after_split_to_send(wallet3: Wallet):
await wallet3.load_proofs()
wallet3.proofs = []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 100)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 100)
assert wallet3.balance == 96
await wallet3.invalidate(wallet3.proofs, check_spendable=True)
assert wallet3.balance == 64
@@ -222,7 +222,7 @@ async def test_restore_wallet_after_send_and_receive(wallet3: Wallet, wallet2: W
await wallet3.mint(64, id=invoice.id)
assert wallet3.balance == 64
_, spendable_proofs = await wallet3.split_to_send(
_, spendable_proofs = await wallet3.swap_to_send(
wallet3.proofs, 32, set_reserved=True
) # type: ignore
@@ -232,7 +232,7 @@ async def test_restore_wallet_after_send_and_receive(wallet3: Wallet, wallet2: W
await wallet3.load_proofs(reload=True)
assert wallet3.proofs == []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 100)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 100)
assert wallet3.balance == 96
await wallet3.invalidate(wallet3.proofs, check_spendable=True)
assert wallet3.balance == 32
@@ -265,7 +265,7 @@ async def test_restore_wallet_after_send_and_self_receive(wallet3: Wallet):
await wallet3.mint(64, id=invoice.id)
assert wallet3.balance == 64
_, spendable_proofs = await wallet3.split_to_send(
_, spendable_proofs = await wallet3.swap_to_send(
wallet3.proofs, 32, set_reserved=True
) # type: ignore
@@ -275,7 +275,7 @@ async def test_restore_wallet_after_send_and_self_receive(wallet3: Wallet):
await wallet3.load_proofs(reload=True)
assert wallet3.proofs == []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 100)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 100)
assert wallet3.balance == 128
await wallet3.invalidate(wallet3.proofs, check_spendable=True)
assert wallet3.balance == 64
@@ -295,7 +295,7 @@ async def test_restore_wallet_after_send_twice(
box.add(wallet3.proofs)
assert wallet3.balance == 2
keep_proofs, spendable_proofs = await wallet3.split_to_send(
keep_proofs, spendable_proofs = await wallet3.swap_to_send(
wallet3.proofs, 1, set_reserved=True
) # type: ignore
box.add(wallet3.proofs)
@@ -309,7 +309,7 @@ async def test_restore_wallet_after_send_twice(
await wallet3.load_proofs(reload=True)
assert wallet3.proofs == []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 10)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 10)
box.add(wallet3.proofs)
assert wallet3.balance == 4
await wallet3.invalidate(wallet3.proofs, check_spendable=True)
@@ -317,7 +317,7 @@ async def test_restore_wallet_after_send_twice(
# again
_, spendable_proofs = await wallet3.split_to_send(
_, spendable_proofs = await wallet3.swap_to_send(
wallet3.proofs, 1, set_reserved=True
) # type: ignore
box.add(wallet3.proofs)
@@ -331,7 +331,7 @@ async def test_restore_wallet_after_send_twice(
await wallet3.load_proofs(reload=True)
assert wallet3.proofs == []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 15)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 15)
box.add(wallet3.proofs)
assert wallet3.balance == 6
await wallet3.invalidate(wallet3.proofs, check_spendable=True)
@@ -354,7 +354,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value(
box.add(wallet3.proofs)
assert wallet3.balance == 64
keep_proofs, spendable_proofs = await wallet3.split_to_send(
keep_proofs, spendable_proofs = await wallet3.swap_to_send(
wallet3.proofs, 10, set_reserved=True
) # type: ignore
box.add(wallet3.proofs)
@@ -368,7 +368,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value(
await wallet3.load_proofs(reload=True)
assert wallet3.proofs == []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 20)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 20)
box.add(wallet3.proofs)
assert wallet3.balance == 84
await wallet3.invalidate(wallet3.proofs, check_spendable=True)
@@ -376,7 +376,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value(
# again
_, spendable_proofs = await wallet3.split_to_send(
_, spendable_proofs = await wallet3.swap_to_send(
wallet3.proofs, 12, set_reserved=True
) # type: ignore
@@ -388,7 +388,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value(
await wallet3.load_proofs(reload=True)
assert wallet3.proofs == []
assert wallet3.balance == 0
await wallet3.restore_promises_from_to(0, 50)
await wallet3.restore_promises_from_to(wallet3.keyset_id, 0, 50)
assert wallet3.balance == 108
await wallet3.invalidate(wallet3.proofs, check_spendable=True)
assert wallet3.balance == 64

View File

@@ -86,7 +86,7 @@ async def test_wallet_subscription_swap(wallet: Wallet):
wallet.proofs, callback=callback
)
_ = await wallet.split_to_send(wallet.proofs, 64)
_ = await wallet.swap_to_send(wallet.proofs, 64)
wait = 1
await asyncio.sleep(wait)