438Release

Interfaces & Reliability

What shipped

Spec version 438 is, by the release's own description, a focused compatibility and correctness release following v437. It gives smart contracts a bounded way to inspect staking positions, lets Ledger-style signatures authorise limit orders, closes two small gaps in mechanism and epoch accounting, repairs testnet warp sync, and makes the release pipeline recover cleanly from a partial Python publication. The note is explicit that there is no new token model and no migration for ordinary wallets: this release tightens surfaces that applications, operators and automation already use. [source]

The source for this page is one document: the project's own note for the V438 upgrade, dated July 2026. [source] [source]

Two of the changes are about who can talk to the chain. A contract can now read a coldkey's non-zero alpha positions on one subnet through the EVM staking precompile, by supplying its own list of candidate hotkeys — up to 64 of them — and receiving back only the candidates that actually hold stake. And a signed limit order can now be authorised with either an sr25519 or an ed25519 signature, over either the raw encoded order or the wrapped payload that a Ledger-style device produces. The release's own point about that second path is that it verifies against the same signer and derives the same on-chain order ID as the first. [source] [source] [source]

The rest is correctness. A custom mechanism emission split must now name every active mechanism explicitly; BlocksSinceLastStep is capped at a subnet's own tempo plus one, so a stalled counter can no longer grow without bound; testnet nodes get two trusted genesis-scoped checkpoints that repair warp sync across historical authority-set changes; and the mainnet watcher now tracks release completion and package publication independently, so a failed upload can be retried instead of being locked out by an otherwise successful release. [source] [source] [source] [source]

What it changes for the ecosystem

Subnet owners who set a custom mechanism emission split have a breaking change to check. Lesson 09 described that split as a list of numbers stored on-chain that must add up to a fixed total, with an unset value simply meaning an even division. Both halves still hold, but the chain is now strict about the list: it must contain one entry for every active mechanism, and the entries must still sum to 65,535. Before this release a shorter list passed validation and was padded with zeroes, which the note says could silently starve trailing mechanisms while the rounding residue was assigned to mechanism zero. Owners who want an even split can still clear the custom value; owners who set one explicitly must now describe the full mechanism set. [source] [source]

EVM integrators have a smaller job: refresh the staking ABI and call the new stake-position view with a bounded, duplicate-free hotkey list. The bound is the design rather than a limitation of it — the release is explicit that the precompile never walks the coldkey's unbounded historical hotkey index, so the caller supplies the search set and the work and gas stay proportional to the request. Limit-order clients need change nothing that already works: raw sr25519 signatures remain valid, the Ledger-style wrapped form and ed25519 are newly valid, and ECDSA stays rejected because its account-recovery model does not map to the 32-byte signer identity the pallet uses. The order ID is unchanged, so cancellation, replay protection, partial fills and relayer restrictions behave exactly as before. [source] [source] [source] [source]

Indexers and operators get the reliability half. The release tells indexers to treat BlocksSinceLastStep as a bounded status counter rather than an elapsed-time source beyond tempo plus one; a deferred epoch can still report the one-block-overdue state that triggers the fallback, but the counter no longer grows indefinitely while state is delayed, and the related epoch-status and next-epoch queries follow the same model. Node operators wait for the on-chain spec_version to move to 438 and then update, and testnet operators are told to update promptly, since testnet is where the warp-sync repair lands. Signers use the release train's own sign command once the upgrade has been proposed. [source] [source] [source] [source]

What to watch

The item on this page most likely to be misread is the companion view that reports the runtime's base staking minimum. The release calls it deliberately a primitive and not a quote: operation fees, subnet price conversion and full-unstake rules can all still change what a particular transaction actually accepts. Both new selectors were added to the Solidity interface, the JSON ABI, the Rust precompile and the gas-accounting tests together, so Solidity and SDK callers at least share a single definition of it. [source]

Unverified The mechanism-split change turns a configuration that was previously accepted into one that is rejected, and the note does not say what happens to a subnet whose short vector was stored and zero-padded under the old rule — whether it keeps operating on its padded form until an owner writes a new one, or is treated as unset and reverts to an even division. Anyone running more than one mechanism should read the stored value rather than assume either answer.
How it actually works

The bounded staking view

The staking precompile at 0x…0805 gains getStakeInfoForColdkeyAndNetuid, which accepts a coldkey, a netuid, and up to 64 distinct candidate hotkeys, and returns only the candidates with stake. The caller supplies the search set deliberately: the precompile never walks the coldkey's unbounded historical hotkey index, and it charges for the bounded reads it actually performs. [source] [source] [source]

IStaking.StakeInfo[] memory positions =
 staking.getStakeInfoForColdkeyAndNetuid(coldkey, netuid, hotkeys);

The companion getDefaultMinStake() view exposes the runtime's base staking minimum as a primitive rather than a quote. Both selectors are added to the Solidity interface, the JSON ABI, the Rust precompile and the gas-accounting tests, so Solidity and SDK callers share one contract. [source] [source]

Limit-order signatures

A signed limit order may now use sr25519 or ed25519, over either the raw SCALE-encoded order or the Ledger-compatible wrapped payload produced by signRaw. The order ID is unchanged — it remains the blake2-256 hash of the versioned order — so both paths verify against the same signer and derive the same on-chain identifier. ECDSA remains rejected because its account-recovery model does not map to the 32-byte signer identity the pallet uses. The release states the accepted and rejected forms directly. [source] [source] [source] [source]

raw = SCALE(versioned_order)
order_id = blake2_256(raw)
wrapped = "<Bytes>" ++ order_id ++ "</Bytes>"
accepted = sr25519(raw | wrapped) or ed25519(raw | wrapped)
rejected = ecdsa

Mechanism split validation

The release publishes the accepted and rejected configurations side by side, before and after this upgrade: [source] [source] [source]

Epoch counters, warp sync, and the release train

BlocksSinceLastStep is capped at the subnet's tempo plus one, and the scheduler's safety check now uses that same subnet-specific tempo instead of a global maximum. Deferred epochs can still report the one-block-overdue state that triggers the fallback, but dashboards and clients no longer see a counter grow indefinitely during inconsistent or delayed state. [source]

Testnet nodes start GRANDPA warp sync from two trusted, genesis-scoped authority checkpoints, enabled only when the node sees the testnet genesis hash; mainnet and development chains keep their existing initial set-ID behaviour. The release also aligns the Polkadot SDK revision needed to verify those proofs and corrects dependency features that affected node log decoding. [source]

The mainnet watcher tracks GitHub release completion and stable Python publication independently. A release can exist while a failed or partial PyPI upload is retried on the next watcher run, and a provenance-bound completion marker is written only after every expected distribution is accepted — removing the old failure mode where a successful GitHub release prevented the SDK publication from being retried. Separately, every merge to main publishes a moving development image, while the deployed :latest tag stays tied to an executed mainnet release and :devnet and :testnet continue following their network mirrors, so a developer can test merged code without mistaking it for the version running on mainnet. [source] [source]