fix(wallets): resolve drained IBEX accounts as zero balance (admin API broken for migrated accounts)#441
Merged
Conversation
IBEX omits the balance field for drained / never-funded accounts (absent
means zero — verified in prod during the USDT cutover). getBalanceForWallet
treated that as UnexpectedIbexResponse('Balance not found'), which throws in
the wallet balance resolvers.
Post-cutover this broke the ADMIN GraphQL API for every migrated account:
wallets[].balance on the legacy (drained) USD wallet errors with IBEX_ERROR,
failing the whole accountDetails* response. The cash-wallet compat redirect
does not apply in admin ctx (no client capabilities / domainAccount), so the
admin path always does the raw read. Public app API was unaffected.
Evidence (prod, patoo): wallets -> USD balance null + IBEX_ERROR, USDT 2000
reads fine. Same signature on TEST for any migrated account.
Fix: missing balance field on an otherwise-valid response resolves to the
currency's ZERO, matching the existing 404 arm and cutover-verifier
semantics. Unit tests for both currencies.
Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Bug
Since the USDT cutover completed (2026-07-10), the admin GraphQL API fails for every migrated account:
accountDetailsByUsername/ByAccountId→wallets[].balanceon the legacy (drained) USD wallet throwsIBEX_ERROR, poisoning the whole response. Any admin-API consumer (Frappe Account Hub) breaks on ~all customer lookups.Why admin only: the cash-wallet compat redirect in the USD wallet resolver only runs when
cashWalletClientCapabilities/domainAccountare in ctx — true for app users on the public API (compat verified during cutover), never for admin ctx → raw read of the drained wallet.Root cause: IBEX omits the
balancefield for drained/never-funded accounts (absent = zero; verified in prod during the cutover).getBalanceForWallethas a ZERO arm forhttpCode 404but treated the missing-field case asUnexpectedIbexResponse("Balance not found")→ resolver throws.Evidence
Direct prod admin-API query (
patoo, migrated, $20):{"errors":[{"path":["accountDetailsByUsername","wallets",0,"balance"],"code":"IBEX_ERROR"}], "data":{"accountDetailsByUsername":{"wallets":[ {"walletCurrency":"USD","balance":null}, {"walletCurrency":"BTC","balance":null}, {"walletCurrency":"USDT","balance":2000}]}}}Same signature on TEST for every migrated account (
ben4,baa).Fix
Missing
balanceon an otherwise-valid account-details response resolves to the currency'sZERO— consistent with the 404 arm and the cutover verifier's drained-reads-as-zero semantics. Applies to all consumers; no resolver/ctx changes.Tests
TEST=get-balance-for-wallet yarn test:unit→ 3 passed (existing + drained-USD + drained-USDT). tsc clean.Deploy note
Wants to ride the next chart release — Account Hub (Frappe) stays broken for migrated accounts until this lands in prod.
🤖 Generated with Claude Code