wative-core 2.4.1 → 2.4.2

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +47 -32
  3. package/dist/artifacts/evm/index.cjs +1 -1
  4. package/dist/artifacts/evm/index.d.cts +2 -2
  5. package/dist/artifacts/evm/index.d.ts +2 -2
  6. package/dist/artifacts/evm/index.js +1 -1
  7. package/dist/artifacts/svm/index.cjs +1 -1
  8. package/dist/artifacts/svm/index.d.cts +3 -3
  9. package/dist/artifacts/svm/index.d.ts +3 -3
  10. package/dist/artifacts/svm/index.js +1 -1
  11. package/dist/{container-provider--npoeR2N.d.ts → container-provider-B8M0ylrK.d.ts} +1 -1
  12. package/dist/{container-provider-Ca_5z1uQ.d.cts → container-provider-YxyMpkhG.d.cts} +1 -1
  13. package/dist/{evm-EHpaW_sK.d.ts → evm-Bo3Dy492.d.ts} +1 -1
  14. package/dist/{evm-hSJJOVG3.d.cts → evm-DA6Sh6jv.d.cts} +1 -1
  15. package/dist/{file-sink-Bk5zYHw-.d.ts → file-sink-Be5iLbuT.d.ts} +2 -2
  16. package/dist/{file-sink-7ZAutH45.d.cts → file-sink-KCCpKHRj.d.cts} +2 -2
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.d.cts +6 -6
  19. package/dist/index.d.ts +6 -6
  20. package/dist/index.js +1 -1
  21. package/dist/index.node.cjs +1 -1
  22. package/dist/index.node.d.cts +5 -5
  23. package/dist/index.node.d.ts +5 -5
  24. package/dist/index.node.js +1 -1
  25. package/dist/node/index.cjs +1 -1
  26. package/dist/node/index.d.cts +3 -3
  27. package/dist/node/index.d.ts +3 -3
  28. package/dist/node/index.js +1 -1
  29. package/dist/{svm-B5q8YaV9.d.ts → svm-B51NevS8.d.ts} +1 -1
  30. package/dist/{svm-CXFwmeMo.d.cts → svm-DswX6XRv.d.cts} +1 -1
  31. package/dist/{workspace-kq3QyAgm.d.cts → workspace-CBxKR80D.d.cts} +2 -1
  32. package/dist/{workspace-kq3QyAgm.d.ts → workspace-CBxKR80D.d.ts} +2 -1
  33. package/examples/03-pk-account.test.cjs +65 -0
  34. package/examples/README.md +1 -1
  35. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,45 @@
2
2
 
3
3
  All notable changes to `wative-core` are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## [2.4.2] — 2026-08-11
6
+
7
+ Importing a private key gets easier and does more: you no longer have to say
8
+ which chain a key is for, more of the formats you actually hold are accepted,
9
+ and one import now gives you an address on both chains.
10
+
11
+ ### Changed
12
+ - **BREAKING. A PK wallet now holds two addresses instead of one.** Importing a
13
+ key gives you an address on the chain that key is for, plus one on the other
14
+ chain seeded by the same 32 secret bytes. The chain you imported for stays at
15
+ `addresses[0]`, so code reading that position is unaffected — but
16
+ `addresses.length` is now 2, and totals derived from it will differ.
17
+
18
+ ⚠️ **One secret controls both addresses.** There is only one key to import,
19
+ so both addresses come from it, and whoever learns that key holds both
20
+ chains. This is not how an HD account behaves: there a slot's two addresses
21
+ come from two derivation paths and are independent keys. Use an HD account,
22
+ or import a separate key per chain, if you need that separation.
23
+
24
+ Wallets already stored keep the single address they were written with. Only
25
+ new imports are paired.
26
+
27
+ ### Added
28
+ - **`importPrivateKey(pk)` no longer needs a `vm`.** The accepted formats do not
29
+ overlap — 64 hex characters for EVM, 80–96 base58 for Solana — so the chain is
30
+ read off the key. Passing `vm` explicitly still works and still wins.
31
+ - **`solana-keygen` JSON byte arrays are accepted.** The contents of
32
+ `~/.config/solana/id.json` can be handed to `importPrivateKey` as-is, instead
33
+ of being converted to base58 by hand first.
34
+
35
+ ### Fixed
36
+ - **An out-of-range EVM private key is now `INVALID_PRIVATE_KEY`.** 32 bytes of
37
+ hex is not necessarily a key: zero, and anything at or above the secp256k1
38
+ group order, previously reached the curve library and surfaced as a bare
39
+ `Error` with no `code`, thrown from inside a queued mutation. It is refused at
40
+ the boundary now, like every other malformed key.
41
+ - Corrected the README's account diagrams, which described a PK wallet as
42
+ carrying exactly one address as though it were a structural rule.
43
+
5
44
  ## [2.4.1] — 2026-08-11
