NatConsensus

Market Prices

Coin Price 24h
BTC Bitcoin
$81,558.8 -1.06%
ETH Ethereum
$2,393.88 -1.21%
SOL Solana
$104.31 -0.41%
BNB BNB Chain
$727.9 +0.28%
XRP XRP Ledger
$1.3 -1.02%
DOGE Dogecoin
$0.0791 -0.84%
ADA Cardano
$0.2164 -2.48%
AVAX Avalanche
$9.51 -2.71%
DOT Polkadot
$1.14 +1.11%
LINK Chainlink
$11.93 -1.78%

Fear & Greed

55

Greed

Market Sentiment

Event Calendar

{{ๅนดไปฝ}}
18
03
unlock Sui Token Unlock

Team and early investor shares released

10
05
upgrade Ethereum Pectra Upgrade

Raises validator limit and account abstraction

08
04
upgrade Solana Firedancer

Independent validator client goes live on mainnet

30
04
upgrade Celestia Mainnet Upgrade

Improves data availability sampling efficiency

28
03
unlock Arbitrum Token Unlock

92 million ARB released

22
03
unlock Optimism Unlock

Circulating supply increases by about 2%

12
05
halving BCH Halving

Block reward halving event

15
04
halving Bitcoin Halving

Block reward reduced to 3.125 BTC

Altseason Index

40

Bitcoin Season

BTC Dominance Altseason

Gas Tracker

Ethereum 28 Gwei
BNB Chain 3 Gwei
Polygon 42 Gwei
Arbitrum 0.5 Gwei
Optimism 0.3 Gwei

Market Cap

All โ†’
1
Bitcoin
BTC
$81,558.8
1
Ethereum
ETH
$2,393.88
1
Solana
SOL
$104.31
1
BNB Chain
BNB
$727.9
1
XRP Ledger
XRP
$1.3
1
Dogecoin
DOGE
$0.0791
1
Cardano
ADA
$0.2164
1
Avalanche
AVAX
$9.51
1
Polkadot
DOT
$1.14
1
Chainlink
LINK
$11.93

๐Ÿ‹ Whale Tracker

๐ŸŸข
0x8837...68ef
1d ago
In
3,359,083 DOGE
๐Ÿ”ด
0x3fd0...e732
12m ago
Out
2,454 ETH
๐Ÿ”ด
0x8ede...312d
2m ago
Out
4,591 SOL

๐Ÿ’ก Smart Money

0x3e50...6426
Experienced On-chain Trader
+$4.5M
95%
0x7be5...88a7
Institutional Custody
+$0.3M
60%
0x2fd8...db77
Top DeFi Miner
+$1.7M
80%

๐Ÿงฎ Tools

All โ†’
Exchanges

ether.fi's AtomicQueue Was Never Locked: A 15.45 ETH Warning Shot for Every Solver-Based Protocol

CryptoAnsem

It was 2:47 a.m. in Mumbai when my phone lit up on the nightstand.

SlowMist had dropped a thread about ether.fi, the liquid restaking giant, and the number attached to it was almost insultingly small. Fifteen point four five ETH. Roughly fifty thousand dollars at the time it moved. In a market where a single whale's slippage costs more than that on a bad Tuesday, 15.45 ETH should not be a story. It should be a rounding note.

It is a story. And it is a story because of one line inside the disclosure. A function called solve(), the engine room of ether.fi's AtomicQueue contract, had no caller verification. None. No role check. No owner check. No whitelist. No allowlist. Nothing. Any address on the planet could walk up to that function, declare itself a solver, and ask the queue to move somebody else's tokens using an approval that user had granted months ago and forgotten about.

The loss was small. The permission gap was not. This is the class of bug that does not stop at 15.45 ETH, it stops when somebody decides to scale it.

I run monitoring scripts that watch exactly this kind of contract, and I want to walk through what actually happened here, because the pattern is going to repeat and the headline number is going to fool a lot of people into staying exposed.

Let me set the stage, because if you have not been living inside restaking for the last two years, the architecture matters.

ether.fi is one of the largest liquid restaking protocols on Ethereum. The pitch is straightforward. You deposit ETH, the protocol stakes it, and you receive a liquid token in return, ezETH, which you can then take into DeFi and use as collateral or liquidity while your underlying ETH keeps earning. The next layer is EigenLayer, which lets that staked ETH secure additional networks in exchange for extra yield. ether.fi also has its own governance and incentive token, ETHFI, and at its peak the protocol sat inside the top tier of DeFi TVL rankings. This is not a weekend project. This is infrastructure with billions of dollars of user deposits flowing through it.

