From 87561a1fa464ad4f72d8f661f61f4a6b4587a161 Mon Sep 17 00:00:00 2001 From: James Boyer Date: Wed, 15 Oct 2025 10:24:34 -0400 Subject: [PATCH 1/2] add xpub to avalanche get accounts --- .../avalanche_getAccounts.test.ts | 56 ++++++++++++++++++- .../avalanche_getAccounts.ts | 55 +++++++++++++++--- 2 files changed, 100 insertions(+), 11 deletions(-) diff --git a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts index 542a08b519..7434a4721c 100644 --- a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts +++ b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts @@ -12,6 +12,29 @@ jest.mock('store/account/slice', () => { } }) +jest.mock('store/wallet/slice', () => ({ + selectWalletById: () => () => ({ + id: 'wallet-1', + name: 'Test Wallet', + type: 'MNEMONIC' + }) +})) + +jest.mock('services/wallet/WalletService', () => ({ + __esModule: true, + default: { + getRawXpubXP: jest + .fn() + .mockResolvedValue( + 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' + ) + } +})) + +jest.mock('utils/Logger', () => ({ + warn: jest.fn() +})) + const mockDispatch = jest.fn() const mockListenerApi = { getState: jest.fn(), @@ -44,7 +67,7 @@ describe('avalanche_getAccounts handler', () => { }) describe('handle', () => { - it('should return success with the list of available accounts', async () => { + it('should return success with the list of available accounts including xpubXP for mnemonic wallets', async () => { const result = await handler.handle(testRequest, mockListenerApi) expect(result).toEqual({ @@ -63,7 +86,10 @@ describe('avalanche_getAccounts handler', () => { active: true, type: 'primary', walletId: 'wallet-1', - walletType: 'mnemonic' + walletType: 'MNEMONIC', + walletName: 'Test Wallet', + xpubXP: + 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' }, { id: '1', @@ -78,10 +104,34 @@ describe('avalanche_getAccounts handler', () => { active: false, type: 'primary', walletId: 'wallet-1', - walletType: 'mnemonic' + walletType: 'MNEMONIC', + walletName: 'Test Wallet', + xpubXP: + 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' } ] }) }) + + it('should return accounts without xpubXP for non-supported wallet types', async () => { + // Mock a Ledger wallet (doesn't support xpubXP) + const mockWalletSlice = require('store/wallet/slice') + mockWalletSlice.selectWalletById = () => () => ({ + id: 'wallet-1', + name: 'Ledger Wallet', + type: 'LEDGER' + }) + + const result = await handler.handle(testRequest, mockListenerApi) + + expect(result.success).toBe(true) + if (result.success) { + const accounts = result.value as any[] + expect(accounts).toHaveLength(2) + expect(accounts[0].xpubXP).toBeUndefined() + expect(accounts[0].walletType).toBe('LEDGER') + expect(accounts[0].walletName).toBe('Ledger Wallet') + } + }) }) }) diff --git a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts index db877c45d8..b195ebaed2 100644 --- a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts +++ b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts @@ -1,7 +1,11 @@ import { AppListenerEffectAPI } from 'store/types' import { selectAccounts, selectActiveAccount } from 'store/account/slice' +import { selectWalletById } from 'store/wallet/slice' import { RpcMethod, RpcRequest } from 'store/rpc/types' import { rpcErrors } from '@metamask/rpc-errors' +import { WalletType } from 'services/wallet/types' +import WalletService from 'services/wallet/WalletService' +import Logger from 'utils/Logger' import { HandleResponse, RpcRequestHandler } from '../../types' export type AvalancheGetAccountsRpcRequest = @@ -16,20 +20,55 @@ class AvalancheGetAccountsHandler _request: AvalancheGetAccountsRpcRequest, listenerApi: AppListenerEffectAPI ): HandleResponse => { - const accounts = selectAccounts(listenerApi.getState()) - const activeAccount = selectActiveAccount(listenerApi.getState()) - if (!activeAccount) + const state = listenerApi.getState() + const accounts = selectAccounts(state) + const activeAccount = selectActiveAccount(state) + + if (!activeAccount) { return { success: false, error: rpcErrors.internal('no active account') } + } - const accountsArray = Object.values(accounts).map(account => { - return { - ...account, - active: account.id === activeAccount.id + // Helper function to get xpubXP for supported wallet types + const getXpubXP = async ( + walletId: string, + walletType: WalletType + ): Promise => { + try { + // Only mnemonic and keystone wallets support xpubXP + if ( + walletType === WalletType.MNEMONIC || + walletType === WalletType.KEYSTONE + ) { + return await WalletService.getRawXpubXP({ walletId, walletType }) + } + return undefined + } catch (error) { + Logger.warn(`Failed to get xpubXP for wallet ${walletId}:`, error) + return undefined } - }) + } + + // Process accounts and add xpubXP where available + const accountsArray = await Promise.all( + Object.values(accounts).map(async account => { + const wallet = selectWalletById(account.walletId)(state) + const xpubXP = wallet + ? await getXpubXP(account.walletId, wallet.type) + : undefined + + return { + ...account, + walletType: wallet?.type, + walletName: wallet?.name, + xpubXP, + active: account.id === activeAccount.id + } + }) + ) + return { success: true, value: accountsArray } } } From 316ec87ada76e551a8452279ddb5b5f8a57df197 Mon Sep 17 00:00:00 2001 From: James Boyer Date: Thu, 16 Oct 2025 16:42:12 -0400 Subject: [PATCH 2/2] no longer checking for wallet type --- .../avalanche_getAccounts.test.ts | 6 ++++++ .../avalanche_getAccounts/avalanche_getAccounts.ts | 11 +---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts index 7434a4721c..330dafe65e 100644 --- a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts +++ b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts @@ -122,6 +122,12 @@ describe('avalanche_getAccounts handler', () => { type: 'LEDGER' }) + // Mock WalletService to throw error for Ledger wallets + const mockWalletService = require('services/wallet/WalletService') + mockWalletService.default.getRawXpubXP.mockRejectedValueOnce( + new Error('Unsupported wallet type') + ) + const result = await handler.handle(testRequest, mockListenerApi) expect(result.success).toBe(true) diff --git a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts index b195ebaed2..f7deb78518 100644 --- a/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts +++ b/packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts @@ -5,7 +5,6 @@ import { RpcMethod, RpcRequest } from 'store/rpc/types' import { rpcErrors } from '@metamask/rpc-errors' import { WalletType } from 'services/wallet/types' import WalletService from 'services/wallet/WalletService' -import Logger from 'utils/Logger' import { HandleResponse, RpcRequestHandler } from '../../types' export type AvalancheGetAccountsRpcRequest = @@ -37,16 +36,8 @@ class AvalancheGetAccountsHandler walletType: WalletType ): Promise => { try { - // Only mnemonic and keystone wallets support xpubXP - if ( - walletType === WalletType.MNEMONIC || - walletType === WalletType.KEYSTONE - ) { - return await WalletService.getRawXpubXP({ walletId, walletType }) - } - return undefined + return await WalletService.getRawXpubXP({ walletId, walletType }) } catch (error) { - Logger.warn(`Failed to get xpubXP for wallet ${walletId}:`, error) return undefined } }