@qorechain/wallet-adapter 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -5
- package/package.json +1 -1
- package/src/index.d.ts +42 -0
- package/src/index.js +1 -1
- package/src/wallet.js +34 -0
package/README.md
CHANGED
|
@@ -72,15 +72,24 @@ await fetch(`${rpc}`, { method:'POST', body: JSON.stringify({
|
|
|
72
72
|
| **Keplr** | `experimentalSuggestChain` + `signDirect` | ✅ supported |
|
|
73
73
|
| **Leap / Cosmostation** | same `signDirect` interface | ✅ supported (any wallet exposing `signDirect`) |
|
|
74
74
|
| **MetaMask** | uses QoreChain's **EVM** path (chainId 9800) — structurally PQC-exempt | ✅ works natively, no adapter needed |
|
|
75
|
-
| **Phantom** |
|
|
75
|
+
| **Phantom** | derive a unified account from a Phantom signature (`walletFromSeed`) | ✅ connect → qor1/0x/svm, receive on any, spend on any (incl. hybrid PQC) |
|
|
76
76
|
|
|
77
77
|
## API
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
- `
|
|
81
|
-
- `
|
|
79
|
+
Wallet generation & unified addresses:
|
|
80
|
+
- `generateQoreWallet(strength?)` / `walletFromMnemonic(mnemonic)` / `walletFromSeed(seed32)` — a unified wallet `{ mnemonic, privateKey, pubkey, cosmos, evm, svm, pqc }`.
|
|
81
|
+
- `addressesFrom20(bytes20)` / `qoreAddresses({cosmos|evm|hex})` — the three encodings of a known account.
|
|
82
|
+
|
|
83
|
+
eth-native Cosmos signing (chain ≥ v3.1.83):
|
|
84
|
+
- `signClassicalEth({ key, chainId, accountNumber, sequence, messages, fee, memo?, timeoutHeight? })` → `TxRaw` bytes (classical, e.g. PQC key registration).
|
|
85
|
+
- `signHybridEth({ ... })` → `TxRaw` bytes (eth_secp256k1 + ML-DSA-87 hybrid).
|
|
86
|
+
- `ETHSECP256K1_PUBKEY_TYPE` — the eth pubkey type URL.
|
|
87
|
+
|
|
88
|
+
Keplr / any-signDirect adapter + PQC framing:
|
|
82
89
|
- `QoreChainSigner#signHybrid({ messages, fee, sequence, memo?, timeoutHeight? })` → `TxRaw` bytes.
|
|
83
|
-
- `
|
|
90
|
+
- `derivePqcKeyFromWallet(wallet, chainId, address)` — deterministic ML-DSA-87 key from a wallet signature.
|
|
91
|
+
- `frame(b0, auth)` — QoreChain hybrid sign-bytes framing; `encodePqcHybridSignature(algId, sig)` — proto encoder for the extension.
|
|
92
|
+
- `qoreChainInfo({ chainId?, rpc, rest })` — Keplr chain descriptor; `qoreEvmChainParams(...)` / `addQoreEvmToWallet(provider, opts)` — MetaMask (EIP-3085) EVM descriptor.
|
|
84
93
|
|
|
85
94
|
## License
|
|
86
95
|
|
|
@@ -112,3 +121,52 @@ under which the chain reads one `x/bank` balance. The account can sign EVM txs
|
|
|
112
121
|
|
|
113
122
|
`addressesFrom20(bytes20)` / `qoreAddresses({cosmos|evm|hex})` derive the three
|
|
114
123
|
encodings from a known account (for explorers / backends).
|
|
124
|
+
|
|
125
|
+
### Derive from a seed (Phantom & other non-mnemonic flows)
|
|
126
|
+
|
|
127
|
+
`walletFromSeed(seed32)` builds the same unified wallet from any 32 bytes (the
|
|
128
|
+
seed becomes the secp256k1 key). Because a wallet's signature over a fixed message
|
|
129
|
+
is deterministic, you can derive **one canonical QoreChain account from a Phantom
|
|
130
|
+
(ed25519) signature** — a Phantom user connects once and gets three usable
|
|
131
|
+
QoreChain addresses they fully control:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
import { walletFromSeed } from "@qorechain/wallet-adapter";
|
|
135
|
+
import { shake256 } from "@qorechain/pqc";
|
|
136
|
+
|
|
137
|
+
const msg = new TextEncoder().encode("QoreChain unified account derivation v1");
|
|
138
|
+
const { signature } = await window.solana.signMessage(msg); // Phantom, deterministic
|
|
139
|
+
const w = await walletFromSeed(shake256(signature, 32)); // → qor1 / 0x / svm + pqc
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## eth-native Cosmos signing (requires chain ≥ v3.1.83)
|
|
143
|
+
|
|
144
|
+
The unified account **signs on the Cosmos lane too**, with the `eth_secp256k1`
|
|
145
|
+
scheme (secp256k1 over `keccak256(signBytes)`, pubkey
|
|
146
|
+
`/cosmos.evm.crypto.v1.ethsecp256k1.PubKey`). `signClassicalEth` builds a
|
|
147
|
+
classical-only tx (for the one-time, bootstrap-exempt PQC key registration);
|
|
148
|
+
`signHybridEth` adds the ML-DSA-87 hybrid signature the ante requires for
|
|
149
|
+
everything else. Both return broadcast-ready `TxRaw` bytes.
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
import { walletFromMnemonic, signClassicalEth, signHybridEth } from "@qorechain/wallet-adapter";
|
|
153
|
+
|
|
154
|
+
const key = await walletFromMnemonic(mnemonic); // has { privateKey, pubkey, pqc }
|
|
155
|
+
const fee = { amount: [{ denom: "uqor", amount: "30000" }], gasLimit: 300000n };
|
|
156
|
+
|
|
157
|
+
// 1) one-time: register the account's ML-DSA-87 key (classical, PQC-exempt)
|
|
158
|
+
const regTx = await signClassicalEth({ key, chainId, accountNumber, sequence,
|
|
159
|
+
messages: [{ typeUrl: "/qorechain.pqc.v1.MsgRegisterPQCKeyV2", value: registerMsgBytes }],
|
|
160
|
+
fee: { amount: [{ denom: "uqor", amount: "600000" }], gasLimit: 6000000n } });
|
|
161
|
+
|
|
162
|
+
// 2) thereafter: hybrid eth_secp256k1 + ML-DSA-87 (e.g. a bank MsgSend)
|
|
163
|
+
const sendTx = await signHybridEth({ key, chainId, accountNumber, sequence,
|
|
164
|
+
messages: [{ typeUrl: "/cosmos.bank.v1beta1.MsgSend", value: msgSendBytes }], fee });
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> **Requires QoreChain ≥ v3.1.83** — that release registers the `eth_secp256k1`
|
|
168
|
+
> pubkey on the node's interface registry so eth-native Cosmos txs decode. Both
|
|
169
|
+
> `qorechain-diana` (testnet) and `qorechain-vladi` (mainnet) run it.
|
|
170
|
+
> `@qorechain/chain-bridge` wraps this server-side (`keyType: 'eth_secp256k1'`,
|
|
171
|
+
> auto-registers the PQC key on first send). **Proven live** on QoreChain: register
|
|
172
|
+
> (code 0) + hybrid send (code 0) + an EVM transfer from the same key, one balance.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qorechain/wallet-adapter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Drop-in adapter to add QoreChain to any Cosmos wallet (Keplr, Leap, Cosmostation, …) and sign its PQC-required transactions. The wallet signs an ordinary SIGN_MODE_DIRECT SignDoc; the adapter layers a standard FIPS-204 ML-DSA-87 hybrid signature into the tx body, so no wallet code changes are needed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/index.d.ts
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
export const HYBRID_SIG_TYPE_URL: string;
|
|
2
2
|
export const ALGORITHM_ML_DSA_87: number;
|
|
3
3
|
|
|
4
|
+
// --- Unified wallet generation (one eth-native key → qor1 / 0x / svm) ---
|
|
5
|
+
export interface PqcKeypair { publicKey: Uint8Array; secretKey: Uint8Array; }
|
|
6
|
+
export interface QoreAddresses {
|
|
7
|
+
addressBytes: Uint8Array;
|
|
8
|
+
cosmos: string; // qor1… (bech32)
|
|
9
|
+
evm: string; // 0x… (EIP-55)
|
|
10
|
+
svm: string; // base58
|
|
11
|
+
}
|
|
12
|
+
export interface QoreWallet extends QoreAddresses {
|
|
13
|
+
mnemonic: string | null;
|
|
14
|
+
privateKey: string; // 0x-hex, 32 bytes
|
|
15
|
+
pubkey: string; // 0x-hex, 33-byte compressed secp256k1
|
|
16
|
+
pqc: PqcKeypair; // ML-DSA-87 (Dilithium-5)
|
|
17
|
+
}
|
|
18
|
+
export function generateQoreWallet(strength?: number): Promise<QoreWallet>;
|
|
19
|
+
export function walletFromMnemonic(mnemonic: string): Promise<QoreWallet>;
|
|
20
|
+
export function walletFromSeed(seed: Uint8Array | string): Promise<QoreWallet>;
|
|
21
|
+
export function addressesFrom20(addr20: Uint8Array): QoreAddresses;
|
|
22
|
+
export function qoreAddresses(opts: { cosmos?: string; evm?: string; hex?: string }): QoreAddresses;
|
|
23
|
+
|
|
24
|
+
// --- eth-native (eth_secp256k1) Cosmos signing (requires chain >= v3.1.83) ---
|
|
25
|
+
export const ETHSECP256K1_PUBKEY_TYPE: string;
|
|
26
|
+
export interface EthSignKey { privateKey: Uint8Array | string; pubkey: Uint8Array | string; pqc?: PqcKeypair; }
|
|
27
|
+
export interface EthSignArgs {
|
|
28
|
+
key: EthSignKey;
|
|
29
|
+
chainId: string;
|
|
30
|
+
accountNumber: number | bigint;
|
|
31
|
+
messages: Array<{ typeUrl: string; value: Uint8Array }>;
|
|
32
|
+
fee: any;
|
|
33
|
+
sequence: number | bigint;
|
|
34
|
+
memo?: string;
|
|
35
|
+
timeoutHeight?: bigint;
|
|
36
|
+
}
|
|
37
|
+
/** Classical-only eth_secp256k1 Cosmos tx (e.g. the bootstrap MsgRegisterPQCKeyV2). */
|
|
38
|
+
export function signClassicalEth(args: EthSignArgs): Promise<Uint8Array>;
|
|
39
|
+
/** Hybrid eth_secp256k1 + ML-DSA-87 Cosmos tx (key.pqc required). */
|
|
40
|
+
export function signHybridEth(args: EthSignArgs): Promise<Uint8Array>;
|
|
41
|
+
|
|
42
|
+
// --- EVM network descriptors (EIP-3085 / MetaMask) ---
|
|
43
|
+
export function qoreEvmChainParams(opts?: { evmChainId?: number; rpcUrl?: string; wsUrl?: string; explorerUrl?: string; testnet?: boolean }): any;
|
|
44
|
+
export function addQoreEvmToWallet(provider: any, opts?: any): Promise<any>;
|
|
45
|
+
|
|
4
46
|
// --- Phantom / any-ed25519-wallet support ---
|
|
5
47
|
export const SYSTEM_PROGRAM_ID: string;
|
|
6
48
|
export function base58Encode(bytes: Uint8Array): string;
|
package/src/index.js
CHANGED
|
@@ -31,7 +31,7 @@ export {
|
|
|
31
31
|
} from './phantom.js';
|
|
32
32
|
// Unified wallet generation: one eth-native key → cosmos/evm/svm addresses + PQC key.
|
|
33
33
|
export {
|
|
34
|
-
generateQoreWallet, walletFromMnemonic, addressesFrom20, qoreAddresses,
|
|
34
|
+
generateQoreWallet, walletFromMnemonic, walletFromSeed, addressesFrom20, qoreAddresses,
|
|
35
35
|
} from './wallet.js';
|
|
36
36
|
// eth-native (eth_secp256k1) Cosmos signing — classical (register) + hybrid (PQC).
|
|
37
37
|
export {
|
package/src/wallet.js
CHANGED
|
@@ -86,6 +86,40 @@ export async function walletFromMnemonic(mnemonic) {
|
|
|
86
86
|
return fromMnemonicObj(mnemonic);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Derive a unified QoreChain wallet directly from a 32-byte seed (no mnemonic).
|
|
91
|
+
*
|
|
92
|
+
* The seed is used as the secp256k1 private key, so a caller can derive one
|
|
93
|
+
* canonical eth-native account deterministically from any 32 bytes — e.g.
|
|
94
|
+
* `shake256(phantomSignature)` for the Phantom "connect → 3 addresses" flow, or
|
|
95
|
+
* an HKDF/KDF output from another wallet. Same 20-byte identity model as
|
|
96
|
+
* `walletFromMnemonic`: qor1 / 0x / svm all resolve to the same account and the
|
|
97
|
+
* same balance, and the key signs on every interface (incl. hybrid PQC).
|
|
98
|
+
*
|
|
99
|
+
* The ML-DSA-87 key is bound to `qorechain:pqc:v1|<qor1>|seed:<hex>` so it is
|
|
100
|
+
* recoverable from the same seed and never collides with a mnemonic wallet.
|
|
101
|
+
* `seed` accepts a 32-byte Uint8Array or a (0x-)hex string.
|
|
102
|
+
*/
|
|
103
|
+
export async function walletFromSeed(seed) {
|
|
104
|
+
const privkey = typeof seed === 'string' ? fromHex(seed.replace(/^0x/, '')) : seed;
|
|
105
|
+
if (!(privkey instanceof Uint8Array) || privkey.length !== 32) {
|
|
106
|
+
throw new Error('seed must be 32 bytes (Uint8Array or hex)');
|
|
107
|
+
}
|
|
108
|
+
const kp = await Secp256k1.makeKeypair(privkey); // validates the scalar is in [1, n-1]
|
|
109
|
+
const uncompressed = kp.pubkey;
|
|
110
|
+
const compressed = Secp256k1.compressPubkey(uncompressed);
|
|
111
|
+
const addr20 = new Keccak256(uncompressed.slice(1)).digest().slice(12);
|
|
112
|
+
const enc = addressesFrom20(addr20);
|
|
113
|
+
const pqcSeed = shake256(new TextEncoder().encode(`qorechain:pqc:v1|${enc.cosmos}|seed:${toHex(privkey)}`), 32);
|
|
114
|
+
return {
|
|
115
|
+
mnemonic: null,
|
|
116
|
+
privateKey: '0x' + toHex(privkey),
|
|
117
|
+
pubkey: '0x' + toHex(compressed),
|
|
118
|
+
...enc,
|
|
119
|
+
pqc: mldsa.keygen(pqcSeed),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
89
123
|
/** Convenience: the three address encodings of an existing account. */
|
|
90
124
|
export function qoreAddresses({ cosmos, evm, hex }) {
|
|
91
125
|
let addr20;
|