Date: 2026-04-19
Investigate whether Ethereum delivery tx 0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db4222 was backed by real source-side funds on Unichain, and whether the LayerZero path configuration explains the failure mode.
The Ethereum-side 116,500 rsETH release came out of real, pre-funded bridge inventory on the Ethereum adapter, but it does not appear to be backed by any legitimate source-side debit on Unichain.
The strongest evidence:
- The Unichain -> Ethereum route is configured as a
1-of-1DVN path with no optional DVNs. - The Ethereum adapter held
116,723.5206355 rsETHone block before the exploit and only223.5206355 rsETHimmediately after, so the exploit drained existing inventory rather than minting newrsETHon Ethereum. - Nonce
308wasPayloadVerifiedat2026-04-18 17:33:35 UTC, committed at17:35:11 UTC, and successfully delivered at17:35:35 UTC. - Ethereum accepted inbound nonce
308, but the matching Unichain source endpoint still reports outbound nonce307. - The Unichain
rsETHsource token did not show a matching burn or supply reduction around the message window. - A second packet, nonce
309, was also verified on Ethereum by the same single DVN, but only after Kelp had already frozen the original recipient. - The first failed retry for nonce
309reverted withTransfersBlocked(0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b, 2026-04-19 18:23:11 UTC), so that failure was not caused by insufficient adapter inventory. - The recipient and its splitter wallets were freshly Tornado-funded and dispersed the full
116,500 rsETHinto prepared branches within about five minutes.
My current conclusion is that the observed behavior is most consistent with a single-DVN verification failure or equivalent verification-path compromise on the Unichain -> Ethereum Kelp route. The onchain evidence does not identify the exact root cause beyond that.
-
Unichain source
rsETHtoken / OFT:0xc3eacf0612346366db554c991d7858716db09f58 -
Unichain LayerZero endpoint:
0x6F475642a6e85809B1c36Fa62763669b1b48DD5B -
Unichain -> Ethereum send library:
0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7 -
Source required DVN on Unichain side:
0x282b3386571f7f794450d5789911a9804fa346b4 -
Ethereum LayerZero endpoint:
0x1a44076050125825900e736c501f859c50fE728c -
Ethereum Kelp
rsETHOFT adapter:0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 -
Ethereum receive library:
0xc02Ab410f0734EFa3F14628780e6e695156024C2 -
Destination required DVN on Ethereum side:
0x589dedbd617e0cbcb916a9223f4d1300c294236b -
Recipient of the first release:
0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b -
Gas-paying executor EOA on Ethereum:
0x4966260619701a80637cDbdAc6A6cE0131f8575E
Onchain config reads for the exact Kelp path show one required DVN and zero optional DVNs on both sides.
getSendLibrary(oapp=0xc3eacf0612346366db554c991d7858716db09f58, dstEid=30101)returned0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7getConfig(oapp=0xc3eacf0612346366db554c991d7858716db09f58, lib=0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7, eid=30101, configType=2)returned data that decodes to:confirmations = 42requiredDVNCount = 1optionalDVNCount = 0optionalDVNThreshold = 0requiredDVNs = [[0x282b3386571f7f794450d5789911a9804fa346b4](https://uniscan.xyz/address/0x282b3386571f7f794450d5789911a9804fa346b4)]optionalDVNs = []
getReceiveLibrary(oapp=0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3, srcEid=30320)returned0xc02Ab410f0734EFa3F14628780e6e695156024C2getConfig(oapp=0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3, lib=0xc02Ab410f0734EFa3F14628780e6e695156024C2, eid=30320, configType=2)returned data that decodes to:confirmations = 42requiredDVNCount = 1optionalDVNCount = 0optionalDVNThreshold = 0requiredDVNs = [[0x589dedbd617e0cbcb916a9223f4d1300c294236b](https://etherscan.io/address/0x589dedbd617e0cbcb916a9223f4d1300c294236b)]optionalDVNs = []
This route is therefore effectively 1-of-1.
The required DVN on the Ethereum side, 0x589dedbd617e0cbcb916a9223f4d1300c294236b, is labeled LayerZero : DVN on Etherscan. Separately, LayerZero's DVN provider docs and Simple Config Generator present LayerZero Labs as a standard DVN provider and use [['LayerZero Labs'], []] as the minimal single-DVN configuration example. That does not by itself prove the exact provider identity for this address from docs alone, but it does show that a 1-of-1 configuration with LayerZero as the sole DVN provider is part of the intended configuration model.
That matters for fault attribution. A 1-of-1 route whose sole verifier is explorer-labeled as LayerZero-associated is materially different from a 1-of-1 route secured by an unrelated third-party verifier. If the path failed at verification, the likely fault domain shifts toward a LayerZero-associated worker or its trust inputs, rather than an arbitrary external DVN provider.
For nonce 308, the verification chain on Ethereum was:
PayloadVerifiedon receive library0xc02Ab410f0734EFa3F14628780e6e695156024C2in tx0xfe575668f895e10f8496fca3bb928fa53bebbea3e1de567d61bcd12d935f0d6fat2026-04-18 17:33:35 UTCcommitVerification(bytes,bytes32)on the same receive library in tx0x68eb14e2d0ea9eca0f6277b6e4242c898a08d83a9ffe322dd875e69112e3b564at2026-04-18 17:35:11 UTClzReceive(...)on the endpoint in tx0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db4222at2026-04-18 17:35:35 UTC
For nonce 309, the chain was separate and later:
PayloadVerifiedin tx0xa3e663b98704def447350b7960d3824340e5c3bad538da529c3a7d21b48836b7at2026-04-18 18:25:47 UTCcommitVerification(bytes,bytes32)in tx0xea851cd85ca45d7ca7012df929e4ef1c602d9a3de5ec93746aa8f24ccafb58aaat2026-04-18 18:26:23 UTC- failed
lzReceive(...)in tx0x8509533aed1c9257242b44447daf4fc5d0c562972f366c98cea92dc531783e53at2026-04-18 18:26:35 UTC
This matters because nonce 309 was not already sitting verified before the freeze. The Kelp Safe freeze tx 0xa1495d12abdd7369bb92ecfc0cbdbdc2a7f631604f783abc1e985f3e682e25fc landed at 2026-04-18 18:23:11 UTC, before 309 was PayloadVerified, committed, or executed.
The actors were also distinct:
- the
PayloadVerifiedtx for308was sent to the DVN contract by0xD95D7761A585bBc1B59B4B6F441B9eDc2878DAdE - the
PayloadVerifiedtx for309was sent by0xD3A227725c3EAe3681eB2817ef6C09200ba46a3f - the
commitVerificationandlzReceivetxs for both packets were sent by the gas-paying executor EOA0x4966260619701a80637cDbdAc6A6cE0131f8575E
So the onchain path was: DVN-side proof submission -> manual commit by 0x4966260619701a80637cDbdAc6A6cE0131f8575E -> manual execution by 0x4966260619701a80637cDbdAc6A6cE0131f8575E.
The DVN-side txs were not generic wallet sends. They were calls to DVN 0x589dedbd617e0cbcb916a9223f4d1300c294236b using execute((uint32,address,bytes,uint256,bytes)[]), with the embedded call targeting receive lib 0xc02Ab410f0734EFa3F14628780e6e695156024C2 and verify(bytes,bytes32,uint64).
On the Unichain source side, getConfig(..., configType=1) for send lib 0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7 returned executor config bytes that decode as:
maxMessageSize = 99executor = [0x4208D6E27538189bB48E603D6123A94b8Abe0A0b](https://etherscan.io/address/0x4208D6E27538189bB48E603D6123A94b8Abe0A0b)
LayerZero's executor docs describe this config as the fee-paying executor for destination delivery, but execution is still permissionless after verification. That is consistent with what happened here: the configured executor address was not the gas-paying EOA. Instead, 0x4966260619701a80637cDbdAc6A6cE0131f8575E manually committed and executed the already-verified packets.
Visible Ethereum history makes 0x4966260619701a80637cDbdAc6A6cE0131f8575E look like a fresh throwaway caller rather than a standing executor wallet:
- it has exactly five outgoing Ethereum txs, all five on this single Kelp LayerZero route
- it has no visible ERC-20 history and no non-LayerZero protocol interactions
- it was funded hours earlier by an internal transfer of
0.99392252389025 ETHfrom TornadoCash contract0x47ce0c6ed5b0ce3d3a51fdb1c52dc66a7c3c2936
By contrast, the configured executor address 0x4208D6E27538189bB48E603D6123A94b8Abe0A0b currently looks dormant on Ethereum: no code, nonce 0, no outgoing txs, and no token activity.
So the evidence supports a narrower description than "the LayerZero executor did this." The visible executor path is: a configured executor role exists in the send-lib config, but the exploit-path commit and delivery calls were made by a fresh, mixer-funded EOA exploiting LayerZero's permissionless post-verification execution model.
DVN 0x589dedbd617e0cbcb916a9223f4d1300c294236b is not a proxy:
- its EIP-1967 implementation and admin slots are zero
- it was deployed directly in tx
0x76548b4ee8bc0c9fcb44cc28df1f4d1073135514ed606010cf1d4adbf2a00cff
The constructor committee was:
- signers:
0x5AB40527AA622960E26a171c58011de58DFA5bE9,0x7e1879A1Fba74d8107E2E3EE42f5fea5E6500f5B,0xE4059e1B02d8d74Fc82d27BD5006Ecc3605D9CEc - quorum:
2 - admins:
0x9F403140Bc0574D7d36eA472b82DAa1Bbd4eF327,0xB8FF877ed78Ba520Ece21B1de7843A8a57cA47Cb
Current state matches the state from about 30 days before the incident:
quorum() = 2signerSize() = 3- all three constructor signers were active both now and at block
24,693,386
I found no UpdateSigner(address,bool) events and no UpdateQuorum(uint64) events. So the signer committee and threshold do not appear to have been changed around the exploit.
What did change was admin surface:
0xD3A227725c3EAe3681eB2817ef6C09200ba46a3fwas grantedADMIN_ROLEin tx0xa32b5521922d2e282363d22243d24f5b6f4a7e910b147395dd1021a530924d08on2025-02-06 11:50:23 UTC0xD95D7761A585bBc1B59B4B6F441B9eDc2878DAdEwas grantedADMIN_ROLEin tx0xd45f564859e3e640b92f77ce43f0cd2b4eed8c0d429b66dc2b9225bb23dfdcaeon2025-02-06 11:51:35 UTC- there was a broader admin expansion on
2026-04-08, when ten newgrantRole(ADMIN_ROLE, ...)txs were sent from0xB8FF877ed78Ba520Ece21B1de7843A8a57cA47Cb
So the suspicious verification submitters were not fresh attacker-controlled signers added right before the incident. They were long-standing authorized DVN admins operating against a stable signer committee.
They also do not look isolated to this packet pair. In a narrow receive-lib sweep over the surrounding window, both submitters were verifying many other packets on 0xc02Ab410f0734EFa3F14628780e6e695156024C2, which makes them look like routine DVN operator/admin EOAs rather than one-off attacker wallets.
Tx:
0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db4222
It is a LayerZero EndpointV2 lzReceive call carrying:
srcEid = 30320(Unichain)sender = [0xc3eacf0612346366db554c991d7858716db09f58](https://uniscan.xyz/address/0xc3eacf0612346366db554c991d7858716db09f58)nonce = 308receiver = [0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3](https://etherscan.io/address/0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3)guid = 0x3f4510d855cf3a805fec59daafae640d290749b7bf1e5450f91b5fb0018b3b4e
The payload delivered 116,500 rsETH to:
- Ethereum destination endpoint:
lazyInboundNonce(0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3, 30320, 0xc3eacf0612346366db554c991d7858716db09f58) = 308
- Unichain source endpoint:
outboundNonce(0xc3eacf0612346366db554c991d7858716db09f58, 30101, 0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3) = 307
If nonce 308 had been legitimately sent from Unichain, the source outbound nonce should have advanced to at least 308. It did not.
LayerZero Scan shows the same mismatch for the packet metadata:
- nonce
308/ GUID0x3f4510d855cf3a805fec59daafae640d290749b7bf1e5450f91b5fb0018b3b4e - destination tx populated on Ethereum
- source tx still blank in the scan response
This is stronger than a public-indexer omission. If a canonical source-side send had succeeded through the LayerZero endpoint, the source outbound nonce should have advanced. It did not.
The Unichain source contract is the token itself:
name() = "KelpDao Restaked ETH"symbol() = "rsETH"token() = [0xc3eacf0612346366db554c991d7858716db09f58](https://uniscan.xyz/address/0xc3eacf0612346366db554c991d7858716db09f58)decimals() = 18sharedDecimals() = 6
Nonce 307 is a clean baseline for expected behavior on this exact route.
- Unichain source tx:
0x32877156a2d7d186f3a43c8365b1743fb7eff84bd94b8ef2688702ba1447d778 - Ethereum destination tx:
0xc232af35a6c98c92fdb0b08675e93d678994c2c97d31e133f909e0cb95960211
In the Unichain source receipt for nonce 307, the token emits:
Transfer(0x222e68aa6658a8067585f19ecca5440feaa8bb00 -> 0x8e60b7b64b63cd56b18ebcecadcb79b04919286e, 0.006 rsETH)Transfer(0x8e60b7b64b63cd56b18ebcecadcb79b04919286e -> 0x0000000000000000000000000000000000000000, 0.006 rsETH)
That is the expected OFT debit-and-burn pattern on the source chain. The LayerZero message payload for nonce 307 ends with 0x1770, which is 6000 shared-decimal units, and the Ethereum destination tx releases exactly 0.006 rsETH.
This control case matters because it shows what a legitimate send on this route looks like. Nonce 308 does not show the same source-side burn footprint.
Unichain source totalSupply() remained unchanged at:
- block
45,785,275:49.259532 rsETH - block
45,785,276(LayerZero Scan creation time for nonce308):49.259532 rsETH - block
45,785,277:49.259532 rsETH - block
45,786,000:49.259532 rsETH
There is no 116,500 rsETH source-side supply reduction.
Using eth_getLogs against the Unichain RPC for the source token 0xc3eacf0612346366db554c991d7858716db09f58 over the message window around nonce 308:
- no
Transferlogs at all for the token in the matching block range - no burn to
0x0000000000000000000000000000000000000000 - no source-side debit pattern resembling a normal OFT send
Taken together with the nonce mismatch, this strongly indicates the destination-side release was not backed by a real source-side debit.
The exploit did not mint new rsETH on Ethereum. The canonical rsETH balance of the Ethereum adapter 0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 was:
- block
24,908,284(one block before the exploit):116,723.5206355 rsETH - block
24,908,285(the exploit block):223.5206355 rsETH
So the exploit was a withdrawal from pre-existing Ethereum bridge inventory against what appears to have been an unbacked cross-chain claim.
The clean control packet 307 was executed through helper contract 0x173272739Bd7Aa6e4e214714048a9fE699453059 using execute302((address,(uint32,bytes32,uint64),bytes32,bytes,bytes,uint256)) in tx 0xc232af35a6c98c92fdb0b08675e93d678994c2c97d31e133f909e0cb95960211. Its decoded packet fields were:
- receiver =
0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 - origin =
(30320, 0xc3eacf0612346366db554c991d7858716db09f58, 307) - payload = recipient
0x222e68aa6658a8067585f19ecca5440feaa8bb00plusamountSD = 6000 - extraData =
0x
The suspicious packets 308 and 309 were delivered directly through endpoint lzReceive(...), but their decoded fields have the same shape:
- same origin tuple layout
(30320, 0xc3eacf0612346366db554c991d7858716db09f58, nonce) - same receiver
0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 - same 28-byte payload shape: 20-byte recipient
0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3bplusamountSD - empty
extraData
Decoded payloads:
308: recipient0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b,amountSD = 116,500,000,000309: recipient0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b,amountSD = 40,000,000,000
So there is no obvious packet-shape anomaly in 308/309. The suspicious property is not malformed packet encoding. It is that structurally normal-looking packets were accepted without the canonical source-side debit.
LayerZero Scan for GUID
0x19073f141ef29ea2eb2c52046e60942a928b2106651e622b73c68e27c969cfe6
shows a second message on the same path:
- same source peer
0xc3eacf0612346366db554c991d7858716db09f58 - same destination peer
0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 nonce = 309- same single DVN
0x589dedbd617e0cbcb916a9223f4d1300c294236b - destination status:
INFLIGHT - message status:
Verification committed - source tx is still blank in the scan response
On Ethereum:
inboundPayloadHash(0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3, 30320, 0xc3eacf0612346366db554c991d7858716db09f58, 309) = 0xbf86af6f10782715c263b7c76c86e7a965b29f2a0119806ea4eb108d197e0c7e
This matches the LayerZero Scan payload hash for nonce 309, meaning the destination endpoint has stored the verified packet.
The failed executor lzReceive retries for nonce 309 encode amountSD = 40,000,000,000.
With sharedDecimals = 6, this corresponds to:
40,000 rsETH
Failed Ethereum executor txs:
0x8509533aed1c9257242b44447daf4fc5d0c562972f366c98cea92dc531783e530x48d9b3e8fc30c3780d3345743f5defc84ea57e5214ec9d3c4abd04f90465d792
Both are failed lzReceive attempts for nonce 309.
The first failed attempt can be replayed as an eth_call against the same block and reverts with:
TransfersBlocked(0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b, 2026-04-19 18:23:11 UTC)
So nonce 309 did not fail because the adapter lacked inventory. It failed because the destination-side transfer to the same recipient was blocked by token or adapter logic.
For completeness, the adapter inventory at those blocks was still sufficient to cover 40,000 rsETH:
- block
24,908,539:40,357.5838335 rsETH - block
24,908,547:40,357.5838335 rsETH
The Ethereum canonical rsETH token at 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7 contains:
mapping(address => uint256) public transfersBlockedUntilerror TransfersBlocked(address account, uint256 blockedUntil)event UserTransfersBlocked(address indexed user, uint256 until)
The live transfersBlockedUntil value for recipient 0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b matches the revert timestamp:
1776622991=2026-04-19 18:23:11 UTC
That block was set in Ethereum block 24,908,522 by tx 0xa1495d12abdd7369bb92ecfc0cbdbdc2a7f631604f783abc1e985f3e682e25fc, which:
- was sent from
0x7AAd74b7f0d60D5867B59dbD377a71783425af47 - called
0xCbcdd778AA25476F203814214dD3E9b9c46829A1 - uses selector
0x6a761202, which decodes tosweep(address[],address) - emitted
UserTransfersBlocked(0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b, 2026-04-19 18:23:11 UTC)on thersETHtoken
0xCbcdd778AA25476F203814214dD3E9b9c46829A1 is a GnosisSafeProxy. Its onchain owner set includes 0x7AAd74b7f0d60D5867B59dbD377a71783425af47, and the Safe threshold is 3.
So the recipient freeze was not incidental. It was an active Ethereum-side intervention through a Kelp-controlled Safe path after nonce 308 had already released funds and before nonce 309 retries.
Recipient 0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b does not look like a normal operational wallet or a reused Kelp address.
- Its first visible funding came from internal tx
0xcb2ee450d6e770216dc3061750b4ac5b5fa494666bcf7eaa936411733e2ef7eeat2026-04-18 11:05:35 UTC - that funding source was
0x12d66f87a04a9e220743712ce6d9bb1b5616b8fc, the verifiedTornadoCash_Eth_01contract - the recipient had no visible prior normal tx history before the exploit
After receipt of 116,500 rsETH, the wallet emptied itself in about five minutes into seven pre-staged branch wallets:
53,000 rsETHto0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeFin tx0xe381248517921e5a576fd915e6c7b93f7ab10f3d323ea89730b28fe91d84e70aat17:37:23 UTC30,000 rsETHto0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129Bin tx0x95fa2f737aa3f22c182dc86898ac63853ce3c6ddc802ced97a635eb8474d19edat17:37:59 UTC10,000 rsETHto0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cCin tx0x2acb453e79dd29844ecbd268ea70ba61c6e309767660e326c035f5121a8156bdat17:39:23 UTC6,000 rsETHto0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787in tx0xc86fbb4c275eaa36b9ae3d6202c31c6a7609c428691cd4c039737ce2811e8d26at17:39:47 UTC5,000 rsETHto0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49in tx0x373dfc8aa9c4e4fd365a24bdf36cfb23f1770086d2568b85dcfd05467c890f23at17:40:35 UTC8,000 rsETHto0x1B748B680373a1dD70A2319261328CaB2A6f644Cin tx0xe8748b75e9156de25b5b5225bf0d274bf31af8a3e7bdc7a14e847b42b00ce3b3at17:41:11 UTC4,500 rsETHto0xE9E2f48Bb0018276391AEC240ABB46e8C3CAD181in tx0x684ccb28d1a9fd7db9c21f3bdf92691c124c17858edd45ad37e07bfd7c26cd2fat17:41:59 UTC
Those branch wallets also look staged. The visible sample shows them funded hours earlier from the same Tornado pool with roughly 0.0978 ETH each. The post-split flows resolve into three concrete buckets:
53,400 rsETHremained on Ethereum as open Aave collateral across two wallets39,742.795185625676946836 rsETHwas re-bridged onward through verifiedLZMultiCall23,357.204814374323053164 rsETHwas monetized on Ethereum into ETH, WBTC, andwstETHbefore final ETH consolidation
Visible ETH proceeds then converged on fresh collector 0x5d3919f12bcc35c26eee5f8226a9bee90c257ccc. Direct branch-to-collector transfers now total 75,700.747423535750706684 ETH:
52,440.676111351964954319 ETHfrom0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeFin tx0xe21c3603917d55641267b12b9a4539e6fa48f2b5b40f7afb50c0e6d46ce4d7f616,731.231215477054061404 ETHfrom0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129Bin tx0x868e114e1ce7020fdbbd81a055ab15ee80d435a015d74df8a4aad83865c00bcb5,580.289999587844936742 ETHfrom0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787in tx0x1f879cad6a610f4bef1bbbb993f79235388c5712d04aec6d9c876ce1d0814298554.538691726288597630 ETHfrom0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cCacross txs0x09b0345be434466a2a2062a79805b901f7953c69370be47767f58f3cb4e56ae3and0xb3b28edc5d13269470384155315017370c45f33109b3cd9b26423a3e3b3608a5394.011405392598156589 ETHfrom0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49in tx0x39c062498d6e9ffe09d308f3951d3c3abeb3d5faff878e8f73799921317271e1
The visible pattern is therefore a purpose-built exploit cluster, not a reused operational wallet.
Branch wallet 0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeF is the clearest on-Ethereum deployment leg.
It received 53,000 rsETH from the intake wallet in tx 0xe381248517921e5a576fd915e6c7b93f7ab10f3d323ea89730b28fe91d84e70a at 2026-04-18 17:37:23 UTC, then moved into Aave V3 in a tight sequence:
2026-04-18 17:38:23 UTC: unlimitedrsETHapproval to Aave pool0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2in tx0x3ce9e67830fba7ce2b6d50d3c27e2627ae9186cb545b7e69e4756e9fe1856bee2026-04-18 17:38:47 UTC: Aavemulticall(bytes[])in tx0x9a7df4837aa8ca1e22f3f40ffee2fa583e9f0e1e31c970c4d34070e01038057d, settingeMode = 3and supplying1 rsETH2026-04-18 17:39:47 UTC:approveDelegation(address,uint256)on the WETH variable debt token0xeA51d7853EEFb32b6ee06b1C12E6dcCA88Be0fFEin tx0x376711142668e3b92c3430651beb5aea362b045a08f0227c5add407e9cda5dcc- further
rsETHsupplies to Aave pool:5,000 rsETHin tx0x3fa3e894a788568190b0da0f1869320b34a02034419615449daad004b24082d0at2026-04-18 17:40:47 UTC20,000 rsETHin tx0xc73c9e7e41c41f9bc7d8b42456490af723b761ef22c6a196c7a674a3f4bb7e0eat2026-04-18 17:41:59 UTC27,999 rsETHin tx0xc295f4cd51fdd7d76f64cb7993aba0630769c032190a70835666516825840fc6at2026-04-18 17:43:11 UTC
Against that collateral, the same wallet borrowed ETH through gateway 0xd01607c3C5eCABa394D8be377a08590149325722 in four draws:
- tx
0xdac71a69422da4436307ac962e5067c4838ac63da75379b2ee896f9a9f1bd0b5at2026-04-18 17:40:11 UTC:0.984790260181950369 ETH - tx
0xbcbc76d167152f63561be5ffb9c6f72a840f20a01c8f94979ba484e226263b3fat2026-04-18 17:41:23 UTC:4,923.961148776689335700 ETH - tx
0x2d464e2df042de474ec17ae48b03ba623295215668670911f1783e33acd263fbat2026-04-18 17:42:35 UTC:19,745.044657455187431632 ETH - tx
0x5e2d5c6c8edd7eac05fca9481127863650cab33ead79edcf6be0d2239002868fat2026-04-18 17:43:47 UTC:27,770.592068918515843779 ETH
Total borrowed: 52,440.58266541057456148 ETH.
The next tx from the same wallet, 0xe21c3603917d55641267b12b9a4539e6fa48f2b5b40f7afb50c0e6d46ce4d7f6, sent 52,440.676111351964954319 ETH to collector 0x5d3919f12bcc35c26eee5f8226a9bee90c257ccc at 2026-04-18 17:44:47 UTC. The small excess over the borrowed amount is consistent with forwarding almost the entire wallet ETH balance, not just the borrowed principal.
This was not a deposit-and-close loop. The Aave position remains open. Current Aave reads show:
eMode = 3- current
rsETHaToken balance:53,000.000000023560640817 - current WETH variable debt:
52,442.233352651116124510 - health factor:
1.026937684262118097 - available borrows:
0
I did not find subsequent Repay, Withdraw, or LiquidationCall events for this wallet on the Aave pool. So this branch used stolen rsETH as Aave collateral, extracted ETH against it, forwarded that ETH to the collector, and left the leveraged position behind.
Branch wallet 0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49 ran the same basic strategy with a smaller allocation.
It received 5,000 rsETH from the intake wallet in tx 0x373dfc8aa9c4e4fd365a24bdf36cfb23f1770086d2568b85dcfd05467c890f23 at 2026-04-18 17:40:35 UTC, then:
- approved
rsETHin tx0x2cac9ca15f4167b324c7ed09a068be3d7694296d8e68498eae6d3d242769a071 - supplied
400 rsETHinto Aave V3 viamulticall(bytes[])in tx0x78a1edff5f7d21ccc9414bdc3e1aeb0efbffbbc7ed22ad2a79717793b90d892dat2026-04-18 17:50:23 UTC, again settingeMode = 3 - approved WETH debt delegation in txs
0x56432b1bcbbaf7469a00a46444a391b4eb5e27f700df6ccbcb8fb06ea0ded8d2and0x912f8d661f2ee5532c7036e398cc844cdb76742a632c863cb91c8be4eaeb883c - borrowed
393.916104072779977528 ETHthrough gateway0xd01607c3C5eCABa394D8be377a08590149325722in tx0x96825137f27847f607a5c4011d99d53f6b26ab58aae6e175f81474bdec6959b5 - re-bridged the remaining
4,600 rsETHin tx0x5006bf68c52eac43da4138d834f7df9db6f6948d63e403c7005f17817b84c68e - sent
394.011405392598156589 ETHto collector0x5d3919f12bcc35c26eee5f8226a9bee90c257cccin tx0x39c062498d6e9ffe09d308f3951d3c3abeb3d5faff878e8f73799921317271e1
This position also remains open. Current Aave reads show:
eMode = 3- current
rsETHaToken balance:400.000000000177392827 - current WETH variable debt:
393.928786891380672123 - health factor:
1.031790326609564651
So the wallet used 400 rsETH as still-open collateral, re-bridged 4,600 rsETH, and forwarded the borrowed ETH to the collector.
Branch wallet 0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B split its 30,000 rsETH across two Compound V3 paths and one LayerZero bridge leg:
26,000 rsETHwas supplied to0xa17581a9e3356d9a858b789d68b4d866e593ae94,Compound WETH / cWETHv3- helper
0xa397a8c2086c554b531c02e29f3291c9704b00c7,MainnetBulker, then delivered962.5530590676 ETHin tx0x58a115455f4990e5cd8cfceb7f1ee542532f901c607410ee0c2e15acb76ed457and11,000 ETHin tx0x88b359fb9fede12e388413b86d6a99b6509a7bb98204a3e7c9c4664e5bf9444f - after that path, tx
0x8ab37c2effb3b49426ce3e0b9b011dbbf4cea253f8e16baa0f3437522738cf16withdrew13,573.295902844253 rsETH - a second Compound path through
0x3d0bb1ccab520a66e607822fc55bc921738fafe3,Compound wstETH / cWstETHv3, turned5,000 rsETHinto3,905.849046033 wstETHin tx0x2d61c66e006390fdc2d3ce85eab00805f241edd459e78f1b58492d072bd2368c - another
4,000 rsETHround trip through the same market came back as4,000.499282781425 rsETHin tx0xca575d29415fee70d93e43c21d867972c70be13eccf310188d1b25efd1c26b17 - tx
0x7497fe1116e9200f5b356191f95e571de90e7410649a9641f71213c3abbb6cdbthen re-bridged12,573.795185625677 rsETH - tx
0x256117bc7e4f947766bdc8d8f607bc41adbf8989aa701dbd7c80e0065a424143swapped the3,905.849046033 wstETHinto4,768.586922288308 ETH - tx
0x868e114e1ce7020fdbbd81a055ab15ee80d435a015d74df8a4aad83865c00bcbforwarded16,731.231215477054061404 ETHto the collector
So this branch monetized 17,426.204814374323053164 rsETH on Ethereum and re-bridged 12,573.795185625676946836 rsETH.
Branch wallet 0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cC used Euler swap-style flows, not collateralized borrowing:
- tx
0x61e2ab997de61276cb8738d0bfeddc68feb2fdd318f5150fd856c8cc1125c438sent1 rsETHto0x1924d7fab80d0623f0836cbf5258a7fa734ee9d9,EVK Vault ersETH-4, and received0.9839345718960282 WETH - tx
0xd21b03ceca22fd1d0b29cf5960b57afad20620267a268f54127ea54d75399faasent200 rsETHand received196.7869143791865 WETH - tx
0x052b7def091b9eb28dfe6e3df38fd5c15c6e90f84565cb86cad767f1ec3c9336sent500 rsETHand received11.14506046 WBTC - tx
0x74e00914e0356491b46cba832bfddfbedf65fba6c4efb5cc8cf9c89e28b7ce85re-bridged the remaining9,299 rsETH - tx
0xa54b508d88820d904560ab297bd4c487e861ca101fabe998d2639abcf2b6900dmoved the wallet's11.14506046 WBTCand paid356.71485110198574 ETHback to the wallet - tx
0x8cf41e0db3620d7eadec52c534375978d0cef72ef7c6c1be1215d1ef328ca2d7unwrapped197.7708489510825 WETHinto ETH - txs
0x09b0345be434466a2a2062a79805b901f7953c69370be47767f58f3cb4e56ae3and0xb3b28edc5d13269470384155315017370c45f33109b3cd9b26423a3e3b3608a5then forwarded554.538691726288597630 ETHto the collector
So this branch re-bridged 9,299 rsETH and directly swapped the remaining 701 rsETH into WETH, WBTC, and then ETH.
Branch wallet 0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787 used direct aggregator swaps:
- through
0x6131b5fae19ea4f9d964eac0408e4408b66337b5,MetaAggregationRouterV2, tx0x9d71b08a6c946520675a379710eeff3a723ccb45cc80571e1e0ab4a6bfe7fa01swapped2,500 rsETHinto2,669.137563630672167344 ETH - tx
0xd4dcf23f200dceae6d20bc6dccc6369b2d3ca91247216fceea8a2acdfb372dd3swapped another2,500 rsETHinto2,667.115725996321975440 ETH - tx
0xb052c5c7a082b5a27a376f13fdfd5523b2bb2f462423f28084643c59f24b287dswapped200 rsETHinto212.547124704837143133 ETH - tx
0xad8716d1aafb1c2e98412aa13532fe381bfe9e4241fd46ddbd5dd304bdbb0d7eswapped the final30 rsETHinto31.422214813145152595 ETH - tx
0x46a3d80d6027c5c03098549140cb067f39eb0e806a0aac9858a4aba45b72a045re-bridged the remaining770 rsETH - tx
0x1f879cad6a610f4bef1bbbb993f79235388c5712d04aec6d9c876ce1d0814298then forwarded5,580.289999587844936742 ETHto the collector
So this branch swapped 5,230 rsETH directly into ETH, re-bridged 770 rsETH, and left no exploit-linked rsETH exposure on Ethereum.
Branch wallet 0x1B748B680373a1dD70A2319261328CaB2A6f644C received 8,000 rsETH in tx 0xe8748b75e9156de25b5b5225bf0d274bf31af8a3e7bdc7a14e847b42b00ce3b3, approved in tx 0x16a169d54927b5f087a29a90e030b938cc3348d9d2a0321d3097f8e7804fa3c5, and re-bridged the full 8,000 rsETH in tx 0xdde8945d6f5812ce2d68197e24fc1abcce84b6a37f3e65f4e8adc54d20d5b71f. No compensating Ethereum-side asset receipt is visible afterward.
Branch wallet 0xE9E2f48Bb0018276391AEC240ABB46e8C3CAD181 did the same with its full 4,500 rsETH, from receipt tx 0x684ccb28d1a9fd7db9c21f3bdf92691c124c17858edd45ad37e07bfd7c26cd2f through approval tx 0x49c89d3000e5271d567ff2bac8771c5a52cf554c30e9a769717f2581101656e3 into full re-bridge tx 0xb4572affd2f6c85bb5ca2839dfb6e0832568ac2750ebb312d461fd40537d8a00. Again, no later Ethereum-side asset return is visible.
Collector 0x5d3919F12bCc35c26Eee5F8226A9bee90c257Ccc still has nonce 0.
Its visible exploit-linked inflows are the five branch transfers listed above, totaling 75,700.747423535750706684 ETH. Current balances are:
75,700.758694571480554178 ETH0 rsETH
The small excess over branch inflows appears to be later dust or spam receipts. On Ethereum, the collector has not yet deployed, bridged, or forwarded the extracted ETH.
All six Ethereum re-bridge txs used the same Kelp Ethereum -> Arbitrum pathway:
- source sender
0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 - destination receiver
0x4186bfc76e2e237523cbc30fd220fe055156b41f,RSETH_OFT srcEid = 30101,dstEid = 30110
The six destination deliveries on Arbitrum were:
- tx
0x2f813c536a4f4dae614ab136f4cc18c7efef74794561496c75c685905afa88fd:8,000 rsETHto0x1B748B680373a1dD70A2319261328CaB2A6f644C - tx
0x319cb7ede5d10733d79e87d1e9fea43fc1661a7fdb3256d984da4097a019794a:4,500 rsETHto0xE9E2f48Bb0018276391AEC240ABB46e8C3CAD181 - tx
0x4b2b98d5699d3bc2069b249ef240703f788cb6574f8c1a46daee1df20db85f23:12,573.795185 rsETHto0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B - tx
0xad0c1829b7b4b33ca705a144f8a859d0e127f4aab11a9e4b2467fffbea70e06e:770 rsETHto0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787 - tx
0x12739d9340198de496ea3957830e8758a7bf50a270e2e856939aa77c286f1782:9,299 rsETHto0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cC - tx
0xe7f7178eb1821ed7a1924176a1901cdaed700d169ff33b2d4207c61c8fd7d5dd:4,600 rsETHto0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49
Five of the six wallets then immediately routed the received rsETH into Aave Arbitrum:
- Arbitrum
rsETH:0x4186bfc76e2e237523cbc30fd220fe055156b41f,RSETH_OFT - Arbitrum Aave
aArbrsETH:0x6b030ff3fb9956b1b69f475b77ae0d3cf2cc5afa - Arbitrum Aave
variableDebtArbWETH:0x0c84331e39d6658cd6e6b9ba04736cc4c4734351 - Arbitrum Aave
variableDebtArbwstETH:0x77ca01483f379e58174739308945f044e1a764dc
The straightforward Arbitrum leg was:
- receive Arbitrum
rsETH - supply it into
aArbrsETH - incur
variableDebtArbWETH - transfer token
0x67598ca3035f4ab009908cdf4bf74c884f3203b4, labeledE.๊.H, to Arbitrum collector0x5d3987fa25ca82f672bf6b009eba60f4dd7c7ccc
That pattern is clear for:
0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B: currentaArbrsETH = 12,573.795184999999999999, currentvariableDebtArbWETH = 12,382.607771179497869770, forwarded12,381.958711311528235018 E.๊.H0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787: currentaArbrsETH = 769.999999999999999999, currentvariableDebtArbWETH = 758.292110121124454116, forwarded758.450236028949914503 E.๊.H0x1B748B680373a1dD70A2319261328CaB2A6f644C: currentaArbrsETH = 7,999.999999999999999999, currentvariableDebtArbWETH = 7,878.363213774692497957, forwarded7,877.39 E.๊.Hacross two txs0xE9E2f48Bb0018276391AEC240ABB46e8C3CAD181: currentaArbrsETH = 4,499.999999999999999999, currentvariableDebtArbWETH = 4,431.579011423528444134, forwarded4,431.172 E.๊.Hacross two txs
0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cC used the same base path but then added a second debt leg:
- current
aArbrsETH = 9,299.999999999999999999 - current
variableDebtArbWETH = 4,308.052246442210827272 - current
variableDebtArbwstETH = 8.131122016749303072 - forwarded
4,317.7 E.๊.Hto the Arbitrum collector across two txs
0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49 was the most complex Arbitrum path. It deposited the full 4,600 rsETH, unwound most of it, redeposited, opened both WETH and wstETH debt, and distributed wstETH across several addresses before sending 998.897 E.๊.H to the same collector. Its current state is:
rsETHdust balance:0.000000081905225048- current
aArbrsETH = 1,024.428942918094774949 - current
variableDebtArbWETH = 28.681503371652002426 - current
variableDebtArbwstETH = 813.113978360517124871
Across the six re-bridged branches, the currently open Arbitrum Aave exposure is:
36,168.224127918094774944 aArbrsETH29,787.575856312706095675 variableDebtArbWETH821.245100377266427943 variableDebtArbwstETH
So the re-bridged funds did not leave the attack surface. They were largely turned into a second live leverage cluster on Arbitrum.
The re-bridged value also converged on a second collector:
- Arbitrum collector
0x5d3987fa25ca82f672bf6b009eba60f4dd7c7ccc - visible inbound
E.๊.Hfrom the six re-bridged branches totals30,765.567947340478149521
Unlike the Ethereum collector, this Arbitrum collector is not idle. Its current nonce is 6. Its visible outbound activity so far is six zero-value txs back to the contributing branch EOAs. I do not yet have a clean explanation for that behavior from onchain data alone.
For the exact route
- source peer
0xc3eacf0612346366db554c991d7858716db09f58 - destination peer
0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 srcEid = 30320
the Ethereum endpoint currently reports:
lazyInboundNonce(...) = 308inboundNonce(...) = 309inboundPayloadHash(..., 309) = 0xbf86af6f10782715c263b7c76c86e7a965b29f2a0119806ea4eb108d197e0c7einboundPayloadHash(..., 310..315) = 0x0
So on this exact route, there is one verified-but-undelivered packet still committed on the destination side: nonce 309. There is no evidence of additional committed packets beyond it.
Scanning the LayerZero message history for Ethereum adapter 0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 shows multiple Kelp inbound pathways from distinct source EIDs.
For the observed source EIDs
301063011030165301813018430214302173030330320303353033930390
the Ethereum endpoint receive-library config decodes as follows:
30106:requiredDVNCount = 1,optionalDVNCount = 030110:requiredDVNCount = 1,optionalDVNCount = 030165:requiredDVNCount = 1,optionalDVNCount = 030181:requiredDVNCount = 1,optionalDVNCount = 030184:requiredDVNCount = 1,optionalDVNCount = 030214:requiredDVNCount = 1,optionalDVNCount = 030217:requiredDVNCount = 2,optionalDVNCount = 030303:requiredDVNCount = 1,optionalDVNCount = 030320:requiredDVNCount = 1,optionalDVNCount = 030335:requiredDVNCount = 1,optionalDVNCount = 030339:requiredDVNCount = 1,optionalDVNCount = 030390:requiredDVNCount = 1,optionalDVNCount = 0
So the Unichain 30320 -> 30101 path was not uniquely weak at the config layer. Among the Kelp inbound routes observed on this Ethereum adapter, almost all were also configured as 1-of-1 at the receive layer. The only observed exception in this set was source EID 30217, which required two DVNs.
Current chain state shows that Unichain is still the only route in this set with a true source/destination nonce mismatch. For the other resolved routes, the source outboundNonce matches Ethereum inboundNonce, and only lazyInboundNonce lags where there is ordinary committed backlog. I resolved 11 of the 12 observed source EIDs in this pass.
30106Avalanche: sourceoutboundNonce = 77, destinationlazyInboundNonce = 77,inboundNonce = 77, no verified backlog30110Arbitrum: sourceoutboundNonce = 3245, destinationlazyInboundNonce = 3241,inboundNonce = 3245, verified backlog at3242..324530165zkSync: sourceoutboundNonce = 534, destinationlazyInboundNonce = 534,inboundNonce = 534, no verified backlog30181Mantle: sourceoutboundNonce = 31, destinationlazyInboundNonce = 31,inboundNonce = 31, no verified backlog30184Base: sourceoutboundNonce = 828, destinationlazyInboundNonce = 824,inboundNonce = 828, verified backlog at825..82830214Scroll: sourceoutboundNonce = 1597, destinationlazyInboundNonce = 1597,inboundNonce = 1597, no verified backlog30217Manta: sourceoutboundNonce = 40, destinationlazyInboundNonce = 40,inboundNonce = 40, no verified backlog30303Zircuit: sourceoutboundNonce = 520, destinationlazyInboundNonce = 517,inboundNonce = 520, verified backlog at518..52030320Unichain: sourceoutboundNonce = 307, destinationlazyInboundNonce = 308,inboundNonce = 309, verified backlog at30930335Swell: sourceoutboundNonce = 111, destinationlazyInboundNonce = 111,inboundNonce = 111, no verified backlog30339Ink: sourceoutboundNonce = 94, destinationlazyInboundNonce = 93,inboundNonce = 94, verified backlog at94
That distinction matters. The Arbitrum, Base, Zircuit, and Ink routes currently show committed packets waiting to be lazily advanced or executed, but not unbacked source claims. Unichain remains the only observed route in this Kelp set where the source endpoint itself still reports a lower outbound nonce than Ethereum has already accepted.
I also checked inboundPayloadHash beyond the current backlog window on these resolved routes. I did not find extra committed payload hashes beyond the current inboundNonce.
Live Ethereum blast-radius sample for DVN 0x589dedbd617e0cbcb916a9223f4d1300c294236b
A broader live Ethereum sample shows that 0x589dedbd617e0cbcb916a9223f4d1300c294236b is not Kelp-specific.
- In a sample of the last ~5,000 Ethereum blocks, the endpoint emitted
1,746recent packet-verification events collapsing to258distinct active(receiver, srcEid)routes. - Querying current receive config on the top
40active routes showed35/40with0x589dedbd617e0cbcb916a9223f4d1300c294236binrequiredDVNs. - Most of those were not
1-of-1. The common pattern in the active sample wasrequiredDVNCount = 2, often with0x589dedbd617e0cbcb916a9223f4d1300c294236bplus one other required DVN.
The important point is that 0x589dedbd617e0cbcb916a9223f4d1300c294236b appears widely as a required verifier, but the Kelp route is still unusual in the sample because it is a confirmed nonce-mismatch case on a 1-of-1 path.
The active sample also produced at least one obvious non-Kelp 1-of-1 route:
- River receiver
0xda7ad9dea9397cffddae2f8a052b82f1484252b3on30102 -> 30101, with sole required DVN0x589dedbd617e0cbcb916a9223f4d1300c294236b
Sample nonce-parity checks on other active routes looked normal:
- RaveDAO BSC -> Ethereum: source
outboundNonce = 9346, destinationlazyInboundNonce = 9346,inboundNonce = 9346 - Stargate Base -> Ethereum: source
outboundNonce = 121970, destinationlazyInboundNonce = 121970,inboundNonce = 121970 - River BSC -> Ethereum: source
outboundNonce = 2834, destinationlazyInboundNonce = 2834,inboundNonce = 2834 - Kelp Unichain -> Ethereum remained the outlier: source
outboundNonce = 307, destinationlazyInboundNonce = 308,inboundNonce = 309
This is not a full Ethereum-wide census. It is a recent-activity sample. But it is enough to show two things at once:
0x589dedbd617e0cbcb916a9223f4d1300c294236bis widely used beyond Kelp- in the sampled routes, Kelp is still the only confirmed source/destination nonce anomaly
The Unichain source contract 0xc3eacf0612346366db554c991d7858716db09f58 currently reports:
owner() = [0x9Fc47d6A2F5A1EFd8BaF475E1873c76D9b28dDFD](https://uniscan.xyz/address/0x9Fc47d6A2F5A1EFd8BaF475E1873c76D9b28dDFD)- endpoint delegate for the OApp is also [
0x9Fc47d6A2F5A1EFd8BaF475E1873c76D9b28dDFD](https://uniscan.xyz/address/0x9Fc47d6A2F5A1EFd8BaF475E1873c76D9b28dDFD) - the verified ABI exposes no public
mint(...)function or role-management surface beyond ownership and peer/config controls
Neither the Unichain source contract nor the Ethereum adapter showed a nonzero EIP-1967 implementation slot, so there is no obvious proxy-upgrade layer at those addresses.
More importantly, the exploited-route state is unchanged between the incident window and approximately 90 days earlier:
- on Unichain at block
38,032,441(2026-01-19 00:00:00 UTC),owner(), endpoint delegate, send library fordstEid = 30101, executor config bytes, and DVN config bytes all matched current state exactly - on Ethereum at block
24,265,092(2026-01-19 00:00:11 UTC),owner(), endpoint delegate, receive library forsrcEid = 30320, and DVN config bytes all matched current state exactly - the destination-side
configType = 1call reverted both now and at the historical block, so I cannot use that call to prove a stable executor-config byte string on the receive side
So I do not see evidence that the exploited route was quietly downgraded, peer-swapped, or re-pointed shortly before the incident. The 1-of-1 setup appears to have been longstanding, not a last-minute config change.
The limit here is event-level completeness. I did not finish a full 90-day tx-by-tx event crawl for every possible PeerSet, SetConfig, SetSendLibrary, SetReceiveLibrary, or ownership event. What I can say confidently is narrower but still useful: the live state relevant to the exploited route matches the state from 90 days earlier on both chains, so this does not look like a last-minute route downgrade, and the source token address does not present an obvious public mint hook or proxy-upgrade surface.
2026-04-18 17:33:35 UTC: nonce308isPayloadVerifiedin tx0xfe575668f895e10f8496fca3bb928fa53bebbea3e1de567d61bcd12d935f0d6f2026-04-18 17:35:11 UTC: nonce308is committed in tx0x68eb14e2d0ea9eca0f6277b6e4242c898a08d83a9ffe322dd875e69112e3b5642026-04-18 17:35:35 UTC: nonce308is successfully delivered in tx0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db42222026-04-18 17:37:23 UTCto17:41:59 UTC: the recipient disperses the full116,500 rsETHinto seven pre-funded branch wallets2026-04-18 17:42:23 UTC: the first branch re-bridges funds out throughLZMultiCall2026-04-18 17:44:47 UTC: the first large ETH consolidation reaches collector0x5d3919f12bcc35c26eee5f8226a9bee90c257ccc2026-04-18 18:23:11 UTC: Kelp Safe tx0xa1495d12abdd7369bb92ecfc0cbdbdc2a7f631604f783abc1e985f3e682e25fcfreezes the original recipient2026-04-18 18:25:47 UTC: nonce309isPayloadVerifiedin tx0xa3e663b98704def447350b7960d3824340e5c3bad538da529c3a7d21b48836b72026-04-18 18:26:23 UTC: nonce309is committed in tx0xea851cd85ca45d7ca7012df929e4ef1c602d9a3de5ec93746aa8f24ccafb58aa2026-04-18 18:26:35 UTC: first309execution attempt fails in tx0x8509533aed1c9257242b44447daf4fc5d0c562972f366c98cea92dc531783e532026-04-18 18:28:11 UTC: retry also fails in tx0x48d9b3e8fc30c3780d3345743f5defc84ea57e5214ec9d3c4abd04f90465d792
The cleanest explanation that fits the evidence is:
- The Unichain -> Ethereum Kelp route was secured by a single required DVN.
- A structurally normal-looking packet for nonce
308wasPayloadVerified, committed, and released on Ethereum without a real source-side burn or nonce advance. - A second packet for nonce
309was separatelyPayloadVerifiedand committed only after Kelp had already frozen the original recipient, which is why the execution attempts failed. - The attacker side was pre-staged: the intake wallet and its branch wallets were Tornado-funded ahead of time, and the
116,500 rsETHwas dispersed in minutes into branches that re-bridged funds out or turned them into ETH. - The Unichain
30320 -> 30101route between source peer0xc3eacf0612346366db554c991d7858716db09f58and Ethereum adapter0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3was not uniquely weak. Among the observed inbound Kelp routes into the same Ethereum adapter, almost all were also configured as1-of-1at the receive layer. In a broader active Ethereum sample,0x589dedbd617e0cbcb916a9223f4d1300c294236bappeared widely as a required DVN, but Kelp remained the only confirmed nonce-mismatch case in the sampled routes.
This rules out both of the benign interpretations:
- the
116,500 rsETHwas simply bridged out from real Unichain funds - the destination adapter somehow minted fresh
rsETHon Ethereum
The onchain evidence instead supports a narrower description: real Ethereum-side bridge inventory was released against a claim that does not appear to correspond to any canonical source-side send on Unichain.
The remaining uncertainty is narrower than that. The evidence shows that Ethereum accepted an unbacked-looking packet on a 1-of-1 route, but it does not isolate the exact root cause inside the verification path. Because the sole required DVN is Etherscan-labeled LayerZero : DVN rather than an obviously unrelated third-party verifier, the likely fault domain is narrower than "some weak app-chosen verifier failed." The most important unresolved distinction is whether that LayerZero-associated DVN was compromised, had a verification bug, or trusted a bad upstream input on the Unichain side.

ty ๐