wative-core 2.4.5 → 2.4.7

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 +20 -0
  2. package/README.md +38 -12
  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-_78IyJa7.d.ts → container-provider-D4yopeO_.d.ts} +1 -1
  12. package/dist/{container-provider-BBCTGYIz.d.cts → container-provider-Dh55EEx5.d.cts} +1 -1
  13. package/dist/{evm-DoSOTqrS.d.ts → evm-B-cOplST.d.ts} +1 -1
  14. package/dist/{evm-CttQebXS.d.cts → evm-CkUAeSHX.d.cts} +1 -1
  15. package/dist/{file-sink-B2Y_lOmu.d.cts → file-sink-ClLrovbG.d.cts} +2 -2
  16. package/dist/{file-sink-DCNmCf3a.d.ts → file-sink-GTK4Vv_k.d.ts} +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-FkRN0iiR.d.ts → svm-B0khNLa5.d.ts} +1 -1
  30. package/dist/{svm-DuvHI8Vy.d.cts → svm-BVmGEWtP.d.cts} +1 -1
  31. package/dist/{workspace-B5Uj8CfN.d.cts → workspace-B3nsEAmk.d.cts} +5 -0
  32. package/dist/{workspace-B5Uj8CfN.d.ts → workspace-B3nsEAmk.d.ts} +5 -0
  33. package/examples/04-network-management.test.cjs +5 -4
  34. package/examples/07-custom-provider.test.cjs +1 -1
  35. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
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.7] — 2026-09-11
6
+
7
+ Adds more built-in networks and updates the Solana network identifiers.
8
+
9
+ ### Added
10
+ - Four built-in networks ship preloaded, each with its native coin: HyperEVM, HyperEVM Testnet, Robinhood Chain, and Robinhood Chain Testnet.
11
+
12
+ ### Changed
13
+ - The built-in Solana, Solana Testnet and Solana Devnet networks now report new chain ids. If you look a Solana network up by chain id, read it from the resolved network rather than assuming the earlier value.
14
+
15
+ ## [2.4.6] — 2026-09-11
16
+
17
+ Fixes across signing, contracts and storage, and corrections to the documentation.
18
+
19
+ ### Fixed
20
+ - What a transaction is signed over is fixed the moment signing starts rather than when it ends, so editing the recipient, amount or data part-way through can no longer change what gets signed. An address left unusable by a send whose outcome never came back now recovers on its own within the same session.
21
+ - The one-call contract helpers use the address you pass them. A completed EVM transaction reports the fee it actually paid, and a failed one reports the reason the network gave.
22
+ - A storage backend is held by one workspace at a time. Locking or closing a workspace hands its backend back, so you can reopen the same one; what is refused is unlocking a workspace whose backend another workspace has taken in the meantime. Two networks whose node addresses differ only cosmetically — a trailing slash, a fragment — count as the same network.
23
+ - The README's transaction examples called for a number of confirmations that is not supported and would always fail, and its description of reading records straight off a storage backend was the reverse of what happens. Both are corrected, along with the obligations a custom backend must meet.
24
+
5
25
  ## [2.4.5] — 2026-09-10
6
26
 
