SushiBar ERC777 Reentrancy
Exploit Transactions
0x8037b3dc0bf9d5d396c10506824096afb8125ea96ada011d35faa89fa3893aeaVictim Addresses
0x3561081260186e69369e6c32f280836554292e08EthereumLoss Breakdown
Similar Incidents
JayPeggers JAY Reentrancy Drain
37%PointFarm Reward Reentrancy
37%Curve Vyper Lock Reentrancy
35%Cream Finance cAmp / Amp Reentrancy Exploit
35%Conic ETH Oracle Reentrancy
34%EFVault Withdraw Under-Burn
33%Root Cause Analysis
SushiBar ERC777 Reentrancy
1. Incident Overview TL;DR
On Ethereum mainnet block 15826380, transaction 0x8037b3dc0bf9d5d396c10506824096afb8125ea96ada011d35faa89fa3893aea exploited SushiBar at 0x3561081260186e69369e6c32f280836554292e08 while staking n00dToken at 0x2321537fd8ef4644bacdceec54e5f35bf44311fa. The attacker used a fresh helper contract, borrowed n00dToken from the public n00d/WETH Uniswap V2 pair, reentered SushiBar.enter() through the ERC777 sender hook, redeemed inflated xN00d, repaid the pair, swapped the remainder to WETH, withdrew to ETH, and paid the proceeds to the submitting EOA.
The root cause is a share-inflation bug in SushiBar.enter(): the contract mints shares before collecting the deposited tokens. Because n00dToken.transferFrom() invokes the ERC777 sender hook before balances move, the attacker can reenter enter() multiple times while SushiBar still reads the same stale token balance.
2. Key Background
SushiBar is a share vault. enter(_amount) mints xN00d based on totalShares and sushi.balanceOf(address(this)), and leave(_share) burns shares for the proportional amount of underlying n00dToken.
The staked token is not a passive ERC20. n00dToken is an ERC777 implementation, so transferFrom() delegates to _send(), and _send() calls _callTokensToSend() before balances are updated. An attacker-controlled sender contract can register itself in ERC1820 as the ERC777TokensSender hook implementer and execute arbitrary logic during transferFrom().
The attack needed no privileged access. The helper contract obtained temporary inventory from the public Uniswap V2 pair at 0x5476db8b72337d44a6724277083b1a927c82a389, performed the reentrant share inflation, then unwound the position in the same transaction.
3. Vulnerability Analysis & Root Cause Summary
The vulnerability class is reentrancy-enabled vault share inflation. SushiBar calculates share issuance from the vault's current n00dToken balance and outstanding shares, but it does so before the incoming deposit is actually transferred. That ordering is unsafe when the underlying token can execute sender-side callbacks mid-transfer.
The verified SushiBar source shows the breakpoint directly:
function enter(uint256 _amount) public {
uint256 totalSushi = sushi.balanceOf(address(this));
uint256 totalShares = totalSupply();
if (totalShares == 0 || totalSushi == 0) {
_mint(msg.sender, _amount);
} else {
uint256 what = _amount.mul(totalShares).div(totalSushi);
_mint(msg.sender, what);
}
sushi.transferFrom(msg.sender, address(this), _amount);
}
The required safety invariant is: a deposit must not mint multiple batches of shares against the same pre-deposit asset base. Here, nested enter() calls observe the same totalSushi snapshot while totalShares keeps increasing, so each reentrant call mints more shares than the same deposit should receive. leave() then converts those inflated shares back into a disproportionate amount of n00dToken.
4. Detailed Root Cause Analysis
The relevant n00dToken ERC777 path confirms why reentrancy is possible:
function transferFrom(
address holder,
address recipient,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(holder, spender, amount);
_send(holder, recipient, amount, "", "", false);
return true;
}
function _send(
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
) internal virtual {
address operator = _msgSender();
_callTokensToSend(operator, from, to, amount, userData, operatorData);
_move(operator, from, to, amount, userData, operatorData);
_callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);
}
The seed trace shows the exploit sequence end to end. In the first reentrancy round, SushiBar reads the same vault balance 8058768001881461618923 before each nested call, while share mints increase from 4966798730038660770207 to 8071106172719568973063 to 13115642165513090544737:
SushiBar::enter(5036824491352933286391)
n00dToken::balanceOf(SushiBar) -> 8058768001881461618923
emit Transfer(... value: 4966798730038660770207)
n00dToken::transferFrom(...)
ERC1820Registry::getInterfaceImplementer(...) -> helper
helper::tokensToSend(...)
SushiBar::enter(5036824491352933286391)
n00dToken::balanceOf(SushiBar) -> 8058768001881461618923
emit Transfer(... value: 8071106172719568973063)
n00dToken::transferFrom(...)
helper::tokensToSend(...)
SushiBar::enter(5036824491352933286391)
n00dToken::balanceOf(SushiBar) -> 8058768001881461618923
emit Transfer(... value: 13115642165513090544737)
The same pattern repeats across four flash-swap rounds. After each nested enter() sequence, the helper calls SushiBar::leave(...), repays the pair, and converts the residual n00dToken into WETH/ETH. The trace later shows WETH9::withdraw(20821589213301267212) and the balance diff records the exploit EOA's net ETH increase as 20790124510901267212 wei after gas.
The public Uniswap flash swap was only the funding mechanism. It supplied temporary n00dToken inventory, but the root cause is still the mint-before-transfer ordering in SushiBar combined with ERC777 sender-hook reentrancy.
5. Adversary Flow Analysis
The adversary cluster consists of EOA 0x8ca72f46056d85db271dd305f6944f32a9870ff0 and helper contract 0x9c5a2a6431523fbbc648fb83137a20a2c1789c56. The EOA submitted the transaction; the helper executed all protocol interactions.
The on-chain flow was:
- The helper borrowed
n00dTokenfrom the public Uniswap V2 pair throughswap(..., data), which triggereduniswapV2Call. - The helper had already registered itself in ERC1820 as the sender hook implementer, so
n00dToken.transferFrom()calledtokensToSend()before moving balances. - Inside
tokensToSend(), the helper reenteredSushiBar.enter()twice more while SushiBar still observed the same pre-transfern00dTokenbalance. - After the nested enters completed, the helper held inflated
xN00dand immediately redeemed it throughSushiBar.leave(). - The helper repaid the pair, swapped leftover
n00dTokenfor WETH, withdrew WETH to ETH, and transferred ETH to the submitting EOA.
The attack was permissionless and self-contained within one adversary-crafted transaction, so it satisfies the ACT model.
6. Impact & Losses
SushiBar lost 8051490980645650214607 raw units of n00dToken (8051.490980645650214607 n00d, 18 decimals) in the exploit transaction. The same balance diff shows the Uniswap pair gained that amount, consistent with the helper repaying the pair and routing the remaining extracted value through the pair's market path.
The exploit EOA's native balance increased from 83974654845683612 wei to 20874099165746950824 wei. After subtracting 15125273038271592 wei of gas paid, the net ETH profit was 20790124510901267212 wei.
7. References
- Seed transaction:
0x8037b3dc0bf9d5d396c10506824096afb8125ea96ada011d35faa89fa3893aea - SushiBar victim contract:
0x3561081260186e69369e6c32f280836554292e08 - n00dToken staked asset:
0x2321537fd8ef4644bacdceec54e5f35bf44311fa - Attacker EOA:
0x8ca72f46056d85db271dd305f6944f32a9870ff0 - Attacker helper contract:
0x9c5a2a6431523fbbc648fb83137a20a2c1789c56 - Uniswap V2 pair:
0x5476db8b72337d44a6724277083b1a927c82a389 - Trace artifact:
/workspace/session/artifacts/collector/seed/1/0x8037b3dc0bf9d5d396c10506824096afb8125ea96ada011d35faa89fa3893aea/trace.cast.log - Balance diff artifact:
/workspace/session/artifacts/collector/seed/1/0x8037b3dc0bf9d5d396c10506824096afb8125ea96ada011d35faa89fa3893aea/balance_diff.json - n00dToken source artifact:
/workspace/session/artifacts/collector/seed/1/0x2321537fd8ef4644bacdceec54e5f35bf44311fa/src/Contract.sol - SushiBar verified source: Etherscan
contract/getsourcecodefor0x3561081260186e69369e6c32f280836554292e08