Now the part that matters. Inside that machine sits a contract called AtomicQueue.

The queue exists because Ethereum execution is expensive and awkward. Blocks come every twelve seconds. The mempool leaks. Gas spikes without warning. If every single user action had to be submitted directly and priced individually, you would get failed transactions, griefing, and a lot of capital sitting idle waiting for a cheap block. So teams push execution off chain. Users submit requests into a queue. A designated bot, the solver, picks those requests up, batches them, prices them, and writes the final state back on chain in a single efficient transaction. The queue is shared memory. The solver is the writer.

This design is everywhere now. It is in order flow auctions, intent systems, cross-chain executors, MEV extraction pipelines, account abstraction bundlers. It is genuinely good engineering when it works, and I have watched it work well in plenty of places.

Here is the thing though. The entire design only functions if the solver role is actually enforced somewhere. If solve() accepts calls from anyone, then the solver is not a role at all. The solver is just a function name that any script with a JSON-RPC endpoint can call.

And layered underneath all of this sits the ERC-20 approval model, which is the other half of the crime scene.

When you interact with most DeFi front ends, you click approve. What that click does is grant a contract an allowance, permission to move a specific amount of a specific token out of your wallet. Interfaces overwhelmingly default to the maximum, type(uint256).max, because re-approving on every single transaction is expensive and maddening. So you click once, you move on with your life, and a standing permission sits there. It does not expire. It does not care whether you still use the protocol. It does not care whether the protocol's contract has been patched, abandoned, or broken. It waits.

Put the missing modifier next to the standing allowance and you have a loaded weapon with a trigger that anybody can pull.

Here is the anatomy, as far as the public disclosure goes.

There are two functions at the center of this. The first is solve(), which executes items in the queue. In any sane implementation, this function carries a modifier. OpenZeppelin's AccessControl library has been battle-tested since 2018, and a single line, onlyRole(SOLVER_ROLE), would have closed the entire attack surface. Instead, according to the disclosure, the function had no check at all.

The second is updateAtomicRequest(), which updates the parameters of an existing queued request. Per the disclosure, it allowed arbitrary data to be pushed into a request, including the fields that determine who the solver is and where the funds ultimately go.

Chain those together and the flow is brutally simple. The attacker builds a malicious request. The attacker uses updateAtomicRequest() to rewrite fields inside it, including the identity of the solver and the destination of the payout. The attacker then calls solve() from an address that the contract happily treats as a legitimate executor, because the contract never asked who was calling. The contract assembles what it believes is a normal queued job, and it pulls tokens out of the victim's wallet using the allowance that victim granted long ago, routing them wherever the manipulated request says.

Five things are worth naming out loud, because each one inverts an assumption most people hold about DeFi risk.

One: no cryptography was broken. Zero. The signatures, the hashes, the storage proofs, all of it worked exactly as designed.

Two: no private key was compromised. Nobody's seed phrase was phished. Nobody's hardware wallet was bypassed.

Three: there was no reentrancy, no flash loan, no oracle manipulation, no sandwich attack, no price-feed manipulation. The entire vocabulary of DeFi vulnerability that we have spent five years training auditors to hunt for is absent from this incident.

Four: the weapon was the user's own historical action. A click on Approve, months or years ago, executed in good faith against a contract that looked legitimate, which it was.

Five: the trigger was an if-statement that should have existed and did not. That is it. That is the whole thing.

I call this a permission-slip exploit, and it deserves its own category, because the security stack we have built has almost nothing to say about it. There is no clever math to catch in review. There is no economic model to stress-test. There is no adversarial simulation that reveals it unless the simulation happens to call the function from an unauthorized address, which most test suites do not bother doing, because the developers already know who the solver is.

Now the number everyone is staring at, which is the wrong number.

Fifteen point four five ETH is not the blast radius. The blast radius is the aggregate of every outstanding allowance ever granted to the AtomicQueue contract by every address that has ever touched ether.fi.

That number is unknown. Nobody has published it. That is the point. Every one of those allowances is a live, unexpired, unmonitored permission sitting in a contract that, as of the disclosure, would execute a manipulated request from a stranger. Patch the contract tomorrow and those wallets are still exposed until their owners act. The fix is a code change. The exposure is a behavior change, and behavior changes are slower.

So why did the loss stay small? I have four working hypotheses and I do not think they are mutually exclusive.

