Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.stablenet.network/llms.txt

Use this file to discover all available pages before exploring further.

Transactions sent to StableNet sit in the transaction pool (mempool) until they are included in a block. Understanding the pool explains why a transaction is waiting and how to unstick it.

Two states: pending and queued

Every transaction in the pool is in one of two states:
StateConditionIncluded in next block?
PendingNonce matches sender’s current on-chain nonceYes — eligible immediately
QueuedNonce is higher than current on-chain nonceNo — waiting for lower nonces first
A transaction moves from queued to pending automatically once all preceding nonces from the same sender are confirmed.

Why your transaction is pending

The most common reasons:
  1. Nonce gap — you sent nonce 5 but nonce 4 is still pending. Nonce 5 sits in the queued state until nonce 4 is included.
  2. Gas tip below minimum — the governance-enforced minimum maxPriorityFeePerGas was not met. The transaction is rejected at submission, not queued.
  3. Insufficient balancebalance < value + gasLimit × maxFeePerGas. The transaction fails validation.
  4. Pool full — the global pending limit (5,120 slots by default) is reached and your transaction has lower priority than existing ones.

Gas tip and priority

On StableNet, gas tip competition works differently from Ethereum mainnet. For general accounts, the effective gas tip is fixed by the GovValidator governance contract. All general-account transactions pay the same tip — you cannot outbid other users. For authorized accounts (set by GovCouncil), the GasTipCap in the transaction is used as-is, enabling custom priority. This means pending time is determined almost entirely by nonce order and pool capacity — not by how high you set your tip.

Replacing a stuck transaction

To replace a pending transaction, submit a new transaction with the same nonce and a gas price at least 10% higher than the original:
const replacement = await wallet.sendTransaction({
  to: originalTx.to,
  value: originalTx.value,
  nonce: originalTx.nonce,               // same nonce
  maxPriorityFeePerGas: ethers.parseUnits("30360", "gwei"),  // ≥ 10% above original
  maxFeePerGas: ethers.parseUnits("90000", "gwei"),
});
The 10% bump requirement prevents spam-replacement of transactions by trivially higher bids.

Inspecting the pool

Use the txpool namespace to inspect pool state:
// All pending and queued transactions
const content = await provider.send("txpool_content", []);

// Pending count and queued count
const status = await provider.send("txpool_status", []);
console.log("pending:", parseInt(status.pending, 16));
console.log("queued:", parseInt(status.queued, 16));

// Transactions from a specific address
const mine = await provider.send("txpool_contentFrom", [wallet.address]);

Pool limits

LimitDefaultDescription
Per-account pending16 slotsMax pending txs per sender
Per-account queued64 slotsMax queued txs per sender
Global pending5,120 slotsTotal pending across all senders
Global queued1,024 slotsTotal queued across all senders
When the pool is full, the lowest-priority transactions are evicted first. Locally submitted transactions (via RPC) are protected and evicted last.

What happens after block inclusion

When a new block is added, the pool:
  1. Removes transactions included in the block
  2. Promotes queued transactions whose nonce gaps are now filled
  3. Re-validates remaining transactions against updated balances
  4. Queries GovValidator for the latest gas tip and updates filtering

Developer benefits

  • Pool state is queryable — use txpool_contentFrom to monitor your own transactions
  • Nonce gaps are the primary cause of stuck transactions — manage nonces carefully in concurrent senders
  • Replacement is predictable — 10% price bump guarantees replacement