Skip to content

improve: add shared HyperCore primitives to HyperCoreLib - #1530

Open
droplet-rl wants to merge 6 commits into
masterfrom
droplet/C09JBJ5SLH2-1786995850-655419
Open

improve: add shared HyperCore primitives to HyperCoreLib#1530
droplet-rl wants to merge 6 commits into
masterfrom
droplet/C09JBJ5SLH2-1786995850-655419

Conversation

@droplet-rl

@droplet-rl droplet-rl commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Motivation

Review on contracts-v5#203 (counterfactual HyperCore withdrawals) flagged that CounterfactualHyperCoreWithdrawer hand-rolls a set of HyperCore constants and calls that HyperCoreLib already owns the equivalents of — a second source of truth for precompile addresses and action headers, which is how they drift. Raised by @grasphoper in three separate comments and independently in this one.

This PR upstreams them so the v5 leaf can drop its local copies. Opened separately because the lib sits behind the submodule boundary.

Retargeted at v5#203's rewritten leaf. 187e8d4e removed the rounding logic and 933ddfc6 replaced the perp → spot → EVM two-step with a single sendAsset carrying a sourceDex, which changed what the leaf needs from here. See Changed in the retarget below.

What's added

Purely additive — no existing function or constant changes behavior.

Added Replaces, in v5#203
WITHDRAWABLE_PRECOMPILE_ADDRESS (0x803), struct Withdrawable, withdrawable(address) the hand-rolled staticcall + bare abi.decode(result, (uint64)) in _perpWithdrawable
HYPE_SYSTEM_ADDRESS, HYPE_CORE_INDEX, HYPE_CORE_INDEX_TESTNET, hypeCoreIndex(), isHype(uint32) the local HYPE constants + the testnet/mainnet index ternary in _bridgeTarget
HYPEREVM_CHAIN_ID, HYPEREVM_TESTNET_CHAIN_ID, isHyperEVMChain() the local chain-id pair + inline check in execute (suggested name)
CORE_MAIN_PERP_DEX_ID (0), PERP_USD_TO_USDC_CORE_WEI (100) the leaf's new MAIN_PERP_DEX / PERP_TO_CORE_WEI
toSystemAddress(uint32), error TokenNotBridgeable(uint32) all of the leaf's _bridgeTarget

withdrawable decodes through a named Withdrawable struct rather than a bare uint64 to match how spotBalance / coreUserExists / tokenInfo already read their precompiles. Single-field structs abi-decode identically, so this is wire-compatible with the v5 version.

CORE_MAIN_PERP_DEX_ID sits next to the existing CORE_SPOT_DEX_ID, its counterpart in the same sendAsset selector space. Only the constants are upstreamed, not the leaf's saturating conversion — clamping vs. reverting on a widened reading is caller policy, so it stays at the call site.