The first is that this was a probe. Attackers who find a permissionless drain almost never empty everything at once. They test with one address, watch for whether monitoring trips, watch whether the team notices, and then decide. Fifteen point four five ETH is a canary in a coal mine, and the canary is still alive, which tells the attacker something useful.

The second is a routing constraint. The drain likely only reaches funds that satisfy two conditions simultaneously: the wallet holds a live allowance to AtomicQueue, and the attacker can shape a request path that touches it. Not every approved wallet is exploitable. Only the ones with something pending in a queue path the attacker can construct. That narrows the immediate pool considerably, and it explains why the number is small even if the exposure is large.

The third is economics. At mainnet gas prices, draining a wallet with forty dollars of tokens in it is not profitable. So a rational attacker sorts by size, works down from the top of the list, and skips the dust. That implies an address-scanning campaign, which implies someone is sitting on a dataset of approved addresses right now, sorted by balance.

The fourth is attention. Once SlowMist publishes, the clock becomes public. An attacker who found this path two weeks ago and said nothing had a much better run than an attacker who finds it today. Which means the smartest version of this attack already happened, quietly, and we may never see it in a headline.

My read: probe, or partial, and both of those point in the same ugly direction.

Then there is the audit question, and this is the part that should bother every protocol team reading this.

A missing onlyRole is not a subtle bug. It is not a rounding error in a share calculation. It is not a stale oracle feed, or a cross-function reentrancy that requires a precise state machine to trigger. It is the most basic failure mode in the entire smart contract canon, and it appears on page one of every audit checklist ever written. A team that catches delegatecall-to-untrusted-address cannot miss this unless nobody looked.

So how does a missing access control check reach mainnet on a protocol with billions in TVL? Three explanations, and I have seen all three up close.

Explanation one: the contract was never audited. Not the whole protocol, obviously, but this specific file. Auxiliary contracts that sit next to the money often get written by a small team under time pressure, shipped because they are not the custody layer, and never enter scope. Every audit is scoped by file. What is outside scope is unaudited by definition, no matter what the press release says.

Explanation two: the contract was audited, but the scope explicitly excluded the queue logic. This happens constantly. Teams audit the vault, the share math, the oracle integration, and treat the execution helper as plumbing.

Explanation three, and this is the one that keeps me up at night: the modifier was there, and a later refactor removed it. A gas optimization pass. A library swap. A migration from Ownable to AccessControl. A cleanup commit in a Friday afternoon PR that nobody read carefully because it was labeled refactor. Refactor drift is invisible in a final audit report, because the report describes a version of the code that no longer exists on chain. It is the dominant cause of this entire genre of bug, and no audit process on the market reliably catches it, because audits are point-in-time photographs of a moving target.

I will say the quiet part. If explanation three is correct, the report said safe and the code said open, and the gap between those two documents is where user funds live.

This is the same disease as the Layer2 sequencer problem I have been writing about for two years. Decentralized sequencing has been a slide deck for a very long time. A sequencer is a single node with privileged ordering rights, everyone in the room knows it, and the roadmap says it will be decentralized later. Solver-based DeFi is that same structure applied to execution. You have a privileged writer to shared state, marketed as a competitive marketplace, and the privilege is enforced by a modifier. Or, in this case, by nothing.

I have also made the argument, repeatedly and to some irritation, that Aave and Compound's interest rate curves are arbitrary constructions. The kink at eighty percent utilization, the jump multiplier, the slope parameters, none of it is derived from observed supply and demand. It is a governance vote wearing an engineering costume. I bring that up here because it is the same structural habit. A parameter that looks technical is actually a policy choice, and nothing in the code enforces the story people tell about it.

In this case the story was simple and reassuring: only solvers can call solve(). The code did not enforce it. Same gap, much smaller stakes, and this time somebody got paid.

To be fair to the architecture, because I am not here to dunk on a design I actually like: batching saves real gas. A designated executor genuinely reduces failed transactions. Off-chain computation is genuinely cheaper than on-chain computation. None of that is wrong. What is wrong is giving the executor authority without a permission system, and then treating the executor's own good behavior as the security boundary. That is not a security model. That is a hope with a JSON-RPC endpoint.

If you have ever touched ether.fi, here is what you do tonight, and I mean tonight, not after you finish reading another thread.

Open revoke.cash, or Etherscan's Token Approvals tool, and paste in every address you have ever used with ether.fi or its integrations. Look for allowances to the AtomicQueue contract and set them to zero. Zero, not a smaller number. Partial allowances still permit partial drains, and partial drains of a large position are still your money gone. While you are in there, revoke the approvals you do not recognize, because every wallet in DeFi is carrying a shadow ledger of forgotten permissions and this is the cheapest moment you will ever get to clean it.

