Conversation
There was a problem hiding this comment.
Pull request overview
Integrates the Fusion (unified-asset-transfer) SDK into core-mobile and upgrades the API client layer to be compatible with Zod v4 by replacing Zodios with fetch-based clients and new OpenAPI codegen.
Changes:
- Added Fusion feature flags, Redux listeners, SDK signers, and a FusionService wrapper around TransferManager.
- Migrated multiple API clients from Zodios to
fetchJsonhelpers with optional dev-only Zod validation, and switched OpenAPI codegen to@hey-api/openapi-ts. - Updated Metro resolution and various imports/paths for the new generated API client layout and dynamic supported-chain discovery.
Reviewed changes
Copilot reviewed 68 out of 70 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core-mobile/scripts/codegen.js | Switches generated output path and codegen tool to @hey-api/openapi-ts. |
| packages/core-mobile/profile-api.config.js | Adds @hey-api/openapi-ts config for Profile API schema (env-based URL). |
| packages/core-mobile/package.json | Adds Fusion SDK dep, removes Zodios, upgrades Zod to v4. |
| packages/core-mobile/metro.config.js | Enables unstable_enablePackageExports for unified-asset-transfer (and Lombard). |
| packages/core-mobile/balance-api.config.js | Makes Balance schema URL environment-based; updates output path. |
| packages/core-mobile/app/vmModule/ModuleManager.ts | Updates constants import path for new API utils layout. |
| packages/core-mobile/app/utils/zodToCamelCase.ts | Updates Zod import style for v4 and adjusts typing/transform. |
| packages/core-mobile/app/utils/getAddressesFromXpubXP/getAddressesFromXpubXP.ts | Updates Profile API types import to new generated client output. |
| packages/core-mobile/app/utils/getAddressesFromXpubXP/getAddressesFromXpubXP.test.ts | Updates Profile API types import to new generated client output. |
| packages/core-mobile/app/utils/apiClient/scripts/fixZodIntersections.js | Removes openapi-zod-client patch script (no longer needed). |
| packages/core-mobile/app/utils/apiClient/profile/types.ts | Removes old inferred types wrapper around openapi-zod-client schemas. |
| packages/core-mobile/app/utils/apiClient/profile/profileApi.ts | Removes old axios/Zodios-style generated client setup and interceptors. |
| packages/core-mobile/app/utils/apiClient/balance/balanceApi.ts | Removes old streaming balance implementation in legacy API client folder. |
| packages/core-mobile/app/utils/api/common/fetchWithValidation.ts | Adds new fetch helpers (nitroFetch + expoFetch) with dev-only validation and query builder. |
| packages/core-mobile/app/utils/api/clients/profileApiClient.ts | Adds @hey-api/client-fetch Profile API client configured with AppCheck + headers. |
| packages/core-mobile/app/utils/api/clients/glacierApiClient.ts | Moves CORE_HEADERS import to the new API constants module. |
| packages/core-mobile/app/utils/api/clients/balanceApiClient.ts | Adds streaming balance generator alongside non-streaming generated client. |
| packages/core-mobile/app/utils/api/clients/aggregatedTokensApiClient.ts | Moves CORE_HEADERS import to the new API constants module. |
| packages/core-mobile/app/store/rpc/utils/assert.ts | Adds a reusable RPC-flavored assertion helper. |
| packages/core-mobile/app/store/rpc/handlers/wc_sessionRequest/utils.ts | Updates Zod usage for v4 and simplifies parse function typing. |
| packages/core-mobile/app/store/rpc/handlers/wallet_getNetworkState/utils.ts | Simplifies parse function typing for v4. |
| packages/core-mobile/app/store/rpc/handlers/avalanche_setDeveloperMode/utils.ts | Simplifies parse function typing for v4. |
| packages/core-mobile/app/store/rpc/handlers/account/avalanche_selectAccount/utils.ts | Updates enum schema handling and simplifies parse typing. |
| packages/core-mobile/app/store/rpc/handlers/account/avalanche_renameAccount/utils.ts | Simplifies parse function typing for v4. |
| packages/core-mobile/app/store/rpc/handlers/account/avalanche_addAccount/util.ts | Simplifies parse function typing for v4. |
| packages/core-mobile/app/store/posthog/types.ts | Adds Fusion sub-feature flags. |
| packages/core-mobile/app/store/posthog/slice.ts | Adds selectors for Fusion sub-feature flags. |
| packages/core-mobile/app/store/middleware/listener.ts | Registers Fusion listeners into app middleware. |
| packages/core-mobile/app/services/wallet/WalletService.tsx | Switches Profile addresses call to @hey-api generated client + configured fetch client. |
| packages/core-mobile/app/services/token/types.ts | Updates Zod record() usage for v4 key/value signatures. |
| packages/core-mobile/app/services/token/coingeckoProxyClient.ts | Replaces Zodios client with fetch-based client + Zod validation. |
| packages/core-mobile/app/services/token/TokenService.ts | Updates TokenService calls to the new coingecko proxy client API. |
| packages/core-mobile/app/services/posthog/types.ts | Adds Fusion sub-feature flags. |
| packages/core-mobile/app/services/glacier/GlacierService.ts | Moves CORE_HEADERS import to the new API constants module. |
| packages/core-mobile/app/services/defi/types.ts | Updates Zod record() usage for v4 key/value signatures. |
| packages/core-mobile/app/services/defi/apiClient.ts | Replaces Zodios with fetch-based DeFi + FX clients. |
| packages/core-mobile/app/services/defi/DeFiService.ts | Updates DeFi service calls to new fetch-based client signatures. |
| packages/core-mobile/app/services/browser/apiClient.ts | Replaces Zodios with fetch-based browser DeBank client. |
| packages/core-mobile/app/services/browser/BrowserService.ts | Updates browser service to new api client signature. |
| packages/core-mobile/app/services/balance/utils/mapBalanceResponseToLegacy.ts | Updates generated Balance API import path. |
| packages/core-mobile/app/services/balance/utils/buildRequestItemsForAccounts.ts | Updates generated Balance API import path. |
| packages/core-mobile/app/services/balance/BalanceService.ts | Switches streaming balances to streamingBalanceApiClient. |
| packages/core-mobile/app/services/balance/BalanceService.test.ts | Updates mocks to match new streaming balance client interface. |
| packages/core-mobile/app/new/routes/(signedIn)/(modals)/swapV2/pricingDetails/index.tsx | Updates zustand hook import location. |
| packages/core-mobile/app/new/routes/(signedIn)/(modals)/selectSwapV2ToToken/index.tsx | Updates zustand hook import location. |
| packages/core-mobile/app/new/routes/(signedIn)/(modals)/selectSwapV2FromToken/index.tsx | Updates zustand hook import location. |
| packages/core-mobile/app/new/features/swapV2/store/listeners.ts | Adds Redux listeners to init/cleanup FusionService based on unlock/flags/dev mode. |
| packages/core-mobile/app/new/features/swapV2/services/types.ts | Adds Fusion service/type interfaces for SDK integration. |
| packages/core-mobile/app/new/features/swapV2/services/signers/EvmSigner.ts | Adds EVM signer adaptor for Fusion SDK using in-app RPC requests. |
| packages/core-mobile/app/new/features/swapV2/services/signers/BtcSigner.ts | Adds BTC signer adaptor for Fusion SDK using in-app RPC requests. |
| packages/core-mobile/app/new/features/swapV2/services/FusionService.ts | Adds singleton wrapper around unified-asset-transfer TransferManager and feature-flag enablement. |
| packages/core-mobile/app/new/features/swapV2/screens/SwapScreen.tsx | Aligns “same-token selected” behavior to always clear the “to” token. |
| packages/core-mobile/app/new/features/swapV2/screens/SelectSwapV2TokenScreen.tsx | Replaces hardcoded network list with Fusion SDK-supported chains. |
| packages/core-mobile/app/new/features/swapV2/hooks/useZustandStore.ts | Fixes type import path. |
| packages/core-mobile/app/new/features/swapV2/hooks/useSwapV2Tokens.ts | Uses useNetworks + new query keys and removes hardcoded C/Solana network logic. |
| packages/core-mobile/app/new/features/swapV2/hooks/useSupportedChains.ts | Adds hook to fetch supported chains from FusionService and map to enabled networks. |
| packages/core-mobile/app/new/features/swapV2/contexts/SwapContext.tsx | Updates zustand hook import location. |
| packages/core-mobile/app/new/features/swapV2/consts.ts | Adds Fusion environment selection + Markr API URL constant. |
| packages/core-mobile/app/new/features/swap/utils/svm/jupiterApi.client.ts | Replaces Zodios-based Jupiter client with fetch-based functions + validation. |
| packages/core-mobile/app/new/features/swap/services/MarkrService.ts | Replaces Zodios client with fetch-based client + validation for Markr. |
| packages/core-mobile/app/new/features/swap/services/JupiterService.ts | Updates JupiterService to new Jupiter API client signature. |
| packages/core-mobile/app/new/features/meld/services/apiClient.ts | Replaces Zodios client with fetch-based Meld client factory. |
| packages/core-mobile/app/new/features/meld/services/MeldService.ts | Updates MeldService calls to match new client signatures. |
| packages/core-mobile/app/hooks/networks/useNetworks.ts | Decorates enabled networks with caip2ChainId and adds getEnabledNetworkByCaip2ChainId. |
| packages/core-mobile/app/hooks/balance/useSupportedChains.ts | Updates generated Balance API import path. |
| packages/core-mobile/app/consts/reactQueryKeys.ts | Adds React Query keys for Fusion supported chains & tokens. |
| packages/core-mobile/.gitignore | Updates generated client ignore paths to new output structure. |
| packages/core-mobile/.eslintrc.js | Removes legacy generated-client ignore glob and keeps new generated path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/core-mobile/app/new/features/swapV2/hooks/useSupportedChains.ts
Outdated
Show resolved
Hide resolved
packages/core-mobile/app/new/features/swapV2/hooks/useSupportedChains.ts
Outdated
Show resolved
Hide resolved
packages/core-mobile/app/store/rpc/handlers/account/avalanche_selectAccount/utils.ts
Show resolved
Hide resolved
| // eslint-disable-next-line @typescript-eslint/explicit-function-return-type | ||
| export const parseRequestParams = (params: unknown) => { |
There was a problem hiding this comment.
zod recommends we don't manually type the return type and just let it infer automatically
There was a problem hiding this comment.
just curious instead of manually typing it can we use z.infer here instead?
There was a problem hiding this comment.
we are letting it infer already here by not declaring a return type.
B0Y3R-AVA
left a comment
There was a problem hiding this comment.
left some super minor comments here, Great Work!
| // eslint-disable-next-line @typescript-eslint/explicit-function-return-type | ||
| export const parseRequestParams = (params: unknown) => { |
There was a problem hiding this comment.
just curious instead of manually typing it can we use z.infer here instead?
packages/core-mobile/app/new/features/swapV2/hooks/useSupportedChains.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 69 out of 72 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 71 out of 73 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (1)
packages/core-mobile/app/new/features/swapV2/screens/SwapScreen.tsx:594
- The refs
prevFromRefandprevToRefare declared and assigned but no longer used after the logic change to always clear the "to" field. These refs should be removed to clean up the code.
const prevFromRef = useRef(fromToken)
const prevToRef = useRef(toToken)
useEffect(() => {
if (fromToken && toToken && fromToken.localId === toToken.localId) {
// Always clear the "to" field when same token is selected (matches swap v1 behavior)
setToToken(undefined)
setAmount(undefined)
setToTokenValue(undefined)
setFromTokenValue(undefined)
}
prevFromRef.current = fromToken
prevToRef.current = toToken
}, [fromToken, toToken, setToToken, setFromToken, setAmount])
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/core-mobile/app/new/features/swapV2/hooks/useSupportedChains.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 71 out of 73 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/core-mobile/app/new/features/swapV2/screens/SwapScreen.tsx
Outdated
Show resolved
Hide resolved
| const getEnabledNetworkByCaip2ChainId = useCallback( | ||
| (caip2ChainId: string) => { | ||
| return enabledNetworks.find(n => n.caip2ChainId === caip2ChainId) | ||
| }, | ||
| [enabledNetworks] | ||
| ) |
There was a problem hiding this comment.
The caip2ChainId property is defined as optional (caip2ChainId?: string) in the NetworkWithCaip2ChainId type, but this code assumes it will always be present by using strict equality comparison (n.caip2ChainId === caip2Id). If caip2ChainId is undefined, this comparison will never match, potentially returning undefined even when a matching network exists. Consider either:
- Making caip2ChainId required in the type definition
- Adding a guard to handle undefined caip2ChainId values
- Ensuring all networks always have caip2ChainId populated before being added to enabledNetworks
packages/core-mobile/app/new/features/swapV2/screens/SelectSwapV2TokenScreen.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 71 out of 73 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Create balance lookup map by localId | ||
| const balanceMap = new Map<string, LocalTokenWithBalance>() | ||
| balances?.forEach(balance => { | ||
| if (balance.localId) { | ||
| balanceMap.set(balance.localId.toLowerCase(), balance) | ||
| balanceMap.set(balance.localId, balance) | ||
| } | ||
| }) | ||
|
|
||
| // Determine current network | ||
| const currentNetwork = isAvalancheCChainId(chainId) | ||
| ? cChainNetwork | ||
| : isSolanaChainId(chainId) | ||
| ? solanaNetwork | ||
| : null | ||
|
|
||
| // Create native token if network is available | ||
| let nativeToken: LocalTokenWithBalance | null = null | ||
|
|
||
| if (currentNetwork) { | ||
| const symbol = currentNetwork.networkToken.symbol | ||
| const decimals = currentNetwork.networkToken.decimals | ||
| const localId = `native-${symbol.toLowerCase()}` | ||
| const localId = `NATIVE-${symbol}` | ||
| const nativeBalanceData = balanceMap.get(localId) |
There was a problem hiding this comment.
Inconsistent localId casing in token identification. The code creates native token localIds with uppercase format (NATIVE-${symbol}) on line 92, but the balance lookup uses the localId directly without case normalization. Meanwhile, other parts of the codebase (e.g., useFilteredSwapTokens.ts:45, useSearchableTokenList.ts:98) consistently use .toLowerCase() for localId comparisons.
For ERC20 tokens, getLocalTokenIdFromApi returns address.toLowerCase() (getLocalTokenIdFromApi.ts:11), but the balance map lookup doesn't normalize the keys.
This inconsistency could cause balance data to not be matched correctly for native tokens or tokens with different casing. Consider:
- Normalizing all localIds to lowercase when creating the balance map
- Or ensuring consistent casing in localId generation across native and ERC20 tokens
packages/core-mobile/app/store/rpc/handlers/account/avalanche_selectAccount/utils.ts
Show resolved
Hide resolved
packages/core-mobile/app/new/features/swapV2/hooks/useSupportedChains.ts
Show resolved
Hide resolved
alexnicolae-ava
left a comment
There was a problem hiding this comment.
Dev tested. Great work! 🔥
Description
Ticket: CP-13005
Fusion SDK Integration
Metro Config Update
Dynamic Chain Support
Zod v3 → v4 Upgrade
Testing
iOS: 0.0.0.7481
Android: 0.0.0.7482
Fusion Dynamic Chain Support
Portfolio & Track tabs:
Buy/Sell flow
Swap (v1)
DeFi Protocol (DeFi tab)
Profile API
Checklist
Please check all that apply (if applicable)