Skip to content

Commit a24e624

Browse files
B0Y3R-AVAatn4z7
andauthored
CP-12379: Add xpub to avalanche get accounts (#3291)
Co-authored-by: An Nguyen <[email protected]>
1 parent 0043a5e commit a24e624

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.test.ts

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,29 @@ jest.mock('store/account/slice', () => {
1212
}
1313
})
1414

15+
jest.mock('store/wallet/slice', () => ({
16+
selectWalletById: () => () => ({
17+
id: 'wallet-1',
18+
name: 'Test Wallet',
19+
type: 'MNEMONIC'
20+
})
21+
}))
22+
23+
jest.mock('services/wallet/WalletService', () => ({
24+
__esModule: true,
25+
default: {
26+
getRawXpubXP: jest
27+
.fn()
28+
.mockResolvedValue(
29+
'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'
30+
)
31+
}
32+
}))
33+
34+
jest.mock('utils/Logger', () => ({
35+
warn: jest.fn()
36+
}))
37+
1538
const mockDispatch = jest.fn()
1639
const mockListenerApi = {
1740
getState: jest.fn(),
@@ -44,7 +67,7 @@ describe('avalanche_getAccounts handler', () => {
4467
})
4568

4669
describe('handle', () => {
47-
it('should return success with the list of available accounts', async () => {
70+
it('should return success with the list of available accounts including xpubXP for mnemonic wallets', async () => {
4871
const result = await handler.handle(testRequest, mockListenerApi)
4972

5073
expect(result).toEqual({
@@ -63,7 +86,10 @@ describe('avalanche_getAccounts handler', () => {
6386
active: true,
6487
type: 'primary',
6588
walletId: 'wallet-1',
66-
walletType: 'mnemonic'
89+
walletType: 'MNEMONIC',
90+
walletName: 'Test Wallet',
91+
xpubXP:
92+
'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'
6793
},
6894
{
6995
id: '1',
@@ -78,10 +104,40 @@ describe('avalanche_getAccounts handler', () => {
78104
active: false,
79105
type: 'primary',
80106
walletId: 'wallet-1',
81-
walletType: 'mnemonic'
107+
walletType: 'MNEMONIC',
108+
walletName: 'Test Wallet',
109+
xpubXP:
110+
'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'
82111
}
83112
]
84113
})
85114
})
115+
116+
it('should return accounts without xpubXP for non-supported wallet types', async () => {
117+
// Mock a Ledger wallet (doesn't support xpubXP)
118+
const mockWalletSlice = require('store/wallet/slice')
119+
mockWalletSlice.selectWalletById = () => () => ({
120+
id: 'wallet-1',
121+
name: 'Ledger Wallet',
122+
type: 'LEDGER'
123+
})
124+
125+
// Mock WalletService to throw error for Ledger wallets
126+
const mockWalletService = require('services/wallet/WalletService')
127+
mockWalletService.default.getRawXpubXP.mockRejectedValueOnce(
128+
new Error('Unsupported wallet type')
129+
)
130+
131+
const result = await handler.handle(testRequest, mockListenerApi)
132+
133+
expect(result.success).toBe(true)
134+
if (result.success) {
135+
const accounts = result.value as any[]
136+
expect(accounts).toHaveLength(2)
137+
expect(accounts[0].xpubXP).toBeUndefined()
138+
expect(accounts[0].walletType).toBe('LEDGER')
139+
expect(accounts[0].walletName).toBe('Ledger Wallet')
140+
}
141+
})
86142
})
87143
})

packages/core-mobile/app/store/rpc/handlers/account/avalanche_getAccounts/avalanche_getAccounts.ts

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { AppListenerEffectAPI } from 'store/types'
22
import { selectAccounts, selectActiveAccount } from 'store/account/slice'
3+
import { selectWalletById } from 'store/wallet/slice'
34
import { RpcMethod, RpcRequest } from 'store/rpc/types'
45
import { rpcErrors } from '@metamask/rpc-errors'
6+
import { WalletType } from 'services/wallet/types'
7+
import WalletService from 'services/wallet/WalletService'
58
import { HandleResponse, RpcRequestHandler } from '../../types'
69

710
export type AvalancheGetAccountsRpcRequest =
@@ -16,20 +19,47 @@ class AvalancheGetAccountsHandler
1619
_request: AvalancheGetAccountsRpcRequest,
1720
listenerApi: AppListenerEffectAPI
1821
): HandleResponse => {
19-
const accounts = selectAccounts(listenerApi.getState())
20-
const activeAccount = selectActiveAccount(listenerApi.getState())
21-
if (!activeAccount)
22+
const state = listenerApi.getState()
23+
const accounts = selectAccounts(state)
24+
const activeAccount = selectActiveAccount(state)
25+
26+
if (!activeAccount) {
2227
return {
2328
success: false,
2429
error: rpcErrors.internal('no active account')
2530
}
31+
}
2632

27-
const accountsArray = Object.values(accounts).map(account => {
28-
return {
29-
...account,
30-
active: account.id === activeAccount.id
33+
// Helper function to get xpubXP for supported wallet types
34+
const getXpubXP = async (
35+
walletId: string,
36+
walletType: WalletType
37+
): Promise<string | undefined> => {
38+
try {
39+
return await WalletService.getRawXpubXP({ walletId, walletType })
40+
} catch (error) {
41+
return undefined
3142
}
32-
})
43+
}
44+
45+
// Process accounts and add xpubXP where available
46+
const accountsArray = await Promise.all(
47+
Object.values(accounts).map(async account => {
48+
const wallet = selectWalletById(account.walletId)(state)
49+
const xpubXP = wallet
50+
? await getXpubXP(account.walletId, wallet.type)
51+
: undefined
52+
53+
return {
54+
...account,
55+
walletType: wallet?.type,
56+
walletName: wallet?.name,
57+
xpubXP,
58+
active: account.id === activeAccount.id
59+
}
60+
})
61+
)
62+
3363
return { success: true, value: accountsArray }
3464
}
3565
}

0 commit comments

Comments
 (0)