How a Safe module drained 2,900 rsETH in one block
At 04:38 UTC a searcher got into an Ethereum block first. By the time anyone else landed a transaction, 2,900 aEthrsETH had left a Gnosis Safe without an owner signature.
01 · One block, no stolen key
Two enabled modules and a public batch path
At 04:38 UTC a bot called yoink() and took the first slot in the block.
The attacker who set the trap has no tx of their own in it.
A Gnosis Safe is a multisig wallet. Owners sign, and the Safe runs the call. It can also turn on a module: a contract allowed to move funds without a fresh owner signature. Keepers, vaults and LP bots use that. Anyone who can reach the module can move funds the same way.
This was not a stolen key. It was a module the Safe had already turned on.
The victim wallet is a Safe 1.3.0 proxy from autumn 2023. For months it held Kelp rsETH on Aave V3 as aEthrsETH, with WETH debt against it. Two modules had been calling it since: a gateway from that first autumn, and a Uniswap v4 LP module from early this year. Keepers already used a public batch contract to reach them. The attacker reused that path.
Bitquery indexes every call, event and transfer on Ethereum. We pulled the capture tx, every aEthrsETH outflow from the Safe that day, and the wallets the rsETH landed in. Decoding those module execs is what the smart contract API is for. Following the aToken out is what the address APIs sit on.
02 · The batch contract that named itself
A target check that trusted address(this)
A public executor sits in front of the modules. It exposes a batch call: the caller picks a target and a list of payloads. A check on the target is supposed to keep others out. In the capture tx the helper passed the executor as the target, so the executor called itself.
A "target must be on the allowed list" check treats the contract's own address as trusted. Inner payloads then ran as that trusted executor, through the enabled module, inside the Safe.
The inner payload was another batch call, this time aimed at the gateway module. That module is allowed to call the Safe's module exec. It did so with op set to delegate call. Execute then ran in the Safe's own context and handed work to the Uniswap v4 LP module, which is itself an enabled module.
Keepers had already used this recipe. One of them called the batch function dozens of times. The path was live long before this morning.
The Safe processed every module call as designed. The hole was the caller list on the public batch contract.
03 · A junk token and a vanilla pool
PAT, then Uniswap v4, then an unlocker
Two blocks before the capture, the attacker put a token on chain called PAT and minted a huge pile of it to a helper. The next block, the helper seeded a Uniswap v4 pool of aEthrsETH against PAT. The pool key has hooks set to the zero address. This is a plain v4 pool. We mapped the hooked version on Robinhood Chain.
The Safe then approved the aToken and one wei of PAT through Permit2, and minted an LP NFT. The aToken moved from the Safe into the Pool Manager. A separate contract unlocked the pool, swapped, and took the aToken to the helper. The helper paid PAT as the other side of that swap. PAT has no market, so paying it is how the aToken leaves.
Public notes called that unlocker a hook. The call trace shows an ordinary call into Pool Manager, the same unlock any v4 router can make. The Safe still holds the NFT, empty of value.
04 · How the capture tx ran
From yoink() to the frozen pile
The LP module is a proxy. Its beacon points at a logic contract. On chain,
the named functions are safe and initialize. We do not name a
vendor. After the self-batch, ordinary calls do the rest: approve the
aToken, Permit2, approve one wei of PAT, mint the position, clear the
approvals.
After the mint, the helper talks to the unlocker. Transfers show the
helper getting aEthrsETH and paying PAT. Pool Manager take() sends
the aToken over. The helper then calls Aave withdraw with amount max,
user and receiver both itself. aEthrsETH burns. rsETH lands on the helper
and moves to the Yoink bot, which sells a slice on a real ETH/rsETH
v4 pool and parks the rest.
| Call range | What it did |
|---|---|
| 0–24 | yoink() into the helper, Aave probe, zero-amount aToken transfer |
| 25–31 | batch(self) → gateway module → Safe exec, operation 1, delegate call execute |
| 32–110 | LP module: Permit2, mint UNI-V4-POSM, 2,900 aEthrsETH into Pool Manager |
| 111–133 | Unlocker swap + take aEthrsETH to helper; helper pays 2,905.81 PAT |
| 134–156 | Aave withdraw, burn aEthrsETH, rsETH to helper, then to Yoink bot |
| 157–174 | Sell 17.63 rsETH for 18.95 ETH; park 2,882.37 at 0xC70f00…; skim ETH |
05 · Where the rsETH sits now
A freeze wallet, a skim, and a later seize
The bulk never left the first landing spot. The Yoink bot sent it to a reused wallet that has been live since late 2022. No rsETH has left that wallet since the capture. Native ETH on that same wallet is old money. The capture-day ETH skim went to a second Yoink wallet. Watching whether that pile ever moves is what MoneyFlow is for.
Kelp's public notes speak of a wallet pause. We did not see an admin pause call. The chain shows the zero outflow.
An hour later Yoink came back for leftover aToken. That second hit is
an Aave seize. Yoink took a WETH flash loan from Morpho Blue, then called
liquidationCall with collateral rsETH, debt WETH, user the Safe.
Aave's event records the WETH covered and the rsETH seized. The net
debt-token transfer is smaller because Aave mints accrued interest first.
Yoink sold the seized rsETH on Fluid, repaid Morpho, and kept a thin
ETH skim.
The first drain pulled aToken and left the WETH debt in place. Health fell. The seize is what that drop made possible.
| When UTC | What moved |
|---|---|
| 04:38:47 | 2,882.37 rsETH to 0xC70f00… ; 17.63 sold for 18.95 ETH, skim to 0x6c42… |
| 05:24:47 | Copycat 50 aEthrsETH, same PAT recipe. 40 rsETH into CoW in four tens, 10 to 0x006d0e0d… |
| 05:43–05:58 | Repeat v4 PAT deposits (two nines, then 0.5 drips). Same Safe, same module path. |
| 05:47:59 | Same attacker hits a second Safe: 86,632 DUSD and 38,248 USDC out; 23.69 ETH to the attacker EOA. |
| 05:53:59 | Yoink Aave seize: 168.83 WETH debt covered, 157.71 rsETH taken, sold on Fluid. |
| 06:00 | Owner tx disables the two modules used in this drain (gateway and LP). |
| 06:37 | Same sender repays 248 WETH of Aave debt. |
| 07:20 | Owner tx disables nine other modules on the same Safe. |
06 · What is still on the Safe
The loop did not empty
After the extracts, the seize and the WETH repay, a merge snapshot of the Safe still shows a large aEthrsETH pile and a large WETH debt-token balance. Native rsETH left on the Safe is a few tokens. UNI-V4-POSM still includes the empty PAT NFT. Other token balances on this address look like spam.
| Still on the Safe after the morning | Amount |
|---|---|
| aEthrsETH | 50,279 |
| variableDebt WETH | 51,344 |
| Native rsETH | 7.18 |
| UNI-V4-POSM NFTs | 18, including the empty PAT position |
The two modules used in the drain were turned off that morning, about an hour and a half after the capture. Copycats ran until a few minutes before that. The leftover Aave position is still open.
A second Safe was hit later that morning by the same attacker, with a fresh PAT mint. Yoink did not front-run that one. DUSD and USDC went into Pool Manager, the helper swapped them out, and ETH landed on the attacker. Public notes put the dollar size near the DUSD plus USDC.
07 · Did labels help?
Our database named venues. MetaSleuth named Yoink.
We queried labels and wrote nothing back.
Our directory.labels table has no rows for the victim Safe, the
executor, the attacker, PAT, the modules, Yoink, or the freeze wallet. It
names well-known venues through the
address labels API: Uniswap v4 Pool
Manager, CoW settlement, Morpho Blue, Fluid. That confirms routes we
already had from the trace. It does not name anyone in the case.
MetaSleuth names the searcher MEV Frontrunner Yoink. It also names Safe Singleton 1.3.0, Aave V3, aEthrsETH, Kelp rsETH, Permit2, and Uniswap v4 Position Manager. The Yoink EOA also carries an EXPLOIT tag from an older Aperture Finance case.
Early public notes had Morpho and Fluid swapped. The flash loan is Morpho Blue. The rsETH-to-ETH swap is Fluid.
08 · Related, and not the same
April Kelp, and a second Safe
In April a bridge mint created a large pile of unbacked rsETH. Different people, and a different date. This September event is a user module path. Kelp's rsETH backing is not the failure mode here.
The second Safe is the same PAT recipe against other tokens, same attacker, no Yoink front-run. We treat it as the same crew, a smaller take.
09 · How we read the chain
Transfers first, then events, then labels
Where a swap event and a transfer disagree, we kept the transfer. The same queries sit behind Bitquery MCP.
| What could go wrong | How we handled it |
|---|---|
| Swap event signs vs transfers | Transfers are ground truth: Safe → Pool Manager → helper for aEthrsETH, helper pays PAT. take() matches. |
| Debt token 8.71 vs 168.83 WETH | Aave Burn splits interest mint and repay. LiquidationCall event matches WETH covered and rsETH seized. |
| Hook vs unlocker | PoolKey.hooks is the zero address at initialize and at mint. 0x5d20 is a CALL into unlock. |
| Merge balances on the Safe | aEthrsETH and variableDebtWETH are the two we trust; other tokens on the address are treated as spam. |
| Kelp pause as a fact | We report zero rsETH outflows. We do not claim we saw the pause call. |
10 · The record
The addresses behind the story
| Role | Address |
|---|---|
| Victim Safe 1.3.0 | 0x40E93a…7AbA8 |
| Capture tx | 0x0e7680…8705 |
| Public executor | 0x4f00…8ebC |
| Gateway module | 0xea18…c4ca |
| Uniswap v4 LP module | 0xdcdc…82ab |
| Original attacker EOA | 0x0dC2…9b66 |
| Helper | 0x1060…5Cb1 |
| PAT | 0x8762…61f5 |
| Unlocker | 0x5d20…e8bb |
| Yoink EOA | 0xFDe0…455A |
| Yoink bot | 0x80BF…D4e4 |
| rsETH still here | 0xC70f00…80ea0 |
| ETH skim | 0x6c42…bf0e |
| Second Safe | 0x6a1f…7ea2 |
| Owner-tx sender | 0x8c2a…fee8 |
The same hops are on Coinpath.
If you hold rsETH in a Safe that uses a public executor in front of an LP module, the two modules in this case are worth treating as burned until you have turned them off yourself. An empty capture-day balance is no proof the path is closed.
Ask these questions in plain English
The same index is on the Bitquery MCP server. An assistant can list which modules have been calling a Safe, decode a capture tx, follow an aToken to rsETH, or watch a wallet for outflows, without writing the query by hand.
This article is provided for informational and educational purposes only and reflects analysis of publicly available on-chain data as of the dates indicated. It does not constitute legal, financial, compliance, or investment advice, and nothing in it is a recommendation to buy, sell, or hold any token or asset.
This piece reconstructs one Safe on Ethereum on 15 September 2026 from public call, event and transfer records. Yoink is a public searcher name from MetaSleuth; we describe that bot by its on-chain behaviour and do not claim who runs it. Module, executor and attacker addresses are named by behaviour. We do not claim a vendor for the unverified LP logic, and we do not claim Kelp’s contracts failed. Dollar figures use the capture-day print on the frozen rsETH pile. Owner identity is unlabeled. Aave seize math uses the LiquidationCall event, not the net debt-token transfer. Blockchain addresses are pseudonymous, and a transaction between two addresses does not by itself establish the identity, intent or knowledge of any party. Every entity attribution here is an inference that may be incomplete or wrong.
Nothing herein should be relied upon as a definitive determination of fact. Readers should conduct their own independent verification before taking any action. The authors and publisher accept no liability for any loss or damage arising from reliance on this material. All trademarks and company names are the property of their respective owners.
Run this kind of trace on your own data
Every figure here came from public Ethereum call, event and transfer records: Safe module execs, Uniswap v4 unlocks, Aave burns and the wallets the rsETH landed in.