> ## Documentation Index
> Fetch the complete documentation index at: https://build.flashnet.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Lightning Payments

> Pay Lightning invoices using any token via automatic AMM swap to BTC

Pay Lightning invoices using any token tradeable on Flashnet. The SDK automatically swaps your tokens to BTC via the AMM and uses the BTC to pay the invoice, all in a single function call.

<Note>
  Available in SDK version 0.4.1+. Rollback feature and improved defaults in 0.4.2+.
</Note>

## How It Works

1. **Decode invoice** - Extract the payment amount from the BOLT11 invoice
2. **Estimate fees** - Get Lightning routing fee estimate from Spark
3. **Find best pool** - Select the pool with optimal liquidity for your token → BTC swap
4. **Execute swap** - Swap tokens to BTC via Flashnet AMM
5. **Pay invoice** - Use the received BTC to pay the Lightning invoice

The entire flow is bundled into two simple functions: `getPayLightningWithTokenQuote()` for quotes and `payLightningWithToken()` for execution.

## Getting a Quote

Always get a quote first to see the total cost:

```typescript theme={null}
const quote = await client.getPayLightningWithTokenQuote(
  "lnbc50u1p55pfnq...", // BOLT11 invoice
  "btkn1xgrvjwey..."    // Your token address (bech32m or hex)
);

console.log('Invoice amount:', quote.invoiceAmountSats, 'sats');
console.log('Lightning fee:', quote.estimatedLightningFee, 'sats');
console.log('Total BTC needed:', quote.btcAmountRequired, 'sats');
console.log('Token required:', quote.tokenAmountRequired);
console.log('AMM fee:', quote.estimatedAmmFee);
console.log('Price impact:', quote.priceImpactPct, '%');
```

### Quote Response

| Field                      | Description                                      |
| -------------------------- | ------------------------------------------------ |
| `invoiceAmountSats`        | Original invoice amount                          |
| `estimatedLightningFee`    | Lightning routing fee in sats                    |
| `btcVariableFeeAdjustment` | Extra sats for AMM bit masking (0-63)            |
| `btcAmountRequired`        | Total BTC needed (invoice + LN fee + adjustment) |
| `tokenAmountRequired`      | Total token amount needed (includes AMM fees)    |
| `estimatedAmmFee`          | AMM LP + integrator fees in token units          |
| `executionPrice`           | Token per sat exchange rate                      |
| `priceImpactPct`           | Price impact percentage                          |
| `poolId`                   | The pool selected for the swap                   |

## Executing Payment

After reviewing the quote, execute the payment:

```typescript theme={null}
const result = await client.payLightningWithToken({
  invoice: "lnbc50u1p55pfnq...",
  tokenAddress: "btkn1xgrvjwey...",
  // All options below are optional with sensible defaults
});

if (result.success) {
  console.log('Payment successful!');
  console.log('Lightning payment ID:', result.lightningPaymentId);
  console.log('Token spent:', result.tokenAmountSpent);
  console.log('BTC received from swap:', result.btcAmountReceived, 'sats');
  console.log('AMM fee paid:', result.ammFeePaid);
} else {
  console.log('Payment failed:', result.error);
}
```

### Payment Options

| Option                  | Type    | Default    | Description                                                         |
| ----------------------- | ------- | ---------- | ------------------------------------------------------------------- |
| `invoice`               | string  | required   | BOLT11-encoded Lightning invoice                                    |
| `tokenAddress`          | string  | required   | Token to spend (bech32m or hex)                                     |
| `maxSlippageBps`        | number  | 500        | Max AMM slippage in basis points (5%)                               |
| `maxLightningFeeSats`   | number  | from quote | Max Lightning routing fee (uses `estimatedLightningFee` from quote) |
| `integratorFeeRateBps`  | number  | 0          | Optional integrator fee                                             |
| `transferTimeoutMs`     | number  | 30000      | Timeout waiting for swap completion (30s)                           |
| `rollbackOnFailure`     | boolean | false      | Swap BTC back to token if Lightning payment fails                   |
| `useExistingBtcBalance` | boolean | false      | Pay immediately using existing BTC, don't wait for swap             |

### Payment Result

| Field                | Description                                  |
| -------------------- | -------------------------------------------- |
| `success`            | Whether payment completed successfully       |
| `poolId`             | The pool used for the swap                   |
| `tokenAmountSpent`   | Actual token amount spent                    |
| `btcAmountReceived`  | BTC received from swap                       |
| `swapTransferId`     | Flashnet swap transfer ID                    |
| `lightningPaymentId` | Lightning payment identifier (if successful) |
| `ammFeePaid`         | AMM fee paid in token units                  |
| `lightningFeePaid`   | Lightning routing fee paid in sats           |
| `error`              | Error message (if failed)                    |

## Complete Example

