diff --git a/justfile.local.just b/justfile.local.just index 4b54102..178441d 100644 --- a/justfile.local.just +++ b/justfile.local.just @@ -7,6 +7,12 @@ mprocs: test-ts: bun run wrappers/fedimint-ts/test.ts +test-py: + python3.11 wrappers/fedimint-py/test.py + +test-py-async: + python3.11 wrappers/fedimint-py/test_async.py + test-go: cd wrappers/fedimint-go && go run cmd/main.go diff --git a/wrappers/fedimint-py/AsyncFedimintClient.py b/wrappers/fedimint-py/AsyncFedimintClient.py index c85e543..95a26a8 100644 --- a/wrappers/fedimint-py/AsyncFedimintClient.py +++ b/wrappers/fedimint-py/AsyncFedimintClient.py @@ -1,7 +1,9 @@ import json import logging -from typing import List +from typing import List, Literal, Optional, Union +import asyncio import aiohttp +import atexit from models.common import ( DiscoverVersionRequest, @@ -50,18 +52,20 @@ class AsyncFedimintClient: + def __init__( self, base_url: str, password: str, - active_federationId: str, - active_gatewayId: str = None, + active_federation_id: str, + active_gateway_id: str = None, ): self.base_url = f"{base_url}/v2" self.password = password - self.active_federationId = active_federationId - self.active_gatewayId = active_gatewayId + self.active_federation_id = active_federation_id + self.active_gateway_id = active_gateway_id self.session = aiohttp.ClientSession() + atexit.register(self.close_sync) # Register the cleanup function self.lightning = self.Lightning(self) self.onchain = self.Onchain(self) @@ -70,25 +74,41 @@ def __init__( "Initialized fedimint client, must set active gateway id after intitalization to use lightning module methods or manually pass in gateways" ) - def get_active_federationId(self): - return self.active_federationId + async def close(self): + await self.session.close() + + def close_sync(self): + try: + loop = asyncio.get_event_loop() + except RuntimeError as e: + # If no event loop is available, create a new one for cleanup + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + if loop.is_running(): + loop.create_task(self.close()) + else: + loop.run_until_complete(self.close()) + + def get_active_federation_id(self): + return self.active_federation_id - def set_active_federationId(self, federationId: str): - self.active_federationId = federationId + def set_active_federation_id(self, federation_id: str): + self.active_federation_id = federation_id - def get_active_gatewayId(self): - return self.active_gatewayId + def get_active_gateway_id(self): + return self.active_gateway_id - def set_active_gatewayId(self, gatewayId: str): - self.active_gatewayId = gatewayId + def set_active_gateway_id(self, gateway_id: str): + self.active_gateway_id = gateway_id - def use_default_gateway(self): + async def use_default_gateway(self): # hits list_gateways and sets active_gatewayId to the first gateway try: - gateways = self.lightning.list_gateways() + gateways = await self.lightning.list_gateways() logging.info("Gateways: ", gateways) - self.active_gateway_id = gateways[0].info.gatewayId - logging.info("Set active gateway id to: ", self.active_gatewayId) + self.active_gateway_id = gateways[0]["info"]["gateway_id"] + logging.info("Set active gateway id to: ", self.active_gateway_id) except Exception as e: logging.error("Error setting default gateway id: ", e) @@ -117,14 +137,14 @@ async def _post(self, endpoint: str, data=None): return await response.json() async def _post_with_federation_id( - self, endpoint: str, data=None, federationId: str = None + self, endpoint: str, data=None, federation_id: str = None ): - if federationId is None: - federationId = self.get_active_federation_id() + if federation_id is None: + federation_id = self.get_active_federation_id() if data is None: data = {} - data["federationId"] = federationId + data["federationId"] = federation_id return await self._post(endpoint, data) @@ -132,25 +152,25 @@ async def _post_with_gateway_id_and_federation_id( self, endpoint: str, data=None, - gatewayId: str = None, - federationId: str = None, + gateway_id: str = None, + federation_id: str = None, ): - if gatewayId is None: - gatewayId = self.get_active_gateway_id() + if gateway_id is None: + gateway_id = self.get_active_gateway_id() - if federationId is None: - federationId = self.get_active_federation_id() + if federation_id is None: + federation_id = self.get_active_federation_id() - if federationId is None or gatewayId is None: + if federation_id is None or gateway_id is None: raise Exception( "Must set active gateway id and active federation id before calling this method" ) if data is None: data = {} - data["gatewayId"] = gatewayId - data["federationId"] = federationId + data["gatewayId"] = gateway_id + data["federationId"] = federation_id return await self._post(endpoint, data) @@ -174,9 +194,10 @@ async def federation_ids(self): async def list_operations(self, request: ListOperationsRequest): return await self._post_with_federation_id("/admin/list-operations", request) - async def join(self, invite_code: str, set_default: bool = False): + async def join(self, invite_code: str, use_manual_secret: bool = False): return await self._post( - "/admin/join", {"inviteCode": invite_code, "setDefault": set_default} + "/admin/join", + {"inviteCode": invite_code, "useManualSecret": use_manual_secret}, ) class Lightning: @@ -215,7 +236,7 @@ async def create_invoice_for_pubkey_tweak( federation_id: str = None, ) -> LightningInvoiceForPubkeyTweakResponse: request: LightningInvoiceForPubkeyTweakRequest = { - "pubkey": pubkey, + "externalPubkey": pubkey, "tweak": tweak, "amountMsat": amount_msat, "description": description, @@ -241,30 +262,45 @@ async def claim_pubkey_tweak_receives( } return await self.client._post_with_federation_id( - "/ln/claim-external-pubkey-tweaked", + "/ln/claim-external-receive-tweaked", data=request, federation_id=federation_id, ) async def await_invoice( - self, request: LightningAwaitInvoiceRequest, federationId: str = None + self, operation_id: str, federation_id: str = None ) -> InfoResponse: + request: LightningAwaitInvoiceRequest = {"operationId": operation_id} return await self.client._post_with_gateway_id_and_federation_id( - "/ln/await-invoice", request, federationId + "/ln/await-invoice", request, federation_id=federation_id ) async def pay( - self, request: LightningPayRequest, federationId: str = None + self, + payment_info: str, + amount_msat: Optional[int], + lightning_url_comment: Optional[str], + gateway_id: str = None, + federation_id: str = None, ) -> LightningPayResponse: + request: LightningPayRequest = { + "paymentInfo": payment_info, + "amountMsat": amount_msat, + "lightningUrlComment": lightning_url_comment, + } return await self.client._post_with_gateway_id_and_federation_id( - "/ln/pay", request, federationId + "/ln/pay", request, gateway_id=gateway_id, federation_id=federation_id ) async def await_pay( - self, request: LightningAwaitPayRequest, federationId: str = None + self, operation_id: str, gateway_id: str = None, federation_id: str = None ): + request: LightningAwaitPayRequest = {"operationId": operation_id} return await self.client._post_with_gateway_id_and_federation_id( - "/ln/await-pay", request, federationId + "/ln/await-pay", + request, + gateway_id=gateway_id, + federation_id=federation_id, ) async def list_gateways(self) -> List[Gateway]: @@ -275,28 +311,28 @@ def __init__(self, client): self.client = client async def decode_notes( - self, notes: str, federationId: str = None + self, notes: str, federation_id: str = None ) -> MintDecodeNotesResponse: - request = MintDecodeNotesRequest({"notes": notes}) + request: MintDecodeNotesRequest = {"notes": notes} return await self.client._post_with_federation_id( - "/mint/decode-notes", request, federationId + "/mint/decode-notes", request, federation_id ) async def encode_notes( - self, notes_json: NotesJson, federationId: str = None + self, notes_json: NotesJson, federation_id: str = None ) -> MintEncodeNotesResponse: - request = MintEncodeNotesRequest({"notesJsonStr": json.dumps(notes_json)}) + request: MintEncodeNotesRequest = {"notesJsonStr": json.dumps(notes_json)} return await self.client._post_with_federation_id( - "/mint/encode-notes", request, federationId + "/mint/encode-notes", request, federation_id ) async def reissue( - self, notes: str, federationId: str = None + self, notes: str, federation_id: str = None ) -> MintReissueResponse: - request = MintReissueRequest({"notes": notes}) + request: MintReissueRequest = {"notes": notes} return await self.client._post_with_federation_id( - "/mint/reissue", request, federationId + "/mint/reissue", request, federation_id ) async def spend( @@ -305,67 +341,66 @@ async def spend( allow_overpay: bool, timeout: int, include_invite: bool, - federationId: str = None, + federation_id: str = None, ) -> MintSpendResponse: - request = MintSpendRequest( - { - "amountMsat": amount_msat, - "allowOverpay": allow_overpay, - "timeout": timeout, - "includeInvite": include_invite, - } - ) + request: MintSpendRequest = { + "amountMsat": amount_msat, + "allowOverpay": allow_overpay, + "timeout": timeout, + "includeInvite": include_invite, + } return await self.client._post_with_federation_id( - "/mint/spend", request, federationId + "/mint/spend", request, federation_id ) async def validate( - self, notes: str, federationId: str = None + self, notes: str, federation_id: str = None ) -> MintValidateResponse: - request = MintValidateRequest({"notes": notes}) + request: MintValidateRequest = {"notes": notes} return await self.client._post_with_federation_id( - "/mint/validate", request, federationId + "/mint/validate", request, federation_id ) - async def split(self, notes: str, federationId: str = None): - request = MintSplitRequest({"notes": notes}) + async def split(self, notes: str, federation_id: str = None): + request: MintSplitRequest = {"notes": notes} return await self.client._post_with_federation_id( - "/mint/split", request, federationId + "/mint/split", request, federation_id ) - async def combine(self, notes_vec: List[str], federationId: str = None): - request = MintCombineRequest({"notesVec": notes_vec}) + async def combine(self, notes_vec: List[str], federation_id: str = None): + request: MintCombineRequest = {"notesVec": notes_vec} return await self.client._post_with_federation_id( - "/mint/combine", request, federationId + "/mint/combine", request, federation_id ) class Onchain: def __init__(self, client): self.client = client - async def create_deposit_address(self, timeout: int, federationId: str = None): - request = OnchainDepositAddressRequest({"timeout": timeout}) + async def create_deposit_address(self, timeout: int, federation_id: str = None): + request: OnchainDepositAddressRequest = {"timeout": timeout} return await self.client._post_with_federation_id( - "/wallet/deposit-address", request, federationId + "/wallet/deposit-address", request, federation_id ) async def await_deposit( - self, operation_id: str, federationId: str = None + self, operation_id: str, federation_id: str = None ) -> OnchainAwaitDepositResponse: - request = OnchainAwaitDepositRequest({"operationId": operation_id}) + request: OnchainAwaitDepositRequest = {"operationId": operation_id} return await self.client._post_with_federation_id( - "/wallet/await-deposit", request, federationId + "/wallet/await-deposit", request, federation_id ) async def withdraw( - self, address: str, amount_sat: int | "all", federationId: str = None + self, + address: str, + amount_sat: Union[int, Literal["all"]], + federationId: str = None, ) -> OnchainWithdrawResponse: - request = OnchainWithdrawRequest( - {"address": address, "amountSat": amount_sat} - ) + request: OnchainWithdrawRequest = { + "address": address, + "amountSat": amount_sat, + } return await self.client._post_with_federation_id( "/wallet/withdraw", request, federationId ) - - async def close(self): - await self.session.close() diff --git a/wrappers/fedimint-py/FedimintClient.py b/wrappers/fedimint-py/FedimintClient.py index fe45bf6..ecd5810 100644 --- a/wrappers/fedimint-py/FedimintClient.py +++ b/wrappers/fedimint-py/FedimintClient.py @@ -1,5 +1,6 @@ import json import logging +from typing import List, Literal, Union import requests from models.common import ( @@ -11,22 +12,20 @@ from models.lightning import ( Gateway, - LightningClaimPubkeReceivesRequest, LightningAwaitInvoiceRequest, + LightningClaimPubkeReceivesRequest, LightningCreateInvoiceRequest, LightningCreateInvoiceResponse, LightningInvoiceForPubkeyTweakRequest, LightningInvoiceForPubkeyTweakResponse, LightningPayRequest, LightningPayResponse, - LightningAwaitPayRequest, ) from models.onchain import ( OnchainAwaitDepositRequest, OnchainAwaitDepositResponse, OnchainDepositAddressRequest, - OnchainDepositAddressResponse, OnchainWithdrawRequest, OnchainWithdrawResponse, ) @@ -53,13 +52,13 @@ def __init__( self, base_url: str, password: str, - active_federationId: str, - active_gatewayId: str = None, + active_federation_id: str, + active_gateway_id: str = None, ): self.base_url = f"{base_url}/v2" self.password = password - self.active_federationId = active_federationId - self.active_gatewayId = active_gatewayId + self.active_federation_id = active_federation_id + self.active_gateway_id = active_gateway_id self.lightning = self.Lightning(self) self.onchain = self.Onchain(self) @@ -68,25 +67,25 @@ def __init__( "Initialized fedimint client, must set active gateway id after initialization to use lightning module methods or manually pass in gateways" ) - def get_active_federationId(self): - return self.active_federationId + def get_active_federation_id(self): + return self.active_federation_id - def set_active_federationId(self, federationId: str): - self.active_federationId = federationId + def set_active_federation_id(self, federation_id: str): + self.active_federation_id = federation_id - def get_active_gatewayId(self): - return self.active_gatewayId + def get_active_gateway_id(self): + return self.active_gateway_id - def set_active_gatewayId(self, gatewayId: str): - self.active_gatewayId = gatewayId + def set_active_gateway_id(self, gateway_id: str): + self.active_gateway_id = gateway_id def use_default_gateway(self): # hits list_gateways and sets active_gatewayId to the first gateway try: gateways = self.lightning.list_gateways() logging.info("Gateways: ", gateways) - self.active_gateway_id = gateways[0].info.gatewayId - logging.info("Set active gateway id to: ", self.active_gatewayId) + self.active_gateway_id = gateways[0]["info"]["gateway_id"] + logging.info("Set active gateway id to: ", self.active_gateway_id) except Exception as e: logging.error("Error setting default gateway id: ", e) @@ -114,14 +113,14 @@ def _post(self, endpoint: str, data=None): return response.json() def _post_with_federation_id( - self, endpoint: str, data=None, federationId: str = None + self, endpoint: str, data=None, federation_id: str = None ): - if federationId is None: - federationId = self.get_active_federationId() + if federation_id is None: + federation_id = self.get_active_federation_id() if data is None: data = {} - data["federationId"] = federationId + data["federationId"] = federation_id return self._post(endpoint, data) @@ -129,25 +128,24 @@ def _post_with_gateway_id_and_federation_id( self, endpoint: str, data=None, - gatewayId: str = None, - federationId: str = None, + gateway_id: str = None, + federation_id: str = None, ): + if gateway_id is None: + gateway_id = self.get_active_gateway_id() - if gatewayId is None: - gatewayId = self.get_active_gatewayId() + if federation_id is None: + federation_id = self.get_active_federation_id() - if federationId is None: - federationId = self.get_active_federationId() - - if federationId is None or gatewayId is None: + if federation_id is None or gateway_id is None: raise Exception( "Must set active gateway id and active federation id before calling this method" ) if data is None: data = {} - data["gatewayId"] = gatewayId - data["federationId"] = federationId + data["gatewayId"] = gateway_id + data["federationId"] = federation_id return self._post(endpoint, data) @@ -167,9 +165,10 @@ def federation_ids(self): def list_operations(self, request: ListOperationsRequest): return self._post_with_federation_id("/admin/list-operations", request) - def join(self, invite_code: str, set_default: bool = False): + def join(self, invite_code: str, use_manual_secret: bool = False): return self._post( - "/admin/join", {"inviteCode": invite_code, "setDefault": set_default} + "/admin/join", + {"inviteCode": invite_code, "useManualSecret": use_manual_secret}, ) class Lightning: @@ -197,6 +196,14 @@ def create_invoice( federation_id=federation_id, ) + def await_invoice( + self, operation_id: str, federation_id: str = None + ) -> InfoResponse: + request: LightningAwaitInvoiceRequest = {"operationId": operation_id} + return self.client._post_with_federation_id( + "/ln/await-invoice", request, federation_id + ) + def create_invoice_for_pubkey_tweak( self, pubkey: str, @@ -208,7 +215,7 @@ def create_invoice_for_pubkey_tweak( federation_id: str = None, ) -> LightningInvoiceForPubkeyTweakResponse: request: LightningInvoiceForPubkeyTweakRequest = { - "pubkey": pubkey, + "externalPubkey": pubkey, "tweak": tweak, "amountMsat": amount_msat, "description": description, @@ -234,16 +241,29 @@ def claim_pubkey_tweak_receives( } return self.client._post_with_federation_id( - "/ln/claim-external-pubkey-tweaked", + "/ln/claim-external-receive-tweaked", data=request, federation_id=federation_id, ) def pay( - self, request: LightningPayRequest, federationId: str = None + self, + payment_info: str, + amount_msat: int, + lightning_url_comment: str, + gateway_id: str = None, + federation_id: str = None, ) -> LightningPayResponse: + request: LightningPayRequest = { + "paymentInfo": payment_info, + "amountMsat": amount_msat, + "lightningUrlComment": lightning_url_comment, + } return self.client._post_with_gateway_id_and_federation_id( - "/ln/pay", request, federationId + "/ln/pay", + data=request, + gateway_id=gateway_id, + federation_id=federation_id, ) def list_gateways(self) -> List[Gateway]: @@ -254,26 +274,26 @@ def __init__(self, client): self.client = client def decode_notes( - self, notes: str, federationId: str = None + self, notes: str, federation_id: str = None ) -> MintDecodeNotesResponse: - request = MintDecodeNotesRequest({"notes": notes}) + request: MintDecodeNotesRequest = {"notes": notes} return self.client._post_with_federation_id( - "/mint/decode-notes", request, federationId + "/mint/decode-notes", request, federation_id ) def encode_notes( - self, notes_json: NotesJson, federationId: str = None + self, notes_json: NotesJson, federation_id: str = None ) -> MintEncodeNotesResponse: - request = MintEncodeNotesRequest({"notesJsonStr": json.dumps(notes_json)}) + request: MintEncodeNotesRequest = {"notesJsonStr": json.dumps(notes_json)} return self.client._post_with_federation_id( - "/mint/encode-notes", request, federationId + "/mint/encode-notes", request, federation_id ) - def reissue(self, notes: str, federationId: str = None) -> MintReissueResponse: - request = MintReissueRequest({"notes": notes}) + def reissue(self, notes: str, federation_id: str = None) -> MintReissueResponse: + request: MintReissueRequest = {"notes": notes} return self.client._post_with_federation_id( - "/mint/reissue", request, federationId + "/mint/reissue", request, federation_id ) def spend( @@ -282,64 +302,67 @@ def spend( allow_overpay: bool, timeout: int, include_invite: bool, - federationId: str = None, + federation_id: str = None, ) -> MintSpendResponse: - request = MintSpendRequest( - { - "amountMsat": amount_msat, - "allowOverpay": allow_overpay, - "timeout": timeout, - "includeInvite": include_invite, - } - ) + request: MintSpendRequest = { + "amountMsat": amount_msat, + "allowOverpay": allow_overpay, + "timeout": timeout, + "includeInvite": include_invite, + } + return self.client._post_with_federation_id( - "/mint/spend", request, federationId + "/mint/spend", request, federation_id ) def validate( - self, notes: str, federationId: str = None + self, notes: str, federation_id: str = None ) -> MintValidateResponse: - request = MintValidateRequest({"notes": notes}) + request: MintValidateRequest = {"notes": notes} return self.client._post_with_federation_id( - "/mint/validate", request, federationId + "/mint/validate", request, federation_id ) - def split(self, notes: str, federationId: str = None): - request = MintSplitRequest({"notes": notes}) + def split(self, notes: str, federation_id: str = None): + request: MintSplitRequest = {"notes": notes} return self.client._post_with_federation_id( - "/mint/split", request, federationId + "/mint/split", request, federation_id ) - def combine(self, notes_vec: List[str], federationId: str = None): - request = MintCombineRequest({"notesVec": notes_vec}) + def combine(self, notes_vec: List[str], federation_id: str = None): + request: MintCombineRequest = {"notesVec": notes_vec} return self.client._post_with_federation_id( - "/mint/combine", request, federationId + "/mint/combine", request, federation_id ) class Onchain: def __init__(self, client): self.client = client - def create_deposit_address(self, timeout: int, federationId: str = None): - request = OnchainDepositAddressRequest({"timeout": timeout}) + def create_deposit_address(self, timeout: int, federation_id: str = None): + request: OnchainDepositAddressRequest = {"timeout": timeout} return self.client._post_with_federation_id( - "/wallet/deposit-address", request, federationId + "/wallet/deposit-address", request, federation_id ) def await_deposit( - self, operation_id: str, federationId: str = None + self, operation_id: str, federation_id: str = None ) -> OnchainAwaitDepositResponse: - request = OnchainAwaitDepositRequest({"operationId": operation_id}) + request: OnchainAwaitDepositRequest = {"operationId": operation_id} return self.client._post_with_federation_id( - "/wallet/await-deposit", request, federationId + "/wallet/await-deposit", request, federation_id ) def withdraw( - self, address: str, amount_sat: int | "all", federationId: str = None + self, + address: str, + amount_sat: Union[int, Literal["all"]], + federation_id: str = None, ) -> OnchainWithdrawResponse: - request = OnchainWithdrawRequest( - {"address": address, "amountSat": amount_sat} - ) + request: OnchainWithdrawRequest = { + "address": address, + "amountSat": amount_sat, + } return self.client._post_with_federation_id( - "/wallet/withdraw", request, federationId + "/wallet/withdraw", request, federation_id ) diff --git a/wrappers/fedimint-py/models/common.py b/wrappers/fedimint-py/models/common.py index 71142e8..3268185 100644 --- a/wrappers/fedimint-py/models/common.py +++ b/wrappers/fedimint-py/models/common.py @@ -2,8 +2,7 @@ from typing import List, Optional, Dict, Any -class Tiered(RootModel): - root: Dict[int, Any] +Tiered = RootModel[Dict[int, Any]] class TieredSummary(BaseModel): @@ -18,8 +17,7 @@ class FederationInfo(BaseModel): denominationsMsat: TieredSummary -class InfoResponse(BaseModel): - __root__: Dict[str, FederationInfo] +InfoResponse = RootModel[Dict[str, FederationInfo]] class BackupRequest(BaseModel): @@ -43,8 +41,7 @@ class DiscoverVersionRequest(BaseModel): # Returns a dictionary of federation_ids and their api versions -class DiscoverVersionResponse(BaseModel): - __root__: Dict[str, Any] +DiscoverVersionResponse = RootModel[Dict[str, Any]] class JoinRequest(BaseModel): diff --git a/wrappers/fedimint-py/models/onchain.py b/wrappers/fedimint-py/models/onchain.py index 8481e78..53d1482 100644 --- a/wrappers/fedimint-py/models/onchain.py +++ b/wrappers/fedimint-py/models/onchain.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Union +from typing import Dict, List, Literal, Union from pydantic import BaseModel @@ -45,7 +45,7 @@ class OnchainAwaitDepositResponse(BaseModel): class OnchainWithdrawRequest(BaseModel): address: str - amount_sat: int | "all" + amount_sat: Union[int, Literal["all"]] class OnchainWithdrawResponse(BaseModel): diff --git a/wrappers/fedimint-py/requirements.txt b/wrappers/fedimint-py/requirements.txt index f229360..570fdd0 100644 --- a/wrappers/fedimint-py/requirements.txt +++ b/wrappers/fedimint-py/requirements.txt @@ -1 +1 @@ -requests +requests coincurve diff --git a/wrappers/fedimint-py/test.py b/wrappers/fedimint-py/test.py index 6345b55..46fcd06 100644 --- a/wrappers/fedimint-py/test.py +++ b/wrappers/fedimint-py/test.py @@ -1,6 +1,6 @@ import os from coincurve import PrivateKey -from wrappers.fedimint_py.FedimintClient import FedimintClient +from FedimintClient import FedimintClient def log_method(method: str): @@ -30,7 +30,7 @@ def build_test_client(): client = FedimintClient(base_url, password, active_federation_id) client.use_default_gateway() - print("Default gateway id: ", client.get_active_gatewayId()) + print("Default gateway id: ", client.get_active_gateway_id()) return client @@ -40,104 +40,119 @@ def main(): print("Generated key pair: ", key_pair) # ADMIN METHODS - # `/v2/admin/config` log_method("/v2/admin/config") data = fedimint_client.config() log_input_and_output({}, data) - # `/v2/admin/discover-version` + log_method("/v2/admin/discover-version") - data = fedimint_client.discover_version( - 1 - ) # Assuming threshold is required, adjust as needed + data = fedimint_client.discover_version(1) log_input_and_output({}, data) - # `/v2/admin/federation-ids` + log_method("/v2/admin/federation-ids") data = fedimint_client.federation_ids() log_input_and_output({}, data) - # `/v2/admin/info` + log_method("/v2/admin/info") data = fedimint_client.info() log_input_and_output({}, data) - # `/v2/admin/join` - invite_code = os.getenv("INVITE_CODE", "your_invite_code_here") + + invite_code = os.getenv( + "INVITE_CODE", + "fed11qgqrgvnhwden5te0v9k8q6rp9ekh2arfdeukuet595cr2ttpd3jhq6rzve6zuer9wchxvetyd938gcewvdhk6tcqqysptkuvknc7erjgf4em3zfh90kffqf9srujn6q53d6r056e4apze5cw27h75", + ) log_method("/v2/admin/join") - data = fedimint_client.join(invite_code, True) + data = fedimint_client.join(invite_code, False) log_input_and_output({"inviteCode": invite_code}, data) - # `/v2/admin/list-operations` + log_method("/v2/admin/list-operations") - data = fedimint_client.list_operations( - {"limit": 10} - ) # Adjust the request as needed + data = fedimint_client.list_operations({"limit": 10}) log_input_and_output({"limit": 10}, data) # LIGHTNING METHODS - # `/v2/ln/list-gateways` log_method("/v2/ln/list-gateways") data = fedimint_client.lightning.list_gateways() log_input_and_output({}, data) - # `/v2/ln/invoice` + log_method("/v2/ln/invoice") data = fedimint_client.lightning.create_invoice(10000, "test") log_input_and_output({"amountMsat": 10000, "description": "test"}, data) - # `/v2/ln/pay` + log_method("/v2/ln/pay") - pay_response = fedimint_client.lightning.pay( - {"invoice": data.invoice} - ) # Adjust the request as needed - log_input_and_output({"paymentInfo": data.invoice}, pay_response) - # `/v2/ln/await-invoice` + pay_response = fedimint_client.lightning.pay(data["invoice"], None, None) + log_input_and_output({"paymentInfo": data["invoice"]}, pay_response) + log_method("/v2/ln/await-invoice") - data = fedimint_client.lightning.await_invoice( - {"operationId": data.operation_id} - ) # Adjust the request as needed - log_input_and_output({"operationId": data.operation_id}, data) + pay_data = fedimint_client.lightning.await_invoice(data["operationId"]) + log_input_and_output({"operationId": data["operationId"]}, pay_data) + + log_method("/v2/ln/create-invoice-for-pubkey-tweaked") + data = fedimint_client.lightning.create_invoice_for_pubkey_tweak( + pubkey=key_pair["publicKey"], tweak=1, amount_msat=1000, description="test" + ) + log_input_and_output( + { + "pubkey": key_pair["publicKey"], + "tweak": 1, + "amountMsat": 1000, + "description": "test", + }, + data, + ) + + fedimint_client.lightning.pay(data["invoice"], None, None) + print("Paid locked invoice!") + + log_method("/v2/ln/claim-external-receive-tweaked") + data = fedimint_client.lightning.claim_pubkey_tweak_receives( + private_key=key_pair["privateKey"], + tweaks=[1], + federation_id=fedimint_client.get_active_federation_id(), + ) + log_input_and_output({"privateKey": key_pair["privateKey"], "tweaks": [1]}, data) # MINT METHODS - # `/v2/mint/spend` log_method("/v2/mint/spend") mint_data = fedimint_client.mint.spend(3000, True, 1000, False) log_input_and_output({"allowOverpay": True, "timeout": 1000}, mint_data) - # `/v2/mint/decode-notes` + log_method("/v2/mint/decode-notes") - data = fedimint_client.mint.decode_notes(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) - # `/v2/mint/encode-notes` + data = fedimint_client.mint.decode_notes(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) + log_method("/v2/mint/encode-notes") - data = fedimint_client.mint.encode_notes(data.notes_json) - log_input_and_output({"notesJson": data.notes_json}, data) - # `/v2/mint/validate` + data = fedimint_client.mint.encode_notes(data["notesJson"]) + log_input_and_output({"notesJson": data}, data) + log_method("/v2/mint/validate") - data = fedimint_client.mint.validate(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) - # `/v2/mint/reissue` + data = fedimint_client.mint.validate(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) + log_method("/v2/mint/reissue") - data = fedimint_client.mint.reissue(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) - # `/v2/mint/split` + data = fedimint_client.mint.reissue(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) + log_method("/v2/mint/split") - data = fedimint_client.mint.split(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) - # `/v2/mint/combine` + data = fedimint_client.mint.split(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) + log_method("/v2/mint/combine") - notes_vec = [data.notes] # Assuming `data.notes` is correct, adjust as needed - data = fedimint_client.mint.combine(notes_vec) - log_input_and_output({"notesVec": notes_vec}, data) + notes_vec = [data["notes"]] + notes_values_vec = [ + value for note_dict in notes_vec for value in note_dict.values() + ] + data = fedimint_client.mint.combine(notes_values_vec) + log_input_and_output({"notesVec": notes_values_vec}, data) # ONCHAIN METHODS - # `/v2/onchain/deposit-address` log_method("/v2/onchain/deposit-address") data = fedimint_client.onchain.create_deposit_address(1000) log_input_and_output({"timeout": 1000}, data) - # `/v2/onchain/withdraw` log_method("/v2/onchain/withdraw") - data = fedimint_client.onchain.withdraw(data.address, 1000) - log_input_and_output({"address": data.address, "amountSat": 1000}, data) - # `/v2/onchain/await-deposit` - # This method might be commented out or not implemented in the original script. Adjust as needed. + withdraw_data = fedimint_client.onchain.withdraw(data["address"], 1000) + log_input_and_output({"address": data["address"], "amountSat": 1000}, withdraw_data) print("Done: All methods tested successfully!") -# Run the main function if __name__ == "__main__": main() diff --git a/wrappers/fedimint-py/test_async.py b/wrappers/fedimint-py/test_async.py index 89ee4dc..cfdbee8 100644 --- a/wrappers/fedimint-py/test_async.py +++ b/wrappers/fedimint-py/test_async.py @@ -31,7 +31,7 @@ async def build_test_client(): client = AsyncFedimintClient(base_url, password, active_federation_id) await client.use_default_gateway() - print("Default gateway id: ", client.get_active_gatewayId()) + print("Default gateway id: ", client.get_active_gateway_id()) return client @@ -44,7 +44,7 @@ async def main(): # `/v2/admin/config` log_method("/v2/admin/config") data = await fedimint_client.config() - log_input_and_output({}, data) + # log_input_and_output({}, data) # `/v2/admin/discover-version` log_method("/v2/admin/discover-version") data = await fedimint_client.discover_version( @@ -60,15 +60,16 @@ async def main(): data = await fedimint_client.info() log_input_and_output({}, data) # `/v2/admin/join` - invite_code = os.getenv("INVITE_CODE", "your_invite_code_here") + invite_code = os.getenv( + "INVITE_CODE", + "fed11qgqrgvnhwden5te0v9k8q6rp9ekh2arfdeukuet595cr2ttpd3jhq6rzve6zuer9wchxvetyd938gcewvdhk6tcqqysptkuvknc7erjgf4em3zfh90kffqf9srujn6q53d6r056e4apze5cw27h75", + ) log_method("/v2/admin/join") - data = await fedimint_client.join(invite_code, True) + data = await fedimint_client.join(invite_code, False) log_input_and_output({"inviteCode": invite_code}, data) # `/v2/admin/list-operations` log_method("/v2/admin/list-operations") - data = await fedimint_client.list_operations( - {"limit": 10} - ) # Adjust the request as needed + data = await fedimint_client.list_operations({"limit": 10}) log_input_and_output({"limit": 10}, data) # LIGHTNING METHODS @@ -82,16 +83,41 @@ async def main(): log_input_and_output({"amountMsat": 10000, "description": "test"}, data) # `/v2/ln/pay` log_method("/v2/ln/pay") - pay_response = await fedimint_client.lightning.pay( - {"invoice": data.invoice} - ) # Adjust the request as needed - log_input_and_output({"paymentInfo": data.invoice}, pay_response) + pay_response = await fedimint_client.lightning.pay(data["invoice"], None, None) + log_input_and_output({"paymentInfo": data["invoice"]}, pay_response) # `/v2/ln/await-invoice` log_method("/v2/ln/await-invoice") - data = await fedimint_client.lightning.await_invoice( - {"operationId": data.operation_id} - ) # Adjust the request as needed - log_input_and_output({"operationId": data.operation_id}, data) + pay_data = await fedimint_client.lightning.await_invoice(data["operationId"]) + log_input_and_output({"operationId": data["operationId"]}, pay_data) + + # LIGHTNING METHODS FOR PUBKEY TWEAK + # `/v2/ln/create-invoice-for-pubkey-tweaked` + log_method("/v2/ln/create-invoice-for-pubkey-tweaked") + data = await fedimint_client.lightning.create_invoice_for_pubkey_tweak( + pubkey=key_pair["publicKey"], tweak=1, amount_msat=1000, description="test" + ) + log_input_and_output( + { + "pubkey": key_pair["publicKey"], + "tweak": 1, + "amountMsat": 1000, + "description": "test", + }, + data, + ) + + # Pay the invoice + fedimint_client.lightning.pay(data["invoice"], None, None) + print("Paid locked invoice!") + + # `/v2/ln/claim-external-pubkey-tweaked` + log_method("/v2/ln/claim-external-pubkey-tweaked") + data = await fedimint_client.lightning.claim_pubkey_tweak_receives( + private_key=key_pair["privateKey"], + tweaks=[1], + federation_id=fedimint_client.get_active_federation_id(), + ) + log_input_and_output({"privateKey": key_pair["privateKey"], "tweaks": [1]}, data) # MINT METHODS # `/v2/mint/spend` @@ -100,44 +126,51 @@ async def main(): log_input_and_output({"allowOverpay": True, "timeout": 1000}, mint_data) # `/v2/mint/decode-notes` log_method("/v2/mint/decode-notes") - data = await fedimint_client.mint.decode_notes(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) + data = await fedimint_client.mint.decode_notes(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) # `/v2/mint/encode-notes` log_method("/v2/mint/encode-notes") - data = await fedimint_client.mint.encode_notes(data.notes_json) - log_input_and_output({"notesJson": data.notes_json}, data) + data = await fedimint_client.mint.encode_notes(data["notesJson"]) + log_input_and_output({"notesJson": data}, data) # `/v2/mint/validate` log_method("/v2/mint/validate") - data = await fedimint_client.mint.validate(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) + data = await fedimint_client.mint.validate(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) # `/v2/mint/reissue` log_method("/v2/mint/reissue") - data = await fedimint_client.mint.reissue(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) + data = await fedimint_client.mint.reissue(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) # `/v2/mint/split` log_method("/v2/mint/split") - data = await fedimint_client.mint.split(mint_data.notes) - log_input_and_output({"notes": mint_data.notes}, data) + data = await fedimint_client.mint.split(mint_data["notes"]) + log_input_and_output({"notes": mint_data["notes"]}, data) # `/v2/mint/combine` log_method("/v2/mint/combine") - notes_vec = [data.notes] # Assuming `data.notes` is correct, adjust as needed - data = await fedimint_client.mint.combine(notes_vec) - log_input_and_output({"notesVec": notes_vec}, data) + notes_vec = [data["notes"]] + print("notes_vec: ", notes_vec) + notes_values_vec = [ + value for note_dict in notes_vec for value in note_dict.values() + ] + data = await fedimint_client.mint.combine(notes_values_vec) + log_input_and_output({"notesVec": notes_values_vec}, data) # ONCHAIN METHODS # `/v2/onchain/deposit-address` log_method("/v2/onchain/deposit-address") data = await fedimint_client.onchain.create_deposit_address(1000) + print("data: ", data) log_input_and_output({"timeout": 1000}, data) # `/v2/onchain/withdraw` log_method("/v2/onchain/withdraw") - data = await fedimint_client.onchain.withdraw(data.address, 1000) - log_input_and_output({"address": data.address, "amountSat": 1000}, data) + withdraw_data = await fedimint_client.onchain.withdraw(data["address"], 1000) + log_input_and_output({"address": data["address"], "amountSat": 1000}, data) # `/v2/onchain/await-deposit` - # This method might be commented out or not implemented in the original script. Adjust as needed. + # this blocks for 10 minutes so it's not a good test print("Done: All methods tested successfully!") + await fedimint_client.close() + # Run the main function asyncio.run(main())