Skip to main content

Address Parser

swapper.Utils.parseAddress() & swapper.Utils.parseAddressSync() are the SDK's unified parsers for user-entered destination and source fields. It is useful anywhere you accept free-form input before calling swapper.swap(...), because the same field may contain a Bitcoin address, a BOLT11 invoice, an LNURL, a Lightning address, or a smart chain address.

The parsers recognize:

  • Bitcoin on-chain addresses and bitcoin: BIP-21 URIs
  • BOLT11 Lightning invoices with an embedded amount, including lightning:-prefixed invoice strings
  • LNURL-pay links (LUD-6), in both: bech32 lnurl1... form & raw lnurlp://... form (LUD-17)
  • Lightning addresses (LUD-16)
  • LNURL-withdraw link (LUD-3), in both: bech32 lnurl1... form & raw lnurlw://... form (LUD-17)
  • Smart chain addresses for the chains configured in your swapper instance

Parsing User Input

The SDK exposes two parser variants:

  • an async parseAddress() which parses the address and in case of LNURLs also fetches the LNURL metadata so it can resolve LNURL-pay vs LNURL-withdraw and return amount limits.
  • a synchronous parseAddressSync() which parses the address data, but it does not fetch LNURL metadata and therefore cannot fully resolve LNURL inputs on its own.
tip

You can use synchronous parseAddressSync() in case you don't want support for LNURL links to prevent any hassle for handling an async address parser.

In case you want to support LNURL links the common pattern is to use the sync parser while the user is typing then run the async parseAddress() parser on blur, paste or submit before you create a quote.

Use the async parseAddress() helper when you need the final normalized result for quoting or execution. This is the variant you should use when the input may be an LNURL or Lightning address, because it fetches LNURL metadata and resolves whether the destination is LNURL-pay or LNURL-withdraw.

const parsed = await swapper.Utils.parseAddress(userInput);

if (parsed == null) {
throw new Error("Unsupported address format");
}

switch (parsed.type) {
case "BITCOIN":
console.log("Bitcoin destination:", parsed.address);
console.log("Optional amount from BIP-21:", parsed.amount?.toString());
break;
case "LIGHTNING":
console.log("Lightning invoice amount:", parsed.amount?.toString());
break;
case "LNURL":
if (parsed.lnurl.type === "pay") {
console.log("LNURL-pay / Lightning address");
console.log("Min:", parsed.min?.toString());
console.log("Max:", parsed.max?.toString());
console.log("Fixed amount:", parsed.amount?.toString());
}
if (parsed.lnurl.type === "withdraw") {
console.log("LNURL-withdraw");
console.log("Min:", parsed.min?.toString());
console.log("Max:", parsed.max?.toString());
console.log("Fixed amount:", parsed.amount?.toString());
}
break;
default:
console.log("Smart chain address on:", parsed.type); // e.g. SOLANA, STARKNET, CITREA
}

Parsed Result

Both parsers return a normalized object with the following fields:

ParameterTypeDescription
addressstringNormalized address or identifier recognized by the parser. For bitcoin: or lightning: inputs this is returned without the scheme prefix.
type"BITCOIN" | "LIGHTNING" | "LNURL" | "SOLANA" | "STARKNET" ...The detected address family, or the smart-chain identifier for supported smart-chain addresses.
swapTypeSwapType or nullThe swap direction inferred from the input format when possible, for example Bitcoin on-chain for TO_BTC, Lightning payout for TO_BTCLN, or LNURL-withdraw source for FROM_BTCLN.
amount?TokenAmountFixed amount encoded in a BIP-21 URI, BOLT11 invoice or fixed-amount LNURL.
min?TokenAmountMinimum amount allowed by a variable-amount LNURL. This is only populated by the async parser when the input is LNURL-based.
max?TokenAmountMaximum amount allowed by a variable-amount LNURL. This is only populated by the async parser when the input is LNURL-based.
lnurl?LNURLPay or LNURLWithdrawResolved LNURL metadata. This is only populated by the async parser when the input is LNURL-based.

Address Types

Bitcoin and BIP-21

Bitcoin addresses and bitcoin: payment URIs are parsed as type === "BITCOIN". This is the format you typically use as the destination in Smart Chain → BTC/Lightning swaps.

If the user pastes a BIP-21 URI with an amount, that amount is returned as parsed.amount, which is useful for pre-filling an EXACT_OUT quote.

const parsed = await swapper.Utils.parseAddress(
"bitcoin:bc1q...?amount=0.0001"
);

if (parsed?.type === "BITCOIN") {
console.log("Destination address:", parsed.address);
console.log("Requested BTC amount:", parsed.amount?.toString());
}
info

