BitcoinApp クラスは、Bitcoin
のアドレス取得、メッセージ署名(BIP-137)、PSBT(Partially Signed
Bitcoin Transaction)署名を提供します。
import {
BitcoinApp,
BTC_MAINNET_PATH,
BTC_TESTNET_PATH,
type BtcMessageSignature,
type InputSigningPath,
} from '@openloop/sdk-core'const btc = new BitcoinApp(transport)| メソッド | 説明 |
|---|---|
getAddress(testnet?) |
SegWit アドレス取得(mainnet/testnet 自動切替) |
getAddressWithPath(path) |
任意の BIP32 パスでアドレス取得 |
getAccountXpub(coinType) |
アカウントレベル拡張公開鍵の取得 |
signMessage(message, path) |
BIP-137 メッセージ署名 |
signPsbt(psbt) |
PSBT 署名(バイナリ入出力) |
signPsbtHex(psbt) |
PSBT 署名(hex 入出力) |
signPsbtWithPaths(psbt, inputPaths) |
入力パス指定付き PSBT 署名 |
SegWit(bech32)アドレスを取得します。
async getAddress(testnet?: boolean): Promise<{
publicKey: string // 非圧縮公開鍵 (hex)
address: string // bech32 アドレス ("bc1..." or "tb1...")
chainCode: string // チェーンコード (hex, 32 bytes)
}>| 名前 | 型 | デフォルト | 説明 |
|---|---|---|---|
testnet |
boolean |
false |
true: testnet パス (84'/1'/0'/0/0) |
| ネットワーク | パス | 定数 |
|---|---|---|
| Mainnet | 84'/0'/0'/0/0 |
BTC_MAINNET_PATH |
| Testnet | 84'/1'/0'/0/0 |
BTC_TESTNET_PATH |
// Mainnet
const { address } = await btc.getAddress()
// address: "bc1q..."
// Testnet
const { address } = await btc.getAddress(true)
// address: "tb1q..."任意の BIP32 パスでアドレスを取得します。マルチアカウントやお釣り用アドレスの取得に使用します。
async getAddressWithPath(path: string): Promise<{
publicKey: string
address: string
chainCode: string
}>// 2番目のアカウントの最初のアドレス
const { address } = await btc.getAddressWithPath("84'/0'/1'/0/0")
// お釣り用アドレス
const { address } = await btc.getAddressWithPath("84'/0'/0'/1/0")
// "m/" プレフィックスも可
const { address } = await btc.getAddressWithPath("m/84'/0'/0'/0/5")アカウントレベルの拡張公開鍵(m/84'/coin'/0')を取得します。ソフトウェア側で子鍵導出を行い、残高確認やアドレス生成に使用します。
async getAccountXpub(coinType: number): Promise<{
publicKey: string // 圧縮公開鍵 (hex, 33 bytes)
chainCode: string // チェーンコード (hex, 32 bytes)
}>| 名前 | 型 | 説明 |
|---|---|---|
coinType |
number |
0: mainnet, 1: testnet |
const { publicKey, chainCode } = await btc.getAccountXpub(0) // mainnetBIP-137 形式でメッセージに署名します。
async signMessage(
message: string,
path: string
): Promise<BtcMessageSignature>| 名前 | 型 | 説明 |
|---|---|---|
message |
string |
UTF-8 メッセージ |
path |
string |
BIP32 パス(例: "84'/0'/0'/0/0") |
BtcMessageSignature| フィールド | 型 | 説明 |
|---|---|---|
v |
number |
リカバリー ID (35-38: P2WPKH native SegWit) |
r |
string |
R 値 (32 bytes hex) |
s |
string |
S 値 (32 bytes hex) |
signature |
string |
完全な署名 (65 bytes: V || R || S) の Base64 |
const sig = await btc.signMessage('Hello, Bitcoin!', BTC_MAINNET_PATH)
console.log(sig.signature) // Base64 encoded signaturePSBT(Partially Signed Bitcoin Transaction)に署名します。PSBT 内の
BIP32_DERIVATION フィールドからパスを自動検出します。
async signPsbt(psbt: Uint8Array | string): Promise<Uint8Array>| 名前 | 型 | 説明 |
|---|---|---|
psbt |
Uint8Array \| string |
PSBT バイナリデータまたは hex 文字列 |
署名済み PSBT のバイナリデータ (Uint8Array)
hex 文字列での PSBT 署名。入出力ともに hex 文字列です。
async signPsbtHex(psbt: string): Promise<string>const signedHex = await btc.signPsbtHex('70736274ff...')各入力の BIP32 パスを明示的に指定して PSBT に署名します。PSBT に
BIP32_DERIVATION
フィールドがない場合や、特定の入力のみ署名したい場合に使用します。
async signPsbtWithPaths(
psbt: string,
inputPaths: InputSigningPath[]
): Promise<string>| 名前 | 型 | 説明 |
|---|---|---|
psbt |
string |
PSBT hex 文字列 |
inputPaths |
InputSigningPath[] |
入力ごとのパス指定 |
InputSigningPath| フィールド | 型 | 説明 |
|---|---|---|
index |
number |
PSBT の入力インデックス |
path |
string |
BIP32 パス(例: "84'/0'/0'/0/5") |
const signedHex = await btc.signPsbtWithPaths('70736274ff...', [
{ index: 0, path: "84'/0'/0'/0/0" },
{ index: 1, path: "84'/0'/0'/0/3" },
{ index: 2, path: "84'/0'/0'/1/0" }, // お釣り
])PSBT 署名はデバイスとの 3 フェーズ通信で行われます。
| チャンク | P1 | データ形式 |
|---|---|---|
| 最初 | 0x00 |
[4B total_size][1B num_paths][paths...][psbt_data...] |
| 継続 | 0x80 |
[psbt_data...] |
| 最終 | 0xFF |
[remaining_data] → デバイスで署名開始 |
num_paths=0: PSBT 内の BIP32_DERIVATION
から自動検出num_paths>0:
各入力のパスを明示指定([1B input_index][1B path_len][4B * path_len elements])ユーザーがデバイス画面でトランザクション内容を確認し、承認ボタンを押します。
| レスポンス | ステータスワード | 意味 |
|---|---|---|
[signed_psbt_chunk] |
0x61XX |
続きデータあり(次のチャンクを要求) |
[signed_psbt_chunk] |
0x9000 |
最終チャンク(取得完了) |
チャンクインデックスを 0
から順にインクリメントし、0x9000
が返るまで繰り返します。
import * as bitcoin from 'bitcoinjs-lib'
import { BitcoinApp, BTC_MAINNET_PATH } from '@openloop/sdk-core'
import { WebHidTransport } from '@openloop/transport-webhid'
const transport = await WebHidTransport.connect()
const btc = new BitcoinApp(transport)
// アドレス取得
const { address, publicKey } = await btc.getAddress()
// PSBT 作成
const psbt = new bitcoin.Psbt({ network: bitcoin.networks.bitcoin })
psbt.addInput({
hash: 'txid...',
index: 0,
witnessUtxo: {
script: Buffer.from('0014...', 'hex'),
value: 50000,
},
})
psbt.addOutput({
address: 'bc1q...',
value: 40000,
})
// PSBT をデバイスで署名
const psbtHex = psbt.toHex()
const signedHex = await btc.signPsbtWithPaths(psbtHex, [
{ index: 0, path: BTC_MAINNET_PATH },
])
// 署名済み PSBT を読み込み
const signedPsbt = bitcoin.Psbt.fromHex(signedHex)
signedPsbt.finalizeAllInputs()
// ブロードキャスト用 raw transaction
const rawTx = signedPsbt.extractTransaction().toHex()