Yes, revoking costs gas. On mainnet that is real money. Pay it anyway. Thirty or fifty dollars of gas to remove a live permission from a contract with an unknown exposure list is the best trade you will make in this market.

If you are a protocol integrating with ether.fi, check whether your own contracts hold allowances to AtomicQueue. A smart contract treasury with an infinite approval is a vault with a door that has no lock on it, and it will not complain when it gets drained, because contracts do not have feelings.

People keep asking me what my monitoring scripts actually look for, so here it is, briefly. I track first-time approve() calls to contracts younger than ninety days. I flag any contract that receives approvals and also exposes an ungated mutating function in its verified source, which is a manual review, not an algorithm, and it is the part I cannot automate away. And I watch for solve, execute, fill, and fulfill call patterns from addresses that have never appeared in a contract's history, because the very first time a brand new address calls an executor function, you are usually watching history get made.

That third signal is the one that mattered here. A solve() call from a fresh address is visible on chain before the funds settle. Which means the loss was not discovered after the fact. It was discoverable in the mempool, seconds before finality, by anyone watching.

Most DeFi losses are visible in the mempool before they finalize. Almost nobody is watching. That is the entire industry's problem in one sentence.

Now the part everyone is going to get wrong, so let me say it before the timelines do.

The headline you will read tomorrow is ether.fi drained of 15.45 ETH. That is the wrong headline. The right one is this: a permissionless executor function has been live on a multi-billion-dollar restaking protocol, and nobody currently knows how many wallets are still standing in front of it.

The second unreported angle is the disclosure itself. SlowMist's tweet is simultaneously a public service and a public invitation. The moment a missing access control check gets named in public, every bot operator and half-decent script kiddie can grep the verified source for other ungated functions and start probing. The window between disclosure and patch is the most dangerous period of the entire incident, more dangerous than the period before it, because before the tweet only one attacker knew and now everyone does. That is the unsolvable tension inside responsible disclosure, and I do not have a clean answer for it. Warn the users, arm the attackers, hope the patch lands first.

The third angle is that this industry has standardized everything except the thing that just failed. We have ERC-20, ERC-721, ERC-1155, ERC-4626 for tokenized vaults, ERC-4337 for account abstraction. We do not have a standard access control pattern for solver-based execution. So every team invents their own, and the teams that invent it badly do not find out until someone fuzzes a function name or reads the source looking for a missing word.

And here is the prediction that will annoy people: this happens again within six months, to a project with a bigger number attached. Every condition is present. Dozens of protocols are shipping intent-based and solver-executed flows right now, under time pressure, with new hires writing critical execution paths. The reward for finding a missing modifier is immediate, denominated in hard currency, and functionally untraceable. 15.45 ETH is the price of a lesson. The next tuition payment will not be so cheap.

So what am I actually watching over the next two weeks?

Four things. First, whether ether.fi publishes a patch that includes the diff. Not an announcement, not a blog post about their commitment to security, an actual diff. An access control fix is four lines of Solidity. If those four lines are not public, the fix did not happen, and you should treat the contract as still open.

Second, whether the attacker returns the funds. A RETURN transaction on chain is the tell that a private negotiation happened, and those usually follow a bounty conversation rather than a police report. If the ETH comes back, the incident gets downgraded to a footnote. If it does not, expect a longer tail.

Third, whether SlowMist or PeckShield flags the same request-queue-plus-offline-solver pattern somewhere else. If they do, this stops being an ether.fi story and becomes an architecture story, and the market will have to reprice every protocol that runs a privileged executor against shared state.

Fourth, the revoke volume. If approval revocations to AtomicQueue spike above normal user churn, the market understood the risk even if the token price did not move. Watch the chain, not the chart. The chart is a lagging indicator of other people's conclusions. The chain is the conclusion happening.

The 15.45 ETH is already gone. It left somebody's wallet, it is sitting somewhere, and it is not coming back unless somebody negotiates. That money is a sunk cost and there is nothing to do about it.

The approvals are not gone. They are still there, still live, still waiting. And they represent a number that is almost certainly larger than 15.45 ETH, possibly much larger, and entirely unknowable from the outside.

So here is the question I want every single reader to answer honestly before they close this tab. How many contracts can still spend your tokens right now, at this exact moment, without your permission, without your signature, without you knowing it is happening?

Can you name them? All of them?

If the answer is no, you are not holding assets. You are holding permissions you forgot you gave, and tonight the market just showed you exactly what a forgotten permission is worth.