ウォレットアダプター (@qorechain/wallet-adapter)
@qorechain/wallet-adapter は、signDirect を公開している Cosmos ウォレット(Keplr、Leap、Cosmostation)に QoreChain を追加し、チェーンが要求するトランザクションを構築します。ネイティブレーンのトランザクションには、アカウントの従来型 secp256k1 署名に加えて ML-DSA-87(FIPS 204)署名が必要ですが、標準のウォレットは ML-DSA-87 署名を作成できません。アダプターがそれを作成してトランザクションボディに配置し、その後、変更されていないウォレットに通常の署名を依頼します。dApp 開発者とウォレット開発者に加え、JavaScript で統合 QoreChain ウォレット、EVM 認可ウィンドウのメッセージ、またはリンクキー(オーセンティケーター)のメッセージを扱う必要があるツール開発者向けです。現在のバージョンは 0.4.0 です。
dApp からユーザーの QoreX ウォレットでトランザクションを送信するだけであれば、最短の方法はこのパッケージの qorexSignAndBroadcast、または開発者パッケージのインデックスに掲載されている QoreX パッケージです。ウォレットを開発していて、5 つの言語に対応した完全な署名ライブラリが必要な場合は、まず QoreSign を読んでください。
革新点
- ウォレットは通常のボディに署名します。 アダプターは拡張機能なしでボディを構築し、署名対象バイト列に対して ML-DSA-87 レイヤーに署名し、それを
/qorechain.pqc.v1.PQCHybridSignature拡張オプション(アルゴリズム ID 1)としてボディに入れ、その後で完成したSignDocに対してwallet.signDirectを呼び出します。ウォレットは標準のSIGN_MODE_DIRECT署名を生成するため、QoreChain 固有のコードは不要です。結果は通常のTxRawバイト列です。 - ネットワークごとの署名対象バイト列セレクター。 ML-DSA-87 鍵は 2 つのバイト形式のいずれかに署名し、ネットワークはどの高さでもちょうど 1 つだけを検証します。
signBytesVersion: "auto"(デフォルト)の場合、署名者はノードにGET /cosmos/upgrade/v1beta1/applied_plan/{name}でv3.2.0、続いてv3.1.98を問い合わせ、どちらかの高さが 0 より大きければ v2 形式(ドメインタグqorechain-pqc-hybrid-v2とチェーン ID)に署名し、結果を REST URL とチェーン ID ごとに 60 秒間キャッシュし、問い合わせができない場合は推測せずに例外をスローします。2026年10月27日に稼働中のノードで確認した結果: メインネットとテストネットはどちらもv2に解決され、restなしでqorechain-vladiを呼び出すと例外がスローされます。refreshSignBytesVersion()はキャッシュを迂回し、isHybridSignBytesRejection()はpqcコード 21 の拒否を認識するため、ウォレットを開いている間にネットワークがアップグレードされた場合、呼び出し側は再解決して 1 回だけ再試行できます。 - ニーモニック 1 つにつき ML-DSA-87 鍵 1 つ、ツール間で共有。
walletFromMnemonicは、SHAKE-256("qorechain:pqc:v1|" + address + "|" + mnemonic)を ML-DSA-87 の鍵生成に入力して鍵を導出します。この鍵はアカウントアドレスに紐づいており、SDK、@qorechain/chain-bridge、QoreX、qorechaind tx pqc recover-keyコマンドと同じ導出方法のため、どのツールで署名しても 1 つのニーモニックから得られる鍵は 1 つです。決定論的な鍵導出と復元を参照してください。 - 1 つのアカウント、3 つのアドレス形式、1 つの署名鍵。
generateQoreWalletとwalletFromMnemonicは、同じ 20 バイトの ID を表すqor1、0x(EIP-55)、SVM の base58 の各形式を、ML-DSA-87 キーペアとともに返します。signClassicalEthとsignHybridEthは、このイーサリアムネイティブ鍵(eth_secp256k1)で Cosmos レーンのトランザクションに署名するため、同じ鍵が他の場所で EVM トランザクションにも署名します。 - PQC リカバリーコード。
generatePqcRecoveryCodeは、QRC1-に Crockford base32 と 24 ビットのチェックサムを続けた形式のランダムな 256 ビットのシークレットを返します。pqcKeyFromRecoveryCode(code, address)は、そこからアドレスに紐づけて ML-DSA-87 鍵を導出します。誤入力された文字は、何にも一致しない鍵を黙って導出するのではなく、メッセージ付きで拒否されます。このコードは意図的にシードフレーズではありません。 - 署名者としての QoreX。
qorexSignAndBroadcastは、プロトコルバッファでエンコードされたメッセージ(1 回の呼び出しにつき 1 から 32 個、メモは最大 256 バイト、ガスリミットは 100,000 から 5,000,000)をユーザーの QoreX ウォレットに送ります。ウォレットはそれらをデコードして表示し、ウォレットだけが作成できる ML-DSA-87 レイヤーを追加し、署名してブロードキャストします。アダプターは上限をローカルで確認し、PQC 鍵管理メッセージ(MsgRegisterPQCKey、MsgRegisterPQCKeyV2、MsgMigratePQCKey、MsgRotatePQCKey)を、authz のMsgExecの内側であればどの深さでも拒否します。デコードできないMsgExecは拒否されます。 - EVM 認可ウィンドウのためのビルディングブロック。自動では決して開きません。
openEvmWindowMsg、closeEvmWindowMsg、fetchEvmWindow、parseEvmWindow、isEvmWindowRejectionは、EVM の送信前に開いておく必要があるウィンドウを扱います。すべての上限(blocksは 1 から 17,280、maxTxsは 1 から 1,000、maxValueは 0 より大きい値)は必須で、デフォルトなしにクライアント側で確認され、ウィンドウの状態フィールドは BigInt です。このパッケージが自らウィンドウを開くことはなく、ユーザーが明示的な認可ステップを目にすることを前提としています。 - チェーンと完全に一致するダイジェストを持つリンクキー(オーセンティケーター)のメッセージ。
registerAuthenticatorMsg、registerEthAuthenticatorMsg、buildPhantomExecuteEvm、buildPhantomExecuteCosmos、buildMetaMaskExecuteEvm、buildMetaMaskExecuteCosmosは、Phantom または MetaMask の鍵が、権限セットと支出ルールの下で QoreChain アカウントから支出できるようにするメッセージを構築します。evmAuthSignBytesV2はチェーン v3.2.3 のダイジェストで、呼び出しのガスリミット(0 以外である必要があります)も紐づけます。ノンスはアカウントの EVM ノンスではなく、リンクキーのオーセンティケーターシーケンスです。オーセンティケーターと委任支出を参照してください。 - 安全な鍵ローテーション。
rotateFromLegacyWalletKeyは、廃止されたウォレット署名導出で作られた鍵から離れるMsgRotatePQCKeyを構築し、再導出した鍵が登録済みの鍵と等しくない限り拒否します。rotatePqcKeyMsgFromMnemonicは、レガシーなSHAKE-256(mnemonic)鍵を正規のアドレス紐づけ鍵に移行し、レガシー導出を新しい鍵として使うことを拒否します。
使い方
2 つの cosmjs ピア依存(バージョン 0.32)とともにアダプターをインストールします。
npm install @qorechain/wallet-adapter @cosmjs/stargate @cosmjs/proto-signing
このパッケージは、TypeScript の型定義を備えたプレーンな JavaScript の ES モジュールです。マニフェストには、このパッケージのテスト済みクイックスタートはありません。以下のスニペットはパッケージの型定義とソースに基づいています。2026年10月27日に、ウォレット生成、署名対象バイト列リゾルバー、EVM ウィンドウの状態読み取り、openEvmWindowMsg、廃止された関数のエラーを、公開済みの 0.4.0 パッケージと稼働中のテストネットおよびメインネットの REST エンドポイントに対して実行し、パッケージ自身の 102 件のテストが成功しています。署名と QoreX のスニペットは、エンドツーエンドでは実行していません。
統合ウォレットを生成する
import { generateQoreWallet, walletFromMnemonic } from "@qorechain/wallet-adapter";
const w = await generateQoreWallet(); // random 24-word mnemonic
// const w = await walletFromMnemonic(mnemonic); // or recover one
console.log(w.cosmos); // qor1... (bech32)
console.log(w.evm); // 0x... (EIP-55)
console.log(w.svm); // base58 form of the same 20 bytes
// w.privateKey, w.pubkey, w.pqc = { publicKey (2592 bytes), secretKey }
walletFromSeed(seed32) は、32 バイトのシークレットから同じウォレットを構築します。シードが secp256k1 の秘密鍵になるため、安全な乱数源、またはユーザーだけが持つ素材に対する鍵導出関数から得る必要があります。ウェブサイトがウォレットに生成を要求できる署名から導出してはいけません。
ユーザーのウォレットにチェーンを登録する
import { qoreChainInfo, addQoreEvmToWallet } from "@qorechain/wallet-adapter";
// Keplr and other Cosmos wallets. chainId defaults to the testnet, so pass it for mainnet.
await window.keplr.experimentalSuggestChain(
qoreChainInfo({ chainId: "qorechain-vladi", rpc: "https://rpc.qore.host", rest: "https://api.qore.host" }),
);
await window.keplr.enable("qorechain-vladi");
// MetaMask and other EIP-1193 wallets (18-decimal native currency on the EVM lane).
await addQoreEvmToWallet(window.ethereum, {
evmChainId: 9801, testnet: false, rpcUrl: "https://evm.qore.host",
});
qoreChainInfo は、コインタイプ 118、bech32 プレフィックス qor、小数 6 桁のデノミネーション uqor、ガス価格ステップとしてガス 1 単位あたり 0.1、0.15、0.25 uqor を使用します。これはガス 1 単位あたり 0.1 uqor という手数料の下限を満たしています。addQoreEvmToWallet には rpcUrl が必要です。
Cosmos ウォレットでハイブリッドトランザクションに署名する
import { QoreChainSigner, pqcKeyFromRecoveryCode } from "@qorechain/wallet-adapter";
const signer = window.keplr.getOfflineSigner("qorechain-vladi");
const [account] = await signer.getAccounts();
// The account's ML-DSA-87 keypair, from a recovery code. Use this in a wallet or tool that
// legitimately owns the key; a web page should send its messages to QoreX instead (see below).
const pqc = await pqcKeyFromRecoveryCode(userRecoveryCode, account.address);
const adapter = new QoreChainSigner({
wallet: window.keplr,
chainId: "qorechain-vladi",
address: account.address,
pubkeySecp256k1: account.pubkey,
accountNumber, // from GET /cosmos/auth/v1beta1/accounts/{address}
pqc,
rest: "https://api.qore.host", // lets the signer pick the sign-bytes form this network verifies
});
const txRaw = await adapter.signHybrid({ messages, fee, sequence }); // TxRaw bytes, with .signBytesVersion
// broadcast txRaw yourself (RPC broadcast_tx_sync or REST /cosmos/tx/v1beta1/txs)
知っておくべきこと:
- アダプターは署名し、ブロードキャストはあなたが行います。鍵登録メッセージは構築しません。アカウントの ML-DSA-87 鍵は、QoreSign(
buildRegisterPqKeyMessage)、SDK、または CLI で一度だけ登録してください(鍵の登録を参照)。この最初のトランザクションは、従来型の署名でもかまいません。 - アカウントの ML-DSA-87 鍵をウェブページが保持する設計は避けるべきです。以前はウォレット署名から鍵を導出していた
derivePqcKeyFromWalletは 0.3.0 で廃止され、常に例外をスローします。dApp はメッセージを QoreX(下記)に送り、ウォレットに署名させてください。 pqcコード 21 でブロードキャストが拒否され、"auto"を使っていた場合は、adapter.refreshSignBytesVersion()を呼び出してもう一度署名してください。明示的な"v1"または"v2"を渡していた場合は再試行しないでください。コード 21 のトラブルシューティングを参照してください。
QoreX 経由で送信する
import {
hasQorexSignAndBroadcast, qorexSignAndBroadcast, isQorexRejection,
} from "@qorechain/wallet-adapter";
import { MsgSend } from "cosmjs-types/cosmos/bank/v1beta1/tx.js";
if (!hasQorexSignAndBroadcast()) throw new Error("Install or update QoreX");
try {
const { txHash, code } = await qorexSignAndBroadcast({
chainId: "qorechain-vladi", // must equal the wallet's active network
messages: [{
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: MsgSend.encode(MsgSend.fromPartial({ fromAddress, toAddress, amount })).finish(),
}],
gasLimit: 300_000, // optional, 100,000 to 5,000,000
});
if (code !== 0) throw new Error(`rejected by the chain with code ${code}`);
} catch (err) {
if (isQorexRejection(err)) return; // the user declined; not a failure
throw err;
}
value はプロトコルバッファのバイト列(Uint8Array、数値配列、または base64)で、与えられたとおりに署名されます。dApp からウォレットのネットワークを切り替えることはできません。QoreX 拡張機能 0.3.5 またはアプリ 1.1.5 以降が必要です。バージョンチェックではなく hasQorexSignAndBroadcast() でテストしてください。ワイヤレベルのコントラクトは QoreX ブラウザ拡張機能にあります。
EVM ウィンドウのメッセージを構築する
import { openEvmWindowMsg, fetchEvmWindow } from "@qorechain/wallet-adapter";
const status = await fetchEvmWindow({ rest: "https://api.qore.host", address: qor1 });
if (!status.live) {
const msg = openEvmWindowMsg({
sender: qor1,
blocks: 300, // 1 to 17280
maxTxs: 3, // 1 to 1000
maxValue: "250000", // uqor: value plus the maximum fee of each admitted transaction
});
// sign it with signHybrid (or signHybridEth) and broadcast: it is an ordinary Cosmos-lane message
}
順序が重要です。ウィンドウを開き、次に EVM ノンスを読み取り、その後で EVM トランザクションに署名してください。ウィンドウを開くとアカウントのシーケンスが進み、それが EVM ノンスでもあるためです。openEvmWindowMsg が構築するのはスコープなしの形式のウィンドウのみで、スコープ付きウィンドウ(native_only、allowed_targets)には SDK が必要です。背景: EVM 認可ウィンドウと初めてのトランザクション。
その他のエントリーポイント
| タスク | 関数 |
|---|---|
| PQC 鍵の復元またはローテーション | generatePqcRecoveryCode, pqcKeyFromRecoveryCode, isValidRecoveryCode, rotatePqcKeyMsgFromMnemonic, rotateFromLegacyWalletKey, rotatePqcKeyMsg |
| イーサリアムネイティブ鍵で署名 | signClassicalEth(従来型の鍵登録), signHybridEth |
| 署名対象バイト列のヘルパー | hybridSignBytes(version, chainId, body, authInfo), resolveSignBytesVersion, signBytesVersionFor, SIGN_BYTES_V2_UPGRADES |
| 外部鍵のリンクと支出 | registerAuthenticatorMsg, registerEthAuthenticatorMsg, revokeAuthenticatorMsg, buildPhantom* および buildMetaMask* 関数 |
アクセス方法
- ネットワーク: メインネット
qorechain-vladiとテストネットqorechain-diana。chainIdと、対応するrestURL を渡してください(エンドポイント)。 - ウォレット: QoreSign ガイドと例では Keplr を使用しています(Keplr 互換ウォレット)。Leap と Cosmostation は同じ
signDirectインターフェースを公開しており、このパッケージはそのようなウォレットすべてを想定して書かれていますが、このページのためにそれらに対しては確認していません。MetaMask はアダプターの署名者ではなく EVM レーンを使用し、送信のたびに開いた EVM ウィンドウが必要です(開発者パッケージ)。Phantom はオーセンティケーターとしてリンクされます。 - アカウントと鍵: 手数料用に QOR が入金されたアカウントと、最初のハイブリッドトランザクションの前にオンチェーンで登録されたアカウントの ML-DSA-87 鍵。
- 前提条件: ES モジュールに対応した Node.js、またはブラウザ向けのバンドラー。ピア依存関係は
@cosmjs/stargateと@cosmjs/proto-signingの^0.32。ランタイム依存関係:@qorechain/pqc^0.2.1、cosmjs-types^0.9.0、@cosmjs/cryptoと@cosmjs/encodingの^0.32。 - コスト: パッケージは無料です。トランザクションはガス 1 単位あたり 0.1 uqor 以上のネットワーク手数料を支払います。ML-DSA-87 公開鍵は 2,592 バイトのため、鍵の登録には大きなガスリミットが使われます。
公開場所
| レジストリ | パッケージ | バージョン | リンク |
|---|---|---|---|
| npm | @qorechain/wallet-adapter | 0.4.0(2026年10月20日公開) | npmjs.com |
ソース: github.com/qorechain/qorechain-wallet-adapter(公開、タグ v0.4.0、Apache-2.0)。PyPI、crates.io、Maven Central、Go プロキシでは公開されていません。関連: 開発者パッケージ、QoreSign、ポスト量子署名、取引所統合。
制限と既知の問題
- 署名のみを行い、ブロードキャスト、鍵の登録、ウィンドウを開くことはしません。 ML-DSA-87 鍵を登録する関数はなく、EVM ウィンドウを代わりに開くものもありません。
- 所有証明はありません。 このパッケージだけを使うツールで行った鍵登録には、所有証明が付きません。チェーンはそれでも受け付け、証明がある場合はそれを検証します(所有証明)。
derivePqcKeyFromWalletは廃止されており(0.3.0)、常に例外をスローします。それで鍵を登録したアカウントは、rotateFromLegacyWalletKeyでローテーションしてください。- スコープなしのウィンドウのみ。
openEvmWindowMsgにはスコープのフィールドがありません。 qoreChainInfoのデフォルトはテストネットです。 メインネットでは必ずchainIdを渡してください。- オーセンティケーターのノンス。 リンクキーのオーセンティケーターシーケンスを公開するクエリはまだないため、自分で追跡する必要があります。値が誤っている場合、チェーンは
abstractaccountコード 11 を返します。オーセンティケーターモジュールはテストネットでは有効で、メインネットではオフになっています(SDK の概要を参照)。 - cosmjs 0.32 のピア依存。 SDK は cosmjs 0.39 を使用します。1 つのプロジェクトに両方をインストールすると
ERESOLVEエラーになるため、分けておくか--legacy-peer-depsを渡してください。 - パッケージの README からコピーしないでください。 README には、メインネットが最初の署名対象バイト列形式を検証すること、MetaMask の送信に追加の手順が不要であることが、まだ書かれています。どちらも古い内容です。両方のネットワークが v2 を検証し、EVM の送信には登録済みの鍵と開いたウィンドウが必要です。
- テスト済みのクイックスタートは記録されていません。 このパッケージには記録がなく、QoreX の経路はウォレットのインストールが必要なため、スクリプトでは実行できません。