@ouronet/ouronet-core 4.3.6

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 (101) hide show
  1. package/CHANGELOG.md +3043 -0
  2. package/README.md +1940 -0
  3. package/dist/codex/codec.d.ts +77 -0
  4. package/dist/codex/codec.js +123 -0
  5. package/dist/codex/errors.d.ts +14 -0
  6. package/dist/codex/errors.js +20 -0
  7. package/dist/codex/index.d.ts +27 -0
  8. package/dist/codex/index.js +25 -0
  9. package/dist/codex/seedTypeMigration.d.ts +35 -0
  10. package/dist/codex/seedTypeMigration.js +45 -0
  11. package/dist/codex/types.d.ts +100 -0
  12. package/dist/codex/types.js +19 -0
  13. package/dist/constants/index.d.ts +2 -0
  14. package/dist/constants/index.js +3 -0
  15. package/dist/constants/ouronet.d.ts +33 -0
  16. package/dist/constants/ouronet.js +59 -0
  17. package/dist/constants/tokenIds.d.ts +13 -0
  18. package/dist/constants/tokenIds.js +21 -0
  19. package/dist/index.d.ts +18 -0
  20. package/dist/index.js +1 -0
  21. package/dist/interactions/activateFunctions.d.ts +67 -0
  22. package/dist/interactions/activateFunctions.js +154 -0
  23. package/dist/interactions/addLiquidityFunctions.d.ts +140 -0
  24. package/dist/interactions/addLiquidityFunctions.js +485 -0
  25. package/dist/interactions/coilFunctions.d.ts +73 -0
  26. package/dist/interactions/coilFunctions.js +213 -0
  27. package/dist/interactions/crossChainFunctions.d.ts +211 -0
  28. package/dist/interactions/crossChainFunctions.js +463 -0
  29. package/dist/interactions/dexAcquisitionPoolFunctions.d.ts +18 -0
  30. package/dist/interactions/dexAcquisitionPoolFunctions.js +18 -0
  31. package/dist/interactions/dexCollectablesFunctions.d.ts +28 -0
  32. package/dist/interactions/dexCollectablesFunctions.js +227 -0
  33. package/dist/interactions/dexFunctions.d.ts +23 -0
  34. package/dist/interactions/dexFunctions.js +23 -0
  35. package/dist/interactions/dexOrtoFungibleFunctions.d.ts +33 -0
  36. package/dist/interactions/dexOrtoFungibleFunctions.js +171 -0
  37. package/dist/interactions/dexParseFunctions.d.ts +150 -0
  38. package/dist/interactions/dexParseFunctions.js +316 -0
  39. package/dist/interactions/dexSwapPairAdminFunctions.d.ts +75 -0
  40. package/dist/interactions/dexSwapPairAdminFunctions.js +255 -0
  41. package/dist/interactions/dexSwapPairCalcFunctions.d.ts +55 -0
  42. package/dist/interactions/dexSwapPairCalcFunctions.js +218 -0
  43. package/dist/interactions/dexSwapPairDashboardFunctions.d.ts +47 -0
  44. package/dist/interactions/dexSwapPairDashboardFunctions.js +179 -0
  45. package/dist/interactions/dexSwapPairExecuteFunctions.d.ts +40 -0
  46. package/dist/interactions/dexSwapPairExecuteFunctions.js +301 -0
  47. package/dist/interactions/dexSwapPairSmartSwapFunctions.d.ts +25 -0
  48. package/dist/interactions/dexSwapPairSmartSwapFunctions.js +166 -0
  49. package/dist/interactions/dexTrueFungibleFunctions.d.ts +52 -0
  50. package/dist/interactions/dexTrueFungibleFunctions.js +220 -0
  51. package/dist/interactions/dexTypes.d.ts +465 -0
  52. package/dist/interactions/dexTypes.js +6 -0
  53. package/dist/interactions/errors.d.ts +12 -0
  54. package/dist/interactions/errors.js +13 -0
  55. package/dist/interactions/guardFunctions.d.ts +33 -0
  56. package/dist/interactions/guardFunctions.js +110 -0
  57. package/dist/interactions/index.d.ts +1 -0
  58. package/dist/interactions/index.js +20 -0
  59. package/dist/interactions/infoOneFunctions.d.ts +133 -0
  60. package/dist/interactions/infoOneFunctions.js +566 -0
  61. package/dist/interactions/kadenaFunctions.d.ts +11 -0
  62. package/dist/interactions/kadenaFunctions.js +40 -0
  63. package/dist/interactions/kpayFunctions.d.ts +45 -0
  64. package/dist/interactions/kpayFunctions.js +191 -0
  65. package/dist/interactions/ouroAccountFunctions.d.ts +64 -0
  66. package/dist/interactions/ouroAccountFunctions.js +229 -0
  67. package/dist/interactions/ouroBalanceFunctions.d.ts +39 -0
  68. package/dist/interactions/ouroBalanceFunctions.js +100 -0
  69. package/dist/interactions/ouroCoilFunctions.d.ts +33 -0
  70. package/dist/interactions/ouroCoilFunctions.js +190 -0
  71. package/dist/interactions/ouroFunctions.d.ts +23 -0
  72. package/dist/interactions/ouroFunctions.js +23 -0
  73. package/dist/interactions/ouroMovieBoosterFunctions.d.ts +18 -0
  74. package/dist/interactions/ouroMovieBoosterFunctions.js +203 -0
  75. package/dist/interactions/ouroPriceFunctions.d.ts +38 -0
  76. package/dist/interactions/ouroPriceFunctions.js +96 -0
  77. package/dist/interactions/ouroPrimordialsFunctions.d.ts +10 -0
  78. package/dist/interactions/ouroPrimordialsFunctions.js +480 -0
  79. package/dist/interactions/ouroRotateFunctions.d.ts +22 -0
  80. package/dist/interactions/ouroRotateFunctions.js +114 -0
  81. package/dist/interactions/ouroSubCompressFunctions.d.ts +23 -0
  82. package/dist/interactions/ouroSubCompressFunctions.js +191 -0
  83. package/dist/interactions/ouroTransferFunctions.d.ts +14 -0
  84. package/dist/interactions/ouroTransferFunctions.js +87 -0
  85. package/dist/interactions/ouroTypes.d.ts +113 -0
  86. package/dist/interactions/ouroTypes.js +6 -0
  87. package/dist/interactions/ouroUrStoaFunctions.d.ts +16 -0
  88. package/dist/interactions/ouroUrStoaFunctions.js +121 -0
  89. package/dist/interactions/ouroWrapFunctions.d.ts +22 -0
  90. package/dist/interactions/ouroWrapFunctions.js +234 -0
  91. package/dist/interactions/pensionFunctions.d.ts +12 -0
  92. package/dist/interactions/pensionFunctions.js +127 -0
  93. package/dist/interactions/urStoaFunctions.d.ts +104 -0
  94. package/dist/interactions/urStoaFunctions.js +475 -0
  95. package/dist/interactions/wrapFunctions.d.ts +46 -0
  96. package/dist/interactions/wrapFunctions.js +221 -0
  97. package/dist/pact/cfmBuilders.d.ts +807 -0
  98. package/dist/pact/cfmBuilders.js +812 -0
  99. package/dist/pact/index.d.ts +1 -0
  100. package/dist/pact/index.js +10 -0
  101. package/package.json +64 -0
