Reproduced Exploit
GTE: Non-strict crossing check traps min-tick backstop bids
Chain
Other
Category
untagged
Date
Jan 1970
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 64835-h-02-backstop-bid-side-frozen-by-tick-size-constraint-code4r. The historical source/toolchain is unavailable; this entry is documentation only and claims no executable Forge PoC.
Vulnerability classes: vuln/locked-funds · vuln/price
Reproduction: a faithful minimal reproduction of the vulnerable finding — the vulnerable function is reproduced verbatim (marked
@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
if (ds.getBestAsk() <= newOrder.price) uses a non-strict <=, so a backstop bid at the minimum tick is treated as crossing a min-tick ask and reverts, permanently freezing backstop bid placement at that level.
function _executeBuyOrder(Book storage ds, Order memory newOrder, TiF tif) internal {
// if price crosses the book
if (ds.getBestAsk() <= newOrder.price) { // @> CLOBLib.sol:231 non-strict `<=` traps the min-tick bid against a min-tick ask
if (tif == TiF.MOC) revert PostOnlyOrderWouldBeFilled();
}
Why it's exploitable here#
An attacker parks a SELL backstop maker (MOC) at price == tickSize, so getBestAsk() == tickSize; every legal backstop BID is a positive multiple of tickSize (minimum == tickSize == bestAsk), so the non-strict getBestAsk() <= newOrder.price post-only crossing rule always fires and reverts PostOnlyOrderWouldBeFilled — no backstop bid can ever be posted, permanently freezing the backstop bid side (liquidation-engine liveness DoS).
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in 0x671d353a77…:
- L109 — Place a new order: Setup: entry point that posts
newOrderinto the book, routing bids through the post-only crossing check below. - L124 — Non-strict crossing check bug: The post-only guard uses
<=, so a bid priced exactly at the best ask (both at min tick) is wrongly seen as crossing and reverts; should be<. - L128 — Raise best-bid marker: Updates
bidMaxwhen this bid is the new highest — code that never runs because the crossing check above reverts first. - L129 — Increment resting bid count: Bumps
numBidsto record the posted bid, also unreachable for a min-tick backstop bid due to the revert. - L132 — Execute a sell order: Setup: handles the SELL side; the attacker uses it to park a min-tick maker ask that pins
getBestAsk()totickSize. - L151 — Place-order library overload: Setup: a second
placeOrderoverload in the order-book library. - L224 — Initialize best-bid to zero: Setup: resets
bidMaxto its minimum value when the book is first created.
PoC#
Registry (Foundry, local deploy — verbatim vulnerable source + harm-asserting test + negative control):
cd 64835-h-02-backstop-bid-side-frozen-by-tick-size-constraint-code4r_exp
forge test -vvv
The browser Playground replays the same synthetic opcode-for-opcode and measures the harm: An attacker parks a SELL backstop maker (MOC) at price == tickSize, so getBestAsk() == tickSize; every legal backstop BID is a positive multiple of tickSize (minimum == tickSize == bestAsk), so the non-strict getBestAsk() <= newOrder.price post-only crossing rule always fires and reverts PostOnlyOrderWouldBeFilled — no backstop bid can ever be posted, permanently freezing the backstop bid side (liquidation-engine liveness DoS).. Both gates are green (registry forge test PASS + Playground _verify-poc VERDICT: PASS).
Sources & further analysis#
Reproductions & code
- No executable Forge reproduction is claimed; the historical source/toolchain was unavailable for this finding.
- AuditVault finding: 64835-h-02-backstop-bid-side-frozen-by-tick-size-constraint-code4r.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "GTE: Non-strict crossing check traps min-tick backstop bids".
- Web3Sec X hacked database: search.
- Rekt leaderboard: search.
- Solodit incident search: search.
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.