TL;DR
At 06:18:52 UTC on August 31, 2026, a single transaction emptied the WFLOW lending reserve of More Markets, an Aave V3 fork on Flow EVM. The attacker borrowed 15,488,124.15 WFLOW and left the reserve at exactly zero. Blockaid disclosed the incident and put the impact near $9.3 million, a figure Cointelegraph, crypto.news and everyone downstream repeated. At the price More Markets' own oracle reported in that block, those tokens were worth about $424,000. Thirteen hours later Flow put the drain at approximately $410,000 and placed the root cause in an Ankr Solidity contract, not in Flow EVM or More Markets. The arithmetic is not the interesting part. The oracle was correct to seven decimal places, E-mode behaved exactly as configured, and the reserve went anyway, because the collateral it accepted could be printed for free one contract upstream. Collateral is only as sound as the mint behind it.
What Actually Happened on Flow EVM?
More Markets is a lending protocol on Flow EVM, built on the Aave V3 codebase. Everything below comes from transaction 0x2b2e6ea6...8a3f66c9 in block 76,986,328, and from calls made directly against the contracts involved.
The attacker EOA 0xa1E4B05F9A0425136045D8fC8A4978B25bB6A7Cc received 172.5446 FLOW from an unlabeled address at 05:46:02 UTC, roughly $4.73 of gas money. Six minutes later it deployed a helper contract at 0xA0C2fe72aD9b640994A9c4252F25Fb058DDb3702, then called it once at 06:18:52 UTC, burning 9,697,876 gas and emitting 380 token transfers for a fee of about two cents.
Inside that one transaction the attacker minted 51,942,364.75 ankrFLOW out of nothing, dumped 38.6 million of it into a Uniswap V3 pool for 46.27 million WFLOW, posted 13,307,608.86 ankrFLOW as collateral, and borrowed every WFLOW the protocol had. No governance vote, no compromised key, no price feed to manipulate. The drain was atomic.
Why Is the $9.3 Million Figure Wrong?
Three independent checks put the number an order of magnitude lower.
Start with the price. DeFiLlama's historical price endpoint returns $0.027363468 for FLOW that morning, which values the 15,488,124.15 WFLOW that left the reserve at $423,809. More Markets' own oracle at 0x7287f12c268d7dff22aaa5c2aa242d7640041cb1, read with eth_call at the block before the exploit, returned $0.02742558 and puts it at $424,771. CoinGecko's price API has FLOW under three cents today, on a market cap around $45 million.
A $9.3 million headline requires FLOW to trade at $0.6005, about 22 times higher than it actually was. That is what a stale price entry looks like inside a detector's valuation step.
None of these on-chain numbers need to be taken on trust. Each is one archive call against the public Flow EVM RPC, and these four carry the argument:
RPC=https://mainnet.evm.nodes.onflow.org
# WFLOW price the More Markets oracle itself reported, one block before the drain -> 2742558 (8 decimals)
cast call 0x7287f12c268d7dff22aaa5c2aa242d7640041cb1 "getAssetPrice(address)(uint256)" \
0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e --block 76986327 --rpc-url $RPC
# what one ankrFLOW certificate redeems for -> 1199850498308706989 (1.19985 FLOW)
cast call 0x1b97100eA1D7126C4d60027e231EA4CB25314bdb "sharesToBonds(uint256)(uint256)" \
1000000000000000000 --rpc-url $RPC
# the same conversion asked of the aFLOWEVMb bond token -> 1000000000000000000, the input unchanged
cast call 0xd6Fd021662B83bb1aAbC2006583A62Ad2Efb8d4A "bondsToShares(uint256)(uint256)" \
1000000000000000000 --rpc-url $RPC
# WFLOW in the Uniswap V3 pool, before and after: swap 76986327 for 76986328
cast call 0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e "balanceOf(address)(uint256)" \
0xbB577ac54E4641a7e2b38Ce39e794096CD11A639 --block 76986327 --rpc-url $RPCThe third check is the simplest. DeFiLlama's TVL history has the whole protocol at $3,836,832 at midnight UTC on the day of the drain, six hours before it happened, and $3,971,024 the day before that. You cannot remove $9.3 million from a protocol that size. The Crypto Times came closest, describing the number as Blockaid's initial detector estimate rather than a confirmed loss, and Crypto Briefing flagged it as a developing story.
Trust the token count of 15.5 million WFLOW. The dollar figure was a detector artifact, and it did get corrected, thirteen hours after the first alert and largely unheard over the headlines already in circulation. Flow's statement puts the drain at approximately $410,000, Blockaid deleted its original post, and EtherWorld covered the revision. The remaining gap between $410,000 and our $423,809 is which price snapshot each side used, not a disagreement about what left the reserve.
What Is a Liquid Staking Certificate, and Where Did the Mint Go Wrong?
Ankr issues two token shapes for the same staked position. A bond token is denominated in the underlying asset: hold 100 aFLOWEVMb and you hold a claim on 100 FLOW, and the balance grows as rewards land. A certificate token is denominated in shares: the balance stays fixed and each share redeems for more FLOW over time. Converting between them means multiplying by an exchange rate. On Flow EVM that rate lives on the ankrFLOW contract at 0x1b97100eA1D7126C4d60027e231EA4CB25314bdb, and at the time of the attack it read 0.8334371668883636. One FLOW bought 0.8334 ankrFLOW. One ankrFLOW redeemed for 1.19985 FLOW.
Ankr's FlowStakingPool inherits its staking logic from LiquidTokenStakingPool, whose verified source has two deposit paths that differ by a single word:
function _stakeCerts(address staker, uint256 amount) internal {
uint256 shares = _certificateToken.bondsToShares(amount);
...
}
function _stakeBonds(address staker, uint256 amount) internal {
uint256 shares = _bearingToken.bondsToShares(amount);
...
}Both hand shares to the same _stake, which calls _certificateToken.mint(address(_bearingToken), shares), so both need certificate units. The certificate path computes that correctly. The bond path asks the bond token.
Calling both conversions with one whole token settles it. certificateToken.bondsToShares(1e18) returns 833437166888363555. bearingToken.bondsToShares(1e18) returns exactly 1000000000000000000. The bond token hands the input straight back, so stakeBonds() minted one ankrFLOW certificate for every FLOW deposited, when a certificate was redeemable for 1.19985 FLOW. The public record does not settle whether that identity result is an unset rate or the bond token's intended behavior. The effect is unambiguous either way: deposit 1 FLOW, receive 1 ankrFLOW, redeem it for 1.19985 FLOW. A guaranteed 20% per round, with no price movement required.
This is a units confusion, CWE-682 in MITRE's taxonomy: a calculation whose wrong result later drives a security-critical decision. The pool's getMinStake() returns zero, so there was no floor to clear.
The Attack, Step by Step
| # | Step | On-chain evidence |
|---|---|---|
| 1 | Fund the EOA with gas | 172.5446 FLOW at 05:46:02 UTC, about $4.73 |
| 2 | Deploy the helper contract | 0xA0C2fe72...DDb3702, created 05:52:21 UTC |
| 3 | Flash-swap 5,000 ankrFLOW | Uniswap V3 pool 0xbB577ac5...CD11A639, 0.01% fee tier |
| 4 | Redeem those certificates for FLOW | Staking pool paid 5,999.2525 FLOW, the correct 1.19985 rate |
| 5 | Restake 5,000.5 FLOW through the bond path | Minted 5,000.5 ankrFLOW at 1:1, repaying the flash swap and keeping 998.7525 FLOW |
| 6 | Repeat for 53 more rounds | Each round grew by 1.19985: 1,198.47 then 1,438.12 then 1,725.69 WFLOW |
| 7 | End state of the loop | 51,942,364.75 ankrFLOW minted, supply up 42.55% in one block |
| 8 | Supply 7,639,125.76 ankrFLOW to More Markets | mFlowANKRFLOW minted to the attacker |
| 9 | Borrow 5,668,483.10 WFLOW, restake, supply again | Second tranche of 5,668,483.10 ankrFLOW posted |
| 10 | Borrow the remaining 9,819,641.05 WFLOW | Both transfers out of the reserve, balance now 0 |
| 11 | Swap the proceeds into stablecoins | Twelve follow-up calls, 06:19:41 to 06:41:26 UTC |
| 12 | Bridge out | 186,478.07 PYUSD0, 37,927.07 USDC.E and 23,923.61 USDF through LI.FI's Permit2Proxy, last at 06:43:36 UTC |
Steps 3 through 5 are worth pausing on. The attacker never risked capital. The Uniswap pool lent the opening 5,000 ankrFLOW, Ankr redeemed it at the honest rate, and the 1:1 mint covered the flash repayment with 998.7525 FLOW left over.
Was E-Mode the Problem?
Every account of this incident, including Mpost's, blamed E-mode plus a mispriced LST. The chain does not support that reading.
E-mode is Aave V3's efficiency mode. Assets whose prices track each other, a liquid staking token and the asset it wraps being the canonical case, get grouped into a category with a higher loan-to-value ceiling than either would carry alone. Categories are configured through setEModeCategory, and the risk parameters live on the category rather than the asset.
More Markets' category 1 carries the label "Wrapped native tokens" with an LTV of 97.00%, a liquidation threshold of 97.50% and a liquidation bonus of 101%. The attacker posted 13,307,608.86 ankrFLOW and borrowed 15,488,124.15 WFLOW, which at the oracle's rate is 97.0000% of collateral value. Exactly the configured ceiling, to four decimal places.
And the oracle was right. It priced ankrFLOW at 1.199850 times WFLOW, and the certificate contract's own sharesToBonds(1e18) returns 1.199850498308707. The feed tracked the redemption rate to seven digits, which is what a well-built LST adapter is supposed to do. Reporting that described the collateral as "set higher in the protocol than it actually was" has it backwards. The valuation was accurate. The supply was not.
A 97% ceiling is aggressive, and it turned an upstream mint flaw into a total loss rather than a partial one. But at 78.5%, the base LTV several outlets quoted, the attacker would have run four or five more loop rounds and taken the same reserve, because the loop's growth rate was never capped by anything More Markets controlled. E-mode set the exchange rate between the attacker's free collateral and the protocol's real liquidity. It did not create the free collateral.
Flow's own statement lands in the same place: "The underlying exploit was not a vulnerability in Flow EVM or MORE Markets. It was in an Ankr Solidity smart contract." It also sizes the counterfeit at "approximately 8.6 million ankrFLOW with no backing," which is what our loop arithmetic produces independently: 51,942,364.75 certificates minted at 1:1 where the honest rate was 0.8334371668883636 leaves 8,651,667 unbacked. Two methods, one number.
Who Actually Lost What?
The lending protocol was not the largest victim, a strange thing to write about a lending exploit.
The Uniswap V3 ankrFLOW/WFLOW pool at 0xbB577ac5...CD11A639 held 46,764,434.47 WFLOW before the transaction and 499,266.69 after: 46,265,167.78 WFLOW gone, roughly $1.27 million, swapped for 38.6 million fresh certificates. The pool held about 61% of all wrapped FLOW on the chain in a single 0.01% fee tier, the obvious place to convert printed collateral into liquidity.
More Markets lost the 15,488,124.15 WFLOW of liquidity in its mFlowWFLOW reserve, about $424,000, and the reserve still reads zero. The protocol holds 13.3 million ankrFLOW securing a debt it will never see repaid.
The attacker realized far less than either. The 9,819,641.05 FLOW they walked away holding was worth about $269,000, and selling it into Flow EVM's stablecoin liquidity returned $248,328.75, roughly 7.8% of slippage. Flow puts that realized take at "approximately $246,000," close enough that the two counts are the same event seen through slightly different prices. Either way it is a quarter of a million dollars, on $4.75 of gas, out of a $1.69 million hole. The borrowing position sits on the helper contract, not the wallet, and it is still open: health factor 1.005155 in the exploit block against a 97.5% liquidation threshold, drifting to 1.001093 as interest accrues. Above 1, so nothing can be liquidated, and the collateral under it is the counterfeit.
The Uniswap LPs are holding 39.4 million ankrFLOW, and who eats that depends on Ankr. ankrFLOW's supply went from 122,074,680.71 to 174,017,045.46 across that one block and has not been reduced since: it reads 174,094,870.53 today, and the two conversion functions still disagree when you call them. Flow says the containment happened fast, that Ankr and More Markets paused the affected contracts within hours, that no More Markets or ankrFLOW depositor has lost funds, and that Flow Foundation will work with Ankr to replace the drained WFLOW reserve and rebalance the pool. Staking and lending stay paused until Ankr ships the contract upgrade. Depositors come out whole here because a solvent foundation chose to absorb a counterparty's bug. Nobody should design a lending market on the assumption that someone makes that call.
Why This Generalizes
Lending protocols spend enormous effort on price. Oracle staleness, TWAP windows, deviation bounds, circuit breakers, which feed to trust and when to halt. All of it answers one question: what is this token worth? More Markets answered that correctly and lost its reserve anyway, because there is a second question underneath it that almost nobody asks at listing time. How many of these tokens can exist, and who decides?
An audit certifies the code you showed it, on the day you showed it. More Markets' code was Aave V3's, among the most reviewed in the industry, and the flaw that killed it lives in a contract More Markets does not own, deployed by a different team, on a chain where nobody had looked closely at how two token shapes convert into each other. Listing an asset as collateral inherits every invariant of its issuer. That is a counterparty decision dressed up as a risk-parameter decision.
The pattern is not new. We wrote up FoxMarket, where a bond minted against an unbounded spot price turned into a $119,000 hole, and Tectonic, where a governance token pumped about 100x in 20 minutes underwrote $119 million of loans and cost $75 million. Same shape each time. The market priced its collateral correctly by its own lights and never asked whether the supply was fixed.
An honest note on our own product line. This drain was atomic, and no alerting layer front-runs a single transaction. What monitoring catches is everything either side of it. The divergence between the two conversion functions was a standing, queryable condition in every block before the attack, one eth_call apart and off by 20%, and a listing-time invariant check finds that with no runtime component at all. The 25 minutes between the reserve hitting zero at 06:18:52 and the last stablecoin leaving at 06:43:36 was all observable: ankrFLOW supply up 42.55% in one block, a Uniswap pool losing 99% of one side, one account borrowing an entire reserve to the basis point of its LTV ceiling. That window is where a freeze request or a market pause lands. Here the audit and the listing review were the prevention.
Operator Takeaways
- Test both directions of every conversion function on a collateral asset before listing it. Call
bondsToSharesandsharesToBonds, or their equivalents on whatever wrapper you integrate, with one whole token. If the two shapes of the same position disagree, or either returns the input unchanged, stop. Twoeth_calls would have surfaced this. - Treat a collateral asset's mint path as part of your attack surface. Enumerate every function that can increase supply and who can call it. If the answer is "anyone, at a rate set by a contract we do not control," that is counterparty exposure and should be sized like it.
- Alert on supply deltas for every asset you accept as collateral. A 42.55% increase in one block on an LST you price near its underlying is not a market event. Set the threshold low; a legitimate LST does not move like that.
- Cap exposure per collateral asset independently of LTV. More Markets had no effective ceiling on how much ankrFLOW one account could post. Aave V3 ships supply and borrow caps for exactly this case, and a cap sized to the collateral's real float would have bounded the loss.
- Set E-mode LTVs against the weakest link in the pair. A 97% ceiling assumes the peg holds and the supply is honest. If the correlated asset's issuer can mint, correlation is the wrong risk model and the ceiling should reflect the issuer, not the price chart.
- Reconcile third-party loss figures against on-chain data. A detector's dollar estimate is a token count times a price entry that may be months stale. Take the count, apply your own price, check it against the protocol's TVL.
- Rehearse the exfiltration window. This attacker needed 25 minutes to move funds through a bridge. Know who to contact there before you need them.
Frequently Asked Questions
How much did More Markets actually lose? 15,488,124.15 WFLOW left the mFlowWFLOW reserve, leaving it at zero. At the $0.02742558 price the protocol's own oracle reported in that block, that is $424,771, and DeFiLlama's price for that morning puts it at $423,809. Flow's statement says approximately $410,000. The widely reported $9.3 million figure implies FLOW at $0.6005, roughly 22 times the market rate, and Blockaid has since withdrawn it.
Was the ankrFLOW price oracle manipulated? No. More Markets priced ankrFLOW at 1.199850 times WFLOW, matching the certificate contract's own redemption rate of 1.199850498308707. The attacker did not need a wrong price, because the tokens were free to create.
Is this an Aave V3 vulnerability? No. The Aave V3 code behaved as designed, and E-mode category 1 enforced its 97% LTV ceiling exactly. The flaw is in Ankr's Flow EVM staking pool, whose bond deposit path computes certificate shares from the bond token instead of the certificate token, minting one ankrFLOW per FLOW deposited.
Does this affect ankrFLOW holders or other Ankr deployments? ankrFLOW's supply on Flow EVM rose 42.55% in one block and has not been reduced. Ankr paused staking and Flow says depositor funds are safe and retrievable once the contract upgrade ships, so the backing question now sits with Ankr's fix rather than with holders. We have not tested Ankr's other chains.
Would runtime monitoring have prevented this? Not the drain itself, which was one atomic transaction. The pre-conditions were catchable before listing with a single pair of contract calls, and the 25-minute exfiltration window afterward was fully observable. Monitoring compresses the response window; it does not stop the first block.
Sources / References
- More Markets lending reserve drained for $9.3M: Blockaid, Cointelegraph, August 31, 2026
- More Markets suffers $9.3m WFLOW exploit on Flow EVM, crypto.news, August 31, 2026
- More Markets Drained Of $9.3M In WFLOW After Attacker Exploits Ankr LST And E-Mode Collateral Pricing, Mpost, August 31, 2026
- Ankr Exploit Drains 15.5M WFLOW From More Markets; Flow Corrects $9.3M Claim to $410k, The Crypto Times, August 31, 2026
- Statement on the Ankr Liquid Staking exploit, Flow.com (@flow_blockchain), August 31, 2026 (the $410,000 correction, the 8.6 million unbacked mint, the pause and the reimbursement commitment)
- More Markets Loss Impact Revised to $410K, EtherWorld, August 31, 2026
- More Markets drained of $9.3M in WFLOW exploit, Blockaid reports, Crypto Briefing, August 31, 2026
- Exploit transaction 0x2b2e6ea6...8a3f66c9, Flow EVM explorer API (block, timestamp, gas, addresses)
- Attacker EOA token transfers, Flow EVM explorer API (the stablecoin exit)
- ankrFLOW token record, Flow EVM explorer API (current total supply)
- aFLOWEVMb bond token record, Flow EVM explorer API (the bond side of the pair)
- FLOW price at the hour of the exploit, DeFiLlama price endpoint
- Ankr FlowStakingPool, verified source, Flow EVM explorer API
- mFlowWFLOW reserve transfers, Flow EVM explorer API (the two drain transfers)
- Uniswap V3 ankrFLOW/WFLOW pool balances, Flow EVM explorer API
- Pool Configurator, Aave V3 developer documentation
- CWE-682: Incorrect Calculation, MITRE
- More Markets protocol TVL history, DeFiLlama (the pre-drain snapshots)
- FLOW spot price and market cap, CoinGecko price API
Method: token amounts and timestamps come from the transaction's own transfer log. E-mode parameters, oracle prices, exchange rates, pool balances and the health factor were read with eth_call against mainnet.evm.nodes.onflow.org, at block 76,986,327 for pre-exploit state and the latest block for current state.



