SorbettoFragola Aave/Uniswap route arbitrage extracts USDC via fee collection
Exploit Transactions
0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fcVictim Addresses
0xd63b340f6e9cccf0c997c83c8d036fa53b113546Ethereum0x6f3f35a268b3af45331471eabf3f9881b601f5aaEthereum0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8Ethereum0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640Ethereum0x99ac8ca7087fa4a2a1fb6357269965a2014abc35EthereumLoss Breakdown
Similar Incidents
DOGGO/WETH cross-pool arbitrage MEV extracts WETH spread
38%SASHA cross-DEX MEV arbitrage extracts ETH pricing spread
37%MachineShare CurveStableSwapNG mispricing arbitrage extracts ETH-side liquidity
37%HANA tax-wallet MEV arbitrage on Uniswap V2
36%Multi-venue stablecoin/WETH MEV arbitrage on Ethereum mainnet
35%Morpho-Pendle flash-loan liquidation MEV captures undercollateralized spread
33%Root Cause Analysis
SorbettoFragola Aave/Uniswap route arbitrage extracts USDC via fee collection
1. Incident Overview TL;DR
In Ethereum mainnet block 12955063, EOA 0xf9e3d08196f76f5078882d98941b71c0884bea52 sent a single transaction (0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fc) to adversary-orchestrator contract 0xdfb6fab7f4bc9512d5620e679e90d1c91c4eade6. That transaction atomically borrowed from Aave V2, traded through several Uniswap V3 pools, interacted with SorbettoFragola vaults, collected fees, and withdrew liquidity, finishing with exactly 5,387,085.448419 USDC at the adversary EOA while paying gas only in ETH.
No smart-contract invariant or access control check was violated. Instead, the root cause is an ACT MEV opportunity: permissionless Aave V2, Uniswap V3, and SorbettoFragola contracts allow an unprivileged searcher to route flash liquidity and fee-collection operations such that SorbettoFragola depositors and Uniswap LPs lose value while protocol-level invariants remain satisfied.
2. Key Background
SorbettoFragola vaults are ERC20Permit vaults that manage concentrated Uniswap V3 liquidity. Users deposit token0 and token1 to mint vault shares, and withdraw by burning shares to reclaim a proportional share of the underlying Uniswap position and idle balances. The vault also exposes collectFees so users can claim accumulated Uniswap trading fees according to per-share accounting.
In the exploited configuration, the relevant SorbettoFragola vaults are:
0xd63b340f6e9cccf0c997c83c8d036fa53b113546– SorbettoFragola USDC/WETH vault.0x6f3f35a268b3af45331471eabf3f9881b601f5aa– another SorbettoFragola USDC/WETH vault.
The collected Sorbetto source (Contract.sol under the Sorbetto artifact tree) shows that deposits and fee collections are permissionless and that per-share accounting is handled by global and per-user variables:
/// @inheritdoc ISorbettoFragola
function deposit(
uint256 amount0Desired,
uint256 amount1Desired
)
external
payable
override
nonReentrant
checkDeviation
updateVault(msg.sender)
returns (uint256 shares, uint256 amount0, uint256 amount1)
{
require(amount0Desired > 0 && amount1Desired > 0, "ANV");
...
_mint(msg.sender, shares);
emit Deposit(msg.sender, shares, amount0, amount1);
}
function collectFees(uint256 amount0, uint256 amount1) external nonReentrant updateVault(msg.sender) {
UserInfo storage user = userInfo[msg.sender];
require(user.token0Rewards >= amount0, "A0R");
require(user.token1Rewards >= amount1, "A1R");
...
user.token0Rewards = user.token0Rewards.sub(amount0);
user.token1Rewards = user.token1Rewards.sub(amount1);
emit RewardPaid(msg.sender, amount0, amount1);
}
There is no access control beyond standard reentrancy and deviation checks; any address that has accrued fees or holds shares can call these functions. Global variables such as accruedProtocolFees0, accruedProtocolFees1, token0PerShareStored, and token1PerShareStored track fee accrual per share, while userInfo maintains each account’s reward debt and balances.
The adversary uses an orchestrator contract at 0xdfb6fab7f4bc9512d5620e679e90d1c91c4eade6. Heimdall decompilation for its main entry point (0x6466c309) clearly hard-codes the controlling EOA and routes through standard DeFi components:
/// @custom:selector 0x6466c309
/// @custom:signature Unresolved_6466c309(uint256 arg0, uint256 arg1) public
function Unresolved_6466c309(uint256 arg0, uint256 arg1) public {
...
require(address(msg.sender) == 0xf9e3d08196f76f5078882d98941b71c0884bea52);
...
var_c = 0xdac17f958d2ee523a2206206994597c13d831ec7; // USDT
var_d = 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2; // WETH
...
var_f = 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48; // USDC
var_g = 0x6b175474e89094c44da98b954eedeac495271d0f; // DAI
var_h = 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984; // UNI
...
require(address(0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9).code.length); // Aave V2 lending pool
(bool success, bytes memory ret0) =
address(0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9).Unresolved_ab9c4b5d(var_q); // flash loan entry
...
}
This function requires the call to originate from 0xf9e3...ea52 and then orchestrates Aave flash loans, Uniswap V3 swaps, and SorbettoFragola interactions. There is no privileged dependency beyond control of this EOA and the deployed orchestrator contract.
The key liquidity venues and vaults involved in the exploit are:
- Uniswap V3 USDC/ETH pools:
0x8ad599c3a0ff1de082011efddc58f1908eb6e6d80x88e6a0c2ddd26feeb64f039a2c41296fcb3f56400x99ac8ca7087fa4a2a1fb6357269965a2014abc35
- Aave V2 lending pool:
0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 - USDC token contract:
0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
The pre-state σ_B (state immediately before block 12955063) is reconstructed from:
- Seed transaction metadata and balance diffs for
0xcd7dae...70fc. - Sorbetto-focused call tree for that transaction.
- Pre-exploit tx history of Sorbetto vaults
0xd63b...and0x6f3f...and the adversary cluster, as captured in the data-collector artifacts.
3. Vulnerability Analysis & Root Cause Summary
This incident is not a smart-contract bug but an ACT MEV opportunity. All core protocol invariants for Aave V2, Uniswap V3, and SorbettoFragola remain satisfied throughout the transaction:
- Aave V2 flash loans are fully repaid within the transaction.
- Uniswap V3 pools maintain their pricing and fee-accrual mechanics.
- SorbettoFragola distributes Uniswap trading fees over ERC20 share supply using per-share accounting and user reward debts, with no unauthorized minting or burning of vault shares.
The economic vulnerability is that these invariants, combined with:
- Permissionless access to deposit, withdraw, and collect fees,
- Large amounts of public flash liquidity on Aave V2, and
- Deep, path-dependent liquidity and fee dynamics across multiple Uniswap V3 pools,
allow an unprivileged adversary to construct a single standard transaction which extracts a large amount of USDC from SorbettoFragola vaults and Uniswap LPs. Because the strategy uses only public interfaces, public traces, and permissionless contracts, it constitutes an ACT opportunity that any sufficiently equipped searcher can realize from σ_B.
4. Detailed Root Cause Analysis
Invariants and behavior of SorbettoFragola
SorbettoFragola’s design maintains several key invariants:
- Vault shares represent a pro-rata claim on the underlying Uniswap position and idle balances.
- Collected Uniswap fees are recorded in global
token0PerShareStoredandtoken1PerShareStoredvariables. - Each user’s
userInfoentry trackstoken0Rewards,token1Rewards, and the per-share values they have already been credited for. collectFeesonly transfers amounts the user has actually accrued (A0R/A1Rchecks) and then decrementsuser.token*Rewardsby the amount paid.
State-diff artifacts for the vaults over the seed transaction (state_diff_sorbetto_0xd63b... and state_diff_sorbetto_0x6f3f...) show:
accruedProtocolFees*,usersFees*,token*PerShareStoredall increase modestly, reflecting fee accrual over time.userInfoentries for adversary-linked addresses (orchestrator, helper EOAs) are updated consistently with fee accrual and collection.- Total supply of vault shares remains consistent with the expected mint/burn behavior for the deposit/withdraw operations observed in the call traces.
These observations confirm that SorbettoFragola behaves as designed. There is no arithmetic overflow, unchecked mint, or unauthorized withdrawal; instead, the adversary leverages the intended, but economically fragile, fee and share accounting.
Orchestrated flash-loan route
The orchestrator function 0x6466c309 is callable only by EOA 0xf9e3...ea52. The collected call tree for the seed transaction (sorbetto_call_tree_summary.json) shows the following high-level sequence:
{
"chainid": 1,
"txhash": "0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fc",
"calls": [
{
"from": "0xdfb6fab7f4bc9512d5620e679e90d1c91c4eade6",
"to": "0xd63b340f6e9cccf0c997c83c8d036fa53b113546",
"decoded": { "function": "deposit", "args": [...] }
},
{
"from": "0xdfb6fab7f4bc9512d5620e679e90d1c91c4eade6",
"to": "0xd63b340f6e9cccf0c997c83c8d036fa53b113546",
"decoded": { "function": "withdraw", "args": [...] }
},
{
"from": "0x576cf5f8ba98e1643a2c93103881d8356c3550cf",
"to": "0x6f3f35a268b3af45331471eabf3f9881b601f5aa",
"decoded": { "function": "collectFees", "args": [...] }
}
]
}
Together with the full call tree and trace, this shows that:
- The orchestrator borrows assets via Aave V2 flash loans.
- It deposits into SorbettoFragola vault
0xd63b...to temporarily take a large share of the vault’s position, interacting with the underlying Uniswap V3 pool through mint and swap callbacks. - It then uses multi-hop swaps across Uniswap pools
0x8ad599...,0x88e6a0..., and0x99ac8c...to move prices and fees. - Helper EOA
0x576c...50cfcallscollectFeeson vault0x6f3f..., realizing accumulated fees for an adversary-controlled address. - Finally, the orchestrator withdraws from Sorbetto, repays all flash loans, and returns control to the EOA with a large USDC surplus.
Throughout this sequence:
- Aave V2 enforces full repayment of the flash loans.
- Uniswap V3 pools enforce their swap and fee rules.
- SorbettoFragola enforces its per-share fee distribution and reward-debt checks.
The net effect is that the adversary’s path exploits price and fee path-dependence, along with temporarily concentrated vault positions, to concentrate losses on Sorbetto depositors and Uniswap LPs.
Why this is an ACT MEV opportunity
The opportunity satisfies the ACT criteria:
- Permissionless feasibility: The orchestrator uses only public Aave V2, Uniswap V3, SorbettoFragola, and ERC20 interfaces. Any EOA that deploys an equivalent orchestrator can submit a comparable transaction from σ_B with standard gas pricing.
- No privileged roles or hidden data: All contracts are publicly deployed and verified; the route depends only on on-chain state, not on privileged governance actions or off-chain secrets.
- Deterministic profit predicate: From the balance diff for USDC in the seed transaction, the adversary’s USDC balance increases from
0to5,387,085,448,419units (5,387,085.448419 USDC) while no negative USDC deltas appear for the adversary EOA, orchestrator, or funder. This yields a deterministic positive USDC outcome given σ_B.
Accordingly, the root cause is the existence of this economically harmful yet protocol-compliant route, not an implementation bug in SorbettoFragola or the integrated protocols.
5. Adversary Flow Analysis
Adversary accounts and roles
The adversary cluster comprises:
- EOA
0xf9e3d08196f76f5078882d98941b71c0884bea52– Sender of the seed transaction and recipient of the 5,387,085.448419 USDC profit (USDC delta inbalance_diff.json). - Orchestrator contract
0xdfb6fab7f4bc9512d5620e679e90d1c91c4eade6– Called by the EOA in the seed transaction; decompiled code includesrequire(msg.sender == 0xf9e3...)and sequences all Aave, Uniswap, and Sorbetto interactions. - EOA
0x3a9d90ed069021057d9d11e78f142f2c4267934a– Deployer of the orchestrator and funder of the adversary EOA. - Helper EOA
0x576cf5f8ba98e1643a2c93103881d8356c3550cf– CallscollectFeeson SorbettoFragola vault0x6f3f...during the seed transaction. - Helper contract
0xd282f740bb0ff5d9e0a861df024fcbd3c0bd0dc8– Transfers its token balances (WETH, WBTC, USDC, DAI, UNI) into the orchestrated flow, providing additional liquidity under adversary control.
Lifecycle stages
-
Adversary contract deployment
- Tx
0xb15912667e8d66e11a56c85a69018b024aa6b1a9a411b4b958cb07e2d3484f52at block12954674deploys orchestrator0xdfb6...eade6from EOA0x3a9d...934a. - Etherscan txlist and the decompiled Solidity confirm that this contract implements the MEV route and restricts its main entry to
0xf9e3...ea52.
- Tx
-
Adversary EOA funding
- Tx
0xba5967be2d11eded4bd5fec5e4f8263e9253b736425d8991f4517ff926487389at block12954903sends9.803712915ETH from0x3a9d...934ato0xf9e3...ea52. - This ETH funds the seed transaction’s gas and provides margin where needed; the bulk of trading notional still comes from Aave flash loans and on-chain liquidity.
- Tx
-
Single-tx MEV execution and profit realization
- Tx
0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fcat block12955063is sent from0xf9e3...ea52to0xdfb6...eade6. - The call tree shows:
- Flash loans from Aave V2.
- Swaps across Uniswap V3 pools
0x8ad599...,0x88e6a0...,0x99ac8c.... - Deposits and withdrawals on SorbettoFragola vault
0xd63b.... collectFeescalls on SorbettoFragola vault0x6f3f...via EOA0x576c...50cf.
- All flash loans are repaid; the net result is a large USDC surplus at
0xf9e3...ea52and corresponding losses at Sorbetto vaults and Uniswap pools.
- Tx
6. Impact & Losses
The seed transaction’s USDC balance diff (balance_diff.json for token 0xa0b8...6eb48) shows:
- SorbettoFragola vault
0xd63b340f6e9cccf0c997c83c8d036fa53b113546:-41,675.197889USDC. - SorbettoFragola vault
0x6f3f35a268b3af45331471eabf3f9881b601f5aa:-585.480343USDC. - Uniswap V3 pool
0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8:-3,738,923.233314USDC. - Uniswap V3 pool
0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640:-711,267.681118USDC. - Uniswap V3 pool
0x99ac8ca7087fa4a2a1fb6357269965a2014abc35:-921,633.855755USDC.
The sum of these losses is exactly 5,414,085.448419 USDC. The same diff records:
- Adversary EOA
0xf9e3...ea52:+5,387,085.448419USDC. - Aave-related holder
0xbcca60bb61934080951369a648fb03df4f96263c:+27,000.000000USDC.
An excerpt of the USDC balance diff illustrates these movements:
{
"token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"holder": "0xd63b340f6e9cccf0c997c83c8d036fa53b113546",
"delta": "-41675197889"
},
{
"token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"holder": "0x6f3f35a268b3af45331471eabf3f9881b601f5aa",
"delta": "-585480343"
},
{
"token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"holder": "0xf9e3d08196f76f5078882d98941b71c0884bea52",
"delta": "5387085448419"
}
Here, raw deltas are in USDC’s 6-decimal units. The adversary’s USDC gain and the Aave-related increase together exactly equal the combined losses of the Sorbetto vaults and Uniswap pools, confirming conservation of total USDC and pinpointing where value leaves the victims and arrives.
Native balance deltas show that:
0xf9e3...ea52pays0.49648356ETH in gas to block producer0x99c85bb64564d9ef9a99621301f22c9993cb89e3.- This ETH gas cost is external to the USDC profit computation; in the ACT model used here, USDC is the reference asset and the gas cost is tracked separately.
7. References
- Seed transaction metadata, trace, and balance diff for
0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fc(Ethereum mainnet block 12955063). - SorbettoFragola source code for vaults
0xd63b340f6e9cccf0c997c83c8d036fa53b113546and0x6f3f35a268b3af45331471eabf3f9881b601f5aa(Contract.sol and associated artifacts). - Sorbetto-focused call tree summary and state-diff artifacts for the seed transaction, including address-annotated userInfo and fee accounting.
- Heimdall decompile and tx history for orchestrator contract
0xdfb6fab7f4bc9512d5620e679e90d1c91c4eade6. - Etherscan-style txlists for adversary-related EOAs and helper contracts around blocks 12954000–12956063.