If you only need to check whether a given string is a bitcoin address use isValidBitcoinAddress() instead of the general parser.

Lightning Invoices

warning

Lightning invoices without an amount are not accepted by parseAddress(), as the Smart Chain → Lightning swap requires the use of fixed amount invoices.

BOLT11 invoices (also the ones prefixed with lightning: deeplink) are parsed as type === "LIGHTNING". With the invoice amount returned in parsed.amount.

const parsed = await swapper.Utils.parseAddress("lnbc1000n1...");

if (parsed?.type === "LIGHTNING") {
console.log("Invoice amount:", parsed.amount.toString());
}
tip

If your UI needs to distinguish between "syntactically valid invoice" and "invoice valid for swap creation", use both helpers:

  • isLightningInvoice() checks whether the string is a valid BOLT11 invoice at all.
  • isValidLightningInvoice() checks whether the invoice also contains an amount and is therefore usable for creating Smart Chain → Lightning swaps.

LNURLs and Lightning Addresses

LNURL links and Lightning addresses (also with lightning: deeplink prefix) are parsed as type === "LNURL". The parser accepts both, the bech32 & raw url encoding format for LNURLs.

To fetch the type and amounts of the LNURL you have to use the asynchronous parseAddress() parser, as it has to fetch the LNURL metadata from the LNURL-service. The amounts are returned as:

  • parsed.amount when the LNURL has a fixed amount
  • parsed.min and parsed.max when the amount is user-selectable

And the LNURL types (withdraw or pay):

// Also supports lightning addresses "[email protected]" and raw "lnurlp://" links.
const parsed = await swapper.Utils.parseAddress("lnurl1...");

if (parsed?.type === "LNURL" && parsed.lnurl.type === "pay") {
console.log("Min payable:", parsed.min?.toString());
console.log("Max payable:", parsed.max?.toString());
console.log("Fixed amount:", parsed.amount?.toString());
console.log("Comment limit:", parsed.lnurl.commentMaxLength);
console.log("Short description:", parsed.lnurl.shortDescription);

// Create a quote that swaps to the LNURL-pay destination
const swap = await swapper.swap(
Tokens.STARKNET.STRK,
Tokens.BITCOIN.BTCLN, // Swapping to Lightning
parsed.min?.amount, // Swap the minimum LNURL-pay amount
SwapAmountType.EXACT_OUT, // Use EXACT_OUT mode (though EXACT_IN is also supported for LNURL-pay links!!!)
starknetSigner.getAddress(), // Source signer address
parsed.lnurl // Use parsed LNURL-pay object as destination
);
}
info

If you only need to check whether a string looks like LNURL before fetching metadata, use isValidLNURL(). To fetch the metadata after that, call getLNURLTypeAndData().

Smart Chain Addresses

If the input is a supported smart chain address, the parser returns the configured chain identifier as the type, for example SOLANA, STARKNET or CITREA. This is the format you typically use as the destination in Bitcoin → Smart Chain and Lightning → Smart Chain swaps.

const parsed = await swapper.Utils.parseAddress(starknetSigner.getAddress());

if (parsed?.type === "STARKNET") {
console.log("Destination is a Starknet address:", parsed.address);
}
info

If you only want to know whether a given string is a an address of a specific smart chain (Solana, Starknet, EVM, tc.) you can use the isValidSmartChainAddress() function.

Usage in Quote Forms

Parsed address data is most useful to automatically adjust your form before you create a quote:

  • use parsed.type to automatically pick source or destination tokens / chains
  • use parsed.amount from BIP-21, BOLT11 or LNURLs to pre-fill the quote amount
  • use parsed.min and parsed.max from LNURLs to clamp user-entered amounts
  • use parsed.lnurl.type === "pay" to show comment input for LNURL-pay if commentMaxLength > 0
const parsed = await swapper.Utils.parseAddress(destinationInput);
if (parsed == null) throw new Error("Unsupported destination");

// The address requests a fixed amount
if (parsed.amount != null) {
console.log("Pre-fill quoted amount:", parsed.amount.toString());
}

// Can add comment to the quote for LNURL-pay -links
if (parsed.type === "LNURL" && parsed.lnurl.type === "pay") {
console.log("User may add a comment up to", parsed.lnurl.commentMaxLength, "chars");
}

const quote = await swapper.swap(
fromToken,
toToken,
parsed.amount?.amount ?? userSelectedAmount,
amountType,
sourceAddress,
parsed.address,
{
comment: ... // In case the type is LNURL-pay and `commentMaxLength` is larger than 0
}
);

API Reference