Ethereum API

EthereumApp クラスは、Ethereum のアドレス取得、メッセージ署名、トランザクション署名、EIP-712 Typed Data 署名、EIP-7702 Authorization 署名を提供します。

インポート

import {
  EthereumApp,
  DEFAULT_ETH_PATH,
  type SignatureResult,
} from '@openloop/sdk-core'

初期化

const eth = new EthereumApp(transport)

transportITransport インターフェースを実装する任意の Transport インスタンスです。

メソッド一覧

メソッド 説明
getAddress(path) アドレスと公開鍵を取得
signPersonalMessage(path, message, chainId?) EIP-191 personal_sign
signTransaction(path, rawTx) RLP エンコード済みトランザクションに署名
signTypedData(path, domainHash, msgHash, chainId?) EIP-712 Typed Data に署名
signAuthorization(path, authorizationRlp) EIP-7702 Authorization に署名

getAddress

デバイスから Ethereum アドレスと公開鍵を取得します。

async getAddress(path: string): Promise<{
  publicKey: string  // 非圧縮公開鍵 (hex, 65 bytes)
  address: string    // チェックサム付きアドレス ("0x...")
}>

パラメータ

名前 説明
path string BIP44 パス(例: "44'/60'/0'/0/0"

使用例

import { DEFAULT_ETH_PATH } from '@openloop/sdk-core'

const { address, publicKey } = await eth.getAddress(DEFAULT_ETH_PATH)
// address: "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"
// publicKey: "04a1b2c3d4..."

デフォルトパス

DEFAULT_ETH_PATH = "44'/60'/0'/0/0"


signPersonalMessage

EIP-191 personal_sign でメッセージに署名します。チェーン ID を認識する Openloop 独自の拡張プロトコルを使用します。

async signPersonalMessage(
  path: string,
  message: string,
  chainId?: number
): Promise<SignatureResult>

パラメータ

名前 デフォルト 説明
path string BIP44 パス
message string メッセージ(UTF-8 文字列または 0x プレフィックス付き hex)
chainId number 1 EVM チェーン ID

返り値: SignatureResult

フィールド 説明
v number リカバリー ID (27 or 28)
r string R 値 (32 bytes hex, 0x なし)
s string S 値 (32 bytes hex, 0x なし)

使用例

const sig = await eth.signPersonalMessage(
  DEFAULT_ETH_PATH,
  'Hello, Openloop!',
  1
)
// sig.v = 27
// sig.r = "a1b2c3..."
// sig.s = "d4e5f6..."

注意: 長いメッセージは自動的にチャンク分割されてデバイスに送信されます(最初のチャンク 150 バイト、以降 255 バイトずつ)。


signTransaction

RLP エンコード済みの Ethereum トランザクションに署名します。

async signTransaction(
  path: string,
  rawTx: string
): Promise<SignatureResult>

パラメータ

名前 説明
path string BIP44 パス
rawTx string RLP エンコード済みトランザクション (hex, 0x プレフィックスあり/なし)

使用例

const sig = await eth.signTransaction(
  DEFAULT_ETH_PATH,
  'f86c0a8502540be400825208...'
)

signTypedData

EIP-712 Typed Data に署名します。事前にハッシュ化された domainSeparator と message を渡します。

async signTypedData(
  path: string,
  domainSeparatorHash: string,
  messageHash: string,
  chainId?: number
): Promise<SignatureResult>

パラメータ

名前 デフォルト 説明
path string BIP44 パス
domainSeparatorHash string EIP-712 domain separator ハッシュ (32 bytes hex)
messageHash string EIP-712 message ハッシュ (32 bytes hex)
chainId number 1 EVM チェーン ID

使用例

const sig = await eth.signTypedData(
  DEFAULT_ETH_PATH,
  'aabbccddee...', // domainSeparatorHash
  '1122334455...', // messageHash
  1
)

signAuthorization

EIP-7702 Authorization(EOA に対する Set Code)に署名します。

async signAuthorization(
  path: string,
  authorizationRlp: string
): Promise<SignatureResult>

パラメータ

名前 説明
path string BIP44 パス
authorizationRlp string RLP([chain_id, address, nonce]) の hex

使用例

const sig = await eth.signAuthorization(
  DEFAULT_ETH_PATH,
  'c3010a...' // RLP([1, "0x...", 0])
)

ethers.js 連携

import { ethers } from 'ethers'
import { EthereumApp, DEFAULT_ETH_PATH } from '@openloop/sdk-core'
import { WebHidTransport } from '@openloop/transport-webhid'

const transport = await WebHidTransport.connect()
const eth = new EthereumApp(transport)

// アドレス取得
const { address } = await eth.getAddress(DEFAULT_ETH_PATH)

// トランザクション作成
const tx = {
  to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
  value: ethers.parseEther('0.01'),
  gasLimit: 21000n,
  gasPrice: (await provider.getFeeData()).gasPrice,
  nonce: await provider.getTransactionCount(address),
  chainId: 1n,
}

// RLP エンコードして署名
const unsignedTx = ethers.Transaction.from(tx).unsignedSerialized
const sig = await eth.signTransaction(DEFAULT_ETH_PATH, unsignedTx)

// 署名済みトランザクションを構築
const signedTx = ethers.Transaction.from({
  ...tx,
  signature: {
    v: sig.v,
    r: '0x' + sig.r,
    s: '0x' + sig.s,
  },
})

// ブロードキャスト
const txResponse = await provider.broadcastTransaction(signedTx.serialized)

viem 連携

import { createPublicClient, http, parseEther } from 'viem'
import { mainnet } from 'viem/chains'
import { EthereumApp, DEFAULT_ETH_PATH } from '@openloop/sdk-core'
import { WebHidTransport } from '@openloop/transport-webhid'

const transport = await WebHidTransport.connect()
const eth = new EthereumApp(transport)

const { address } = await eth.getAddress(DEFAULT_ETH_PATH)

// personal_sign
const sig = await eth.signPersonalMessage(
  DEFAULT_ETH_PATH,
  'Hello from viem!',
  1
)

// viem の署名フォーマットに変換
const signature = `0x${sig.r}${sig.s}${sig.v.toString(16)}` as `0x${string}`

次のステップ