跳转到主要内容
LI.FI 意图上的 BTC 支持目前尚未上线,仍在开发中。
LI.FI 意图支持比特币验证层。但是,填充比特币交换在技术上比填充 EVM 交换更复杂。如果您已经在填充 EVM 交换并有兴趣填充 BTC 交换,或者如果您想通过 LI.FI 意图将比特币交换添加到您的应用程序中,请联系我们,我们可以帮助您入门。 要确定订单是否涉及比特币交易,请检查 orderDto.order.outputs[].token 字段。如果代币指示比特币,请确保满足以下条件:
  • 代币的前 30 个字节应为 0x000000000000000000000000BC0000000000000000000000000000000000。 第 13 个字节是 0xBC
  • 第 31 个字节指示在订单可以在链上验证之前所需的确认数。
    • 0x000x01 代表 1 次确认。
    • 0x02 代表 2 次确认。
    • 0x03 代表 3 次确认,依此类推。
  • 第 32 个字节包含地址版本标识符,应解码为 uint8
如果交易指向比特币,地址(orderDto.order.outputs[].recipient)将包含相关的目标哈希或见证,而不是地址本身。此值必须与地址版本标识符——代币的第 32 个字节——一起使用以解码地址。
版本名称编码方案前缀哈希长度
0未知忽略
1P2PKHBase58Check(00+PKH)1*20
2P2SHBase58Check(05+SH)3*20
3P2WPKHBech32bc1q**20
4P2WSHBech32bc1q**32
5P2TRBech32mbc1p**32
* 前缀由编码方案确定。
** 前缀的一部分——1q/1p——由编码方案确定。
您可以使用下面的脚本获取有关如何从输出描述解码比特币地址的灵感。
import bs58check from 'bs58check';
import { bech32, bech32m } from 'bech32';

const hexStringToUint8Array = (hexString: string) =>
  Uint8Array.from(
    hexString.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16))
  );

function decodeBitcoinAddress(
  version: number,
  recipientHash: string,
  testnet = false,
): string {
  if (version === 1) {
    const prefix = !testnet ? '00' : '6F';
    const bytes = hexStringToUint8Array(
      prefix + recipientHash.replace('0x', '').slice(0, 40)
    );
    return bs58check.encode(bytes);
  }
  if (version === 2) {
    const prefix = !testnet ? '05' : 'C4';
    const bytes = hexStringToUint8Array(
      prefix + recipientHash.replace('0x', '').slice(0, 40)
    );
    return bs58check.encode(bytes);
  }
  const prefix = !testnet ? 'bc' : 'tb';
  if (version === 3) {
    const bytes = hexStringToUint8Array(
      recipientHash.replace('0x', '').slice(0, 40)
    );
    const words = bech32.toWords(bytes);
    words.unshift(0x00);
    return bech32.encode(prefix, words);
  }
  const bytes = hexStringToUint8Array(
    recipientHash.replace('0x', '').slice(0, 64)
  );
  if (version === 4) {
    const words = bech32.toWords(bytes);
    words.unshift(0x00);
    return bech32.encode(prefix, words);
  }
  if (version === 5) {
    const words = bech32m.toWords(bytes);
    words.unshift(0x01);
    return bech32m.encode(prefix, words);
  }

  throw Error(`Unsupported Address Type ${version}`);
}
生成地址后,创建一个至少有一个输出完全匹配已启动订单描述的输出的比特币交易。交易可以有任意数量的输入和输出,只要一个输出精确匹配订单输出指定的输出即可。这种灵活性允许批量填充、合并等。 如果在输出描述上设置了 calldata,比特币交易需要第二个输出,该输出正好是填充订单的输出之后的下一个输出索引:
// 假设您使用 BitcoinJS PSBT:
import * as bitcoin from 'bitcoinjs-lib';
...
bitcoin.initEccLib(ecc); // 用于 Taproot 支持。

const mainnet: boolean;
const psbt = new bitcoin.Psbt({
  network: mainnet ? bitcoin.networks.bitcoin : bitcoin.networks.testnet,
});

// ... 添加输入

// 添加求解输出。
psbt.addOutput({ address: to, value: outputValue });

// 下一个输出应该是 OP_RETURN
const opReturnData = returnData.replace("0x", "");
if (opReturnData.length > 0) {
  const data_embed = bitcoin.payments.embed({
      data: [hexStringToUint8Array(opReturnData)],
  });
  psbt.addOutput({
    script: data_embed.output!,
    value: 0n,
  });
}

// ... 完成交易
I