feat(account): add GET /account/balances with CHEQ/USD conversion - #814
Open
fraseragain wants to merge 4 commits into
Open
fraseragain wants to merge 4 commits into
fraseragain wants to merge 4 commits into
Conversation
Returns the on-chain balance of the authenticated customer's mainnet and testnet payment accounts in ncheq, CHEQ and USD. The CHEQ/USD rate is sourced from CoinGecko (coin id `cheqd-network`) via a new PriceHelper and cached in-process for CHEQ_USD_RATE_CACHE_TTL seconds. The endpoint degrades gracefully: if the rate lookup or a network's RPC endpoint is unavailable it still returns 200, with the affected usd/rate/balance fields set to null. Per-network balance queries are isolated so one RPC outage doesn't blank the other network or the addresses, and checkBalance is bounded by an 8s timeout. Also extracts the ncheq<->CHEQ helpers (cheqToNcheq, ncheqToCheq, toSafeFaucetAmount) out of account.ts into helpers/denom.ts, and generalises getTestnetBalanceNcheq to getBalanceNcheq(address, rpcUrl). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- unit: ncheqToCheq edge cases (zero, sub-CHEQ, > Number.MAX_SAFE_INTEGER) and the cheq * rate USD calculation - e2e: authenticated shape check + testnet address parity with GET /account, and an unauthenticated 401 check Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 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.
What
Adds
GET /account/balances— the on-chain balance of the authenticated customer's mainnet and testnet payment accounts, inncheq,CHEQandUSD.Why
GET /accountreturns only the payment-account addresses.checkBalancefrom@cheqd/sdkwas used internally (faucet top-up) but never surfaced, and there was no CHEQ→USD lookup anywhere. The Studio portal needs both to show customers their account funding status. Studio owns the price-feed dependency and caching (the same way it wraps Stripe); the portal just displays.How
src/helpers/price.ts— newPriceHelper.getCheqUsdRate(). Fetches the CHEQ/USD spot rate from CoinGecko (coin idcheqd-network, matchingcheqd/market-monitoring), caches it in-process forCHEQ_USD_RATE_CACHE_TTLseconds (default 300), 5s request timeout. Never throws — any failure logs and returnsnull.src/helpers/denom.ts— new. ExtractsncheqToCheq/cheqToNcheq/toSafeFaucetAmountout ofaccount.tsso the pure conversion logic has one home and is unit-testable in isolation.account.ts—getBalances()controller method (inline@openapi,[Account]tag).getTestnetBalanceNcheqgeneralised togetBalanceNcheq(address, rpcUrl)with an 8s timeout guard (StargateClientexposes no cancellation).app.ts,read:accountrule inaccount-auth.ts,AccountBalancesResponse/AccountNetworkBalanceschemas inswagger-api-types.ts(+ regeneratedswagger-api.json).COINGECKO_API_URL/COINGECKO_TOKEN_ID/COINGECKO_API_KEY/CHEQ_USD_RATE_CACHE_TTL(constants use the existingparseNumberEnv; documented inREADME.md+example.env).Edge cases handled
null.balanceisnull(the address is still returned); the other network is unaffected.rateisnulland everyusdisnull; balances still returned; response is still200.Number.MAX_SAFE_INTEGERncheq → conversion viaNumber(bigint) / 1e9, no throw (covered by a unit test).Deliberate deviations from existing conventions
PriceHelper(its ownnode-cache), notLocalStore—LocalStoreis coupled toPaymentAccountEntityand sits underdatabase/; a market-rate cache doesn't belong there.checkBalancetimeout — the existinggetTestnetBalanceNcheqlets RPC errors propagate./account/balancesisolates them so one RPC outage doesn't blank the other network or the addresses.AccountBalancesResponse) rather than fully inline like the newest/account/faucetblock — the response is structured enough that a named schema (likeAccountAnalyticsResponse) reads better.Testing
npm run build(swagger + tsc) — clean.npm run test:unit— 137/137 pass (6 new intests/unit/account/balances.test.ts).prettier --check 'src/**/*.ts' 'tests/**/*.ts'— clean.tests/e2e/parallel/account/(authenticated shape check + testnet address parity with/account, and an unauthenticated 401) — these need a deployed environment, so they run in CI, not locally./account), a live balance, and a live CoinGecko rate; with CoinGecko pointed at a dead URL,rate/usdwerenull, balances still returned,200, no crash.Follow-up
Per-account transaction history is tracked in the
paymenttable (PaymentEntity) but has no read endpoint — raised as #815.🤖 Generated with Claude Code