fix: request EXACT_OUTPUT for HyperCore perps deposits so the full margin arrives - #9751
fix: request EXACT_OUTPUT for HyperCore perps deposits so the full margin arrives#9751abretonc7s wants to merge 7 commits into
Conversation
Unactivated trade-with-token deposits sized to exact margin left users short after HyperLiquid's ~$1 first-credit fee, so the auto-placed order failed. Co-authored-by: Cursor <cursoragent@cursor.com>
Automated fix-bug run — TAT-3400
Worker reportExplanationTrade-with-token deposits size the Relay quote to exact Core already reserved this fee on HyperLiquid withdrawals. This change mirrors that for perps deposits: after Arbitrum USDC is normalized to HyperCore, No exported API or type surface changes. Clients need no coordinated bump beyond consuming the next References
Checklist
|
Link the changelog entry to PR #9751 and cover the HyperLiquid-source deposit-target branch so package coverage thresholds pass. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Relay quotes for HyperCore perps deposits used tradeType EXPECTED_OUTPUT, which only guarantees `target * (1 - slippage)` arrives on the destination. Clients size these deposits at the exact margin required and immediately place an order needing that same margin, so any slippage inside the 0.5% band left the order short and it failed with insufficient margin. HyperCore deposits reach this state because `skipDelegation` is true for them, so they never take the delegation path that already used EXACT_OUTPUT. Request EXACT_OUTPUT for them directly instead. Verified against the live Relay API from $10 to $1000: the guaranteed minimum previously fell short at every size (-$0.05 to -$5.00) and now equals the requested target, at identical source cost. This replaces the previous activation-fee approach, which assumed HyperLiquid deducts ~$1 from the first inbound credit. That premise was not supported by mainnet ledger data, and a flat $1 both over-charged small deposits and under-funded ones above ~$200.
…th-token-has-20-failur # Conflicts: # packages/transaction-pay-controller/CHANGELOG.md
aganglada
left a comment
There was a problem hiding this comment.
Summary
Verdict: Approve — the fix is correct, minimal, and well-supported. A few small nits below.
What it does
HyperCore perps deposits go through Relay with skipDelegation = true (because isHypercore is set in processTransactions). Non-HyperCore flows that don't skip delegation already get EXACT_OUTPUT via the delegation path. HyperCore deposits were the gap: they stayed on EXPECTED_OUTPUT, which only guarantees target × (1 − slippage).
Since clients size deposits to exact marginRequired and immediately place an order needing that margin, the 0.5% slippage band could leave the account short and fail the order leg.
The fix detects normalized HyperCore USDC deposits and requests EXACT_OUTPUT instead.
What works well
-
Root cause is right. The delegation bypass explains why this path differed from other perps flows. The live Relay API table in the PR description ($10–$1000) is strong evidence: guaranteed minimum was short before, exact after, same source cost.
-
Narrow, safe change. No API/type changes.
getTradeTypeis a clean extraction.isHypercoreDepositcorrectly operates on the normalized request (post Arbitrum→HyperCore rewrite) and excludes withdrawals via!request.isHyperliquidSource. -
Better than the activation-fee approach. The pivot away from a flat ~$1 top-up is justified — it would over-charge small deposits and under-fund large ones.
EXACT_OUTPUTaddresses the actual slippage shortfall without padding. -
Tests cover the important cases. HyperCore deposit →
EXACT_OUTPUT; generic quote →EXPECTED_OUTPUTunchanged. -
Aligns with Across. Across already uses
exactOutputfor target-amount flows; Relay was the outlier here.
Issues / nits
1. Orphaned JSDoc (should fix)
The PR inserts isHypercoreDeposit and getTradeType between the existing normalizeRequest JSDoc and the function itself. Move the helpers above the normalizeRequest block, or restore the JSDoc directly above normalizeRequest.
2. Stale inline comment
The comment in getSingleQuote still says "For regular flows with a target amount, use EXPECTED_OUTPUT." HyperCore deposits are now a third case (EXACT_OUTPUT). Worth a one-line update so future readers don't reintroduce the bug.
3. Test could be tighter
The new test uses perpsDepositAndOrder, but the existing "updates request if Arbitrum deposit to Hyperliquid" test already covers perpsDeposit normalization. Consider adding tradeType: 'EXACT_OUTPUT' to that test's objectContaining assertion — or at least add a perpsDeposit case so both PERPS_DEPOSIT_TYPES are covered explicitly.
4. isHypercoreDeposit is broader than perps-only
It keys off normalized target (HyperCore USDC), not transaction.type. Any Relay quote depositing into HyperCore USDC gets EXACT_OUTPUT, not only perps deposits. That's probably fine — a stricter delivery guarantee is reasonable — but worth a conscious choice.
Risks considered (non-blocking)
| Risk | Assessment |
|---|---|
Higher source cost with EXACT_OUTPUT |
PR shows identical currencyIn before/after across sizes — not a concern if Relay behavior holds |
| Post-quote / max-amount flows | Correctly excluded: useExactInput takes precedence |
HyperLiquid withdrawals (isHyperliquidSource) |
Correctly excluded: target is not HyperCore USDC |
| Server strategy same bug | Server still uses ExpectedOutput for HyperCore, but trade-with-token goes through Relay today — out of scope, worth a follow-up if Server is ever routed for perps |
Suggested test plan before merge
- Unit tests pass
- End-to-end trade-with-token deposit at ~$20 margin on Mobile (the reported failure size)
- Confirm
currencyOut.minimumAmount === targetin the Relay quote response for a HyperCore deposit - Regression: standard non-perps Relay quotes still use
EXPECTED_OUTPUT
Bottom line: Ship it after fixing the JSDoc placement. The approach is the right fix for TAT-3400 — you're buying a delivery guarantee at no extra source cost, which is exactly what margin-sized deposits need.
isMaxAmount and isPostQuote are both optional, so useExactInput is boolean | undefined and the build failed on the narrowed parameter type.
Automated pr-complete run — #9751
Worker reportPR #9751 — Comment Triage ReportPR: #9751 Context reloadInherited context: present ( Resolved inherited artifacts: Summary of prior run:
Recipe provenance: Live comment fetch
Triage
No Core compatibility assessmentChanged files touch
Validation this session
Recipe pin correction: the inherited recipe asserted Update — original approach reverted and replacedTriage above found no actionable reviewer comments, and the PR was green. The substantive Live mainnet validation (
Core compatibility assessment (revised)Still non-breaking and still confined to Extension does not yet create Validation (revised)
|
Automated update-branch run — #9751
Worker reportUpdate-Branch Report — PR #9751PR: #9751 — fix: request EXACT_OUTPUT for HyperCore perps deposits so the full margin arrives Selected strategy
What main brought inBranch was 2 commits behind:
62 files changed on the incoming side, mostly release version bumps across package manifests, Conflicts resolvedOne conflict: Both sides added a section under the same
Resolution: kept both, ordered Resolved Files changedConflict resolution touched exactly one file: The PR's own diff against
Merge commit: Downstream compatibilityNo risk introduced by this run.
Validation
Push command usedgit push origin TAT-3400-fix-trade-with-token-has-20-failurRegular push, no Post-push verification
Validation recipe — replaced, not just re-runThe task dir was seeded with an inherited The new
Run result: Supporting artifacts: ResultBranch updated to include The one judgement call beyond mechanical merge work: the inherited recipe was obsolete and was |
Explanation
Trade-with-token perps deposits failed intermittently with insufficient margin on the order leg.
Root cause. Core requested HyperCore perps deposits from Relay with
tradeType: EXPECTED_OUTPUT, which only guaranteestarget * (1 - slippage)arrives at the destination. Clients size these deposits at exactlymarginRequiredand immediately place an order needing that same margin, so any slippage inside the 0.5% band left the account short and the order was rejected.HyperCore deposits end up on this path because
skipDelegationis true for them, so they never take the delegation path that already usedEXACT_OUTPUT.Fix. Request
EXACT_OUTPUTfor HyperCore deposits, so Relay guarantees the full target arrives.Verified against the live Relay API
Same quote request Core builds, across deposit sizes — no mocks. "Guaranteed" is Relay's
currencyOut.minimumAmount; "source cost" is the Arbitrum USDC the user spends (currencyIn).The shortfall reproduced at all six sizes before the change and none after.
Relay quotes the same input amount for both trade types, so the user spends exactly what they spend today — this buys a delivery guarantee at no extra cost, rather than padding the deposit.
Client impact
No exported API or type changes. Mobile HyperCore deposits now deliver the full requested margin at the same source cost. Extension does not yet create
perpsDepositAndOrder, so it is unaffected today but inherits the fix when trade-with-token ships there.References
Checklist
Note
Medium Risk
Changes Relay trade-type selection for HyperCore deposit quotes, which affects real money perps deposit-and-order flows but is narrowly scoped with tests and no public API changes.
Overview
Fixes intermittent insufficient margin failures on trade-with-token perps flows by changing how Relay quotes are built for HyperCore USDC deposits.
Relay quote requests now send
tradeType: EXACT_OUTPUT(instead ofEXPECTED_OUTPUT) when the normalized destination is HyperCore USDC and the flow is not max-amount or post-quote.EXPECTED_OUTPUTonly guaranteed delivery within slippage, so deposits sized to exact margin could land short and the follow-on order would fail;EXACT_OUTPUTguarantees the full target arrives.EXACT_INPUTbehavior is unchanged for max and post-quote paths.Implementation adds
isHypercoreDepositandgetTradeTypeinrelay-quotes.ts, with tests asserting HyperliquidperpsDepositAndOrderquotes useEXACT_OUTPUTwhile other targets still useEXPECTED_OUTPUT. Changelog documents the fix; no exported API changes.Reviewed by Cursor Bugbot for commit 7303a1e. Bugbot is set up for automated code reviews on this repo. Configure here.