package/README.md ADDED
@@ -0,0 +1,1940 @@
1
+ # @ouronet/ouronet-core
2
+
3
+ Ouronet protocol business logic on top of [`@stoachain/stoa-core`](https://www.npmjs.com/package/@stoachain/stoa-core) — codex backup format, the 13 `interactions/*` Pact builders for the `ouronet-ns` modules, the `STOA_AUTONOMIC_*` autonomic accounts, and the cfm Pact-code assembler. Consumed by **OuronetUI** (browser SPA) and the **AncientHolder HUB** (Node.js server).
4
+
5
+ Chain-generic infrastructure (signing, wallet, crypto, network failover, gas, guard, errors, observability, dalos, reads, pact-format helpers) lives in the sibling [`@stoachain/stoa-core`](https://www.npmjs.com/package/@stoachain/stoa-core) package — install both, or just this one if you only need the Ouronet-specific surface.
6
+
7
+ > **Renamed.** This package was published as `@stoachain/ouronet-core` through 4.3.5. The
8
+ > code, version line, and release history continue unbroken under the `@ouronet` scope —
9
+ > the published name now matches the organisation that owns it. The old name is deprecated
10
+ > on npm and points here. Migration is a rename and nothing else:
11
+ >
12
+ > ```diff
13
+ > - import { serializeCodex } from "@stoachain/ouronet-core/codex";
14
+ > + import { serializeCodex } from "@ouronet/ouronet-core/codex";
15
+ > ```
16
+
17
+ ## Status
18
+
19
+ **`4.3.6` on public npmjs** — **PATCH (atomic-triplet alignment with `@stoachain/stoa-core@4.3.6` + `@stoachain/kadena-stoic-legacy@4.3.6`).** Released 2026-06-11. NO code changes in this package; version bumped solely to maintain the atomic-triplet invariant. The v4.3.6 change (a `@stoachain/stoa-core` auto-gas-limit floor fix in `calculateAutoGasLimit`) lives entirely in `@stoachain/stoa-core`. Functionally identical to `4.3.5`. **829 specs pass.**
20
+
21
+ **`4.3.5` on public npmjs** — **ADDITIVE (atomic-triplet with `@stoachain/stoa-core@4.3.5` + `@stoachain/kadena-stoic-legacy@4.3.5` — those two functionally identical to 4.3.4; only ouronet-core changed).** Released 2026-06-10. Smart Ouronet Account deploy (`buildDeploySmartAccountPactCode` + `getDeploySmartAccountInfo`/`…InfoOnly` → `C_DeploySmartAccount`/`URC_DeploySmartAccount`); keyset-ref-aware activation (`buildDeploy{Standard,Smart}AccountPactCode` gained `mode`/`keysetRef` → `(keyset-ref-guard "<ref>")` in `"existing"` mode, preserving the keyset-ref guard type); and `getIgnisBalance` moved to tier **T1** (balance reads belong there — at T5 the patron IGNIS balance stayed stale right after a transfer, falsely blocking spends). Pure additive — existing exports unchanged (deploy builders gained optional defaults). See CHANGELOG.
22
+
23
+ **`4.3.4` on public npmjs** — **PATCH (atomic-triplet with `@stoachain/stoa-core@4.3.4` + `@stoachain/kadena-stoic-legacy@4.3.4`).** Released 2026-06-08. **Bugfix — UrStoa vault-earnings hover unwrap.** `ouroPrimordialsFunctions.parseResponse` routed `urstoa-vault-earning-hover` (a `{ decimal }` object) through `String()` → `"[object Object]"` → `0`, wrongly disabling the Dashboard UrStoa **Collect** button; it is now routed through `supplyHoverVal` (→ `mayComeWithDeimal`), matching the supply row. **822 specs pass.** See CHANGELOG.
24
+
25
+ **`4.3.3` on public npmjs** — **Additive (atomic-triplet with `@stoachain/stoa-core@4.3.3` + `@stoachain/kadena-stoic-legacy@4.3.3`).** Released 2026-05-30. New StoicTag + governor-rotation builders (`buildRotateGovernorPactCode`, `buildNonKeyGuardExpr`, `buildReleaseStoicTagPactCode`, `buildRegisterStoicTagPactCode`) + readers (`getStoicTagInfo` URC_0027c, `getStoicTagSelectorData` URC_0027b, `getRegisterStoicTagInfo`) + `StoicTagSelectorData` type, supporting the OuronetUI v1.2.5 StoicTag cycle. Bundles the never-published v4.3.2 frozen-keyset fix in `resolveGuard` / `getKadenaAccountGuard` (shallow-copy instead of mutating a frozen read result). Pure additive — no signature changes to existing exports. **822 specs pass.** npm publishes 4.3.1 → 4.3.3 (4.3.2 was never tagged).
26
+
27
+ **`4.3.1` on public npmjs** — **PATCH (atomic-triplet with `@stoachain/stoa-core@4.3.1` + `@stoachain/kadena-stoic-legacy@4.3.1`).** Released 2026-05-27. **ESM extensionless-relative-import fix** in emitted `dist/**/*.js` — same bug pattern as the sibling 4.3.1 packages. 40 source files updated, 90 imports rewritten. Strict ESM dynamic-imports (`await import('@ouronet/ouronet-core/codex')`, `/pact`, `/constants`, `/interactions/*`) now succeed under Node 22+. Peer-deps on `@stoachain/kadena-stoic-legacy` + `@stoachain/stoa-core` bumped 4.3.0 → 4.3.1. No API changes. **797/797 specs pass.** See CHANGELOG.
28
+
29
+ **`4.3.0` on public npmjs** — **MINOR (atomic-triplet with `@stoachain/stoa-core@4.3.0` + `@stoachain/kadena-stoic-legacy@4.3.0`).** Released 2026-05-25. Pure additive surface: 2 new account-rotation Pact builders — `buildRotateGuardPactCode({ patron, account, mode, keysetRef?, safe })` (emits `C_RotateGuard` with runtime-conditional `(read-keyset "ks")` or `(keyset-ref-guard "<ref>")` expression) + `buildRotateKadenaPactCode({ patron, account, newPaymentKey })` (emits `C_RotateKadena`, the kadena-ledger payment-key rotation Pact). MINOR over PATCH because these unlock a new categorised public consumer surface — the new sibling package [`@ouronet/ouronet-codex@0.1.0`](https://www.npmjs.com/package/@ouronet/ouronet-codex)'s headless rotation modals — that wasn't reachable through the prior builder set. Deferred: `buildRotateGovernorPactCode` (Pact function exists on chain, Smart Account `Σ.` only, but no consumer UI ships it yet; lands when OuronetUI consumes it post-Phase-9-migration). Test count: **797 specs pass** (was 788 in v4.2.2; +9 across the new builders). No signature changes to existing exports — consumers on `4.2.2` continue to work unchanged.
30
+
31
+ **`4.2.2` on public npmjs** — **PATCH (atomic-triplet with `@stoachain/stoa-core@4.2.2` + `@stoachain/kadena-stoic-legacy@4.2.2`).** Released 2026-05-18. Pure additive surface: 4 new `buildXxxPactCode` helpers (`ModifyCanChangeOwner`, `ModifyWeights`, `ToggleSwapCapability`, `ToggleAddLiquidity`) + 5 new INFO readers (`ChangeOwnership`, `ModifyCanChangeOwner`, `ModifyWeights`, `ToggleSwapCapability`, `ToggleAddLiquidity`) + 4 new UR\_\* reads (`getSwpairOwnerKonto`, `getSwpairCanChangeOwner`, `getSwpairCanSwap`, `getSwpairCanAdd`), supporting the OuronetUI v1.0.8 cycle wiring the SWP-pair Liquidity-Pools-Management page buttons. Shipped mid-cycle at 5-of-11 buttons wired (Change Ownership from v1.0.7 + Modify Can Change Owner / Modify Weights / Toggle Swapping / Toggle Provisioning) to validate the cascade on devwallet before the remaining 6 land in v4.2.3. Test count: **~796 specs pass** (was 776 in v4.2.1; +20 across the new builders). No signature changes to existing exports — consumers on `4.2.1` continue to work unchanged.
32
+
33
+ **`4.2.1` on public npmjs** — **PATCH (atomic-triplet with `@stoachain/stoa-core@4.2.1` + `@stoachain/kadena-stoic-legacy@4.2.1`).** Released 2026-05-16. Pure additive surface: 23 new `buildXxxPactCode` helpers + 1 INFO reader (`getChangeOwnershipInfo`) + 1 unprotected read helper (`getSwpairOwnerKonto`), supporting the OuronetUI v1.0.7 Phase-3b strategy migration cycle (every legacy `executeXxx` direct-helper caller — 14 modals — migrated onto the canonical `useCFMStrategy + buildXxxPactCode` pattern). New families: SWP (ChangeOwnership), TS01-C2.LQD (Wrap + Unwrap families with composite-create-account variants), TS01-C1.DALOS (DeployStandardAccount), TS01-C3.SWP liquidity + swap (AddLiquidity, RemoveLiquidity, 4 swap variants), TS02-C1.DPSF + TS02-C2.DPNF (token-set creation), coin.C_URV (Stake / Unstake / Collect), coin.C_UR (4 native UR transfer variants). Test count: **776 specs pass** (was 710 in v4.2.0; +66 across the new builders). No signature changes to existing exports — consumers on `4.2.0` continue to work unchanged.
34
+
35
+ **`4.2.0` on public npmjs** — **MINOR (atomic with `@stoachain/stoa-core@4.2.0` + `@stoachain/kadena-stoic-legacy@4.2.0`).** Released 2026-05-09. Closes 6 audit findings: **F-ARCH-001** (Phase 1 dex god-file split — ~10 entity-oriented files + thin re-export shim), **F-ARCH-002** (Phase 2 ouro god-file split + chain/UI surgical separation — ~11 entity-oriented files + thin re-export shim), **F-ARCH-003** (Phase 3 parameterized liquidity executor — 5 thin wrappers + 1 internal `executeLiquidityOp`, LOC reduction ~600 → ~200), **F-API-002** (Phase 4 — 12 functions honor declared `Promise<T | null>` contract, return null on RPC failure instead of rethrowing), **F-API-018** (Phase 5 readonly sweep — ~50 public-type fields in `codex/types.ts` and all `*Params` interfaces), **F-TEST-006** (Phase 7 — +127 specs across 6 modules: `infoOneFunctions`, `coilFunctions`, `kpayFunctions`, `pensionFunctions`, `activateFunctions`, `guardFunctions`). NEW deliverable: [`INTEGRATION-GUIDE.md`](https://github.com/StoaChain/stoa-js/blob/main/INTEGRATION-GUIDE.md) at repo root — comprehensive cold-start consumer onboarding doc, 13 sections, full v4.0 → v4.1 → v4.2 architectural arc. 8 new `v4-2-0-*.test.ts` regression-lock files. Test count: **710 specs pass** (was ~330 in v4.1.1). Cross-reference: see [`MIGRATION-v4.2.md`](https://github.com/StoaChain/stoa-js/blob/main/MIGRATION-v4.2.md) at the monorepo root.
36
+
37
+ **v4.3.6** — atomic-triplet alignment bump (atomic with `@stoachain/stoa-core@4.3.6` + `@stoachain/kadena-stoic-legacy@4.3.6`). Released 2026-06-11. NO code changes; the v4.3.6 change (a stoa-core auto-gas-limit floor fix in `calculateAutoGasLimit`) lives in `@stoachain/stoa-core`. Functionally identical to v4.3.5. **829 specs pass.**
38
+
39
+ **v4.3.5** — ADDITIVE (atomic-triplet with `@stoachain/stoa-core@4.3.5` + `@stoachain/kadena-stoic-legacy@4.3.5`). Released 2026-06-10. Smart Ouronet Account deploy builder (`buildDeploySmartAccountPactCode` + `getDeploySmartAccountInfo`/`…InfoOnly`); keyset-ref-aware activation (`mode`/`keysetRef` → `(keyset-ref-guard "<ref>")`); `getIgnisBalance` moved to tier T1 (fresh balance read). Pure additive. **829 specs pass.**
40
+
41
+ **v4.3.4** — PATCH bugfix (atomic-triplet with `@stoachain/stoa-core@4.3.4` + `@stoachain/kadena-stoic-legacy@4.3.4`). Released 2026-06-08. Routes the `urstoa-vault-earning-hover` `{ decimal }` object through `supplyHoverVal` instead of `String()`, re-enabling the Dashboard UrStoa Collect button. **822 specs pass.**
42
+
43
+ **v4.3.3** — additive StoicTag + governor-rotation release (atomic-triplet with `@stoachain/stoa-core@4.3.3` + `@stoachain/kadena-stoic-legacy@4.3.3`). Released 2026-05-30. New builders `buildRotateGovernorPactCode`, `buildNonKeyGuardExpr`, `buildReleaseStoicTagPactCode`, `buildRegisterStoicTagPactCode`; new readers `getStoicTagInfo`, `getStoicTagSelectorData`, `getRegisterStoicTagInfo`; new `StoicTagSelectorData` type. Bundles the never-published v4.3.2 frozen-keyset fix (`resolveGuard` / `getKadenaAccountGuard` shallow-copy). Pure additive — no signature changes to existing exports. **822 specs pass.**
44
+
45
+ **v4.3.1** — ESM packaging fix (atomic-triplet with `@stoachain/stoa-core@4.3.1` + `@stoachain/kadena-stoic-legacy@4.3.1`). Released 2026-05-27. Fixes extensionless relative imports in emitted `dist/**/*.js` that broke `await import('@ouronet/ouronet-core/...')` under Node 22+ strict ESM. 40 source files updated, 90 imports rewritten. Per TypeScript's recommended `.js`-suffix-in-source ESM pattern. Peer-deps on `@stoachain/kadena-stoic-legacy` + `@stoachain/stoa-core` bumped 4.3.0 → 4.3.1. No API changes; **797/797 specs pass**.
46
+
47
+ **v4.3.0** — additive account-rotation release (atomic-triplet with `@stoachain/stoa-core@4.3.0` + `@stoachain/kadena-stoic-legacy@4.3.0`). Released 2026-05-25. 2 new `buildXxxPactCode` helpers — `buildRotateGuardPactCode` (emits `C_RotateGuard` with runtime-conditional guard expression switched by `mode: "define" | "existing"`; the `safe` boolean is emitted as a bare Pact literal) and `buildRotateKadenaPactCode` (emits `C_RotateKadena`, the kadena-ledger payment-key rotation Pact). Supporting the new sibling package `@ouronet/ouronet-codex@0.1.0`'s headless `<RotateGuardModal>` + `<RotatePaymentKeyModal>` (`<RotateSovereignModal>` uses the pre-existing `buildRotateSovereignPactCode`). Pure additive — no signature changes to existing exports. Test count: 797 (was 788 in v4.2.2; +9 across the new builders). Deferred: `buildRotateGovernorPactCode` lands when OuronetUI consumes it post-migration.
48
+
49
+ **v4.2.2** — additive SWP-pair management release (atomic-triplet with `@stoachain/stoa-core@4.2.2` + `@stoachain/kadena-stoic-legacy@4.2.2`). Released 2026-05-18. 4 new `buildXxxPactCode` helpers (`ModifyCanChangeOwner`, `ModifyWeights`, `ToggleSwapCapability`, `ToggleAddLiquidity`) + 5 new INFO readers + 4 new UR\_\* reads, supporting the OuronetUI v1.0.8 cycle wiring the SWP-pair Liquidity-Pools-Management page buttons. Shipped mid-cycle at 5-of-11 buttons wired; remaining 6 (Modify Amplifier, Activate Frozen LP, Activate Sleeping LP, Update Special Fee Targets, Update Pending Branding, Upgrade Branding) will land in v4.2.3. Pure additive — no signature changes to existing exports. Test count: ~796 (was 776 in v4.2.1; +20 across the new builders + UR reads).
50
+
51
+ **v4.2.1** — additive strategy-migration release (atomic-triplet with `@stoachain/stoa-core@4.2.1` + `@stoachain/kadena-stoic-legacy@4.2.1`). Released 2026-05-16. 23 new `buildXxxPactCode` helpers + 1 INFO reader + 1 unprotected read helper, supporting the OuronetUI v1.0.7 Phase-3b strategy migration cycle (14 modals migrated off legacy `executeXxx` direct-helper paths onto `useCFMStrategy + buildXxxPactCode`). New families: SWP `C_ChangeOwnership` + `getSwpairOwnerKonto`; TS01-C2.LQD `Wrap{Stoa,UrStoa}` + `Unwrap{Stoa,UrStoa}` (simple + composite-with-create-account variants); TS01-C1.DALOS `DeployStandardAccount`; TS01-C3.SWP `AddLiquidity` + `RemoveLiquidity` + 4 swap variants (single/multi × with/no-slippage); TS02-C1.DPSF + TS02-C2.DPNF `CreateSet` + `CreateSetNFT`; coin.C_URV `Stake` + `Unstake` + `Collect` (simple + WithCreateAccount); coin.C_UR `NativeUrTransfer` / `Transmit` (+ their `Anew` variants). Composite-shape builders (Unwrap/Collect/Anew family) require the call site to `addData("ks", { keys: [<pub>], pred: "keys-all" })`. Pure additive — no signature changes to existing exports. Test count: 776 (was 710 in v4.2.0; +47 from cfm-builders test growth + ~19 from related coverage). All builders fully tested with canonical-shape + argument-ORDER + module/function-name guards.
52
+
53
+ **v4.2.0** — architectural-closures + INTEGRATION-GUIDE deliverable. **MINOR (atomic with `@stoachain/stoa-core@4.2.0` + `@stoachain/kadena-stoic-legacy@4.2.0`).** Released 2026-05-09. Lands the v4.2.0 audit-closures release: 6 audit findings closed in this package — **F-ARCH-001 (Phase 1)**: dex god-file split (~600 LOC `interactions/dexFunctions.ts` decomposed into ~10 entity-oriented files: `dexSwapPairCalcFunctions`, `dexSwapPairExecFunctions`, `dexLiquidityCalcFunctions`, `dexLiquidityExecFunctions`, `dexFuelCalcFunctions`, `dexFuelExecFunctions`, `dexDashboardFunctions`, `dexAccountSuppliesFunctions`, `dexCappedInverseFunctions`, `dexTypes`); old import path `@ouronet/ouronet-core/interactions/dexFunctions` continues to work as thin re-export shim. **F-ARCH-002 (Phase 2)**: ouro god-file split + chain/UI surgical separation (~2200 LOC `interactions/ouroFunctions.ts` → ~11 entity-oriented files; chain-side and UI-side surfaces cleanly separated per the locked principle); thin re-export shim preserved. **F-ARCH-003 (Phase 3)**: parameterized liquidity executor — `executeAddLiquiditySingle`, `executeAddLiquidity`, `executeSpecialAddLiquidity`, `executeFuel`, `executeRemoveLiquidity` consolidated into 5 thin wrappers + 1 internal `executeLiquidityOp` (LOC reduction ~600 → ~200); public function signatures preserved verbatim — zero consumer impact. **F-API-002 (Phase 4)**: 12 swap-calc and dashboard-read functions whose declared return type was `Promise<T | null>` now honor that contract — they return null on RPC failure (with `logger.error` invoked first) instead of rethrowing. Existing try/catch consumer patterns continue to work; new code can rely on the static-type signature with the `if (result === null)` pattern. Affected: `getSWPairDashboardInfo`, `getPoolPreviewData`, `getSWPairMultiDashboardInfo`, `getSwpairInternalDashboard`, `calculateDirectSwap`, `calculateInverseSwap`, `calculateDirectSwapB`, `calculateInverseSwapB`, `getCappedInverseAmount`, `getUserAccountSupplies`, plus 2 dashboard-read functions. **F-API-018 (Phase 5)**: aggressive `readonly` sweep across ~50 public-type fields in `codex/types.ts` and all `*Params` interfaces. TypeScript-only signal — no runtime change. Switch in-place mutations to immutable spread copy: `const updatedParams = { ...params, account: 'k:...' };`. **F-TEST-006 (Phase 7)**: +127 specs across 6 modules (`infoOneFunctions` / `coilFunctions` / `kpayFunctions` / `pensionFunctions` / `activateFunctions` / `guardFunctions`); the audit's stated 37 untested functions corrected to 38 (`guardFunctions.describeKeyset` was missed by the 2026-05-05 audit; absorbed by Phase 7 as +1 function = +3 it-blocks). NEW deliverable: **INTEGRATION-GUIDE.md** at repo root — comprehensive cold-start consumer onboarding doc, 13 mandated sections covering the full v4.0 → v4.1 → v4.2 architectural arc (install + peer-deps, the 3-package atomic-release model, subpath imports per package, the 5 typed error classes, the 7-entity Ouronet taxonomy, the 3 pluggable seams `setPactReader`/`KeyResolver`+`PactClient`/`BalanceResolver`, codex backup format `"1.2"`, smart-account auth, gas calibration, full quick-start example). Doc-validity test (`tests/v4-2-0-integration-guide-validity.test.ts`) verifies all cited subpaths resolve, all cited error classes import, all cited seam functions are exported. 8 new `v4-2-0-*.test.ts` regression-lock files in this package. Test count: 710 specs pass (was ~330 in v4.1.1; +127 from Phase 7 + ~250 from Phases 1-5 + 8 regression-lock specs). Cross-reference: [`MIGRATION-v4.2.md`](https://github.com/StoaChain/stoa-js/blob/main/MIGRATION-v4.2.md) for the v4.1.x → v4.2.0 transition guide, [`INTEGRATION-GUIDE.md`](https://github.com/StoaChain/stoa-js/blob/main/INTEGRATION-GUIDE.md) for cold-start onboarding.
54
+
55
+ **`4.1.1` on public npmjs** — **PATCH (atomic with `@stoachain/stoa-core@4.1.1` + `@stoachain/kadena-stoic-legacy@4.1.1`).** Released 2026-05-08. Closes audit findings: F-ERR-022 (fabricated `"0"` fallbacks in `kadenaFunctions` dropped — typed `KadenaShapeError` thrown instead), F-API-005 (`getSublimateInfo` dedup with deprecation shim), F-API-006 (`describeKeyset` dedup), F-API-007 (`EncryptedDataV1` collapse), F-SEC-007 (codex strict-shape with `CodexUnknownFieldError`), F-BUG-010 (`migrateSeedType` strict throw with `UnknownSeedTypeError`), F-API-014 (`getSparksBalance` return type narrowed). New file: `src/interactions/errors.ts` (`KadenaShapeError`). No breaking changes — `getSublimateInfo` deprecation shim preserves backward compatibility. **~330 specs pass.**
56
+
57
+ **`4.1.0` on public npmjs** — **MIGRATION (atomic with `@stoachain/stoa-core@4.1.0` + `@stoachain/kadena-stoic-legacy@4.1.0`).** Retargets all 12 internal `@kadena/*` imports in `src/interactions/` to the new sibling subpaths under [`@stoachain/kadena-stoic-legacy`](https://www.npmjs.com/package/@stoachain/kadena-stoic-legacy). Drops the three `@kadena/*` peer-dep declarations; bumps `@stoachain/stoa-core` peer-dep `4.0.1 → 4.1.0` (atomic-version invariant); adds `@stoachain/kadena-stoic-legacy: "4.1.0"`. No interactions-surface change for consumers — every `Pact.builder` call site rewires under the hood. Test count: 261 (was 218; +43 from new `tests/v4-1-0-no-kadena-imports.test.ts` runtime regression-lock).
58
+
59
+ **`4.0.1` on public npmjs** — **PATCH, cosmetic (published-metadata cleanup).** Strips the redundant `devDependencies` block from `package.json`. Pre-v4.0.1 the manifest carried `@stoachain/stoa-core: "*"` (workspace-resolution plumbing — meaningless on a published artifact since the `peerDependency` already pins `@stoachain/stoa-core@4.0.1`) plus duplicates of the `@kadena/*` peer entries. The npmjs.com page now shows the cleaner shape: zero `dependencies`, just the canonical `peerDependencies`. Atomic-version invariant: peer-dep on `@stoachain/stoa-core` bumped from `4.0.0` to `4.0.1` (both packages always release at the same version). NO source-code change. NO behaviour change. **218/218 tests pass.**
60
+
61
+ **`v4.0.0`** — **MAJOR, breaking (monorepo split + deprecated-alias removal).** v4.0.0 is the structural refactor that v3.3.8 set up. The single `@ouronet/ouronet-core` package was split into two atomic-release npm packages under the new `StoaChain/stoa-js` GitHub monorepo: `@stoachain/stoa-core` (chain-generic foundation) + `@ouronet/ouronet-core` (Ouronet protocol, this package). Both packages release atomically out of the monorepo at the same version — a single `vX.Y.Z` git tag publishes both. Removed the v3.3.8-deprecated aliases (`KADENA_BASE_URL`, `PACT_URL`, `GAS_STATION`, `NATIVE_TOKEN_VAULT`) and the duplicate `IKadenaKeypair` interface in `interactions/ouroFunctions.ts`. Consumers using only the Ouronet-specific surface (codex, interactions, the `ouronet-ns` namespace) can keep this package and bump the version. Consumers using chain-generic surfaces must add `@stoachain/stoa-core` and update the import paths — see [`MIGRATION-v4.md`](https://github.com/StoaChain/stoa-js/blob/main/MIGRATION-v4.md) at the monorepo root for the full upgrade map. **703/703 tests pass** across both packages (485 in stoa-core, 218 in ouronet-core; up from v3.3.8's 698 because the F-ARCH-011/F-ARCH-012 v3.3.8 regression locks now live alongside their stoa-core SUTs — every prior test preserved). Also pinned all `@kadena/*` + `@noble/curves` + `@scure/bip39` + `@ouronet/dalos-crypto` peer/dev deps to exact versions (no `^`) — prep work for v4.1.0's selective vendoring of `@kadena/client` (supply-chain hardening after Kadena LLC's dissolution).
62
+
63
+ **`v3.3.8`** — **MINOR, additive
64
+ (documentation/deprecation cleanup pass).** Closes 5
65
+ LOW-severity findings from the 2026-05-05 audit's `"v3.x
66
+ deprecation cleanup"` + `"v3.x conventions alignment"` + `"v3.x
67
+ API hygiene"` themes in a single bundled release.
68
+ **F-API-015** rewrote stale `strict`-parameter JSDoc on
69
+ `src/dalos/account.ts:42-45` (the parameter never existed in
70
+ the `CreateAccountOptions` type union; new doc explains the
71
+ actual mode-vs-primitive throw contract).
72
+ **F-API-016** added `export` to the `CoilConfig` interface in
73
+ `src/interactions/coilFunctions.ts:17` — consumers holding a
74
+ `CoilConfig` value (e.g. from `COIL_CONFIGS.ouroToAuryn`)
75
+ could USE it but couldn't TYPE-ANNOTATE a parameter or local
76
+ with `CoilConfig` without re-declaring the shape; now they can.
77
+ **F-SEC-005 / F-ARCH-014** added `@deprecated` JSDoc to
78
+ `KADENA_BASE_URL` redirecting consumers to the failover-aware
79
+ `getActivePactUrl(chainId)` / `getActiveSpvUrl(chainId)` (or
80
+ the same-subpath thin wrappers `getPactUrl(chainId)` /
81
+ `getSpvUrl(chainId)`); removal scheduled for v4.0.0. The
82
+ constant was pinned to `node2.stoachain.com` and bypassed the
83
+ v2.1.0 failover layer.
84
+ **F-ARCH-011** consolidated `normalizeKeysetRef` deep-import
85
+ in `src/interactions/ouroFunctions.ts:10` to the `../guard`
86
+ barrel, matching the project's subpath-import discipline.
87
+ **F-ARCH-012** converted 19 single-quoted string literals to
88
+ double quotes in `src/dalos/account.ts` — the file was the
89
+ only remaining drift after v3.1.1's fix to
90
+ `src/dalos/index.ts`. Pure stylistic; TypeScript treats the
91
+ two forms as identical string literals at the type level.
92
+ **NO breaking change**, **NO observable runtime behavior
93
+ change**, **698/698 tests pass** (was 695 in v3.3.7; +3 from
94
+ the new `tests/v3-3-8-doc-cleanup.test.ts` regression-lock
95
+ file). One new public-API export (`CoilConfig` interface).
96
+
97
+ **`3.3.7`** — **MINOR, additive (security
98
+ pass).** Closes two MEDIUM security findings from the
99
+ 2026-05-05 audit in a single bundled release: **F-SEC-003**
100
+ (seam-setter input validation) and **F-SEC-004** (V1-fallback
101
+ security advisory). **F-SEC-003** adds two new typed errors —
102
+ `InvalidPactReaderError` (rejects non-function values passed to
103
+ `setPactReader`) and `InvalidLoggerError` (rejects null /
104
+ undefined / non-object inputs and any object whose `warn` or
105
+ `error` are non-callable, passed to `setLogger`). Both extend
106
+ `TypeError` so existing consumer `instanceof TypeError` catches
107
+ are unchanged. Pre-v3.3.7 the misconfigurations only surfaced
108
+ later as `_reader is not a function` / `_logger.warn is not a
109
+ function` at the first call site, far from the boot wiring;
110
+ v3.3.7 surfaces them at the boot site. **F-SEC-004** wires a
111
+ **one-shot** `getLogger().warn(...)` security advisory into the
112
+ V1-decrypt path (V1 = PBKDF2-SHA256 / 10,000 iterations; OWASP
113
+ 2023+ recommends 600,000) — fires on the FIRST V1 envelope
114
+ decoded per process lifetime, stays silent after that so a
115
+ codex with 100 V1 entries logs ONE warning, not 100. Adds two
116
+ new public-API rich variants `decryptStringV2WithDetails` and
117
+ `smartDecryptWithDetails` that return `{plaintext, wasLegacyV1}`
118
+ for the per-call programmatic signal — consumers can react by
119
+ re-encrypting affected entries to V2 in-place. JSDoc CVE-style
120
+ risk documentation added to `EncryptedDataV1`,
121
+ `decryptStringV2`, and `smartDecrypt`. **NO breaking change**,
122
+ **695/695 tests pass** (was 674 in v3.3.6; +21 from
123
+ `tests/v3-3-7-seam-validators.test.ts` (11) +
124
+ `tests/v3-3-7-v1-warning.test.ts` (10)). v3.3.0 contract test
125
+ locking the byte-identical `setLogger requires a non-null
126
+ Logger` message preserved verbatim — the new
127
+ `InvalidLoggerError` extends `TypeError` to keep that contract
128
+ intact.
129
+
130
+ **`3.3.6`** — **MINOR, additive (performance
131
+ pass).** Closes three MEDIUM performance findings from the
132
+ 2026-05-05 audit in a single bundled release:
133
+ **F-PERF-008** — added `"sideEffects": false` to `package.json`
134
+ (the audit's "single most impactful tree-shaking fix"; lets
135
+ downstream bundlers prune unused barrel imports from the
136
+ 16-subpath exports map; verified safe via top-level-mutation
137
+ grep across `src/`);
138
+ **F-PERF-003** — memoized 8 `RegExp` allocations per call in
139
+ `coilFunctions.getCoilPreviewGeneric` to a per-`targetTokenName`
140
+ `Map<string, CoilPatternSet>` cache (the audit's literal
141
+ suggested fix "hoist to module-level const" doesn't apply
142
+ because patterns interpolate `targetTokenName` from `config`,
143
+ but the cache form achieves the same outcome — steady-state
144
+ allocation cost is 0 RegExp objects per call after warm-up);
145
+ **F-PERF-004** — parallelized `ouroFunctions.getOuronetKdaDetails`
146
+ from sequential `await getKadenaAccountOwner()` →
147
+ `await getKadenaAccountGuard()` to a single
148
+ `Promise.all([owner, guard])` (verified independent: probes
149
+ `DALOS.UR_AccountKadena` vs `DALOS.UR_AccountGuard` with no
150
+ causal dependency; halves happy-path latency from 2 sequential
151
+ RPC roundtrips to 1 parallel roundtrip).
152
+ All three are low-risk, behaviorally identical to v3.3.5.
153
+ Consumer-side impact: smaller OuronetUI bundle sizes (F-PERF-008,
154
+ exact savings bundler-config-dependent); faster
155
+ `getOuronetKdaDetails` (F-PERF-004, ~half wall-clock); no
156
+ observable difference for `getCoilPreviewGeneric` (F-PERF-003,
157
+ internal-only). **NO public API change**, **674/674 tests pass**
158
+ (was 672 in v3.3.5; +2 from the new
159
+ `tests/v3-3-6-perf-pass.test.ts` regression-lock file). Locks
160
+ both F-PERF-008 (`expect(pkg.sideEffects).toBe(false)` strict
161
+ equality) and F-PERF-004 (counting reader proves both
162
+ `UR_AccountKadena` AND `UR_AccountGuard` reads still happen,
163
+ catching a regression that accidentally drops one of the reads).
164
+
165
+ **`3.3.5`** — **MINOR, additive (test-only).**
166
+ Closes audit finding **F-TEST-006** (MEDIUM, testing-auditor) —
167
+ six interaction modules previously had insufficient runtime
168
+ coverage: three with **zero runtime tests at all**
169
+ (`pensionFunctions`, `guardFunctions`, `infoOneFunctions`) and
170
+ three with **compile-only tests** (`coilFunctions`,
171
+ `kpayFunctions`, `activateFunctions` are all type-checked at
172
+ `tests/types.test.ts:44-47` via `expectTypeOf`, but the functions
173
+ never actually execute in the test suite). Compile-only tests
174
+ prove the type signature matches consumer expectations but do
175
+ NOT prove the function executes correctly — a bug that swapped
176
+ two argument-string concatenations, forgot to await a Promise,
177
+ or mis-routed the `pactRead` call would all type-check cleanly
178
+ while producing wrong runtime behaviour. v3.3.5 closes the gap
179
+ with `tests/v3-3-5-smoke.test.ts` — **12 new it-blocks across 6
180
+ describe groups**, one happy-path + one error-path test per
181
+ module, picking the simplest representative read-only function
182
+ from each: `pensionFunctions.getHibernateFee` (the ONLY of the 6
183
+ with a non-null error path — graceful-degradation fallback
184
+ formula `0.12 - 0.000008 * lockDays` clamped non-negative);
185
+ `guardFunctions.getRotateGuardInfo`;
186
+ `infoOneFunctions.getCoilPreviewInfo` (locks the
187
+ `{result: ...}` envelope wrap contract);
188
+ `coilFunctions.getCoilPreviewGeneric` (the ONLY of the 6 that
189
+ rethrows rather than returning `null`/fallback — locks the
190
+ rethrow contract that consumers depend on for try/catch flow);
191
+ `kpayFunctions.getKpayData`;
192
+ `activateFunctions.getDeployStandardAccountInfoOnly`. Strategy
193
+ mirrors v3.3.4: install a stubbed reader via `setPactReader(...)`,
194
+ call SUT, assert. **NO source-code change**, **NO public API
195
+ change**, **672/672 tests pass** (was 660 in v3.3.4; +12 from
196
+ the new test file). With v3.3.5 the **v3.3.x audit-closure track
197
+ is COMPLETE** — all MEDIUM testing findings from the 2026-05-05
198
+ audit are now closed (F-LOGGER-SEAM-001 → v3.3.0; F-TEST-002 →
199
+ v3.3.2; F-TEST-005 → v3.3.4; F-TEST-006 → v3.3.5).
200
+
201
+ **`3.3.4`** — **MINOR, additive (test-only).**
202
+ Closes audit finding **F-TEST-005** (MEDIUM, testing-auditor) —
203
+ the v3.0.0 nullable-widening sweep widened 16 read-side
204
+ interaction functions from `Promise<T>` → `Promise<T | null>`,
205
+ but only **3 of the 16** had a paired success-path test
206
+ (`getStoaPriceUSD` at `tests/interactions-pricing.test.ts:80`,
207
+ `getLPTypeInfo`'s mixed-state lock at
208
+ `interactions-balance-cluster.test.ts:137`, and
209
+ `getUrStoaGuard`'s 3-state contract at the same file:207). The
210
+ other 13 could not distinguish "always returns null" (silent
211
+ regression) from "returns null only on RPC failure" (correct
212
+ contract) — a future bug that returned `null` unconditionally
213
+ would slip past every existing test, surface only at consumer
214
+ runtime, and be caught only by chain-side breakage. v3.3.4
215
+ closes the gap with `tests/v3-3-4-success-paths.test.ts` —
216
+ **13 new it-blocks across 6 describe groups**, one per missing
217
+ function, each installing a `successReader` stub via
218
+ `setPactReader(...)` and asserting the parsed non-null return
219
+ value. The 13 functions: `getTokenDecimals`, `getPoolTotalFee`,
220
+ `getDPTFMinMove` (pricing-quartet missing 3); `getIgnisBalance`,
221
+ `getAccountTokenSupply`, `getOuroDispoCapacity`, `getVirtualOuro`
222
+ (string-balance cluster — none previously covered);
223
+ `getUrStoaBalance` and `checkCoinAccountExists` (urStoa pair);
224
+ `validateLiquidity` (mixed-shape success — locks the
225
+ `valid:true` ↔ `error:undefined` mutual exclusion that
226
+ distinguishes a successful liquidity check from an RPC-failure
227
+ one); `getMaxBuyMovieBooster` (locks `Number.isFinite` guard
228
+ against v2.x fabricated-`0`); `getSWPSpawnLimit` and
229
+ `getSWPInactiveLimit` (magic-string elimination — also asserts
230
+ `expect(out).not.toBe("N/A")` so the v3.0.0 BREAKING swap
231
+ cannot regress unnoticed). **NO source-code change**, **NO
232
+ public API change**, **660/660 tests pass** (was 647 in v3.3.3;
233
+ +13 from the new test file).
234
+
235
+ **`3.3.3`** — **MINOR, additive (NEW PUBLIC
236
+ SURFACE — not a bug fix).** Ships the multi-party
237
+ partial-signature workflow OuronetUI has been blocked on:
238
+ "Person A signs → exports → Person B imports → signs → exports →
239
+ Person C imports → signs → submits", with cross-party tamper
240
+ detection at every handoff. Builds on v3.3.2's locked
241
+ partial-signing primitive (signing with a subset of declared
242
+ signers fills only those slots; pre-existing slots stay intact
243
+ across re-signing passes) by wrapping it in a versioned export
244
+ envelope + slot-status helpers + Ed25519 sig-verification helper.
245
+ New `src/signing/partialSig.ts` module re-exported from
246
+ `@ouronet/ouronet-core/signing`, exposing 7 functions
247
+ (`signPartial`, `serializePartialTransaction`,
248
+ `deserializePartialTransaction`, `getMissingSigners`,
249
+ `getFilledSigners`, `isFullySigned`, `verifyExistingSignatures`)
250
+ + 2 typed errors (`InvalidEnvelopeError`, `TamperedHashError`) +
251
+ the `PartialSigEnvelope` interface. The envelope embeds both
252
+ `cmd` and `hash` so importers can verify integrity; if the cmd
253
+ was tampered mid-flight, `deserializePartialTransaction` rejects
254
+ with `TamperedHashError` carrying both `expected` and `actual` for
255
+ operator diagnosability. As a second layer,
256
+ `verifyExistingSignatures` runs `nacl.sign.detached.verify` on
257
+ every filled slot — works for both nacl-direct (koala/foreign)
258
+ and BIP32-WASM (chainweaver/eckowallet) sigs since both produce
259
+ standard Ed25519 over the same canonical hash bytes. **NO
260
+ existing API changed**, **NO source-side behaviour change**
261
+ outside the new module, **647/647 tests pass** (was 631 in
262
+ v3.3.2; +16 from the new `tests/partial-sig.test.ts`).
263
+
264
+ **`3.3.2`** — **MINOR, additive (test-only).**
265
+ Closes audit finding **F-TEST-002** (HIGH) — the central signing
266
+ entry point `universalSignTransaction` in
267
+ `src/signing/universalSign.ts` had ZERO direct tests pre-v3.3.2.
268
+ The only mention in `tests/` was a comment in
269
+ `tests/signing.test.ts:5` stating "the full
270
+ universalSignTransaction is not exercised here";
271
+ `tests/strategy.test.ts` exercises a higher-level wrapper but only
272
+ covers `seedType: "koala"`. The chainweaver / eckowallet / foreign
273
+ branches AND the seedType dispatcher itself were never
274
+ runtime-tested — a regression that mis-routed `eckowallet` →
275
+ `koala` (or any other dispatch error) would silently produce
276
+ wrong-shape signatures, surfaced only by chain-side "invalid
277
+ signature" rejection at consumer runtime. v3.3.2 adds
278
+ `tests/universal-sign.test.ts` with **9 new it-blocks** covering
279
+ all three seedType branches with real-keypair round-trips
280
+ (koala via RFC-8032 vector, chainweaver/eckowallet via the
281
+ @kadena/hd-wallet vendor vector through
282
+ `KadenaWalletBuilder.createWalletPairFromMnemonic`), the
283
+ foreign-key `onMissingKey` callback (success and key-mismatch
284
+ error cases), the multi-signer mixed-seedType case, the
285
+ partial-signing primitive (foundation lock for v3.3.3's
286
+ multi-party signing public surface), and the
287
+ silent-skip-when-not-in-signers contract. **NO source-code
288
+ change**, **NO public API change**, **631/631 tests pass** (was
289
+ 622 in v3.3.1; +9 from the new test file).
290
+
291
+ **`3.3.1`** — **PATCH, workflow-only.** Closes the
292
+ two carried-forward follow-ups that have appeared in every
293
+ pollinate run's "follow-ups" block since v3.0.0: (1) `npm publish`
294
+ now passes `--provenance` (and the workflow gains `id-token:
295
+ write` permission), so v3.3.1 onwards every release carries a
296
+ verifiable SLSA attestation linking the published tarball to the
297
+ exact GitHub Action run that produced it; (2) the `gh release
298
+ create` calls drop the `--repo` flag, eliminating the
299
+ `gh release create --notes-from-tag --repo X` flag-combination
300
+ incompatibility that the GitHub-hosted runners' gh-CLI image
301
+ rejected starting around 2026-04-30 (every v3.x release pre-v3.3.1
302
+ needed pollinate's REST-API fallback at Step 9c to create the
303
+ GitHub Release manually). Both fixes are workflow-file-only —
304
+ `.github/workflows/publish.yml` is the only file with a behaviour
305
+ change. **NO source-code change**, **NO public API change**,
306
+ **622/622 tests pass unchanged**. Consumers see byte-identical
307
+ package contents to v3.3.0; the difference is the v3.3.1
308
+ attestation badge on npmjs.com and a green-check on the GitHub
309
+ Action run page (vs the recurring red-X for the gh-CLI Release
310
+ step that every v3.x release pre-v3.3.1 produced).
311
+
312
+ **`3.3.0`** — **MINOR, additive (Logger interface
313
+ extension) + behaviour change (call-site routing)** — first release
314
+ in the v3.3.x line. Closes the consolidated **F-LOGGER-SEAM-001**
315
+ finding flagged by all 8 audit agents at 9 distinct source sites
316
+ (highest-redundancy finding in the entire 2026-05-05 audit). Two
317
+ of the nine sites were already removed by v3.2.2's deletion of
318
+ `executeAddLiquidityMultiStepComplete`; v3.3.0 closes the remaining
319
+ seven by extending the `Logger` interface from `{warn, error}` to
320
+ `{warn, error, info}` and routing every surviving raw `console.*`
321
+ call in `src/` through the seam (or deleting debug-leak
322
+ instrumentation that had no operational value). Post-v3.3.0
323
+ invariant: **zero raw `console.*` call sites in `src/`** outside
324
+ the seam's own default-logger implementation, verified by a new
325
+ regression-lock test that scans the entire src/ tree on every run.
326
+ Backwards-compat: v3.2.x consumers wiring
327
+ `setLogger({warn, error})` continue to work — the setter synthesises
328
+ an `info` wrapper that falls through to `console.info` for the new
329
+ channel; consumers that want full control pass
330
+ `setLogger({warn, error, info})`. **622/622 tests pass.**
331
+
332
+ **`3.2.3`** — **MINOR, behaviour change** — fourth
333
+ and final wave of the v3.2.x audit-cycle close-out track. Four
334
+ targeted bug fixes closing the highest-user-impact remaining
335
+ findings: **F-BUG-002** (added `creationTime: safeCreationTime()`
336
+ to `buildCrossChainTransfer` setMeta block — the lone interactions
337
+ builder that omitted the helper after v2.3.0's sweep, causing
338
+ sporadic chain-side rejections under client clock drift); **F-BUG-004**
339
+ (rewrote `fetchSpvProof` to wrap in `withFailover` + add
340
+ `AbortSignal.timeout(30s)` per-attempt deadline — pre-v3.2.3 a
341
+ wedged primary node would hang the function indefinitely with the
342
+ user's KDA committed to `kadena-xchain-gas` escrow and no recovery
343
+ path, identified as the highest-impact bug in the entire audit);
344
+ **F-SEC-002** (added URL parse + `https:` scheme allow-list to
345
+ `setNodeConfig("custom", customUrl)` — pre-v3.2.3 it accepted any
346
+ truthy string and assigned it to `PRIMARY_HOST`, allowing an
347
+ attacker-controlled custom-node setting to redirect every signed
348
+ transaction); and **F-ERR-001** (added `@throws` JSDoc to
349
+ `submitCrossChainTransfer`, `submitContinuation`, and
350
+ `listenForCompletion`, documenting the
351
+ TIMEOUT-as-pending-not-failed contract that prevents user
352
+ double-pay on `listen` timeouts). With these four findings closed,
353
+ the v3.2.x sequence has remediated **15 of the audit's 62
354
+ confirmed findings** across four ship cycles. **618/618 tests pass**
355
+ (was 601 in v3.2.2; +17 new it-blocks). Next: v3.3.x for
356
+ logger-seam completion + test coverage; v4.0.0 for structural
357
+ decomposition + monorepo split + type consolidation.
358
+
359
+ **`3.2.2`** — **MINOR, public API removal** —
360
+ third wave of the v3.2.x audit-cycle close-out track. Removes the
361
+ four `executeAddLiquidityMultiStep*` functions plus the
362
+ `MultiStepAddLiquidityResult` type from
363
+ `src/interactions/addLiquidityFunctions.ts`, along with the
364
+ unused `_strategy` parameter on `executeAddLiquidity`. Closes audit
365
+ findings **F-ERR-005** (`error.message.includes` retry-loop crash on
366
+ non-Error throws), **F-ERR-014** (listen-timeout vs submit-failure
367
+ conflation causing user double-pay risk), **F-PERF-014** (4×
368
+ hardcoded 3-second sleeps adding ~6s wall-clock latency to every
369
+ successful flow), **F-PERF-015** (retry-with-fixed-sleep against
370
+ string-matched `error.message.includes("Cannot find module")`
371
+ patterns), and **F-API-026** (the always-`"auto"` `_strategy`
372
+ parameter on `executeAddLiquidity` was dead public surface). All
373
+ five findings closed **by removal** rather than fix — the
374
+ multi-step pipeline existed because the historical Kadena chainweb
375
+ gas limit (150k per block) couldn't fit a single-block
376
+ add-liquidity transaction; StoaChain's 2M-per-block chainweb fits
377
+ the entire flow in one transaction, so multi-step has been dead
378
+ code in OuronetUI since the gas-limit increase. Net code change:
379
+ **−338 lines** (1031 → 693 lines in `addLiquidityFunctions.ts`).
380
+ **601/601 tests pass** unchanged; no test exercised the removed
381
+ functions, which was itself a v3.2.x audit signal that the surface
382
+ was unused. The Pact-side multi-step contract
383
+ (`TS01-CP.SWP|C_AddStandardLiquidity` defpact) is still on chain
384
+ for historical interoperability — this package just stops exposing
385
+ the TypeScript wrappers around it. Strict-semver-wise this is a
386
+ breaking change requiring a MAJOR bump; classified MINOR for v3.2.2
387
+ because the removed functions had no known consumer (verified via
388
+ repo-wide grep + user confirmation that OuronetUI no longer uses
389
+ multi-step). v3.2.3 will land the targeted bug fixes
390
+ (`creationTime`, `fetchSpvProof` failover, `setNodeConfig` URL
391
+ validation).
392
+
393
+ **`3.2.1`** — **MINOR, behaviour change** —
394
+ second wave of the v3.2.x audit-cycle close-out track. Puts the
395
+ v3.2.0 number-hygiene helpers (`formatDecimalForPact`,
396
+ `formatIntegerForPact`, `ValidatedDecimal` / `ValidatedInteger`
397
+ brand types) to work at the four chain-call sites the 2026-05-05
398
+ audit flagged: `buildCrossChainTransfer` (`crossChainFunctions:92`),
399
+ `executeNativeUrStoaTransfer` (`urStoaFunctions:206`),
400
+ `executeStakeUrStoa` (`urStoaFunctions:441`), and
401
+ `executeUnstakeUrStoa` (`urStoaFunctions:497`). Closes audit
402
+ findings **F-SEC-001** (Pact-code injection via raw `${amount}`
403
+ interpolation in urStoa stake/unstake) and **F-BUG-003**
404
+ (`parseFloat(amount).toFixed(N)` silent precision loss + silent
405
+ rounding). All four sites now route through the validated
406
+ formatter: malformed input throws synchronously before any chain
407
+ interaction begins; arbitrary-precision decimals (e.g., 39-digit
408
+ integer amounts that would overflow float64) round-trip
409
+ byte-identical; EU-locale comma input (`"1,5"`) is normalised to
410
+ period; and the urStoa stake/unstake cap-arg now reuses the
411
+ validated string so pact-code and cap-arg are guaranteed to agree.
412
+ The `numAmount` field on `StakeUrStoaParams` / `UnstakeUrStoaParams`
413
+ is deprecated (still accepted, no longer read; will be removed in
414
+ v4.0.0). **601/601 tests pass.** v3.2.2 will remove the dead
415
+ multi-step add-liquidity surface; v3.2.3 will land the targeted
416
+ bug fixes (`creationTime`, `fetchSpvProof` failover,
417
+ `setNodeConfig` URL validation).
418
+
419
+ **`3.2.0`** — **MINOR, additive** release that opened
420
+ the v3.2.x audit-cycle close-out track with number-hygiene
421
+ infrastructure for Pact-bound integers and decimals.
422
+ `formatDecimalForPact` now accepts a single comma as decimal
423
+ separator (so European-locale UI text fields work without upstream
424
+ normalisation); a new sibling `formatIntegerForPact(amount: string):
425
+ ValidatedInteger` validates integer-typed Pact arguments without ever
426
+ round-tripping through float64 (arbitrary-precision-safe — a
427
+ 100-digit integer string passes through byte-identical); two new
428
+ branded TypeScript types (`ValidatedDecimal`, `ValidatedInteger`)
429
+ prove "this string passed the formatter" at the type level so
430
+ downstream call sites get compile-time guarantees that consumer
431
+ input has been validated before it reaches Pact-code interpolation.
432
+ **No consumer-visible behaviour changes** — every previously-valid
433
+ input continues to produce byte-identical output. **593/593 tests
434
+ pass** (was 565 in v3.1.1; +28 covering comma-normalisation,
435
+ arbitrary-precision round-trips with the explicit
436
+ truncation-at-maxDecimals lock, the new integer formatter, and the
437
+ brand-type compile contract). v3.2.1 will apply the new helpers at
438
+ the existing `parseFloat(...).toFixed(N)` call sites to close the
439
+ F-SEC-001 / F-BUG-003 precision-loss vectors; v3.2.2 will remove
440
+ the dead multi-step add-liquidity surface (chainweb's gas bump made
441
+ it obsolete); v3.2.3 will land the targeted bug fixes
442
+ (`creationTime`, `fetchSpvProof` failover, `setNodeConfig` URL
443
+ validation).
444
+
445
+ **`3.1.1`** — **PATCH, additive** release that closed the
446
+ audit-cycle gaps identified by the post-v3.1.0-integration audit
447
+ (see [`CHANGELOG.md`](CHANGELOG.md) v3.1.1 entry for the full
448
+ per-finding trace). Three additive re-exports completed the
449
+ `./dalos` integration surface (`InvalidBitStringError`,
450
+ `InvalidBitmapError`, `InvalidPrivateKeyError` for typed
451
+ validation-failure discrimination + `CoordAffine` companion type
452
+ for `SchnorrSignature`); the `src/dalos/` subdirectory was
453
+ realigned with CONVENTIONS.md (double-quoted imports, no `.js`
454
+ extensions); the v3.1.0 locale-determinism test assertion in
455
+ `tests/gas.test.ts` was tightened to strict equality (was a
456
+ substring regex that wouldn't detect a regression on a US-locale
457
+ CI host); a fresh `tests/dalos-integration.test.ts` block covered
458
+ the v3.1.0 Schnorr re-exports end-to-end. No runtime change for
459
+ any v3.1.0 consumer; v3.1.0 itself was committed locally
460
+ (`bf10dc1`) but never pushed to npm — the npm registry skips from
461
+ `3.0.0` to `3.1.1`.
462
+
463
+ **`3.1.0`** (committed locally `bf10dc1`, never published) — **MINOR,
464
+ additive** release that upgrades `@ouronet/dalos-crypto` from
465
+ `^1.2.0` to `^4.0.3` (covering
466
+ the v2.x/v3.x/v4.x line of the upstream package — Schnorr v2 wire
467
+ format, cofactor subgroup-membership hardening, generator-precompute
468
+ matrix cache, async signing surfaces, the v4.0.0 Elliptic-package
469
+ carve-out on the Go side, and the v4.0.3 LOW-band closures), exposes
470
+ the previously-internal **Schnorr signature surface** through the
471
+ `./dalos` subpath (`schnorrSign` / `schnorrVerify` and the browser-
472
+ friendly `schnorrSignAsync` / `schnorrVerifyAsync` async variants
473
+ that yield to the event loop on a fixed cadence; plus the typed
474
+ `SchnorrSignError` exception and the `SchnorrSignature` shape type),
475
+ and ships a small locale-determinism fix in `formatMaxFee` so the
476
+ ANU thousands separator is `,` on every host (was host-locale-
477
+ dependent — silently passed CI on en-US Linux while failing locally
478
+ on a German-locale host). **558/558 tests pass.** No public surface
479
+ from prior versions changes shape; all additions are opt-in. Per
480
+ the upstream v4.0.0 changelog: TypeScript consumers see no breaking
481
+ surface changes across the dalos-crypto v1.2.0 → v4.0.3 jump (the
482
+ v4.0.0 major bump was driven entirely by a Go-reference
483
+ reorganisation that doesn't affect TS consumers). See
484
+ [`CHANGELOG.md`](CHANGELOG.md) for the full v3.1.0 entry.
485
+
486
+ **`3.0.0`** — **BREAKING** major release closing M3 from the
487
+ 2026-04-30 audit cycle (F-CORE-007 fabricated-fallback removal +
488
+ comprehensive HIGH-risk catalog sweep). This was the FIRST major
489
+ bump since **v2.0.0** (2026-05-01) — downstream consumers
490
+ (OuronetUI, AncientHolder HUB) MUST update call sites to handle
491
+ `null` returns. **16 fabricated-fallback widenings** land across 4
492
+ interaction files: 15 functions widen from `Promise<T>` to
493
+ `Promise<T | null>` so that consumers see RPC failures instead of
494
+ fabricated chain values (`1.0` USD prices, `"0"` balances, sentinel
495
+ `"N/A"` strings, fake `false` existence flags), plus 1 mixed-shape
496
+ addition for `validateLiquidity` (preserves `valid: boolean` while
497
+ adding optional `error?: string` to distinguish RPC failure from
498
+ validation rejection). In lockstep, **14 NON-BREAKING logger-routing
499
+ additions** across 5 files complete the silent-catch-elimination
500
+ sweep started in v2.3.0 — every previously-silent diagnostic catch
501
+ in `src/interactions/*` now routes through the
502
+ `@ouronet/ouronet-core/observability` `getLogger().error()` seam.
503
+ NO public-API removals (NFR-03): all 16 modified functions retain
504
+ their names and parameter signatures; only return types widen. See
505
+ [`CHANGELOG.md`](CHANGELOG.md) for the full v3.0.0 entry, and the
506
+ **Migrating to v3.x** H2 section below for per-cluster `Before:` /
507
+ `After:` migration patterns (Option B null-pattern locked decision
508
+ per Q3..Q11 of the requirements). The optional **What's new in
509
+ v3.0.0** section ships a copy-paste example for adapting to nullable
510
+ returns.
511
+
512
+ Every piece of blockchain logic that used to live in OuronetUI has
513
+ landed here: Pact builders, signing pipeline (CodexSigningStrategy +
514
+ universalSignTransaction), encryption (V1 + V2 + smartDecrypt), guard
515
+ analysis, gas calibration, codex codec, seed-type migration. OuronetUI
516
+ is now a pure consumer.
517
+
518
+ As of the current **v3.1.0** shipping line (originally introduced in
519
+ **v1.3.0**, dep range bumped to `^4.0.3` in v3.1.0), OuronetCore
520
+ integrates
521
+ **[`@ouronet/dalos-crypto@^4.0.3`](https://www.npmjs.com/package/@ouronet/dalos-crypto)**
522
+ via the `./dalos` subpath — consumers mint Ouronet accounts locally
523
+ (all six DALOS input modes: random, bitmap, bitstring, base-10,
524
+ base-49, seed words) without touching the retired
525
+ `go.ouronetwork.io/api/generate` endpoint. As of v3.1.0 the `./dalos`
526
+ subpath also re-exports the lower-level **Schnorr signature surface**
527
+ (`schnorrSign`, `schnorrVerify`, plus browser-friendly
528
+ `schnorrSignAsync` / `schnorrVerifyAsync` variants, the typed
529
+ `SchnorrSignError` exception, and the `SchnorrSignature` shape type)
530
+ for advanced consumers who need direct access without going through
531
+ `primitive.sign(...)`.
532
+
533
+ The per-version paragraphs below are compact deltas; for the full
534
+ authoritative per-version detail (Added / Changed / Fixed sections,
535
+ finding closures, file-level citations) see
536
+ [`CHANGELOG.md`](CHANGELOG.md). The README mirrors the headline only
537
+ and points readers at the changelog for the rest.
538
+
539
+ **v1.4.0** — `AccountSelectorData` now includes `public-key`,
540
+ `sovereign`, and `governor` for Smart Ouronet Account display (Σ.
541
+ prefix accounts with sovereign + governor authorisation paths).
542
+
543
+ **v1.5.0** — re-exports `Leto` / `Artemis` / `Apollo` historical-curve
544
+ primitives + `createGen1Primitive` factory through the `./dalos`
545
+ subpath. NOT registered in `createDefaultRegistry()` — Ouronet stays
546
+ Genesis-only; consumers opt in.
547
+
548
+ **v1.6.0** — Smart Ouronet Account auth-path primitives. `/guard`
549
+ gains `classifyGuardKind`, `extractKeysetFromGuard`,
550
+ `analyzeSmartAccountAuthPaths` to discriminate the four guard shapes
551
+ and resolve the `enforce-one` over (account guard / sovereign /
552
+ governor). `buildRotateSovereignPactCode` is the first CFM function
553
+ targeting a Smart account's auth path.
554
+
555
+ **v1.6.1** — every internal `interactions/*` helper now honors the
556
+ active failover node (no more `createClient(PACT_URL)` pinned to
557
+ node2).
558
+
559
+ **v1.7.0** — `IKadenaKeypair` consolidated to a single canonical
560
+ declaration in `src/signing/types.ts`. The duplicate copies that lived
561
+ across `interactions/*` are replaced with `import type` re-exports.
562
+ Closes audit finding F-CORE-001 (CRITICAL).
563
+
564
+ **v2.0.0** — wallet subpath layering restored + `pactRead` injection
565
+ seam fully adopted. Closes F-CORE-005 + F-CORE-006 (HIGH). **Two
566
+ breaking changes** for consumers — see migration guide below.
567
+
568
+ **v2.0.1** — documentation/release-process patch. Adds `CHANGELOG.md`
569
+ to the npm tarball, auto-creates GitHub Releases on tag push, and
570
+ backfills Releases for v1.7.0 and v2.0.0. No runtime change.
571
+
572
+ **v2.0.2 / v2.0.3 / v2.0.4** — release-pipeline hardening patches. No
573
+ runtime change. v2.0.2 added `permissions: contents: write` to
574
+ `publish.yml` for the GitHub Releases step. v2.0.3 introduced a
575
+ `RELEASE_TOKEN` PAT fallback expression to bypass org-locked
576
+ `GITHUB_TOKEN` write permissions. v2.0.4 triggered the workflow with
577
+ the secret installed.
578
+
579
+ **v2.1.0** — reliability hardening release. New `getFailoverClient(chainId, options?)`
580
+ factory composes `withFailover` + per-tier timeout into one reusable
581
+ surface; all 81 legacy `createClient(getPactUrl(chainId))` invocations
582
+ across the 11 interaction files now route through it (primary node
583
+ failure on any chain call now triggers automatic fallback retry).
584
+ Bounded timeouts on every chain-call tier (read 15s, submit 60s,
585
+ listen 180s, pollOne 30s) with `Promise.race` + `AbortController`
586
+ defence-in-depth. New `runWithTimeout(operation, fn, timeoutMs)`
587
+ helper, new `createTimeoutError(...)` factory returning a
588
+ `SigningError { code: "TIMEOUT" }`, new `resetNodeFailover()` export
589
+ for test isolation, new `readTimeoutMs?: number` option on
590
+ `PactReader` and `rawCalibratedDirtyRead`. MINOR, non-breaking —
591
+ existing imports continue to work; the new surface is opt-in.
592
+
593
+ **v2.1.2** — concurrency-race correction in `withFailover`. PATCH, no
594
+ public API change. The retry guard now uses per-invocation captured
595
+ base URLs (`attemptedBaseUrl` AND `attemptedPrimaryBaseUrl` captured
596
+ at fn-entry as local consts) instead of reading the shared
597
+ module-level `currentHost === PRIMARY_HOST` at catch-time. This makes
598
+ the catch-block decision robust to concurrent module-state mutation
599
+ (sibling `withFailover` flip, mid-flight `setNodeConfig`, mid-flight
600
+ `resetNodeFailover`). Closes F-BUG-001. New module-private
601
+ `getPrimaryBaseUrl()` helper added to `src/network/nodeFailover.ts`;
602
+ not exported.
603
+
604
+ **v2.2.0** — crypto error-taxonomy + test-coverage hardening release.
605
+ MINOR, additive. The `./crypto` subpath gains three typed error
606
+ classes — `WrongPasswordError`, `CorruptEnvelopeError`,
607
+ `UnsupportedFormatError` — that discriminate decryption failure modes
608
+ (closes F-CORE-009). `smartDecrypt` switches to single-path dispatch
609
+ via the existing `isEncryptedV2` shape predicate, eliminating the
610
+ ~1.5s wall-time differential a wrong-password V1 input previously
611
+ exhibited (timing-leak fix); the V1 catch path no longer logs to
612
+ `console.error` and propagates the original failure via ES2022
613
+ `Error.cause`. Existing `instanceof Error` checks and `error.message`
614
+ access continue to work — the new typed-class discrimination is
615
+ opt-in. Test coverage expands across 4 previously-untested critical
616
+ surfaces (closes F-CORE-011, F-CORE-012): four new test files cover
617
+ the `pactReader` injection seam (`tests/pact-reader.test.ts`),
618
+ `KadenaWalletBuilder` mnemonic dispatch with vendor-vector pinning for
619
+ all three seed types (`tests/wallet-builder.test.ts`), every
620
+ documented branch of `createSigningError` + `createSimulationError`
621
+ (`tests/transaction-errors.test.ts`), and the codex seed-type
622
+ migration round-trip (`tests/seed-type-migration.test.ts`). Five
623
+ existing test files gain extensions: `tests/encryption.test.ts`,
624
+ `tests/encryption-upgrade.test.ts`, `tests/codex-codec.test.ts`,
625
+ `tests/cfm-builders.test.ts`, `tests/pact-format.test.ts`. F-CORE-010
626
+ (a proposed `pactString` charset/blocklist helper) was reviewed and
627
+ explicitly **rejected** — chain-side Pact validation already enforces
628
+ identifier rules, so a client-side blocklist would duplicate
629
+ authoritative server-side checks and risk silent drift if Pact's
630
+ grammar evolves. The decision is logged in `CHANGELOG.md` under a
631
+ `### Rejected (decisions log)` section.
632
+
633
+ **v2.3.0** — medium-and-low audit closures release. MINOR, additive.
634
+ Closes 13 audit findings grouped into two milestones: **M1 — 7
635
+ MEDIUM tier** (F-CORE-013 codex shape validation; F-CORE-014
636
+ foreign-key resolver pre-flight in `CodexSigningStrategy`; F-CORE-015
637
+ `safeCreationTime` DRY refactor — 11 inline copies removed across
638
+ `src/interactions/*Functions.ts`, all routed through the canonical
639
+ declaration in `src/pact/format.ts`; F-CORE-016a tightened
640
+ `classifyGuardKind` requiring full minimal shape per kind; F-CORE-016b
641
+ new `normalizeKeysetRef` helper at the `resolveGuard` boundary;
642
+ F-CORE-016c `SmartAccountAuthPathsAnalysis` JSDoc enumerating 4
643
+ reachable states + optional `firstSignableButUnsatisfied` field;
644
+ F-CORE-017 typed `UnknownPredicateError` class re-exported from
645
+ `./guard` plus `predicateRecognized: false` bit on `analyzeGuard`'s
646
+ returned analysis, replacing the previous silent `console.warn`
647
+ diagnostic) and **M2 — 6 LOW tier** (F-CORE-018a README header
648
+ version table refresh; F-CORE-018b CONTEXT.md interactions section
649
+ refresh covering v1.4 / v1.5 / v1.6 additions; F-CORE-019 catch-block
650
+ consistency in `ouroFunctions.ts` — all 7 affected catch sites now
651
+ route via `getLogger().error(...)` from `../observability`; F-CORE-020
652
+ tier-semantics JSDoc on `pactReader.ts` and `rawCalibratedRead.ts`
653
+ enumerating the canonical T1=balance / T2=preview / T3=metadata /
654
+ T7=very-static mapping; F-CORE-021 dead try/catch wrapping
655
+ `getLPTypeInfo`'s `Promise.all` removed (Option A — the
656
+ "comment as belt-and-braces" alternative was explicitly rejected);
657
+ F-CORE-022 central logger seam at `./observability` with two-file
658
+ source layout `src/observability/{index.ts,logger.ts}`, `Logger` type
659
+ + `setLogger` (throws `TypeError("setLogger requires a non-null
660
+ Logger")` on null/undefined input) + `getLogger` exports, and a
661
+ sweep that reroutes every `console.warn` / `console.error` in `src/`
662
+ through the seam — verified by `grep -nE "console\.(warn|error)"
663
+ src/` returning ZERO matches outside the seam itself). Two new
664
+ public surfaces ship in lockstep: `UnknownPredicateError` on
665
+ `./guard` and the `./observability` subpath. All changes additive;
666
+ no existing exports change shape.
667
+
668
+ **v3.0.0** — fabricated-fallbacks-removal release. **BREAKING.**
669
+ Closes M3 from the 2026-04-30 audit cycle (lead finding F-CORE-007
670
+ HIGH plus the comprehensive ~24-site catalog sweep). First major
671
+ bump since v2.0.0. **Phase 1 — critical pricing functions (4
672
+ BREAKING widenings):** `getStoaPriceUSD`, `getTokenDecimals`,
673
+ `getPoolTotalFee`, `getDPTFMinMove` all widen from `Promise<number>`
674
+ to `Promise<number | null>`; the previous `1.0` / `0` / `8`
675
+ fabrication sentinels are replaced with `null`, and
676
+ `Number.isFinite()` guards catch `NaN` from malformed chain data
677
+ (e.g. `parseInt("abc", 10)` or `parseFloat(String(undefined))`).
678
+ **Phase 2 — catalog sweep + bonus extras + magic-strings (12
679
+ BREAKING widenings):** the 4-function string-balance cluster
680
+ (`getIgnisBalance`, `getAccountTokenSupply`, `getOuroDispoCapacity`,
681
+ `getVirtualOuro`) widens uniformly to `Promise<string | null>`;
682
+ `LPTypeInfo` field types widen to `boolean | null` per inner flag
683
+ (Approach A — function return type unchanged; chain-failure-status
684
+ returns `false`, catch returns `null`, success returns `true`); the
685
+ urStoa trio (`getUrStoaBalance`, `getUrStoaGuard`,
686
+ `checkCoinAccountExists`) widens to nullable returns and
687
+ `getUrStoaGuard` drops its sentinel `empty` shape; `validateLiquidity`
688
+ gains an optional `error?: string` field on its mixed shape (preserves
689
+ `valid: boolean` — consumers route a populated `error` to the
690
+ network-failure banner and a `valid: false` with no `error` to the
691
+ validation-failure message); `getMaxBuyMovieBooster` widens to
692
+ `Promise<number | null>`; magic-string sentinels disappear from
693
+ `getSWPSpawnLimit` and `getSWPInactiveLimit` (now `Promise<string |
694
+ null>` — consumers swap `=== "N/A"` for `=== null`). **Phase 3 —
695
+ logger parity (14 NON-BREAKING):** `getLogger().error("Error in
696
+ <funcName>:", error)` routing lands in 14 previously-silent catches
697
+ across 5 files (`dexFunctions.ts`, `ouroFunctions.ts`,
698
+ `activateFunctions.ts`, `infoOneFunctions.ts`, and the
699
+ `urStoaFunctions.ts` private helpers `verifyEd25519Sig` +
700
+ `describeKeyset`) — completes the silent-catch elimination sweep
701
+ started in v2.3.0. NO public-API removals (NFR-03): all 16 modified
702
+ functions keep their names + parameter signatures; only return types
703
+ widen. See the new **Migrating to v3.x** H2 section below for
704
+ per-cluster `Before:` / `After:` migration patterns and the locked
705
+ Option B / Approach A / mixed-shape / 3-state-preservation /
706
+ magic-string-removal decisions (Q3..Q11) embedded verbatim.
707
+
708
+ **v3.1.0** — dalos-crypto v4.0.3 integration + Schnorr surface
709
+ re-exports + locale-determinism fix. **MINOR, additive.** Bumps the
710
+ `@ouronet/dalos-crypto` dep from `^1.2.0` to `^4.0.3` (per the
711
+ upstream v4.0.0 changelog: TypeScript consumers see no breaking
712
+ surface changes across the v1.2.0 → v4.0.3 jump — the v4.0.0 major
713
+ bump was driven entirely by a Go-reference reorganisation, not the
714
+ TS port). The `./dalos` subpath gains direct re-exports of the
715
+ **Schnorr signature surface** for advanced consumers:
716
+ `schnorrSign` / `schnorrVerify` for synchronous use; the
717
+ browser-friendly `schnorrSignAsync` / `schnorrVerifyAsync` async
718
+ variants that yield to the event loop on a fixed data-independent
719
+ cadence (the upstream package's REQ-14 yield-count constant-time
720
+ test verifies the cadence is data-independent and constant-time);
721
+ the typed `SchnorrSignError` exception class for `instanceof` catch
722
+ blocks; and the `SchnorrSignature` shape type for parameter typing.
723
+ The high-level `primitive.sign(keyPair, message)` path through the
724
+ registry is unchanged (it has always been Schnorr internally for
725
+ DalosGenesis); the new direct-access surface is opt-in and exists
726
+ mainly so OuronetUI's browser path can use the `*Async` variants to
727
+ keep INP under the 200 ms budget during signing. Also fixes
728
+ `formatMaxFee` in `./gas` to pin its `toLocaleString()` call to
729
+ `'en-US'` so the ANU thousands separator is `,` on every host (was
730
+ host-locale-dependent — silently passed CI on en-US Linux while
731
+ failing locally on a German-locale host); the test suite was already
732
+ pinning the en-US shape, so this restores cross-host parity. NO
733
+ public-API removals or shape changes; all changes additive. See the
734
+ v3.1.0 **CHANGELOG.md** entry for the full per-symbol export list,
735
+ the audit-trail of the 18 dalos-crypto symbols verified
736
+ shape-compatible at upgrade time, and the verification-gate results
737
+ (typecheck + 558/558 tests + build all green).
738
+
739
+ **v3.1.1** — pre-publish audit-cycle close-out for the v3.1.0
740
+ dalos-crypto integration. **PATCH, additive.** Closes 5 audit
741
+ findings the post-v3.1.0-integration audit (2026-05-05) flagged
742
+ against commit `bf10dc1` before that commit reached npm: 3 typed
743
+ validation-error class re-exports added to `./dalos`
744
+ (`InvalidBitStringError`, `InvalidBitmapError`,
745
+ `InvalidPrivateKeyError` — close F-BUG-005 by completing the
746
+ `instanceof`-discrimination surface); 1 type-only re-export added
747
+ (`CoordAffine` — closes F-API-024 by restoring the "single
748
+ integration surface" promise for `SchnorrSignature.r`); 1
749
+ stylistic alignment (`src/dalos/{index,account}.ts` converted
750
+ from single quotes + `.js` extensions to the codebase's standard
751
+ double quotes + bare relative imports — closes F-ARCH-012); 1
752
+ test-strictness fix (`tests/gas.test.ts` `formatMaxFee` assertion
753
+ tightened from `toMatch(/10,000,000/)` substring regex to strict
754
+ `toBe("10,000,000")` — closes F-TEST-001 so the v3.1.0
755
+ locale-determinism contract is actually locked); and 1 fresh
756
+ test block (`tests/dalos-integration.test.ts` gains coverage for
757
+ the v3.1.0 Schnorr re-exports — closes F-TEST-004 with 5
758
+ new it-blocks covering sign/verify round-trip, async variants,
759
+ `SchnorrSignError` class identity, and `SchnorrSignature` /
760
+ `CoordAffine` type-import compile probes). v3.1.0 was committed
761
+ locally (`bf10dc1`) but never pushed to npm, so the npm registry
762
+ goes from `3.0.0` straight to `3.1.1` with v3.1.0 visible only in
763
+ the GitHub commit history. **565/565 tests pass** (was 558 in
764
+ v3.1.0; +7 = 1 new strict locale grouping-style sibling
765
+ assertion + 5 new Schnorr re-export it-blocks + 1 new
766
+ validation-error class probe).
767
+
768
+ **v3.2.0** — number-hygiene infrastructure for the v3.2.x
769
+ audit-cycle close-out track. **MINOR, additive.** First wave of the
770
+ v3.2.x sequence (v3.2.0 = infrastructure / v3.2.1 = apply at call
771
+ sites / v3.2.2 = delete dead multi-step add liquidity / v3.2.3 =
772
+ targeted bug fixes). v3.2.0 lands three additive surfaces in the
773
+ `./pact` subpath: (1) `formatDecimalForPact` now accepts a single
774
+ comma as decimal separator and normalises it to a period before
775
+ validation, so European-locale UI inputs (`"1,5"`, `"0,9"`,
776
+ `"1234,567890"`) work without upstream normalisation; multi-comma
777
+ strings (`"1,234,567"` thousand-separator-style) and mixed
778
+ period+comma strings (`"1,5.6"`, `"1.234,56"`) still throw because
779
+ they are ambiguous. (2) New `formatIntegerForPact(amount: string):
780
+ ValidatedInteger` sibling helper for integer-typed Pact arguments
781
+ — Pact distinguishes integers from decimals at the lexer level
782
+ (`integer` cap-args reject `1.0`, accept `1`); the new helper
783
+ validates `^\d+$` and returns the trimmed input verbatim with no
784
+ float round-trip, so 100-digit integer strings round-trip
785
+ byte-identical (versus `Number(big)` which collapses past
786
+ `Number.MAX_SAFE_INTEGER` ≈ `9.0e15`). (3) Two new branded
787
+ TypeScript types `ValidatedDecimal` and `ValidatedInteger` (zero
788
+ runtime cost — just `unique symbol` brands on `string`) flow out
789
+ of the formatters; functions declared `(amount: ValidatedDecimal)
790
+ => Transaction` cannot accidentally accept raw user input, and the
791
+ two brands are distinct types so the lexer-level int-vs-decimal
792
+ distinction is enforced at the function-boundary level. The
793
+ file-level JSDoc in `src/pact/format.ts` now spells out the
794
+ three-rule number-hygiene contract: strings in, strings out, never
795
+ round-trip through float64. NO consumer-visible behaviour change
796
+ — every previously-valid input produces byte-identical output;
797
+ the new surface is opt-in. v3.2.1 will adopt the new helpers at
798
+ the existing `parseFloat(...).toFixed(N)` and raw `${amount}`
799
+ interpolation sites to close the F-SEC-001 / F-BUG-003
800
+ precision-loss vectors that the 2026-05-05 audit flagged.
801
+
802
+ **v3.2.1** — applies the v3.2.0 number-hygiene helpers at the four
803
+ chain-call sites flagged by the 2026-05-05 audit. **MINOR,
804
+ behaviour change.** Closes **F-SEC-001** (Pact-code injection vector
805
+ in urStoa stake/unstake's raw `${amount}` interpolation) and
806
+ **F-BUG-003** (`parseFloat(amount).toFixed(N)` silent precision loss
807
+ in `buildCrossChainTransfer:92` and `executeNativeUrStoaTransfer:206`,
808
+ plus silent rounding `1.9999 → 2.000` in the urStoa transfer path).
809
+ All four sites now route through `formatDecimalForPact(amount)`:
810
+ malformed input throws synchronously before any chain interaction
811
+ begins (counting-stub `PactReader` test proves the reader is never
812
+ invoked when the amount is malformed — validation is at the function
813
+ boundary, not deeper); arbitrary-precision decimals round-trip
814
+ byte-identical (39-digit integer amounts and 18-digit-fractional
815
+ decimals that pre-v3.2.1's float-based formatters would have
816
+ truncated or scientific-notation-mangled now reach the chain
817
+ intact); EU-locale comma input is auto-normalised to period (per
818
+ v3.2.0's relaxed input contract); and the urStoa stake/unstake
819
+ cap-args now reuse the **same** validated string as the pact-code
820
+ interpolation, so the `coin.URV|STAKE` / `coin.URV|UNSTAKE` cap-arg
821
+ and the executed `coin.C_URV|Stake` / `coin.C_URV|Unstake` decimal
822
+ literal are guaranteed to agree (was `String(numAmount)` separately
823
+ which had the float-precision drift). The `numAmount: number` field
824
+ on `StakeUrStoaParams` and `UnstakeUrStoaParams` is **deprecated** in
825
+ v3.2.1 (still accepted on the interfaces for v3.x backwards
826
+ compatibility, no longer read by the executors; will be removed in
827
+ v4.0.0). 8 new it-blocks in `tests/interactions-decimal-validation.test.ts`
828
+ pin the contract: synchronous throw on malformed input, pact-code
829
+ contains comma-normalised value, high-precision and 39-digit-int
830
+ amounts preserved past pre-v3.2.1's truncation point, reader-stub
831
+ proves fail-fast at function entry. NO consumer-side migration
832
+ required for callers passing well-formed decimal strings; consumers
833
+ that previously relied on silent `"NaN"` interpolation or
834
+ silent-rounding need to wrap calls in try/catch (the throw is the
835
+ audit-mandated improvement).
836
+
837
+ **v3.2.2** — removes the dead multi-step add-liquidity surface from
838
+ `src/interactions/addLiquidityFunctions.ts`. **MINOR, public API
839
+ removal.** Closes **F-ERR-005**, **F-ERR-014**, **F-PERF-014**,
840
+ **F-PERF-015**, and **F-API-026** — five audit findings
841
+ simultaneously, all by removal rather than fix. The historical
842
+ multi-step pipeline existed because Kadena chainweb's 150k-per-block
843
+ gas limit couldn't fit a single-block add-liquidity transaction;
844
+ StoaChain runs at 2M gas per block (13×), which fits the entire
845
+ flow in one transaction. OuronetUI hasn't called the multi-step
846
+ path since the gas-limit increase, and no test in this package's
847
+ suite exercised it — both signals that the four exported
848
+ `executeAddLiquidityMultiStep*` functions plus their
849
+ `MultiStepAddLiquidityResult` return type plus the unused
850
+ `_strategy` parameter on `executeAddLiquidity` were dead public
851
+ surface carrying real correctness risk (F-ERR-005's
852
+ `.includes(...)` crash on non-Error throws; F-ERR-014's
853
+ listen-timeout-vs-submit-failure conflation that could cause user
854
+ double-pay; F-PERF-014's 4× hardcoded 3-second sleeps adding ~6s
855
+ to every successful flow; F-PERF-015's retry loops against
856
+ string-matched `error.message`). Net code change: **−338 lines**
857
+ (1031 → 693 in `addLiquidityFunctions.ts`). The Pact-side defpact
858
+ contract (`TS01-CP.SWP|C_AddStandardLiquidity` with continuation
859
+ steps) is still on chain for historical interoperability;
860
+ consumers with unusual need can still invoke it via
861
+ `@kadena/client`'s low-level `Pact.builder.continuation()` API.
862
+ Migration: callers of `executeAddLiquidityMultiStep*` should
863
+ switch to `executeAddLiquidity(params)`, same `AddLiquidityParams`
864
+ shape, single-step path. Callers passing `_strategy` to
865
+ `executeAddLiquidity` should drop the second argument (the
866
+ function's behaviour is identical — it always called the
867
+ single-step path anyway). Strict-semver-wise the removal is
868
+ breaking and would justify a MAJOR bump; classified MINOR for
869
+ v3.2.2 because the removed surface had no known consumer
870
+ (verified via repo-wide grep + user confirmation).
871
+
872
+ **v3.2.3** — final wave of the v3.2.x audit-cycle close-out track.
873
+ **MINOR, behaviour change.** Four targeted bug fixes closing the
874
+ highest-user-impact remaining findings: **F-BUG-002** added
875
+ `creationTime: safeCreationTime()` to `buildCrossChainTransfer`
876
+ setMeta (the lone interactions/* builder that omitted the helper
877
+ post v2.3.0's DRY sweep, causing sporadic chain-side rejections
878
+ under client-clock drift); **F-BUG-004** rewrote `fetchSpvProof` to
879
+ wrap in `withFailover` + 30-second `AbortSignal.timeout()` —
880
+ pre-v3.2.3 this was the only chain-RPC function calling raw
881
+ `fetch()` without either guard, with the consequence that a wedged
882
+ primary node hung cross-chain transfers indefinitely with the
883
+ user's KDA committed to `kadena-xchain-gas` escrow on the source
884
+ chain and no recovery path (the highest-impact bug surfaced by the
885
+ 2026-05-05 audit); **F-SEC-002** added URL parse + `https:` scheme
886
+ allow-list to `setNodeConfig`'s custom-URL path — pre-v3.2.3 it
887
+ accepted any truthy string and assigned it to `PRIMARY_HOST`,
888
+ allowing an attacker-controlled custom-node setting to redirect
889
+ every signed transaction (now throws `TypeError` on missing,
890
+ unparseable, or non-https customUrl, with the parsed origin only
891
+ stored to discard pathname/query/fragment); **F-ERR-001** added
892
+ `@throws` JSDoc to the three `crossChainFunctions` submit/listen
893
+ helpers — documentation-only, no runtime change, but the
894
+ `listenForCompletion` JSDoc now explicitly calls out that a
895
+ TIMEOUT must be treated as `pending` (poll via
896
+ `pollTransactionStatus`) **not** as `failed` (do NOT retry the
897
+ submit, which would double-pay gas for a transaction that may
898
+ already be confirmed). 17 new it-blocks in
899
+ `tests/v3-2-3-bug-fixes.test.ts` cover all four fixes; 2 existing
900
+ `tests/network.test.ts` tests updated to reflect the new
901
+ `setNodeConfig` throw-on-malformed-input contract.
902
+
903
+ **v3.2.x sequence completed** — 15 audit findings closed across 4
904
+ ship cycles (v3.2.0 infrastructure / v3.2.1 apply-formatters /
905
+ v3.2.2 delete-multi-step / v3.2.3 targeted-bug-fixes). Combined
906
+ with v3.1.1's 5 audit-cycle gaps, the v3.x line has remediated
907
+ **20 audit findings** total. The remaining ~47 confirmed findings
908
+ are scheduled for v3.3.x (logger-seam completion + test coverage
909
+ + documentation cleanups) and v4.0.0 (structural decomposition +
910
+ monorepo split into `@stoachain/stoa-core` + `@ouronet/ouronet-core`
911
+ + type consolidation + `readonly` on public types + nullable
912
+ widening for the 10 swap functions).
913
+
914
+ **v3.3.0** — Logger seam completion. **MINOR, additive + behaviour
915
+ change.** First release in the v3.3.x cleanup track. Closes the
916
+ consolidated **F-LOGGER-SEAM-001** finding (9 distinct source sites
917
+ flagged by 8 of 8 audit agents — the highest-redundancy finding in
918
+ the entire 2026-05-05 audit). v3.2.2's `executeAddLiquidityMultiStepComplete`
919
+ deletion already removed 2 of the 9 sites by removal; v3.3.0 closes
920
+ the remaining 7 — `transactionErrors.ts:252-261` (3 calls in
921
+ `logDetailedError`), `nodeFailover.ts:61` (primary-recovery
922
+ announcement), `infoOneFunctions.ts:599-600` (debug-leak in remove-
923
+ liquidity preview), `ouroFunctions.ts:1590,1595` (Coil preview
924
+ failure path + success-path data dump), and `urStoaFunctions.ts:348`
925
+ (signature-pruning announcement). 4 of those 7 are routed through
926
+ the seam (`getLogger().info` for ops events, `getLogger().warn` for
927
+ unusual operational events worth structured-log capture, folded
928
+ into existing `getLogger().error` calls where grouping framing was
929
+ the only thing using `console.group`); 3 are deleted as
930
+ debug-leak (the `console.log` calls flagged by the audit as
931
+ "left-over dev instrumentation" with no operational value beyond
932
+ developer trace). The `Logger` interface gains an `info(msg,
933
+ ...args): void` channel — the missing surface that caused 4 of
934
+ the 7 seam violations (the seam previously exposed only `warn` and
935
+ `error`, so `info`-class events fell through to raw `console.info`
936
+ that bypassed consumer-supplied loggers). v3.3.0's `setLogger`
937
+ accepts BOTH the v3.2.x 2-method input shape (`{warn, error}` —
938
+ synthesised wrapper fills in `info` from default `console.info`
939
+ routing) AND the v3.3.0 3-method input shape (`{warn, error, info}`
940
+ — reference identity preserved). Backwards-compat is automatic;
941
+ v3.2.x consumers see no behaviour change unless they were emitting
942
+ to one of the seven raw-console sites that no longer exist. New
943
+ regression-lock test in `tests/v3-3-0-logger-seam-completion.test.ts`
944
+ scans the entire `src/` tree on every run and fails on any future
945
+ commit that re-introduces a raw `console.*` call (filters out
946
+ JSDoc/comments + the seam's own intentional default-logger
947
+ implementation in `observability/logger.ts`). The audit's
948
+ consolidated finding becomes a permanent invariant rather than a
949
+ one-time cleanup. NO breaking changes: every previously-valid
950
+ consumer call shape continues to work; new surface is opt-in.
951
+
952
+ **v3.3.x trajectory ahead:** test coverage completion (F-TEST-002
953
+ adding `tests/universal-sign.test.ts` for the chainweaver/
954
+ eckowallet/foreign branches; F-TEST-005 adding success-path tests
955
+ for the 13 v3.0.0 nullable-widened functions; F-TEST-006 adding
956
+ behavioural tests for `pensionFunctions`/`guardFunctions`/
957
+ `infoOneFunctions`); various documentation cleanups (deprecate
958
+ `KADENA_BASE_URL`, fix `CreateAccountOptions` JSDoc, etc.).
959
+ v4.0.0 is the major structural release (monorepo split into
960
+ `@stoachain/stoa-core` + `@ouronet/ouronet-core`, god-file
961
+ decomposition, type consolidation, `readonly` modifiers across
962
+ the public type surface).
963
+
964
+ **v4.1.1** — audit-closure patch. **PATCH (atomic with `@stoachain/stoa-core@4.1.1` + `@stoachain/kadena-stoic-legacy@4.1.1`).** Closes 7 STILL-OPEN audit findings: F-ERR-022 (fabricated `"0"` fallbacks in `kadenaFunctions.ts` lines 16+27 dropped — `getBalance` and `accountDescription` now throw a typed `KadenaShapeError` (extends Error with ES2022 `cause`) on shape-mismatched RPC envelopes; legitimate fallbacks at lines 28-29 preserved), F-API-005 (`getSublimateInfo` dedup — duplicate body removed from `ouroFunctions.ts:2148` and replaced with a `@deprecated` JSDoc compat shim that adapts the legacy signature; canonical at `infoOneFunctions.ts:179`; shim removed in v4.2.0), F-API-006 (`describeKeyset` dedup with `describeKeysetOrNull` adapter helper that preserves the two behaviors the canonical does NOT have: `pred ?? "keys-all"` coercion + map-keys-not-array-to-null), F-API-007 (byte-identical `EncryptedDataV1` collapsed into a re-export of `EncryptedData` from `crypto/v1` in stoa-core), F-SEC-007 (codex strict-shape — `deserializeCodex` rejects envelopes with unknown top-level fields against KNOWN_TOP_LEVEL_FIELDS = {version, exportedAt, kadenaWallets, ouronetWallets, addressBook, uiSettings} via new `CodexUnknownFieldError`), F-BUG-010 (`migrateSeedType` no longer silently returns `"koala"` for unknown seed types — throws new `UnknownSeedTypeError` instead), F-API-014 (`getSparksBalance` return type narrowed from `Promise<any>` to `Promise<any | null>`). New file: `src/interactions/errors.ts` (`KadenaShapeError`). New codex/errors.ts contains `CodexUnknownFieldError` + `UnknownSeedTypeError`. Test count: ~330 (was 261; +~69 from 11 new v4-1-1-*.test.ts files: kadena-no-fallbacks, codec-strict-shape, seed-type-strict, seed-type-dedup, sparks-balance-narrow, dist-structure, esm-roundtrip, type-preservation, doc-gates, migration-doc-validity, package-metadata, peer-dep-coverage, full-chain-integration, cross-package-version-pin, publish-workflow-simulation, coil-functions-memoization). NO breaking changes — `getSublimateInfo` deprecation shim preserves backward compatibility for one release. See `MIGRATION-v4.1.md` v4.1.1 appendix at the monorepo root for caller-impact details.
965
+
966
+ **v4.1.0** — sovereign supply-chain migration. **MINOR (atomic with `@stoachain/stoa-core@4.1.0` + `@stoachain/kadena-stoic-legacy@4.1.0`).** Retargets all 12 internal `@kadena/*` imports in `src/interactions/` to the new sibling subpaths under [`@stoachain/kadena-stoic-legacy`](https://www.npmjs.com/package/@stoachain/kadena-stoic-legacy) — a sovereign vendoring of `@kadena/{client,cryptography-utils,types,hd-wallet}` under StoaChain stewardship, born at v4.1.0 in response to Kadena LLC's dissolution and the resulting unmaintained-upstream supply-chain risk. The three `@kadena/*` peer-dep declarations (`@kadena/client`, `@kadena/cryptography-utils`, `@kadena/types`) are dropped from `package.json`; the peer-dep on `@stoachain/stoa-core` is bumped `4.0.1 → 4.1.0` (atomic-version invariant — all three packages always release at the same version); a new `@stoachain/kadena-stoic-legacy@4.1.0` peer-dep is added. Every `Pact.builder` call site across the 13 `interactions/*` modules rewires under the hood — the public function signatures (`getOuronetKdaDetails`, `getCoilPreviewGeneric`, every interactions function) keep byte-identical shape. Test count: **261** (was 218; +43 from the new `tests/v4-1-0-no-kadena-imports.test.ts` runtime regression-lock that asserts no `@kadena/*` literal appears in any built or source file). Release is atomic — `vX.Y.Z` git tag publishes all three packages simultaneously via `.github/workflows/publish.yml` in dependency order (kadena-stoic-legacy first, stoa-core second, ouronet-core third), each with its own `--provenance` SLSA attestation. **No consumer migration required** for subpath imports — every `interactions/*` and `pact/cfm` surface is unchanged.
967
+
968
+ **v4.0.1** — cosmetic published-metadata cleanup. **PATCH.** Strips the redundant `devDependencies` block from `package.json`. Pre-v4.0.1 the manifest carried `@stoachain/stoa-core: "*"` (workspace-resolution plumbing — meaningless on a published artifact) plus `@kadena/*` peer/dev duplicates. The npmjs.com page now shows zero `dependencies`, just the canonical `peerDependencies` (the `@kadena/*` set + `@stoachain/stoa-core@4.0.1` exact-pin). Atomic-version invariant: peer-dep on `@stoachain/stoa-core` bumped from `4.0.0` to `4.0.1` (both packages always release at the same version). NO source-code change. NO behaviour change. **218/218 tests pass.** Regression-lock at `tests/package-version.test.ts` updated to assert `4.0.1`.
969
+
970
+ **v4.0.0** — monorepo split + deprecated-alias removal. **MAJOR,
971
+ breaking.** The structural refactor that v3.3.8 set up. The single
972
+ `@ouronet/ouronet-core` package was split into two atomic-release
973
+ npm packages under the new `StoaChain/stoa-js` GitHub monorepo:
974
+ [`@stoachain/stoa-core`](https://www.npmjs.com/package/@stoachain/stoa-core)
975
+ (chain-generic foundation — signing, wallet, crypto, network
976
+ failover, gas, guard, errors, observability, dalos, reads,
977
+ pact-format) + `@ouronet/ouronet-core` (this package — Ouronet
978
+ protocol business logic: codex codec, interactions/* function
979
+ library, `KADENA_NAMESPACE`, `STOA_AUTONOMIC_*` accounts, cfm Pact
980
+ builders). Both packages release atomically out of the monorepo at
981
+ the same version — a single `vX.Y.Z` git tag publishes both.
982
+ **Breaking removals**: the v3.3.8-deprecated `KADENA_BASE_URL` /
983
+ `PACT_URL` / `GAS_STATION` / `NATIVE_TOKEN_VAULT` aliases plus the
984
+ duplicate `IKadenaKeypair` interface in
985
+ `interactions/ouroFunctions.ts` were removed. Migration: use the
986
+ failover-aware `getPactUrl(chainId)` / `getSpvUrl(chainId)` from
987
+ `@stoachain/stoa-core/constants`; rename references to the canonical
988
+ `STOA_AUTONOMIC_OURONETGASSTATION` / `STOA_AUTONOMIC_LIQUIDPOT` (still
989
+ exported from `@ouronet/ouronet-core/constants`); `import type
990
+ { IKadenaKeypair } from "@stoachain/stoa-core/signing"`. Consumers
991
+ using only the Ouronet-specific surface (codex, interactions, the
992
+ `ouronet-ns` namespace) can keep this package and bump the version.
993
+ Consumers using chain-generic surfaces must add `@stoachain/stoa-core`
994
+ and update the import paths — see
995
+ [`MIGRATION-v4.md`](https://github.com/StoaChain/stoa-js/blob/main/MIGRATION-v4.md)
996
+ at the monorepo root for the full upgrade map. **Internal moves**
997
+ (transparent if you stayed on subpath imports): chain-generic
998
+ constants moved to `@stoachain/stoa-core/constants` (re-exported
999
+ through `@ouronet/ouronet-core/constants` for source-level
1000
+ back-compat); `pact/cfmBuilders.ts` stays under
1001
+ `@ouronet/ouronet-core/pact` (uses `KADENA_NAMESPACE`); chain-generic
1002
+ `formatDecimalForPact` / `formatIntegerForPact` / `mayComeWithDeimal`
1003
+ / `filterFreePositionData` / `formatEU` / `safeCreationTime` helpers
1004
+ moved to `@stoachain/stoa-core/pact`. **Dependency hardening**: all
1005
+ `@kadena/*` + `@noble/curves` + `@scure/bip39` +
1006
+ `@ouronet/dalos-crypto` peer/dev deps pinned to exact versions (no
1007
+ `^`) — prep work for v4.1.0's selective vendoring of `@kadena/client`
1008
+ (supply-chain hardening after Kadena LLC's dissolution). **CI
1009
+ workflow** rewritten for dual-package publish: a single `vX.Y.Z`
1010
+ tag now triggers two `npm publish` calls in dependency order
1011
+ (stoa-core first, ouronet-core second), each with its own
1012
+ `--provenance` SLSA attestation; per-package version-parity gates
1013
+ (README + CHANGELOG must reference the publish version on EACH
1014
+ package independently) preserve the v2.1.x staleness lessons.
1015
+ **703/703 tests pass** across the two packages (485 in stoa-core,
1016
+ 218 in ouronet-core; up from v3.3.8's 698 because the
1017
+ F-ARCH-011/F-ARCH-012 v3.3.8 regression locks now live alongside
1018
+ their stoa-core SUTs — every prior test preserved).
1019
+
1020
+ **v3.3.8** — documentation/deprecation cleanup pass closing 5
1021
+ LOW-severity findings from the 2026-05-05 audit. **MINOR,
1022
+ additive.** **F-API-015** rewrote a stale JSDoc parameter
1023
+ mention in `src/dalos/account.ts` (the `strict` flag was never
1024
+ implemented; new wording documents the actual contract).
1025
+ **F-API-016** added `export` to the `CoilConfig` interface so
1026
+ consumers can type-annotate `CoilConfig` values directly
1027
+ without re-declaring the shape — one-word change, additive,
1028
+ consumer-facing improvement. **F-SEC-005 / F-ARCH-014** marked
1029
+ `KADENA_BASE_URL` `@deprecated` redirecting to the
1030
+ failover-aware `getActivePactUrl` / `getActiveSpvUrl` (or the
1031
+ same-subpath `getPactUrl` / `getSpvUrl` wrappers); the constant
1032
+ itself remains for backwards-compat, removal scheduled for
1033
+ v4.0.0. **F-ARCH-011** consolidated `normalizeKeysetRef`
1034
+ deep-import in `ouroFunctions.ts` to the `../guard` barrel,
1035
+ matching the project's subpath-import discipline. **F-ARCH-012**
1036
+ converted 19 single-quoted string literals to double quotes in
1037
+ `src/dalos/account.ts` — the only remaining drift after v3.1.1's
1038
+ fix to `src/dalos/index.ts`; TypeScript treats both forms as
1039
+ identical string literals at the type level (pure stylistic).
1040
+ NO breaking change. NO observable runtime behavior change. One
1041
+ new public-API export (`CoilConfig` interface). Locked at
1042
+ `tests/v3-3-8-doc-cleanup.test.ts` with 3 it-blocks across 3
1043
+ describe groups: T1 verifies the `CoilConfig` type export via
1044
+ `expectTypeOf`; T2 verifies `normalizeKeysetRef` is reachable
1045
+ through the `../guard` barrel and round-trips a
1046
+ keysetref-shaped object; T3 reads `src/dalos/account.ts` source
1047
+ verbatim and asserts no single-quoted string literals remain in
1048
+ code (English apostrophes inside JSDoc comments are exempt).
1049
+ F-API-015 (stale JSDoc) and F-SEC-005/F-ARCH-014 (`@deprecated`
1050
+ marker) are pure JSDoc changes that don't surface at runtime;
1051
+ the CHANGELOG entry is the audit trail. **+3 new tests**
1052
+ bringing the suite to **698/698 passing** (was 695 in v3.3.7).
1053
+
1054
+ **v3.3.7** — security pass closing two MEDIUM security findings
1055
+ from the 2026-05-05 audit in one bundled release. **MINOR,
1056
+ additive.** **F-SEC-003** ships `InvalidPactReaderError` and
1057
+ `InvalidLoggerError` (both extend `TypeError`) and tightens
1058
+ `setPactReader` (now rejects non-function inputs with a clear
1059
+ message naming the actual type) and `setLogger` (now rejects
1060
+ null / undefined / non-object inputs AND objects whose `warn`
1061
+ or `error` are non-callable). Pre-v3.3.7 misconfigurations
1062
+ only surfaced later as `_reader is not a function` /
1063
+ `_logger.warn is not a function` at the first call site, far
1064
+ from the boot wiring. **F-SEC-004** wires a one-shot
1065
+ `getLogger().warn(...)` security advisory into the V1-decrypt
1066
+ path — V1 envelopes use PBKDF2-SHA256 / 10,000 iterations,
1067
+ well below OWASP's current 600,000 minimum; the warning fires
1068
+ once per process lifetime (no bulk-decrypt log spam). Adds
1069
+ new rich variants `decryptStringV2WithDetails` and
1070
+ `smartDecryptWithDetails` returning `{plaintext, wasLegacyV1}`
1071
+ for per-call programmatic detection so consumers can re-encrypt
1072
+ affected codex entries to V2 in-place. JSDoc CVE-style risk
1073
+ documentation added to `EncryptedDataV1`, `decryptStringV2`,
1074
+ and `smartDecrypt`. NO breaking change. v3.3.0 contract test
1075
+ locking the byte-identical `setLogger requires a non-null
1076
+ Logger` message preserved verbatim. Locked at
1077
+ `tests/v3-3-7-seam-validators.test.ts` (11 it-blocks across 3
1078
+ describe groups: setPactReader input validation,
1079
+ setLogger input-shape validation, setLogger
1080
+ backwards-compat preservation) and
1081
+ `tests/v3-3-7-v1-warning.test.ts` (10 it-blocks across 3
1082
+ describe groups: decryptStringV2WithDetails,
1083
+ smartDecryptWithDetails, one-shot warning behavior including
1084
+ the load-bearing "second V1 decrypt is silent" assertion that
1085
+ proves the bulk-codex-decrypt UX is non-spammy). **+21 new
1086
+ tests** bringing the suite to **695/695 passing** (was 674 in
1087
+ v3.3.6).
1088
+
1089
+ **v3.3.6** — performance pass closing three MEDIUM perf findings
1090
+ from the 2026-05-05 audit in one release. **MINOR, additive.**
1091
+ **F-PERF-008** added `"sideEffects": false` to `package.json` —
1092
+ the audit's "single most impactful tree-shaking fix"; verified
1093
+ safe via grep showing zero top-level callable statements in
1094
+ `src/` (every seam — `setPactReader`, `setLogger`, `setNodeConfig`
1095
+ — is consumer-invoked at boot, never at module top-level);
1096
+ consumer bundles can now prune unused barrel imports from the
1097
+ 16-subpath exports map. **F-PERF-003** memoized 8 `RegExp`
1098
+ allocations per call in `coilFunctions.getCoilPreviewGeneric`
1099
+ to a `Map<string, CoilPatternSet>` cache keyed by
1100
+ `targetTokenName` — patterns are dynamic per token (interpolate
1101
+ `config.targetToken`) so the audit's literal "hoist to
1102
+ module-level const" doesn't apply; the cache form achieves the
1103
+ same outcome with steady-state 0 RegExp allocations per call
1104
+ after warm-up. **F-PERF-004** parallelized
1105
+ `ouroFunctions.getOuronetKdaDetails` via `Promise.all([owner,
1106
+ guard])` — verified independent (probes `DALOS.UR_AccountKadena`
1107
+ vs `DALOS.UR_AccountGuard` with no causal dependency); halves
1108
+ happy-path latency from ~2 sequential RPC roundtrips to ~1
1109
+ parallel roundtrip. NO public API change. NO observable
1110
+ behavior change outside the latency win and the bundler
1111
+ tree-shaking pruning. Locked at
1112
+ `tests/v3-3-6-perf-pass.test.ts` with 2 it-blocks: T1 strict
1113
+ equality `pkg.sideEffects === false` for F-PERF-008, T2
1114
+ counting-reader assertion that both `UR_AccountKadena` AND
1115
+ `UR_AccountGuard` Pact codes appear in the recorded calls for
1116
+ F-PERF-004. F-PERF-003's regex memoization is module-internal;
1117
+ behavioral coverage already lives in v3.3.5's
1118
+ `tests/v3-3-5-smoke.test.ts:117-141` for `getCoilPreviewGeneric`
1119
+ which passes unchanged. **+2 new tests** bringing the suite to
1120
+ **674/674 passing** (was 672 in v3.3.5).
1121
+
1122
+ **v3.3.5** — runtime smoke tests for 6 interaction modules with
1123
+ no runtime test coverage prior to this release. **MINOR,
1124
+ additive (test-only).** Closes audit finding **F-TEST-006**
1125
+ (MEDIUM, testing-auditor). Three modules had **zero runtime
1126
+ tests** (`pensionFunctions`, `guardFunctions`,
1127
+ `infoOneFunctions`); three more had **compile-only tests**
1128
+ (`coilFunctions`, `kpayFunctions`, `activateFunctions`). v3.3.5
1129
+ adds `tests/v3-3-5-smoke.test.ts` — **12 new it-blocks across 6
1130
+ describe groups**, one happy-path + one error-path test per
1131
+ module: `getHibernateFee` parses `{decimal:"0.99"}` → `0.99` and
1132
+ catches into local fallback formula on thrown read;
1133
+ `getRotateGuardInfo` returns success-path data verbatim, `null`
1134
+ on failure-status; `getCoilPreviewInfo` wraps success data in
1135
+ `{result: ...}`, returns `null` on failure-status;
1136
+ `getCoilPreviewGeneric` parses `"generates 5.0 AURYN"` from
1137
+ `pre-text` regex match, **rethrows** on failure-status (the only
1138
+ module of the 6 that rethrows); `getKpayData` returns success
1139
+ data verbatim, `null` on failure-status;
1140
+ `getDeployStandardAccountInfoOnly` returns success data
1141
+ verbatim, `null` + `getLogger().error` on thrown read. Read-only
1142
+ function smoke is sufficient per F-TEST-006's "function actually
1143
+ executes" assertion; transaction-execute coverage requires
1144
+ mocking the full `@kadena/client` signing + submit chain and is
1145
+ queued for v4.0.0's monorepo split. NO source-code change. **+12
1146
+ new tests** bringing the suite to **672/672 passing** (was 660
1147
+ in v3.3.4). Closes the v3.3.x audit-closure track —
1148
+ F-LOGGER-SEAM-001 (v3.3.0), F-TEST-002 (v3.3.2), F-TEST-005
1149
+ (v3.3.4), F-TEST-006 (v3.3.5) all CLOSED; remaining MEDIUM
1150
+ findings are performance/architecture, not test coverage.
1151
+
1152
+ **v3.3.4** — success-path tests for the 13 v3.0.0 nullable-widened
1153
+ functions that previously had only RPC-failure-path coverage.
1154
+ **MINOR, additive (test-only).** Closes audit finding
1155
+ **F-TEST-005** (MEDIUM, testing-auditor). Pre-v3.3.4, only 3 of
1156
+ the 16 v3.0.0 widenings had a paired success-path test —
1157
+ `getStoaPriceUSD`, `getLPTypeInfo` mixed-state, and
1158
+ `getUrStoaGuard` 3-state. The remaining 13 could not distinguish
1159
+ "always returns null" (silent regression) from "returns null
1160
+ only on RPC failure" (correct contract). v3.3.4 adds
1161
+ `tests/v3-3-4-success-paths.test.ts` — **13 new it-blocks
1162
+ across 6 describe groups**: pricing-quartet (3 — int/decimal
1163
+ parse paths for `getTokenDecimals`/`getPoolTotalFee`/`getDPTFMinMove`);
1164
+ string-balance cluster (4 — `getIgnisBalance` /
1165
+ `getAccountTokenSupply` / `getOuroDispoCapacity` /
1166
+ `getVirtualOuro` all unwrap `{decimal:"..."}` to the
1167
+ underlying string via `mayComeWithDeimal`); urStoa pair (2 —
1168
+ `getUrStoaBalance` parses `{decimal:"42.5"}` → `42.5`,
1169
+ `checkCoinAccountExists` (urStoa) returns `true` when chain
1170
+ data is `true`); `validateLiquidity` mixed-shape success (1 —
1171
+ chain returns `[{decimal:"0.05"}, {decimal:"0.10"}]` →
1172
+ function returns `{valid:true, computed:"0.05", max:"0.10"}`
1173
+ AND `error` is `undefined`, locking the v3.0.0 mutual
1174
+ exclusion); `getMaxBuyMovieBooster` (1 — `{int:"5000"}` →
1175
+ `5000`); magic-string elimination (2 — `getSWPSpawnLimit` and
1176
+ `getSWPInactiveLimit` return the decimal string AND
1177
+ `expect(out).not.toBe("N/A")` so the v3.0.0 BREAKING swap
1178
+ cannot regress unnoticed). Strategy mirrors the pre-existing
1179
+ `tests/interactions-pricing.test.ts:80-88` success-path lock:
1180
+ `setPactReader(successReader({...}))` → call SUT → assert. NO
1181
+ source-code change; every interaction function is byte-identical
1182
+ to v3.3.3. **+13 new tests** bringing the suite to **660/660
1183
+ passing** (was 647 in v3.3.3).
1184
+
1185
+ **v3.3.3** — multi-party partial-signature public surface for
1186
+ cross-party signing handoffs. **MINOR, additive (NEW PUBLIC
1187
+ SURFACE — not a bug fix).** Ships the OuronetUI-requested
1188
+ "Person A signs → exports → Person B imports → signs → exports
1189
+ → Person C imports → signs → submits" workflow as shared core,
1190
+ with cross-party tamper detection at every handoff. Builds on
1191
+ v3.3.2's locked partial-signing primitive (signing with a subset
1192
+ of declared signers fills only those slots; pre-existing slots
1193
+ stay intact across re-signing passes) by wrapping it in a
1194
+ versioned export envelope + slot-status helpers + Ed25519
1195
+ sig-verification helper. New `src/signing/partialSig.ts` module
1196
+ re-exported from `@ouronet/ouronet-core/signing`, exposing
1197
+ **7 functions** (`signPartial`, `serializePartialTransaction`,
1198
+ `deserializePartialTransaction`, `getMissingSigners`,
1199
+ `getFilledSigners`, `isFullySigned`,
1200
+ `verifyExistingSignatures`), **2 typed errors**
1201
+ (`InvalidEnvelopeError`, `TamperedHashError`), and the
1202
+ `PartialSigEnvelope` interface. Two-layer tamper defence: (1)
1203
+ `deserializePartialTransaction` recomputes blake2b-256(cmd) and
1204
+ rejects mismatch with `TamperedHashError` carrying both
1205
+ `expected` and `actual` for operator diagnosability; (2)
1206
+ `verifyExistingSignatures` runs `nacl.sign.detached.verify` on
1207
+ every filled slot — works for both nacl-direct (koala/foreign)
1208
+ and BIP32-WASM (chainweaver/eckowallet) sigs since both produce
1209
+ standard Ed25519 over the same canonical hash bytes; catches
1210
+ the "tampered cmd + tampered hash to match" attack the
1211
+ hash-integrity gate alone misses (any cmd modification
1212
+ invalidates every prior signature against the new hash). NO
1213
+ existing API changed; NO source-side behaviour change outside
1214
+ the new module. **+16 new tests** (`tests/partial-sig.test.ts`
1215
+ — 16 it-blocks across 7 describe groups including end-to-end
1216
+ 3-party round-trip via serialize/deserialize handoffs), bringing
1217
+ the suite to **647/647 passing** (was 631 in v3.3.2; +16).
1218
+
1219
+ **v3.3.2** — direct test coverage for `universalSignTransaction`
1220
+ (closes audit finding **F-TEST-002** HIGH). **MINOR, additive
1221
+ (test-only).** Pre-v3.3.2, the central signing entry point in
1222
+ `src/signing/universalSign.ts` had ZERO direct tests — the
1223
+ chainweaver / eckowallet / foreign seedType branches AND the
1224
+ seedType dispatcher itself were never runtime-tested. v3.3.2 adds
1225
+ `tests/universal-sign.test.ts` with 9 new it-blocks across 6
1226
+ describe groups: koala branch round-trip with RFC-8032 vector
1227
+ (2 tests including the `fromKeypair` adapter that normalises
1228
+ consumer-shape `privateKey` field into universal `secretKey`);
1229
+ chainweaver branch round-trip with real WASM `kadenaSign`
1230
+ derived from the @kadena/hd-wallet vendor mnemonic vector
1231
+ (1 test); eckowallet branch round-trip proving the dispatcher
1232
+ routes both labels to the same WASM signing path (1 test);
1233
+ multi-signer mixed-seedType case proving the
1234
+ iterate-and-dispatch-each loop's correctness (1 test);
1235
+ foreign-key `onMissingKey` callback resolution — success path
1236
+ where the callback returns the matching private key (1 test) +
1237
+ failure path where the callback returns a mismatched key →
1238
+ "Key mismatch" error citing both expected and derived pubkeys
1239
+ (1 test); and the partial-signing primitive that v3.3.3's
1240
+ planned multi-party signing public surface will build on —
1241
+ 3-signer transaction signed with only 1 keypair fills only
1242
+ that slot, other slots stay empty (1 test); and keypairs whose
1243
+ pubkey is NOT in cmd.signers are silently skipped (1 test).
1244
+ The verification helper uses `nacl.sign.detached.verify` over
1245
+ the base64URL-decoded `signed.hash` bytes — works for BOTH
1246
+ the nacl-direct path (koala/foreign) AND the WASM-Ed25519
1247
+ path (chainweaver/eckowallet) since both produce standard
1248
+ Ed25519 signatures over the same canonical hash. NO
1249
+ source-code change; `universalSign.ts` is byte-identical to
1250
+ v3.3.1.
1251
+
1252
+ **v3.3.1** — workflow-file patch. **PATCH, workflow-only.** Closes
1253
+ the two carried-forward follow-ups that appeared in every
1254
+ pollinate run's final report from v3.0.0 through v3.3.0: (1) `npm
1255
+ publish --provenance` flag added (plus the `id-token: write`
1256
+ workflow permission required to mint the GitHub-Actions-OIDC token
1257
+ that npm exchanges with npmjs.org's attestation endpoint) — every
1258
+ v3.3.1+ release carries a SLSA attestation visible as the
1259
+ "Provenance" badge on npmjs.com and a 200 response on
1260
+ `https://registry.npmjs.org/-/npm/v1/attestations/@ouronet/ouronet-core@{version}`;
1261
+ pre-v3.3.1, every release shipped without provenance because
1262
+ `lifecycle.use_provenance: true` in `.bee/config.json` was
1263
+ truth-claimed by pollinate but the actual workflow's `npm publish
1264
+ --access public` lacked the flag. (2) `gh release create`
1265
+ invocations drop the `--repo` flag — the
1266
+ `gh release create --notes-from-tag --repo X` flag combination
1267
+ started failing on GitHub-hosted runners around 2026-04-30 with
1268
+ the gh-CLI image update; every v3.x release pre-v3.3.1 needed
1269
+ pollinate's REST-API fallback (Step 9c) to create the GitHub
1270
+ Release manually. Dropping `--repo` lets gh auto-detect the repo
1271
+ from the working-directory context (set by `actions/checkout@v4`
1272
+ at the top of the workflow), which is the same repo we want
1273
+ anyway. From v3.3.1 onwards the workflow's gh-Release step
1274
+ succeeds inline; pollinate's REST fallback becomes
1275
+ idempotency-skip code (Step 9b's "release exists?" check passes,
1276
+ Step 9c skips). Workflow-only patch — `.github/workflows/publish.yml`
1277
+ is the sole behaviour-change file; source code is byte-identical
1278
+ to v3.3.0; **622/622 tests pass unchanged** (workflow files
1279
+ aren't in the test scope; verification arrives with the v3.3.1
1280
+ publish run itself).
1281
+
1282
+ **698 tests** pass on every commit (up from 695 in v3.3.7; +3
1283
+ from the new `tests/v3-3-8-doc-cleanup.test.ts` regression-lock
1284
+ file added in v3.3.8 to close 5 LOW-severity findings from the
1285
+ 2026-05-05 audit — F-API-015 stale JSDoc, F-API-016 export
1286
+ CoilConfig, F-SEC-005/F-ARCH-014 KADENA_BASE_URL @deprecated
1287
+ marker, F-ARCH-011 normalizeKeysetRef barrel-import
1288
+ consolidation, F-ARCH-012 dalos/account.ts quote-style cleanup.
1289
+ With v3.3.8 the v3.3.x audit-closure track now spans testing
1290
+ AND performance AND security-input-validation AND
1291
+ documentation/deprecation categories; remaining items are
1292
+ either reserved for v4.0.0 (arch + sleep-replacement) or
1293
+ NEEDS CONTEXT findings flagged for human review.
1294
+ Dependency-hygiene release planned for v3.3.9 / v3.4.0. Published to the public npmjs registry via
1295
+ `.github/workflows/publish.yml` on every `v*` tag (which also
1296
+ creates a GitHub Release). Published to the public
1297
+ npmjs registry via `.github/workflows/publish.yml` on every `v*`
1298
+ tag (which also creates a GitHub Release).
1299
+
1300
+ ```bash
1301
+ npm install @ouronet/ouronet-core
1302
+ ```
1303
+
1304
+ ## What's new in v2.1.0
1305
+
1306
+ The chain-RPC surface used to be 81 ad-hoc `createClient(getPactUrl(chainId))`
1307
+ calls scattered across 11 interaction files, each pinned to whatever
1308
+ URL `getPactUrl` returned at the moment of construction and each with
1309
+ no timeout. v2.1.0 collapses that into one reusable factory:
1310
+
1311
+ ```ts
1312
+ import { getFailoverClient } from "@ouronet/ouronet-core/network";
1313
+
1314
+ // All four standard chain operations, each wrapped in withFailover +
1315
+ // per-tier timeout. The factory's submit captures the same signed-tx
1316
+ // reference across primary + fallback attempts (REQ-01 dedup contract).
1317
+ const { dirtyRead, submit, listen, pollOne } = getFailoverClient(chainId);
1318
+
1319
+ const txDescriptor = await submit(signedTx); // 60s default, auto-failover
1320
+ const result = await listen(txDescriptor); // 180s default (~6 Kadena blocks), auto-failover
1321
+ ```
1322
+
1323
+ ### Timeouts
1324
+
1325
+ Per-tier defaults: **read 15s**, **submit 60s**, **listen 180s**
1326
+ (~6 Kadena blocks for inclusion long-polling), **pollOne 30s**.
1327
+ Two-tier override precedence — per-call wins over factory-time wins
1328
+ over locked default:
1329
+
1330
+ ```ts
1331
+ // Factory-time override
1332
+ const client = getFailoverClient(chainId, { submitTimeoutMs: 30_000 });
1333
+
1334
+ // Per-call override
1335
+ await client.submit(signedTx, { submitTimeoutMs: 5_000 });
1336
+ ```
1337
+
1338
+ A primary-side timeout rejects with `Error.name === "AbortError"`
1339
+ inside `withFailover`, which classifier-matches the existing fallback
1340
+ contract — so a primary timeout transparently triggers the fallback
1341
+ retry. Only if **both** primary and fallback time out does the consumer
1342
+ see a `SigningError { code: "TIMEOUT" }` surfaced via the factory's
1343
+ outer-boundary catch.
1344
+
1345
+ ### Lower-level helpers
1346
+
1347
+ For the codex signing strategy seam (where failover is intentionally
1348
+ the consumer's `PactClient` responsibility), v2.1.0 also exports a
1349
+ plain timeout helper:
1350
+
1351
+ ```ts
1352
+ import { runWithTimeout } from "@ouronet/ouronet-core/network";
1353
+
1354
+ await runWithTimeout("operation-name", (controller) =>
1355
+ fetch("https://...", { signal: controller.signal }), 15_000);
1356
+ // Rejects with Error.name === "AbortError" on timeout. Caller is
1357
+ // responsible for converting to SigningError { code: "TIMEOUT" }.
1358
+ ```
1359
+
1360
+ Plus `createTimeoutError(operation, timeoutMs, originalError?, additionalContext?)`
1361
+ from `@ouronet/ouronet-core/errors` for that conversion, and
1362
+ `resetNodeFailover()` from `@ouronet/ouronet-core/network` for test
1363
+ isolation.
1364
+
1365
+ ### Migration
1366
+
1367
+ **No migration required.** All existing imports continue to work
1368
+ unchanged. The new surface is purely opt-in. Internal calls have
1369
+ already been migrated — your existing reads and submits now get
1370
+ failover and timeouts automatically.
1371
+
1372
+ ## What's new in v2.2.0
1373
+
1374
+ The `./crypto` subpath previously surfaced every decryption failure as
1375
+ a generic `Error` — wrong password, structurally damaged envelope, and
1376
+ unsupported schema version all collapsed to a string-message check.
1377
+ v2.2.0 adds three typed error classes that discriminate the failure
1378
+ modes, plus a single-path `smartDecrypt` dispatch that closes a
1379
+ wall-time timing differential observed on V1 wrong-password inputs:
1380
+
1381
+ ```ts
1382
+ import {
1383
+ smartDecrypt,
1384
+ WrongPasswordError,
1385
+ CorruptEnvelopeError,
1386
+ } from "@ouronet/ouronet-core/crypto";
1387
+
1388
+ try {
1389
+ const plaintext = await smartDecrypt(blob, password);
1390
+ } catch (err) {
1391
+ if (err instanceof WrongPasswordError) {
1392
+ // most common case — show "wrong password" UI
1393
+ } else if (err instanceof CorruptEnvelopeError) {
1394
+ // blob is structurally damaged — recovery / re-import path
1395
+ } else {
1396
+ // unexpected (UnsupportedFormatError, or anything else) — log and
1397
+ // surface to user as a generic decrypt failure
1398
+ throw err;
1399
+ }
1400
+ }
1401
+ ```
1402
+
1403
+ Existing consumers that only check `instanceof Error` or read
1404
+ `error.message` continue to work unchanged — the typed classes extend
1405
+ `Error`, so the new discrimination is purely opt-in.
1406
+
1407
+ ## What's new in v2.3.0
1408
+
1409
+ The v2.3.0 audit-closure release introduces a central logger seam at
1410
+ `@ouronet/ouronet-core/observability` mirroring the existing
1411
+ `setPactReader` injection-seam pattern. Every diagnostic
1412
+ `console.warn` / `console.error` call inside `src/` now routes through
1413
+ this seam, so consumers can capture, redirect, or suppress library
1414
+ log events without monkey-patching the global `console`:
1415
+
1416
+ ```ts
1417
+ import { setLogger, getLogger, type Logger } from "@ouronet/ouronet-core/observability";
1418
+
1419
+ // Option 1: Forward to your existing app logger (Pino, Winston, Sentry, …).
1420
+ const myLogger: Logger = {
1421
+ warn: (msg, ...args) => myApp.warn(msg, args),
1422
+ error: (msg, ...args) => myApp.error(msg, args),
1423
+ };
1424
+ setLogger(myLogger);
1425
+
1426
+ // Option 2: Capture for telemetry without losing console output.
1427
+ const original = getLogger();
1428
+ setLogger({
1429
+ warn: (msg, ...args) => { telemetry.warn(msg, args); original.warn(msg, ...args); },
1430
+ error: (msg, ...args) => { telemetry.error(msg, args); original.error(msg, ...args); },
1431
+ });
1432
+
1433
+ // Or do nothing — the default routes to console.warn / console.error so
1434
+ // existing v2.2.x behavior is preserved exactly.
1435
+ ```
1436
+
1437
+ The mutator rejects null/undefined input with a clear `TypeError`:
1438
+
1439
+ ```ts
1440
+ setLogger(null);
1441
+ // throws TypeError: setLogger requires a non-null Logger
1442
+ ```
1443
+
1444
+ The companion addition is a typed `UnknownPredicateError` class
1445
+ re-exported from the `./guard` subpath. `computeThreshold` throws it
1446
+ when it encounters an unrecognized predicate; the general-purpose
1447
+ `analyzeGuard` catches it and folds it into a structured
1448
+ `predicateRecognized: false` bit on the returned analysis. Consumers
1449
+ that want to discriminate this failure mode can branch on the typed
1450
+ class:
1451
+
1452
+ ```ts
1453
+ import { computeThreshold, UnknownPredicateError } from "@ouronet/ouronet-core/guard";
1454
+
1455
+ try {
1456
+ const threshold = computeThreshold(guard);
1457
+ } catch (err) {
1458
+ if (err instanceof UnknownPredicateError) {
1459
+ // Surface a recognizable "unknown predicate" diagnostic to the user.
1460
+ } else {
1461
+ throw err;
1462
+ }
1463
+ }
1464
+ ```
1465
+
1466
+ Existing `instanceof Error` checks and existing analysis-flag access
1467
+ continue to work unchanged — the typed-class discrimination from
1468
+ `./guard` and the logger-seam injection from `./observability` are
1469
+ both purely opt-in.
1470
+
1471
+ ## What's new in v3.0.0
1472
+
1473
+ The v3.0.0 fabricated-fallbacks-removal release closes M3 from the
1474
+ 2026-04-30 audit cycle (lead finding F-CORE-007 HIGH plus the
1475
+ ~24-site catalog sweep). The headline change is uniform: every
1476
+ `src/interactions/*` read helper that previously fabricated a chain
1477
+ value on RPC failure (`1.0` USD prices, `"0"` balances, sentinel
1478
+ `"N/A"` strings, fake `false` existence flags) now returns `null`
1479
+ on failure so consumers can distinguish "RPC failed" from "chain
1480
+ returned this real value." Sixteen functions widen their return
1481
+ types in lockstep; consumers add `if (result === null) { ... }`
1482
+ branches at call sites:
1483
+
1484
+ ```ts
1485
+ import { getStoaPriceUSD } from "@ouronet/ouronet-core/interactions/ouroFunctions";
1486
+
1487
+ // v3.0.0 — null on RPC failure / chain failure / non-finite parse,
1488
+ // real number on success.
1489
+ const price = await getStoaPriceUSD();
1490
+
1491
+ if (price === null) {
1492
+ // RPC failed or chain returned malformed data — show an error
1493
+ // banner instead of computing positions against a fabricated 1.0.
1494
+ showRPCErrorBanner("Could not fetch STOA/USD price");
1495
+ return;
1496
+ }
1497
+
1498
+ // price is a real Number.isFinite(...) value — safe to use.
1499
+ renderPriceLabel(`$${price.toFixed(4)}`);
1500
+ ```
1501
+
1502
+ `getLPTypeInfo` keeps its function-level return type but widens its
1503
+ inner field types so consumers can render mixed UI per flag (Frozen
1504
+ LP succeeded, Sleeping LP RPC-failed):
1505
+
1506
+ ```ts
1507
+ import { getLPTypeInfo } from "@ouronet/ouronet-core/interactions/addLiquidityFunctions";
1508
+
1509
+ const info = await getLPTypeInfo(swpair); // { hasFrozenLP, hasSleepingLP }
1510
+
1511
+ // Three states per flag now: true (chain confirmed exists),
1512
+ // false (chain confirmed absent OR chain failure-status), null (catch).
1513
+ if (info.hasFrozenLP === null) {
1514
+ renderFrozenSection({ status: "rpc-error" });
1515
+ } else {
1516
+ renderFrozenSection({ status: info.hasFrozenLP ? "present" : "absent" });
1517
+ }
1518
+
1519
+ if (info.hasSleepingLP === null) {
1520
+ renderSleepingSection({ status: "rpc-error" });
1521
+ } else {
1522
+ renderSleepingSection({ status: info.hasSleepingLP ? "present" : "absent" });
1523
+ }
1524
+ ```
1525
+
1526
+ In lockstep, **14 NON-BREAKING logger-routing additions** across 5
1527
+ files complete the silent-catch-elimination sweep started in v2.3.0
1528
+ — previously-silent diagnostic catches in `dexFunctions.ts`,
1529
+ `ouroFunctions.ts`, `activateFunctions.ts`, `infoOneFunctions.ts`,
1530
+ and `urStoaFunctions.ts` private helpers now route via
1531
+ `getLogger().error("Error in <funcName>:", error)`. Consumers who
1532
+ called `setLogger(...)` (introduced in v2.3.0) automatically capture
1533
+ these new error events with no additional wiring.
1534
+
1535
+ ## Migrating to v3.x
1536
+
1537
+ v3.0.0 is the first major bump since v2.0.0 and the deliberate
1538
+ forcing function for **Option B null-pattern** (locked Q3..Q11):
1539
+ sixteen `src/interactions/*` read helpers that previously fabricated
1540
+ chain values on RPC failure now widen their return types so consumers
1541
+ see RPC failures instead of silently fabricated sentinels (`1.0` USD
1542
+ prices, `"0"` balances, sentinel `"N/A"` strings, fake `false`
1543
+ existence flags). Fifteen functions widen from `Promise<T>` to
1544
+ `Promise<T | null>`; one (`validateLiquidity`) adds an optional
1545
+ `error?: string` field on its mixed shape to distinguish "RPC failed"
1546
+ from "validation rejected" without dropping the existing `valid:
1547
+ boolean` contract.
1548
+
1549
+ Every breaking change below stems from the **Option B null-pattern**
1550
+ locked decision per the 2026-04-30 audit cycle: callers add `if
1551
+ (result === null) { showRPCErrorBanner(); return; }` branches before
1552
+ reading the previously-fabricated value. The 14 NON-BREAKING
1553
+ logger-routing additions across 5 files (Phase 3) require **NO
1554
+ consumer migration** — they are pure observability and existing call
1555
+ sites continue to work unchanged.
1556
+
1557
+ ### 1. Pricing-quartet — `Promise<number>` → `Promise<number | null>`
1558
+
1559
+ `getStoaPriceUSD`, `getTokenDecimals`, `getPoolTotalFee`, and
1560
+ `getDPTFMinMove` (REQ-01..REQ-04) all widen to `Promise<number |
1561
+ null>`. The previous `1.0` / `0` / `8` fabrication sentinels are
1562
+ replaced with `null`, and `Number.isFinite()` guards catch `NaN`
1563
+ from malformed chain data (e.g. `parseInt("abc", 10)` or
1564
+ `parseFloat(String(undefined))`). All three failure paths — outer
1565
+ catch (network failure), `status !== "success"` branch (chain
1566
+ failure), and success-but-not-finite branch — now return `null`.
1567
+
1568
+ These are transaction-relevant amounts: silently fabricating `1.0`
1569
+ for a missing USD price would have produced wildly wrong position
1570
+ values; silently returning `8` for missing token decimals would have
1571
+ produced off-by-many-orders-of-magnitude amounts. The **Option B
1572
+ null-pattern** locked decision makes this failure mode explicit at
1573
+ the call site.
1574
+
1575
+ ```ts
1576
+ // Before (v2.x):
1577
+ const price = await getStoaPriceUSD(); // number — could be fabricated 1.0
1578
+ const decimals = await getTokenDecimals(token); // number — could be fabricated 8
1579
+ renderPosition(price * amount, decimals);
1580
+
1581
+ // After (v3.x):
1582
+ const price = await getStoaPriceUSD();
1583
+ const decimals = await getTokenDecimals(token);
1584
+ if (price === null || decimals === null) {
1585
+ showRPCErrorBanner("Could not fetch pricing data");
1586
+ return;
1587
+ }
1588
+ renderPosition(price * amount, decimals);
1589
+ ```
1590
+
1591
+ ### 2. String-balance cluster — `Promise<string>` → `Promise<string | null>`
1592
+
1593
+ `getIgnisBalance`, `getAccountTokenSupply`, `getOuroDispoCapacity`,
1594
+ and `getVirtualOuro` (REQ-05) all widen to `Promise<string | null>`
1595
+ as a tightly-coupled cluster — both `return "0"` sentinels in each
1596
+ function become `return null`. Per the locked decision, "changing
1597
+ only some risks a UI where some buttons silently misbehave on RPC
1598
+ failure while others now correctly disable" — these four functions
1599
+ move together so consumer-side balance-display UI can branch
1600
+ uniformly on `null`.
1601
+
1602
+ Existing v2.3.0 logger routing is preserved; only the type and
1603
+ sentinel change. Catch paths still route via `getLogger().error()`.
1604
+
1605
+ ```ts
1606
+ // Before (v2.x):
1607
+ const balance = await getIgnisBalance(account); // string — could be fabricated "0"
1608
+ showBalance(formatToken(balance));
1609
+
1610
+ // After (v3.x):
1611
+ const balance = await getIgnisBalance(account);
1612
+ if (balance === null) {
1613
+ showBalanceUnknown(); // Distinguish RPC failure from a real "0" balance
1614
+ return;
1615
+ }
1616
+ showBalance(formatToken(balance));
1617
+ ```
1618
+
1619
+ ### 3. `getLPTypeInfo` field widening (Approach A — function return type unchanged)
1620
+
1621
+ `getLPTypeInfo` (REQ-06) widens its inner field types from `{
1622
+ hasFrozenLP: boolean; hasSleepingLP: boolean }` to `{ hasFrozenLP:
1623
+ boolean | null; hasSleepingLP: boolean | null }`. Per the locked
1624
+ **Approach A** decision, the **function-level return type is
1625
+ UNCHANGED** — only the inner field types widen. Consumers can render
1626
+ granular per-flag mixed UI (e.g. Frozen LP succeeded but Sleeping LP
1627
+ RPC-failed). Approach B (function-level null) was rejected because
1628
+ it loses granularity; Approach C (separate error channel) was
1629
+ rejected because it is non-breaking and defeats the audit purpose.
1630
+
1631
+ Per the Phase 2 P-001 fix, **3-state preservation** is the locked
1632
+ contract for each flag: chain-failure-status (`response.result.status
1633
+ !== "success"`) returns `false`, the inner IIFE catch returns `null`,
1634
+ and a successful chain read returns `true`. Both inner catches route
1635
+ via `getLogger().error("Error checking Frozen LP:", error)` and
1636
+ `("Error checking Sleeping LP:", error)`.
1637
+
1638
+ ```ts
1639
+ // Before (v2.x):
1640
+ const info = await getLPTypeInfo(swpair);
1641
+ // { hasFrozenLP: boolean; hasSleepingLP: boolean }
1642
+ if (info.hasFrozenLP) renderFrozen();
1643
+ if (info.hasSleepingLP) renderSleeping();
1644
+
1645
+ // After (v3.x):
1646
+ const info = await getLPTypeInfo(swpair);
1647
+ // { hasFrozenLP: boolean | null; hasSleepingLP: boolean | null }
1648
+ if (info.hasFrozenLP === null) renderFrozenRpcError();
1649
+ else if (info.hasFrozenLP) renderFrozen();
1650
+ else renderFrozenAbsent();
1651
+
1652
+ if (info.hasSleepingLP === null) renderSleepingRpcError();
1653
+ else if (info.hasSleepingLP) renderSleeping();
1654
+ else renderSleepingAbsent();
1655
+ ```
1656
+
1657
+ ### 4. urStoa trio — `Promise<T>` → `Promise<T | null>`
1658
+
1659
+ `getUrStoaBalance`, `getUrStoaGuard`, and `checkCoinAccountExists`
1660
+ (urStoa) (REQ-07) all widen to nullable returns as a tightly-coupled
1661
+ trio. `getUrStoaBalance` widens `Promise<number>` → `Promise<number
1662
+ | null>` (both `return 0` sites become `return null`).
1663
+ `getUrStoaGuard` widens `Promise<UrStoaGuardResult>` →
1664
+ `Promise<UrStoaGuardResult | null>` and **drops the sentinel** `empty
1665
+ = { exists: false, isKeyset: false, keys: [], pred: "" }` value;
1666
+ `null` now means RPC failed, while a real `UrStoaGuardResult` means
1667
+ the chain answered. **3-state preservation** in `getUrStoaGuard` is
1668
+ the locked contract: `null` (RPC failed), `{ exists: false, ... }`
1669
+ (chain confirmed no guard), `{ exists: true, ... }` (chain returned a
1670
+ real guard). `checkCoinAccountExists` widens `Promise<boolean>` →
1671
+ `Promise<boolean | null>` and gains `getLogger().error("Error in
1672
+ checkCoinAccountExists (urStoa):", error)` routing (was silent); JSDoc
1673
+ gains a cross-reference to the `ouroFunctions.ts:2088` sibling that
1674
+ already has the same nullable-boolean shape.
1675
+
1676
+ ```ts
1677
+ // Before (v2.x):
1678
+ const guard = await getUrStoaGuard(account);
1679
+ // guard is always present; "empty" sentinel masks RPC failure
1680
+ if (!guard.exists) renderCreateGuardForm();
1681
+ else renderEditGuardForm(guard);
1682
+
1683
+ // After (v3.x):
1684
+ const guard = await getUrStoaGuard(account);
1685
+ if (guard === null) showRPCError(); // RPC failed
1686
+ else if (!guard.exists) renderCreateGuardForm(); // chain confirmed no guard
1687
+ else renderEditGuardForm(guard); // chain returned a real guard
1688
+ ```
1689
+
1690
+ ### 5. `validateLiquidity` mixed-shape addition
1691
+
1692
+ `validateLiquidity` (REQ-08) **preserves** its existing `valid:
1693
+ boolean` field but adds an optional `error?: string` field on RPC
1694
+ failure. This is the **mixed-shape** locked decision: distinguishing
1695
+ "validation rejected" from "RPC failed" without collapsing both into
1696
+ `valid: false`. Consumers route a populated `error` to the
1697
+ network-failure banner and a `valid: false` with no `error` to the
1698
+ validation-failure message.
1699
+
1700
+ The catch path now routes via `getLogger().error("Error in
1701
+ validateLiquidity:", error)` (preserved from v2.3.0) and sets the
1702
+ `error` field on the returned object.
1703
+
1704
+ ```ts
1705
+ // Before (v2.x):
1706
+ const result = await validateLiquidity(...); // { valid: boolean; ... }
1707
+ if (!result.valid) showValidationFail("Liquidity rejected");
1708
+
1709
+ // After (v3.x):
1710
+ const result = await validateLiquidity(...); // { valid: boolean; error?: string; ... }
1711
+ if (result.error) {
1712
+ showRPCErrorBanner(result.error); // RPC failure
1713
+ } else if (!result.valid) {
1714
+ showValidationFail("Liquidity rejected"); // real validation rejection
1715
+ }
1716
+ ```
1717
+
1718
+ ### 6. `getMaxBuyMovieBooster` — `Promise<number>` → `Promise<number | null>`
1719
+
1720
+ `getMaxBuyMovieBooster` (REQ-08) widens to `Promise<number | null>`,
1721
+ matching the Phase 1 `getPoolTotalFee` pattern exactly. Both `return
1722
+ 0` sites become `return null`; the success-path falsy-collapse (`||
1723
+ 0`) becomes a `Number.isFinite()` guard. A `0` max-buy is a plausible
1724
+ chain return (e.g. when a booster is sold out) — collapsing the
1725
+ fabricated-failure case onto the same `0` made the two states
1726
+ indistinguishable. Existing v2.3.0 logger routing is preserved.
1727
+
1728
+ ```ts
1729
+ // Before (v2.x):
1730
+ const max = await getMaxBuyMovieBooster(); // number — 0 could mean sold-out OR RPC fail
1731
+ if (max === 0) showSoldOut(); // ambiguous
1732
+
1733
+ // After (v3.x):
1734
+ const max = await getMaxBuyMovieBooster();
1735
+ if (max === null) showRPCErrorBanner(); // RPC failed
1736
+ else if (max === 0) showSoldOut(); // chain confirmed sold-out
1737
+ else showAvailable(max); // chain returned real positive max
1738
+ ```
1739
+
1740
+ ### 7. Magic-string elimination — `getSWPSpawnLimit` + `getSWPInactiveLimit`
1741
+
1742
+ `getSWPSpawnLimit` and `getSWPInactiveLimit` (REQ-09) widen from
1743
+ `Promise<string>` (sentinel `"N/A"`) to `Promise<string | null>` per
1744
+ the **magic-string elimination** locked decision. Both `return
1745
+ "N/A"` sites in each function become `return null`; consumers swap
1746
+ `=== "N/A"` checks for `=== null` checks. Both functions also gain
1747
+ `getLogger().error("Error in <funcName>:", error)` routing in their
1748
+ catch paths (was silent).
1749
+
1750
+ ```ts
1751
+ // Before (v2.x):
1752
+ const spawnLimit = await getSWPSpawnLimit(swpair);
1753
+ if (spawnLimit === "N/A") showRPCError();
1754
+ else renderLimit(spawnLimit);
1755
+
1756
+ // After (v3.x):
1757
+ const spawnLimit = await getSWPSpawnLimit(swpair);
1758
+ if (spawnLimit === null) showRPCError();
1759
+ else renderLimit(spawnLimit);
1760
+ ```
1761
+
1762
+ ### Phase 3 logger-routing additions — no consumer migration required
1763
+
1764
+ The 14 NON-BREAKING logger-routing additions across 5 files
1765
+ (`dexFunctions.ts`, `ouroFunctions.ts`, `activateFunctions.ts`,
1766
+ `infoOneFunctions.ts`, and the `urStoaFunctions.ts` private helpers
1767
+ `verifyEd25519Sig` + `describeKeyset`) are pure observability —
1768
+ return types and parameter signatures are unchanged. Consumers who
1769
+ called `setLogger(...)` (introduced in v2.3.0) automatically capture
1770
+ the new error events with no additional wiring; consumers who did
1771
+ not configure a logger continue to see the default `console.error`
1772
+ output that the seam falls back to. No migration is required for
1773
+ this set of changes.
1774
+
1775
+ ## Migrating to v2.x
1776
+
1777
+ Two breaking changes shipped in v2.0.0 — both consumer-side, no
1778
+ internal call sites in `src/` are affected.
1779
+
1780
+ ### 1. `KadenaWallet` requires a `balanceResolver` to fetch balances
1781
+
1782
+ The `wallet/` subpath no longer imports from `interactions/*` (closes
1783
+ F-CORE-005). The `KadenaWallet` class now exposes a publicly mutable
1784
+ `balanceResolver: BalanceResolver` instance property. The default is a
1785
+ lazy throwing stub — it fires only when `wallet.getBalance()` is
1786
+ actually called, so wallets used purely for address derivation stay
1787
+ zero-config.
1788
+
1789
+ ```ts
1790
+ import KadenaWallet from "@ouronet/ouronet-core/wallet";
1791
+ import { getBalance } from "@ouronet/ouronet-core/interactions/kadenaFunctions";
1792
+
1793
+ const wallet = new KadenaWallet({
1794
+ parentId: 0, index: 0,
1795
+ secret: ..., publicKey: ..., derivationPath: "m/44'/...",
1796
+ // Wrap interactions.getBalance to match the
1797
+ // (address) => Promise<string> contract:
1798
+ balanceResolver: (addr) => getBalance(addr).then((r) => r.balance ?? "0"),
1799
+ });
1800
+
1801
+ // Or assign post-construction:
1802
+ wallet.balanceResolver = (addr) => myIndexer.balanceOf(addr);
1803
+ ```
1804
+
1805
+ `wallet.getBalance()` now **propagates errors** — the previous
1806
+ `?? "0"` silent fallback is gone (mildly breaking behavioural shift).
1807
+ Wrap the call in `try/catch`, or have your resolver default-on-error
1808
+ return `"0"`.
1809
+
1810
+ ### 2. `simulateTransaction(pactCode, chainId)` signature change
1811
+
1812
+ `interactions/crossChainFunctions.simulateTransaction` previously
1813
+ accepted a pre-built `IUnsignedCommand` transaction object. It now
1814
+ accepts the Pact code string directly:
1815
+
1816
+ ```ts
1817
+ // Before (v1.x):
1818
+ const tx = Pact.builder.execution(code).setMeta(...).createTransaction();
1819
+ const result = await simulateTransaction(tx, chainId);
1820
+
1821
+ // After (v2.x):
1822
+ const result = await simulateTransaction(code, chainId);
1823
+ ```
1824
+
1825
+ The return shape `{ success, result?, error?, gas? }` is unchanged.
1826
+
1827
+ ## Design docs
1828
+
1829
+ The architectural plan, per-phase migration history, HUB handoff, and
1830
+ decision log live in the **OuronetUI repo** under `docs/`:
1831
+
1832
+ - [`EXTRACT_OURONET_CORE_PLAN.md`](https://github.com/DemiourgosHoldings/OuronetUI/blob/dev/docs/EXTRACT_OURONET_CORE_PLAN.md) — the 8-phase migration plan (now complete)
1833
+ - [`ANCIENTHOLDER_HUB_HANDOFF.md`](https://github.com/DemiourgosHoldings/OuronetUI/blob/dev/docs/ANCIENTHOLDER_HUB_HANDOFF.md) — what the HUB agent needs to know to integrate
1834
+ - [`TESTING_STRATEGY.md`](https://github.com/DemiourgosHoldings/OuronetUI/blob/dev/docs/TESTING_STRATEGY.md) — 3-tier testing approach + current state + roadmap
1835
+ - [`CFM_BUILD_GUIDE.md`](https://github.com/DemiourgosHoldings/OuronetUI/blob/dev/docs/CFM_BUILD_GUIDE.md) — how a CFM modal uses this package
1836
+
1837
+ Don't fork logic — add to core, version-bump, publish, and consumers
1838
+ upgrade deliberately.
1839
+
1840
+ ## Submodules
1841
+
1842
+ Each is a subpath export of the package: `import { ... } from "@ouronet/ouronet-core/<submodule>"`.
1843
+
1844
+ | Path | Contains |
1845
+ |---|---|
1846
+ | `@ouronet/ouronet-core/constants` | `KADENA_NAMESPACE`, `KADENA_CHAIN_ID`, `KADENA_NETWORK`, `PACT_URL`, gas-station + liquidpot addresses, every `TOKEN_ID_*` |
1847
+ | `@ouronet/ouronet-core/network` | Node failover (node2 → node1), URL construction; **(v2.1.0+)** `getFailoverClient(chainId, options?)` factory returning `{ dirtyRead, submit, listen, pollOne }` with `withFailover` + per-tier timeout baked in, `runWithTimeout(operation, fn, timeoutMs)` helper, `FailoverClientOptions` type, `resetNodeFailover()` for test isolation |
1848
+ | `@ouronet/ouronet-core/gas` | `calculateAutoGasLimit`, ANU/STOA math |
1849
+ | `@ouronet/ouronet-core/guard` | `analyzeGuard`, `buildCodexPubSet`, `selectCapsSigningKey`, `computeThreshold` (all predicates including `stoa-ns.stoic-predicates.*`); **(v1.6.0+)** `classifyGuardKind`, `extractKeysetFromGuard`, `analyzeSmartAccountAuthPaths` for the Smart Ouronet Account three-branch auth-path resolution (`enforce-one` over account-guard / sovereign-guard / governor) |
1850
+ | `@ouronet/ouronet-core/crypto` | V1 + V2 AES-GCM-256 encryption, `smartDecrypt`, pure `smartEncrypt(pt, pw, schemaVersion)`; **(v2.2.0+)** typed error classes `WrongPasswordError`, `CorruptEnvelopeError`, `UnsupportedFormatError` discriminate decryption failure modes; `smartDecrypt` single-path dispatch eliminates v1-then-v2 timing-leak |
1851
+ | `@ouronet/ouronet-core/signing` | `KeyResolver` / `SigningStrategy` interfaces, `CodexSigningStrategy`, `universalSignTransaction`, signing primitives (`publicKeyFromPrivateKey`, etc.) |
1852
+ | `@ouronet/ouronet-core/codex` | `PlaintextCodex` generic type, `serializeCodex` / `deserializeCodex` (backup format `"1.2"`), `migrateSeedType` |
1853
+ | `@ouronet/ouronet-core/reads` | `rawCalibratedDirtyRead` (pure Pact read with node failover + 15s timeout; no cache); **(v2.1.0+)** accepts a `readTimeoutMs?: number` option for per-call timeout override; **(v2.3.0+)** JSDoc enumerates the canonical tier mapping (T1=balance, T2=preview, T3=metadata, T7=very-static) and documents that the default reader accepts and ignores the `tier` argument — see `setPactReader` for cache-aware consumers |
1854
+ | `@ouronet/ouronet-core/observability` | **(v2.3.0+)** central logger seam mirroring `setPactReader`. Exports `Logger` type (`{ warn(msg, ...args), error(msg, ...args) }`), `setLogger(logger)` mutator (throws `TypeError("setLogger requires a non-null Logger")` on null/undefined), `getLogger()` accessor. Default routes `warn` to `console.warn` and `error` to `console.error` — consumers who do nothing observe identical behavior to direct `console.*` calls. |
1855
+ | `@ouronet/ouronet-core/guard` | **(v2.3.0+)** `UnknownPredicateError` typed class — thrown by `computeThreshold` on unrecognized predicates; `analyzeGuard` catches it and folds it into a `predicateRecognized: false` bit on the returned analysis. Also adds optional `firstSignableButUnsatisfied: number` field on `SmartAccountAuthPathsAnalysis`. |
1856
+ | `@ouronet/ouronet-core/pact` | `formatDecimalForPact`, `safeCreationTime`, `filterFreePositionData`, EU locale formatters, and **14 `buildXxxPactCode` builders** for every CFM function the ecosystem ships |
1857
+ | `@ouronet/ouronet-core/interactions` | Read helpers (`getXxxInfo`, `getXxxBalance`, `getHibernatedNonces…`) + non-CFM execute helpers (`executeWrapStoa`, `executeWrapUrStoa`, `executeNativeUrStoaTransfer`); **(v2.0.0+)** `simulateTransaction(pactCode, chainId)` (signature change — see Migrating to v2.x); **(v3.0.0+)** 16 fabricated-fallback fabrications widened to `Promise<T \| null>` (BREAKING — see Migrating to v3.x); 14 logger-routing additions across 5 files complete the silent-catch elimination (NON-BREAKING) |
1858
+ | `@ouronet/ouronet-core/dalos` | **(v1.3.0+)** thin re-export of `@ouronet/dalos-crypto/registry` + `createOuronetAccount(registry, options)` convenience helper covering all 6 DALOS input modes. One-stop shop for browser-side key-gen; no need to install `dalos-crypto` as a separate dep. **(v3.1.0+)** dep range bumped to `@ouronet/dalos-crypto@^4.0.3`; re-exports the lower-level Schnorr signature surface (`schnorrSign`, `schnorrVerify`, `schnorrSignAsync`, `schnorrVerifyAsync`, `SchnorrSignError`, `SchnorrSignature`) for advanced consumers — the `*Async` variants yield to the event loop on a fixed data-independent cadence so browser signing keeps INP < 200ms. |
1859
+
1860
+ ## Quick start — `/dalos` subpath
1861
+
1862
+ Mint a new Ouronet account locally in one call:
1863
+
1864
+ ```ts
1865
+ import {
1866
+ createDefaultRegistry,
1867
+ createOuronetAccount,
1868
+ } from "@ouronet/ouronet-core/dalos";
1869
+
1870
+ const registry = createDefaultRegistry();
1871
+
1872
+ // Random account (simplest — OS randomness)
1873
+ const a = createOuronetAccount(registry, { mode: "random" });
1874
+
1875
+ // From a seed phrase (any array of UTF-8 words, 4–256 entries)
1876
+ const b = createOuronetAccount(registry, {
1877
+ mode: "seedWords",
1878
+ data: ["mountain", "whisper", "aurora", "eternal"],
1879
+ });
1880
+
1881
+ // From a 40×40 bitmap (1 = black, 0 = white; row-major TTB-LTR)
1882
+ import type { Bitmap } from "@ouronet/ouronet-core/dalos";
1883
+ const bitmap: Bitmap = /* 40 rows × 40 cols */;
1884
+ const c = createOuronetAccount(registry, { mode: "bitmap", data: bitmap });
1885
+
1886
+ console.log(b.standardAddress); // Ѻ.xxxxx…
1887
+ console.log(b.keyPair.priv); // base-49 private key
1888
+ console.log(b.privateKey.int49); // same, via `privateKey` object
1889
+ console.log(b.privateKey.int10); // base-10 representation
1890
+ console.log(b.privateKey.bitString); // 1600-bit binary
1891
+ ```
1892
+
1893
+ Same API shape as `@ouronet/dalos-crypto/registry` — OuronetCore just
1894
+ re-exports the types and adds `createOuronetAccount` as a convenience.
1895
+ See [`@ouronet/dalos-crypto`](https://www.npmjs.com/package/@ouronet/dalos-crypto)
1896
+ for deeper documentation on the cryptographic primitive itself.
1897
+
1898
+ ## Local development
1899
+
1900
+ ```bash
1901
+ npm install
1902
+ npm run build # tsc -p tsconfig.build.json → dist/
1903
+ npm run typecheck # tsc --noEmit
1904
+ npm test # vitest run — 558 tests across crypto, guard, gas, pact format, signing, strategy, codex, cfmBuilders, dalos integration, wallet, interactions-read-seam, network, failover-client, timeouts, failover-submit, pact-reader, wallet-builder, transaction-errors, seed-type-migration, crypto-errors, crypto-v2-classification, package-version, observability-logger, phase5-catch-routing, interactions-pricing, interactions-balance-cluster, interactions-logger-parity
1905
+ ```
1906
+
1907
+ To hot-reload changes into OuronetUI (which now depends on the published
1908
+ registry version), use `npm link`:
1909
+
1910
+ ```bash
1911
+ cd stoa-js && npm link
1912
+ cd OuronetUI && npm link @ouronet/ouronet-core
1913
+ # Edit core, run `npm run build` in stoa-js, UI picks up the change.
1914
+ # npm unlink @ouronet/ouronet-core # restores registry resolution
1915
+ ```
1916
+
1917
+ ## Publishing
1918
+
1919
+ Push a `v*`-prefixed tag and `.github/workflows/publish.yml` handles the
1920
+ rest — typecheck + build + test + `npm publish` to **public npmjs.org**
1921
+ under the `@stoachain` scope. Version parity check bakes in protection
1922
+ against mismatched tag / package.json versions.
1923
+
1924
+ ```bash
1925
+ # After bumping package.json + CHANGELOG.md and committing:
1926
+ git tag v1.3.1 -m "v1.3.1 — ..."
1927
+ git push origin v1.3.1
1928
+ # Workflow publishes within ~2 minutes. Consumers run `npm install` to pick up.
1929
+ ```
1930
+
1931
+ ## Versioning
1932
+
1933
+ Strict semver. Breaking changes → major version bump → consumers upgrade
1934
+ deliberately. Changelog in `CHANGELOG.md`.
1935
+
1936
+ ## License
1937
+
1938
+ UNLICENSED (org-owned package). Public on
1939
+ [npmjs.com/package/@ouronet/ouronet-core](https://www.npmjs.com/package/@ouronet/ouronet-core);
1940
+ authoring rights retained by AncientHoldings GmbH.