shell-sdk 0.6.0 → 0.7.1
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/CHANGELOG.md +64 -0
- package/README.md +22 -20
- package/dist/adapters.d.ts +4 -6
- package/dist/adapters.js +4 -6
- package/dist/address.d.ts +5 -32
- package/dist/address.js +10 -62
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -2
- package/dist/keystore.d.ts +3 -8
- package/dist/keystore.js +17 -26
- package/dist/provider.d.ts +11 -8
- package/dist/provider.js +5 -3
- package/dist/signer.d.ts +5 -13
- package/dist/signer.js +12 -20
- package/dist/system-contracts.d.ts +7 -15
- package/dist/system-contracts.js +13 -29
- package/dist/transactions.js +6 -6
- package/dist/types.d.ts +88 -3
- package/dist/types.js +33 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.1] — 2026-05-06
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Typed Shell RPC reward metadata for address-history and transaction-summary
|
|
7
|
+
responses, including block gas rewards, STARK rewards, reward layers,
|
|
8
|
+
source hashes, and compression accounting fields.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Preserve pq1-only compatibility from `0.7.0` while aligning the SDK type
|
|
12
|
+
surface with `shell-chain v0.21.1`.
|
|
13
|
+
|
|
14
|
+
## [0.7.0] — 2026-04-30 ⚠️ BREAKING
|
|
15
|
+
|
|
16
|
+
### Breaking Changes — F-PQ1-ONLY (pq1 bech32m addresses everywhere)
|
|
17
|
+
|
|
18
|
+
This is a **breaking release**. All `0x` hex address support has been removed.
|
|
19
|
+
|
|
20
|
+
#### Removed
|
|
21
|
+
- `hexAddress()` / `hexAddressFromPubkey()` exports deleted — use `pq1Address()` instead.
|
|
22
|
+
- `normalizePqAddress()` no longer accepts `0x...` hex strings — only `pq1...` bech32m.
|
|
23
|
+
- Keystore `address` field: `encryptKeystore()` now always emits `pq1...` bech32m (was `0x...` hex).
|
|
24
|
+
- `decryptKeystore()` rejects keystores with `0x` address fields (use `shell-node key migrate` first).
|
|
25
|
+
|
|
26
|
+
#### Added
|
|
27
|
+
- `pq1Address(pubkey, sigType)` — canonical address derivation returning `pq1...` bech32m string.
|
|
28
|
+
- SK-only keystore format: `encryptKeystore` stores only the secret key in ciphertext (no pk concatenation), matching `shell-node key generate` output for full cross-language compatibility.
|
|
29
|
+
- Full cross-format compatibility: SDK keystores are now byte-for-byte compatible with Rust CLI keystores.
|
|
30
|
+
|
|
31
|
+
#### Updated
|
|
32
|
+
- All SDK test fixtures regenerated with `pq1` addresses.
|
|
33
|
+
- `SIGNATURE_TYPE_IDS.MlDsa65 = 1` (was incorrectly aliased to `0` in v0.6.x).
|
|
34
|
+
- ML-DSA-65 (FIPS 204) via `@noble/post-quantum` — real implementation, not a Dilithium3 alias.
|
|
35
|
+
|
|
36
|
+
### Migration Guide
|
|
37
|
+
```js
|
|
38
|
+
// Before (0.6.x)
|
|
39
|
+
import { hexAddress } from 'shell-sdk';
|
|
40
|
+
const addr = hexAddress(pubkey, sigType); // "0x..."
|
|
41
|
+
|
|
42
|
+
// After (0.7.0)
|
|
43
|
+
import { pq1Address } from 'shell-sdk';
|
|
44
|
+
const addr = pq1Address(pubkey, sigType); // "pq1..."
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For existing keystores with `0x` addresses: run `shell-node key migrate <keystore.json>` to upgrade to pq1 format.
|
|
48
|
+
|
|
49
|
+
### Compatibility
|
|
50
|
+
- Requires `shell-chain v0.21.0+` (pq1-only RPC).
|
|
51
|
+
- Not backwards-compatible with SDK `0.6.x` address handling.
|
|
52
|
+
|
|
53
|
+
## [0.6.0] — 2026-04-27
|
|
54
|
+
|
|
55
|
+
### Added — ML-DSA-65 (FIPS 204) + Keystore SK-only format
|
|
56
|
+
|
|
57
|
+
#### Crypto (`keystore.ts`, `address.ts`)
|
|
58
|
+
- **`MlDsa65Adapter`**: real FIPS 204 ML-DSA-65 implementation via `@noble/post-quantum`.
|
|
59
|
+
- **`SIGNATURE_TYPE_IDS.MlDsa65 = 1`**: ML-DSA-65 is now a distinct algorithm (was aliased to Dilithium3=0).
|
|
60
|
+
- **SK-only keystore**: `encryptKeystore` stores only secret key bytes in ciphertext, matching `shell-node` CLI format. Cross-language compatible.
|
|
61
|
+
- **`decryptCliKeystore`** helper removed — standard `decryptKeystore` now handles CLI keystores.
|
|
62
|
+
|
|
63
|
+
#### Compatibility
|
|
64
|
+
- Fully cross-language compatible: Rust CLI keystores decryptable by SDK and vice versa.
|
|
65
|
+
- `shell-chain v0.20.0+` required for ML-DSA-65 transaction signing.
|
|
66
|
+
|
|
3
67
|
## [0.5.0] — 2026-04-26
|
|
4
68
|
|
|
5
69
|
### Added — AA Phase 2 (matches `shell-chain v0.19.0`)
|
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
- **Native account abstraction** — key rotation and custom validation code via system contracts
|
|
41
41
|
- **viem integration** — standard Ethereum JSON-RPC methods via a typed `PublicClient`
|
|
42
42
|
- **Shell-specific RPC** — `shell_getPqPubkey`, `shell_sendTransaction`, `shell_getTransactionsByAddress`, `shell_getNodeInfo`, `shell_getWitness`
|
|
43
|
+
- **Reward-aware history types** — block/address transaction summaries expose readable `shellType`, `rewardKind`, and STARK reward metadata (`rewardLayer`, `rewardSourceHash`, `originalSize`, `compressedSize`)
|
|
43
44
|
- **Node introspection** — `getNodeInfo()` returns version, block height, peer count, and storage profile; `getWitness()` fetches raw PQ signatures for any block
|
|
44
45
|
- **Encrypted keystore** — argon2id KDF + xchacha20-poly1305 cipher; compatible with the Shell CLI
|
|
45
46
|
|
|
@@ -78,7 +79,7 @@ const signer = new ShellSigner("MlDsa65", adapter);
|
|
|
78
79
|
const from = signer.getAddress(); // pq1…
|
|
79
80
|
|
|
80
81
|
const provider = createShellProvider();
|
|
81
|
-
const nonce = await provider.client.getTransactionCount({ address:
|
|
82
|
+
const nonce = await provider.client.getTransactionCount({ address: from });
|
|
82
83
|
|
|
83
84
|
const tx = buildTransferTransaction({ chainId: 424242, nonce, to: "pq1recipient…", value: parseEther("1") });
|
|
84
85
|
const txHash = hashTransaction(tx);
|
|
@@ -107,7 +108,7 @@ blake3( version(1) || algo_id(1) || public_key )[0..20]
|
|
|
107
108
|
|
|
108
109
|
Algorithm IDs: `Dilithium3=0`, `MlDsa65=1`, `SphincsSha2256f=2`.
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
Shell Chain v0.21.0+ accepts `pq1…` addresses at user-facing RPC and SDK boundaries. Legacy `0x…` address inputs are rejected.
|
|
111
112
|
|
|
112
113
|
### Native account abstraction (AA)
|
|
113
114
|
|
|
@@ -147,7 +148,9 @@ Defined in `src/types.ts`. All types are re-exported from the package root.
|
|
|
147
148
|
| `ShellSignature` | `{ sig_type, data: number[] }` |
|
|
148
149
|
| `SignedShellTransaction` | Complete signed transaction ready to broadcast |
|
|
149
150
|
| `ShellAccessListItem` | EIP-2930 access list entry |
|
|
150
|
-
| `
|
|
151
|
+
| `ShellKnownRpcTxType` | Literal union of known Shell RPC transaction kinds |
|
|
152
|
+
| `ShellRpcTransactionSummary` | Lightweight transaction summary with Shell reward metadata |
|
|
153
|
+
| `ShellTxByAddressPage` | Paginated address history response with effective `fromBlock`/`toBlock` range |
|
|
151
154
|
| `ShellKdfParams` | argon2id parameters inside a keystore |
|
|
152
155
|
| `ShellCipherParams` | xchacha20-poly1305 nonce inside a keystore |
|
|
153
156
|
| `ShellEncryptedKey` | Full encrypted keystore file structure |
|
|
@@ -173,10 +176,7 @@ Defined in `src/types.ts`. All types are re-exported from the package root.
|
|
|
173
176
|
| `bytesToPqAddress` | `(bytes: Uint8Array, version?) → string` | Encode 20 raw bytes as a `pq1…` bech32m address |
|
|
174
177
|
| `pqAddressToBytes` | `(address: string) → Uint8Array` | Decode a `pq1…` address to its 20 raw bytes |
|
|
175
178
|
| `pqAddressVersion` | `(address: string) → number` | Extract the version byte from a `pq1…` address |
|
|
176
|
-
| `
|
|
177
|
-
| `bytesToHexAddress` | `(bytes: Uint8Array) → HexString` | Encode 20 bytes as a `0x…` hex address |
|
|
178
|
-
| `normalizePqAddress` | `(address: string) → string` | Accept either pq1 or 0x form, always return pq1 |
|
|
179
|
-
| `normalizeHexAddress` | `(address: string) → HexString` | Accept either pq1 or 0x form, always return 0x |
|
|
179
|
+
| `normalizePqAddress` | `(address: string) → string` | Validate and return a `pq1…` address |
|
|
180
180
|
| `derivePqAddressFromPublicKey` | `(pk, algoId, version?) → string` | Derive pq1 address from a raw public key |
|
|
181
181
|
| `isPqAddress` | `(address: string) → boolean` | Return `true` if the string is a valid pq1 address |
|
|
182
182
|
|
|
@@ -194,9 +194,9 @@ const address = derivePqAddressFromPublicKey(publicKey, 1 /* MlDsa65 */);
|
|
|
194
194
|
|
|
195
195
|
console.log(isPqAddress(address)); // true
|
|
196
196
|
|
|
197
|
-
//
|
|
198
|
-
normalizePqAddress("0xabcdef…"); // → "pq1…"
|
|
197
|
+
// Validation / normalisation
|
|
199
198
|
normalizePqAddress("pq1qx3f…"); // → "pq1qx3f…" (unchanged)
|
|
199
|
+
normalizePqAddress("0xabcdef…"); // throws: expected a pq1… bech32m address
|
|
200
200
|
```
|
|
201
201
|
|
|
202
202
|
---
|
|
@@ -236,8 +236,8 @@ import { shellDevnet } from "shell-sdk/provider";
|
|
|
236
236
|
| `.rpcHttpUrl` | HTTP RPC URL in use |
|
|
237
237
|
| `getPqPubkey(address)` | `shell_getPqPubkey` → hex public key or `null` |
|
|
238
238
|
| `sendTransaction(signed)` | `shell_sendTransaction` → tx hash string |
|
|
239
|
-
| `getTransactionsByAddress(address, opts)` | `shell_getTransactionsByAddress` with optional `fromBlock/toBlock/page/limit` |
|
|
240
|
-
| `getBlockReceipts(block)` | `eth_getBlockReceipts` →
|
|
239
|
+
| `getTransactionsByAddress(address, opts)` | `shell_getTransactionsByAddress` with optional `fromBlock/toBlock/page/limit`; pin `toBlock` from page 0 for stable full-history pagination |
|
|
240
|
+
| `getBlockReceipts(block)` | `eth_getBlockReceipts` → `ShellRpcReceipt[]` |
|
|
241
241
|
| `getNodeInfo()` | `shell_getNodeInfo` → `ShellNodeInfo` (version, block height, peer count, storage profile) |
|
|
242
242
|
| `getWitness(blockNumberOrHash)` | `shell_getWitness` → `ShellWitnessBundle` or `null` if pruned |
|
|
243
243
|
| `getStorageProfile()` | Convenience wrapper around `getNodeInfo()` → `ShellStorageProfile \| undefined` |
|
|
@@ -258,6 +258,11 @@ const pubkeyHex = await provider.getPqPubkey("pq1…");
|
|
|
258
258
|
const txHash = await provider.sendTransaction(signedTx);
|
|
259
259
|
|
|
260
260
|
const history = await provider.getTransactionsByAddress("pq1…", { page: 0, limit: 20 });
|
|
261
|
+
const older = await provider.getTransactionsByAddress("pq1…", {
|
|
262
|
+
page: 1,
|
|
263
|
+
limit: 20,
|
|
264
|
+
toBlock: history.toBlock ?? history.to_block,
|
|
265
|
+
});
|
|
261
266
|
```
|
|
262
267
|
|
|
263
268
|
**Custom endpoint:**
|
|
@@ -334,7 +339,6 @@ const signer = new ShellSigner("MlDsa65", MlDsa65Adapter.generate());
|
|
|
334
339
|
| `algorithmId` | Numeric algorithm ID (`0`, `1`, or `2`) |
|
|
335
340
|
| `getPublicKey()` | Raw public key bytes |
|
|
336
341
|
| `getAddress()` | `pq1…` bech32m address |
|
|
337
|
-
| `getHexAddress()` | `0x…` hex address |
|
|
338
342
|
| `sign(message)` | Sign an arbitrary byte message → signature bytes |
|
|
339
343
|
| `buildSignedTransaction(options)` | Sign `txHash` and assemble a `SignedShellTransaction` |
|
|
340
344
|
|
|
@@ -568,7 +572,6 @@ import { buildTransferTransaction, hashTransaction } from "shell-sdk/transaction
|
|
|
568
572
|
const adapter = MlDsa65Adapter.generate();
|
|
569
573
|
const signer = new ShellSigner("MlDsa65", adapter);
|
|
570
574
|
const from = signer.getAddress(); // pq1…
|
|
571
|
-
const fromHex = signer.getHexAddress(); // 0x…
|
|
572
575
|
|
|
573
576
|
console.log("Address:", from);
|
|
574
577
|
|
|
@@ -576,7 +579,7 @@ console.log("Address:", from);
|
|
|
576
579
|
const provider = createShellProvider(); // defaults to http://127.0.0.1:8545
|
|
577
580
|
|
|
578
581
|
// 3. Get current nonce
|
|
579
|
-
const nonce = await provider.client.getTransactionCount({ address:
|
|
582
|
+
const nonce = await provider.client.getTransactionCount({ address: from });
|
|
580
583
|
|
|
581
584
|
// 4. Build the transaction
|
|
582
585
|
const tx = buildTransferTransaction({
|
|
@@ -614,7 +617,7 @@ import { parseEther } from "viem";
|
|
|
614
617
|
|
|
615
618
|
const signer = await decryptKeystore(readFileSync("./key.json", "utf8"), process.env.PASSPHRASE!);
|
|
616
619
|
const provider = createShellProvider();
|
|
617
|
-
const nonce = await provider.client.getTransactionCount({ address: signer.
|
|
620
|
+
const nonce = await provider.client.getTransactionCount({ address: signer.getAddress() });
|
|
618
621
|
|
|
619
622
|
const tx = buildTransferTransaction({
|
|
620
623
|
chainId: 424242,
|
|
@@ -639,13 +642,13 @@ This is the recommended shape for a Chrome extension background worker: keep the
|
|
|
639
642
|
import { createShellProvider, buildTransferTransaction, hashTransaction } from "shell-sdk";
|
|
640
643
|
|
|
641
644
|
async function submitTransfer({ signer, to, value, rpcHttpUrl }: {
|
|
642
|
-
signer: {
|
|
645
|
+
signer: { getAddress(): string; buildSignedTransaction(args: { tx: unknown; txHash: Uint8Array; includePublicKey?: boolean }): Promise<unknown> };
|
|
643
646
|
to: string;
|
|
644
647
|
value: bigint;
|
|
645
648
|
rpcHttpUrl: string;
|
|
646
649
|
}) {
|
|
647
650
|
const provider = createShellProvider({ rpcHttpUrl });
|
|
648
|
-
const nonce = await provider.client.getTransactionCount({ address: signer.
|
|
651
|
+
const nonce = await provider.client.getTransactionCount({ address: signer.getAddress() });
|
|
649
652
|
|
|
650
653
|
const tx = buildTransferTransaction({
|
|
651
654
|
chainId: 424242,
|
|
@@ -671,7 +674,7 @@ const provider = createShellProvider({
|
|
|
671
674
|
rpcHttpUrl: "https://rpc.testnet.shell.network",
|
|
672
675
|
});
|
|
673
676
|
|
|
674
|
-
const account = normalizePqAddress("
|
|
677
|
+
const account = normalizePqAddress("pq1qx3f...");
|
|
675
678
|
const history = await provider.getTransactionsByAddress(account, { page: 1, limit: 10 });
|
|
676
679
|
|
|
677
680
|
console.log("recent txs:", history.transactions);
|
|
@@ -699,7 +702,7 @@ const currentSigner = await decryptKeystore(readFileSync("old-key.json", "utf8")
|
|
|
699
702
|
const newAdapter = MlDsa65Adapter.generate();
|
|
700
703
|
const newSigner = new ShellSigner("MlDsa65", newAdapter);
|
|
701
704
|
|
|
702
|
-
const nonce = await provider.client.getTransactionCount({ address: currentSigner.
|
|
705
|
+
const nonce = await provider.client.getTransactionCount({ address: currentSigner.getAddress() });
|
|
703
706
|
|
|
704
707
|
// Build the rotateKey system transaction
|
|
705
708
|
const tx = buildRotateKeyTransaction({
|
|
@@ -728,7 +731,6 @@ All SDK functions throw standard `Error` instances. Common error messages:
|
|
|
728
731
|
|---|---|
|
|
729
732
|
| `expected 20 address bytes, got N` | Wrong-length bytes passed to address helpers |
|
|
730
733
|
| `expected pq address prefix, got X` | bech32m prefix is not `pq` |
|
|
731
|
-
| `invalid hex address` | String does not start with `0x` |
|
|
732
734
|
| `invalid bech32m address` | String is not a valid bech32m address |
|
|
733
735
|
| `unsupported key type: X` | Keystore `key_type` not recognised |
|
|
734
736
|
| `unsupported kdf: X` | Only `argon2id` is supported |
|
package/dist/adapters.d.ts
CHANGED
|
@@ -4,12 +4,10 @@
|
|
|
4
4
|
* `@noble/post-quantum` provides ML-DSA-65 and SLH-DSA-SHA2-256f via
|
|
5
5
|
* WebAssembly-accelerated pure-JS implementations.
|
|
6
6
|
*
|
|
7
|
-
* **Dilithium3
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* wire-compatible with the chain's Dilithium3 verifier. Both `"Dilithium3"`
|
|
12
|
-
* and `"MlDsa65"` algorithm names route to the same adapter.
|
|
7
|
+
* **Algorithm distinction**: `"Dilithium3"` (type_id=0) and `"ML-DSA-65"` /
|
|
8
|
+
* `"MlDsa65"` (type_id=1) are now separate algorithms on chain with distinct
|
|
9
|
+
* address derivation. `MlDsa65Adapter` and `DilithiumAdapter` both use the
|
|
10
|
+
* same underlying `ml_dsa65` crypto (FIPS 204), but produce different addresses.
|
|
13
11
|
*
|
|
14
12
|
* @module adapters
|
|
15
13
|
*/
|
package/dist/adapters.js
CHANGED
|
@@ -4,12 +4,10 @@
|
|
|
4
4
|
* `@noble/post-quantum` provides ML-DSA-65 and SLH-DSA-SHA2-256f via
|
|
5
5
|
* WebAssembly-accelerated pure-JS implementations.
|
|
6
6
|
*
|
|
7
|
-
* **Dilithium3
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* wire-compatible with the chain's Dilithium3 verifier. Both `"Dilithium3"`
|
|
12
|
-
* and `"MlDsa65"` algorithm names route to the same adapter.
|
|
7
|
+
* **Algorithm distinction**: `"Dilithium3"` (type_id=0) and `"ML-DSA-65"` /
|
|
8
|
+
* `"MlDsa65"` (type_id=1) are now separate algorithms on chain with distinct
|
|
9
|
+
* address derivation. `MlDsa65Adapter` and `DilithiumAdapter` both use the
|
|
10
|
+
* same underlying `ml_dsa65` crypto (FIPS 204), but produce different addresses.
|
|
13
11
|
*
|
|
14
12
|
* @module adapters
|
|
15
13
|
*/
|
package/dist/address.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export declare const PQ_ADDRESS_HRP = "pq";
|
|
|
4
4
|
export declare const PQ_ADDRESS_LENGTH = 20;
|
|
5
5
|
/** Version byte for V1 Shell addresses (`0x01`). */
|
|
6
6
|
export declare const PQ_ADDRESS_VERSION_V1 = 1;
|
|
7
|
-
type HexAddress = `0x${string}`;
|
|
8
7
|
/**
|
|
9
8
|
* Encode 20 raw address bytes as a `pq1…` bech32m address.
|
|
10
9
|
*
|
|
@@ -45,40 +44,15 @@ export declare function pqAddressToBytes(address: string): Uint8Array;
|
|
|
45
44
|
*/
|
|
46
45
|
export declare function pqAddressVersion(address: string): number;
|
|
47
46
|
/**
|
|
48
|
-
*
|
|
47
|
+
* Normalise an address: validates it is a `pq1…` bech32m address and returns it.
|
|
49
48
|
*
|
|
50
|
-
*
|
|
51
|
-
* @returns The 20-byte address payload.
|
|
52
|
-
* @throws {Error} If the string does not start with `"0x"` or is not exactly 20 bytes.
|
|
53
|
-
*/
|
|
54
|
-
export declare function hexAddressToBytes(address: string): Uint8Array;
|
|
55
|
-
/**
|
|
56
|
-
* Encode 20 raw address bytes as a `0x…` hex address.
|
|
57
|
-
*
|
|
58
|
-
* @param bytes - Exactly 20 address bytes.
|
|
59
|
-
* @returns A `0x`-prefixed 40-character hex string.
|
|
60
|
-
* @throws {Error} If `bytes.length !== 20`.
|
|
61
|
-
*/
|
|
62
|
-
export declare function bytesToHexAddress(bytes: Uint8Array): HexAddress;
|
|
63
|
-
/**
|
|
64
|
-
* Normalise an address to `pq1…` bech32m form.
|
|
49
|
+
* Hex (`0x…`) addresses are no longer accepted. Use `pq1…` format everywhere.
|
|
65
50
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* @param address - A `pq1…` or `0x…` address.
|
|
70
|
-
* @returns The `pq1…` bech32m address.
|
|
51
|
+
* @param address - A `pq1…` bech32m address.
|
|
52
|
+
* @returns The same `pq1…` address (validated).
|
|
53
|
+
* @throws {Error} If the address is not a valid `pq1…` bech32m address.
|
|
71
54
|
*/
|
|
72
55
|
export declare function normalizePqAddress(address: string): string;
|
|
73
|
-
/**
|
|
74
|
-
* Normalise an address to `0x…` hex form.
|
|
75
|
-
*
|
|
76
|
-
* Accepts either a `pq1…` or `0x…` address and always returns the hex form.
|
|
77
|
-
*
|
|
78
|
-
* @param address - A `pq1…` or `0x…` address.
|
|
79
|
-
* @returns The `0x`-prefixed hex address.
|
|
80
|
-
*/
|
|
81
|
-
export declare function normalizeHexAddress(address: string): HexAddress;
|
|
82
56
|
/**
|
|
83
57
|
* Derive a `pq1…` address from a raw post-quantum public key.
|
|
84
58
|
*
|
|
@@ -116,4 +90,3 @@ export declare function derivePqAddressFromPublicKey(publicKey: Uint8Array, algo
|
|
|
116
90
|
* ```
|
|
117
91
|
*/
|
|
118
92
|
export declare function isPqAddress(address: string): boolean;
|
|
119
|
-
export {};
|
package/dist/address.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PQ address utilities for Shell Chain.
|
|
3
3
|
*
|
|
4
|
-
* Shell Chain uses **bech32m**-encoded addresses (prefix `"pq"`)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Shell Chain uses **bech32m**-encoded addresses (prefix `"pq"`) exclusively.
|
|
5
|
+
* Each address encodes a version byte and 20 address bytes derived from the
|
|
6
|
+
* account's post-quantum public key:
|
|
7
7
|
*
|
|
8
8
|
* ```
|
|
9
9
|
* address_bytes = blake3(version || algo_id || public_key)[0..20]
|
|
@@ -12,14 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Algorithm IDs: Dilithium3=0, MlDsa65=1, SphincsSha2256f=2.
|
|
14
14
|
*
|
|
15
|
-
* Both pq1… and 0x… representations refer to the same underlying 20 bytes;
|
|
16
|
-
* the SDK accepts either form in most places via the `AddressLike` type.
|
|
17
|
-
*
|
|
18
15
|
* @module address
|
|
19
16
|
*/
|
|
20
17
|
import { blake3 } from "@noble/hashes/blake3";
|
|
21
18
|
import { bech32m } from "@scure/base";
|
|
22
|
-
import { bytesToHex, hexToBytes } from "viem";
|
|
23
19
|
/** Human-readable part (HRP) used in Shell bech32m addresses. */
|
|
24
20
|
export const PQ_ADDRESS_HRP = "pq";
|
|
25
21
|
/** Number of raw address bytes (excluding the version byte). */
|
|
@@ -31,11 +27,6 @@ function assertBech32Address(value) {
|
|
|
31
27
|
throw new Error("invalid bech32m address");
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
|
-
function assertHexAddress(value) {
|
|
35
|
-
if (!value.startsWith("0x")) {
|
|
36
|
-
throw new Error("invalid hex address");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
30
|
/**
|
|
40
31
|
* Encode 20 raw address bytes as a `pq1…` bech32m address.
|
|
41
32
|
*
|
|
@@ -106,61 +97,18 @@ export function pqAddressVersion(address) {
|
|
|
106
97
|
return bytes[0];
|
|
107
98
|
}
|
|
108
99
|
/**
|
|
109
|
-
*
|
|
100
|
+
* Normalise an address: validates it is a `pq1…` bech32m address and returns it.
|
|
110
101
|
*
|
|
111
|
-
*
|
|
112
|
-
* @returns The 20-byte address payload.
|
|
113
|
-
* @throws {Error} If the string does not start with `"0x"` or is not exactly 20 bytes.
|
|
114
|
-
*/
|
|
115
|
-
export function hexAddressToBytes(address) {
|
|
116
|
-
assertHexAddress(address);
|
|
117
|
-
const bytes = hexToBytes(address);
|
|
118
|
-
if (bytes.length !== PQ_ADDRESS_LENGTH) {
|
|
119
|
-
throw new Error(`expected ${PQ_ADDRESS_LENGTH} address bytes, got ${bytes.length}`);
|
|
120
|
-
}
|
|
121
|
-
return bytes;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Encode 20 raw address bytes as a `0x…` hex address.
|
|
102
|
+
* Hex (`0x…`) addresses are no longer accepted. Use `pq1…` format everywhere.
|
|
125
103
|
*
|
|
126
|
-
* @param
|
|
127
|
-
* @returns
|
|
128
|
-
* @throws {Error} If `
|
|
129
|
-
*/
|
|
130
|
-
export function bytesToHexAddress(bytes) {
|
|
131
|
-
if (bytes.length !== PQ_ADDRESS_LENGTH) {
|
|
132
|
-
throw new Error(`expected ${PQ_ADDRESS_LENGTH} address bytes, got ${bytes.length}`);
|
|
133
|
-
}
|
|
134
|
-
return bytesToHex(bytes);
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Normalise an address to `pq1…` bech32m form.
|
|
138
|
-
*
|
|
139
|
-
* Accepts either a `pq1…` or `0x…` address and always returns the canonical
|
|
140
|
-
* bech32m form.
|
|
141
|
-
*
|
|
142
|
-
* @param address - A `pq1…` or `0x…` address.
|
|
143
|
-
* @returns The `pq1…` bech32m address.
|
|
104
|
+
* @param address - A `pq1…` bech32m address.
|
|
105
|
+
* @returns The same `pq1…` address (validated).
|
|
106
|
+
* @throws {Error} If the address is not a valid `pq1…` bech32m address.
|
|
144
107
|
*/
|
|
145
108
|
export function normalizePqAddress(address) {
|
|
146
|
-
if (isPqAddress(address)) {
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
return bytesToPqAddress(hexAddressToBytes(address));
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Normalise an address to `0x…` hex form.
|
|
153
|
-
*
|
|
154
|
-
* Accepts either a `pq1…` or `0x…` address and always returns the hex form.
|
|
155
|
-
*
|
|
156
|
-
* @param address - A `pq1…` or `0x…` address.
|
|
157
|
-
* @returns The `0x`-prefixed hex address.
|
|
158
|
-
*/
|
|
159
|
-
export function normalizeHexAddress(address) {
|
|
160
|
-
if (isPqAddress(address)) {
|
|
161
|
-
return bytesToHexAddress(pqAddressToBytes(address));
|
|
109
|
+
if (!isPqAddress(address)) {
|
|
110
|
+
throw new Error(`expected a pq1… bech32m address, got: "${address.slice(0, 10)}…"`);
|
|
162
111
|
}
|
|
163
|
-
assertHexAddress(address);
|
|
164
112
|
return address;
|
|
165
113
|
}
|
|
166
114
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { PQ_ADDRESS_HRP, PQ_ADDRESS_LENGTH, PQ_ADDRESS_VERSION_V1, bytesToPqAddress, derivePqAddressFromPublicKey, isPqAddress, normalizePqAddress, pqAddressVersion, pqAddressToBytes, } from "./address.js";
|
|
2
2
|
export { createShellProvider, createShellPublicClient, createShellWsClient, ShellProvider, shellDevnet, type CreateShellPublicClientOptions, } from "./provider.js";
|
|
3
|
-
export { accountManagerAddress,
|
|
3
|
+
export { accountManagerAddress, cancelRecoverySelector, clearValidationCodeSelector, encodeCancelRecoveryCalldata, encodeClearValidationCodeCalldata, encodeExecuteRecoveryCalldata, encodeRotateKeyCalldata, encodeSetGuardiansCalldata, encodeSetValidationCodeCalldata, encodeSubmitRecoveryCalldata, executeRecoverySelector, isSystemContractAddress, rotateKeySelector, setGuardiansSelector, setValidationCodeSelector, submitRecoverySelector, validatorRegistryAddress, } from "./system-contracts.js";
|
|
4
4
|
export { AA_BUNDLE_TX_TYPE, AA_MAX_INNER_CALLS, buildBatchTransaction, buildClearValidationCodeTransaction, buildContractPaymasterTransaction, buildInnerCall, buildInnerTransfer, buildRotateKeyTransaction, buildSessionKeyTransaction, buildSetValidationCodeTransaction, buildSignature, buildSignedTransaction, buildSponsoredTransaction, buildSystemTransaction, buildTransaction, buildTransferTransaction, DEFAULT_AA_GAS_LIMIT, DEFAULT_MAX_FEE_PER_GAS, DEFAULT_MAX_PRIORITY_FEE_PER_GAS, DEFAULT_SYSTEM_GAS_LIMIT, DEFAULT_TRANSFER_GAS_LIMIT, DEFAULT_TX_TYPE, hashBatchTransaction, hashTransaction, type BuildBatchTransactionOptions, type BuildContractPaymasterTransactionOptions, type BuildSessionKeyTransactionOptions, type BuildSponsoredTransactionOptions, } from "./transactions.js";
|
|
5
5
|
export { assertSignerMatchesKeystore, decryptKeystore, exportEncryptedKeyJson, parseEncryptedKey, validateEncryptedKeyAddress, type ParsedShellKeystore, } from "./keystore.js";
|
|
6
6
|
export { adapterFromKeyPair, generateAdapter, generateMlDsa65KeyPair, generateSlhDsaKeyPair, MlDsa65Adapter, SlhDsaAdapter, type MlDsa65KeyPair, type SlhDsaKeyPair, } from "./adapters.js";
|
|
7
7
|
export { buildShellSignature, publicKeyFromHex, ShellSigner, signatureTypeFromKeyType, type SignerAdapter, } from "./signer.js";
|
|
8
8
|
export { AA_MAX_PAYMASTER_CONTEXT, AA_SESSION_KEY_GAS_SURCHARGE } from "./types.js";
|
|
9
|
-
export
|
|
9
|
+
export { formatShellRpcTxType } from "./types.js";
|
|
10
|
+
export type { AaBundle, AaInnerCall, AddressLike, GuardianConfig, HexString, RecoveryProposal, SessionAuth, ShellAccessListItem, ShellBatchInnerCallRequest, ShellBatchInnerGas, ShellCipherParams, ShellEncryptedKey, ShellEstimateBatchRequest, ShellEstimateBatchResult, ShellKnownRpcTxType, ShellIsSponsoredResult, ShellKdfParams, ShellNodeInfo, ShellPaymasterPolicy, ShellReadableTxType, ShellRewardKind, ShellRpcReceipt, ShellRpcTransaction, ShellRpcTransactionSummary, ShellRpcTxType, ShellSendTransactionParams, ShellSignature, ShellStorageProfile, ShellTransactionRequest, ShellTxByAddressPage, ShellTxWitness, ShellWitnessBundle, ShellWitnessRootResult, SignedShellTransaction, SignatureTypeName, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { PQ_ADDRESS_HRP, PQ_ADDRESS_LENGTH, PQ_ADDRESS_VERSION_V1, bytesToPqAddress, derivePqAddressFromPublicKey, isPqAddress, normalizePqAddress, pqAddressVersion, pqAddressToBytes, } from "./address.js";
|
|
2
2
|
export { createShellProvider, createShellPublicClient, createShellWsClient, ShellProvider, shellDevnet, } from "./provider.js";
|
|
3
|
-
export { accountManagerAddress,
|
|
3
|
+
export { accountManagerAddress, cancelRecoverySelector, clearValidationCodeSelector, encodeCancelRecoveryCalldata, encodeClearValidationCodeCalldata, encodeExecuteRecoveryCalldata, encodeRotateKeyCalldata, encodeSetGuardiansCalldata, encodeSetValidationCodeCalldata, encodeSubmitRecoveryCalldata, executeRecoverySelector, isSystemContractAddress, rotateKeySelector, setGuardiansSelector, setValidationCodeSelector, submitRecoverySelector, validatorRegistryAddress, } from "./system-contracts.js";
|
|
4
4
|
export { AA_BUNDLE_TX_TYPE, AA_MAX_INNER_CALLS, buildBatchTransaction, buildClearValidationCodeTransaction, buildContractPaymasterTransaction, buildInnerCall, buildInnerTransfer, buildRotateKeyTransaction, buildSessionKeyTransaction, buildSetValidationCodeTransaction, buildSignature, buildSignedTransaction, buildSponsoredTransaction, buildSystemTransaction, buildTransaction, buildTransferTransaction, DEFAULT_AA_GAS_LIMIT, DEFAULT_MAX_FEE_PER_GAS, DEFAULT_MAX_PRIORITY_FEE_PER_GAS, DEFAULT_SYSTEM_GAS_LIMIT, DEFAULT_TRANSFER_GAS_LIMIT, DEFAULT_TX_TYPE, hashBatchTransaction, hashTransaction, } from "./transactions.js";
|
|
5
5
|
export { assertSignerMatchesKeystore, decryptKeystore, exportEncryptedKeyJson, parseEncryptedKey, validateEncryptedKeyAddress, } from "./keystore.js";
|
|
6
6
|
export { adapterFromKeyPair, generateAdapter, generateMlDsa65KeyPair, generateSlhDsaKeyPair, MlDsa65Adapter, SlhDsaAdapter, } from "./adapters.js";
|
|
7
7
|
export { buildShellSignature, publicKeyFromHex, ShellSigner, signatureTypeFromKeyType, } from "./signer.js";
|
|
8
8
|
export { AA_MAX_PAYMASTER_CONTEXT, AA_SESSION_KEY_GAS_SURCHARGE } from "./types.js";
|
|
9
|
+
export { formatShellRpcTxType } from "./types.js";
|
package/dist/keystore.d.ts
CHANGED
|
@@ -16,8 +16,6 @@ export interface ParsedShellKeystore {
|
|
|
16
16
|
publicKey: Uint8Array;
|
|
17
17
|
/** Canonical `pq1…` address derived from `publicKey`. */
|
|
18
18
|
canonicalAddress: string;
|
|
19
|
-
/** `0x`-prefixed hex representation of the same address. */
|
|
20
|
-
hexAddress: string;
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
23
21
|
* Parse a Shell keystore file (string or object) and extract public metadata.
|
|
@@ -33,7 +31,7 @@ export interface ParsedShellKeystore {
|
|
|
33
31
|
* ```typescript
|
|
34
32
|
* const parsed = parseEncryptedKey(readFileSync("key.json", "utf8"));
|
|
35
33
|
* console.log(parsed.canonicalAddress); // pq1…
|
|
36
|
-
* console.log(parsed.signatureType); // "
|
|
34
|
+
* console.log(parsed.signatureType); // "ML-DSA-65"
|
|
37
35
|
* ```
|
|
38
36
|
*/
|
|
39
37
|
export declare function parseEncryptedKey(input: string | ShellEncryptedKey): ParsedShellKeystore;
|
|
@@ -77,17 +75,14 @@ export declare function assertSignerMatchesKeystore(signer: ShellSigner, keystor
|
|
|
77
75
|
*
|
|
78
76
|
* **KDF**: argon2id (parameters from `kdf_params`)
|
|
79
77
|
* **Cipher**: xchacha20-poly1305 (24-byte nonce from `cipher_params`)
|
|
80
|
-
* **Plaintext layout**:
|
|
81
|
-
*
|
|
82
|
-
* The decrypted public key is compared against `raw.public_key` to detect
|
|
83
|
-
* wrong passwords or corrupt files before returning the signer.
|
|
78
|
+
* **Plaintext layout (v1)**: secret key bytes only (sk-only format).
|
|
79
|
+
* The public key is read from the `public_key` JSON field directly.
|
|
84
80
|
*
|
|
85
81
|
* @param input - Keystore JSON string or object.
|
|
86
82
|
* @param password - The passphrase used to encrypt the key.
|
|
87
83
|
* @returns A fully configured `ShellSigner` ready for signing transactions.
|
|
88
84
|
* @throws {Error} If the KDF or cipher is unsupported.
|
|
89
85
|
* @throws {Error} If decryption fails (wrong password or corrupt ciphertext).
|
|
90
|
-
* @throws {Error} If the decrypted public key does not match the stored one.
|
|
91
86
|
*
|
|
92
87
|
* @example
|
|
93
88
|
* ```typescript
|
package/dist/keystore.js
CHANGED
|
@@ -6,19 +6,23 @@
|
|
|
6
6
|
* - **KDF**: argon2id (memory-hard password derivation)
|
|
7
7
|
* - **Cipher**: xchacha20-poly1305 (authenticated encryption)
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* compatible with the SDK's `decryptKeystore` function.
|
|
9
|
+
* ## Keystore format (v1 — canonical)
|
|
11
10
|
*
|
|
12
|
-
*
|
|
11
|
+
* The **ciphertext** contains **only the secret key bytes** (sk-only format).
|
|
12
|
+
* The public key is stored separately in the `public_key` field as plain hex.
|
|
13
|
+
* This matches the format produced by `shell-node key generate`.
|
|
14
|
+
*
|
|
15
|
+
* Previous SDK versions expected `sk || pk` in the ciphertext. That format
|
|
16
|
+
* is no longer produced or accepted; all new keystores use sk-only.
|
|
13
17
|
*
|
|
14
18
|
* @module keystore
|
|
15
19
|
*/
|
|
16
20
|
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
17
21
|
import { argon2id } from "hash-wasm";
|
|
18
|
-
import { derivePqAddressFromPublicKey,
|
|
22
|
+
import { derivePqAddressFromPublicKey, normalizePqAddress } from "./address.js";
|
|
19
23
|
import { adapterFromKeyPair } from "./adapters.js";
|
|
20
|
-
import { ShellSigner, publicKeyFromHex, signatureTypeFromKeyType } from "./signer.js";
|
|
21
|
-
const SIG_IDS = { "ML-DSA-65":
|
|
24
|
+
import { ShellSigner, canonicalSignatureType, publicKeyFromHex, signatureTypeFromKeyType, } from "./signer.js";
|
|
25
|
+
const SIG_IDS = { "ML-DSA-65": 1, Dilithium3: 0, MlDsa65: 1, SphincsSha2256f: 2 };
|
|
22
26
|
/**
|
|
23
27
|
* Parse a Shell keystore file (string or object) and extract public metadata.
|
|
24
28
|
*
|
|
@@ -33,7 +37,7 @@ const SIG_IDS = { "ML-DSA-65": 0, Dilithium3: 0, MlDsa65: 0, SphincsSha2256f: 2
|
|
|
33
37
|
* ```typescript
|
|
34
38
|
* const parsed = parseEncryptedKey(readFileSync("key.json", "utf8"));
|
|
35
39
|
* console.log(parsed.canonicalAddress); // pq1…
|
|
36
|
-
* console.log(parsed.signatureType); // "
|
|
40
|
+
* console.log(parsed.signatureType); // "ML-DSA-65"
|
|
37
41
|
* ```
|
|
38
42
|
*/
|
|
39
43
|
export function parseEncryptedKey(input) {
|
|
@@ -42,8 +46,7 @@ export function parseEncryptedKey(input) {
|
|
|
42
46
|
const algorithmId = SIG_IDS[signatureType];
|
|
43
47
|
const publicKey = publicKeyFromHex(raw.public_key);
|
|
44
48
|
const canonicalAddress = derivePqAddressFromPublicKey(publicKey, algorithmId);
|
|
45
|
-
|
|
46
|
-
return { raw, signatureType, algorithmId, publicKey, canonicalAddress, hexAddress };
|
|
49
|
+
return { raw, signatureType, algorithmId, publicKey, canonicalAddress };
|
|
47
50
|
}
|
|
48
51
|
/**
|
|
49
52
|
* Parse a keystore and verify that the declared address matches the public key.
|
|
@@ -89,7 +92,7 @@ export function exportEncryptedKeyJson(input) {
|
|
|
89
92
|
* ```
|
|
90
93
|
*/
|
|
91
94
|
export function assertSignerMatchesKeystore(signer, keystore) {
|
|
92
|
-
if (signer.signatureType !== keystore.signatureType) {
|
|
95
|
+
if (canonicalSignatureType(signer.signatureType) !== keystore.signatureType) {
|
|
93
96
|
throw new Error("algorithm mismatch: signer=" + signer.signatureType + " keystore=" + keystore.signatureType);
|
|
94
97
|
}
|
|
95
98
|
const addr = signer.getAddress();
|
|
@@ -110,17 +113,14 @@ function hexToBytes(hex) {
|
|
|
110
113
|
*
|
|
111
114
|
* **KDF**: argon2id (parameters from `kdf_params`)
|
|
112
115
|
* **Cipher**: xchacha20-poly1305 (24-byte nonce from `cipher_params`)
|
|
113
|
-
* **Plaintext layout**:
|
|
114
|
-
*
|
|
115
|
-
* The decrypted public key is compared against `raw.public_key` to detect
|
|
116
|
-
* wrong passwords or corrupt files before returning the signer.
|
|
116
|
+
* **Plaintext layout (v1)**: secret key bytes only (sk-only format).
|
|
117
|
+
* The public key is read from the `public_key` JSON field directly.
|
|
117
118
|
*
|
|
118
119
|
* @param input - Keystore JSON string or object.
|
|
119
120
|
* @param password - The passphrase used to encrypt the key.
|
|
120
121
|
* @returns A fully configured `ShellSigner` ready for signing transactions.
|
|
121
122
|
* @throws {Error} If the KDF or cipher is unsupported.
|
|
122
123
|
* @throws {Error} If decryption fails (wrong password or corrupt ciphertext).
|
|
123
|
-
* @throws {Error} If the decrypted public key does not match the stored one.
|
|
124
124
|
*
|
|
125
125
|
* @example
|
|
126
126
|
* ```typescript
|
|
@@ -150,17 +150,8 @@ export async function decryptKeystore(input, password) {
|
|
|
150
150
|
});
|
|
151
151
|
const derivedKey = hexToBytes(derivedKeyHex);
|
|
152
152
|
const chacha = xchacha20poly1305(derivedKey, nonce);
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
const skLen = plaintext.length - pubkeyLen;
|
|
156
|
-
if (skLen <= 0) {
|
|
157
|
-
throw new Error("payload too short: " + plaintext.length + " bytes");
|
|
158
|
-
}
|
|
159
|
-
const secretKey = plaintext.slice(0, skLen);
|
|
160
|
-
const derivedPubkey = plaintext.slice(skLen);
|
|
161
|
-
if (!derivedPubkey.every((b, i) => b === parsed.publicKey[i])) {
|
|
162
|
-
throw new Error("decrypted public key mismatch");
|
|
163
|
-
}
|
|
153
|
+
// Plaintext is sk-only; public key comes from the JSON `public_key` field.
|
|
154
|
+
const secretKey = chacha.decrypt(ciphertext);
|
|
164
155
|
const adapter = adapterFromKeyPair(parsed.signatureType, parsed.publicKey, secretKey);
|
|
165
156
|
return new ShellSigner(parsed.signatureType, adapter);
|
|
166
157
|
}
|
package/dist/provider.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* @module provider
|
|
17
17
|
*/
|
|
18
18
|
import { type Chain, type PublicClient } from "viem";
|
|
19
|
-
import type { ShellEstimateBatchRequest, ShellEstimateBatchResult, ShellIsSponsoredResult, ShellNodeInfo, ShellPaymasterPolicy, ShellStorageProfile, ShellWitnessBundle, ShellWitnessRootResult, SignedShellTransaction } from "./types.js";
|
|
19
|
+
import type { ShellEstimateBatchRequest, ShellEstimateBatchResult, ShellIsSponsoredResult, ShellNodeInfo, ShellPaymasterPolicy, ShellRpcReceipt, ShellStorageProfile, ShellTxByAddressPage, ShellWitnessBundle, ShellWitnessRootResult, SignedShellTransaction } from "./types.js";
|
|
20
20
|
/**
|
|
21
21
|
* Pre-configured viem chain definition for Shell Devnet.
|
|
22
22
|
*
|
|
@@ -90,6 +90,7 @@ export interface CreateShellPublicClientOptions {
|
|
|
90
90
|
}
|
|
91
91
|
/** A typed alias for a viem `PublicClient`. */
|
|
92
92
|
export type ShellPublicClient = PublicClient;
|
|
93
|
+
export type ShellBlockRangeBound = number | `0x${string}`;
|
|
93
94
|
/**
|
|
94
95
|
* RPC client for Shell Chain.
|
|
95
96
|
*
|
|
@@ -113,7 +114,7 @@ export declare class ShellProvider {
|
|
|
113
114
|
* Calls `shell_getPqPubkey`. Returns `null` if the address has not yet
|
|
114
115
|
* submitted a transaction (public key is only recorded on first send).
|
|
115
116
|
*
|
|
116
|
-
* @param address - A `pq1…`
|
|
117
|
+
* @param address - A `pq1…` bech32m address.
|
|
117
118
|
* @returns Hex-encoded public key string, or `null` if unknown.
|
|
118
119
|
*/
|
|
119
120
|
getPqPubkey(address: string): Promise<string | null>;
|
|
@@ -138,14 +139,16 @@ export declare class ShellProvider {
|
|
|
138
139
|
* @param options.toBlock - End of block range (inclusive).
|
|
139
140
|
* @param options.page - Zero-based page index.
|
|
140
141
|
* @param options.limit - Maximum number of results per page.
|
|
141
|
-
* @returns
|
|
142
|
+
* @returns Paginated response from the node. `fromBlock`/`toBlock` in the
|
|
143
|
+
* response is the effective inclusive range; clients that paginate under
|
|
144
|
+
* live load should pin `toBlock` from the first page.
|
|
142
145
|
*/
|
|
143
146
|
getTransactionsByAddress(address: string, options?: {
|
|
144
|
-
fromBlock?:
|
|
145
|
-
toBlock?:
|
|
147
|
+
fromBlock?: ShellBlockRangeBound;
|
|
148
|
+
toBlock?: ShellBlockRangeBound;
|
|
146
149
|
page?: number;
|
|
147
150
|
limit?: number;
|
|
148
|
-
}): Promise<
|
|
151
|
+
}): Promise<ShellTxByAddressPage>;
|
|
149
152
|
/**
|
|
150
153
|
* Fetch all transaction receipts for a block.
|
|
151
154
|
*
|
|
@@ -154,7 +157,7 @@ export declare class ShellProvider {
|
|
|
154
157
|
* @param block - Block identifier: `"latest"`, `"earliest"`, or a hex block number.
|
|
155
158
|
* @returns Array of transaction receipt objects.
|
|
156
159
|
*/
|
|
157
|
-
getBlockReceipts(block: string): Promise<
|
|
160
|
+
getBlockReceipts(block: string): Promise<ShellRpcReceipt[]>;
|
|
158
161
|
/**
|
|
159
162
|
* Fetch metadata about the connected Shell Chain node.
|
|
160
163
|
*
|
|
@@ -279,7 +282,7 @@ export declare function createShellWsClient(options?: CreateShellPublicClientOpt
|
|
|
279
282
|
* @example
|
|
280
283
|
* ```typescript
|
|
281
284
|
* const provider = createShellProvider();
|
|
282
|
-
* const balance = await provider.
|
|
285
|
+
* const balance = await provider.getBalance(signer.getAddress());
|
|
283
286
|
* const hash = await provider.sendTransaction(signedTx);
|
|
284
287
|
* ```
|
|
285
288
|
*/
|
package/dist/provider.js
CHANGED
|
@@ -86,7 +86,7 @@ export class ShellProvider {
|
|
|
86
86
|
* Calls `shell_getPqPubkey`. Returns `null` if the address has not yet
|
|
87
87
|
* submitted a transaction (public key is only recorded on first send).
|
|
88
88
|
*
|
|
89
|
-
* @param address - A `pq1…`
|
|
89
|
+
* @param address - A `pq1…` bech32m address.
|
|
90
90
|
* @returns Hex-encoded public key string, or `null` if unknown.
|
|
91
91
|
*/
|
|
92
92
|
async getPqPubkey(address) {
|
|
@@ -115,7 +115,9 @@ export class ShellProvider {
|
|
|
115
115
|
* @param options.toBlock - End of block range (inclusive).
|
|
116
116
|
* @param options.page - Zero-based page index.
|
|
117
117
|
* @param options.limit - Maximum number of results per page.
|
|
118
|
-
* @returns
|
|
118
|
+
* @returns Paginated response from the node. `fromBlock`/`toBlock` in the
|
|
119
|
+
* response is the effective inclusive range; clients that paginate under
|
|
120
|
+
* live load should pin `toBlock` from the first page.
|
|
119
121
|
*/
|
|
120
122
|
async getTransactionsByAddress(address, options = {}) {
|
|
121
123
|
return this.request("shell_getTransactionsByAddress", [
|
|
@@ -294,7 +296,7 @@ export function createShellWsClient(options = {}) {
|
|
|
294
296
|
* @example
|
|
295
297
|
* ```typescript
|
|
296
298
|
* const provider = createShellProvider();
|
|
297
|
-
* const balance = await provider.
|
|
299
|
+
* const balance = await provider.getBalance(signer.getAddress());
|
|
298
300
|
* const hash = await provider.sendTransaction(signedTx);
|
|
299
301
|
* ```
|
|
300
302
|
*/
|
package/dist/signer.d.ts
CHANGED
|
@@ -4,9 +4,8 @@ import type { SignedShellTransaction, SignatureTypeName } from "./types.js";
|
|
|
4
4
|
* Maps each {@link SignatureTypeName} to its numeric algorithm ID used in
|
|
5
5
|
* address derivation and on-chain records.
|
|
6
6
|
*
|
|
7
|
-
* - `"
|
|
8
|
-
* - `"
|
|
9
|
-
* - `"MlDsa65"` → `0` (camelCase alias, same algorithm)
|
|
7
|
+
* - `"Dilithium3"` → `0` (Round 3 Dilithium, legacy compat)
|
|
8
|
+
* - `"ML-DSA-65"` / `"MlDsa65"` → `1` (FIPS 204 ML-DSA-65, canonical)
|
|
10
9
|
* - `"SphincsSha2256f"` → `2`
|
|
11
10
|
*/
|
|
12
11
|
export declare const SIGNATURE_TYPE_IDS: Record<SignatureTypeName, number>;
|
|
@@ -15,9 +14,9 @@ export declare const SIGNATURE_TYPE_IDS: Record<SignatureTypeName, number>;
|
|
|
15
14
|
* corresponding {@link SignatureTypeName}.
|
|
16
15
|
*
|
|
17
16
|
* Keys are lowercase; matching is done after calling `.toLowerCase()`.
|
|
18
|
-
* Always returns the FIPS 204 canonical name `"ML-DSA-65"` for ML-DSA-65 variants.
|
|
19
17
|
*/
|
|
20
18
|
export declare const KEY_TYPE_TO_SIGNATURE_TYPE: Record<string, SignatureTypeName>;
|
|
19
|
+
export declare function canonicalSignatureType(signatureType: SignatureTypeName): SignatureTypeName;
|
|
21
20
|
/**
|
|
22
21
|
* Minimal interface that any post-quantum signing implementation must satisfy
|
|
23
22
|
* to be used with {@link ShellSigner}.
|
|
@@ -55,8 +54,7 @@ export interface SignerAdapter {
|
|
|
55
54
|
* const adapter = MlDsa65Adapter.generate();
|
|
56
55
|
* const signer = new ShellSigner("MlDsa65", adapter);
|
|
57
56
|
*
|
|
58
|
-
* console.log(signer.getAddress());
|
|
59
|
-
* console.log(signer.getHexAddress()); // 0x…
|
|
57
|
+
* console.log(signer.getAddress()); // pq1…
|
|
60
58
|
* ```
|
|
61
59
|
*/
|
|
62
60
|
export declare class ShellSigner {
|
|
@@ -83,12 +81,6 @@ export declare class ShellSigner {
|
|
|
83
81
|
* The address is computed deterministically from the public key and algorithm ID.
|
|
84
82
|
*/
|
|
85
83
|
getAddress(): string;
|
|
86
|
-
/**
|
|
87
|
-
* Return the `0x…` hex representation of this signer's address.
|
|
88
|
-
*
|
|
89
|
-
* Equivalent to `normalizeHexAddress(signer.getAddress())`.
|
|
90
|
-
*/
|
|
91
|
-
getHexAddress(): `0x${string}`;
|
|
92
84
|
/**
|
|
93
85
|
* Sign a raw byte message with the underlying adapter.
|
|
94
86
|
*
|
|
@@ -132,7 +124,7 @@ export declare class ShellSigner {
|
|
|
132
124
|
*
|
|
133
125
|
* @example
|
|
134
126
|
* ```typescript
|
|
135
|
-
* signatureTypeFromKeyType("mldsa65"); // "
|
|
127
|
+
* signatureTypeFromKeyType("mldsa65"); // "ML-DSA-65"
|
|
136
128
|
* signatureTypeFromKeyType("sphincs-sha2-256f"); // "SphincsSha2256f"
|
|
137
129
|
* ```
|
|
138
130
|
*/
|
package/dist/signer.js
CHANGED
|
@@ -10,21 +10,20 @@
|
|
|
10
10
|
* @module signer
|
|
11
11
|
*/
|
|
12
12
|
import { hexToBytes } from "viem";
|
|
13
|
-
import { derivePqAddressFromPublicKey,
|
|
13
|
+
import { derivePqAddressFromPublicKey, normalizePqAddress } from "./address.js";
|
|
14
14
|
import { buildSignature, buildSignedTransaction, } from "./transactions.js";
|
|
15
15
|
/**
|
|
16
16
|
* Maps each {@link SignatureTypeName} to its numeric algorithm ID used in
|
|
17
17
|
* address derivation and on-chain records.
|
|
18
18
|
*
|
|
19
|
-
* - `"
|
|
20
|
-
* - `"
|
|
21
|
-
* - `"MlDsa65"` → `0` (camelCase alias, same algorithm)
|
|
19
|
+
* - `"Dilithium3"` → `0` (Round 3 Dilithium, legacy compat)
|
|
20
|
+
* - `"ML-DSA-65"` / `"MlDsa65"` → `1` (FIPS 204 ML-DSA-65, canonical)
|
|
22
21
|
* - `"SphincsSha2256f"` → `2`
|
|
23
22
|
*/
|
|
24
23
|
export const SIGNATURE_TYPE_IDS = {
|
|
25
|
-
"ML-DSA-65":
|
|
24
|
+
"ML-DSA-65": 1,
|
|
26
25
|
Dilithium3: 0,
|
|
27
|
-
MlDsa65:
|
|
26
|
+
MlDsa65: 1,
|
|
28
27
|
SphincsSha2256f: 2,
|
|
29
28
|
};
|
|
30
29
|
/**
|
|
@@ -32,14 +31,16 @@ export const SIGNATURE_TYPE_IDS = {
|
|
|
32
31
|
* corresponding {@link SignatureTypeName}.
|
|
33
32
|
*
|
|
34
33
|
* Keys are lowercase; matching is done after calling `.toLowerCase()`.
|
|
35
|
-
* Always returns the FIPS 204 canonical name `"ML-DSA-65"` for ML-DSA-65 variants.
|
|
36
34
|
*/
|
|
37
35
|
export const KEY_TYPE_TO_SIGNATURE_TYPE = {
|
|
38
36
|
"ml-dsa-65": "ML-DSA-65",
|
|
39
37
|
mldsa65: "ML-DSA-65",
|
|
40
|
-
dilithium3: "
|
|
38
|
+
dilithium3: "Dilithium3",
|
|
41
39
|
"sphincs-sha2-256f": "SphincsSha2256f",
|
|
42
40
|
};
|
|
41
|
+
export function canonicalSignatureType(signatureType) {
|
|
42
|
+
return signatureType === "MlDsa65" ? "ML-DSA-65" : signatureType;
|
|
43
|
+
}
|
|
43
44
|
/**
|
|
44
45
|
* High-level Shell Chain signer.
|
|
45
46
|
*
|
|
@@ -54,8 +55,7 @@ export const KEY_TYPE_TO_SIGNATURE_TYPE = {
|
|
|
54
55
|
* const adapter = MlDsa65Adapter.generate();
|
|
55
56
|
* const signer = new ShellSigner("MlDsa65", adapter);
|
|
56
57
|
*
|
|
57
|
-
* console.log(signer.getAddress());
|
|
58
|
-
* console.log(signer.getHexAddress()); // 0x…
|
|
58
|
+
* console.log(signer.getAddress()); // pq1…
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
61
|
export class ShellSigner {
|
|
@@ -68,7 +68,7 @@ export class ShellSigner {
|
|
|
68
68
|
* @param adapter - An adapter providing `sign` and `getPublicKey`.
|
|
69
69
|
*/
|
|
70
70
|
constructor(signatureType, adapter) {
|
|
71
|
-
this.signatureType = signatureType;
|
|
71
|
+
this.signatureType = canonicalSignatureType(signatureType);
|
|
72
72
|
this.adapter = adapter;
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
@@ -91,14 +91,6 @@ export class ShellSigner {
|
|
|
91
91
|
getAddress() {
|
|
92
92
|
return derivePqAddressFromPublicKey(this.getPublicKey(), this.algorithmId);
|
|
93
93
|
}
|
|
94
|
-
/**
|
|
95
|
-
* Return the `0x…` hex representation of this signer's address.
|
|
96
|
-
*
|
|
97
|
-
* Equivalent to `normalizeHexAddress(signer.getAddress())`.
|
|
98
|
-
*/
|
|
99
|
-
getHexAddress() {
|
|
100
|
-
return normalizeHexAddress(this.getAddress());
|
|
101
|
-
}
|
|
102
94
|
/**
|
|
103
95
|
* Sign a raw byte message with the underlying adapter.
|
|
104
96
|
*
|
|
@@ -150,7 +142,7 @@ export class ShellSigner {
|
|
|
150
142
|
*
|
|
151
143
|
* @example
|
|
152
144
|
* ```typescript
|
|
153
|
-
* signatureTypeFromKeyType("mldsa65"); // "
|
|
145
|
+
* signatureTypeFromKeyType("mldsa65"); // "ML-DSA-65"
|
|
154
146
|
* signatureTypeFromKeyType("sphincs-sha2-256f"); // "SphincsSha2256f"
|
|
155
147
|
* ```
|
|
156
148
|
*/
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import type { AddressLike, HexString } from "./types.js";
|
|
2
|
-
/** Hex address of the ValidatorRegistry system contract (`0x…0001`). */
|
|
3
|
-
export declare const validatorRegistryHexAddress = "0x0000000000000000000000000000000000000001";
|
|
4
|
-
/** Hex address of the AccountManager system contract (`0x…0002`). */
|
|
5
|
-
export declare const accountManagerHexAddress = "0x0000000000000000000000000000000000000002";
|
|
6
2
|
/** `pq1…` bech32m address of the ValidatorRegistry system contract. */
|
|
7
3
|
export declare const validatorRegistryAddress: string;
|
|
8
4
|
/** `pq1…` bech32m address of the AccountManager system contract. */
|
|
@@ -57,17 +53,13 @@ export declare function encodeClearValidationCodeCalldata(): HexString;
|
|
|
57
53
|
/**
|
|
58
54
|
* Return `true` if `address` refers to one of the Shell system contracts.
|
|
59
55
|
*
|
|
60
|
-
*
|
|
61
|
-
* ValidatorRegistry addresses.
|
|
62
|
-
*
|
|
63
|
-
* @param address - Address to test (any format accepted by `AddressLike`).
|
|
56
|
+
* @param address - `pq1…` address to test.
|
|
64
57
|
* @returns `true` if the address matches AccountManager or ValidatorRegistry.
|
|
65
58
|
*
|
|
66
59
|
* @example
|
|
67
60
|
* ```typescript
|
|
68
|
-
* isSystemContractAddress(
|
|
69
|
-
* isSystemContractAddress(
|
|
70
|
-
* isSystemContractAddress("pq1someuser…"); // false
|
|
61
|
+
* isSystemContractAddress(accountManagerAddress); // true
|
|
62
|
+
* isSystemContractAddress("pq1someuser…"); // false
|
|
71
63
|
* ```
|
|
72
64
|
*/
|
|
73
65
|
export declare function isSystemContractAddress(address: AddressLike): boolean;
|
|
@@ -78,7 +70,7 @@ export declare function isSystemContractAddress(address: AddressLike): boolean;
|
|
|
78
70
|
* account owner can call this (the call must be made as an inner call from
|
|
79
71
|
* the owner's AA bundle, or as a direct transaction).
|
|
80
72
|
*
|
|
81
|
-
* @param guardians - Array of guardian addresses (1..5).
|
|
73
|
+
* @param guardians - Array of guardian addresses (1..5). Must be `pq1…` bech32m form.
|
|
82
74
|
* @param threshold - k-of-n required votes (1 ≤ threshold ≤ guardians.length).
|
|
83
75
|
* @param timelock - Minimum blocks between threshold-reach and execution (≥ 100).
|
|
84
76
|
* @returns `HexString` with the 4-byte selector prepended.
|
|
@@ -86,7 +78,7 @@ export declare function isSystemContractAddress(address: AddressLike): boolean;
|
|
|
86
78
|
* @example
|
|
87
79
|
* ```typescript
|
|
88
80
|
* const data = encodeSetGuardiansCalldata(
|
|
89
|
-
* ["
|
|
81
|
+
* ["pq1guardian1…", "pq1guardian2…", "pq1guardian3…"],
|
|
90
82
|
* 2, // 2-of-3 threshold
|
|
91
83
|
* 100, // 100-block timelock
|
|
92
84
|
* );
|
|
@@ -100,7 +92,7 @@ export declare function encodeSetGuardiansCalldata(guardians: AddressLike[], thr
|
|
|
100
92
|
* When k-of-n threshold is reached, the proposal becomes executable after
|
|
101
93
|
* `timelock` blocks.
|
|
102
94
|
*
|
|
103
|
-
* @param account - Account being recovered (
|
|
95
|
+
* @param account - Account being recovered (`pq1…` bech32m form).
|
|
104
96
|
* @param newPubkey - Raw bytes of the new PQ public key.
|
|
105
97
|
* @param newAlgo - Algorithm ID for the new key (ML-DSA-65 = 0, etc.).
|
|
106
98
|
* @returns `HexString` with the 4-byte selector prepended.
|
|
@@ -108,7 +100,7 @@ export declare function encodeSetGuardiansCalldata(guardians: AddressLike[], thr
|
|
|
108
100
|
* @example
|
|
109
101
|
* ```typescript
|
|
110
102
|
* const data = encodeSubmitRecoveryCalldata(
|
|
111
|
-
* "
|
|
103
|
+
* "pq1accountaddress…",
|
|
112
104
|
* newPubkeyBytes,
|
|
113
105
|
* 0, // ML-DSA-65
|
|
114
106
|
* );
|
package/dist/system-contracts.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* @module system-contracts
|
|
19
19
|
*/
|
|
20
20
|
import { bytesToHex, encodeAbiParameters, keccak256, toBytes } from "viem";
|
|
21
|
-
import { bytesToPqAddress } from "./address.js";
|
|
21
|
+
import { bytesToPqAddress, pqAddressToBytes } from "./address.js";
|
|
22
22
|
const SYSTEM_ADDRESS_LENGTH = 20;
|
|
23
23
|
function systemAddress(lastByte) {
|
|
24
24
|
const bytes = new Uint8Array(SYSTEM_ADDRESS_LENGTH);
|
|
@@ -28,10 +28,6 @@ function systemAddress(lastByte) {
|
|
|
28
28
|
function selector(signature) {
|
|
29
29
|
return keccak256(toBytes(signature)).slice(0, 10);
|
|
30
30
|
}
|
|
31
|
-
/** Hex address of the ValidatorRegistry system contract (`0x…0001`). */
|
|
32
|
-
export const validatorRegistryHexAddress = "0x0000000000000000000000000000000000000001";
|
|
33
|
-
/** Hex address of the AccountManager system contract (`0x…0002`). */
|
|
34
|
-
export const accountManagerHexAddress = "0x0000000000000000000000000000000000000002";
|
|
35
31
|
/** `pq1…` bech32m address of the ValidatorRegistry system contract. */
|
|
36
32
|
export const validatorRegistryAddress = bytesToPqAddress(systemAddress(1));
|
|
37
33
|
/** `pq1…` bech32m address of the AccountManager system contract. */
|
|
@@ -100,24 +96,17 @@ export function encodeClearValidationCodeCalldata() {
|
|
|
100
96
|
/**
|
|
101
97
|
* Return `true` if `address` refers to one of the Shell system contracts.
|
|
102
98
|
*
|
|
103
|
-
*
|
|
104
|
-
* ValidatorRegistry addresses.
|
|
105
|
-
*
|
|
106
|
-
* @param address - Address to test (any format accepted by `AddressLike`).
|
|
99
|
+
* @param address - `pq1…` address to test.
|
|
107
100
|
* @returns `true` if the address matches AccountManager or ValidatorRegistry.
|
|
108
101
|
*
|
|
109
102
|
* @example
|
|
110
103
|
* ```typescript
|
|
111
|
-
* isSystemContractAddress(
|
|
112
|
-
* isSystemContractAddress(
|
|
113
|
-
* isSystemContractAddress("pq1someuser…"); // false
|
|
104
|
+
* isSystemContractAddress(accountManagerAddress); // true
|
|
105
|
+
* isSystemContractAddress("pq1someuser…"); // false
|
|
114
106
|
* ```
|
|
115
107
|
*/
|
|
116
108
|
export function isSystemContractAddress(address) {
|
|
117
|
-
return
|
|
118
|
-
address === validatorRegistryAddress ||
|
|
119
|
-
address === accountManagerHexAddress ||
|
|
120
|
-
address === validatorRegistryHexAddress);
|
|
109
|
+
return address === accountManagerAddress || address === validatorRegistryAddress;
|
|
121
110
|
}
|
|
122
111
|
// ---------------------------------------------------------------------------
|
|
123
112
|
// AA Phase 2 — Guardian Recovery calldata encoders (v0.19.0-dev)
|
|
@@ -129,7 +118,7 @@ export function isSystemContractAddress(address) {
|
|
|
129
118
|
* account owner can call this (the call must be made as an inner call from
|
|
130
119
|
* the owner's AA bundle, or as a direct transaction).
|
|
131
120
|
*
|
|
132
|
-
* @param guardians - Array of guardian addresses (1..5).
|
|
121
|
+
* @param guardians - Array of guardian addresses (1..5). Must be `pq1…` bech32m form.
|
|
133
122
|
* @param threshold - k-of-n required votes (1 ≤ threshold ≤ guardians.length).
|
|
134
123
|
* @param timelock - Minimum blocks between threshold-reach and execution (≥ 100).
|
|
135
124
|
* @returns `HexString` with the 4-byte selector prepended.
|
|
@@ -137,18 +126,15 @@ export function isSystemContractAddress(address) {
|
|
|
137
126
|
* @example
|
|
138
127
|
* ```typescript
|
|
139
128
|
* const data = encodeSetGuardiansCalldata(
|
|
140
|
-
* ["
|
|
129
|
+
* ["pq1guardian1…", "pq1guardian2…", "pq1guardian3…"],
|
|
141
130
|
* 2, // 2-of-3 threshold
|
|
142
131
|
* 100, // 100-block timelock
|
|
143
132
|
* );
|
|
144
133
|
* ```
|
|
145
134
|
*/
|
|
146
135
|
export function encodeSetGuardiansCalldata(guardians, threshold, timelock) {
|
|
147
|
-
//
|
|
148
|
-
const hexGuardians = guardians.map((g) =>
|
|
149
|
-
const s = typeof g === "string" ? g : bytesToHex(g);
|
|
150
|
-
return (s.startsWith("0x") ? s : `0x${s}`);
|
|
151
|
-
});
|
|
136
|
+
// Decode pq1… addresses to raw 20 bytes, then to 0x-hex for ABI encoding.
|
|
137
|
+
const hexGuardians = guardians.map((g) => bytesToHex(pqAddressToBytes(g)));
|
|
152
138
|
const encoded = encodeAbiParameters([{ type: "address[]" }, { type: "uint8" }, { type: "uint64" }], [hexGuardians, threshold, BigInt(timelock)]);
|
|
153
139
|
return `${setGuardiansSelector}${encoded.slice(2)}`;
|
|
154
140
|
}
|
|
@@ -159,7 +145,7 @@ export function encodeSetGuardiansCalldata(guardians, threshold, timelock) {
|
|
|
159
145
|
* When k-of-n threshold is reached, the proposal becomes executable after
|
|
160
146
|
* `timelock` blocks.
|
|
161
147
|
*
|
|
162
|
-
* @param account - Account being recovered (
|
|
148
|
+
* @param account - Account being recovered (`pq1…` bech32m form).
|
|
163
149
|
* @param newPubkey - Raw bytes of the new PQ public key.
|
|
164
150
|
* @param newAlgo - Algorithm ID for the new key (ML-DSA-65 = 0, etc.).
|
|
165
151
|
* @returns `HexString` with the 4-byte selector prepended.
|
|
@@ -167,7 +153,7 @@ export function encodeSetGuardiansCalldata(guardians, threshold, timelock) {
|
|
|
167
153
|
* @example
|
|
168
154
|
* ```typescript
|
|
169
155
|
* const data = encodeSubmitRecoveryCalldata(
|
|
170
|
-
* "
|
|
156
|
+
* "pq1accountaddress…",
|
|
171
157
|
* newPubkeyBytes,
|
|
172
158
|
* 0, // ML-DSA-65
|
|
173
159
|
* );
|
|
@@ -209,9 +195,7 @@ export function encodeCancelRecoveryCalldata(account) {
|
|
|
209
195
|
// ---------------------------------------------------------------------------
|
|
210
196
|
// Internal helpers
|
|
211
197
|
// ---------------------------------------------------------------------------
|
|
198
|
+
/** Convert a pq1… address to a 0x-hex form for EVM ABI encoding. */
|
|
212
199
|
function normaliseToHex(address) {
|
|
213
|
-
|
|
214
|
-
return bytesToHex(address);
|
|
215
|
-
}
|
|
216
|
-
return (address.startsWith("0x") ? address : `0x${address}`);
|
|
200
|
+
return bytesToHex(pqAddressToBytes(address));
|
|
217
201
|
}
|
package/dist/transactions.js
CHANGED
|
@@ -11,7 +11,7 @@ import { bytesToHex, keccak256, toRlp, hexToBytes } from "viem";
|
|
|
11
11
|
import { AA_BUNDLE_TX_TYPE, AA_MAX_INNER_CALLS } from "./types.js";
|
|
12
12
|
export { AA_BUNDLE_TX_TYPE, AA_MAX_INNER_CALLS };
|
|
13
13
|
import { accountManagerAddress, encodeClearValidationCodeCalldata, encodeRotateKeyCalldata, encodeSetValidationCodeCalldata, } from "./system-contracts.js";
|
|
14
|
-
import {
|
|
14
|
+
import { pqAddressToBytes } from "./address.js";
|
|
15
15
|
/** Default transaction type: `2` (EIP-1559). */
|
|
16
16
|
export const DEFAULT_TX_TYPE = 2;
|
|
17
17
|
/** Default gas limit for simple SHELL token transfers (`21_000`). */
|
|
@@ -40,7 +40,7 @@ function toRlpAccessList(accessList) {
|
|
|
40
40
|
return [];
|
|
41
41
|
}
|
|
42
42
|
return accessList.map((item) => [
|
|
43
|
-
|
|
43
|
+
bytesToHex(pqAddressToBytes(item.address)),
|
|
44
44
|
item.storage_keys.map((key) => key),
|
|
45
45
|
]);
|
|
46
46
|
}
|
|
@@ -249,7 +249,7 @@ export function hashTransaction(tx) {
|
|
|
249
249
|
const fields = [
|
|
250
250
|
toRlpUint(tx.chain_id),
|
|
251
251
|
toRlpUint(tx.nonce),
|
|
252
|
-
tx.to ?
|
|
252
|
+
tx.to ? bytesToHex(pqAddressToBytes(tx.to)) : "0x",
|
|
253
253
|
toRlpUint(tx.value),
|
|
254
254
|
tx.data,
|
|
255
255
|
toRlpUint(tx.gas_limit),
|
|
@@ -368,14 +368,14 @@ export function hashBatchTransaction(tx, bundle) {
|
|
|
368
368
|
}
|
|
369
369
|
// Encode inner calls for signing (matches chain's encode_for_signing).
|
|
370
370
|
const innerCallsRlp = bundle.inner_calls.map((call) => [
|
|
371
|
-
call.to ?
|
|
371
|
+
call.to ? bytesToHex(pqAddressToBytes(call.to)) : "0x",
|
|
372
372
|
toRlpUint(call.value),
|
|
373
373
|
call.data,
|
|
374
374
|
toRlpUint(call.gas_limit),
|
|
375
375
|
]);
|
|
376
376
|
// Paymaster: 20-byte address or empty bytes.
|
|
377
377
|
const paymasterField = bundle.paymaster
|
|
378
|
-
?
|
|
378
|
+
? bytesToHex(pqAddressToBytes(bundle.paymaster))
|
|
379
379
|
: "0x";
|
|
380
380
|
// paymaster_context: raw bytes or empty.
|
|
381
381
|
const paymasterContextField = bundle.paymaster_context && bundle.paymaster_context.length > 0
|
|
@@ -384,7 +384,7 @@ export function hashBatchTransaction(tx, bundle) {
|
|
|
384
384
|
const txFields = [
|
|
385
385
|
toRlpUint(tx.chain_id),
|
|
386
386
|
toRlpUint(tx.nonce),
|
|
387
|
-
tx.to ?
|
|
387
|
+
tx.to ? bytesToHex(pqAddressToBytes(tx.to)) : "0x",
|
|
388
388
|
toRlpUint(tx.value),
|
|
389
389
|
tx.data,
|
|
390
390
|
toRlpUint(tx.gas_limit),
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** A `0x`-prefixed hex string, e.g. `"0xdeadbeef"`. */
|
|
2
2
|
export type HexString = `0x${string}`;
|
|
3
|
-
/**
|
|
3
|
+
/** A `pq1…` bech32m address string (Shell Chain canonical address format). */
|
|
4
4
|
export type AddressLike = string;
|
|
5
5
|
/** A single entry in an EIP-2930 access list. */
|
|
6
6
|
export interface ShellAccessListItem {
|
|
@@ -18,7 +18,7 @@ export interface ShellTransactionRequest {
|
|
|
18
18
|
chain_id: number;
|
|
19
19
|
/** Sender account nonce. */
|
|
20
20
|
nonce: number;
|
|
21
|
-
/** Recipient address (pq1
|
|
21
|
+
/** Recipient address (`pq1…` bech32m format), or `null` for contract deployment. */
|
|
22
22
|
to: AddressLike | null;
|
|
23
23
|
/** Transfer value as a hex-encoded bigint string, e.g. `"0xde0b6b3a7640000"`. */
|
|
24
24
|
value: string;
|
|
@@ -237,6 +237,83 @@ export interface SignedShellTransaction {
|
|
|
237
237
|
*/
|
|
238
238
|
aa_bundle?: AaBundle | null;
|
|
239
239
|
}
|
|
240
|
+
/** Product-level transaction kind emitted by Shell Chain RPC. */
|
|
241
|
+
export type ShellKnownRpcTxType = "transfer" | "contractCreate" | "contractCall" | "aaBatch" | "blockGasReward" | "starkReward";
|
|
242
|
+
export type ShellRpcTxType = ShellKnownRpcTxType | (string & {});
|
|
243
|
+
/** Reward kind emitted for first-class system reward transactions. */
|
|
244
|
+
export type ShellRewardKind = "blockGasReward" | "starkReward";
|
|
245
|
+
/** Human-readable transaction label for wallets, explorers, and apps. */
|
|
246
|
+
export type ShellReadableTxType = "Transfer" | "Contract Create" | "Contract Call" | "AA Batch" | "Block Reward" | "STARK Reward" | "System" | "Transaction";
|
|
247
|
+
/** Shell Chain `eth_getTransactionByHash` transaction shape. */
|
|
248
|
+
export interface ShellRpcTransaction {
|
|
249
|
+
hash: HexString;
|
|
250
|
+
blockHash?: HexString | null;
|
|
251
|
+
blockNumber?: HexString | null;
|
|
252
|
+
transactionIndex?: HexString | null;
|
|
253
|
+
from: AddressLike;
|
|
254
|
+
to?: AddressLike | null;
|
|
255
|
+
value: HexString;
|
|
256
|
+
gas: HexString;
|
|
257
|
+
gasPrice: HexString;
|
|
258
|
+
maxFeePerGas?: HexString;
|
|
259
|
+
maxPriorityFeePerGas?: HexString;
|
|
260
|
+
nonce: HexString;
|
|
261
|
+
input: HexString;
|
|
262
|
+
chainId: HexString;
|
|
263
|
+
type: HexString;
|
|
264
|
+
shellType?: ShellRpcTxType | null;
|
|
265
|
+
rewardKind?: ShellRewardKind | null;
|
|
266
|
+
rewardLayer?: HexString | null;
|
|
267
|
+
rewardSourceHash?: HexString | null;
|
|
268
|
+
originalSize?: HexString | null;
|
|
269
|
+
compressedSize?: HexString | null;
|
|
270
|
+
}
|
|
271
|
+
/** Shell Chain transaction summary returned in block/address transaction lists. */
|
|
272
|
+
export interface ShellRpcTransactionSummary {
|
|
273
|
+
hash: HexString;
|
|
274
|
+
blockHash?: HexString | null;
|
|
275
|
+
blockNumber?: HexString | null;
|
|
276
|
+
transactionIndex?: HexString | null;
|
|
277
|
+
from?: AddressLike;
|
|
278
|
+
to?: AddressLike | null;
|
|
279
|
+
value?: HexString;
|
|
280
|
+
type?: HexString;
|
|
281
|
+
hasInput?: boolean;
|
|
282
|
+
shellType?: ShellRpcTxType | null;
|
|
283
|
+
rewardKind?: ShellRewardKind | null;
|
|
284
|
+
rewardLayer?: HexString | null;
|
|
285
|
+
rewardSourceHash?: HexString | null;
|
|
286
|
+
originalSize?: HexString | null;
|
|
287
|
+
compressedSize?: HexString | null;
|
|
288
|
+
}
|
|
289
|
+
/** Shell Chain transaction receipt shape, including system reward metadata. */
|
|
290
|
+
export interface ShellRpcReceipt {
|
|
291
|
+
transactionHash: HexString;
|
|
292
|
+
blockHash: HexString;
|
|
293
|
+
blockNumber: HexString;
|
|
294
|
+
transactionIndex: HexString;
|
|
295
|
+
from: AddressLike;
|
|
296
|
+
to?: AddressLike | null;
|
|
297
|
+
status: HexString;
|
|
298
|
+
gasUsed: HexString;
|
|
299
|
+
cumulativeGasUsed: HexString;
|
|
300
|
+
effectiveGasPrice: HexString;
|
|
301
|
+
contractAddress?: AddressLike | null;
|
|
302
|
+
logs: unknown[];
|
|
303
|
+
logsBloom: HexString;
|
|
304
|
+
type: HexString;
|
|
305
|
+
shellType?: ShellRpcTxType | null;
|
|
306
|
+
rewardKind?: ShellRewardKind | null;
|
|
307
|
+
}
|
|
308
|
+
/** Return a user-facing transaction type label without leaking EIP wire labels. */
|
|
309
|
+
export declare function formatShellRpcTxType(tx: {
|
|
310
|
+
type?: string | null;
|
|
311
|
+
to?: AddressLike | null;
|
|
312
|
+
hasInput?: boolean;
|
|
313
|
+
input?: string | null;
|
|
314
|
+
shellType?: ShellRpcTxType | null;
|
|
315
|
+
rewardKind?: ShellRewardKind | null;
|
|
316
|
+
}): ShellReadableTxType;
|
|
240
317
|
/**
|
|
241
318
|
* A single inner call entry in a `shell_estimateBatch` request.
|
|
242
319
|
*/
|
|
@@ -399,10 +476,18 @@ export interface ShellWitnessBundle {
|
|
|
399
476
|
/** Paginated response from `shell_getTransactionsByAddress`. */
|
|
400
477
|
export interface ShellTxByAddressPage {
|
|
401
478
|
address: AddressLike;
|
|
479
|
+
/** Inclusive lower block bound used for the query, hex-encoded. */
|
|
480
|
+
from_block?: HexString;
|
|
481
|
+
/** Inclusive upper block snapshot used for the query, hex-encoded. */
|
|
482
|
+
to_block?: HexString;
|
|
483
|
+
/** Inclusive lower block bound used for the query, hex-encoded. */
|
|
484
|
+
fromBlock?: HexString;
|
|
485
|
+
/** Inclusive upper block snapshot used for the query, hex-encoded. */
|
|
486
|
+
toBlock?: HexString;
|
|
402
487
|
page: number;
|
|
403
488
|
limit: number;
|
|
404
489
|
total: number;
|
|
405
|
-
transactions:
|
|
490
|
+
transactions: ShellRpcTransactionSummary[];
|
|
406
491
|
}
|
|
407
492
|
/** Parameters for `shell_sendTransaction`. */
|
|
408
493
|
export interface ShellSendTransactionParams {
|
package/dist/types.js
CHANGED
|
@@ -23,3 +23,36 @@ export const AA_MAX_PAYMASTER_CONTEXT = 256;
|
|
|
23
23
|
* Added to intrinsic gas when a session key is used.
|
|
24
24
|
*/
|
|
25
25
|
export const AA_SESSION_KEY_GAS_SURCHARGE = 20_000;
|
|
26
|
+
/** Return a user-facing transaction type label without leaking EIP wire labels. */
|
|
27
|
+
export function formatShellRpcTxType(tx) {
|
|
28
|
+
const shellType = tx.shellType ?? tx.rewardKind;
|
|
29
|
+
if (shellType === "blockGasReward")
|
|
30
|
+
return "Block Reward";
|
|
31
|
+
if (shellType === "starkReward")
|
|
32
|
+
return "STARK Reward";
|
|
33
|
+
if (shellType === "aaBatch")
|
|
34
|
+
return "AA Batch";
|
|
35
|
+
if (shellType === "contractCreate")
|
|
36
|
+
return "Contract Create";
|
|
37
|
+
if (shellType === "contractCall")
|
|
38
|
+
return "Contract Call";
|
|
39
|
+
if (shellType === "transfer")
|
|
40
|
+
return "Transfer";
|
|
41
|
+
if (shellType)
|
|
42
|
+
return "System";
|
|
43
|
+
if (tx.type === "0x7e")
|
|
44
|
+
return "AA Batch";
|
|
45
|
+
if (tx.to === null)
|
|
46
|
+
return "Contract Create";
|
|
47
|
+
if (tx.hasInput || (tx.input && tx.input !== "0x"))
|
|
48
|
+
return "Contract Call";
|
|
49
|
+
if (tx.type === "0x80")
|
|
50
|
+
return "System";
|
|
51
|
+
if (tx.type == null &&
|
|
52
|
+
tx.to === undefined &&
|
|
53
|
+
tx.hasInput === undefined &&
|
|
54
|
+
tx.input === undefined) {
|
|
55
|
+
return "Transaction";
|
|
56
|
+
}
|
|
57
|
+
return "Transfer";
|
|
58
|
+
}
|