|
|
|
|
@ -2,7 +2,7 @@ import asyncio
|
|
|
|
|
import urllib |
|
|
|
|
import re |
|
|
|
|
from decimal import Decimal, InvalidOperation |
|
|
|
|
from typing import NamedTuple, Optional, Callable, Any, Sequence |
|
|
|
|
from typing import NamedTuple, Optional, Callable, Any, Sequence, List |
|
|
|
|
from urllib.parse import urlparse |
|
|
|
|
|
|
|
|
|
from . import bitcoin |
|
|
|
|
@ -16,6 +16,7 @@ from .bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC, opcodes, construct_sc
|
|
|
|
|
from .lnaddr import lndecode, LnDecodeException, LnInvoiceException |
|
|
|
|
from .lnutil import IncompatibleOrInsaneFeatures |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def maybe_extract_lightning_payment_identifier(data: str) -> Optional[str]: |
|
|
|
|
data = data.strip() # whitespaces |
|
|
|
|
data = data.lower() |
|
|
|
|
@ -36,7 +37,8 @@ BITCOIN_BIP21_URI_SCHEME = 'bitcoin'
|
|
|
|
|
LIGHTNING_URI_SCHEME = 'lightning' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidBitcoinURI(Exception): pass |
|
|
|
|
class InvalidBitcoinURI(Exception): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_bip21_URI(uri: str) -> dict: |
|
|
|
|
@ -122,7 +124,6 @@ def parse_bip21_URI(uri: str) -> dict:
|
|
|
|
|
return out |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_bip21_uri(addr, amount_sat: Optional[int], message: Optional[str], |
|
|
|
|
*, extra_query_params: Optional[dict] = None) -> str: |
|
|
|
|
if not bitcoin.is_address(addr): |
|
|
|
|
@ -145,12 +146,11 @@ def create_bip21_uri(addr, amount_sat: Optional[int], message: Optional[str],
|
|
|
|
|
path=addr, |
|
|
|
|
params='', |
|
|
|
|
query='&'.join(query), |
|
|
|
|
fragment='', |
|
|
|
|
fragment='' |
|
|
|
|
) |
|
|
|
|
return str(urllib.parse.urlunparse(p)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_uri(data: str) -> bool: |
|
|
|
|
data = data.lower() |
|
|
|
|
if (data.startswith(LIGHTNING_URI_SCHEME + ":") or |
|
|
|
|
@ -159,19 +159,21 @@ def is_uri(data: str) -> bool:
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FailedToParsePaymentIdentifier(Exception): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PayToLineError(NamedTuple): |
|
|
|
|
line_content: str |
|
|
|
|
exc: Exception |
|
|
|
|
idx: int = 0 # index of line |
|
|
|
|
is_multiline: bool = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RE_ALIAS = r'(.*?)\s*\<([0-9A-Za-z]{1,})\>' |
|
|
|
|
RE_EMAIL = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PaymentIdentifier(Logger): |
|
|
|
|
""" |
|
|
|
|
Takes: |
|
|
|
|
@ -502,7 +504,7 @@ class PaymentIdentifier(Logger):
|
|
|
|
|
on_success(self) |
|
|
|
|
|
|
|
|
|
@log_exceptions |
|
|
|
|
async def round_2(self, on_success, amount_sat:int=None, comment=None): |
|
|
|
|
async def round_2(self, on_success, amount_sat: int = None, comment: str = None): |
|
|
|
|
from .invoices import Invoice |
|
|
|
|
if self.lnurl: |
|
|
|
|
if not (self.lnurl_data.min_sendable_sat <= amount_sat <= self.lnurl_data.max_sendable_sat): |
|
|
|
|
|