@ouronet/ouronet-core 4.4.0 → 4.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,90 @@ All notable changes to `@ouronet/ouronet-core`.
|
|
|
4
4
|
|
|
5
5
|
This package is the historical continuation of `@ouronet/ouronet-core` v0.x–v3.3.8. v4.0.0 split it into a two-package npm workspace under `StoaChain/stoa-js` — chain-generic infrastructure moved out into [`@stoachain/stoa-core`](https://www.npmjs.com/package/@stoachain/stoa-core), this package retained the Ouronet-specific business logic. The `4.0.0` heading below is the first release after the split.
|
|
6
6
|
|
|
7
|
+
## 4.5.1 — 2026-09-07
|
|
8
|
+
|
|
9
|
+
**PATCH — the two rotation executors were submitting underpriced transactions.**
|
|
10
|
+
|
|
11
|
+
### What was broken
|
|
12
|
+
|
|
13
|
+
`guardFunctions.rotateGuard` and `ouroRotateFunctions.rotateKadenaPaymentKey` set
|
|
14
|
+
`creationTime` in `setMeta` but never set `gasPrice`. The vendored client fills the gap with
|
|
15
|
+
its own default of `1.0e-8` — which is exactly the Yin Engine's **genesis** floor of 10,000
|
|
16
|
+
ANU. The floor has risen 1 ANU every 3 hours since 2026-02-23, so from its first tick onward
|
|
17
|
+
both rotations were built below the chain-wide minimum price and rejected as underpriced.
|
|
18
|
+
|
|
19
|
+
Paying via the Gas Station does not exempt a transaction from this: `DALOS.GAS_PAYER` decides
|
|
20
|
+
*who* pays, not *how little*. The minimum-price rule is evaluated before the payer guard runs,
|
|
21
|
+
so a well-funded `STOA_AUTONOMIC_OURONETGASSTATION` made no difference.
|
|
22
|
+
|
|
23
|
+
This is the same live-gas-floor defect 4.5.0 fixed in `crossChainFunctions.ts`; these two files
|
|
24
|
+
were not part of that change. User-visible symptom: Codex's **Rotate Guard** and **Rotate
|
|
25
|
+
Payment Key** modals failing at submit.
|
|
26
|
+
|
|
27
|
+
### What changed
|
|
28
|
+
|
|
29
|
+
Both `setMeta` calls now spread the same `stoaGasMeta()` helper 4.5.0 introduced, which returns
|
|
30
|
+
`{ creationTime, gasPrice }` from a **single clock read** — the price is derived from the exact
|
|
31
|
+
`creationTime` that ships in the command, so the two can never disagree. The ANU → STOA
|
|
32
|
+
conversion is string-padding-built (`"0." + String(anu).padStart(12, "0")`), never float
|
|
33
|
+
division, so the value stays exact at 12 decimals.
|
|
34
|
+
|
|
35
|
+
The helper is a **temporary local duplicate** — the third copy in this repo, after
|
|
36
|
+
`crossChainFunctions.ts` and OuronetUI's `src/lib/gas-price.ts`. All copies carry the same
|
|
37
|
+
constants (genesis 10,000 ANU at `1771869600`, +1 ANU per 3 h, capped at 400,000 ANU) and all
|
|
38
|
+
should be deleted together once `@stoachain/stoa-core/gas` ships the formula; it still exports
|
|
39
|
+
only the static `GAS_PRICE_MIN_ANU = 10_000`.
|
|
40
|
+
|
|
41
|
+
**Note for auditors:** 17 other `interactions/*` files call `setMeta` without a `gasPrice` and
|
|
42
|
+
are underpriced by the same mechanism. They are out of scope for this patch and unfixed.
|
|
43
|
+
|
|
44
|
+
### Verification
|
|
45
|
+
|
|
46
|
+
New `tests/v4-5-1-rotation-gas-price.test.ts` locks the behaviour for both executors (12
|
|
47
|
+
specs): price tracks the live floor, is derived from the shipped `creationTime`, holds at the
|
|
48
|
+
genesis floor at tick 0, caps at 400,000 ANU, stays exact at 12 decimals, and matches between
|
|
49
|
+
the simulated build and the auto-gas-limit rebuild. Confirmed non-vacuous — 8 of the 12 fail
|
|
50
|
+
against the pre-fix source.
|
|
51
|
+
|
|
52
|
+
Non-breaking. No exported signatures changed. **800 specs pass.**
|
|
53
|
+
|
|
54
|
+
## 4.5.0 — 2026-09-07
|
|
55
|
+
|
|
56
|
+
**MINOR — cross-chain gas payer switched to `stoa-xchain-gas`; live Yin-Engine gas pricing.**
|
|
57
|
+
|
|
58
|
+
### What changed
|
|
59
|
+
|
|
60
|
+
`crossChainFunctions.ts`'s non-chain-0 gas payer moves off the legacy `kadena-xchain-gas`
|
|
61
|
+
account (a static `gasPrice <= 0.00000001` / `gasLimit <= 850` guard) onto StoaChain's own
|
|
62
|
+
`stoa-xchain-gas` account. Its guard (`pact/genesis/stoa/stoa-genesis-5.pact`) requires
|
|
63
|
+
`gasPrice <= UC_MinimumGasPriceANU()` — a **live floor**, not a fixed ceiling — so a hardcoded
|
|
64
|
+
price would eventually either be rejected by this guard's ceiling (once the floor rises above
|
|
65
|
+
whatever was hardcoded, that part is safe) or, more importantly, fall **below** the chain-wide
|
|
66
|
+
minimum price the Yin Engine enforces post-fork.
|
|
67
|
+
|
|
68
|
+
All four `gasPrice` call sites in this file now derive `{ creationTime, gasPrice }` from a
|
|
69
|
+
single local Yin-Engine helper instead of a hardcoded number or the static `GAS_PRICE_MIN_ANU`:
|
|
70
|
+
|
|
71
|
+
- `buildCrossChainTransfer` (legacy single-step `coin.transfer-crosschain`, self-paid gas)
|
|
72
|
+
- `buildCTransferAcross` — chain-0 branch (`DALOS.GAS_PAYER`, previously on the static
|
|
73
|
+
`anuToStoa(GAS_PRICE_MIN_ANU)`)
|
|
74
|
+
- `buildCTransferAcross` — non-chain-0 branch (now `stoa-xchain-gas`, was `kadena-xchain-gas`)
|
|
75
|
+
- `buildContinuationTransaction` — default `gasPayerAccount` (now `stoa-xchain-gas`)
|
|
76
|
+
|
|
77
|
+
The Yin-Engine helper is a **temporary local duplicate** of OuronetUI's `src/lib/gas-price.ts`
|
|
78
|
+
(same constants, same formula — genesis 10,000 ANU, +1 ANU/3h, capped at 400,000 ANU). It
|
|
79
|
+
belongs in `@stoachain/stoa-core/gas` once that package ships the same formula; that package
|
|
80
|
+
currently still only exports the static `GAS_PRICE_MIN_ANU = 10_000`. Consolidate then.
|
|
81
|
+
|
|
82
|
+
### Verification
|
|
83
|
+
|
|
84
|
+
Confirmed against a live StoaChain node (not just simulated): both the initial
|
|
85
|
+
`C_TransferAcross` (chain-0, `DALOS.GAS_PAYER`) and the `stoa-xchain-gas`-paid continuation
|
|
86
|
+
landed successfully at **11,565 ANU/gas**, the live floor at time of testing.
|
|
87
|
+
|
|
88
|
+
Non-breaking. No exported function signatures changed — only the default `gasPayerAccount`
|
|
89
|
+
value and the internal price derivation. **787 specs pass.**
|
|
90
|
+
|
|
7
91
|
## 4.4.0 — 2026-07-22
|
|
8
92
|
|
|
9
93
|
**MINOR — the codex writer is held at `"1.2"` while the reader keeps accepting `"1.2"` and `"1.3"`.**
|
package/README.md
CHANGED
|
@@ -23,6 +23,10 @@ Chain-generic infrastructure (signing, wallet, crypto, network failover, gas, gu
|
|
|
23
23
|
|
|
24
24
|
## Status
|
|
25
25
|
|
|
26
|
+
**`4.5.1` on public npmjs** — **PATCH (the two rotation executors were submitting underpriced transactions).** Released 2026-09-07. `guardFunctions.rotateGuard` and `ouroRotateFunctions.rotateKadenaPaymentKey` set `creationTime` but never set `gasPrice`, so the vendored client stamped its `1.0e-8` default — exactly the Yin Engine's *genesis* floor of 10,000 ANU. Since the floor rises 1 ANU every 3 hours, both rotations were built below the chain-wide minimum price and rejected as underpriced from the floor's first tick onward. Gas-Station payment is no exemption: `DALOS.GAS_PAYER` decides *who* pays, not *how little*, and the minimum-price rule runs before the payer guard. Same defect 4.5.0 fixed in `crossChainFunctions.ts`; these two files were not part of that change. Both `setMeta` calls now spread the same `stoaGasMeta()` helper — `{ creationTime, gasPrice }` from a single clock read, with a padding-built (never float-divided) ANU → STOA conversion. New `tests/v4-5-1-rotation-gas-price.test.ts` locks it with 12 specs, 8 of which fail against the pre-fix source. Note for auditors: 17 other `interactions/*` files call `setMeta` without a `gasPrice` and remain underpriced by the same mechanism — out of scope here. Non-breaking — no exported signatures changed. **800 specs pass.**
|
|
27
|
+
|
|
28
|
+
**`4.5.0` on public npmjs** — **MINOR (cross-chain gas payer switched to `stoa-xchain-gas`; live Yin-Engine gas pricing).** Released 2026-09-07. `crossChainFunctions.ts`'s non-chain-0 gas payer moves off the legacy `kadena-xchain-gas` account (a static `gasPrice <= 0.00000001` / `gasLimit <= 850` guard) onto StoaChain's own `stoa-xchain-gas` account, whose guard (`pact/genesis/stoa/stoa-genesis-5.pact`) requires `gasPrice <= UC_MinimumGasPriceANU()` — a *live floor*, not a fixed ceiling. All four `gasPrice` call sites in this file (the legacy `buildCrossChainTransfer`, both `buildCTransferAcross` branches — including the chain-0 `DALOS.GAS_PAYER` path, previously on the static `GAS_PRICE_MIN_ANU` — and `buildContinuationTransaction`'s default payer) now derive `{ creationTime, gasPrice }` from a local Yin-Engine helper instead of a hardcoded price. That helper is a temporary duplicate of OuronetUI's `src/lib/gas-price.ts` — it belongs in `@stoachain/stoa-core/gas` once that package ships the same formula (it currently still exports only the static `GAS_PRICE_MIN_ANU = 10_000`); consolidate then. Verified against a live StoaChain node: both the initial `C_TransferAcross` (chain-0, `DALOS.GAS_PAYER`) and the `stoa-xchain-gas`-paid continuation landed successfully at 11,565 ANU/gas. Non-breaking — no exported signatures changed, only the default `gasPayerAccount` value and the internal price derivation. **787 specs pass.**
|
|
29
|
+
|
|
26
30
|
**`4.4.0` on public npmjs** — **MINOR (codec writer held at 1.2; reader still accepts 1.2 and 1.3).** Released 2026-07-22. Corrects 4.3.6/4.3.7, which shipped an unreleased 1.3 *writer* and so produced backups that apps on a 1.2-only reader could not open. The reader is unchanged and still accepts both, so any 1.3 file already written stays readable; the writer stamps 1.2 again. Nothing is lost — this writer never emitted the 1.3-only `foreignKeys` block. Those two versions are deprecated and point here. **787 specs pass.**
|
|
27
31
|
|
|
28
32
|
**`4.3.7` on public npmjs** — **PATCH (chain-peer realignment with `@stoachain/stoa-core@4.3.7` + `@stoachain/kadena-stoic-legacy@4.3.7`).** Released 2026-07-22. NO code changes in this package. The exact chain peers move 4.3.6 → 4.3.7 so consumers resolving the current chain layer get a satisfiable tree; stoa-js 4.3.7 repointed DALOS onto `@ouronet/dalos-crypto@4.0.4`. **785 specs pass.**
|
|
@@ -45,6 +49,10 @@ Chain-generic infrastructure (signing, wallet, crypto, network failover, gas, gu
|
|
|
45
49
|
|
|
46
50
|
**`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.
|
|
47
51
|
|
|
52
|
+
**v4.5.1** — live Yin-Engine gas pricing for the two rotation executors (`rotateGuard`, `rotateKadenaPaymentKey`). Released 2026-09-07. Both omitted `gasPrice` entirely and inherited the client's `1.0e-8` genesis-floor default, so every rotation submitted after the floor's first tick was rejected as underpriced. No signature changes. **800 specs pass.**
|
|
53
|
+
|
|
54
|
+
**v4.5.0** — cross-chain gas payer switched to `stoa-xchain-gas` with live Yin-Engine pricing (replaces the legacy `kadena-xchain-gas` static ceiling). Released 2026-09-07. All four `gasPrice` sites in `crossChainFunctions.ts` now derive price from the current Yin floor instead of a hardcoded value; verified landing on a live StoaChain node at 11,565 ANU/gas. No signature changes. **787 specs pass.**
|
|
55
|
+
|
|
48
56
|
**v4.4.0** — codec writer held at `"1.2"`; reader still accepts `"1.2"` and `"1.3"`. Released 2026-07-22. Corrects the 4.3.6/4.3.7 mispublish, which shipped an unreleased 1.3 writer under version numbers the old `@stoachain` package had already used. **787 specs pass.**
|
|
49
57
|
|
|
50
58
|
**v4.3.7** — chain-peer realignment bump (exact peers on `@stoachain/stoa-core@4.3.7` + `@stoachain/kadena-stoic-legacy@4.3.7`). Released 2026-07-22. NO code changes. Required because this package pins its chain peers exactly and stoa-js now releases independently. **785 specs pass.**
|
|
@@ -53,7 +53,7 @@ export interface CTransferAcrossParams {
|
|
|
53
53
|
* Build a coin.C_TransferAcross transaction (step 0 of cross-chain transfer).
|
|
54
54
|
*
|
|
55
55
|
* Chain 0: Gas paid by Ouronet Gas Station (DALOS.GAS_PAYER).
|
|
56
|
-
* Other chains: Gas paid by
|
|
56
|
+
* Other chains: Gas paid by stoa-xchain-gas (unsigned).
|
|
57
57
|
*/
|
|
58
58
|
export declare function buildCTransferAcross(params: CTransferAcrossParams): any;
|
|
59
59
|
/**
|
|
@@ -1,9 +1,49 @@
|
|
|
1
1
|
import { Pact } from "@stoachain/kadena-stoic-legacy/client";
|
|
2
2
|
import { getFailoverClient, withFailover } from "@stoachain/stoa-core/network";
|
|
3
3
|
import { KADENA_NETWORK, getPactUrl, STOA_AUTONOMIC_OURONETGASSTATION, KADENA_NAMESPACE } from "../constants/index.js";
|
|
4
|
-
import { GAS_PRICE_MIN_ANU, anuToStoa } from "@stoachain/stoa-core/gas";
|
|
5
4
|
import { pactRead } from "@stoachain/stoa-core/reads";
|
|
6
5
|
import { safeCreationTime, formatDecimalForPact } from "@stoachain/stoa-core/pact";
|
|
6
|
+
/**
|
|
7
|
+
* Yin Engine — StoaChain's time-varying minimum gas price.
|
|
8
|
+
*
|
|
9
|
+
* TEMPORARY LOCAL COPY. This mirrors `OuronetUI/src/lib/gas-price.ts` exactly
|
|
10
|
+
* (same constants, same formula) because `@stoachain/stoa-core/gas` has not
|
|
11
|
+
* yet been upgraded past the static `GAS_PRICE_MIN_ANU = 10_000`. It belongs
|
|
12
|
+
* there long-term (chain-generic, not Ouronet-specific) — consolidate this
|
|
13
|
+
* away once stoa-core ships it.
|
|
14
|
+
*
|
|
15
|
+
* The floor starts at 10,000 ANU at genesis and rises by 1 ANU every 3 hours,
|
|
16
|
+
* capped at 400,000 ANU. Source of truth: `UC_MinimumGasPriceANU` in
|
|
17
|
+
* `pact/stoa-coin/new-coin.pact` (evaluated against `(at "block-time"
|
|
18
|
+
* (chain-data))` on-chain — creationTime is a close client-side proxy for it).
|
|
19
|
+
*
|
|
20
|
+
* `stoa-xchain-gas`'s own guard (`pact/genesis/stoa/stoa-genesis-5.pact`)
|
|
21
|
+
* requires `gasPrice <= UC_MinimumGasPriceANU()` (an upper bound, not a
|
|
22
|
+
* floor) — combined with the chain-wide "must be >= the floor" rule, the
|
|
23
|
+
* only value that satisfies both is the floor itself. Never overpay this
|
|
24
|
+
* account; it pays minimum-priced redemptions only.
|
|
25
|
+
*/
|
|
26
|
+
const YIN_GENESIS_TIME_S = 1771869600; // 2026-02-23T18:00:00Z — tick 0
|
|
27
|
+
const YIN_GENESIS_MIN_GAS_ANU = 10000;
|
|
28
|
+
const YIN_MAX_GAS_ANU = 400000;
|
|
29
|
+
const YIN_GAS_PRICE_INTERVAL_S = 10800; // 3 h per tick
|
|
30
|
+
function minGasPriceAnu(creationTimeS) {
|
|
31
|
+
const elapsed = creationTimeS - YIN_GENESIS_TIME_S;
|
|
32
|
+
const ticks = elapsed <= 0 ? 0 : Math.floor(elapsed / YIN_GAS_PRICE_INTERVAL_S);
|
|
33
|
+
return Math.min(YIN_GENESIS_MIN_GAS_ANU + ticks, YIN_MAX_GAS_ANU);
|
|
34
|
+
}
|
|
35
|
+
/** Built by string padding, never float division — avoids exponential notation / precision loss. */
|
|
36
|
+
function anuToStoaNumber(anu) {
|
|
37
|
+
return Number("0." + String(anu).padStart(12, "0"));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* One clock read: the `creationTime` to stamp and the `gasPrice` derived
|
|
41
|
+
* FROM THAT EXACT VALUE, so the two can never disagree.
|
|
42
|
+
*/
|
|
43
|
+
function stoaGasMeta() {
|
|
44
|
+
const creationTime = safeCreationTime();
|
|
45
|
+
return { creationTime, gasPrice: anuToStoaNumber(minGasPriceAnu(creationTime)) };
|
|
46
|
+
}
|
|
7
47
|
/**
|
|
8
48
|
* Get KDA balance for an account on a specific chain.
|
|
9
49
|
* exists=false means the account row does not exist on that chain (not just zero balance).
|
|
@@ -72,20 +112,17 @@ export function buildCrossChainTransfer(params) {
|
|
|
72
112
|
.setMeta({
|
|
73
113
|
chainId: sourceChain,
|
|
74
114
|
senderAccount: sender,
|
|
75
|
-
// v3.2.3:
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
// every other setMeta block (including `buildCTransferAcross` two
|
|
84
|
-
// functions below) already includes it.
|
|
85
|
-
creationTime: safeCreationTime(),
|
|
115
|
+
// v3.2.3: `creationTime` closes audit finding F-BUG-002 — without it
|
|
116
|
+
// `@kadena/client` falls back to raw current time and a client clock
|
|
117
|
+
// slightly ahead of node time gets sporadic submit failures.
|
|
118
|
+
// `stoaGasMeta()` supplies both `creationTime` (via `safeCreationTime()`)
|
|
119
|
+
// and the `gasPrice` derived from that exact value, per the Yin Engine
|
|
120
|
+
// (see the module-level comment above) — the chain-wide minimum price
|
|
121
|
+
// rises over time, so a hardcoded `gasPrice` would eventually be
|
|
122
|
+
// rejected as underpriced.
|
|
86
123
|
gasLimit: 2500,
|
|
87
|
-
gasPrice: 0.00000001,
|
|
88
124
|
ttl: 28800,
|
|
125
|
+
...stoaGasMeta(),
|
|
89
126
|
})
|
|
90
127
|
.setNetworkId(KADENA_NETWORK)
|
|
91
128
|
.createTransaction();
|
|
@@ -95,7 +132,7 @@ export function buildCrossChainTransfer(params) {
|
|
|
95
132
|
* Build a coin.C_TransferAcross transaction (step 0 of cross-chain transfer).
|
|
96
133
|
*
|
|
97
134
|
* Chain 0: Gas paid by Ouronet Gas Station (DALOS.GAS_PAYER).
|
|
98
|
-
* Other chains: Gas paid by
|
|
135
|
+
* Other chains: Gas paid by stoa-xchain-gas (unsigned).
|
|
99
136
|
*/
|
|
100
137
|
export function buildCTransferAcross(params) {
|
|
101
138
|
const { sender, receiver, receiverGuard, amount, sourceChain, targetChain, senderPublicKey, gasStationPublicKey, } = params;
|
|
@@ -118,18 +155,19 @@ export function buildCTransferAcross(params) {
|
|
|
118
155
|
.setMeta({
|
|
119
156
|
chainId: "0",
|
|
120
157
|
senderAccount: STOA_AUTONOMIC_OURONETGASSTATION,
|
|
121
|
-
creationTime: safeCreationTime(),
|
|
122
158
|
gasLimit: 2500,
|
|
123
|
-
gasPrice: anuToStoa(GAS_PRICE_MIN_ANU),
|
|
124
159
|
ttl: 28800,
|
|
160
|
+
...stoaGasMeta(),
|
|
125
161
|
})
|
|
126
162
|
.setNetworkId(KADENA_NETWORK)
|
|
127
163
|
.createTransaction();
|
|
128
164
|
}
|
|
129
165
|
else {
|
|
130
|
-
// Non-chain-0:
|
|
166
|
+
// Non-chain-0: stoa-xchain-gas pays gas (StoaChain's own xchain gas
|
|
167
|
+
// station — replaces the legacy `kadena-xchain-gas` account).
|
|
131
168
|
// Its guard uses coin.gas-only (no signature needed) BUT requires:
|
|
132
|
-
// - gasPrice <=
|
|
169
|
+
// - gasPrice <= UC_MinimumGasPriceANU() (the live Yin floor — an upper
|
|
170
|
+
// bound, not a static ceiling; see the module-level comment above)
|
|
133
171
|
// - gasLimit <= 850
|
|
134
172
|
// No signer needed for gas — only sender signs TRANSFER_XCHAIN cap.
|
|
135
173
|
return Pact.builder
|
|
@@ -140,10 +178,10 @@ export function buildCTransferAcross(params) {
|
|
|
140
178
|
])
|
|
141
179
|
.setMeta({
|
|
142
180
|
chainId: sourceChain,
|
|
143
|
-
senderAccount: "
|
|
144
|
-
gasLimit: 850, // must be
|
|
145
|
-
gasPrice: 0.00000001, // must be ≤ 0.00000001 for kadena-xchain-gas guard
|
|
181
|
+
senderAccount: "stoa-xchain-gas",
|
|
182
|
+
gasLimit: 850, // must be <= 850 for the stoa-xchain-gas guard
|
|
146
183
|
ttl: 28800,
|
|
184
|
+
...stoaGasMeta(),
|
|
147
185
|
})
|
|
148
186
|
.setNetworkId(KADENA_NETWORK)
|
|
149
187
|
.createTransaction();
|
|
@@ -326,7 +364,7 @@ export async function pollSpvProof(requestKey, sourceChain, targetChain, maxAtte
|
|
|
326
364
|
* Build a continuation transaction for step 2 of cross-chain transfer
|
|
327
365
|
* This can be executed by anyone - no signature required from original sender
|
|
328
366
|
*/
|
|
329
|
-
export function buildContinuationTransaction(pactId, proof, targetChain, gasPayerAccount = "
|
|
367
|
+
export function buildContinuationTransaction(pactId, proof, targetChain, gasPayerAccount = "stoa-xchain-gas") {
|
|
330
368
|
const transaction = Pact.builder
|
|
331
369
|
.continuation({
|
|
332
370
|
pactId,
|
|
@@ -337,9 +375,9 @@ export function buildContinuationTransaction(pactId, proof, targetChain, gasPaye
|
|
|
337
375
|
.setMeta({
|
|
338
376
|
chainId: targetChain,
|
|
339
377
|
senderAccount: gasPayerAccount,
|
|
340
|
-
gasLimit: 850,
|
|
341
|
-
gasPrice: 0.00000001,
|
|
378
|
+
gasLimit: 850, // must be <= 850 for the stoa-xchain-gas guard
|
|
342
379
|
ttl: 28800,
|
|
380
|
+
...stoaGasMeta(),
|
|
343
381
|
})
|
|
344
382
|
.setNetworkId(KADENA_NETWORK)
|
|
345
383
|
.createTransaction();
|
|
@@ -7,6 +7,47 @@ import { universalSignTransaction, fromKeypair } from "@stoachain/stoa-core/sign
|
|
|
7
7
|
import { createSimulationError, logDetailedError } from "@stoachain/stoa-core/errors";
|
|
8
8
|
import { safeCreationTime } from "@stoachain/stoa-core/pact";
|
|
9
9
|
import { getLogger } from "@stoachain/stoa-core/observability";
|
|
10
|
+
/**
|
|
11
|
+
* Yin Engine — StoaChain's time-varying minimum gas price.
|
|
12
|
+
*
|
|
13
|
+
* TEMPORARY LOCAL COPY, identical to the one in `crossChainFunctions.ts`
|
|
14
|
+
* (v4.5.0). Both belong in `@stoachain/stoa-core/gas` long-term — that package
|
|
15
|
+
* still exposes only the static `GAS_PRICE_MIN_ANU = 10_000`, which is the
|
|
16
|
+
* genesis floor and has been stale since 2026-02-23. Delete every copy in the
|
|
17
|
+
* same change that consumes the chain-generic version.
|
|
18
|
+
*
|
|
19
|
+
* The floor starts at 10,000 ANU at genesis and rises by 1 ANU every 3 hours,
|
|
20
|
+
* capped at 400,000 ANU. Source of truth: `UC_MinimumGasPriceANU` in
|
|
21
|
+
* `pact/stoa-coin/new-coin.pact` (evaluated against `(at "block-time"
|
|
22
|
+
* (chain-data))` on-chain — creationTime is a close client-side proxy for it).
|
|
23
|
+
*
|
|
24
|
+
* This applies to gas-station-paid transactions too: `DALOS.GAS_PAYER` decides
|
|
25
|
+
* WHO pays, not HOW LITTLE. The chain-wide "gasPrice must be >= the live
|
|
26
|
+
* floor" rule is checked before the payer guard ever runs, so a transaction
|
|
27
|
+
* left at the client's `1.0e-8` default is rejected as underpriced no matter
|
|
28
|
+
* how well-funded the Ouronet Gas Station is.
|
|
29
|
+
*/
|
|
30
|
+
const YIN_GENESIS_TIME_S = 1771869600; // 2026-02-23T18:00:00Z — tick 0
|
|
31
|
+
const YIN_GENESIS_MIN_GAS_ANU = 10000;
|
|
32
|
+
const YIN_MAX_GAS_ANU = 400000;
|
|
33
|
+
const YIN_GAS_PRICE_INTERVAL_S = 10800; // 3 h per tick
|
|
34
|
+
function minGasPriceAnu(creationTimeS) {
|
|
35
|
+
const elapsed = creationTimeS - YIN_GENESIS_TIME_S;
|
|
36
|
+
const ticks = elapsed <= 0 ? 0 : Math.floor(elapsed / YIN_GAS_PRICE_INTERVAL_S);
|
|
37
|
+
return Math.min(YIN_GENESIS_MIN_GAS_ANU + ticks, YIN_MAX_GAS_ANU);
|
|
38
|
+
}
|
|
39
|
+
/** Built by string padding, never float division — avoids exponential notation / precision loss. */
|
|
40
|
+
function anuToStoaNumber(anu) {
|
|
41
|
+
return Number("0." + String(anu).padStart(12, "0"));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One clock read: the `creationTime` to stamp and the `gasPrice` derived
|
|
45
|
+
* FROM THAT EXACT VALUE, so the two can never disagree.
|
|
46
|
+
*/
|
|
47
|
+
function stoaGasMeta() {
|
|
48
|
+
const creationTime = safeCreationTime();
|
|
49
|
+
return { creationTime, gasPrice: anuToStoaNumber(minGasPriceAnu(creationTime)) };
|
|
50
|
+
}
|
|
10
51
|
/**
|
|
11
52
|
* Query RotateGuard info object from the chain.
|
|
12
53
|
* (ouronet-ns.DALOS-INFO.DALOS-INFO|URC_RotateGuard <patron> <account>)
|
|
@@ -69,9 +110,15 @@ export async function rotateGuard(params) {
|
|
|
69
110
|
builder = builder
|
|
70
111
|
.setMeta({
|
|
71
112
|
senderAccount: STOA_AUTONOMIC_OURONETGASSTATION,
|
|
72
|
-
creationTime: safeCreationTime(),
|
|
73
113
|
chainId: KADENA_CHAIN_ID,
|
|
74
114
|
gasLimit: gasLimitOverride || gasLimit,
|
|
115
|
+
// `stoaGasMeta()` supplies both `creationTime` (via `safeCreationTime()`)
|
|
116
|
+
// and the `gasPrice` derived from that exact value, per the Yin Engine
|
|
117
|
+
// (see the module-level comment above). Pre-4.5.1 this set only
|
|
118
|
+
// `creationTime`, leaving `gasPrice` at the vendored client's
|
|
119
|
+
// `1.0e-8` default — the genesis floor — so every rotation submitted
|
|
120
|
+
// after the floor's first tick was rejected as underpriced.
|
|
121
|
+
...stoaGasMeta(),
|
|
75
122
|
})
|
|
76
123
|
.setNetworkId(KADENA_NETWORK)
|
|
77
124
|
// Gas Station key: GAS_PAYER capability
|
|
@@ -11,6 +11,47 @@ import { universalSignTransaction, fromKeypair } from "@stoachain/stoa-core/sign
|
|
|
11
11
|
import { createSimulationError, logDetailedError } from "@stoachain/stoa-core/errors";
|
|
12
12
|
import { pactRead } from "@stoachain/stoa-core/reads";
|
|
13
13
|
import { getLogger } from "@stoachain/stoa-core/observability";
|
|
14
|
+
/**
|
|
15
|
+
* Yin Engine — StoaChain's time-varying minimum gas price.
|
|
16
|
+
*
|
|
17
|
+
* TEMPORARY LOCAL COPY, identical to the one in `crossChainFunctions.ts`
|
|
18
|
+
* (v4.5.0). Both belong in `@stoachain/stoa-core/gas` long-term — that package
|
|
19
|
+
* still exposes only the static `GAS_PRICE_MIN_ANU = 10_000`, which is the
|
|
20
|
+
* genesis floor and has been stale since 2026-02-23. Delete every copy in the
|
|
21
|
+
* same change that consumes the chain-generic version.
|
|
22
|
+
*
|
|
23
|
+
* The floor starts at 10,000 ANU at genesis and rises by 1 ANU every 3 hours,
|
|
24
|
+
* capped at 400,000 ANU. Source of truth: `UC_MinimumGasPriceANU` in
|
|
25
|
+
* `pact/stoa-coin/new-coin.pact` (evaluated against `(at "block-time"
|
|
26
|
+
* (chain-data))` on-chain — creationTime is a close client-side proxy for it).
|
|
27
|
+
*
|
|
28
|
+
* This applies to gas-station-paid transactions too: `DALOS.GAS_PAYER` decides
|
|
29
|
+
* WHO pays, not HOW LITTLE. The chain-wide "gasPrice must be >= the live
|
|
30
|
+
* floor" rule is checked before the payer guard ever runs, so a transaction
|
|
31
|
+
* left at the client's `1.0e-8` default is rejected as underpriced no matter
|
|
32
|
+
* how well-funded the Ouronet Gas Station is.
|
|
33
|
+
*/
|
|
34
|
+
const YIN_GENESIS_TIME_S = 1771869600; // 2026-02-23T18:00:00Z — tick 0
|
|
35
|
+
const YIN_GENESIS_MIN_GAS_ANU = 10000;
|
|
36
|
+
const YIN_MAX_GAS_ANU = 400000;
|
|
37
|
+
const YIN_GAS_PRICE_INTERVAL_S = 10800; // 3 h per tick
|
|
38
|
+
function minGasPriceAnu(creationTimeS) {
|
|
39
|
+
const elapsed = creationTimeS - YIN_GENESIS_TIME_S;
|
|
40
|
+
const ticks = elapsed <= 0 ? 0 : Math.floor(elapsed / YIN_GAS_PRICE_INTERVAL_S);
|
|
41
|
+
return Math.min(YIN_GENESIS_MIN_GAS_ANU + ticks, YIN_MAX_GAS_ANU);
|
|
42
|
+
}
|
|
43
|
+
/** Built by string padding, never float division — avoids exponential notation / precision loss. */
|
|
44
|
+
function anuToStoaNumber(anu) {
|
|
45
|
+
return Number("0." + String(anu).padStart(12, "0"));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* One clock read: the `creationTime` to stamp and the `gasPrice` derived
|
|
49
|
+
* FROM THAT EXACT VALUE, so the two can never disagree.
|
|
50
|
+
*/
|
|
51
|
+
function stoaGasMeta() {
|
|
52
|
+
const creationTime = safeCreationTime();
|
|
53
|
+
return { creationTime, gasPrice: anuToStoaNumber(minGasPriceAnu(creationTime)) };
|
|
54
|
+
}
|
|
14
55
|
/**
|
|
15
56
|
* Query RotateKadena info object from the chain.
|
|
16
57
|
* (ouronet-ns.INFO-ZERO.DALOS-INFO|URC_RotateKadena <patron> <account>)
|
|
@@ -70,9 +111,15 @@ export async function rotateKadenaPaymentKey(patronAddress, accountAddress, newP
|
|
|
70
111
|
builder = builder
|
|
71
112
|
.setMeta({
|
|
72
113
|
senderAccount: STOA_AUTONOMIC_OURONETGASSTATION,
|
|
73
|
-
creationTime: safeCreationTime(),
|
|
74
114
|
chainId: KADENA_CHAIN_ID,
|
|
75
115
|
gasLimit: gasLimitOverride || gasLimit,
|
|
116
|
+
// `stoaGasMeta()` supplies both `creationTime` (via `safeCreationTime()`)
|
|
117
|
+
// and the `gasPrice` derived from that exact value, per the Yin Engine
|
|
118
|
+
// (see the module-level comment above). Pre-4.5.1 this set only
|
|
119
|
+
// `creationTime`, leaving `gasPrice` at the vendored client's
|
|
120
|
+
// `1.0e-8` default — the genesis floor — so every payment-key rotation
|
|
121
|
+
// submitted after the floor's first tick was rejected as underpriced.
|
|
122
|
+
...stoaGasMeta(),
|
|
76
123
|
})
|
|
77
124
|
.setNetworkId(KADENA_NETWORK)
|
|
78
125
|
// Gas Station key: GAS_PAYER capability (SEPARATE from guard keys)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouronet/ouronet-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.1",
|
|
4
4
|
"description": "Ouronet-specific business logic for the Ouronet protocol on StoaChain — interactions/* read+execute functions for the ouronet-ns Pact modules, the Codex encrypted-multi-wallet format, Ouronet protocol accounts and tokens. Depends on @stoachain/stoa-core for chain-generic infrastructure (signing, wallet, crypto, network, etc.).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|