```typescript theme={null}
import { SparkWallet } from "@buildonspark/spark-sdk";
import { FlashnetClient } from "@flashnet/sdk";

async function payInvoiceWithUSDB() {
  // Initialize wallet
  const { wallet } = await SparkWallet.initialize({
    mnemonicOrSeed: "your-mnemonic",
    options: { network: "MAINNET" },
  });

  // Initialize Flashnet client
  const client = new FlashnetClient(wallet);
  await client.initialize();

  // Get wallet balance and find USDB token
  const balance = await client.getBalance();
  let usdbAddress: string | null = null;
  let usdbBalance = 0n;

  for (const [tokenPubkey, tokenData] of balance.tokenBalances.entries()) {
    const symbol = tokenData.tokenInfo?.tokenSymbol || "";
    if (symbol.toUpperCase().includes("USDB")) {
      usdbAddress = tokenData.tokenInfo?.tokenAddress || tokenPubkey;
      usdbBalance = tokenData.balance;
      console.log(`Found USDB: ${usdbBalance} (${tokenData.tokenInfo?.tokenDecimals} decimals)`);
    }
  }

  if (!usdbAddress) {
    throw new Error("No USDB token found in wallet");
  }

  // Lightning invoice to pay
  const invoice = "lnbc50u1p55pfnqpp5...";

  // Step 1: Get quote
  const quote = await client.getPayLightningWithTokenQuote(invoice, usdbAddress);
  
  console.log(`Paying ${quote.invoiceAmountSats} sats invoice`);
  console.log(`Requires ${quote.tokenAmountRequired} USDB (smallest units)`);
  console.log(`Price impact: ${quote.priceImpactPct}%`);

  // Check sufficient balance
  if (usdbBalance < BigInt(quote.tokenAmountRequired)) {
    throw new Error(`Insufficient USDB: need ${quote.tokenAmountRequired}, have ${usdbBalance}`);
  }

  // Step 2: Execute payment (with optional rollback on failure)
  const result = await client.payLightningWithToken({
    invoice,
    tokenAddress: usdbAddress,
    rollbackOnFailure: true, // Recover tokens if Lightning payment fails
  });

  if (result.success) {
    console.log('✅ Payment successful!');
    console.log('Lightning payment ID:', result.lightningPaymentId);
    console.log('Token spent:', result.tokenAmountSpent);
    console.log('BTC received:', result.btcAmountReceived, 'sats');
  } else {
    console.log('❌ Payment failed:', result.error);
  }

  await wallet.cleanupConnections();
}
```

## Fee Breakdown

The total token cost includes multiple fee components:

1. **Lightning routing fee** - Network fee to route the payment (\~0.1-0.5%)
2. **AMM LP fee** - Liquidity provider fee (typically 20 bps)
3. **Integrator fee** - Optional fee for integrators (if specified)
4. **BTC variable fee** - Up to 63 sats adjustment for AMM leaf management

All fees are bundled into `tokenAmountRequired` in the quote—what you see is what you pay.

### Fee Calculation Example

For a 5000 sat invoice with 20 bps LP fee:

```
Invoice amount:     5,000 sats
Lightning fee:     +   14 sats  
BTC adjustment:    +   42 sats (rounds to next multiple of 64)
─────────────────────────────
Total BTC needed:   5,056 sats

Token input calculated via AMM:
  amount_in_effective = (reserve_token × 5056) / (reserve_btc - 5056)
  amount_in = amount_in_effective × (1 + 0.002)  // 20 bps fee
```

## Minimum Amounts

Flashnet enforces minimum amounts for swaps:

* **BTC output**: 1,000 sats minimum
* **Token input**: Varies by token (typically 1 USD equivalent)

Invoices below the BTC minimum will throw an error with a clear message.

## Instant Payment with Existing BTC

If you already have BTC in your wallet, you can pay the invoice immediately without waiting for the swap to complete:

```typescript theme={null}
const result = await client.payLightningWithToken({
  invoice,
  tokenAddress,
  useExistingBtcBalance: true, // Pay instantly if BTC available
});
```

When enabled, this:

1. Checks if you have enough BTC to cover the invoice + Lightning fee
2. If yes: executes swap → pays immediately → swap BTC arrives async
3. If no: falls back to normal flow (waits for swap to complete)

<Tip>
  This gracefully falls back to waiting if BTC balance is insufficient—no error is thrown.
</Tip>

## Rollback on Failure

If the Lightning payment fails after the swap succeeds, you can enable automatic rollback to swap the BTC back to your original token:

```typescript theme={null}
const result = await client.payLightningWithToken({
  invoice,
  tokenAddress,
  rollbackOnFailure: true, // Swap BTC back to token if Lightning fails
});

if (!result.success) {
  // Check if funds were rolled back
  if (result.error?.includes('Funds rolled back')) {
    console.log('Payment failed but tokens were recovered');
  } else if (result.error?.includes('BTC remains in wallet')) {
    console.log('Payment failed, BTC needs manual handling');
  }
}
```

<Warning>
  Rollback incurs an additional swap fee and may result in slightly fewer tokens due to price movement.
</Warning>

## Error Handling

```typescript theme={null}
try {
  const result = await client.payLightningWithToken({
    invoice,
    tokenAddress,
  });
  
  if (!result.success) {
    console.error('Payment failed:', result.error);
  }
} catch (error) {
  if (error.message.includes('Invoice amount too small')) {
    console.error('Invoice below minimum (1000 sats)');
  } else if (error.message.includes('Insufficient liquidity')) {
    console.error('Pool lacks liquidity for this swap');
  } else if (error.message.includes('Insufficient token balance')) {
    console.error('Not enough tokens in wallet');
  } else {
    console.error('Unexpected error:', error);
  }
}
```

## Next Steps

* [Swaps](/products/flashnet-amm/swaps) - Learn more about AMM swaps
* [Fees](/products/flashnet-amm/fees) - Understand the fee structure
* [Pools](/products/flashnet-amm/pools) - View available liquidity pools
