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

# Bitcoin Providers

> Bitcoin Architecture

export const SupportedTools = ({chainId}) => {
  const [chains, setChains] = useState(null);
  const [tools, setTools] = useState(null);
  const [error, setError] = useState(null);
  useEffect(() => {
    const fetchChains = async () => {
      try {
        const response = await fetch('https://li.quest/v1/chains?chainTypes=EVM,SVM,UTXO,MVM,TVM');
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const jsonData = await response.json();
        setChains(jsonData.chains);
      } catch (err) {
        setError(err.message);
      }
    };
    fetchChains();
  }, []);
  useEffect(() => {
    const fetchTools = async () => {
      try {
        const response = await fetch('https://li.quest/v1/tools');
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const jsonData = await response.json();
        setTools(jsonData);
      } catch (err) {
        setError(err.message);
      }
    };
    fetchTools();
  }, []);
  const parseBridges = (bridges, selectedChainId) => bridges.map(bridge => {
    const fromChainIds = bridge.supportedChains.filter(connection => connection.toChainId === selectedChainId).map(connection => connection.fromChainId);
    const toChainIds = bridge.supportedChains.filter(connection => connection.fromChainId === selectedChainId).map(connection => connection.toChainId);
    const connectedChainIds = [...new Set([...fromChainIds, ...toChainIds])];
    return {
      ...bridge,
      fromChainIds,
      toChainIds,
      connectedChainIds
    };
  }).filter(bridge => bridge.connectedChainIds.length).sort((a, b) => b.connectedChainIds.length - a.connectedChainIds.length);
  const parseExchanges = (exchanges, selectedChainId) => exchanges.filter(exchange => exchange.supportedChains.includes(selectedChainId));
  const renderChains = chains => <div className="p-2">
      <div className="flex flex-wrap gap-4">
        {chains.map(chain => <div key={chain.key} className="relative group flex-shrink-0">
            <img src={chain.logoURI} alt={chain.name} className="w-10 h-10 rounded-full object-cover not-prose" />
            <div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 hidden group-hover:block bg-gray-800 text-white text-xs rounded py-1 px-2 whitespace-nowrap z-10">
              {chain.name}
            </div>
          </div>)}
      </div>
    </div>;
  const renderTools = (tools, chains) => {
    const bridges = parseBridges(tools.bridges, Number(chainId));
    const exchanges = parseExchanges(tools.exchanges, Number(chainId));
    return <div>
      <h2>Supported Bridges</h2>
      <ul>
        {bridges.map(bridge => <li>
            {bridge.name} (<code>{bridge.key}</code>) connects to:
            {renderChains(chains.filter(chain => bridge.connectedChainIds.includes(chain.id)))}
          </li>)}
      </ul>

      <h2>Supported Exchanges</h2>
      <ul>
        {exchanges.map(exchange => <li>{exchange.name} (<code>{exchange.key}</code>)</li>)}
        {exchanges.length === 0 ? '-' : ''}
      </ul>
    </div>;
  };
  if (error) return <div>Error: {error}</div>; else if (chains && tools) return renderTools(tools, chains); else return <div>Loading...</div>;
};

LI.FI offers seamless native Bitcoin bridging and swaps between native Bitcoin, major EVM chains and Solana.

<SupportedTools chainId="20000000000001" />

## Requesting a quote

A quote for Bitcoin can be requested using the same endpoints as EVM. The only difference will be the transaction data when source chain is Bitcoin.

<Note>
  `fromAddress` when source chain is Bitcoin supports flexible formats for maximum convenience:

  * **Single Bitcoin address**: `bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh`
  * **Multiple addresses** (semicolon-separated): `address1;address2;address3`
  * **Extended public key (xpub)**: `xpub6CUG...`
  * **Multiple xpubs**: `xpub1,xpub2`
  * **Combination of xpubs and addresses**: `xpub1;address1;address2`

  **UTXO Collection**: The system builds transaction inputs by collecting UTXOs from:

  * Provided addresses directly, OR
  * Addresses derived from the provided xpub(s) that contain UTXOs

  The `fromAddress` must have enough UTXOs to cover the requested transaction amount, otherwise no quote will be returned. UTXOs are checked and combined in the most efficient way to build the transaction.

  **Transaction Signing**: All input addresses (wallets) that contribute UTXOs to the transaction must sign the PSBT. This ensures that funds from each participating address are properly authorized.

  **Refund Address**: The third output in the PSBT is a refund/change output that will be returned to the address that contributed the most significant input to the transaction.
</Note>

## Executing a transaction

### Transaction data

After retrieving the quote, the funds need to be sent to the BTC vault address provided in the response, along with a memo.

* Memo Functionality: Similar to Thorchain, LI.FI uses memos for BTC to EVM swaps. The memo in the BTC transaction specifies the swap's destination address and chain.

* Transaction Handling: The transaction that leaves BTC and goes to EVM needs to be sent to an EVM address. The memo ensures that the swap details are correctly processed by the validators.

<Note>
  NOTE: Only send transactions in a timely manner (\~30min). It is always
  recommended to request an up-to-date quote to ensure to get the latest
  information.
</Note>

<Warning>
  **Risk of modifying Bitcoin transaction data**

  Modifying PSBT or raw Bitcoin transaction data received from our API (for
  example removing outputs, changing amounts, or editing opcodes/scripts) can
  invalidate signatures or spending conditions and lead to irreversible loss of
  funds.

  Do not alter PSBTs unless you are an expert and have explicitly confirmed with
  us the modification you intend to make.
</Warning>

<Note>
  `data` in transactionRequest object is PSBT (partially signed bitcoin
  transaction) and memo needs to be retrieved from PSBT by decoding it.
</Note>

### Retrieving memo from PSBT

PSBT can be decoded using any library like [bitcoinjs](https://github.com/bitcoinjs/bitcoinjs-lib) or [scure-btc-signer](https://github.com/paulmillr/scure-btc-signer).

Here's an example using `bitcoinjs`

```typescript theme={"system"}
const psbtHex = transactionRequest.data;

// Create PSBT object from hex data
const psbt = Psbt.fromHex(psbtHex, { network: networks.bitcoin });

// Find OP_RETURN output in the transaction outputs
const opReturnOutput = psbt.txOutputs.find((output) => {
  if (output?.script) {
    // Convert the output script to hex string for checking
    const scriptHex = Array.from(output.script)
      .map((b) => b.toString(16).padStart(2, "0"))
      .join("");

    // Check if script starts with OP_RETURN opcode (0x6a)
    return scriptHex.startsWith("6a");
  }
  return false;
});

// If an OP_RETURN output exists, decode its script data as UTF-8 text (memo)
const memo = opReturnOutput?.script
  ? new TextDecoder().decode(
      new Uint8Array(Object.values(opReturnOutput.script))
    )
  : undefined;
```
