diff --git a/nostr_dvm/utils/cashu_utils.py b/nostr_dvm/utils/cashu_utils.py index 8a473e2..2f4a2a5 100644 --- a/nostr_dvm/utils/cashu_utils.py +++ b/nostr_dvm/utils/cashu_utils.py @@ -1,15 +1,54 @@ import base64 import json + +import httpx import requests +from cashu.core.models import GetInfoResponse, MintMeltMethodSetting +from cashu.mint.ledger import Ledger +from cashu.nostr.key import PublicKey, PrivateKey +from cashu.wallet.wallet import Wallet + from nostr_dvm.utils.database_utils import get_or_add_user from nostr_dvm.utils.zap_utils import create_bolt11_ln_bits, create_bolt11_lud16 +BASE_URL = "https://mint.minibits.cash/Bitcoin" + + +async def test_create_p2pk_pubkey(wallet1: Wallet): + invoice = await wallet1.request_mint(64) + # await pay_if_regtest(invoice.bolt11) + await wallet1.mint(64, id=invoice.id) + pubkey = await wallet1.create_p2pk_pubkey() + PublicKey(bytes.fromhex(pubkey), raw=True) + + +async def cashu_wallet(): + wallet1 = await Wallet.with_db( + url=BASE_URL, + db="db/Cashu", + name="wallet_mint_api", + ) + await wallet1.load_mint() + return wallet1 + + +async def test_info(ledger: Ledger): + response = httpx.get(f"{BASE_URL}/v1/info") + assert response.status_code == 200, f"{response.url} {response.status_code}" + assert ledger.pubkey + assert response.json()["pubkey"] == ledger.pubkey.serialize().hex() + info = GetInfoResponse(**response.json()) + assert info.nuts + assert info.nuts[4]["disabled"] is False + setting = MintMeltMethodSetting.parse_obj(info.nuts[4]["methods"][0]) + assert setting.method == "bolt11" + assert setting.unit == "sat" + async def get_cashu_balance(url): from cashu.wallet.wallet import Wallet from cashu.core.settings import settings - settings.tor = False wallet = await Wallet.with_db( url=url, @@ -17,7 +56,7 @@ async def get_cashu_balance(url): ) await wallet.load_mint() await wallet.load_proofs() - print("Cashu Wallet balance " + str(wallet.available_balance) + " sats") + print("Cashu Wallet balance " + str(wallet.available_balance) + " sats") mint_balances = await wallet.balance_per_minturl() print(mint_balances) @@ -26,7 +65,6 @@ async def mint_cashu_test(url, amount): from cashu.wallet.wallet import Wallet from cashu.core.settings import settings - settings.tor = False wallet = await Wallet.with_db( url=url, @@ -39,7 +77,7 @@ async def mint_cashu_test(url, amount): print(mint_balances) # mint tokens into wallet, skip if wallet already has funds - #if wallet.available_balance <= 10: + # if wallet.available_balance <= 10: # invoice = await wallet.request_mint(amount) # input(f"Pay this invoice and press any button: {invoice.bolt11}\n") # await wallet.mint(amount, id=invoice.id) @@ -50,6 +88,7 @@ async def mint_cashu_test(url, amount): print(token_str) return token_str + async def receive_cashu_test(token_str): from cashu.wallet.wallet import Wallet from cashu.core.settings import settings @@ -69,7 +108,6 @@ async def receive_cashu_test(token_str): print(f"Wallet balance: {wallet.available_balance} sats") - try: await wallet.redeem(token.token[0].proofs) print(f"Wallet balance: {wallet.available_balance} sats") @@ -77,10 +115,6 @@ async def receive_cashu_test(token_str): print(e) - - - - def parse_cashu(cashu_token: str): try: prefix = "cashuA" @@ -99,7 +133,6 @@ def parse_cashu(cashu_token: str): for proof in proofs: total_amount += proof["amount"] - return proofs, mint, total_amount, None except Exception as e: @@ -122,7 +155,7 @@ async def redeem_cashu(cashu, config, client, required_amount=0, update_self=Fal else: user = await get_or_add_user(db=config.DB, npub=config.PUBLIC_KEY, - client=client, config=config, update=update_self) + client=client, config=config, update=update_self) invoice = create_bolt11_lud16(user.lud16, estimated_redeem_invoice_amount) print(invoice) if invoice is None: @@ -136,7 +169,7 @@ async def redeem_cashu(cashu, config, client, required_amount=0, update_self=Fal tree = json.loads(request.text) fees = tree["fee"] print("Fees on this mint are " + str(fees) + " Sats") - redeem_invoice_amount = total_amount -fees + redeem_invoice_amount = total_amount - fees if redeem_invoice_amount < required_amount: err = ("Token value (Payment: " + str(total_amount) + " Sats. Fees: " + str(fees) + " Sats) below required amount of " + str(required_amount) @@ -149,7 +182,7 @@ async def redeem_cashu(cashu, config, client, required_amount=0, update_self=Fal else: user = await get_or_add_user(db=config.DB, npub=config.PUBLIC_KEY, - client=client, config=config, update=update_self) + client=client, config=config, update=update_self) invoice = create_bolt11_lud16(user.lud16, redeem_invoice_amount) print(invoice) diff --git a/tests/discovery.py b/tests/discovery.py index 7bb8d18..2c566f3 100644 --- a/tests/discovery.py +++ b/tests/discovery.py @@ -41,7 +41,10 @@ log_level = LogLevel.ERROR RECONCILE_DB_RELAY_LIST = [ "wss://relay.nostr.net", "wss://relay.nostr.bg", "wss://relay.damus.io", "wss://nostr.oxtr.dev"] - +RELAY_LIST = ["wss://relay.primal.net", + "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg", + "wss://relay.nostr.net" + ] if use_logger: init_logger(log_level) @@ -56,6 +59,7 @@ def build_db_scheduler(name, identifier, admin_config, options, image, descripti dvm_config.UPDATE_DATABASE = update_db dvm_config.LOGLEVEL = LogLevel.INFO dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST # Activate these to use a subscription based model instead # dvm_config.SUBSCRIPTION_REQUIRED = True @@ -102,6 +106,7 @@ def build_example_gallery(name, identifier, admin_config, options, image, cost=0 dvm_config.UPDATE_DATABASE = update_db dvm_config.LOGLEVEL = LogLevel.DEBUG dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg admin_config.LUD16 = dvm_config.LN_ADDRESS @@ -139,6 +144,7 @@ def build_example_nostrband(name, identifier, admin_config, image, about, custom dvm_config.USE_OWN_VENV = False dvm_config.CUSTOM_PROCESSING_MESSAGE = custom_processing_msg dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST dvm_config.LOGLEVEL = LogLevel.INFO #dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", # "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg" @@ -173,6 +179,7 @@ def build_longform(name, identifier, admin_config, options, cost=0, update_rate= dvm_config.UPDATE_DATABASE = update_db dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST dvm_config.LOGLEVEL = LogLevel.INFO # Activate these to use a subscription based model instead # dvm_config.SUBSCRIPTION_REQUIRED = True @@ -224,6 +231,7 @@ def build_wiki(name, identifier, admin_config, options, cost=0, update_rate=180, dvm_config.UPDATE_DATABASE = update_db dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST dvm_config.LOGLEVEL = LogLevel.INFO # Activate these to use a subscription based model instead # dvm_config.SUBSCRIPTION_REQUIRED = True @@ -277,6 +285,7 @@ def build_example_topic(name, identifier, admin_config, options, image, descript dvm_config.LOGLEVEL = LogLevel.INFO dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST #dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", # "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg" # ] @@ -323,6 +332,7 @@ def build_example_popular(name, identifier, admin_config, options, image, cost=0 #"wss://relay.nostr.net"] dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST #dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", # "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg" # ] @@ -366,6 +376,7 @@ def build_example_popular_followers(name, identifier, admin_config, options, ima dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST #dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", # "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg" # ] @@ -413,6 +424,7 @@ def build_example_popular_non_followers(name, identifier, admin_config, options, dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST dvm_config.SUBSCRIPTION_REQUIRED = True admin_config.LUD16 = dvm_config.LN_ADDRESS admin_config.REBROADCAST_NIP88 = False @@ -478,6 +490,7 @@ def build_example_top_zapped(name, identifier, admin_config, options, image, cos dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST + dvm_config.RELAY_LIST = RELAY_LIST #dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", # "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg" # ] @@ -523,6 +536,7 @@ def build_example_mostr(name, identifier, admin_config, options, image, cost=0, # dvm_config.SHOWLOG = True dvm_config.SCHEDULE_UPDATES_SECONDS = update_rate # Every 10 minutes dvm_config.UPDATE_DATABASE = update_db + dvm_config.RELAY_LIST = RELAY_LIST dvm_config.RECONCILE_DB_RELAY_LIST = ["wss://nfrelay.app/?user=activitypub"] dvm_config.LOGLEVEL = LogLevel.DEBUG diff --git a/tests/search.py b/tests/search.py index e37e53f..92d6b5f 100644 --- a/tests/search.py +++ b/tests/search.py @@ -27,10 +27,16 @@ if use_logger: init_logger(log_level) +RELAY_LIST = ["wss://relay.primal.net", + "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg", + "wss://relay.nostr.net" + ] + def build_advanced_search(name, identifier): dvm_config = DVMConfig() dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) npub = Keys.parse(dvm_config.PRIVATE_KEY).public_key().to_bech32() + dvm_config.RELAY_LIST = RELAY_LIST invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys(identifier, npub) dvm_config.LNBITS_INVOICE_KEY = invoice_key dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back @@ -84,6 +90,7 @@ def build_advanced_search_wine(name, identifier): dvm_config = DVMConfig() dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) npub = Keys.parse(dvm_config.PRIVATE_KEY).public_key().to_bech32() + dvm_config.RELAY_LIST = RELAY_LIST invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys(identifier, npub) dvm_config.LNBITS_INVOICE_KEY = invoice_key dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back @@ -140,6 +147,7 @@ def build_user_search(name, identifier): dvm_config = build_default_config(identifier) dvm_config.RECONCILE_DB_RELAY_LIST = ["wss://relay.damus.io"] npub = Keys.parse(dvm_config.PRIVATE_KEY).public_key().to_bech32() + dvm_config.RELAY_LIST = RELAY_LIST invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys(identifier, npub) admin_config = AdminConfig() admin_config.REBROADCAST_NIP89 = rebroadcast_NIP89