CP-14673: switch Glacier calls to the core-proxy-api Glacier proxy - #4012
Conversation
Coverage report ✅2/2 packages passed thresholds 🟢 @avalabs/core-mobile
🟢 @avalabs/k2-alpine
Artifacts and threshold sources
Source run: Mobile PR |
CP-14673 device verification evidence — Glacier via core-proxy-api
Requests to core-proxy-api (Glacier proxy) — unique endpointsStatus code distribution (all core-proxy-api traffic this session)(the 401s are the ~3-minute window where an unprovisioned Core API key was baked in for testing — removed, documented separately; all AppCheck-authenticated traffic is 200) All Core APIs — per-host totalsVerbatim raw log samples (logcat, ReactNativeJS) |
There was a problem hiding this comment.
Pull request overview
Migrates Core Mobile’s Glacier traffic to be compatible with the authenticated core-proxy-api Glacier proxy by introducing a shared auth-header resolver (Firebase AppCheck + optional Core API key) and wiring it into both the legacy glacier-sdk client and the upgraded vm-modules runtime.
Changes:
- Add
getCoreAuthHeadersand integrate it intoGlacierServiceandModuleManagerruntime (getAuthHeaders) for proxy-required per-request auth headers. - Bump
@avalabs/{evm,avalanche,bitcoin,svm}-moduleand@avalabs/vm-module-typesto4.0.0, updating codepaths/tests for newly introduced Hypercore token/VM types. - Document
CORE_API_KEYin.env.exampleand exportAPPCHECK_HEADERfor reuse.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Updates lockfile for vm-modules + types bump to 4.0.0. |
| packages/core-mobile/package.json | Bumps vm-modules + vm-module-types dependencies to 4.0.0. |
| packages/core-mobile/app/vmModule/ModuleManager.ts | Passes runtime.getAuthHeaders so vm-modules can auth Glacier proxy calls. |
| packages/core-mobile/app/utils/publicKeys.ts | Adds NetworkVMType.HYPERCORE to emptyAddresses() mapping. |
| packages/core-mobile/app/utils/api/common/getCoreAuthHeaders.ts | New per-request auth header resolver (AppCheck + optional x-core-api-key). |
| packages/core-mobile/app/utils/api/common/getCoreAuthHeaders.test.ts | Unit tests for resolver behavior (AppCheck header, optional API key, per-call token re-read). |
| packages/core-mobile/app/utils/api/common/appCheckFetch.ts | Exports APPCHECK_HEADER for shared usage. |
| packages/core-mobile/app/services/glacier/GlacierService.ts | Uses async HEADERS resolver to attach proxy auth headers per request. |
| packages/core-mobile/app/services/balance/utils/getLocalTokenId.ts | Adds guard for tokens without address (Hypercore spot token compatibility). |
| packages/core-mobile/app/services/balance/utils/getLocalTokenid.test.ts | Adds test coverage for Hypercore spot token fallback behavior. |
| packages/core-mobile/app/new/features/swap/utils/getTokenAddress.ts | Avoids accessing missing address for non-swappable Hypercore spot tokens. |
| packages/core-mobile/app/new/features/swap/utils/getTokenAddress.test.ts | Adds test for Hypercore spot token returning empty address. |
| packages/core-mobile/app/new/features/swap/utils/buildLocalToken.ts | Avoids reading balanceData.address when absent (Hypercore spot compatibility). |
| packages/core-mobile/app/hooks/networks/utils/getNetworkContractTokens.ts | Filters out Hypercore spot tokens from contract token pipeline. |
| packages/core-mobile/app/hooks/browser/injectedProvider/approvalMethods.test.ts | Updates enum snapshot to include newly-added RPC method. |
| packages/core-mobile/.env.example | Documents CORE_API_KEY for dev/E2E proxy auth. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!('address' in token) || !token.address) { | ||
| Logger.error('Token address is missing', { token }) | ||
| return fallbackTokenId | ||
| } |
There was a problem hiding this comment.
Good catch — fixed in 1069ee1. getLocalTokenId now returns the ${type}-${symbol} fallback for TokenType.HYPERCORE_SPOT before the missing-address check, so expected addressless hypercore tokens no longer log an error; unexpected missing addresses still do. Added a test asserting Logger.error is not called for the hypercore case.
…vice for the Glacier proxy migration
…nager, absorb hypercore types
…anche signing set (RpcMethod enum grew in 4.0.0)
…enId (Copilot review)
1069ee1 to
9fc125a
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
packages/core-mobile/app/hooks/networks/utils/getNetworkContractTokens.ts:23
- The filter predicate only excludes
TokenType.HYPERCORE_SPOT, but it still type-asserts the remaining values asNetworkContractToken. Ifmodule.getTokens()ever returns other entries without anaddress(or an empty address), this will violate the function’s return type and can break callers that assume contract tokens always have an address. Filter byaddresspresence as well (and still exclude Hypercore spot tokens).
return (tokens ?? []).filter(
(token): token is NetworkContractToken =>
token.type !== TokenType.HYPERCORE_SPOT
)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
packages/core-mobile/app/utils/api/common/getCoreAuthHeaders.test.ts:31
- Use the shared
APPCHECK_HEADERconstant in the expectation instead of repeating the header string literal.
await expect(getCoreAuthHeaders()).resolves.toEqual({
'X-Firebase-AppCheck': 'appcheck-token'
})
packages/core-mobile/app/utils/api/common/getCoreAuthHeaders.test.ts:43
- Use the shared
APPCHECK_HEADERconstant in the expectation instead of repeating the header string literal.
await expect(getCoreAuthHeaders()).resolves.toEqual({
'X-Firebase-AppCheck': 'appcheck-token',
'x-core-api-key': 'core-api-key'
})
packages/core-mobile/app/utils/api/common/getCoreAuthHeaders.test.ts:60
- Use the shared
APPCHECK_HEADERconstant in the expectation instead of repeating the header string literal.
await expect(getCoreAuthHeaders()).resolves.toEqual({
'X-Firebase-AppCheck': 'token-1'
})
await expect(getCoreAuthHeaders()).resolves.toEqual({
'X-Firebase-AppCheck': 'token-2'
})
packages/core-mobile/app/utils/api/common/getCoreAuthHeaders.test.ts:2
- The test hardcodes the AppCheck header name string. Since the production code uses the exported
APPCHECK_HEADERconstant, importing and using it here avoids duplication and keeps the test aligned if the header name ever changes.
This issue also appears in the following locations of the same file:
- line 29
- line 40
- line 55
import AppCheckService from 'services/fcm/AppCheckService'
import { getCoreAuthHeaders } from './getCoreAuthHeaders'
| GLACIER_URL= | ||
| GLACIER_API_KEY= | ||
| # Core API key for core-proxy-api (dev/E2E: authorizes + bypasses rate limits; 1Password "front end eng" vault -> "Core API keys") | ||
| CORE_API_KEY= |
There was a problem hiding this comment.
Should we call it CORE_PROXY_API_KEY? There are multiple Core Apis we use
| CORE_API_KEY= | |
| CORE_PROXY_API_KEY= |
Description
Ticket: CP-14673
First slice of the mobile side of the Glacier migration: all Glacier traffic must move to the authenticated smart-routing proxy (
core-proxy-api.../v1/proxy/glacier), which requires a Firebase AppCheck token (or a per-client Core API key) on every request. The oldglacier-api.avax.networkhost is losing its EVM endpoints at the end of July.In this PR:
getCoreAuthHeaders— shared per-request auth-header resolver: AppCheck token always, plusx-core-api-keywhenConfig.CORE_API_KEYis set (dev/E2E; key lives in 1Password "front end eng" vault → "Core API keys")GlacierService(legacy glacier-sdk client) now passes the resolver as an asyncHEADERSresolver — proxy-ready.env.exampledocumentsCORE_API_KEYglacierApiClientneeds no change (already onappCheckFetch; URL comes from env)Follow-ups (unblocked by core-vm-modules#452 merging — done):
@avalabs/{evm,avalanche,bitcoin,svm}-module+vm-module-typesto 4.0.0ModuleManager.init: passgetAuthHeaders: getCoreAuthHeadersinruntime(required by the new module constructors)HypercoreSpotTokenguards in token utils,NetworkVMType.HYPERCOREin publicKeys) — with unit tests for the new fallback pathsNot in this PR (ops, coordinated with BE at release time):
GLACIER_URLswap in the AWS canonical env files + Bitrise; prod deploy of core-proxy-api is on-request from Feri.Screenshots/Videos
N/A — no UI changes. Feature verification (balances, tx history, NFTs, stake flows, P/X-chain send) happens after the module bump lands, against the staging proxy.
Testing
Dev Testing (if applicable)
GLACIER_URLpointed athttps://core-proxy-api.avax-test.network/v1/proxy/glacierin.env.development, Glacier-backed features (watchlist, validator lists, NFT reindex) work on a dev build; AppCheck debug tokens are honored on stagingQA Testing (if applicable)
Checklist
Please check all that apply (if applicable)
🤖 Generated with Claude Code