docs(evm): add nonce lanes guide for concurrent submission from one account - #75
docs(evm): add nonce lanes guide for concurrent submission from one account#75alexander-sei wants to merge 5 commits into
Conversation
Add a High-Frequency Trading group to the EVM tab with a guide to sei-protocol/sei-parallel-nonce-hft: how EIP-7702 delegation, ERC-4337 nonce lanes, a private mempool, and gas-only relayers let one funded address submit many independent operations without a sequential nonce queue. - Explain the problem (sequential nonces, no pending state on Sei, strict nonce admission under Giga) and each mechanism with its own diagram - Add a "moat" section comparing the design with single wallets, wallet fleets, and public ERC-4337 bundlers - Step-by-step tutorial for a local Prague fork and Atlantic-2, an annotated example report, tuning notes, a configuration reference, venue-integration guidance, and troubleshooting - Six theme-aware SVG diagrams in snippets/parallel-nonce-diagrams.jsx, following the existing Giga diagram convention - Link the page from the EVM home page Use Cases Co-authored-by: Cursor <cursoragent@cursor.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
…check The spelling check treats the "Pn"/"pn" prefix as a misspelling of "on". Rename the snippet components to a ParallelNonce* prefix, matching the Giga* diagram convention, and give SVG marker ids descriptive names. Co-authored-by: Cursor <cursoragent@cursor.com>
…laim The page promised parallelism it does not deliver and narrowed its audience to one industry. "Parallel nonce" names a mechanism that does not exist: EVM nonces are never parallel, and the actual feature is ERC-4337's two-dimensional nonce. Inside Sei's docs "parallel" also reads as parallel execution, which is why the page previously needed a warning to undo the association its own title created. Retitle to "Nonce Lanes", lead with submission concurrency, and name the other audiences this serves (keepers, liquidators, oracle updaters, payout batchers) rather than HFT alone. Correct the load-bearing factual claim. The page asserted that `eth_getTransactionCount(address, "pending")` returns the same value as `"latest"`. evm/reference documents the opposite: the pending tag returns EvmNextPendingNonce from the mempool. The supportable claim is the one in evm/evm-parity/finality, that a pending nonce differing from the confirmed nonce is unreliable. The design argument is unaffected, since a hot path that reads no nonces is the right answer either way, so this is a rewording rather than a restructure. Fix the comparison table, which overstated the result. It put `LANE_POOL_SIZE` "up to 4096" against a wallet fleet's N, comparing signed unresolved operations against concurrent transactions. Split those into separate rows, state that broadcast width is `RELAYER_COUNT`, and say plainly that a wallet fleet can match the width -- what it cannot match is doing so from one balance, one approval set, and one key. Also: - Move the page from a new top-level "High-Frequency Trading" group into the existing "Ecosystem Tutorials" group, next to the other standalone tutorials. A dedicated top-level group for one page put a niche topic ahead of the core SDK group in reading order - Retitle "The moat" to "Why this is hard to replicate"; AGENTS.md asks for no investment framing - Attribute the mempool to Autobahn under Giga mode, matching node/technical-reference and evm/reference - Drop the hard-coded 400 ms figure in favor of a pointer to Twin-Turbo and Giga, since sei-giga-specs warns against mixing current and Giga numbers - Cross-link Pimlico and Thirdweb EIP-7702, and say when to prefer a hosted bundler; those were the only other 4337/7702 pages and went unlinked - Track the repository's renames: sei-nonce-lanes, `npm run submit`, `REVERT_ORDER_INDEX`, and Node 22 rather than 26 - Fix "neighbours"/"neighbouring"; the repo is American English in prose and _typos.toml sets no locale, so CI would not have caught it - Rename the snippet to nonce-lane-diagrams.jsx with matching components mint broken-links and mint validate both pass. Vale reports no errors; the one remaining Sei.Headings warning fires on any heading containing "ERC-<digits>" because ERC is absent from the exceptions list in .github/styles/Sei/Headings.yml, which also affects existing pages. Co-authored-by: Cursor <cursoragent@cursor.com>
Sei.Headings flagged any heading containing a hyphenated ERC standard even when the heading was already correct sentence case, because ERC was missing from the exceptions list while EVM, NFT, RPC, and the other acronyms were present. "ERC-4337 nonce lanes" tripped it, as did "NFT and ERC-1155" and the "ERC-20 Interaction" headings on the existing evm-parity example pages. Add ERC alongside EVM. Repo-wide this clears seven warnings and introduces none (1213 -> 1206). It does not hide genuine sentence-case violations: the check already tolerates a single stray capitalized word, so headings like "EVM Interaction" never warned in the first place, and every remaining ERC heading still warns because it has an independent title-case problem. Co-authored-by: Cursor <cursoragent@cursor.com>
A mempool is a shared admission buffer: transactions arrive from strangers, are gossiped, and wait for whichever producer or bundler picks them up. sei-nonce-lanes has none of that. Its queue is an in-process array, filled only by the process that signed the operations and gone when that process exits. Calling it a "private mempool" sent readers looking for gossip, admission policy, and eviction that do not exist, and it was especially confusing on a Sei page where "mempool" otherwise means the Autobahn producer mempool two sections earlier. Rename it to "bundling queue" throughout, which says what it does: hold signed UserOperations and pack them into lane-safe handleOps bundles. The paragraph that explains the ERC-7562 exemption now leads with why the component is not a mempool, since that is precisely what earns the exemption -- an in-process queue never enters the alt-mempool, so SAME_SENDER_MEMPOOL_COUNT never applies to it. - Retitle the pipeline diagram box and update its aria-label - "take bundle from the mempool" -> "from the queue" in the bundle lifecycle diagram - Rename the `mempool.add(...)` call in the integration snippet to `bundlingQueue.add(...)`, tracking the repository rename of PrivateMempool to BundlingQueue and mempool.ts to bundling-queue.ts The remaining "mempool" mentions on the page are deliberate and refer to real mempools: Autobahn's strict nonce admission, the pending-nonce warning, and the canonical ERC-4337 alt-mempool this design bypasses. Vale and typos both report no errors. Co-authored-by: Cursor <cursoragent@cursor.com>
PR SummaryLow Risk Overview Supporting updates wire the page into Reviewed by Cursor Bugbot for commit b1ce183. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
A well-structured, unusually thorough new EVM guide whose internal links, snippet conventions, and cited facts I verified against the repo — but one diagram still carries the exact eth_getTransactionCount(..., "pending") == "latest" claim the prose was rewritten to correct, and the tutorial's first step clones a repository the author states is still private.
Findings: 2 blocking | 8 non-blocking | 6 posted inline
Blockers
- Tutorial depends on a private repository (Codex P1).
sei-protocol/sei-nonce-lanesis referenced from the intro (evm/nonce-lanes.mdx:12), the clone step (:205), the configuration reference, and a resource card. The PR description states the repo is private and asks that this not merge until it is public — until then the first tutorial step fails for every public reader and four links 404. I could not independently confirm current visibility (no network access from this environment), so please verify before merging. - 1 blocking issue(s) flagged inline on specific lines.
Non-blocking
- The Cursor second-opinion pass produced no output —
cursor-review.mdis empty, so that review lane contributed nothing.REVIEW_GUIDELINES.mdis also empty; I appliedAGENTS.mdandSTYLE_GUIDE.mdconventions instead. - Verified clean: every internal link target resolves —
/evm/evm-parity/finality#pending-state,/evm/evm-parity/transaction-types#set-code-eip-7702-auth-list-requirement,/node/technical-reference#giga-mode-behavior-and-per-block-limits(h4 atnode/technical-reference.mdx:226), plus/evm/networks,/learn/rpc-providers,/learn/twin-turbo-consensus,/learn/sei-giga,/evm/best-practices/optimizing-for-parallelization,/evm/wallet-integrations/{pimlico,thirdweb-7702}. Thetxpool_contenttruncation claim matchesevm/reference.mdx:1122, the EntryPoint v0.8 address and chain IDs are correct, and the snippet follows thegiga-diagrams.jsxconvention (currentColorink,--sei-maroon-50/--sei-gold-25, both defined instyle.css). - Bundling a shared lint-config change with content.
.github/styles/Sei/Headings.ymlis repo-wide and affects existing pages' annotations. The author already offered to split it; given it only changes advisory annotations (prose-style.ymlsetsfail_on_error: false), keeping it here is fine, but splitting would make the content diff cleanly revertable. - 5 suggestion(s)/nit(s) flagged inline on specific lines.
| ); | ||
| })} | ||
| <text x={40} y={124} fontSize="10.5" fill={ink} fillOpacity="0.7">nonces 7 and 8 are signed and valid, but nothing at or above 7 can execute until 6 is filled or replaced</text> | ||
| <text x={40} y={142} fontSize="10.5" fill={ink} fillOpacity="0.7">on Sei there is no pending view to inspect: eth_getTransactionCount(addr, "pending") equals "latest", and a nonce gap is rejected with a bad nonce error</text> |
There was a problem hiding this comment.
[blocker] This diagram still carries the claim the PR was specifically rewritten to remove. It says eth_getTransactionCount(addr, "pending") equals "latest", which contradicts:
- this page's own
<Warning>: "it is not an alias for"latest"" evm/reference.mdx:345: "For the 'pending' tag Sei returnsEvmNextPendingNoncefrom the CometBFT mempool"
A reader who trusts the diagram gets the opposite mental model from the paragraph directly above it.
Second issue on the same line: "a nonce gap is rejected with a bad nonce error" is stated unconditionally, while the prose correctly scopes it to Giga ("Under Giga, the Autobahn producer mempool ... rejects a gap with a bad nonce error").
Suggested rewording that matches both the prose and evm/reference.mdx:
on Sei the pending view is not dependable:
eth_getTransactionCount(addr, "pending")varies by node, and under Giga a nonce gap is rejected with a bad nonce error
| </defs> | ||
|
|
||
| <rect x={40} y={40} width={330} height={216} rx={9} {...box} stroke={accent} strokeOpacity="0.9" strokeWidth="1.3" /> | ||
| <text x={205} y={64} fontSize="13" fontWeight="600" textAnchor="middle" fill={ink}>Trading EOA, same address</text> |
There was a problem hiding this comment.
[suggestion] The retitling deliberately moved the page off trading-specific framing ("market making and order flow, but also liquidation and keeper bots, oracle updates, payout and claim batching, and game backends"), and the prose consistently says funded account / funded EOA. The diagrams didn't follow: "Trading EOA" (:152, :211), "the trading EOA" (:141, :181, :248), "chosen by the trader" (:89), "the trader's signature" (:251), and "inventory" (:47, :51, :54, :207, :237).
The TRADER_PRIVATE_KEY env var is upstream and should stay, but the diagram labels are yours — "Funded EOA" and "funds"/"assets" would match the reframing and cost nothing.
| - Sei Network | ||
| - SeiDB | ||
| - EVM | ||
| - ERC |
There was a problem hiding this comment.
[suggestion] If ERC needs the exception, EIP almost certainly does too — the $sentence check lowercases non-exception words, so EIP-7702 gets the same treatment as ERC-4337 even in first position. This page has ### EIP-7702 keeps the funded address (evm/nonce-lanes.mdx:80), and existing pages have several mid-heading cases (evm/evm-parity/gas-and-fees.mdx:36, evm/evm-parity/signing.mdx:53, evm/evm-parity/transaction-types.mdx:19, evm/wallet-integrations/thirdweb-7702.mdx:28).
Since filter_mode: added means only changed lines are annotated, line 80 of this PR is exactly the kind of hit this would surface. Worth adding EIP in the same one-line spirit.
| </Warning> | ||
|
|
||
| <Note> | ||
| Block time and gas limits differ between today's [Twin-Turbo consensus](/learn/twin-turbo-consensus) and [Sei Giga](/learn/sei-giga). Size a relayer pool against the network you are actually submitting to, and measure rather than assuming. |
There was a problem hiding this comment.
[nit] AGENTS.md lists Twin Turbo Consensus as a proper noun, and the rest of the repo writes it unhyphenated (learn/sei-giga.mdx:99, :196-197). Suggest "Twin Turbo consensus" to match.
| <Accordion title="Bundle width: gas efficiency against isolation"> | ||
| `MAX_OPS_PER_BUNDLE` trades amortized outer-transaction overhead for the size of the shared validation failure domain. A width of `1` gives maximum isolation and the highest overhead. Execution reverts stay per-operation at any width. The relayer caps signed transaction gas below the live block gas limit and rejects a bundle whose estimate cannot fit. | ||
|
|
||
| As a reference point, on Atlantic-2 on September 3, 2026, the real-swap path sustained 77 operations per bundle; 78 hit the 12,500,000 block-gas ceiling and failed safely during simulation. Width 76 produced the best observed submission rate for that call shape, 47.7 landed swaps per second. Treat these as measurements for one call shape on one network at one point in time, not as protocol limits. |
There was a problem hiding this comment.
[nit] AGENTS.md says to "link to live status/dashboards rather than hard-coding network stats that change" — 12,500,000 is a block gas limit and will drift, especially across the Twin Turbo → Giga transition this page already warns about two sections up.
The closing caveat ("measurements for one call shape on one network at one point in time, not as protocol limits") does most of the work, so this is a nit rather than a fix-now. Consider dropping just the absolute gas figure and keeping the relative result (77 fits, 78 does not), which is the part that stays true longer.
| <line x1={30} y1={222} x2={870} y2={222} stroke={ink} strokeOpacity="0.15" strokeWidth="1" /> | ||
| <rect x={30} y={236} width={840} height={58} rx={9} fill={warn} fillOpacity="0.08" stroke={warn} strokeOpacity="0.8" strokeWidth="1" /> | ||
| <text x={48} y={258} fontSize="11.5" fontWeight="600" fill={ink}>Never submitted: nothing consumed</text> | ||
| <text x={48} y={278} fontSize="10" fill={ink} fillOpacity="0.8">a signed operation whose outer transaction was dropped, evicted, or never broadcast leaves its lane sequence untouched; neighbouring lanes stay valid and the journal requeues it</text> |
There was a problem hiding this comment.
[nit] neighbouring → neighboring. The PR description notes two British spellings were fixed in the MDX; this one in the snippet was missed, and _typos.toml won't catch it since it sets no locale.
What is the purpose of the change?
Add new content: a guide and tutorial for sei-nonce-lanes, for teams that need many independent transactions in flight from one funded Sei address.
Previously opened as "Parallel Nonce Submission for High-Frequency Trading." Both halves of that title were wrong, so the page has been retitled and reframed — see Renamed and corrected below.
Describe the changes to the documentation
Target audience: anyone who needs one funded address to do many things that do not depend on each other and currently works around Sei's sequential nonce model with a fleet of hot wallets. Market making and order flow, but also liquidation and keeper bots, oracle updates, payout and claim batching, and game backends.
New page
evm/nonce-lanes.mdx, added to the existing Ecosystem Tutorials group in the EVM tab:<Steps>from clone and verify throughstatus → delegate → fund → submit, with<Tabs>for a local Anvil Prague fork vs. Atlantic-2, an annotated report, and optional real-swap and baseline runs.buildOpsnippet, the production-readiness list, troubleshooting, and resources.Supporting changes:
snippets/nonce-lane-diagrams.jsx— six theme-aware SVG diagrams following the existing Giga diagram convention (currentColorink,--sei-maroon-50accent).docs.json— one line, adding the page to Ecosystem Tutorials.evm/index.mdx— a card in Use Cases..github/styles/Sei/Headings.yml— one line, addingERCto the exceptions list (see Notes).Renamed and corrected
Reviewers of the first version should know what changed and why.
The title over-promised and under-served. "Parallel nonce" names a mechanism that does not exist — EVM nonces are never parallel; the feature is ERC-4337's two-dimensional nonce. In Sei's docs "parallel" also reads as parallel execution, so the old title created an association the page then needed a
<Warning>to undo. "HFT" over-claimed (the reference implementation has no strategy engine, market data, or order book) while excluding the keepers, liquidators, and batchers the pattern serves equally well.A load-bearing factual claim was wrong. The page stated that
eth_getTransactionCount(address, "pending")returns the same value as"latest".evm/referencedocuments the opposite: the pending tag returnsEvmNextPendingNoncefrom the mempool. The supportable claim is the one inevm/evm-parity/finality— a pending nonce differing from the confirmed nonce is unreliable. Reworded, not restructured: the design argument holds either way, because its hot path reads no nonces at all.The comparison table overstated the result. It set
LANE_POOL_SIZE"up to 4096" against a wallet fleet's N, which compares signed-and-unresolved operations against concurrent transactions. Those are now separate rows, broadcast width is stated asRELAYER_COUNT, and the text says plainly that a wallet fleet can match the width — what it cannot match is doing so from one balance, one approval set, and one key."Private mempool" named a component that does not exist. A mempool is a shared admission buffer: transactions arrive from strangers, are gossiped, and wait for whichever producer or bundler picks them up. The reference implementation has none of that — its queue is an in-process array, filled only by the process that signed the operations and gone when that process exits. The old name sent readers looking for gossip, admission policy, and eviction, and it was especially confusing on a page where "mempool" otherwise means Autobahn's producer mempool two sections earlier. It is now a bundling queue, which says what it does: hold signed UserOperations and pack them into lane-safe
handleOpsbundles. The paragraph explaining the ERC-7562 exemption now leads with why the component is not a mempool, since that is exactly what earns the exemption — an in-process queue never enters the alt-mempool, soSAME_SENDER_MEMPOOL_COUNTnever applies. The upstream repository made the matching rename (PrivateMempool→BundlingQueue,mempool.ts→bundling-queue.ts), so thebuildOpsnippet now readsbundlingQueue.add(...). Every remaining "mempool" on the page refers to a real one.Navigation. The first version added a top-level High-Frequency Trading group holding one page, which put a niche topic ahead of the core sei-js group. The page now sits in Ecosystem Tutorials alongside the other standalone tutorials, which is also where the account-abstraction pages live.
Smaller fixes: retitled "The moat" (AGENTS.md asks for no investment framing); attributed the mempool to Autobahn under Giga mode to match
node/technical-reference; replaced the hard-coded 400 ms figure with pointers to Twin-Turbo and Giga, sincesei-giga-specswarns against mixing current and Giga numbers; cross-linked Pimlico and Thirdweb EIP-7702 with guidance on when a hosted bundler is the better choice; fixed two British spellings that_typos.tomlwould not catch because it sets no locale.Notes
mint broken-linksandmint validateboth pass. Vale andtyposreport 0 errors and 0 warnings. TheSei.Headingswarning noted earlier on "ERC-4337 nonce lanes" is fixed here rather than deferred: the rule flagged any heading containingERC-<digits>becauseERCwas missing from the exceptions list, which also affected several existing pages. That is a one-line change to.github/styles/Sei/Headings.yml; say the word if you would rather it were a separate PR.main).llms.txtis left to the scheduled regeneration workflow.