Skip to main content
Sei EVM executes non-conflicting transactions in parallel. If you design contracts that minimize shared state access and avoid unnecessary storage writes, you can increase throughput significantly and reduce gas.
This guide is based on Sei’s recommendations to reduce gas usage and improve parallel execution. For the engine design, see the parallelization engine page.

Principles for parallel-friendly contracts

  • Minimize shared writes: The scheduler can parallelize transactions that do not write to the same storage keys. Avoid hot globals (for example, a single counter that every call updates).
  • Partition state: Shard storage by user, asset, or ID so that independent transactions touch disjoint keys.
  • Prefer pull over push: Let users claim funds instead of paying many recipients in a loop.
  • Avoid unbounded loops: This applies especially to loops that write to storage or iterate over dynamic arrays or mappings.
  • Batch internal work and isolate external effects: Do heavy computation in memory and commit a minimal set of storage writes.
  • Use precompiles when available: Precompiles are highly optimized and cost less than the same logic written in Solidity.
Parallelization checklist:
  • Partition storage by user, asset, or ID, and avoid hot globals
  • Minimize the number of storage writes per call: batch work in memory and commit once
  • Avoid loops with storage writes, and switch to pull-based flows
  • Favor precompiles for supported features
  • Apply standard gas optimizations (external, packing, unchecked, memory-first)

Storage design patterns

Partition state by key

Isolate per-user and per-asset data instead of centralizing writes.
Anti-patterns:
  • Writing a global totalVolume += amount; in every transaction
  • Maintaining a single on-chain queue or registry that most calls update
Prefer to compute aggregates off-chain from events. Alternatively, update them periodically through a dedicated maintenance transaction and place them in the calldata.

Prefer pull payments

Avoid writing to many recipients in a single transaction. Emit events, and let recipients call withdraw() when they need to.

Avoid large storage writes in loops

If you must process many items, keep the work in memory and commit a compact result. Alternatively, split the work across multiple transactions keyed by different IDs.

Gas-efficient Solidity practices

  • Use external for externally called functions. Mark pure and read-only functions with pure and view.
  • Pack variables to share storage slots (for example, multiple uint8 values in one slot).
  • Prefer bytes32 over string when applicable.
  • Cache array lengths in loops and short-circuit cheap conditions first.
  • Use unchecked for arithmetic when overflow is impossible.
  • Prefer memory over storage for temporary data, and commit only final values.
These practices reduce gas and often reduce storage access, which also improves parallelism.

Leverage Sei precompiles

Sei has precompiled contracts for common functionality. They are cheaper and simpler than custom Solidity equivalents: See precompile examples for quick starts.

Testing and analysis

  • Use Foundry or Hardhat gas reporters to track changes per function.
  • Benchmark under concurrent load to detect hot keys (addresses or IDs) that serialize execution.
  • Inspect execution with JavaScript tracers and runtime logs.