feat: HyperCore spot-balance withdraw leaf for counterfactual deposits - #1503
Draft
droplet-rl wants to merge 1 commit into
Draft
feat: HyperCore spot-balance withdraw leaf for counterfactual deposits#1503droplet-rl wants to merge 1 commit into
droplet-rl wants to merge 1 commit into
Conversation
Adds HyperCoreWithdrawImplementation, a withdraw leaf implementation that recovers funds stranded in a counterfactual deposit address's HyperCore spot balance (Core-side spot Sends never touch an EVM chain, so WithdrawImplementation cannot reach them). It CoreWriter-spotSends the clone's Core balance to the leaf-committed user; params/submitterData mirror WithdrawImplementation so both AdminWithdrawManager paths work unchanged, and the recipient is always the committed user. Includes the recovery script for the live incident (deposit address 0xACDe1Bc4...2cb6, id 1083070, 3,848.240373 USDC): builds the +1-leaf route tree and single-leaf upgrade tree and prints the four-tx sequence (setUpgradeRoot -> factory.deploy -> updateRoot -> directWithdraw). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
First live case of a Core-side stranding: a user spot-Sent 3,848.240373 USDC on HyperCore to their Across v3 counterfactual deposit address
0xACDe1Bc40B4DF760FB388DA503ee6a99794E2cb6(counterfactual_deposit_addressid 1083070, Intercom 215475222911726). A HyperCore internal Send never touches an EVM chain, so no leaf in the creation-time route tree — includingWithdrawImplementation— can reach the funds: the clone's Core account can only be debited by the clone itself, via a CoreWriter action.What this adds
HyperCoreWithdrawImplementation— a withdraw leaf implementation (HyperEVM-only) that CoreWriter-spotSends the clone's HyperCore spot balance to the leaf-committeduser.params/submitterDatamirrorWithdrawImplementation(WithdrawParams(admin, user)/(token, to, amount)), so bothAdminWithdrawManagerpaths (directWithdraw,signedWithdrawToUser) work unchanged. Differences:tokenis the Core token's asset-bridge address (USDC =0x2000…0000),amountis in Core wei units (u64), and the Core recipient is always the committeduser—tois ignored.DeployHyperCoreWithdrawImplementation.s.sol— CREATE2 deploy (salt 0), mirroring the existing withdraw-impl deploy script.RecoverHyperCoreSpotBalance.s.sol— worked recovery for the live incident: rebuilds the 8-leaf route tree (7 creation-time leaf hashes + the new Core-withdraw leaf, sameWithdrawParamsas the existing withdraw leaf), the single-leaf upgrade tree, and prints the 4-tx sequence:beacon.setUpgradeRoot(upgradeRoot)— beacon owner Safe (0xd396Cc…2A7F, 3/5 on chain 999)factory.deploy(salt, initialRoot)— anyone (materializes the proxy at the deposit address)proxy.updateRoot(newRoot, [])— anyonemanager.directWithdraw(…)— directWithdrawer Safe (same Safe)Verification
testRecoveryFlowViaRootUpdate(root update adds the Core leaf to a clone minted without it, then the manager withdraws) and both AWM-path compatibility tests. All pass.factory.predictAddress(salt, initialRoot)== the deposit address; recomputed withdraw leaf == creation materials leaf hash; every DB merkle proof verifies againstinitialRoot.total,hold0) at the address; recipient == creation-pinned refund address == the user's main account.Safety
The new leaf is authorized for this one proxy only (single-leaf upgrade tree), the recipient is pinned in the leaf params to the creation-time refund address, and
submitterDatacannot redirect funds. Worst case of a bad broadcast is a silently-failed Core action (funds stay put) — the script header documents the post-broadcast Core-side verification step.Slack context: https://risklabs.slack.com/archives/C0B8JA20R24/p1784968036530869
🤖 Generated with Claude Code