NAN 006: Owning Our Dependencies, a Nonce-Aware Mempool, and 24-Hour Votes
Posted by Unique on 2026-07-31. Releases: v2.16.0, v2.17.0. Prior mainnet upgrade: v2.15.0.

Summary
- Our dependencies live in our repository. The Cosmos SDK, IBC Go,
x/wasm, and the Wasm VM are first-party source underlib/andx/wasm, so one PR can fix a bug that spans them. - One sender can't flood blocks with EVM transactions that can never execute. The mempool now tracks each sender's nonces.
- Mainnet governance votes take 24 hours instead of 48.
- Authz is off. No account can grant another account permission to act for it. Grants can't be created, executed, or revoked.
- Chain maintenance can run every block without a bot. Wasm block hooks let a governed registry contract schedule privileged calls at the start and end of each block.
- Events roll back with the EVM. A reverted EVM call takes its Cosmos events with it.
- Balance queries understand both VMs. One query returns a token's Bank and ERC20 balances.
1) Why we stopped consuming forks
Nibiru had been running patched versions of the Cosmos SDK, wasmd, and the Wasm VM for a long time. Each lived in its own fork and repository. A fix that touched two layers, say the SDK and the EVM module, meant coordinated PRs across repositories, version bumps, and replace directives that drifted.
In July we moved all of it into the chain repository:
- The Cosmos SDK and wasmd forks moved to
lib/, with public module tagslib/cosmos-sdk/v0.47.14-nibiruandlib/wasmd/v0.44.1-nibiruso other Go projects can import them (PR #2646). x/wasmbecame first-party chain code, and the Wasm VM's Go bindings moved tolib/wasmvm-ffiwith their own CI and release tags (PR #2656).- IBC Go v7 moved to
lib/ibc-go. We removed the ICS-29 fee middleware at the same time, since it was never active on mainnet (PR #2686). - The SDK and IBC Go were flattened into the root module, and protobuf generation now resolves them locally (PR #2690).

The cost was real. The flatten alone touched about 2,500 files, mostly import rewrites and regenerated protobuf code. The move also broke the version flags in release builds, which left nibid version empty until PR #2713 fixed it. CI now fails if a build has empty version fields, or if anything imports the upstream modules again.
Why one repository? Because these pieces were never really separate. The chain, the SDK fork, wasmd, and the Wasm VM change together. Keeping them in separate repositories hid that coupling instead of removing it. A patch in one place quietly changed a dependency somewhere else, and Go replace statements piled up to hold it all together. Google and Meta keep coupled code in one repository for the same reason, at far larger scale.
The payoff is that one PR can now fix a bug across the SDK, the EVM, and Wasm, and one test run covers all three. There are far fewer replace statements. Refactors and bug fixes are faster, and so is the loop from a change to a built binary to a passing end-to-end test. In October we did the same thing for the consensus engine.
2) A mempool that understands nonces
An EVM account's transactions run in nonce order. If nonce 11 is missing, nonce 12 can't run, however long it waits.
Before v2.17, a sender could submit a pile of transactions with future nonces. The node accepted anything within its future window and gossiped it to peers. Proposers could then pack blocks with transactions that had no chance of executing.
v2.17 adds an EVM-aware mempool (PR #2702):
- It indexes transactions by sender and nonce.
- Each sender gets at most 8 live nonce slots. A different transaction for a slot that's already taken is rejected.
- Block proposals only include each sender's contiguous chain starting from the committed nonce. Gaps stay out.
- After each block, recheck drops any transaction whose earlier nonces are missing.

Two choices are worth calling out. The PR first allowed 64 slots per sender, and we lowered it to 8 before release. We were dealing with heavy bursts of spam at the time, and real accounts rarely need many pending transactions. Most send two or three in a row, sometimes five, and we've almost never seen one need more than ten. A tight limit costs real users nothing and makes spamming the nodes harder. If usage grows into it, we can raise it.
The second choice is that there's no fee-based replacement. You can't resubmit the same nonce with a higher fee to jump ahead. That keeps the mempool simple, at the cost of a feature some wallets expect.
None of this needed a CometBFT fork or a consensus migration. The index is local to each node and only shapes which transactions get proposed. Block validation still requires exact nonces.
3) Faster governance
v2.16 cut mainnet's governance voting period from 48 hours to 24 (PR #2632). Even at two days, we kept waiting on votes for no reason. Validators reached quorum quickly, everyone was prepared for the upgrade, and the release sat until the window closed. Chains that ship a few times a year can afford week-long votes. Nibiru ships far more often than that, so we treat upgrades more like game patches than rare events. The one-day window has worked better for everyone.
4) Turning off authz
The Cosmos SDK's authz module lets one account grant another permission to send messages on its behalf. Every delegation path is one more way to act for an account, and we chose to close this one.
v2.16 disables it (PR #2629). MsgGrant, MsgExec, and MsgRevoke fail on every path, including through Wasm. The module stays registered so codecs and queries don't break. Existing grants stay in state, but none of them can be executed.
5) Smaller changes worth knowing
- Wasm block hooks. A sudo-configured registry contract can plan privileged Wasm calls during
BeginBlockandEndBlock, with bounded plans and isolated execution (PR #2667). Chain-level maintenance can now run on schedule without a bot sending transactions. - Events follow EVM snapshots. When the EVM reverts to a snapshot, the Cosmos events emitted after it go too (PR #2696). This finishes the work NAN 004 started.
- ERC-2470 in genesis. New chains include the standard singleton factory for deterministic
CREATE2deployment (PR #2697). - Multi-VM balances.
QueryBalancereturns a token's Bank and ERC20 balances together, and reads WNIBI from its own ledger (PR #2630, PR #2631).
6) On Sai
- Export your key. If you signed up with Google or another social login, you can now export your wallet's private key.
- Volume fee tiers. The more you trade, the lower your fees.
- Sai is readable by AI.
llms.txtand an LLM sitemap describe Sai for agents and assistants. - A cleaner app. A compact order form, redesigned navigation, and portfolio cards on mobile.
References
Pull requests behind each section. The Sai repositories are private, so the text above describes each change on its own.
1) Why we stopped consuming forks
- nibiru#2646: Public tags for the Cosmos SDK and wasmd forks.
- nibiru#2656: Wasm VM build dependencies consolidated in the chain repo.
- nibiru#2686: ibc-go in-tree.
- nibiru#2690 and nibiru#2713: The vendored Cosmos SDK and IBC flattened into the repo, and a version fix after the flatten.
2) A mempool that understands nonces
- nibiru#2702: The nonce-aware EVM mempool.
3) Faster governance
- nibiru#2632: 24-hour votes on mainnet.
4) Turning off authz
- nibiru#2629: Disable authz.
5) Smaller changes worth knowing
- nibiru#2667: Wasm block hooks.
- nibiru#2696: Roll back events from failed EVM transactions.
- nibiru#2697: The ERC-2470 deployer.
- nibiru#2630 and nibiru#2631: Multi-VM token balances in balance queries.
6) On Sai
- sai-web#1049: Private key export for social-login wallets.
- sai-web#785: Volume fee tiers.
- sai-web#1006:
llms.txtand an LLM sitemap. - sai-web#1043, sai-web#1031, and sai-web#1085: Compact order form, navigation, and mobile portfolio cards.