7
27
  Safer handling of references you hold, of account names, and of sending transactions.
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Wative Core 2
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/wative-core?color=cb3837&logo=npm)](https://www.npmjs.com/package/wative-core)
4
- [![CI](https://github.com/braady/wative-core/actions/workflows/ci.yml/badge.svg)](https://github.com/braady/wative-core/actions/workflows/ci.yml)
5
4
  [![node](https://img.shields.io/node/v/wative-core)](https://nodejs.org)
6
5
  [![license](https://img.shields.io/badge/license-Modified%20MIT-blue)](./LICENSE)
7
6
 
@@ -321,7 +320,7 @@ The library is organized around seven things you'll work with:
321
320
  - **`Address`** — an on-chain identity. Sign messages, build transactions, send them.
322
321
  - **`Network`** — chain metadata. 10 networks ship pre-loaded.
323
322
  - **`Asset`** — token metadata. 25 tokens ship pre-loaded.
324
- - **`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.
323
+ - **`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 `whenConfirmed(n)` with `n > 1` rejects `UNSUPPORTED_OP` — call it with no argument and poll `receipt.blockNumber` against the chain head if you need depth — and `whenFinalized()` rejects `UNSUPPORTED_OP` unless the node reported finality directly.
325
324
 
326
325
  Everything is encrypted on disk under your workspace password.
327
326
 
@@ -484,7 +483,7 @@ tracker.on("confirmed", (receipt) => console.log("confirmed", receipt));
484
483
  tracker.on("failed", (err) => console.error("failed", err));
485
484
 
486
485
  const hash = await tracker.whenSubmitted();
487
- const receipt = await tracker.whenConfirmed(3);
486
+ const receipt = await tracker.whenConfirmed(); // no argument — see note below
488
487
 
489
488
  const sim = await evmAddr.simulateTransaction(tx);
490
489
  console.log(sim.gasUsed);
@@ -566,7 +565,7 @@ const evmTx = new EvmTransaction({
566
565
  await evmAddr.signTransaction(evmTx);
567
566
  const evmTracker = await evmAddr.sendTransaction(evmTx);
568
567
 
569
- const receipt = await evmTracker.whenConfirmed(3);
568
+ const receipt = await evmTracker.whenConfirmed();
570
569
  ```
571
570
 
572
571
  For Solana transactions, build instructions with `@solana/web3.js` (or your preferred Solana toolkit) and pass them to `new SvmTransaction({ from, recipient, amount, instructions })`. The signing, sending, and tracker lifecycle then mirror the EVM flow.
@@ -642,25 +641,31 @@ const ws = await Workspace.open({ provider, password });
642
641
 
643
642
  Everything a workspace persists is a `Record` — an account, a network, an asset, the config. You mostly work with the domain objects (`Account`, `Network`, …) and never touch a Record directly; you need this when you write a custom backend, or when you read records straight off a provider.
644
643
 
645
- A Record arrives **locked** and holds ciphertext until you unlock it:
644
+ A Record loaded from an **unlocked** provider arrives **already decrypted** — the
645
+ provider opens it with the workspace password as it hands it back. Only a record
646
+ sealed under its own separate password comes back locked:
646
647
 
647
648
  ```ts
648
649
  const record = await provider.loadRecord("ACCOUNTS", "alice");
649
650
 
650
- record.locked; // true
651
- record.value; // throws RECORD_LOCKED
652
-
653
- record.unlock(password); // decrypts in memory
651
+ record.locked; // false — the workspace password opened it
654
652
  record.value; // your data
655
653
 
656
654
  record.value.displayName = "Alice Desk";
657
655
  await record.save(); // re-encrypts and writes back
656
+
657
+ // A record sealed under its OWN password is the locked case:
658
+ const sealed = await provider.loadRecord("ACCOUNTS", "bob");
659
+ sealed.locked; // true
660
+ sealed.value; // throws RECORD_LOCKED
661
+ sealed.unlock(ownPwd); // decrypts in memory
662
+ sealed.value; // your data
658
663
  ```
659
664
 
660
665
  | member | behaviour |
661
666
  |---|---|
662
- | `locked` | `true` until `unlock()` succeeds |
663
- | `value` | throws `RECORD_LOCKED` while locked |
667
+ | `locked` | `false` when the workspace password opened the record; `true` when it did not, until `unlock()` succeeds |
668
+ | `value` | your data when unlocked; throws `RECORD_LOCKED` while locked |
664
669
  | `unlock(password)` | `BAD_PASSWORD` if wrong, `DECRYPT_FAILED` if the record cannot be read at all |
665
670
  | `save()` | throws if locked, or if the workspace that issued it has since been locked |
666
671
 
@@ -733,7 +738,28 @@ class MyDatabaseProvider extends Provider {
733
738
  const ws = await Workspace.open({ provider: new MyDatabaseProvider("postgres://..."), password: "wsp-pwd" });
734
739
  ```
735
740
 
736
- `Workspace.open()` accepts any `Provider` subclass — the rest of the library is identical regardless of where state lives.
741
+ `Workspace.open()` accepts any `Provider` subclass, and no library code branches
742
+ on which one you passed.
743
+
744
+ Two obligations the abstract signatures do not state, and one set of defaults you
745
+ may need to override:
746
+
747
+ - **`loadRecord` must distinguish "absent" from "unreadable".** A record that is
748
+ not there MUST reject with `RECORD_NOT_FOUND`. A record that is there but
749
+ cannot be decrypted MUST come back as a locked `Record`, not as a throw and not
750
+ by being omitted. A provider that returns a locked `Record` for a row it does
751
+ not have makes every name look taken, and no account can be created at all.
752
+ - **`loadRecords` must include the rows it could not open**, as locked `Record`s.
753
+ `Workspace` derives its damaged-record list from exactly that.
754
+ - **`occupiedAccountStems()` defaults to empty**, which is right for a store
755
+ whose keys collide only on exact equality. On a store whose collision rule is
756
+ wider — a case-insensitive filesystem, an S3-style key space, a
757
+ `utf8_general_ci` column — override it to return the lowercased stems.
758
+ Otherwise a damaged `Alice-Desk` row leaves `alice-desk` looking free and
759
+ account creation is refused as a name collision. Your bytes are safe either
760
+ way; the caller just cannot create the account. `accountRecordExists()` and
761
+ `unreadableRecordSlugs()` carry defaults in the same family — see their JSDoc
762
+ before overriding either.
737
763
 
738
764
  ## Imports from sub-paths
739
765