Rescue ENS & Vesting Contracts From a Compromised Wallet
By Merunas Grincalaitis (X · GitHub · DEV · Hashnode · Telegram), Founder & Lead MEV Engineer at MEV DAO — Ethereum smart contract, Flashbots & MEV builder since 2017. Last updated: October 2026.
TL;DR: To rescue an ENS name from a compromised wallet (rescue ens compromised wallet), you must check whether the .eth domain is unwrapped (ERC-721 BaseRegistrarImplementation + ENSRegistry—requiring both Registrant and Controller transfers) or wrapped in the ENS NameWrapper contract (ERC-1155 safeTransferFrom), and execute the transfer inside an atomic Flashbots bundle (eth_sendBundle). To rescue a vesting contract from a hacked wallet (vesting contract hacked wallet), first check if the stream is transferable (e.g., Sablier V2 NFTs or changeRecipient), and if it is non-transferable, deploy a continuous Block-0 Cliff Rescue Bot that atomically claims and sweeps each vested token tranche the microsecond a cliff unlocks.
Part of the Compromised Wallet & Sweeper Bot Rescue Topic Cluster: Start with our Pillar Guide, How to Rescue Tokens From a Compromised Wallet With a Sweeper Bot (Flashbots Guide), for the complete architectural blueprint. This guide focuses specifically on rescue ens compromised wallet with production Ethereum mainnet parameters and runnable verification steps.
Most wallet recovery guides only show you how to transfer a standard ERC-20 token. But what if your leaked Ethereum wallet owns your primary .eth ENS domain (which controls your web3 identity, subdomains, and payment routing) or is the hardcoded beneficiary of a $50,000+ token vesting contract (Sablier, Hedgey, Team Finance, Unicrypt, or an investor cliff contract)?
Because sweeper bots normally only scan for liquid ETH and top ERC-20 balances, your ENS names and unvested token streams are often still sitting untouched inside the compromised wallet right now—until the hacker manually inspects your address or sets up a cliff monitor. Here is the exact technical playbook to rescue ENS names and vesting contracts from a compromised wallet using our MEV DAO Sweeper Bot Rescue Service and open-source compromised-wallet-sweeper-rescue GitHub scripts.
Rescue Architecture: ENS Domains & Vesting Contracts (Comparison Table)
| Compromised Asset Type | On-Chain Contract & Standard | Why Simple Transfers Fail | Exact Atomic Flashbots Rescue Call Sequence |
|---|---|---|---|
Unwrapped .eth ENS Name (rescue ens compromised wallet) |
BaseRegistrarImplementation (0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85 — ERC-721) + ENSRegistry (0x00000...00000000000C2E074eC69A0dFb2997BA6C7d2e1e) |
Transferring only the Controller leaves the Registrant (ultimate owner) on the hacked wallet—or vice versa! | [tx1: Sponsor ETH, tx2: BaseRegistrar.reclaim(labelHash, safeWallet), tx3: BaseRegistrar.transferFrom(hacked, safeWallet, labelHash)] |
Wrapped .eth ENS Name (NameWrapper) |
ENS NameWrapper (0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401 — ERC-1155) |
Standard ERC-721 scripts fail because wrapped ENS names are ERC-1155 tokens keyed by namehash(name)! |
[tx1: Sponsor ETH, tx2: NameWrapper.safeTransferFrom(hacked, safeWallet, uint256(namehash), 1, "0x")] |
| Transferable Token Vesting Stream (Sablier V2 / Hedgey NFT) | Sablier V2 LockupLinear / LockupDynamic (ERC-721 Stream NFT) |
Victim waits for tokens to vest instead of rescuing the entire future stream NFT immediately! | [tx1: Sponsor ETH, tx2: SablierLockup.transferFrom(hacked, safeWallet, streamId)] (Rescues 100% of future unvested tokens in 1 block!) |
Non-Transferable Cliff / Linear Vesting Contract (vesting contract hacked wallet) |
Custom OpenZeppelin VestingWallet or Team/Seed release() contract |
Beneficiary address is immutable (immutable beneficiary), and release() sends tokens to the hacked wallet! |
[tx1: Sponsor ETH, tx2: Vesting.release(token), tx3: Token.transfer(safeWallet, vestedAmount)] inside one atomic bundle! |
Part 1: How to `rescue ens compromised wallet` (.eth domains) without leaving a backdoor
An Ethereum Name Service (.eth) domain has two separate permission layers when unwrapped:
- The Registrant (ERC-721 Token Owner on
BaseRegistrarImplementation): The ultimate owner of the.ethsecond-level domain (keccak256("yourname")). The Registrant can overwrite the Controller at any time viareclaim(). - The Controller / Manager (Record Owner on
ENSRegistry): The address allowed to change the ETH resolution address (addr), avatar, and text records.
The #1 mistake victims make: They transfer only the ERC-721 NFT (transferFrom) without calling reclaim()—leaving the compromised wallet as the active Controller on ENSRegistry! A hacker with the leaked private key can then change your .eth resolving address to their own wallet so anyone sending ETH to yourname.eth sends it straight to the attacker!
Step-by-step Flashbots bundle to rescue an Unwrapped .eth name:
// Compute labelhash for "vitalik.eth" -> label is "vitalik"
const labelHash = ethers.id("yourname"); // keccak256("yourname")
const tokenId = BigInt(labelHash);
// Inside your atomic Flashbots bundle (signed by compromisedWallet, funded by sponsorWallet):
// Call 1: Overwrite the ENSRegistry Controller to your new safeWallet!
const txReclaim = await baseRegistrar.reclaim.populateTransaction(tokenId, safeWalletAddress);
// Call 2: Transfer the ERC-721 Registrant ownership to your new safeWallet!
const txTransfer = await baseRegistrar.transferFrom.populateTransaction(
compromisedAddress,
safeWalletAddress,
tokenId
);
What if your .eth name is Wrapped inside ENS NameWrapper?
Check if the owner of your domain on BaseRegistrarImplementation is 0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401 (NameWrapper). If so, your ENS domain is an ERC-1155 token whose id is the full namehash("yourname.eth") (not keccak256("yourname")).
Your Flashbots bundle simply calls NameWrapper.safeTransferFrom(compromisedAddress, safeWalletAddress, BigInt(ethers.namehash("yourname.eth")), 1n, "0x"), which atomically transfers both ownership and management rights to your new wallet in a single transaction! (For other NFTs, see Recover NFT From a Hacked Wallet: Sweeper Bot Guide.)
Part 2: How to rescue a `vesting contract hacked wallet` (Sablier, Linear & Cliff Vesting)
When a founder, employee, or angel investor suffers a leaked private key on the address registered in a token vesting contract, millions of dollars in unvested tokens are suddenly at risk.
Follow this exact 3-step decision tree to rescue a vesting contract from a hacked wallet:
Scenario A: The vesting contract is an NFT or has a changeRecipient / transferOwnership function
Check the vesting contract on Etherscan (Read Contract / Write Contract) first!
- Sablier V2 (
LockupLinear/LockupDynamic), Hedgey, and Llamapay Vesting NFTs: In Sablier V2, every vesting stream is minted as an ERC-721 NFT to the recipient! Unless the sender explicitly marked the stream non-transferable, you do not have to wait for the tokens to vest. Run an atomic Flashbots bundle right now callingsablierContract.transferFrom(compromisedWallet, safeWallet, streamId). The moment that bundle lands, 100% of all future unvested tokens now stream directly to your new safe wallet! - Custom Vesting with
setBeneficiary/transferOwnership: Some custom vesting contracts allow the current beneficiary to update their receiving address. Bundle[tx_sponsor_gas, tx_change_beneficiary(safeWallet)]viaeth_sendBundle.
Scenario B: Non-transferable Linear Vesting (VestingWallet.release(token))
Many seed/team allocations use OpenZeppelin's immutable VestingWallet where release(address token) always transfers vested ERC-20 tokens into the hardcoded beneficiary (compromisedWallet), and anyone can call release().
- Notice the danger: If the attacker calls
vestingContract.release(token)in transaction 1 of their bundle, the tokens land insidecompromisedWallet, and the attacker's transaction 2 (token.transfer(hackerWallet)) steals them! - How to win: Never let a large unclaimed balance accumulate in a linear vesting contract! Use an atomic 3-transaction Flashbots bundle (
[tx1: Sponsor ETH, tx2: VestingWallet.release(token), tx3: Token.transfer(safeWallet, amount)]) that triggers the release and sweeps the ERC-20 tokens out to your safe wallet in the exact same block and transaction sequence.
Scenario C: Upcoming Cliff Unlock (unlockTimestamp / unlockBlock)
If you have a large cliff unlock scheduled for a specific block.timestamp (e.g., 25% of your allocation unlocks on November 1, 2026 at 00:00:00 UTC), treat it exactly like a contested unstaking cooldown (see Unstake From a Compromised Wallet: Rescue Locked Tokens):
- Pre-simulate the
[Sponsor ETH -> Claim/Release -> Transfer ERC-20 to Safe Wallet]bundle usingeth_callBundlewith a timestamp override (timestamp: unlockTimestamp) to verify exact gas and token balance deltas (see Simulate a Flashbots Bundle With eth_callBundle). - Point our multi-builder rescue bot at Titan Builder, Beaverbuild, Flashbots, and Rsync starting 10 blocks before
unlockTimestamp, bidding a competitivecoinbasebuilder tip so your rescue bundle lands at the top of the very first block whereblock.timestamp >= cliffTimestamp!
Frequently asked questions
Can a sweeper bot steal my .eth ENS domain?
Most automated sweeper bots only monitor native ETH and liquid ERC-20 tokens, so your .eth ENS domain often sits untouched in a compromised wallet for weeks. However, you cannot transfer it normally because any gas ETH you send to the wallet will be stolen by the sweeper—you must use an atomic Flashbots bundle (eth_sendBundle) to pay gas and transfer the ENS domain in one block.
Why do I need to call both reclaim() and transferFrom() when rescuing an unwrapped ENS name?
In unwrapped .eth domains, transferFrom() on the BaseRegistrarImplementation contract transfers the Registrant (ERC-721 owner), but leaves the old compromised wallet set as the Controller in ENSRegistry. Calling reclaim(labelHash, safeWallet) inside the same Flashbots bundle updates the Controller to your safe wallet so the hacker cannot hijack your .eth payment records.
How can I rescue tokens from a Sablier V2 vesting stream in a hacked wallet?
Sablier V2 streams are represented as ERC-721 NFTs. Check isTransferable(streamId) on the Sablier Lockup contract—if true, you can rescue the entire stream (including all future unvested tokens) immediately in a single Flashbots bundle by calling transferFrom(compromisedWallet, safeWallet, streamId).
What if my vesting contract has an immutable beneficiary address that cannot be changed?
When the beneficiary address is hardcoded and release() sends tokens into the compromised wallet, you must execute an atomic Flashbots bundle: [tx1: Sponsor sends exact gas ETH, tx2: Call release() on the vesting contract, tx3: Compromised wallet transfers the released ERC-20 tokens to Safe Wallet]. All three steps execute back-to-back in the same block so the sweeper bot can never intercept the tokens.
Can MEV DAO help me rescue an upcoming vesting cliff or ENS portfolio from a compromised wallet?
Yes! Our MEV DAO Sweeper Bot Rescue Service handles ENS domain rescues (wrapped and unwrapped), Sablier/Hedgey stream transfers, and high-priority multi-builder cliff rescues for non-transferable vesting contracts.
Related articles
- Rescue Tokens From a Compromised Wallet: Sweeper Bot Rescue Service
- Unstake From a Compromised Wallet: Rescue Locked Tokens
- Recover NFT From a Hacked Wallet: Sweeper Bot Guide
- How to Claim an Airdrop From a Compromised Wallet (Before the Sweeper Does)
- EIP 7702 Rescue vs Flashbots Bundles: Saving Tokens
Need to rescue .eth ENS names, a Sablier/Hedgey stream, or an upcoming token vesting cliff from a compromised Ethereum wallet? Use the MEV DAO Token Rescue Bot with a 3-day free trial at mevdao.org/subscribe, or message me directly on Telegram (@merunas) to set up a custom cliff rescue bundle.