Changed in the retarget

  • Dropped transferUsdClass / USD_CLASS_TRANSFER_HEADER. Their only motivating caller was the leaf's _perpToSpot, removed in 933ddfc6 — the perp source now rides transferERC20CoreToCore, which this lib already had. Rather than land an unused CoreWriter action in a library that's heading into audit, it comes back when something needs it. Say the word if you'd rather keep it.

  • Added toSystemAddress, previously in out of scope here. It was held back because it owned the evmContract == address(0) revert, which looked like leaf policy; 187e8d4e dropped the evmExtraWeiDecimals return and left it a plain address resolver, so it now reads as a lib-shaped primitive. It's also the line @grasphoper flagged in this comment.

    The error moves with it. TokenNotBridgeable(uint32) has the same signature in both places, so the selector is unchanged and no off-chain decoding breaks; only the Solidity reference path moves (HyperCoreLib.TokenNotBridgeable rather than the leaf's).

Verification

Constants were read off the live mainnet/testnet tokenInfo precompile (0x…80C) rather than copied from the v5 PR, so a mistake there wouldn't be propagated:

Read Result
tokenInfo(0), mainnet "USDC", weiDecimals = 8, evmExtraWeiDecimals = -2 → confirms PERP_USD_TO_USDC_CORE_WEI = 1e8/1e6 = 100
tokenInfo(150), mainnet "HYPE", evmContract = address(0) → confirms the HYPE branch must precede the bridgeability check
tokenInfo(1105), testnet "HYPE" → confirms HYPE_CORE_INDEX_TESTNET

withdrawable's shape was cross-checked against the vendored hyper-evm-lib reference (PrecompileLib.withdrawable → precompile 0x803, decoded via Withdrawable { uint64 withdrawable; }).

End-to-end against v5#203. Pointed the v5 across-contracts submodule at this branch, rewrote the leaf to use the new helpers, and ran 203's own suite:

FOUNDRY_PROFILE=counterfactual forge build   # Compiler run successful
FOUNDRY_PROFILE=test forge test --match-contract CounterfactualHyperCoreWithdrawer
# 31 passed; 0 failed

The leaf goes 146 → 114 lines (+7 −39): all six local constants, both private helpers (_bridgeTarget, _perpWithdrawable), and one error go away.

This side:

yarn test-evm-foundry -- --match-contract "HyperCore|Hyperliquid|Sponsored|SwapHandler"
# 60 passed; 0 failed (HyperCoreLibTest 17)
yarn lint-solidity  # no new warnings on HyperCoreLib

Heads-up: the submodule bump is blocked independently of this PR

Consuming this in v5 means bumping lib/across-contracts off its current pin (8026a507). That pin is an ancestor of master, but #1520 (db91f503, counterfactual v3 deployments) reshaped ICounterfactualBeacon in between, removing gateway(), stablePrice() and the *DepositExecutor() getters that the v5 counterfactual vertical calls. A straight bump to master fails to compile at CounterfactualPrefunder.sol:63.

Nothing to do with these changes — I verified above by overlaying only HyperCoreLib.sol onto the existing pin — but it's in the way of picking them up, so either cherry-pick this file or reconcile v5 with #1520 first. Flagging rather than guessing which.

Still out of scope

The substantive design questions on v5#203 (HYPE fee reserve, _resolveAmount, full-amount-only withdrawals) belong on that PR.

🤖 Generated with Claude Code

@droplet-rl
droplet-rl force-pushed the droplet/C09JBJ5SLH2-1786995850-655419 branch 2 times, most recently from ffb15b7 to a7d49c6 Compare August 18, 2026 19:54
Comment thread contracts/libraries/HyperCoreLib.sol Outdated
@droplet-rl

Copy link
Copy Markdown
Contributor Author

Addressed the review in 9ade0c5.

The one inline comment: PERP_USD_TO_USDC_CORE_WEI = 100 is gone, replaced by PERP_USD_DECIMALS = 6 and a perpUsdToCoreWei helper that derives the factor from USDC's weiDecimals via convertCoreDecimalsSimple, as suggested. Replied on the thread with the details.

Two deviations worth flagging:

  • Named the parameter amountPerpUsd rather than ntlwithdrawable returns a margin-free balance, not a notional, so the literal name reads less misleadingly. Easy to switch back.
  • Added test coverage the suggestion didn't ask for: one test pinning the live 8-wei-decimal case, one asserting the factor is genuinely derived (equal decimals pass through; fewer wei decimals than perp USD round down rather than revert).

yarn test-evm-foundry --match-contract HyperCoreLibTest — 19 passed, 0 failed. Prettier clean; solhint shows only the pre-existing one-contract-per-file warning on HyperCoreLib.sol.

@droplet-rl

Copy link
Copy Markdown
Contributor Author

🔎 View trace

@tbwebb22 tbwebb22 added the need to audit This PR needs to be audited externally before deploying label Aug 20, 2026
@tbwebb22

Copy link
Copy Markdown
Contributor

@droplet-rl remove these from HyperCoreLib as we no longer need them in CounterfactualHyperCoreWithdrawer:

  • withdrawable()
  • WITHDRAWABLE_PRECOMPILE_ADDRESS
  • struct Withdrawable
  • WithdrawablePrecompileCallFailed
  • perpUsdToCoreWei()
  • PERP_USD_DECIMALS
  • CORE_MAIN_PERP_DEX_ID

@droplet-rl

Copy link
Copy Markdown
Contributor Author

Removed all seven in 4f10326:

  • withdrawable()
  • WITHDRAWABLE_PRECOMPILE_ADDRESS
  • struct Withdrawable
  • WithdrawablePrecompileCallFailed
  • perpUsdToCoreWei()
  • PERP_USD_DECIMALS
  • CORE_MAIN_PERP_DEX_ID

Also dropped their four tests. Grep confirms no remaining references anywhere in contracts/, script/, or the HyperCoreLib test — the only hits left are in the vendored test/evm/foundry/local/external/hyper-evm-lib/, which is third-party and untouched.

Left SEND_ASSET_TO_DEX_HEADER and CORE_SPOT_DEX_ID in place since both predate this PR and weren't on your list — say the word if you want the send-asset-to-dex header gone too, since CORE_MAIN_PERP_DEX_ID was its main perp-side consumer.

Verified: yarn build-evm-foundry compiles all 527 files clean; HyperCoreLibTest 15 passed / 0 failed (was 19, minus the 4 removed); prettier clean.

Net effect on the PR: it's now the HYPE/chain/system-address primitives only — isHyperEVMChain, hypeCoreIndex, isHype, toSystemAddress, and their constants.

@droplet-rl

Copy link
Copy Markdown
Contributor Author

🔎 View trace

droplet-rl and others added 4 commits August 21, 2026 11:58
CounterfactualHyperCoreWithdrawer (contracts-v5#203) hand-rolled a set of
HyperCore constants and calls that HyperCoreLib already owns the equivalents
of. Review on that PR asked for them to be upstreamed rather than kept as a
second source of truth. Adds, with no change to existing behavior:

- WITHDRAWABLE_PRECOMPILE_ADDRESS (0x803) and withdrawable(), decoded through
  a named Withdrawable struct to match spotBalance/coreUserExists
- USD_CLASS_TRANSFER_HEADER and transferUsdClass(), replacing a direct
  ICoreWriter.sendRawAction at the call site
- HYPE_SYSTEM_ADDRESS, HYPE_CORE_INDEX, HYPE_CORE_INDEX_TESTNET, plus
  hypeCoreIndex()/isHype() for the chain-dependent index selection
- HYPEREVM_CHAIN_ID, HYPEREVM_TESTNET_CHAIN_ID and isHyperEVMChain()

Encodings verified against the vendored hyper-evm-lib reference
(PrecompileLib.withdrawable, CoreWriterLib.transferUsdClass, HLConstants).

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: droplet-rl <284132418+droplet-rl@users.noreply.github.com>
…rawal

contracts-v5#203 dropped its perp -> spot -> EVM two-step for a single
`sendAsset` carrying a `sourceDex`, so the shape of what the leaf needs
from this library changed.

- Drop `transferUsdClass` / `USD_CLASS_TRANSFER_HEADER`. Their only
  motivating caller was the leaf's `_perpToSpot`, removed in 933ddfc6;
  `transferERC20CoreToCore` already covers the new path.
- Add `CORE_MAIN_PERP_DEX_ID` and `PERP_USD_TO_USDC_CORE_WEI`, the two
  constants the rewritten leaf now keeps locally. USDC's Core
  `weiDecimals` is 8 against perp's 1e6, so the ratio is 100 (read off
  the mainnet `tokenInfo` precompile, not assumed).
- Add `toSystemAddress`, the remaining duplicated branch of the leaf's
  `_bridgeTarget`. Held back last time because it owned a revert; the
  rounding removal in 187e8d4e left it a plain address resolver, and it
  was flagged twice in review.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: droplet-rl <284132418+droplet-rl@users.noreply.github.com>
Replace the hardcoded PERP_USD_TO_USDC_CORE_WEI = 100 factor with a
PERP_USD_DECIMALS constant and a perpUsdToCoreWei helper that reads
USDC's weiDecimals off tokenInfo, so the conversion tracks the token's
actual on-chain config instead of baking in today's 1e6 -> 1e8 gap.

Co-Authored-By: Claude <noreply@anthropic.com>
CounterfactualHyperCoreWithdrawer no longer needs these, so remove them
rather than ship dead surface area: withdrawable(), the Withdrawable
struct, WITHDRAWABLE_PRECOMPILE_ADDRESS, WithdrawablePrecompileCallFailed,
perpUsdToCoreWei(), PERP_USD_DECIMALS, and CORE_MAIN_PERP_DEX_ID, plus
their tests.

Co-Authored-By: Claude <noreply@anthropic.com>
@tbwebb22
tbwebb22 force-pushed the droplet/C09JBJ5SLH2-1786995850-655419 branch from 4f10326 to db554d3 Compare August 21, 2026 18:02
grasphoper and others added 2 commits August 21, 2026 13:32
Fold toAssetBridgeAddress into toSystemAddress (now uint64) so every
sender resolves through the HYPE-aware, linkage-checked path:
isCoreAmountSafeToBridge previously read the derived 0x2000... address
for HYPE instead of 0x2222...2222, and the ERC20 EVM -> Core paths
stranded funds at inert addresses for unlinked indices instead of
reverting TokenNotBridgeable.

Add transferNativeEVMToSelfOnSpot, the native-HYPE sibling of
transferERC20EVMToSelfOnSpot, for callers hand-rolling raw sends to
HYPE_SYSTEM_ADDRESS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Ihor Farion <ihor@umaproject.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

need to audit This PR needs to be audited externally before deploying

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants