fix(perps): suppress "User or API Wallet does not exist" Sentry noise from unfunded wallets#29972
Conversation
Hyperliquid rejects exchange writes (agentSetAbstraction, userSetAbstraction, setReferrer) with "User or API Wallet 0x... does not exist." when the wallet has never deposited USDC. The catch in #ensureUnifiedAccountEnabled was forwarding these benign rejections to Sentry on every Perps section open — ~530k events / ~100k users in 14d on 7.75.1 (METAMASK-MOBILE-4XB5 iOS, METAMASK-MOBILE-4Q4M Android). Fix is proactive: probe infoClient.clearinghouseState (cheap, non-throwing, returns zeros for unfunded wallets) before any user-scoped exchange write. When every existence signal is empty (accountValue / withdrawable / positions), skip the migration and referral writes and fire a not_applicable analytics event. Positive observations are cached in PerpsSigningCache.walletRegistered; negative results re-probe on next entry so the gate self-heals once the user deposits. isHyperLiquidUserNotFoundError classifier remains as a safety net in three catches (ensureUnifiedAccountEnabled, ensureReferralSet, setReferralCode) for races where the probe succeeded but the write still rejected. Unrelated SDK errors still reach logger.error. CHANGELOG entry: null
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
…ates
Replaces clearinghouseState string-zero parsing with a simple array-length
check on the deposit/withdraw ledger. A non-empty ledger is necessary and
sufficient for `agentSetAbstraction` / `userSetAbstraction` / `setReferrer`
to succeed.
Why: clearinghouseState returns balances as strings ("0.0", "0", "0.00",
"0e0"); a string-equality check against the canonical "0.0" would let
non-canonical zero formats slip through and bypass the gate. The ledger
endpoint returns a plain array — empty if and only if the wallet has never
interacted with Hyperliquid.
Cost: same single API call, ~100 ms.
…e-user-api-wallet
gambinish
left a comment
There was a problem hiding this comment.
Approved, but please evaluate my two comments to determine if necessary
…e-user-api-wallet # Conflicts: # app/controllers/perps/providers/HyperLiquidProvider.ts # app/controllers/perps/utils/errorUtils.test.ts
Replace regex with case-insensitive .includes() checks per reviewer feedback — less brittle across mobile and extension error message variants.
…etaMask/metamask-mobile into fix/perps-sentry-noise-user-api-wallet
Worker reportComments Report — PR #29972
Summary
|
Worker reportComments Report — PR #29972
Summary
|
Worker reportComments Report — PR #29972
Summary |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1a633a7. Configure here.
When the !isRegistered branch defers migration, the memoized #ensureReadyPromise must be reset so subsequent #ensureReady calls re-probe. Without this flag, unfunded wallets stay permanently deferred until provider reconnect or app restart. Sets #unifiedAccountSetupNeedsRetry = true in both ensureUnifiedAccountEnabled and ensureReferralSet deferred branches.
Worker reportComments Report — PR #29972
Summary
|
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
SmokePerps is the primary tag since these changes directly affect the Perps trading readiness flow, account setup initialization, and Add Funds flow. The SmokeWalletPlatform is required per SmokePerps tag description (Perps is a section inside the Trending tab). SmokeConfirmations is required per SmokePerps tag description (Add Funds deposits are on-chain transactions). The changes are scoped to the Perps controller and don't affect other wallet features (accounts, networks, swaps, browser, etc.), so other tags are not needed. Performance Test Selection: |
|




Description
Hyperliquid creates user accounts server-side on first USDC deposit. Until then, every user-scoped exchange write (
agentSetAbstraction,userSetAbstraction,setReferrer) rejects withUser or API Wallet 0x... does not exist.and the catch inHyperLiquidProvider.#ensureUnifiedAccountEnabledwas forwarding these benign rejections to Sentry on every Perps section open.Last 14d on
7.75.1+4800:Source pinned by event Additional Context:
HyperLiquidProvider.method: ensureUnifiedAccountEnabled.Fix: proactive gate. Probe
infoClient.userNonFundingLedgerUpdatesonce (cheap, ~100 ms, non-throwing) before any user-scoped exchange write. The ledger is empty if and only if the wallet has never interacted with Hyperliquid — a necessary and sufficient precondition for the exchange writes to succeed. When empty, skip the migration / referral writes, firePerp Account Setupwithstatus: not_applicable,error_message: no_hl_account. Positive observations cached inPerpsSigningCache.walletRegistered; negative results re-probe on next entry so the gate self-heals once the user deposits.isHyperLiquidUserNotFoundErrorremains as a safety net in three catches (ensureUnifiedAccountEnabled,ensureReferralSet,setReferralCode) for the small race window where the probe succeeded but the write still rejected. Unrelated SDK errors keep reachinglogger.error.Reproduced standalone
Confirmed with a node script (not committed) that drives the SDK directly with a freshly-generated EOA. Key signals:
exchangeClient.agentSetAbstraction({abstraction:'u'})rejects with the exact Sentry string.infoClient.userAbstractionis not the throw site — it returns'default'for fresh wallets.infoClient.userNonFundingLedgerUpdatesreturns[]for fresh wallets — a clean array-length discriminator (no string parsing).Why this supersedes #29828
#29828 catches and classifies after the SDK rejects. This PR prevents the SDK call when we already know it will fail.
ensureUnifiedAccountEnabledonlyensureUnifiedAccountEnabled+ensureReferralSetCherry-picked from #29828:
isHyperLiquidUserNotFoundErrorhelper,reason: 'no_hl_account'discriminator,STATUS.NOT_APPLICABLEconstant.Changelog
CHANGELOG entry: null
Related issues
Supersedes: #29828
Sentry: METAMASK-MOBILE-4XB5, METAMASK-MOBILE-4Q4M, METAMASK-MOBILE-4KC4
Manual testing steps
Automated:
yarn lintclean.tsc --noEmitclean.Screenshots/Recordings
N/A — internal observability change. Verify via Sentry dashboard delta 24–48h after release.
Pre-merge author checklist
Performance checks (if applicable)
Pre-merge reviewer checklist
Note
Medium Risk
Touches Hyperliquid account setup and referral flows and adds new caching/gating logic; mistakes could defer migration/referral for some funded users, though the probe is designed to fail open and has test coverage.
Overview
Reduces Perps Sentry noise by proactively skipping Hyperliquid exchange writes when the wallet has no Hyperliquid account yet (no funding/ledger history), and instead tracking
Perp Account Setupwithstatus: not_applicableanderror_message: no_hl_account.Adds
#isWalletOnHyperliquid(ledger probe + positive-only cache inPerpsSigningCache.walletRegistered) and uses it to gate#ensureUnifiedAccountEnabledand referral setup; also introducesisHyperLiquidUserNotFoundErroras a safety-net classifier so these benign rejections are debug-logged rather than sent to Sentry.Extends analytics constants with
STATUS.NOT_APPLICABLE, enrichesTradingReadinessCacheentries with an optionalreason, and adds focused unit tests covering the new gate, cache behavior, and error classification.Reviewed by Cursor Bugbot for commit 9e54db7. Bugbot is set up for automated code reviews on this repo. Configure here.