Skip to content

Avoid false-positive settlement cancellations during node receipt lag#4510

Open
squadgazzz wants to merge 11 commits into
mainfrom
fix/driver-skip-cancel-when-already-mined
Open

Avoid false-positive settlement cancellations during node receipt lag#4510
squadgazzz wants to merge 11 commits into
mainfrom
fix/driver-skip-cancel-when-already-mined

Conversation

@squadgazzz

@squadgazzz squadgazzz commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Description

On some chains (Avalanche especially) the node reports a new block before its by-hash receipt lookup catches up. Right after our settlement mines, the driver asks "did my tx land?" by hash, gets "not found", and re-simulates the tx against the pending state to check it still works. That state already includes our just-mined (or still-queued) settlement, so the re-run reverts (GPv2: order filled on a full fill, transfer amount exceeds balance on a partial). The driver reads that as a real revert, cancels (the cancel then fails with nonce too low), and reports the settlement as failed even though it landed. This is the main source of the Avalanche "too many failing settlements" alert, and the settlements actually succeed on-chain.

Instead of trusting the lagging by-hash lookup, the driver now leans on two signals that do not lag:

  • Our Settlement event in the latest block. The contract emits it only on a successful settle, and eth_getLogs reads block logs directly, so it sees the event while the receipt-by-hash lookup is still catching up. If it is there, the tx mined, so report success.
  • The signer's pending nonce (eth_getTransactionCount with the pending tag). While our tx is still in the mempool the pending nonce sits above the nonce we submitted with, so the re-simulation revert is just our own queued tx re-applied, a false positive, and we keep waiting. Only when the pending nonce shows our tx has left the mempool, and the re-simulation still reverts, do we cancel.

An earlier version of this PR used eth_getLogs on the pending block for the second signal, but measuring our nodes showed pending log queries are rejected on 4 of 11 chains (polygon, bnb, arbitrum, linea, with "pending logs are not supported"). eth_getTransactionCount on pending is accepted on all 11, and since the re-simulation already runs against the pending state, the two signals read the same state.

Old code cancelled whenever the re-simulation reverted, minus a brittle GPv2: order filled string match that only caught full fills. New code cancels only when the tx is provably gone from the mempool, so a settlement that is mined-but-receipt-lagging or still queued is never cancelled.

Changes

  • Added Ethereum::contains_successful_tx, which checks for our Settlement event in the latest block via eth_getLogs.
  • Added Ethereum::pending_transaction_count, the signer's nonce including the mempool.
  • Reworked the submission loop: report success when the settlement event is already in the latest block, and cancel only when the re-simulation reverts and the pending nonce shows the tx has left the mempool. Anything else keeps waiting.
  • Dropped the old GPv2: order filled revert-byte special case.

How to test

New unit tests cover the cancel decision (requires_cancellation): a revert with the tx gone from the mempool cancels, a revert while the tx is still queued waits, and an unknown pending nonce never cancels.

The log and nonce lookups and the receipt-lag race itself have no automated coverage. The e2e harness runs anvil, which returns receipts immediately, so it cannot reproduce the lag. Verify on Avalanche: settlements that land on-chain should stop being counted as driver_settlements{result="SubmissionError"} and should stop logging a cancel right after a re-simulation revert, while still showing up as on-chain settlements.

@squadgazzz squadgazzz force-pushed the fix/driver-skip-cancel-when-already-mined branch from 4c41108 to 87d39e9 Compare June 9, 2026 10:05
@squadgazzz squadgazzz changed the title Skip settlement cancellation when the tx is already included on-chain Detect on-chain settlement via getLogs to avoid false-positive cancellations Jun 9, 2026
@squadgazzz squadgazzz force-pushed the fix/driver-skip-cancel-when-already-mined branch 2 times, most recently from 6924402 to cd96b8e Compare June 9, 2026 11:23
@squadgazzz squadgazzz force-pushed the fix/driver-skip-cancel-when-already-mined branch from cd96b8e to e7efe37 Compare June 9, 2026 11:26
@squadgazzz squadgazzz marked this pull request as ready for review June 9, 2026 11:27
@squadgazzz squadgazzz requested a review from a team as a code owner June 9, 2026 11:27
@claude

