# kelp-rseth-unichain-path-investigation-2026-04-19.md Source: https://gist.github.com/banteg/705d0284513b74ad20f61d90f5b5de62 ## Summary The 116,500 rsETH released on Ethereum came from real pre-funded adapter inventory but does not appear backed by any legitimate source-side debit on Unichain, and the evidence is most consistent with a single-DVN verification failure or equivalent verification-path compromise. The Kelp route is configured 1-of-1 with no optional DVNs, and the Ethereum adapter fell from 116,723.5206355 rsETH one block before the exploit to 223.5206355 rsETH immediately after. Ethereum accepted inbound nonce 308, yet the Unichain source endpoint still reports outbound nonce 307, and the recipient dispersed the full amount within about five minutes of being freshly Tornado-funded. ## Article Kelp rsETH Unichain -> Ethereum Path Investigation Date: 2026-04-19 Scope 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. Executive Summary 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-1 DVN path with no optional DVNs. The Ethereum adapter held 116,723.5206355 rsETH one block before the exploit and only 223.5206355 rsETH immediately after, so the exploit drained existing inventory rather than minting new rsETH on Ethereum. Nonce 308 was PayloadVerified at 2026-04-18 17:33:35 UTC, committed at 17:35:11 UTC, and successfully delivered at 17:35:35 UTC. Ethereum accepted inbound nonce 308, but the matching Unichain source endpoint still reports outbound nonce 307. The Unichain rsETH source 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 309 reverted with TransfersBlocked(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 rsETH into 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. Entities Unichain source rsETH token / OFT: 0xc3eacf0612346366db554c991d7858716db09f58 Unichain LayerZero endpoint: 0x6F475642a6e85809B1c36Fa62763669b1b48DD5B Unichain -> Ethereum send library: 0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7 Source required DVN on Unichain side: 0x282b3386571f7f794450d5789911a9804fa346b4 Ethereum LayerZero endpoint: 0x1a44076050125825900e736c501f859c50fE728c Ethereum Kelp rsETH OFT 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 Finding 1: The route is single-DVN Onchain config reads for the exact Kelp path show one required DVN and zero optional DVNs on both sides. Source side getSendLibrary(oapp=0xc3eacf0612346366db554c991d7858716db09f58, dstEid=30101) returned 0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7 getConfig(oapp=0xc3eacf0612346366db554c991d7858716db09f58, lib=0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7, eid=30101, configType=2) returned data that decodes to: confirmations = 42 requiredDVNCount = 1 optionalDVNCount = 0 optionalDVNThreshold = 0 requiredDVNs = [[0x282b3386571f7f794450d5789911a9804fa346b4](https://uniscan.xyz/address/0x282b3386571f7f794450d5789911a9804fa346b4)] optionalDVNs = [] Destination side getReceiveLibrary(oapp=0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3, srcEid=30320) returned 0xc02Ab410f0734EFa3F14628780e6e695156024C2 getConfig(oapp=0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3, lib=0xc02Ab410f0734EFa3F14628780e6e695156024C2, eid=30320, configType=2) returned data that decodes to: confirmations = 42 requiredDVNCount = 1 optionalDVNCount = 0 optionalDVNThreshold = 0 requiredDVNs = [[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. Verification and execution were distinct steps For nonce 308, the verification chain on Ethereum was: PayloadVerified on receive library 0xc02Ab410f0734EFa3F14628780e6e695156024C2 in tx 0xfe575668f895e10f8496fca3bb928fa53bebbea3e1de567d61bcd12d935f0d6f at 2026-04-18 17:33:35 UTC commitVerification(bytes,bytes32) on the same receive library in tx 0x68eb14e2d0ea9eca0f6277b6e4242c898a08d83a9ffe322dd875e69112e3b564 at 2026-04-18 17:35:11 UTC lzReceive(...) on the endpoint in tx 0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db4222 at 2026-04-18 17:35:35 UTC For nonce 309, the chain was separate and later: PayloadVerified in tx 0xa3e663b98704def447350b7960d3824340e5c3bad538da529c3a7d21b48836b7 at 2026-04-18 18:25:47 UTC commitVerification(bytes,bytes32) in tx 0xea851cd85ca45d7ca7012df929e4ef1c602d9a3de5ec93746aa8f24ccafb58aa at 2026-04-18 18:26:23 UTC failed lzReceive(...) in tx 0x8509533aed1c9257242b44447daf4fc5d0c562972f366c98cea92dc531783e53 at 2026-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 PayloadVerified tx for 308 was sent to the DVN contract by 0xD95D7761A585bBc1B59B4B6F441B9eDc2878DAdE the PayloadVerified tx for 309 was sent by 0xD3A227725c3EAe3681eB2817ef6C09200ba46a3f the commitVerification and lzReceive txs for both packets were sent by the gas-paying executor EOA 0x4966260619701a80637cDbdAc6A6cE0131f8575E 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). Configured executor vs. actual executor behavior On the Unichain source side, getConfig(..., configType=1) for send lib 0xC39161c743D0307EB9BCc9FEF03eeb9Dc4802de7 returned executor config bytes that decode as: maxMessageSize = 99 executor = [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 ETH from TornadoCash contract 0x47ce0c6ed5b0ce3d3a51fdb1c52dc66a7c3c2936 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. The DVN signer committee was stable 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() = 2 signerSize() = 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: 0xD3A227725c3EAe3681eB2817ef6C09200ba46a3f was granted ADMIN_ROLE in tx 0xa32b5521922d2e282363d22243d24f5b6f4a7e910b147395dd1021a530924d08 on 2025-02-06 11:50:23 UTC 0xD95D7761A585bBc1B59B4B6F441B9eDc2878DAdE was granted ADMIN_ROLE in tx 0xd45f564859e3e640b92f77ce43f0cd2b4eed8c0d429b66dc2b9225bb23dfdcae on 2025-02-06 11:51:35 UTC there was a broader admin expansion on 2026-04-08, when ten new grantRole(ADMIN_ROLE, ...) txs were sent from 0xB8FF877ed78Ba520Ece21B1de7843A8a57cA47Cb 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. Finding 2: Nonce 308 was accepted on Ethereum, but the source endpoint never advanced past 307 Ethereum-side delivery Tx: 0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db4222 It is a LayerZero EndpointV2 lzReceive call carrying: srcEid = 30320 (Unichain) sender = [0xc3eacf0612346366db554c991d7858716db09f58](https://uniscan.xyz/address/0xc3eacf0612346366db554c991d7858716db09f58) nonce = 308 receiver = [0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3](https://etherscan.io/address/0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3) guid = 0x3f4510d855cf3a805fec59daafae640d290749b7bf1e5450f91b5fb0018b3b4e The payload delivered 116,500 rsETH to: 0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b Endpoint nonce mismatch 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 / GUID 0x3f4510d855cf3a805fec59daafae640d290749b7bf1e5450f91b5fb0018b3b4e 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. Finding 3: No source-side debit exists for the 116,500 rsETH release The Unichain source contract is the token itself: name() = "KelpDao Restaked ETH" symbol() = "rsETH" token() = [0xc3eacf0612346366db554c991d7858716db09f58](https://uniscan.xyz/address/0xc3eacf0612346366db554c991d7858716db09f58) decimals() = 18 sharedDecimals() = 6 Control case: a normal send on the same path burns on Unichain 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. Supply check Unichain source totalSupply() remained unchanged at: block 45,785,275: 49.259532 rsETH block 45,785,276 (LayerZero Scan creation time for nonce 308): 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. Source token event check Using eth_getLogs against the Unichain RPC for the source token 0xc3eacf0612346366db554c991d7858716db09f58 over the message window around nonce 308: no Transfer logs 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 116,500 rsETH came from existing Ethereum-side inventory 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. Packet structure comparison: 307, 308, and 309 look structurally normal 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 0x222e68aa6658a8067585f19ecca5440feaa8bb00 plus amountSD = 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 0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b plus amountSD empty extraData Decoded payloads: 308: recipient 0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b, amountSD = 116,500,000,000 309: recipient 0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b, 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. Finding 4: A second packet (nonce 309) was also verified 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. Amount in nonce 309 The failed executor lzReceive retries for nonce 309 encode amountSD = 40,000,000,000. With sharedDecimals = 6, this corresponds to: 40,000 rsETH Finding 5: Nonce 309 was verified, but execution was blocked on the recipient side Failed Ethereum executor txs: 0x8509533aed1c9257242b44447daf4fc5d0c562972f366c98cea92dc531783e53 0x48d9b3e8fc30c3780d3345743f5defc84ea57e5214ec9d3c4abd04f90465d792 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 transfer block was set deliberately on Ethereum The Ethereum canonical rsETH token at 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7 contains: mapping(address => uint256) public transfersBlockedUntil error 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 to sweep(address[],address) emitted UserTransfersBlocked(0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b, 2026-04-19 18:23:11 UTC) on the rsETH token 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. The recipient was a freshly funded exploit intake wallet Recipient 0x8b1b6c9a6db1304000412dd21ae6a70a82d60d3b does not look like a normal operational wallet or a reused Kelp address. Its first visible funding came from internal tx 0xcb2ee450d6e770216dc3061750b4ac5b5fa494666bcf7eaa936411733e2ef7ee at 2026-04-18 11:05:35 UTC that funding source was 0x12d66f87a04a9e220743712ce6d9bb1b5616b8fc, the verified TornadoCash_Eth_01 contract 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 rsETH to 0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeF in tx 0xe381248517921e5a576fd915e6c7b93f7ab10f3d323ea89730b28fe91d84e70a at 17:37:23 UTC 30,000 rsETH to 0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B in tx 0x95fa2f737aa3f22c182dc86898ac63853ce3c6ddc802ced97a635eb8474d19ed at 17:37:59 UTC 10,000 rsETH to 0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cC in tx 0x2acb453e79dd29844ecbd268ea70ba61c6e309767660e326c035f5121a8156bd at 17:39:23 UTC 6,000 rsETH to 0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787 in tx 0xc86fbb4c275eaa36b9ae3d6202c31c6a7609c428691cd4c039737ce2811e8d26 at 17:39:47 UTC 5,000 rsETH to 0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49 in tx 0x373dfc8aa9c4e4fd365a24bdf36cfb23f1770086d2568b85dcfd05467c890f23 at 17:40:35 UTC 8,000 rsETH to 0x1B748B680373a1dD70A2319261328CaB2A6f644C in tx 0xe8748b75e9156de25b5b5225bf0d274bf31af8a3e7bdc7a14e847b42b00ce3b3 at 17:41:11 UTC 4,500 rsETH to 0xE9E2f48Bb0018276391AEC240ABB46e8C3CAD181 in tx 0x684ccb28d1a9fd7db9c21f3bdf92691c124c17858edd45ad37e07bfd7c26cd2f at 17: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 rsETH remained on Ethereum as open Aave collateral across two wallets 39,742.795185625676946836 rsETH was re-bridged onward through verified LZMultiCall 23,357.204814374323053164 rsETH was monetized on Ethereum into ETH, WBTC, and wstETH before 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 ETH from 0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeF in tx 0xe21c3603917d55641267b12b9a4539e6fa48f2b5b40f7afb50c0e6d46ce4d7f6 16,731.231215477054061404 ETH from 0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B in tx 0x868e114e1ce7020fdbbd81a055ab15ee80d435a015d74df8a4aad83865c00bcb 5,580.289999587844936742 ETH from 0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787 in tx 0x1f879cad6a610f4bef1bbbb993f79235388c5712d04aec6d9c876ce1d0814298 554.538691726288597630 ETH from 0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cC across txs 0x09b0345be434466a2a2062a79805b901f7953c69370be47767f58f3cb4e56ae3 and 0xb3b28edc5d13269470384155315017370c45f33109b3cd9b26423a3e3b3608a5 394.011405392598156589 ETH from 0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49 in tx 0x39c062498d6e9ffe09d308f3951d3c3abeb3d5faff878e8f73799921317271e1 The visible pattern is therefore a purpose-built exploit cluster, not a reused operational wallet. One branch used Aave V3 to turn rsETH into ETH and left the position open 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: unlimited rsETH approval to Aave pool 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2 in tx 0x3ce9e67830fba7ce2b6d50d3c27e2627ae9186cb545b7e69e4756e9fe1856bee 2026-04-18 17:38:47 UTC: Aave multicall(bytes[]) in tx 0x9a7df4837aa8ca1e22f3f40ffee2fa583e9f0e1e31c970c4d34070e01038057d, setting eMode = 3 and supplying 1 rsETH 2026-04-18 17:39:47 UTC: approveDelegation(address,uint256) on the WETH variable debt token 0xeA51d7853EEFb32b6ee06b1C12E6dcCA88Be0fFE in tx 0x376711142668e3b92c3430651beb5aea362b045a08f0227c5add407e9cda5dcc further rsETH supplies to Aave pool: 5,000 rsETH in tx 0x3fa3e894a788568190b0da0f1869320b34a02034419615449daad004b24082d0 at 2026-04-18 17:40:47 UTC 20,000 rsETH in tx 0xc73c9e7e41c41f9bc7d8b42456490af723b761ef22c6a196c7a674a3f4bb7e0e at 2026-04-18 17:41:59 UTC 27,999 rsETH in tx 0xc295f4cd51fdd7d76f64cb7993aba0630769c032190a70835666516825840fc6 at 2026-04-18 17:43:11 UTC Against that collateral, the same wallet borrowed ETH through gateway 0xd01607c3C5eCABa394D8be377a08590149325722 in four draws: tx 0xdac71a69422da4436307ac962e5067c4838ac63da75379b2ee896f9a9f1bd0b5 at 2026-04-18 17:40:11 UTC: 0.984790260181950369 ETH tx 0xbcbc76d167152f63561be5ffb9c6f72a840f20a01c8f94979ba484e226263b3f at 2026-04-18 17:41:23 UTC: 4,923.961148776689335700 ETH tx 0x2d464e2df042de474ec17ae48b03ba623295215668670911f1783e33acd263fb at 2026-04-18 17:42:35 UTC: 19,745.044657455187431632 ETH tx 0x5e2d5c6c8edd7eac05fca9481127863650cab33ead79edcf6be0d2239002868f at 2026-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 rsETH aToken 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. A second branch repeated the Aave pattern at smaller size 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 rsETH in tx 0x2cac9ca15f4167b324c7ed09a068be3d7694296d8e68498eae6d3d242769a071 supplied 400 rsETH into Aave V3 via multicall(bytes[]) in tx 0x78a1edff5f7d21ccc9414bdc3e1aeb0efbffbbc7ed22ad2a79717793b90d892d at 2026-04-18 17:50:23 UTC, again setting eMode = 3 approved WETH debt delegation in txs 0x56432b1bcbbaf7469a00a46444a391b4eb5e27f700df6ccbcb8fb06ea0ded8d2 and 0x912f8d661f2ee5532c7036e398cc844cdb76742a632c863cb91c8be4eaeb883c borrowed 393.916104072779977528 ETH through gateway 0xd01607c3C5eCABa394D8be377a08590149325722 in tx 0x96825137f27847f607a5c4011d99d53f6b26ab58aae6e175f81474bdec6959b5 re-bridged the remaining 4,600 rsETH in tx 0x5006bf68c52eac43da4138d834f7df9db6f6948d63e403c7005f17817b84c68e sent 394.011405392598156589 ETH to collector 0x5d3919f12bcc35c26eee5f8226a9bee90c257ccc in tx 0x39c062498d6e9ffe09d308f3951d3c3abeb3d5faff878e8f73799921317271e1 This position also remains open. Current Aave reads show: eMode = 3 current rsETH aToken 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. Three non-Aave branches monetized the stolen rsETH directly on Ethereum Branch wallet 0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B split its 30,000 rsETH across two Compound V3 paths and one LayerZero bridge leg: 26,000 rsETH was supplied to 0xa17581a9e3356d9a858b789d68b4d866e593ae94, Compound WETH / cWETHv3 helper 0xa397a8c2086c554b531c02e29f3291c9704b00c7, MainnetBulker, then delivered 962.5530590676 ETH in tx 0x58a115455f4990e5cd8cfceb7f1ee542532f901c607410ee0c2e15acb76ed457 and 11,000 ETH in tx 0x88b359fb9fede12e388413b86d6a99b6509a7bb98204a3e7c9c4664e5bf9444f after that path, tx 0x8ab37c2effb3b49426ce3e0b9b011dbbf4cea253f8e16baa0f3437522738cf16 withdrew 13,573.295902844253 rsETH a second Compound path through 0x3d0bb1ccab520a66e607822fc55bc921738fafe3, Compound wstETH / cWstETHv3, turned 5,000 rsETH into 3,905.849046033 wstETH in tx 0x2d61c66e006390fdc2d3ce85eab00805f241edd459e78f1b58492d072bd2368c another 4,000 rsETH round trip through the same market came back as 4,000.499282781425 rsETH in tx 0xca575d29415fee70d93e43c21d867972c70be13eccf310188d1b25efd1c26b17 tx 0x7497fe1116e9200f5b356191f95e571de90e7410649a9641f71213c3abbb6cdb then re-bridged 12,573.795185625677 rsETH tx 0x256117bc7e4f947766bdc8d8f607bc41adbf8989aa701dbd7c80e0065a424143 swapped the 3,905.849046033 wstETH into 4,768.586922288308 ETH tx 0x868e114e1ce7020fdbbd81a055ab15ee80d435a015d74df8a4aad83865c00bcb forwarded 16,731.231215477054061404 ETH to 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 0x61e2ab997de61276cb8738d0bfeddc68feb2fdd318f5150fd856c8cc1125c438 sent 1 rsETH to 0x1924d7fab80d0623f0836cbf5258a7fa734ee9d9, EVK Vault ersETH-4, and received 0.9839345718960282 WETH tx 0xd21b03ceca22fd1d0b29cf5960b57afad20620267a268f54127ea54d75399faa sent 200 rsETH and received 196.7869143791865 WETH tx 0x052b7def091b9eb28dfe6e3df38fd5c15c6e90f84565cb86cad767f1ec3c9336 sent 500 rsETH and received 11.14506046 WBTC tx 0x74e00914e0356491b46cba832bfddfbedf65fba6c4efb5cc8cf9c89e28b7ce85 re-bridged the remaining 9,299 rsETH tx 0xa54b508d88820d904560ab297bd4c487e861ca101fabe998d2639abcf2b6900d moved the wallet's 11.14506046 WBTC and paid 356.71485110198574 ETH back to the wallet tx 0x8cf41e0db3620d7eadec52c534375978d0cef72ef7c6c1be1215d1ef328ca2d7 unwrapped 197.7708489510825 WETH into ETH txs 0x09b0345be434466a2a2062a79805b901f7953c69370be47767f58f3cb4e56ae3 and 0xb3b28edc5d13269470384155315017370c45f33109b3cd9b26423a3e3b3608a5 then forwarded 554.538691726288597630 ETH to 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, tx 0x9d71b08a6c946520675a379710eeff3a723ccb45cc80571e1e0ab4a6bfe7fa01 swapped 2,500 rsETH into 2,669.137563630672167344 ETH tx 0xd4dcf23f200dceae6d20bc6dccc6369b2d3ca91247216fceea8a2acdfb372dd3 swapped another 2,500 rsETH into 2,667.115725996321975440 ETH tx 0xb052c5c7a082b5a27a376f13fdfd5523b2bb2f462423f28084643c59f24b287d swapped 200 rsETH into 212.547124704837143133 ETH tx 0xad8716d1aafb1c2e98412aa13532fe381bfe9e4241fd46ddbd5dd304bdbb0d7e swapped the final 30 rsETH into 31.422214813145152595 ETH tx 0x46a3d80d6027c5c03098549140cb067f39eb0e806a0aac9858a4aba45b72a045 re-bridged the remaining 770 rsETH tx 0x1f879cad6a610f4bef1bbbb993f79235388c5712d04aec6d9c876ce1d0814298 then forwarded 5,580.289999587844936742 ETH to 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. Two branches simply re-bridged their full allocations 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. The collector has not moved the extracted ETH on Ethereum 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 ETH 0 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. The re-bridged funds landed on Arbitrum and mostly became a second Aave extraction leg 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 rsETH to 0x1B748B680373a1dD70A2319261328CaB2A6f644C tx 0x319cb7ede5d10733d79e87d1e9fea43fc1661a7fdb3256d984da4097a019794a: 4,500 rsETH to 0xE9E2f48Bb0018276391AEC240ABB46e8C3CAD181 tx 0x4b2b98d5699d3bc2069b249ef240703f788cb6574f8c1a46daee1df20db85f23: 12,573.795185 rsETH to 0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B tx 0xad0c1829b7b4b33ca705a144f8a859d0e127f4aab11a9e4b2467fffbea70e06e: 770 rsETH to 0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787 tx 0x12739d9340198de496ea3957830e8758a7bf50a270e2e856939aa77c286f1782: 9,299 rsETH to 0xCBB24a6B4dAfaaA1A759a2F413Ea0eb6aE1455cC tx 0xe7f7178eb1821ed7a1924176a1901cdaed700d169ff33b2d4207c61c8fd7d5dd: 4,600 rsETH to 0x8D11Aeac74267DD5C56d371Bf4AE1aFa174c2D49 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, labeled E.ꓔ.H, to Arbitrum collector 0x5d3987fa25ca82f672bf6b009eba60f4dd7c7ccc That pattern is clear for: 0xEBA786c9517A4823A5CfD9c72E4E80Bf8168129B: current aArbrsETH = 12,573.795184999999999999, current variableDebtArbWETH = 12,382.607771179497869770, forwarded 12,381.958711311528235018 E.ꓔ.H 0xBB6A6006eb71205E977eCEB19FcaD1c8D631C787: current aArbrsETH = 769.999999999999999999, current variableDebtArbWETH = 758.292110121124454116, forwarded 758.450236028949914503 E.ꓔ.H 0x1B748B680373a1dD70A2319261328CaB2A6f644C: current aArbrsETH = 7,999.999999999999999999, current variableDebtArbWETH = 7,878.363213774692497957, forwarded 7,877.39 E.ꓔ.H across two txs 0xE9E2f48Bb0018276391AEC240ABB46e8C3CAD181: current aArbrsETH = 4,499.999999999999999999, current variableDebtArbWETH = 4,431.579011423528444134, forwarded 4,431.172 E.ꓔ.H across 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.ꓔ.H to 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: rsETH dust 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 aArbrsETH 29,787.575856312706095675 variableDebtArbWETH 821.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.ꓔ.H from the six re-bridged branches totals 30,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. Finding 6: Only one more verified packet is currently sitting on the exact route For the exact route source peer 0xc3eacf0612346366db554c991d7858716db09f58 destination peer 0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 srcEid = 30320 the Ethereum endpoint currently reports: lazyInboundNonce(...) = 308 inboundNonce(...) = 309 inboundPayloadHash(..., 309) = 0xbf86af6f10782715c263b7c76c86e7a965b29f2a0119806ea4eb108d197e0c7e inboundPayloadHash(..., 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. Finding 7: This was not the only 1-of-1 Kelp inbound route into the Ethereum adapter Scanning the LayerZero message history for Ethereum adapter 0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 shows multiple Kelp inbound pathways from distinct source EIDs. For the observed source EIDs 30106 30110 30165 30181 30184 30214 30217 30303 30320 30335 30339 30390 the Ethereum endpoint receive-library config decodes as follows: 30106: requiredDVNCount = 1, optionalDVNCount = 0 30110: requiredDVNCount = 1, optionalDVNCount = 0 30165: requiredDVNCount = 1, optionalDVNCount = 0 30181: requiredDVNCount = 1, optionalDVNCount = 0 30184: requiredDVNCount = 1, optionalDVNCount = 0 30214: requiredDVNCount = 1, optionalDVNCount = 0 30217: requiredDVNCount = 2, optionalDVNCount = 0 30303: requiredDVNCount = 1, optionalDVNCount = 0 30320: requiredDVNCount = 1, optionalDVNCount = 0 30335: requiredDVNCount = 1, optionalDVNCount = 0 30339: requiredDVNCount = 1, optionalDVNCount = 0 30390: 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 nonce-parity check across other observed Kelp routes 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. 30106 Avalanche: source outboundNonce = 77, destination lazyInboundNonce = 77, inboundNonce = 77, no verified backlog 30110 Arbitrum: source outboundNonce = 3245, destination lazyInboundNonce = 3241, inboundNonce = 3245, verified backlog at 3242..3245 30165 zkSync: source outboundNonce = 534, destination lazyInboundNonce = 534, inboundNonce = 534, no verified backlog 30181 Mantle: source outboundNonce = 31, destination lazyInboundNonce = 31, inboundNonce = 31, no verified backlog 30184 Base: source outboundNonce = 828, destination lazyInboundNonce = 824, inboundNonce = 828, verified backlog at 825..828 30214 Scroll: source outboundNonce = 1597, destination lazyInboundNonce = 1597, inboundNonce = 1597, no verified backlog 30217 Manta: source outboundNonce = 40, destination lazyInboundNonce = 40, inboundNonce = 40, no verified backlog 30303 Zircuit: source outboundNonce = 520, destination lazyInboundNonce = 517, inboundNonce = 520, verified backlog at 518..520 30320 Unichain: source outboundNonce = 307, destination lazyInboundNonce = 308, inboundNonce = 309, verified backlog at 309 30335 Swell: source outboundNonce = 111, destination lazyInboundNonce = 111, inboundNonce = 111, no verified backlog 30339 Ink: source outboundNonce = 94, destination lazyInboundNonce = 93, inboundNonce = 94, verified backlog at 94 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,746 recent packet-verification events collapsing to 258 distinct active (receiver, srcEid) routes. Querying current receive config on the top 40 active routes showed 35/40 with 0x589dedbd617e0cbcb916a9223f4d1300c294236b in requiredDVNs. Most of those were not 1-of-1. The common pattern in the active sample was requiredDVNCount = 2, often with 0x589dedbd617e0cbcb916a9223f4d1300c294236b plus 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 0xda7ad9dea9397cffddae2f8a052b82f1484252b3 on 30102 -> 30101, with sole required DVN 0x589dedbd617e0cbcb916a9223f4d1300c294236b Sample nonce-parity checks on other active routes looked normal: RaveDAO BSC -> Ethereum: source outboundNonce = 9346, destination lazyInboundNonce = 9346, inboundNonce = 9346 Stargate Base -> Ethereum: source outboundNonce = 121970, destination lazyInboundNonce = 121970, inboundNonce = 121970 River BSC -> Ethereum: source outboundNonce = 2834, destination lazyInboundNonce = 2834, inboundNonce = 2834 Kelp Unichain -> Ethereum remained the outlier: source outboundNonce = 307, destination lazyInboundNonce = 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: 0x589dedbd617e0cbcb916a9223f4d1300c294236b is widely used beyond Kelp in the sampled routes, Kelp is still the only confirmed source/destination nonce anomaly Finding 8: Route ownership, delegate, and library state look stable across the last 90 days 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 for dstEid = 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 for srcEid = 30320, and DVN config bytes all matched current state exactly the destination-side configType = 1 call 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. Timeline 2026-04-18 17:33:35 UTC: nonce 308 is PayloadVerified in tx 0xfe575668f895e10f8496fca3bb928fa53bebbea3e1de567d61bcd12d935f0d6f 2026-04-18 17:35:11 UTC: nonce 308 is committed in tx 0x68eb14e2d0ea9eca0f6277b6e4242c898a08d83a9ffe322dd875e69112e3b564 2026-04-18 17:35:35 UTC: nonce 308 is successfully delivered in tx 0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db4222 2026-04-18 17:37:23 UTC to 17:41:59 UTC: the recipient disperses the full 116,500 rsETH into seven pre-funded branch wallets 2026-04-18 17:42:23 UTC: the first branch re-bridges funds out through LZMultiCall 2026-04-18 17:44:47 UTC: the first large ETH consolidation reaches collector 0x5d3919f12bcc35c26eee5f8226a9bee90c257ccc 2026-04-18 18:23:11 UTC: Kelp Safe tx 0xa1495d12abdd7369bb92ecfc0cbdbdc2a7f631604f783abc1e985f3e682e25fc freezes the original recipient 2026-04-18 18:25:47 UTC: nonce 309 is PayloadVerified in tx 0xa3e663b98704def447350b7960d3824340e5c3bad538da529c3a7d21b48836b7 2026-04-18 18:26:23 UTC: nonce 309 is committed in tx 0xea851cd85ca45d7ca7012df929e4ef1c602d9a3de5ec93746aa8f24ccafb58aa 2026-04-18 18:26:35 UTC: first 309 execution attempt fails in tx 0x8509533aed1c9257242b44447daf4fc5d0c562972f366c98cea92dc531783e53 2026-04-18 18:28:11 UTC: retry also fails in tx 0x48d9b3e8fc30c3780d3345743f5defc84ea57e5214ec9d3c4abd04f90465d792 Interpretation 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 308 was PayloadVerified, committed, and released on Ethereum without a real source-side burn or nonce advance. A second packet for nonce 309 was separately PayloadVerified and 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 rsETH was dispersed in minutes into branches that re-bridged funds out or turned them into ETH. The Unichain 30320 -> 30101 route between source peer 0xc3eacf0612346366db554c991d7858716db09f58 and Ethereum adapter 0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3 was not uniquely weak. Among the observed inbound Kelp routes into the same Ethereum adapter, almost all were also configured as 1-of-1 at the receive layer. In a broader active Ethereum sample, 0x589dedbd617e0cbcb916a9223f4d1300c294236b appeared 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 rsETH was simply bridged out from real Unichain funds the destination adapter somehow minted fresh rsETH on 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.