6
45
 
7
46
  One breaking item, and it is the kind worth reading before upgrading: a
package/README.md CHANGED
@@ -44,28 +44,64 @@ Account "Trading Desk" (HD) one mnemonic
44
44
  └── … account.deriveWallets(n)
45
45
  ```
46
46
 
47
- **PK** — imported keys. A `Wallet` is one key you handed in, on the one chain
48
- you imported it for. Wallets have no relationship to each other:
47
+ **PK** — imported keys. Each import allocates its own `Wallet`, and that wallet
48
+ gets an address on **both** chains: the key signs on its own curve, and the same
49
+ 32 secret bytes seed a keypair on the other one. The chain you imported for
50
+ comes first.
49
51
 
50
52
  ```
51
53
  Account "Cold Storage" (PK) no mnemonic
52
54
  ├── Wallet 0 the key passed to accounts.create()
53
- │ └── Address vm: "evm" 0x90F8bf6A…
54
- ├── Wallet 1 account.importPrivateKey(pk, "evm")
55
- │ └── Address vm: "evm" 0xFFcf8FDE…
56
- └── Wallet 2 account.importPrivateKey(pk, "svm")
57
- └── Address vm: "svm" 7WktogJEd… one chain per wallet
55
+ │ ├── Address vm: "evm" 0x90F8bf6A… the imported key
56
+ │ └── Address vm: "svm" HaWmh8svNQ… same secret, other curve
57
+ ├── Wallet 1 account.importPrivateKey(evmKey)
58
+ │ ├── Address vm: "evm" 0xFFcf8FDE…
59
+ │ └── Address vm: "svm" Fgdy5QRxtP…
60
+ └── Wallet 2 account.importPrivateKey(svmKey)
61
+ ├── Address vm: "svm" 3QVq8D876h… the imported key
62
+ └── Address vm: "evm" 0x1a740984… same secret, other curve
63
+ ```
64
+
65
+ A PK account can hold as many keys as you like, on any mix of chains — but it
66
+ refuses the same identity twice, on either chain.
67
+
68
+ > ⚠️ **One secret controls both addresses in a PK wallet.** There is only one
69
+ > key to import, so both addresses come from it. Whoever learns that key holds
70
+ > both chains.
71
+ >
72
+ > This is not how an HD account works. There, a slot's two addresses come from
73
+ > two different derivation paths — the mnemonic is shared, the private keys are
74
+ > independent. If you want independent keys per chain, use an HD account, or
75
+ > import a separate key for each and read `addresses[0]` of each wallet.
76
+
77
+ > **`wallet.addresses` is a list.** It holds one address per `(vm, network)`
78
+ > pair and is free to carry several. Read it rather than assuming a position:
79
+ >
80
+ > ```ts
81
+ > const evm = wallet.addresses.find((a) => a.vm === "evm");
82
+ > ```
83
+
84
+ **Which chain a key is for is read off the key** — `vm` is optional:
85
+
86
+ ```ts
87
+ await acc.importPrivateKey(evmKey); // 64 hex chars -> evm
88
+ await acc.importPrivateKey(solanaKey); // base58 -> svm
89
+ await acc.importPrivateKey(readFileSync("id.json")); // solana-keygen -> svm
90
+ await acc.importPrivateKey(key, "evm"); // or say so explicitly
58
91
  ```
59
92
 
60
- A PK account can hold as many keys as you like, and they can be on different
61
- chains — but it refuses the same identity twice.
93
+ The formats do not overlap, so this is a decision rather than a guess. A value
94
+ that is neither is refused with `INVALID_PRIVATE_KEY` — including 32 bytes of
95
+ hex that is not a valid secp256k1 scalar, and a bare 32-byte base58 value,
96
+ which is indistinguishable from a Solana *public* key.
62
97
 
63
98
  | | HD | PK |
64
99
  | ---------------------- | ----------------------------- | ------------------------------- |
65
100
  | Created from | a BIP-39 mnemonic | one private key |
66
101
  | Grows with | `deriveWallets(n)` | `importPrivateKey(pk, vm)` |
67
102
  | A `Wallet` is | a derivation slot | one imported key |
68
- | Addresses per `Wallet` | **2** — one evm, one svm | **1** — the chain you imported |
103
+ | Addresses per `Wallet` | **2** — one evm, one svm | **2** — imported chain first |
104
+ | Those two addresses | independent keys, two paths | **one key, both curves** |
69
105
  | `dumpMnemonic()` | ✔ | throws `UNSUPPORTED_OP` |
70
106
  | `sliceWallets(n)` | ✔ | throws `UNSUPPORTED_OP` |
71
107
  | `importPrivateKey()` | throws `UNSUPPORTED_OP` | ✔ |
@@ -150,7 +186,6 @@ await ws.lock();
150
186
  | Storage | encrypted files on disk | IndexedDB |
151
187
  | Where it lives | `Workspace.open({ path })`, or default | `IdbProvider.create(name)` |
152
188
  | Extra setup | none | `Buffer` polyfill |
153
- | Keys can vanish| no | yes — storage is evictable |
154
189
 
155
190
  `HybridProvider`, `HybridProviderV3` and `FileSink` are re-exported from the
156
191
  package root in Node.
@@ -233,17 +268,6 @@ produces the same keys.
233
268
  Nothing to install: it runs on a bundled WebAssembly build by default, with no
234
269
  native binary and no build step.
235
270
 
236
- ### Browser: grant `'wasm-unsafe-eval'`
237
-
238
- ```
239
- Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval'
240
- ```
241
-
242
- Optional. Without it nothing breaks and nothing throws — key derivation falls
243
- back to a slower implementation that produces identical results, so unlocking a
244
- wallet with a dozen addresses takes tens of seconds instead of about one. Grant
245
- it if that matters to you. `argon2BackendInfo()` reports which one ran.
246
-
247
271
  ### One derivation per container: `HybridProviderV3` (Node only)
248
272
 
249
273
  ```ts