claude Bot commented Jun 9, 2026

Copy link
Copy Markdown

Claude finished @squadgazzz's task in 3m 6s —— View job


PR Review

  • Read changed files
  • Analyze submission loop logic
  • Analyze settlement_block (eth_getLogs) implementation
  • Review unit tests
  • Post review

The diagnosis (Avalanche reports a new block before its receipt index catches up; re-simulation reverts on the already-mined tx and the driver cancels it) matches what's been seen in logs, and the fix — looking up the Settlement event via eth_getLogs to disambiguate — is sound. The classification helper is small, pure, and well covered. Below are the things I'd want addressed before merging.

Correctness

  1. Silently swallowing eth_getLogs errors recreates the original bug. crates/driver/src/domain/mempools.rs:281-283:

    match classify_resimulation(
        in_latest.unwrap_or_default(),
        in_pending.unwrap_or_default(),
        resimulation_reverted,
    ) {

    If both settlement_block calls return Err (RPC blip, rate limit, broken pending-tag support on a given node) and the re-simulation reverts, we collapse to ResimOutcome::Revert and cancel a tx that may well have mined. That is exactly the scenario this PR is fixing for Avalanche, just triggered by a different cause. Consider keeping the result inconclusive (or at least delaying the cancel decision) when both lookups errored — otherwise we silently regress as soon as the log endpoint flakes.
    At minimum, log a warn! on each Err from settlement_block so we can spot a chain where the lookup is consistently failing rather than discovering it via metrics weeks later. Fix this →

  2. Pending block tag behavior is node-dependent. eth_getLogs with fromBlock = toBlock = Pending is not consistently implemented:

    • geth returns logs from the pending block being assembled,
    • some Avalanche/erigon variants treat it like latest,
    • some return an error or empty array.
      When pending == latest we just get a redundant call; when it errors we hit issue (1). Worth documenting on settlement_block so a future reader understands why both tags are needed and what to expect per node. A note in Ethereum::settlement_block's doc comment would suffice.
  3. Stale comment in the post-loop fallback. crates/driver/src/domain/mempools.rs:335-336:

    // Do one last attempt to see if the transaction was confirmed (in case of race
    // conditions or misclassified errors like `OrderFilled` simulation failures).

    The OrderFilled special case is exactly what this PR removes, so the comment is now misleading. Either update it to reference the new receipt-lag rationale or drop the OrderFilled example.

Performance

  1. Three concurrent RPC calls per Pending block, every chain. Previously the loop did one re-simulation per block; it now also does two eth_getLogs queries on every poll. The Avalanche bug is the only known motivation, but the extra load applies workspace-wide. A few options, none required to merge but worth considering:
    • only issue the settlement_block calls when re-simulation reports a revert (lose parallelism, halve the steady-state RPC count),
    • guard behind a chain whitelist (only Avalanche today),
    • run the two log queries serially pendinglatest and short-circuit when one returns a hit.
      Given how cheap a filtered eth_getLogs(from=N, to=N, address=settlement, topic0=Settlement) is, the simplest change (option 1) is probably the right one — every block that doesn't revert is the happy path, and the log lookup buys you nothing there.

Nits

  1. crates/driver/src/domain/mempools.rs:269-272 comment refers to "a node can report a new block before its receipt index catches up" — that's accurate but generic. Calling out which chain motivated it (Avalanche) would help the next person debugging this code; otherwise it reads like a general-purpose race description and the chain-specific context is lost.

  2. SubmissionSuccess doc comments at crates/driver/src/domain/mempools.rs:578-584 are swapped — included_in_block carries the "started to submit" doc and submitted_at_block carries the "appeared onchain" doc. Pre-existing, not introduced here, but since this PR populates these fields with the new included_in_block from settlement_block it's a good moment to fix the comments.

  3. crates/driver/src/infra/blockchain/mod.rs:287-288from_block(block).to_block(block) is the same value twice. Slightly clearer as a single .at_block_hash/.at_block_number if you have one, but the explicit form is fine and matches the Pending use case where there's no concrete block number.

  4. ResimOutcome only logs the underlying gas error in the Inconclusive branch when it actually errored (good), but the PendingWillSucceed branch silently drops gas even if it was a revert. That's the right behavior, but worth a single-line comment explaining "we trust the pending-block hit over the simulation" — currently the absence of an error log there could read as a regression to someone debugging a real revert.

Tests

  1. classify_resimulation coverage is clean. The receipt-lag race itself has no test (as the PR description notes — anvil won't reproduce it), which is fine, but Ethereum::settlement_block has no test at all — not even a smoke test that confirms it filters by transaction_hash correctly. If you mock the event_filter().query() call (or extract the filter→matching logic into a pure helper) you can at least cover the "two events in one block, only ours matches" case.

Verdict

Approve with the cancel-on-double-error fix (item 1). Items 3, 6, and the chain-specific comment (5) are quick wins worth bundling in.
Branch

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism to handle submitted settlements whose receipts are not yet available by querying the Settlement event on both latest and pending blocks to classify the re-simulation outcome. The reviewer identified a critical issue where many Ethereum JSON-RPC providers do not support eth_getLogs on the pending block tag, which would cause the query to fail and lead to false-positive transaction cancellations. To address this, the reviewer suggested updating classify_resimulation to accept the Result of the pending query and check for known false-positive reverts (like GPv2: order filled) when the pending log query fails, along with updating the corresponding unit tests.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/infra/blockchain/mod.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs Outdated
@squadgazzz squadgazzz marked this pull request as draft June 9, 2026 18:43
@squadgazzz squadgazzz changed the title Detect on-chain settlement via getLogs to avoid false-positive cancellations Avoid false-positive settlement cancellations during node receipt lag Jun 9, 2026
@squadgazzz

Copy link
Copy Markdown
Contributor Author

@claude review

@claude

claude Bot commented Jun 9, 2026

Copy link
Copy Markdown

Claude finished @squadgazzz's task in 3m 59s —— View job


PR Review

  • Read changed files
  • Analyze submission loop logic
  • Analyze the new contains_successful_tx and pending_transaction_count helpers
  • Review the requires_cancellation decision and tests
  • Post review

The latest revision is a solid improvement over the version I reviewed earlier. Pinning the cancel decision to the signer's pending nonce (crates/driver/src/domain/mempools.rs:669-675) makes the original failure mode of "RPC blip on eth_getLogs collapses to a spurious cancel" unreachable: a log-lookup error now only loses the early-success shortcut, never triggers a cancel. The requires_cancellation helper is small, well-named, and the new tests (mempools.rs:721-737) cover the three cases that matter. Nice cleanup of ResimOutcome and the brittle GPv2: order filled byte-match.

A few things I'd want addressed before merging:

Correctness

  1. contains_successful_tx queries only Latest and races against the node's notion of Latest. crates/driver/src/infra/blockchain/mod.rs:278-290:

    .from_block(alloy::eips::BlockNumberOrTag::Latest)
    .to_block(alloy::eips::BlockNumberOrTag::Latest)

    The block stream just told us about block N, but by the time the RPC resolves Latest server-side it may already be at N+1 (or further on Arbitrum, where blocks land every ~250ms). When that happens we query a block our tx wasn't in, get Ok(false), lose the early-success path, and fall through to pending_nonce. pending_nonce will (correctly) keep us waiting until the receipt finally lands, so we don't cancel a mined tx — but on a chain where the receipt lag is the whole problem, we may sit there until the submission deadline and then trip the deadline-cancel path at mempools.rs:259-267, defeating the fix's purpose.

    Pass the stream's block.number through and pin the query to it:

    pub async fn contains_successful_tx(&self, tx_hash: TxId, block: BlockNo) -> Result<bool, Error> {.from_block(BlockNumberOrTag::Number(block.0))
        .to_block(BlockNumberOrTag::Number(block.0))
    }

    That's the block the loop is reasoning about, so there's no ambiguity. Fix this →

  2. pending_transaction_count doc is slightly imprecise. crates/driver/src/infra/blockchain/mod.rs:292-294:

    When this exceeds the nonce we submitted with, our tx is still queued in the mempool.

    Strictly speaking, count > submission_nonce only says some tx with our nonce is in the pending state — including a mined one (pending count stays at N+1 after mining), or a replacement we initiated (a cancel). The decision is still correct because (a) the driver owns the signer and (b) the early-success branch handles the mined case first, but a future reader looking at this in isolation might think the predicate is more discriminating than it is. One line clarifying "count > submission_nonce ⇒ our tx is either still queued or already mined" would help.

  3. included_in_block in the new success path isn't actually the block of inclusion. mempools.rs:289-293:

    return Ok(SubmissionSuccess {included_in_block: block.number.into(),
    });

    block.number is the block the loop is currently iterating, which is the block we detected the event in — not necessarily the block the tx mined in (could be one earlier under the same receipt-lag race). Worth a one-line comment that this is the detection block, since blocks_passed at mempools.rs:585-589 reports it as the inclusion delta. Combined with the existing swapped docstrings noted below, this is the kind of thing that quietly distorts metrics.

Carry-over from the previous review

  1. SubmissionSuccess field doc comments are still swapped. mempools.rs:577-580:

    /// At which block we started to submit the transaction.
    pub included_in_block: eth::BlockNo,
    /// In which block the transaction actually appeared onchain.
    pub submitted_at_block: eth::BlockNo,

    Pre-existing, but this PR is the one populating included_in_block from a new code path — a good moment to swap the docstrings back. Otherwise a future reader debugging metrics will believe the wrong field. Fix this →

  2. Performance concern from the prior review still stands. Every block where the receipt hasn't landed yet now fans out three concurrent RPC calls (estimate_gas, contains_successful_tx, pending_transaction_count) instead of one. On the happy path (block where re-simulation succeeds) only the simulation is interesting — the log/nonce lookups don't change the decision. Consider only firing them when estimate_gas errors:

    let gas = self.ethereum.estimate_gas(tx.clone()).await;
    let resimulation_reverted = matches!(&gas, Err(err) if err.is_revert());
    if !resimulation_reverted { /* normal log, continue */ }
    else {
        let (mined, pending_nonce) = futures::join!();}

    You lose ~one block-stream-interval of latency on the early-success path, but you halve steady-state RPC traffic. Not a blocker — flagging because it was raised before and isn't addressed here.

Tests / coverage

  1. Ethereum::contains_successful_tx still has no test (the PR description acknowledges this). It's the new method most likely to silently regress — e.g., a Settlement event from a different solver landing in the same block would be filtered out, but only because of the transaction_hash check at line 289. A small unit test that pins down "two events in one block, only ours matches" would protect this. Same for pending_transaction_count — at least a smoke test that the .pending() tag is being used (since the entire fix hinges on it).

Nits

  1. mempools.rs:7-11 — the alloy import group was reformatted from inline to one-per-line. Pure rustfmt artifact, not something to touch by hand, but it adds churn to the diff without any code change. If cargo +nightly fmt keeps re-flattening this on your machine, the difference is probably stale rustfmt.toml settings.

  2. mempools.rs:331-333 — the post-loop fallback comment is now correct and tidy. Nothing to fix; just noting it landed cleanly.

Verdict

The cancel logic is correctly hardened — items 1 (block-pinning the log query) and 4 (docstring swap) are the two I'd want before merging. Items 2, 3, 5, 6 are quick-win polish; the rest are nits.
Branch

@squadgazzz squadgazzz marked this pull request as ready for review June 10, 2026 11:32
@claude

claude Bot commented Jun 10, 2026

Copy link
Copy Markdown

Claude finished @squadgazzz's task in 2m 25s —— View job


PR Review

  • Read the latest changes on this branch
  • Analyze the new requires_cancellation decision logic
  • Analyze successful_settlement_block and pending_transaction_count helpers
  • Review tests
  • Post review

The latest revision lands all the blocking items from the prior reviews:

  • The log lookup is now pinned to an explicit [submission_block, head] range (crates/driver/src/infra/blockchain/mod.rs:282-301), so we no longer race the node's notion of Latest. As a bonus the range covers blocks the block stream may have coalesced past on fast chains.
  • included_in_block in the success path now comes from the log record itself (mempools.rs:295), not from "the block the loop is currently iterating", which makes blocks_passed/inclusion metrics honest.
  • pending_transaction_count has a precise docstring (blockchain/mod.rs:303-307) that calls out the queued-or-already-mined ambiguity and pairs cleanly with the early-success branch handling the mined case first.
  • requires_cancellation (mempools.rs:673-679) is small, well-named, and the tests at mempools.rs:725-749 cover the three cases that matter: revert + tx gone → cancel, revert + still queued → wait, unknown nonce → wait. The brittle GPv2: order filled byte-match is gone.

Nice cleanup. A few non-blocking things I'd consider folding in:

Non-blocking observations

  1. Err from successful_settlement_block is silently dropped. mempools.rs:281:

    if let Ok(Some(included_in_block)) = mined { ... }

    An Err (RPC blip, node-side eth_getLogs rejection, range too large) just falls through to the cancel decision. That's now safe — the cancel decision keys off pending_nonce, not mined — but it means a chain where the log lookup is consistently failing degrades silently to "no early-success shortcut", and you'd only spot it via the cancel-on-deadline metric weeks later. One warn! on Err would surface that. Fix this →

  2. Range query grows linearly per iteration. mempools.rs:273-277 calls successful_settlement_block(hash, submission_block.0, block.number). On every block where the receipt hasn't landed yet we re-scan all blocks since submission, even blocks we already scanned. For a long-running submission near the deadline this becomes O(n²) work for the node's log index. Two cheap mitigations:

    • track the highest block we've already scanned and only query [last_scanned + 1, head],
    • or just query the single block block.number since we re-enter every block — the comment about the block stream coalescing is the only reason to widen it, so range-of-one-block-plus-a-small-overlap would suffice.

    Not a regression vs. main (this code path didn't exist), so a follow-up is fine.

  3. Three concurrent RPC calls every block where the receipt lags. Same concern as the prior reviews — the happy path (simulation succeeds, no revert) doesn't need the log/nonce lookups at all. Gating them behind if estimate_gas.is_err() would halve steady-state RPC traffic and only adds one block-stream-interval of latency to the early-success path. Still not a merge blocker.

  4. No coverage for successful_settlement_block itself. The "two events in one block, only ours matches" case is filtered solely by the transaction_hash == Some(tx_hash.0) check at blockchain/mod.rs:298. If someone later refactors the filter and drops that line, the helper would silently return any successful settlement in the range as ours. A single small unit test would protect against that. (Per the PR description, the receipt-lag race itself can't be tested under anvil, which is fair.)

Verdict

Looks good to merge as-is. Items 1 and 4 are worth a follow-up; 2 and 3 are pure optimisations that can wait.
Branch

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the mempool transaction monitoring logic to prevent false-positive simulation reverts. It does this by checking if a transaction has already been mined (via eth_getLogs) or is still queued in the mempool (via pending nonce) before attempting cancellation. Feedback points out that unconditionally querying logs and pending nonces on every block is highly inefficient and suggests lazily evaluating these queries only when estimate_gas actually returns a revert error.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +271 to 324
let (gas, mined, pending_nonce) = futures::join!(
self.ethereum.estimate_gas(tx.clone()),
self.ethereum.successful_settlement_block(
hash,
submission_block.0,
block.number,
),
self.ethereum.pending_transaction_count(signer),
);

if let Ok(Some(included_in_block)) = mined {
// Found on-chain in [submission_block, head]. The receipt-by-hash
// lookup is just lagging, and scanning the whole range catches it
// even if the block stream coalesced past the block it mined in.
// Report success now rather than wait on the receipt and risk the
// deadline.
tracing::info!(
?hash,
?included_in_block,
"settlement found on-chain via getLogs, treating as success"
);
return Ok(SubmissionSuccess {
tx_hash: hash,
submitted_at_block: submission_block,
included_in_block,
});
}

let resimulation_reverted = matches!(&gas, Err(err) if err.is_revert());
if requires_cancellation(resimulation_reverted, &pending_nonce, nonce) {
tracing::info!(
settle_tx_hash = ?hash,
err = ?gas.as_ref().err(),
"tx dropped from the mempool without mining, cancelling"
);
let _ = self.cancel(mempool, final_gas_price, signer, nonce).await;
return Err(Error::SimulationRevert {
submitted_at_block: submission_block,
reverted_at_block: block.number.into(),
});
} else if let Err(err) = &pending_nonce {
tracing::warn!(
?hash,
?err,
"couldn't fetch the pending nonce, not cancelling"
);
} else if resimulation_reverted {
tracing::debug!(
?hash,
"tx still queued in the mempool, waiting for inclusion"
);
} else if let Err(err) = &gas {
tracing::warn!(?hash, ?err, "couldn't re-simulate tx");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Unconditionally querying eth_getLogs (successful_settlement_block) and eth_getTransactionCount (pending_transaction_count) on every single block is highly inefficient and will hammer the RPC node, especially on fast-block chains like Avalanche or Arbitrum. Since these checks are only needed to distinguish between a real revert and a false positive when the transaction re-simulation actually fails, they should be lazily evaluated only when estimate_gas returns a revert error.

                        let gas = self.ethereum.estimate_gas(tx.clone()).await;
                        let resimulation_reverted = matches!(&gas, Err(err) if err.is_revert());

                        if resimulation_reverted {
                            let (mined, pending_nonce) = futures::join!(
                                self.ethereum.successful_settlement_block(
                                    hash,
                                    submission_block.0,
                                    block.number,
                                ),
                                self.ethereum.pending_transaction_count(signer),
                            );

                            if let Ok(Some(included_in_block)) = mined {
                                tracing::info!(
                                    ?hash,
                                    ?included_in_block,
                                    "settlement found on-chain via getLogs, treating as success"
                                );
                                return Ok(SubmissionSuccess {
                                    tx_hash: hash,
                                    submitted_at_block: submission_block,
                                    included_in_block,
                                });
                            }

                            if requires_cancellation(resimulation_reverted, &pending_nonce, nonce) {
                                tracing::info!(
                                    settle_tx_hash = ?hash,
                                    err = ?gas.as_ref().err(),
                                    "tx dropped from the mempool without mining, cancelling"
                                );
                                let _ = self.cancel(mempool, final_gas_price, signer, nonce).await;
                                return Err(Error::SimulationRevert {
                                    submitted_at_block: submission_block,
                                    reverted_at_block: block.number.into(),
                                });
                            } else if let Err(err) = &pending_nonce {
                                tracing::warn!(
                                    ?hash,
                                    ?err,
                                    "couldn't fetch the pending nonce, not cancelling"
                                );
                            } else {
                                tracing::debug!(
                                    ?hash,
                                    "tx still queued in the mempool, waiting for inclusion"
                                );
                            }
                        } else if let Err(err) = &gas {
                            tracing::warn!(?hash, ?err, "couldn't re-simulate tx");
                        }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That loop runs per in-flight settlement, not globally per block, so I think it is fine to fire everything at once.

@MartinquaXD

Copy link
Copy Markdown
Contributor

Once you tested this on avalanche please share a graph of the improved submission rate or some other proof that this does indeed work correctly in prod.

@squadgazzz squadgazzz added the hotfix Labels PRs that should be applied into production right away label Jun 10, 2026
@squadgazzz

Copy link
Copy Markdown
Contributor Author

@MartinquaXD
image

@squadgazzz squadgazzz requested a review from MartinquaXD June 10, 2026 18:46

@MartinquaXD MartinquaXD left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some minor details.

Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs Outdated
Comment thread crates/driver/src/domain/mempools.rs
@squadgazzz squadgazzz added this pull request to the merge queue Jun 11, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hotfix Labels PRs that should be applied into production right away

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants