Openloop SDK は WalletConnect v2 を通じたリモートデバイスアクセスを 2 つの方式でサポートしています。
| 方式 | レベル | 説明 |
|---|---|---|
| WcTransport | 低レベル | APDU コマンドを WalletConnect リレー経由で中継 |
| AppKit | 高レベル | Reown AppKit でマルチチェーン対応の標準 WC 接続 |
WcTransport は ITransport
を実装し、WalletConnect v2 リレーを通じて APDU コマンドをリモートの
Openloop Connect アプリに送信します。
カスタム JSON-RPC メソッド openloop_exchange で hex
エンコードされた APDU を送受信します。
import { WcTransport, EthereumApp, DEFAULT_ETH_PATH } from '@openloop/sdk-core'
import SignClient from '@walletconnect/sign-client'
// WalletConnect SignClient を初期化
const client = await SignClient.init({
projectId: 'your-project-id',
})
// ペアリングとセッション確立
const { uri, approval } = await client.connect({
requiredNamespaces: {
eip155: {
methods: ['openloop_exchange', 'openloop_lock', 'openloop_unlock'],
chains: ['eip155:1'],
events: [],
},
},
})
// URI を QR コードで表示 → ユーザーが Openloop Connect でスキャン
console.log('Pairing URI:', uri)
// セッション承認を待つ
const session = await approval()
// WcTransport 作成
const transport = new WcTransport({
client,
session: { topic: session.topic },
chainId: 'eip155:1', // オプション(デフォルト: 'eip155:1')
})
await transport.open()
// 通常の App クラスがそのまま使える
const eth = new EthereumApp(transport)
const { address } = await eth.getAddress(DEFAULT_ETH_PATH)interface WcTransportOptions {
client: IWcSignClient // WalletConnect SignClient インスタンス
session: WcSession // アクティブセッション { topic: string }
chainId?: string // チェーン ID(デフォルト: "eip155:1")
}
interface IWcSignClient {
request<T>(params: {
topic: string
chainId: string
request: { method: string; params: unknown }
}): Promise<T>
}
interface WcSession {
topic: string
}| メソッド | 説明 |
|---|---|
openloop_exchange |
APDU コマンド送受信 |
openloop_lock |
デバイスの排他ロック取得 |
openloop_unlock |
デバイスの排他ロック解放 |
ITransport インターフェースを実装しているため、全 App
クラスがそのまま使えるlock/unlock)もリレー経由で動作Reown AppKit を使うと、WalletConnect
の標準メソッド(eth_signTransaction,
personal_sign 等)で署名できます。この方式では APDU
は直接扱わず、Openloop Connect が内部でデバイス操作を行います。
チェーン: - eip155:1 — Ethereum Mainnet -
eip155:11155111 — Sepolia Testnet
メソッド: | メソッド | 説明 | |———|——| |
eth_sendTransaction | トランザクション送信 | |
eth_signTransaction | トランザクション署名 | |
eth_sign | データ署名 | | personal_sign |
EIP-191 メッセージ署名 | | eth_signTypedData | EIP-712
Typed Data 署名 | | eth_signTypedData_v3 | EIP-712 v3 | |
eth_signTypedData_v4 | EIP-712 v4 | |
wallet_getCapabilities | ウォレット機能取得 |
チェーン(@openloop/sdk-core の
SUPPORTED_BIP122_CHAINS): -
bip122:000000000019d6689c085ae165831e93 — Bitcoin Mainnet -
bip122:000000000933ea01ad0ee984209779ba — Bitcoin
Testnet3
メソッド(SUPPORTED_BIP122_METHODS): | メソッド | 説明
| |———|——| | signPsbt | PSBT 署名 | |
getAccountAddresses | アカウントアドレス取得 | |
signMessage | メッセージ署名(BIP-137) | |
sendTransfer | 送金 |
import { SUPPORTED_BIP122_CHAINS, SUPPORTED_BIP122_METHODS } from '@openloop/sdk-core'
console.log(SUPPORTED_BIP122_CHAINS.length, SUPPORTED_BIP122_METHODS.join(', '))
// 2 "signPsbt, getAccountAddresses, signMessage, sendTransfer"Openloop Connect は、署名済み PSBT(signPsbt の結果の
psbt)と BIP-137 署名(signMessage の結果の
signature)を base64 で返します。SDK
の関数は hex を受け取るので、変換してから渡します。
import type { BtcMessageSignature } from '@openloop/sdk-core'
import { extractRawTx } from '@openloop/sdk-core/bitcoin'
import { verifyBtcMessage } from '@openloop/sdk-core/verify'
function base64ToBytes(b64: string): Uint8Array {
return Uint8Array.from(atob(b64), c => c.charCodeAt(0))
}
function toHex(bytes: Uint8Array): string {
return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')
}
// signPsbt の結果 → ブロードキャストできる生の取引
function rawTxFromSignPsbt(result: { psbt: string }) {
return extractRawTx(toHex(base64ToBytes(result.psbt))) // { rawTxHex, txid }
}
// signMessage の結果 → BIP-137 署名の検証
function verifySignMessage(message: string, result: { address: string; signature: string }) {
const bytes = base64ToBytes(result.signature) // [v(1)][r(32)][s(32)]
const hex = toHex(bytes)
const sig: BtcMessageSignature = { v: bytes[0], r: hex.slice(2, 66), s: hex.slice(66, 130), signature: result.signature }
return verifyBtcMessage(message, sig, result.address)
}v の範囲は BitcoinApp.signMessage
と同じです(アドレスの型ごとに 31〜42)。extractRawTx と
verifyBtcMessage の詳細は Bitcoin
API を参照してください。
▲ Reown の Bitcoin アダプター(
@reown/appkit-adapter-bitcoin1.8.19 で確認)のsignMessageは、署名を hex として読むため、上の base64 の署名からは空の結果になります。署名には、アダプターの下にある WalletConnect のprovider.request({ method: 'signMessage', params: { message, account, address } }, chainId)を直接呼んでください。
チェーン: - solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp —
Mainnet Beta - solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 —
Devnet
メソッド: | メソッド | 説明 | |———|——| |
solana_signTransaction | トランザクション署名 | |
solana_signAllTransactions | 複数トランザクション署名 | |
solana_signAndSendTransaction | 署名+送信 | |
solana_signMessage | メッセージ署名 |
チェーン: - tron:0x2b6653dc — TRON Mainnet -
tron:0x94a9059e — TRON Shasta Testnet
メソッド: | メソッド | 説明 | |———|——| |
tron_signTransaction | トランザクション署名 | |
tron_signMessage | メッセージ署名 |
import { createAppKit } from '@reown/appkit/react'
import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
import { SolanaAdapter } from '@reown/appkit-adapter-solana'
import { BitcoinAdapter } from '@reown/appkit-adapter-bitcoin'
import { TronAdapter } from '@reown/appkit-adapter-tron'
import { mainnet, sepolia, bitcoin, bitcoinTestnet } from '@reown/appkit/networks'
const projectId = 'your-walletconnect-project-id'
// アダプター作成
const wagmiAdapter = new WagmiAdapter({ projectId, networks: [mainnet, sepolia] })
const solanaAdapter = new SolanaAdapter()
const bitcoinAdapter = new BitcoinAdapter()
const tronAdapter = new TronAdapter()
// AppKit 作成
const modal = createAppKit({
projectId,
adapters: [wagmiAdapter, solanaAdapter, bitcoinAdapter, tronAdapter],
networks: [mainnet, sepolia, bitcoin, bitcoinTestnet],
metadata: {
name: 'My dApp',
description: 'My dApp with Openloop',
url: 'https://my-dapp.com',
icons: ['https://my-dapp.com/icon.png'],
},
customWallets: [
{
id: 'openloop-connect',
name: 'Openloop Connect',
homepage: 'https://crypto.haudi.jp/openloop/',
mobile_link: 'openloop://',
desktop_link: 'openloop://',
image_url: 'https://crypto.haudi.jp/openloop/images/logo/openloop-icon.png',
},
],
})| 比較項目 | WcTransport | AppKit |
|---|---|---|
| APDU レベル制御 | ✓ 完全制御 | ✗ 抽象化済み |
| 導入の容易さ | やや複雑 | 簡単 |
| UI コンポーネント | なし(自前で実装) | モーダル付き |
| マルチチェーン | 手動切替 | 自動切替 |
| EIP-7702 | ✓ 対応 | ✗ 非対応 |
| 対応ウォレット | Openloop Connect のみ | 全 WC 対応ウォレット |
推奨: - Openloop デバイスとの統合が主目的 → WcTransport - 複数ウォレットをサポートしたい → AppKit
exchange タイムアウトは WalletConnect
リレーの制約に依存