@@ -262,15 +286,6 @@ It is the Node default where `@node-rs/argon2` is installed, and Node-only: that
262
286
  package has no browser build. Construct it yourself only to pick a location, or
263
287
  to be sure you get it rather than the fallback.
264
288
 
265
- Two things to plan for:
266
-
267
- - **An existing workspace does not get faster on its own.** Secrets written
268
- before the switch keep their own keys, so they keep costing one derivation
269
- each. `account.resetPassword(old, new)` rewrites them.
270
- - ⚠️ **Older versions of this library cannot open a V3 workspace**, and there is
271
- no way back. Once a workspace has been opened with V3, keep using a version
272
- that supports it.
273
-
274
289
  ### Checking which implementation ran
275
290
 
276
291
  ```ts
@@ -312,7 +327,7 @@ The library is organized around seven things you'll work with:
312
327
 
313
328
  - **`Workspace`** — your top-level container. Holds the password, your accounts, your network and asset list, and a built-in logger.
314
329
  - **`Account`** — either an HD account (one BIP-39 mnemonic, can derive many wallets) or a PK account (raw private keys you import one at a time). Each account can have its own password or share the workspace password.
315
- - **`Wallet`** — a unit inside an account. HD wallets carry one EVM and one Solana address; PK wallets carry one address.
330
+ - **`Wallet`** — a unit inside an account, holding one address per `(vm, network)`. Both kinds give you an EVM and a Solana address: an HD slot derives one per chain from the mnemonic, an import derives its sibling from the imported key. Treat `wallet.addresses` as the list it is.
316
331
  - **`Address`** — an on-chain identity. Sign messages, build transactions, send them.
317
332
  - **`Network`** — chain metadata. 10 networks ship pre-loaded.
318
333
  - **`Asset`** — token metadata. 25 tokens ship pre-loaded.