wative-core 2.2.0 → 2.3.9
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 +493 -9
- package/LICENSE +114 -0
- package/README.md +228 -8
- package/dist/artifacts/evm/index.cjs +1 -1
- package/dist/artifacts/evm/index.d.cts +2 -2
- package/dist/artifacts/evm/index.d.ts +2 -2
- package/dist/artifacts/evm/index.js +1 -1
- package/dist/artifacts/svm/index.cjs +1 -1
- package/dist/artifacts/svm/index.d.cts +3 -3
- package/dist/artifacts/svm/index.d.ts +3 -3
- package/dist/artifacts/svm/index.js +1 -1
- package/dist/{container-provider-i614LDE1.d.cts → container-provider-CkKGyHis.d.cts} +10 -3
- package/dist/{container-provider-C59yqd5Z.d.ts → container-provider-D_557LVN.d.ts} +10 -3
- package/dist/{evm-BLml33LX.d.cts → evm-Xw4zBLUH.d.ts} +2 -2
- package/dist/{evm-DTzqGlL6.d.ts → evm-gsdoVj16.d.cts} +2 -2
- package/dist/{file-sink-LS4hyXXi.d.ts → file-sink-C_SlT9IC.d.cts} +8 -5
- package/dist/{file-sink-B73MuigK.d.cts → file-sink-D33jvque.d.ts} +8 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +20 -7
- package/dist/index.d.ts +20 -7
- package/dist/index.js +1 -1
- package/dist/index.node.cjs +1 -1
- package/dist/index.node.d.cts +6 -6
- package/dist/index.node.d.ts +6 -6
- package/dist/index.node.js +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +3 -3
- package/dist/node/index.d.ts +3 -3
- package/dist/node/index.js +1 -1
- package/dist/{svm-DieFbh9k.d.ts → svm-CTCJsYri.d.cts} +2 -2
- package/dist/{svm-CCzqNAWM.d.cts → svm-CUuqpl1h.d.ts} +2 -2
- package/dist/{workspace-CamTHxso.d.cts → workspace-Du_jy51u.d.cts} +19 -4
- package/dist/{workspace-CamTHxso.d.ts → workspace-Du_jy51u.d.ts} +19 -4
- package/{tests → examples}/11-subpath-imports.test.cjs +5 -2
- package/examples/15-package-resolution.test.cjs +262 -0
- package/examples/18-envelope-v3.test.cjs +106 -0
- package/package.json +6 -3
- package/tests/15-package-resolution.test.cjs +0 -76
- /package/{tests → examples}/01-quick-start.test.cjs +0 -0
- /package/{tests → examples}/02-hd-account.test.cjs +0 -0
- /package/{tests → examples}/03-pk-account.test.cjs +0 -0
- /package/{tests → examples}/04-network-management.test.cjs +0 -0
- /package/{tests → examples}/05-asset-management.test.cjs +0 -0
- /package/{tests → examples}/06-address-signing.test.cjs +0 -0
- /package/{tests → examples}/07-custom-provider.test.cjs +0 -0
- /package/{tests → examples}/08-persistence.test.cjs +0 -0
- /package/{tests → examples}/09-workspace-filter.test.cjs +0 -0
- /package/{tests → examples}/10-default-network.test.cjs +0 -0
- /package/{tests → examples}/12-logger.test.cjs +0 -0
- /package/{tests → examples}/13-workspace-config.test.cjs +0 -0
- /package/{tests → examples}/14-esm-runtime.test.mjs +0 -0
- /package/{tests → examples}/16-known-answer-vectors.test.cjs +0 -0
- /package/{tests → examples}/17-locked-state.test.cjs +0 -0
- /package/{tests → examples}/README.md +0 -0
package/README.md
CHANGED
|
@@ -1,7 +1,88 @@
|
|
|
1
1
|
# Wative Core 2
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/wative-core)
|
|
4
|
+
[](https://github.com/braady/wative-core/actions/workflows/ci.yml)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
3
8
|
Hyperscale crypto wallet management library — multi-workspace, multi-chain, originally designed for on-chain market makers.
|
|
4
9
|
|
|
10
|
+
Runs in Node and in the browser. Wallets live in one encrypted container: on disk
|
|
11
|
+
under Node, in IndexedDB in a browser, or in any storage you plug in yourself.
|
|
12
|
+
|
|
13
|
+
## How it fits together
|
|
14
|
+
|
|
15
|
+
A workspace is the container. Everything else nests inside it:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Workspace one encrypted container, one password
|
|
19
|
+
│
|
|
20
|
+
├── Account an identity — HD (from a mnemonic) or PK (imported keys)
|
|
21
|
+
│ └── Wallet one slot in that account
|
|
22
|
+
│ └── Address one key on one chain — this is what signs
|
|
23
|
+
│
|
|
24
|
+
├── Network the chains you can reach (RPC, chain id)
|
|
25
|
+
└── Asset the tokens tracked on each network
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Two kinds of Account
|
|
29
|
+
|
|
30
|
+
The nesting is the same for both, but a `Wallet` means something different in
|
|
31
|
+
each — and that is the part most people get wrong first.
|
|
32
|
+
|
|
33
|
+
**HD** — one mnemonic, many slots. A `Wallet` is a derivation slot, and it holds
|
|
34
|
+
the EVM *and* Solana keys derived from that same slot:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Account "Trading Desk" (HD) one mnemonic
|
|
38
|
+
├── Wallet 0 m/44'/60'/0'/0/0
|
|
39
|
+
│ ├── Address vm: "evm" 0x9858EfFD…
|
|
40
|
+
│ └── Address vm: "svm" HAgk14JpMQ… same slot, both chains
|
|
41
|
+
├── Wallet 1 m/44'/60'/0'/0/1
|
|
42
|
+
│ ├── Address vm: "evm" 0x6Fac4D18…
|
|
43
|
+
│ └── Address vm: "svm" Hh8QwFUA6…
|
|
44
|
+
└── … account.deriveWallets(n)
|
|
45
|
+
```
|
|
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:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Account "Cold Storage" (PK) no mnemonic
|
|
52
|
+
├── 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
|
|
58
|
+
```
|
|
59
|
+
|
|
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.
|
|
62
|
+
|
|
63
|
+
| | HD | PK |
|
|
64
|
+
| ---------------------- | ----------------------------- | ------------------------------- |
|
|
65
|
+
| Created from | a BIP-39 mnemonic | one private key |
|
|
66
|
+
| Grows with | `deriveWallets(n)` | `importPrivateKey(pk, vm)` |
|
|
67
|
+
| A `Wallet` is | a derivation slot | one imported key |
|
|
68
|
+
| Addresses per `Wallet` | **2** — one evm, one svm | **1** — the chain you imported |
|
|
69
|
+
| `dumpMnemonic()` | ✔ | throws `UNSUPPORTED_OP` |
|
|
70
|
+
| `sliceWallets(n)` | ✔ | throws `UNSUPPORTED_OP` |
|
|
71
|
+
| `importPrivateKey()` | throws `UNSUPPORTED_OP` | ✔ |
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// HD — one slot gives you the matching keys on both chains
|
|
75
|
+
const hd = await ws.accounts.create("Trading Desk", password, mnemonic);
|
|
76
|
+
await hd.deriveWallets(5); // slots 1..5, alongside slot 0
|
|
77
|
+
hd.wallets[0].addresses.find((a) => a.vm === "evm");
|
|
78
|
+
hd.wallets[0].addresses.find((a) => a.vm === "svm");
|
|
79
|
+
|
|
80
|
+
// PK — each import is its own wallet, on one chain
|
|
81
|
+
const pk = await ws.accounts.create("Cold Storage", password, privateKey);
|
|
82
|
+
await pk.importPrivateKey(anotherEvmKey, "evm"); // -> a new Wallet
|
|
83
|
+
await pk.importPrivateKey(aSolanaKey, "svm"); // -> another new Wallet
|
|
84
|
+
```
|
|
85
|
+
|
|
5
86
|
## Install
|
|
6
87
|
|
|
7
88
|
```bash
|
|
@@ -71,9 +152,25 @@ await ws.lock();
|
|
|
71
152
|
| Extra setup | none | `Buffer` polyfill |
|
|
72
153
|
| Keys can vanish| no | yes — storage is evictable |
|
|
73
154
|
|
|
74
|
-
`HybridProvider` and `FileSink` are
|
|
75
|
-
|
|
76
|
-
|
|
155
|
+
`HybridProvider`, `HybridProviderV3` and `FileSink` are re-exported from the
|
|
156
|
+
package root in Node.
|
|
157
|
+
|
|
158
|
+
Take the provider from the **same entry point** as `Workspace`:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
// Right — one entry point.
|
|
162
|
+
import { Workspace, HybridProvider } from "wative-core";
|
|
163
|
+
const ws = await Workspace.open(new HybridProvider("~/wallets"), password);
|
|
164
|
+
|
|
165
|
+
// Wrong — rejected with a PARAMETER_ERROR naming the fix.
|
|
166
|
+
import { Workspace } from "wative-core";
|
|
167
|
+
import { HybridProvider } from "wative-core/node";
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Each entry point is a separate bundle with its own class identities and module
|
|
171
|
+
state, so a provider built by one is not recognised by a `Workspace` from the
|
|
172
|
+
other. `Workspace.open` rejects it with an error naming the fix. A bare
|
|
173
|
+
`import "wative-core/node"` for its side-effects is unaffected.
|
|
77
174
|
|
|
78
175
|
### Browser: the Buffer polyfill
|
|
79
176
|
|
|
@@ -126,9 +223,131 @@ const backup = await provider.exportContainer(); // still encrypted
|
|
|
126
223
|
await otherProvider.importContainer(backup); // same password opens it
|
|
127
224
|
```
|
|
128
225
|
|
|
226
|
+
## Key derivation
|
|
227
|
+
|
|
228
|
+
Passwords are stretched with Argon2id (RFC 9106) at t=3, m=64 MiB, p=1 before
|
|
229
|
+
they ever touch a key. That is deliberately expensive, and an account unlock
|
|
230
|
+
runs one derivation per sealed secret — so the implementation matters.
|
|
231
|
+
|
|
232
|
+
By default it runs on a vendored WebAssembly build: no native binary, no build
|
|
233
|
+
step, nothing to install. Measured over a full workspace lifecycle it is about
|
|
234
|
+
**25x** faster than the pure-JS implementation it replaced.
|
|
235
|
+
|
|
236
|
+
### Browser: grant `'wasm-unsafe-eval'`
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval'
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Without it the browser blocks WebAssembly compilation entirely — synchronously
|
|
243
|
+
and asynchronously, main thread and worker alike. **Nothing throws.** Key
|
|
244
|
+
derivation quietly falls back to a pure-JS implementation that produces
|
|
245
|
+
identical bytes roughly 17x slower, so unlocking a wallet with a dozen addresses
|
|
246
|
+
goes from under a second to tens of seconds. The fallback is announced once on
|
|
247
|
+
the console and reported permanently by `argon2BackendInfo()`.
|
|
248
|
+
|
|
249
|
+
## Upgrading to 2.3.0
|
|
250
|
+
|
|
251
|
+
**v1 containers can no longer be opened.** Support for the v1 envelope
|
|
252
|
+
(PBKDF2-HMAC-SHA256, written by wative-core 1.x) was removed and there is no
|
|
253
|
+
migration path in this release. Containers written by any 2.x version are v2 and
|
|
254
|
+
open unchanged.
|
|
255
|
+
|
|
256
|
+
If you hold a v1 container, recover it with **2.2.x or earlier** before
|
|
257
|
+
upgrading. `exportContainer()` will not do it — it copies sealed bytes without
|
|
258
|
+
decrypting, so the export is as unreadable as the original. Use the accessors
|
|
259
|
+
that return plaintext:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// under wative-core 2.2.x — NOT 2.3.0, which can no longer open a v1 container
|
|
263
|
+
import { Workspace, HybridProvider } from "wative-core";
|
|
264
|
+
|
|
265
|
+
const ws = await Workspace.open(new HybridProvider("~/wallets"), password);
|
|
266
|
+
|
|
267
|
+
for (const account of ws.accounts) {
|
|
268
|
+
await account.tryUnlock(password);
|
|
269
|
+
|
|
270
|
+
// HD accounts: the mnemonic regenerates every derived key, so it is the only
|
|
271
|
+
// thing you need.
|
|
272
|
+
if (account.organizationType === "HD") {
|
|
273
|
+
console.log(account.slug, "mnemonic:", account.dumpMnemonic());
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// PK accounts: there is no mnemonic, so every imported key must be kept.
|
|
278
|
+
// `dumpPrivateKey` lives on the WALLET and takes the VM of the address you
|
|
279
|
+
// want — a wallet holds at most one address per VM.
|
|
280
|
+
for (const wallet of account.wallets) {
|
|
281
|
+
for (const address of wallet.addresses) {
|
|
282
|
+
console.log(account.slug, wallet.id, address.vm, wallet.dumpPrivateKey(address.vm));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Keep that material somewhere safe, upgrade, then re-import it with
|
|
289
|
+
`accounts.create(...)` and `importPrivateKey(...)`.
|
|
290
|
+
|
|
291
|
+
Three public members were removed with v1: `Provider.passwordTanren`,
|
|
292
|
+
`ContainerProvider.passwordTanren` and `HybridProvider.kdfIterations`. All three
|
|
293
|
+
existed only to expose the PBKDF2 derivation.
|
|
294
|
+
|
|
295
|
+
### One derivation per container: `HybridProviderV3` (Node only)
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
import { Workspace, HybridProviderV3 } from "wative-core";
|
|
299
|
+
|
|
300
|
+
const ws = await Workspace.open(new HybridProviderV3("~/wallets"), password);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
The default provider derives an Argon2 key per sealed secret, so unlocking an
|
|
304
|
+
account costs one derivation per address — at production parameters that is
|
|
305
|
+
essentially the whole cost, and it grows with the account. `HybridProviderV3`
|
|
306
|
+
derives once per container instead. Measured: unlocking a 50-address account
|
|
307
|
+
goes from 7.3 s to 144 ms, and the v3 figure does not grow with the address
|
|
308
|
+
count.
|
|
309
|
+
|
|
310
|
+
It is opt-in, and Node-only: it derives through native `@node-rs/argon2`, which
|
|
311
|
+
has no browser build. In a browser use `HybridProvider`, which needs no binary
|
|
312
|
+
and no install and is already about 25x faster than what preceded it.
|
|
313
|
+
|
|
314
|
+
⚠️ **The speedup applies to records written as v3, not to ones you already
|
|
315
|
+
have.** Pointing `HybridProviderV3` at a container built by 2.x keeps every
|
|
316
|
+
existing secret on its own salt, so it keeps costing one derivation each — the
|
|
317
|
+
container still opens, it just does not get faster. Rewriting an account's
|
|
318
|
+
secrets with `account.resetPassword(old, new)` converts them. A container
|
|
319
|
+
reaches one derivation once all of its records have been written as v3, which
|
|
320
|
+
happens on its own only for containers created under v3.
|
|
321
|
+
|
|
322
|
+
The first v3 unlock of an existing container costs one extra derivation, once,
|
|
323
|
+
and converts its CONFIG record to v3 — after which wative-core 2.2.x and earlier
|
|
324
|
+
can no longer open it.
|
|
325
|
+
|
|
326
|
+
Reads do not depend on the choice — every record carries its own version byte,
|
|
327
|
+
so either 2.3.0 provider opens either format, in both directions. ⚠️ But **older
|
|
328
|
+
library versions cannot read v3**: wative-core 2.2.x and earlier know only v1 and
|
|
329
|
+
v2 and will fail with `Unknown envelope version: 3`. Adopting v3 is a one-way
|
|
330
|
+
door with respect to the library version.
|
|
331
|
+
|
|
332
|
+
### Checking which implementation ran
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
import { argon2BackendInfo } from "wative-core";
|
|
336
|
+
|
|
337
|
+
argon2BackendInfo();
|
|
338
|
+
// { backend: "wasm", wasm: true, overrides: [] }
|
|
339
|
+
// { backend: "noble", wasm: false, reason: "...", overrides: [] } ← degraded
|
|
340
|
+
// { backend: "unresolved", wasm: false, ..., overrides: ["node-rs"] }
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
`backend` is the process-wide default. A provider may carry its own — a
|
|
344
|
+
`HybridProviderV3` does — so check **`overrides`** to confirm the native path
|
|
345
|
+
took. It is a pure read and resolves nothing, so before the first unlock it
|
|
346
|
+
honestly answers `"unresolved"`.
|
|
347
|
+
|
|
129
348
|
## Runnable examples
|
|
130
349
|
|
|
131
|
-
|
|
350
|
+
An `examples/` folder ships with the package — runnable JavaScript files demonstrating every domain's use cases. Read them top-to-bottom as walkthroughs, or run them as integration tests via Node's built-in test runner.
|
|
132
351
|
|
|
133
352
|
Copy them out of `node_modules` first, then run the whole set:
|
|
134
353
|
|
|
@@ -140,10 +359,10 @@ node --test wative-examples/
|
|
|
140
359
|
The copy is required: Node's test runner skips anything under `node_modules`, so pointing `--test` there finds no files. To run a single example without copying, execute it directly — a `node:test` file runs itself:
|
|
141
360
|
|
|
142
361
|
```bash
|
|
143
|
-
node node_modules/wative-core/
|
|
362
|
+
node node_modules/wative-core/examples/01-quick-start.test.cjs
|
|
144
363
|
```
|
|
145
364
|
|
|
146
|
-
Files cover: quick start, HD vs PK accounts, network management, asset management, address signing, custom storage backends, persistence, workspace search, default-network selection, subpath imports, the workspace logger, workspace config, the ESM entry, and package resolution. See [
|
|
365
|
+
Files cover: quick start, HD vs PK accounts, network management, asset management, address signing, custom storage backends, persistence, workspace search, default-network selection, subpath imports, the workspace logger, workspace config, the ESM entry, and package resolution. See [examples/README.md](./examples/README.md) for the index.
|
|
147
366
|
|
|
148
367
|
## What you can do
|
|
149
368
|
|
|
@@ -155,7 +374,7 @@ The library is organized around seven things you'll work with:
|
|
|
155
374
|
- **`Address`** — an on-chain identity. Sign messages, build transactions, send them.
|
|
156
375
|
- **`Network`** — chain metadata. 10 networks ship pre-loaded.
|
|
157
376
|
- **`Asset`** — token metadata. 25 tokens ship pre-loaded.
|
|
158
|
-
- **`Transaction`** — `EvmTransaction` or `SvmTransaction`. Subscribe to lifecycle events (`change` / `confirmed` / `failed`) or await terminal states (`whenSubmitted` / `whenMined` / `whenConfirmed` / `whenFinalized`).
|
|
377
|
+
- **`Transaction`** — `EvmTransaction` or `SvmTransaction`. Subscribe to lifecycle events (`change` / `confirmed` / `failed`) or await terminal states (`whenSubmitted` / `whenMined` / `whenConfirmed` / `whenFinalized`). Tracking stops at first inclusion, so `whenFinalized()` rejects `UNSUPPORTED_OP` unless the node reported finality directly.
|
|
159
378
|
|
|
160
379
|
Everything is encrypted on disk under your workspace password.
|
|
161
380
|
|
|
@@ -487,10 +706,11 @@ import { TokenProgram, Token2022Program } from "wative-core/artifacts/svm";
|
|
|
487
706
|
|
|
488
707
|
## Compatibility notes
|
|
489
708
|
|
|
709
|
+
- **Content-Security-Policy (browser)**: grant `'wasm-unsafe-eval'` in `script-src`, or key derivation silently degrades to a ~17x slower pure-JS path. See [Key derivation](#key-derivation).
|
|
490
710
|
- **Runtime**: Node.js 22.12+. Deno / Bun / browser support is partial. Some chain libraries that ship as compiled dependencies do not have universal builds yet.
|
|
491
711
|
- **Platform builds**: a few compiled dependencies lack pre-built binaries for Windows-ARM64 and Alpine-musl. Most installs on macOS / Linux x64 / Linux ARM64 won't notice.
|
|
492
712
|
- **One process at a time**: opening the same workspace from two Node processes simultaneously isn't supported.
|
|
493
713
|
|
|
494
714
|
## License
|
|
495
715
|
|
|
496
|
-
[
|
|
716
|
+
[Modified MIT](./LICENSE) — MIT terms with one added condition: products or services earning over US$50,000 monthly revenue must display "Wative" in their user interface. Everything else is standard MIT. The `LICENSE` file also carries third-party notices for the compiled components embedded in `dist/`.
|