From 7c22f6ead00237159f52531746bbc356762ec794 Mon Sep 17 00:00:00 2001 From: Junghwan Date: Tue, 25 Nov 2025 15:32:57 -0500 Subject: [PATCH 1/7] x/p addresses with new account model --- .../hooks/send/utils/evm/validate.test.ts | 6 +- .../app/new/features/ledger/consts.ts | 2 + .../features/ledger/hooks/useLedgerWallet.ts | 3 +- .../components/CollectibleFetchAndRender.tsx | 11 +- .../app/services/account/AccountsService.tsx | 3 +- .../app/services/earn/EarnService.ts | 67 +++--- .../services/wallet/KeystoneWallet/index.ts | 11 +- .../app/services/wallet/LedgerWallet.ts | 2 +- .../app/services/wallet/MnemonicWallet.ts | 4 +- .../app/services/wallet/WalletService.tsx | 141 +++++++----- .../services/walletconnectv2/utils.test.ts | 3 +- .../core-mobile/app/store/account/utils.ts | 45 ---- packages/core-mobile/app/store/migrations.ts | 3 +- ...otificationsForActiveStakesPeriodically.ts | 2 +- .../avalanche_getAccounts.ts | 6 +- .../avalanche_getAddressesInRange.ts | 18 +- .../request/handleRequestViaVMModule.ts | 6 +- .../EncryptThenMacTransform.test.ts | 3 +- .../core-mobile/app/store/wallet/thunks.ts | 3 +- .../app/utils/getAddressesFromXpubXP.ts | 14 +- packages/core-mobile/app/utils/publicKeys.ts | 4 + packages/core-mobile/package.json | 26 +-- yarn.lock | 207 ++++++++++++------ 23 files changed, 345 insertions(+), 245 deletions(-) diff --git a/packages/core-mobile/app/new/common/hooks/send/utils/evm/validate.test.ts b/packages/core-mobile/app/new/common/hooks/send/utils/evm/validate.test.ts index 4d2663d1fe..b375693b01 100644 --- a/packages/core-mobile/app/new/common/hooks/send/utils/evm/validate.test.ts +++ b/packages/core-mobile/app/new/common/hooks/send/utils/evm/validate.test.ts @@ -109,7 +109,8 @@ describe('validate evm send', () => { logoSmall: 'logoSmall', logoUri: 'logoUri', collectionName: 'collectionName', - description: 'description' + description: 'description', + chainId: 1 } beforeEach(() => { @@ -145,7 +146,8 @@ describe('validate evm send', () => { logoSmall: 'logoSmall', logoUri: 'logoUri', collectionName: 'collectionName', - description: 'description' + description: 'description', + chainId: 1 } beforeEach(() => { diff --git a/packages/core-mobile/app/new/features/ledger/consts.ts b/packages/core-mobile/app/new/features/ledger/consts.ts index 0534ace65f..4ed61e0c29 100644 --- a/packages/core-mobile/app/new/features/ledger/consts.ts +++ b/packages/core-mobile/app/new/features/ledger/consts.ts @@ -34,6 +34,8 @@ export const SOLANA_DERIVATION_PATH_PREFIX = "44'/501'/0'/0'" // Deprecated Avalanche public key path prefix export const DEPRECATED_AVALANCHE_DERIVATION_PATH_PREFIX = "m/44'/9000'/0'" +export const AVALANCHE_DERIVATION_PATH_PREFIX = "m/44'/9000'" + /** * Generate a Solana derivation path for a specific account index * @param accountIndex - The account index to generate the path for diff --git a/packages/core-mobile/app/new/features/ledger/hooks/useLedgerWallet.ts b/packages/core-mobile/app/new/features/ledger/hooks/useLedgerWallet.ts index 290f121180..e3494d7204 100644 --- a/packages/core-mobile/app/new/features/ledger/hooks/useLedgerWallet.ts +++ b/packages/core-mobile/app/new/features/ledger/hooks/useLedgerWallet.ts @@ -572,7 +572,8 @@ export function useLedgerWallet(): UseLedgerWalletReturn { addressAVM: addresses.AVM, addressPVM: addresses.PVM, addressSVM: addresses.SVM, - addressCoreEth: addresses.CoreEth + addressCoreEth: addresses.CoreEth, + xpAddresses: [] // TODO: add xp addresses } dispatch(setAccount(newAccount)) diff --git a/packages/core-mobile/app/new/features/portfolio/collectibles/components/CollectibleFetchAndRender.tsx b/packages/core-mobile/app/new/features/portfolio/collectibles/components/CollectibleFetchAndRender.tsx index 6e83631f7f..81bccec765 100644 --- a/packages/core-mobile/app/new/features/portfolio/collectibles/components/CollectibleFetchAndRender.tsx +++ b/packages/core-mobile/app/new/features/portfolio/collectibles/components/CollectibleFetchAndRender.tsx @@ -28,6 +28,8 @@ export const CollectibleFetchAndRender = memo( const tokenId = token?.collectableTokenId?.toString() || '' const initialCollectible = useMemo(() => { + const chainId = Number(tx.chainId) + return { localId, type: token?.type as TokenType.ERC721 | TokenType.ERC1155, @@ -36,14 +38,15 @@ export const CollectibleFetchAndRender = memo( status: NftLocalStatus.Unprocessed, balance: BigInt(0), balanceDisplayValue: '', - networkChainId: Number(tx.chainId), + networkChainId: chainId, description: '', logoUri: '', logoSmall: '', name: '', symbol: '', tokenUri: '', - collectionName: '' + collectionName: '', + chainId } }, [localId, token?.type, tx.to, tx.chainId, tokenId]) @@ -69,6 +72,7 @@ export const CollectibleFetchAndRender = memo( processedMetadata.animation_url || processedMetadata.external_url ) + const chainId = Number(tx.chainId) setCollectible({ ...result, @@ -86,7 +90,8 @@ export const CollectibleFetchAndRender = memo( logoUri: '', logoSmall: '', collectionName: '', - networkChainId: Number(tx.chainId), + networkChainId: chainId, + chainId, symbol: '' }) } diff --git a/packages/core-mobile/app/services/account/AccountsService.tsx b/packages/core-mobile/app/services/account/AccountsService.tsx index f9d31775a9..20c993828c 100644 --- a/packages/core-mobile/app/services/account/AccountsService.tsx +++ b/packages/core-mobile/app/services/account/AccountsService.tsx @@ -150,7 +150,8 @@ class AccountsService { addressAVM: addresses[NetworkVMType.AVM], addressPVM: addresses[NetworkVMType.PVM], addressCoreEth: addresses[NetworkVMType.CoreEth], - addressSVM: addresses[NetworkVMType.SVM] + addressSVM: addresses[NetworkVMType.SVM], + xpAddresses: [] // TODO: add xp addresses } } diff --git a/packages/core-mobile/app/services/earn/EarnService.ts b/packages/core-mobile/app/services/earn/EarnService.ts index cb0247d89b..a5bed61db4 100644 --- a/packages/core-mobile/app/services/earn/EarnService.ts +++ b/packages/core-mobile/app/services/earn/EarnService.ts @@ -1,4 +1,4 @@ -import { Account, AccountCollection } from 'store/account/types' +import { Account } from 'store/account/types' import { importPWithBalanceCheck } from 'services/earn/importP' import Big from 'big.js' import { FujiParams, MainnetParams } from 'utils/NetworkParams' @@ -29,7 +29,7 @@ import AnalyticsService from 'services/analytics/AnalyticsService' import { TokenUnit } from '@avalabs/core-utils-sdk' import { Avalanche } from '@avalabs/core-wallets-sdk' import { AvaxXP } from 'types/AvaxXP' -import AccountsService from 'services/account/AccountsService' +import { NetworkVMType } from '@avalabs/core-chains-sdk' import { getTransformedTransactions, maxGetAtomicUTXOsRetries, @@ -352,7 +352,7 @@ class EarnService { }: { walletId: string walletType: WalletType - accounts: AccountCollection + accounts: Account[] isTestnet: boolean startTimestamp?: number }): Promise< @@ -365,44 +365,47 @@ class EarnService { }[] | undefined > => { - const accountsArray = Object.values(accounts) - try { - const currentNetworkAddresses = accountsArray - .map(account => account.addressPVM) - .filter((address): address is string => address !== undefined) - const currentNetworkTransactions = await getTransformedTransactions( - currentNetworkAddresses, + const currentNetworkAddresses = await WalletService.getXPAddresses({ + accounts, + walletId, + walletType, isTestnet, - startTimestamp - ) + networkType: NetworkVMType.PVM, + onlyWithActivity: true + }) + const currentNetworkTransactions = + currentNetworkAddresses.length > 0 + ? await getTransformedTransactions( + currentNetworkAddresses, + isTestnet, + startTimestamp + ) + : [] - const oppositeNetworkAddresses = ( - await Promise.all( - accountsArray.map(account => - AccountsService.getAddresses({ - walletId, - walletType, - accountIndex: account.index, - isTestnet - }) - ) - ) - ).map(address => address.PVM) - const oppositeNetworkTransactions = await getTransformedTransactions( - oppositeNetworkAddresses, - !isTestnet, - startTimestamp - ) + const oppositeNetworkAddresses = await WalletService.getXPAddresses({ + accounts, + walletId, + walletType, + isTestnet: !isTestnet, + networkType: NetworkVMType.PVM, + onlyWithActivity: true + }) + const oppositeNetworkTransactions = + oppositeNetworkAddresses.length > 0 + ? await getTransformedTransactions( + oppositeNetworkAddresses, + !isTestnet, + startTimestamp + ) + : [] const now = new Date() return currentNetworkTransactions .concat(oppositeNetworkTransactions) .flatMap(transaction => { // find account that matches the transaction's index - const account = accountsArray.find( - acc => acc.index === transaction.index - ) + const account = accounts.find(acc => acc.index === transaction.index) // flat map will remove this if (!account) return [] diff --git a/packages/core-mobile/app/services/wallet/KeystoneWallet/index.ts b/packages/core-mobile/app/services/wallet/KeystoneWallet/index.ts index 4708542b03..e04d40b034 100644 --- a/packages/core-mobile/app/services/wallet/KeystoneWallet/index.ts +++ b/packages/core-mobile/app/services/wallet/KeystoneWallet/index.ts @@ -89,6 +89,7 @@ export default class KeystoneWallet implements Wallet { s: string v: number }> { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const signature: any = ETHSignature.fromCBOR(cbor).getSignature() const r = hexlify(new Uint8Array(signature.slice(0, 32))) const s = hexlify(new Uint8Array(signature.slice(32, 64))) @@ -192,11 +193,9 @@ export default class KeystoneWallet implements Wallet { { masterFingerprint: Buffer.from(this.mfp, 'hex'), pubkey: getAddressPublicKeyFromXPub(this.xpub, accountIndex), - path: getAddressDerivationPath( - accountIndex, - DerivationPath.BIP44, - 'EVM' - ) + path: getAddressDerivationPath(accountIndex, 'EVM', { + pathSpec: DerivationPath.BIP44 + }) } ] }) @@ -238,6 +237,7 @@ export default class KeystoneWallet implements Wallet { return await signer(requestUR, ['avax-signature'], cbor => { const response = AvalancheSignature.fromCBOR(cbor) const sig = response.getSignature() + // eslint-disable-next-line @typescript-eslint/no-explicit-any tx.addSignature(sig as any) return Promise.resolve(JSON.stringify(tx.toJSON())) }) @@ -332,6 +332,7 @@ export default class KeystoneWallet implements Wallet { // This here is BIP44 for the first account (index 0). 2nd account should be M/44'/60'/0'/0/1, etc.. const keyPath = `${EVM_DERIVATION_PATH}/0/${activeAccountIndex}` const ethSignRequest = EthSignRequest.constructETHRequest( + // eslint-disable-next-line @typescript-eslint/no-explicit-any Buffer.from(message as any), dataType, keyPath, diff --git a/packages/core-mobile/app/services/wallet/LedgerWallet.ts b/packages/core-mobile/app/services/wallet/LedgerWallet.ts index b88e45c340..522fbaf653 100644 --- a/packages/core-mobile/app/services/wallet/LedgerWallet.ts +++ b/packages/core-mobile/app/services/wallet/LedgerWallet.ts @@ -828,7 +828,7 @@ export class LedgerWallet implements Wallet { } } - public async getRawXpubXP(): Promise { + public async getRawXpubXP(_accountIndex: number): Promise { // TODO: implement this throw new Error('getRawXpubXP not implemented yet for LedgerWallet') } diff --git a/packages/core-mobile/app/services/wallet/MnemonicWallet.ts b/packages/core-mobile/app/services/wallet/MnemonicWallet.ts index c687c3b35e..9be6993241 100644 --- a/packages/core-mobile/app/services/wallet/MnemonicWallet.ts +++ b/packages/core-mobile/app/services/wallet/MnemonicWallet.ts @@ -178,8 +178,8 @@ export class MnemonicWallet implements Wallet { this.#mnemonic = mnemonic } - public getRawXpubXP(): string { - return Avalanche.getXpubFromMnemonic(this.mnemonic) + public getRawXpubXP(accountIndex: number): string { + return Avalanche.getXpubFromMnemonic(this.mnemonic, accountIndex) } /** WALLET INTERFACE IMPLEMENTATION **/ diff --git a/packages/core-mobile/app/services/wallet/WalletService.tsx b/packages/core-mobile/app/services/wallet/WalletService.tsx index 9df112d877..8ff0af334a 100644 --- a/packages/core-mobile/app/services/wallet/WalletService.tsx +++ b/packages/core-mobile/app/services/wallet/WalletService.tsx @@ -37,8 +37,15 @@ import { import { UTCDate } from '@date-fns/utc' import { nanoToWei } from 'utils/units/converter' import { SpanName } from 'services/sentry/types' -import { Curve } from 'utils/publicKeys' +import { Curve, isAvalanchePublicKey } from 'utils/publicKeys' import fetchWithAppCheck from 'utils/httpClient' +import { + AVALANCHE_MAINNET_NETWORK, + AVALANCHE_TESTNET_NETWORK +} from 'services/network/consts' +import ModuleManager from 'vmModule/ModuleManager' +import { Network as VmNetwork } from '@avalabs/vm-module-types' +import { SeedlessPubKeysStorage } from 'seedless/services/storage/SeedlessPubKeysStorage' import { getAddressDerivationPath, getAssetId, @@ -244,10 +251,12 @@ class WalletService { public async getRawXpubXP({ walletId, - walletType + walletType, + accountIndex }: { walletId: string walletType: WalletType + accountIndex: number }): Promise { if (!this.hasXpub(walletType)) { throw new Error('Unable to get raw xpub XP: unsupported wallet type') @@ -268,25 +277,28 @@ class WalletService { ) } - return wallet.getRawXpubXP() + return wallet.getRawXpubXP(accountIndex) } public async getAddressesFromXpubXP({ walletId, walletType, + accountIndex, networkType, isTestnet = false, onlyWithActivity }: { walletId: string walletType: WalletType + accountIndex: number networkType: NetworkVMType.AVM | NetworkVMType.PVM isTestnet: boolean onlyWithActivity: boolean }): Promise { const xpubXP = await this.getRawXpubXP({ walletId, - walletType + walletType, + accountIndex }) try { @@ -311,57 +323,6 @@ class WalletService { } } - public async getAddressesByIndices({ - walletId, - walletType, - indices, - chainAlias, - isChange, - isTestnet - }: { - walletId: string - walletType: WalletType - indices: number[] - chainAlias: 'X' | 'P' - isChange: boolean - isTestnet: boolean - }): Promise { - if ( - walletType === WalletType.SEEDLESS || - walletType === WalletType.PRIVATE_KEY || - (isChange && chainAlias !== 'X') - ) { - return [] - } - - if ([WalletType.MNEMONIC, WalletType.KEYSTONE].includes(walletType)) { - const provXP = await NetworkService.getAvalancheProviderXP(isTestnet) - - const xpubXP = await this.getRawXpubXP({ walletId, walletType }) - - return xpubXP - ? indices.map(index => { - try { - return Avalanche.getAddressFromXpub( - xpubXP, - index, - provXP, - chainAlias, - isChange - ) - } catch (e) { - Logger.error('error getting address from xpub', e) - return '' - } - }) - : [] - } - - throw new Error( - 'Unable to get addresses by indices: unsupported wallet type' - ) - } - /** * Get atomic transactions that are in VM memory. */ @@ -480,7 +441,20 @@ class WalletService { avaxXPNetwork ) - const nonce = await readOnlySigner.getNonce() + // Get nonce from C-Chain EVM provider + const evmAddress = readOnlySigner.getAddressEVM() + // Get C-Chain network based on testnet flag + const cChainNetwork = avaxXPNetwork.isTestnet + ? AVALANCHE_TESTNET_NETWORK + : AVALANCHE_MAINNET_NETWORK + + const evmProvider = await NetworkService.getProviderForNetwork( + cChainNetwork + ) + if (!(evmProvider instanceof JsonRpcBatchInternal)) { + throw new Error('Unable to get nonce: wrong provider obtained') + } + const nonce = await evmProvider.getTransactionCount(evmAddress) const unsignedTx = readOnlySigner.exportC( amountInNAvax, @@ -983,6 +957,61 @@ class WalletService { Logger.info('burned amount is valid') } + + async getXPAddresses({ + accounts, + walletId, + walletType, + isTestnet, + networkType, + onlyWithActivity + }: { + accounts: Account[] + walletId: string + walletType: WalletType + isTestnet: boolean + networkType: NetworkVMType.AVM | NetworkVMType.PVM + onlyWithActivity: boolean + }): Promise { + if (this.hasXpub(walletType)) { + const promises = accounts + .map(account => account.index) + .map(accountIndex => + this.getAddressesFromXpubXP({ + walletId, + walletType, + networkType, + isTestnet, + accountIndex, + onlyWithActivity + }) + ) + + const networkAddresses = await Promise.all(promises) + return networkAddresses + .map(address => address.externalAddresses) + .flat() + .map(address => address.address) + } + + if (walletType === WalletType.SEEDLESS) { + const storedPubKeys = await SeedlessPubKeysStorage.retrieve() + const publicKeys = storedPubKeys.filter(isAvalanchePublicKey) + + const provider = await ModuleManager.avalancheModule.getProvider({ + isTestnet + } as VmNetwork) + return publicKeys.map(publicKey => { + const publicKeyXP = Buffer.from(publicKey.key, 'hex') + return provider.getAddress( + publicKeyXP, + networkType === NetworkVMType.AVM ? 'X' : 'P' + ) + }) + } + + return [] + } } // Keep as singleton diff --git a/packages/core-mobile/app/services/walletconnectv2/utils.test.ts b/packages/core-mobile/app/services/walletconnectv2/utils.test.ts index 23222cd5f4..d8110e2fcf 100644 --- a/packages/core-mobile/app/services/walletconnectv2/utils.test.ts +++ b/packages/core-mobile/app/services/walletconnectv2/utils.test.ts @@ -22,7 +22,8 @@ const mockAccount: CorePrimaryAccount = { addressBTC: 'BTCAddress', addressC: 'CAddress', addressCoreEth: 'CoreEthAddress', - addressSVM: 'SVMAddress' + addressSVM: 'SVMAddress', + xpAddresses: [] } describe('getCaip2ChainId', () => { diff --git a/packages/core-mobile/app/store/account/utils.ts b/packages/core-mobile/app/store/account/utils.ts index cd08b1ab73..be395447bc 100644 --- a/packages/core-mobile/app/store/account/utils.ts +++ b/packages/core-mobile/app/store/account/utils.ts @@ -3,7 +3,6 @@ import { Account } from 'store/account/types' import { Network, NetworkVMType } from '@avalabs/core-chains-sdk' import WalletFactory from 'services/wallet/WalletFactory' import { WalletType } from 'services/wallet/types' -import { uniqWith } from 'lodash' import SeedlessWallet from 'seedless/services/wallet/SeedlessWallet' import { transactionSnackbar } from 'common/utils/toast' import Logger from 'utils/Logger' @@ -16,7 +15,6 @@ import { commonStorage } from 'utils/mmkv' import { StorageKey } from 'resources/Constants' import { appendToStoredArray, loadArrayFromStorage } from 'utils/mmkv/storages' import { setIsMigratingActiveAccounts } from 'store/wallet/slice' -import WalletService from 'services/wallet/WalletService' import { selectWalletState, WalletState } from 'store/app' import { setAccounts, setNonActiveAccounts } from './slice' @@ -221,46 +219,3 @@ const markWalletAsMigrated = (walletId: string): void => { walletId ) } -export async function getAddressesForXP({ - isDeveloperMode, - walletId, - walletType, - networkType, - onlyWithActivity -}: { - isDeveloperMode: boolean - walletId: string | null - walletType: WalletType | undefined - networkType: NetworkVMType.AVM | NetworkVMType.PVM - onlyWithActivity: boolean -}): Promise { - if (!walletId) { - throw new Error('Wallet ID is required') - } - if (!walletType) { - throw new Error('Wallet type is unknown') - } - try { - const activeAddresses = await WalletService.getAddressesFromXpubXP({ - walletId, - walletType, - networkType, - isTestnet: isDeveloperMode, - onlyWithActivity - }) - - const externalAddresses = activeAddresses.externalAddresses.map( - address => address.address - ) - const internalAddresses = activeAddresses.internalAddresses.map( - address => address.address - ) - return uniqWith( - [...externalAddresses, ...internalAddresses], - (a, b) => a === b - ) - } catch (error) { - Logger.error('Failed to get addresses for XP', error) - throw new Error('Failed to get addresses for XP') - } -} diff --git a/packages/core-mobile/app/store/migrations.ts b/packages/core-mobile/app/store/migrations.ts index cf500765b1..985f46c7af 100644 --- a/packages/core-mobile/app/store/migrations.ts +++ b/packages/core-mobile/app/store/migrations.ts @@ -429,7 +429,8 @@ export const migrations = { // Add new/changed properties id: uuid(), walletId: activeWalletId, - index: index + index, + xpAddresses: [] } newAccountsCollection[newAccount.id] = newAccount diff --git a/packages/core-mobile/app/store/notifications/listeners/scheduleNotificationsForActiveStakesPeriodically.ts b/packages/core-mobile/app/store/notifications/listeners/scheduleNotificationsForActiveStakesPeriodically.ts index e5a58d9303..b15770cb83 100644 --- a/packages/core-mobile/app/store/notifications/listeners/scheduleNotificationsForActiveStakesPeriodically.ts +++ b/packages/core-mobile/app/store/notifications/listeners/scheduleNotificationsForActiveStakesPeriodically.ts @@ -100,7 +100,7 @@ const scheduleNotificationsForActiveStakes = async ( await EarnService.getTransformedStakesForAllAccounts({ walletId: activeWallet.id, walletType: activeWallet.type, - accounts, + accounts: Object.values(accounts), isTestnet: isDeveloperMode, startTimestamp }) 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 f7deb78518..09cbec09f3 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 @@ -36,7 +36,11 @@ class AvalancheGetAccountsHandler walletType: WalletType ): Promise => { try { - return await WalletService.getRawXpubXP({ walletId, walletType }) + return await WalletService.getRawXpubXP({ + walletId, + walletType, + accountIndex: activeAccount.index + }) } catch (error) { return undefined } diff --git a/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts b/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts index c7d5e5e458..0874012953 100644 --- a/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts +++ b/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts @@ -23,6 +23,7 @@ class AvalancheGetAddressesInRangeHandler const state = getState() const activeWallet = selectActiveWallet(state) const isDeveloperMode = selectIsDeveloperMode(state) + const activeAccount = selectActiveAccount(state) if (!activeWallet) { return { @@ -31,16 +32,14 @@ class AvalancheGetAddressesInRangeHandler } } - if (activeWallet.type === WalletType.PRIVATE_KEY) { - const activeAccount = selectActiveAccount(state) - - if (!activeAccount) { - return { - success: false, - error: rpcErrors.internal('No active account') - } + if (!activeAccount) { + return { + success: false, + error: rpcErrors.internal('No active account') } + } + if (activeWallet.type === WalletType.PRIVATE_KEY) { return { success: true, value: { @@ -71,7 +70,8 @@ class AvalancheGetAddressesInRangeHandler const addresses = await getAddressesFromXpubXP({ isDeveloperMode: isDeveloperMode, walletId: activeWallet.id, - walletType: activeWallet.type + walletType: activeWallet.type, + accountIndex: activeAccount.index }) return { success: true, value: addresses } } catch (e) { diff --git a/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts b/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts index 5460704b1c..1ac6017af0 100644 --- a/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts +++ b/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts @@ -154,7 +154,11 @@ const getContext = async ({ const context: Record = { currentAddress } if (walletType === WalletType.MNEMONIC && activeAccount) { - const xpubXP = await WalletService.getRawXpubXP({ walletId, walletType }) + const xpubXP = await WalletService.getRawXpubXP({ + walletId, + walletType, + accountIndex: activeAccount.index + }) if (xpubXP) { context.xpubXP = xpubXP diff --git a/packages/core-mobile/app/store/transforms/EncryptThenMacTransform.test.ts b/packages/core-mobile/app/store/transforms/EncryptThenMacTransform.test.ts index d16595140a..5cdcdd34d2 100644 --- a/packages/core-mobile/app/store/transforms/EncryptThenMacTransform.test.ts +++ b/packages/core-mobile/app/store/transforms/EncryptThenMacTransform.test.ts @@ -130,7 +130,8 @@ const initialState = { walletId: 'walletId0', walletType: WalletType.MNEMONIC, id: 'id0', - walletName: 'Wallet 1' + walletName: 'Wallet 1', + xpAddresses: [] } }, activeAccountId: '0' diff --git a/packages/core-mobile/app/store/wallet/thunks.ts b/packages/core-mobile/app/store/wallet/thunks.ts index c4b61c21fb..c05b959c8b 100644 --- a/packages/core-mobile/app/store/wallet/thunks.ts +++ b/packages/core-mobile/app/store/wallet/thunks.ts @@ -141,7 +141,8 @@ export const importMnemonicWalletAndAccount = createAsyncThunk< addressAVM: addresses.AVM, addressPVM: addresses.PVM, addressSVM: addresses.SVM, - addressCoreEth: addresses.CoreEth + addressCoreEth: addresses.CoreEth, + xpAddresses: [] // TODO: add xp addresses } dispatch(setAccount(newAccount)) diff --git a/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts b/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts index 2ec7654149..5d92bfb51d 100644 --- a/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts +++ b/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts @@ -43,23 +43,27 @@ const flattenAddresses = ( export const getAddressesFromXpubXP = async ({ isDeveloperMode, walletId, - walletType + walletType, + accountIndex }: { isDeveloperMode: boolean walletId: string walletType: WalletType + accountIndex: number }): Promise<{ external: string[]; internal: string[] }> => { const avmAddresses = await WalletService.getAddressesFromXpubXP({ - walletId: walletId, - walletType: walletType, + walletId, + walletType, + accountIndex, networkType: NetworkVMType.AVM, isTestnet: isDeveloperMode, onlyWithActivity: false }) const pvmAddresses = await WalletService.getAddressesFromXpubXP({ - walletId: walletId, - walletType: walletType, + walletId, + walletType, + accountIndex, networkType: NetworkVMType.PVM, isTestnet: isDeveloperMode, onlyWithActivity: false diff --git a/packages/core-mobile/app/utils/publicKeys.ts b/packages/core-mobile/app/utils/publicKeys.ts index 28c61b82e4..53be796687 100644 --- a/packages/core-mobile/app/utils/publicKeys.ts +++ b/packages/core-mobile/app/utils/publicKeys.ts @@ -1,4 +1,5 @@ import { NetworkVMType } from '@avalabs/vm-module-types' +import { AVALANCHE_DERIVATION_PATH_PREFIX } from 'features/ledger/consts' export const emptyAddresses = (): Record => ({ [NetworkVMType.AVM]: '', @@ -33,3 +34,6 @@ export type SeedlessPublicKeys = { export const isEvmPublicKey = (publicKey: AddressPublicKey): boolean => publicKey.derivationPath.startsWith(EVM_BASE_DERIVATION_PATH_PREFIX) + +export const isAvalanchePublicKey = (publicKey: AddressPublicKey): boolean => + publicKey.derivationPath.startsWith(AVALANCHE_DERIVATION_PATH_PREFIX) diff --git a/packages/core-mobile/package.json b/packages/core-mobile/package.json index 6fd36c3ddb..d9b6f3f6e7 100644 --- a/packages/core-mobile/package.json +++ b/packages/core-mobile/package.json @@ -25,22 +25,22 @@ "appium": "wdio run ./e2e-appium/wdio.conf.ts" }, "dependencies": { - "@avalabs/avalanche-module": "1.11.0", + "@avalabs/avalanche-module": "0.0.0-refactor-xp-derivation-paths-20251119091515", "@avalabs/avalanchejs": "5.1.0-alpha.2", - "@avalabs/bitcoin-module": "1.11.0", + "@avalabs/bitcoin-module": "0.0.0-refactor-xp-derivation-paths-20251119091515", "@avalabs/bridge-unified": "4.3.0", - "@avalabs/core-bridge-sdk": "3.1.0-alpha.61", - "@avalabs/core-chains-sdk": "3.1.0-alpha.61", - "@avalabs/core-coingecko-sdk": "3.1.0-alpha.61", - "@avalabs/core-gasless-sdk": "3.1.0-alpha.61", - "@avalabs/core-utils-sdk": "3.1.0-alpha.61", - "@avalabs/core-wallets-sdk": "3.1.0-alpha.61", - "@avalabs/evm-module": "1.11.0", - "@avalabs/glacier-sdk": "3.1.0-alpha.58", + "@avalabs/core-bridge-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/core-chains-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/core-coingecko-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/core-gasless-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/core-utils-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/core-wallets-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/evm-module": "0.0.0-refactor-xp-derivation-paths-20251119091515", + "@avalabs/glacier-sdk": "3.1.0-canary.4b3bc0b.0", "@avalabs/k2-alpine": "workspace:*", - "@avalabs/svm-module": "1.11.0", - "@avalabs/types": "3.1.0-alpha.58", - "@avalabs/vm-module-types": "1.11.0", + "@avalabs/svm-module": "0.0.0-refactor-xp-derivation-paths-20251119091515", + "@avalabs/types": "3.1.0-canary.4b3bc0b.0", + "@avalabs/vm-module-types": "0.0.0-refactor-xp-derivation-paths-20251119091515", "@babel/runtime": "7.25.7", "@bitcoinerlab/secp256k1": "1.2.0", "@blockaid/client": "0.48.0", diff --git a/yarn.lock b/yarn.lock index d3b6c96a80..fbca194797 100644 --- a/yarn.lock +++ b/yarn.lock @@ -225,9 +225,9 @@ __metadata: languageName: node linkType: hard -"@avalabs/avalanche-module@npm:1.11.0": - version: 1.11.0 - resolution: "@avalabs/avalanche-module@npm:1.11.0" +"@avalabs/avalanche-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515": + version: 0.0.0-refactor-xp-derivation-paths-20251119091515 + resolution: "@avalabs/avalanche-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515" dependencies: "@avalabs/avalanchejs": 5.1.0-alpha.2 "@avalabs/core-chains-sdk": 3.1.0-alpha.61 @@ -237,12 +237,12 @@ __metadata: "@avalabs/core-wallets-sdk": 3.1.0-alpha.61 "@avalabs/glacier-sdk": 3.1.0-alpha.61 "@avalabs/types": 3.1.0-alpha.61 - "@avalabs/vm-module-types": 1.11.0 + "@avalabs/vm-module-types": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@metamask/rpc-errors": 6.3.0 big.js: 6.2.1 bn.js: 5.2.1 zod: 3.23.8 - checksum: d401fb16a61dfb099fa36a01887baa1d2026edec22f35c363e9ebe2d384a8a085d47d0e0aa5bfcd92e4503417d24399053294bf82a92cf3004f067183645a67c + checksum: 9e9b0263500f4081739199de1a72c485ae2bb0325c1e8f7454cb7b66249d5aeec9b61be94f7395a6638ca62690ec6d7ae75821e2d645382e6dc68a685f1b9bd8 languageName: node linkType: hard @@ -259,20 +259,20 @@ __metadata: languageName: node linkType: hard -"@avalabs/bitcoin-module@npm:1.11.0": - version: 1.11.0 - resolution: "@avalabs/bitcoin-module@npm:1.11.0" +"@avalabs/bitcoin-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515": + version: 0.0.0-refactor-xp-derivation-paths-20251119091515 + resolution: "@avalabs/bitcoin-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515" dependencies: "@avalabs/core-coingecko-sdk": 3.1.0-alpha.61 "@avalabs/core-utils-sdk": 3.1.0-alpha.61 "@avalabs/core-wallets-sdk": 3.1.0-alpha.61 - "@avalabs/vm-module-types": 1.11.0 + "@avalabs/vm-module-types": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@metamask/rpc-errors": 6.3.0 big.js: 6.2.1 bitcoinjs-lib: 5.2.0 bn.js: 5.2.1 zod: 3.23.8 - checksum: b926cad8665c9b24578ba665078c42f11466f7721b1b5be40e7936ad17a501b16b2ae05f313497da5cb7abf1be1aebf575bdceb4d2eb5265f7af1428982a1864 + checksum: a4975668daa647ca7e74ca43ff49cab5a33b59c949b8ad92d2270c0e3e72ecdbc38656b1353cc2536ea2fc4d33a6fea6a7694cda29ff2cd1c68fc12f4aa7235f languageName: node linkType: hard @@ -292,20 +292,20 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-bridge-sdk@npm:3.1.0-alpha.61": - version: 3.1.0-alpha.61 - resolution: "@avalabs/core-bridge-sdk@npm:3.1.0-alpha.61" +"@avalabs/core-bridge-sdk@npm:3.1.0-canary.4b3bc0b.0": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/core-bridge-sdk@npm:3.1.0-canary.4b3bc0b.0" dependencies: - "@avalabs/core-coingecko-sdk": 3.1.0-alpha.61 - "@avalabs/core-utils-sdk": 3.1.0-alpha.61 - "@avalabs/core-wallets-sdk": 3.1.0-alpha.61 + "@avalabs/core-coingecko-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b + "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b + "@avalabs/core-wallets-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b peerDependencies: big.js: ^6.2.1 bitcoinjs-lib: ^5.2.0 coinselect: ^3.1.12 ethers: ^6.7.1 react: ^17.0.2 - checksum: 987a19958c567563cbc807d6ef658797544372303030f8f932dd840c5f043b96f3b45db964f37d971e7abe6e67af9ed5a60eef4c180e56247084506f8657eef2 + checksum: d14b0cf1870c642bb8c32607a2ed89b8b4c242f3dbcc15efa19b3147f85fa27467312f9c18adc7d6f35725ee85e4956df839e5e146d2246349bb77da487860b9 languageName: node linkType: hard @@ -318,6 +318,15 @@ __metadata: languageName: node linkType: hard +"@avalabs/core-chains-sdk@npm:3.1.0-canary.4b3bc0b.0": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/core-chains-sdk@npm:3.1.0-canary.4b3bc0b.0" + dependencies: + "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b + checksum: 4b8be834d3a827f359d67be49761dcb34048ef036ae222d19cea0acae5642fb0866098f888127a9d2c11107ea26e2ec39fd0c5b25fd26f3d062e3c84e85d1d59 + languageName: node + linkType: hard + "@avalabs/core-coingecko-sdk@npm:3.1.0-alpha.61": version: 3.1.0-alpha.61 resolution: "@avalabs/core-coingecko-sdk@npm:3.1.0-alpha.61" @@ -327,6 +336,15 @@ __metadata: languageName: node linkType: hard +"@avalabs/core-coingecko-sdk@npm:3.1.0-canary.4b3bc0b.0, @avalabs/core-coingecko-sdk@npm:3.1.0-canary.4b3bc0b.0+4b3bc0b": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/core-coingecko-sdk@npm:3.1.0-canary.4b3bc0b.0" + dependencies: + "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b + checksum: 595f3f19bf25642dc42e3396cba75637ad1cdd90fb5fa856aacf7fa5d9005df996d89c2b18d11ccde467eb5f94eee45a40b0b05c6da42c55ac00ff8005d83450 + languageName: node + linkType: hard + "@avalabs/core-etherscan-sdk@npm:3.1.0-alpha.61": version: 3.1.0-alpha.61 resolution: "@avalabs/core-etherscan-sdk@npm:3.1.0-alpha.61" @@ -336,13 +354,13 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-gasless-sdk@npm:3.1.0-alpha.61": - version: 3.1.0-alpha.61 - resolution: "@avalabs/core-gasless-sdk@npm:3.1.0-alpha.61" +"@avalabs/core-gasless-sdk@npm:3.1.0-canary.4b3bc0b.0": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/core-gasless-sdk@npm:3.1.0-canary.4b3bc0b.0" dependencies: "@noble/hashes": 1.7.1 zod: 3.23.8 - checksum: e90a984de51796dfd42b59e8faca06679bf7dfa23fb03e5766415841e9a98cbabaa883496642d3eb138e90e2c7c0b3862ce89282d1c6b9f509fd013e0b53eb60 + checksum: 547efb141d24af0d8f32dc799d499587c5f6cbcf6a181963c01007cbb67ecb2d037076373548f8aefbbbdc18bbd24587d8a319dee7be4cb490c60f19d3e5622f languageName: node linkType: hard @@ -350,23 +368,23 @@ __metadata: version: 0.0.0-use.local resolution: "@avalabs/core-mobile@workspace:packages/core-mobile" dependencies: - "@avalabs/avalanche-module": 1.11.0 + "@avalabs/avalanche-module": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@avalabs/avalanchejs": 5.1.0-alpha.2 - "@avalabs/bitcoin-module": 1.11.0 + "@avalabs/bitcoin-module": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@avalabs/bridge-unified": 4.3.0 - "@avalabs/core-bridge-sdk": 3.1.0-alpha.61 - "@avalabs/core-chains-sdk": 3.1.0-alpha.61 - "@avalabs/core-coingecko-sdk": 3.1.0-alpha.61 - "@avalabs/core-gasless-sdk": 3.1.0-alpha.61 - "@avalabs/core-utils-sdk": 3.1.0-alpha.61 - "@avalabs/core-wallets-sdk": 3.1.0-alpha.61 - "@avalabs/evm-module": 1.11.0 - "@avalabs/glacier-sdk": 3.1.0-alpha.58 + "@avalabs/core-bridge-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/core-chains-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/core-coingecko-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/core-gasless-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/core-wallets-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/evm-module": 0.0.0-refactor-xp-derivation-paths-20251119091515 + "@avalabs/glacier-sdk": 3.1.0-canary.4b3bc0b.0 "@avalabs/k2-alpine": "workspace:*" - "@avalabs/svm-module": 1.11.0 + "@avalabs/svm-module": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@avalabs/tsconfig-mobile": "workspace:*" - "@avalabs/types": 3.1.0-alpha.58 - "@avalabs/vm-module-types": 1.11.0 + "@avalabs/types": 3.1.0-canary.4b3bc0b.0 + "@avalabs/vm-module-types": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@babel/core": 7.28.0 "@babel/plugin-proposal-nullish-coalescing-operator": 7.18.6 "@babel/plugin-syntax-object-rest-spread": 7.8.3 @@ -685,6 +703,20 @@ __metadata: languageName: node linkType: hard +"@avalabs/core-utils-sdk@npm:3.1.0-canary.4b3bc0b.0, @avalabs/core-utils-sdk@npm:3.1.0-canary.4b3bc0b.0+4b3bc0b": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/core-utils-sdk@npm:3.1.0-canary.4b3bc0b.0" + dependencies: + "@hpke/core": 1.2.5 + is-ipfs: 6.0.2 + peerDependencies: + big.js: ^6.2.1 + bn.js: ^5.2.1 + ethers: ^6.7.1 + checksum: 399c93344853a1646de8bca5476800d98006125ae4410de124619b3612bc44874758b8842497172e9a484bbe6e46bed6f84adff7a622432d00a5bb4bb1ae5ec0 + languageName: node + linkType: hard + "@avalabs/core-wallets-sdk@npm:3.1.0-alpha.61": version: 3.1.0-alpha.61 resolution: "@avalabs/core-wallets-sdk@npm:3.1.0-alpha.61" @@ -721,9 +753,46 @@ __metadata: languageName: node linkType: hard -"@avalabs/evm-module@npm:1.11.0": - version: 1.11.0 - resolution: "@avalabs/evm-module@npm:1.11.0" +"@avalabs/core-wallets-sdk@npm:3.1.0-canary.4b3bc0b.0, @avalabs/core-wallets-sdk@npm:3.1.0-canary.4b3bc0b.0+4b3bc0b": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/core-wallets-sdk@npm:3.1.0-canary.4b3bc0b.0" + dependencies: + "@avalabs/avalanchejs": 5.1.0-alpha.2 + "@avalabs/core-chains-sdk": 3.1.0-alpha.61 + "@avalabs/core-utils-sdk": 3.1.0-alpha.61 + "@avalabs/glacier-sdk": 3.1.0-alpha.61 + "@avalabs/hw-app-avalanche": 1.1.1 + "@ledgerhq/hw-app-btc": 10.11.0 + "@ledgerhq/hw-app-eth": 6.45.18 + "@ledgerhq/hw-app-solana": 7.5.3 + "@ledgerhq/hw-transport": 6.31.10 + "@metamask/eth-sig-util": 7.0.2 + "@noble/curves": 1.6.0 + "@noble/hashes": 1.7.1 + "@scure/base": 1.2.4 + "@solana-program/system": 0.7.0 + "@solana-program/token": 0.5.1 + "@solana/kit": 2.1.0 + bip174: 2.1.1 + bip32: 2.0.6 + bip32-path: 0.4.2 + bip39: 3.1.0 + bitcoinjs-lib: 5.2.0 + coinselect: 3.1.13 + create-hash: 1.2.0 + hdkey: 2.0.1 + ledger-bitcoin: 0.2.3 + micro-key-producer: 0.7.5 + xss: 1.0.14 + peerDependencies: + ethers: ^6.7.1 + checksum: 888d0b1b764c2a76afe6c3f3bad863b8ffca540f8ec3ad02ee9bbe8a8b4efa6811f1bac74f1102f84e666c3a17cbb8876742152da99b038b7797fea00f0fb8a9 + languageName: node + linkType: hard + +"@avalabs/evm-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515": + version: 0.0.0-refactor-xp-derivation-paths-20251119091515 + resolution: "@avalabs/evm-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515" dependencies: "@avalabs/core-chains-sdk": 3.1.0-alpha.61 "@avalabs/core-coingecko-sdk": 3.1.0-alpha.61 @@ -732,7 +801,7 @@ __metadata: "@avalabs/core-wallets-sdk": 3.1.0-alpha.61 "@avalabs/glacier-sdk": 3.1.0-alpha.61 "@avalabs/types": 3.1.0-alpha.61 - "@avalabs/vm-module-types": 1.11.0 + "@avalabs/vm-module-types": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@blockaid/client": 0.48.0 "@metamask/rpc-errors": 6.3.0 "@openzeppelin/contracts": 4.9.6 @@ -742,14 +811,7 @@ __metadata: zod: 3.23.8 peerDependencies: ethers: 6.13.5 - checksum: 34e4a2e838f35bbe8a669c7529df366da3b279aa2bc69543ae97136af3e146883841944735d841526776d67d25de1f672cd299c075bc577f85503f55d28639df - languageName: node - linkType: hard - -"@avalabs/glacier-sdk@npm:3.1.0-alpha.58": - version: 3.1.0-alpha.58 - resolution: "@avalabs/glacier-sdk@npm:3.1.0-alpha.58" - checksum: 1d0b0b97b73f07cee1c41fd4f4b0692591b82a9f65852cadc15aca0e03f3fef76d77f7beb2e25d4fb82ddb8bbc81c68288c4df47e5c5dc8c6cd2ec9ec0b2e469 + checksum: 0732d98bca455374b7c767ffcc97b60f38565cd9256a1324480259517bafe777620e32d342b9a011cc1a438ba7fe897df50bafe93fc4387503cca7de399ad10c languageName: node linkType: hard @@ -760,6 +822,13 @@ __metadata: languageName: node linkType: hard +"@avalabs/glacier-sdk@npm:3.1.0-canary.4b3bc0b.0": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/glacier-sdk@npm:3.1.0-canary.4b3bc0b.0" + checksum: d68849b63aaeb2b62625cf2a330cd3b2a12eecc5e6d867af175d839bb8399e62d0b39fb1b93a2709c56d7a1ddb94a8fd5412baca2796f125d31278b080b0fe6f + languageName: node + linkType: hard + "@avalabs/hw-app-avalanche@npm:1.1.0": version: 1.1.0 resolution: "@avalabs/hw-app-avalanche@npm:1.1.0" @@ -772,6 +841,18 @@ __metadata: languageName: node linkType: hard +"@avalabs/hw-app-avalanche@npm:1.1.1": + version: 1.1.1 + resolution: "@avalabs/hw-app-avalanche@npm:1.1.1" + dependencies: + "@ledgerhq/hw-app-eth": 6.45.18 + "@ledgerhq/hw-transport": 6.31.10 + "@ledgerhq/types-live": 6.82.0 + bs58: 6.0.0 + checksum: 8b1918c378777e5c315558ffd81746fb0e768a9e6bee6eec8734cdd57e27597d12157c6e941f1c92cdb59c458c9e1f6de987db0a1a57161ade16a6af4fa110f1 + languageName: node + linkType: hard + "@avalabs/k2-alpine@workspace:*, @avalabs/k2-alpine@workspace:packages/k2-alpine": version: 0.0.0-use.local resolution: "@avalabs/k2-alpine@workspace:packages/k2-alpine" @@ -848,15 +929,15 @@ __metadata: languageName: unknown linkType: soft -"@avalabs/svm-module@npm:1.11.0": - version: 1.11.0 - resolution: "@avalabs/svm-module@npm:1.11.0" +"@avalabs/svm-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515": + version: 0.0.0-refactor-xp-derivation-paths-20251119091515 + resolution: "@avalabs/svm-module@npm:0.0.0-refactor-xp-derivation-paths-20251119091515" dependencies: "@avalabs/core-chains-sdk": 3.1.0-alpha.61 "@avalabs/core-coingecko-sdk": 3.1.0-alpha.61 "@avalabs/core-utils-sdk": 3.1.0-alpha.61 "@avalabs/core-wallets-sdk": 3.1.0-alpha.61 - "@avalabs/vm-module-types": 1.11.0 + "@avalabs/vm-module-types": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@blockaid/client": 0.48.0 "@metamask/rpc-errors": 6.3.0 "@scure/base": 1.2.4 @@ -867,7 +948,7 @@ __metadata: "@wallet-standard/base": 1.1.0 "@wallet-standard/features": 1.1.0 zod: 3.23.8 - checksum: 239cb64e19336ac983385116b65369bbaa014975aab042cb459a5971b5c767175138fe8daebb3694855da08c2fb30a935e5a83026880e03ee1d8b7deb203b53f + checksum: 9e4ce74903d31db5cb6f303abeb551b54178824e7c9ec60365d12de64110a77d7c693d2c05097dac7d72eb7694ae6964ba47f8b3ab4fdf1a97ed98bf1f3cf40c languageName: node linkType: hard @@ -877,13 +958,6 @@ __metadata: languageName: unknown linkType: soft -"@avalabs/types@npm:3.1.0-alpha.58": - version: 3.1.0-alpha.58 - resolution: "@avalabs/types@npm:3.1.0-alpha.58" - checksum: adcfbb800777981962a24e575e551be78c062bebcc32b6800af834d7a4e732b09109019f5e75d94c64ef7741cbde1d5948b84913678cb6c097d7bc78995689fb - languageName: node - linkType: hard - "@avalabs/types@npm:3.1.0-alpha.61": version: 3.1.0-alpha.61 resolution: "@avalabs/types@npm:3.1.0-alpha.61" @@ -891,9 +965,16 @@ __metadata: languageName: node linkType: hard -"@avalabs/vm-module-types@npm:1.11.0": - version: 1.11.0 - resolution: "@avalabs/vm-module-types@npm:1.11.0" +"@avalabs/types@npm:3.1.0-canary.4b3bc0b.0": + version: 3.1.0-canary.4b3bc0b.0 + resolution: "@avalabs/types@npm:3.1.0-canary.4b3bc0b.0" + checksum: 06b5c46895bb28e4b2ed0583c6aeb10365512da28283a94a068d830302eac9d853513ba68a7b6d3ec8acce78efd7cdcb77009f2eeb3395c325addbe070b316b4 + languageName: node + linkType: hard + +"@avalabs/vm-module-types@npm:0.0.0-refactor-xp-derivation-paths-20251119091515": + version: 0.0.0-refactor-xp-derivation-paths-20251119091515 + resolution: "@avalabs/vm-module-types@npm:0.0.0-refactor-xp-derivation-paths-20251119091515" dependencies: "@avalabs/core-wallets-sdk": 3.1.0-alpha.61 "@avalabs/glacier-sdk": 3.1.0-alpha.61 @@ -904,7 +985,7 @@ __metadata: zod: 3.23.8 peerDependencies: ethers: 6.13.5 - checksum: 895948b9d2a1bae2e2cf11f8c3ce8f6fb2c7a7858da0f71243ac97eaa48ed514f7a76c8e7cc314fc47f1bcfb318b58e07b0127cbd8d0ebb7311b71724066968e + checksum: 28204504ea8f7cfa40aaead3a6d1108faf2a07feba9c852f092afd0024cbf4827ddc432f289c423dec7524dd4dfbb7a47bbc54f27eda810ed5c29ef649a0e156 languageName: node linkType: hard @@ -33284,7 +33365,7 @@ react-native-webview@ava-labs/react-native-webview: peerDependencies: react: "*" react-native: "*" - checksum: e08d1254d04f3074970b63cdf0a363d6b189009270d457e868a26ef534addd69b320b85bef2a22e4eddb79006751bded431b56aaf2baf41976a6d0a5a2a2b91e + checksum: 44ee8c8ebc4dc4d3423e9045e1aebac31829eb518824e24f41b2bd10ab1e8343e824e9d912f259bfec7bfa798e96513cc05dbdcdf36087b2a43806f74a3b0fa2 languageName: node linkType: hard From 025d5338a7fbdd95cc3b476df1bf9cbe6c274510 Mon Sep 17 00:00:00 2001 From: Junghwan Date: Tue, 25 Nov 2025 16:15:41 -0500 Subject: [PATCH 2/7] fix --- packages/core-mobile/app/new/features/ledger/consts.ts | 5 ----- .../seedless/services/transformKeyInfosToPubkeys.ts | 7 +++++-- .../core-mobile/app/services/wallet/WalletService.tsx | 10 ++++++++-- packages/core-mobile/app/utils/publicKeys.ts | 9 +++++---- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/core-mobile/app/new/features/ledger/consts.ts b/packages/core-mobile/app/new/features/ledger/consts.ts index 4ed61e0c29..d0e96f34f4 100644 --- a/packages/core-mobile/app/new/features/ledger/consts.ts +++ b/packages/core-mobile/app/new/features/ledger/consts.ts @@ -31,11 +31,6 @@ export const SOLANA_DERIVATION_PATH = "44'/501'/0'/0'/0" // Solana derivation path prefix for generating indexed paths export const SOLANA_DERIVATION_PATH_PREFIX = "44'/501'/0'/0'" -// Deprecated Avalanche public key path prefix -export const DEPRECATED_AVALANCHE_DERIVATION_PATH_PREFIX = "m/44'/9000'/0'" - -export const AVALANCHE_DERIVATION_PATH_PREFIX = "m/44'/9000'" - /** * Generate a Solana derivation path for a specific account index * @param accountIndex - The account index to generate the path for diff --git a/packages/core-mobile/app/seedless/services/transformKeyInfosToPubkeys.ts b/packages/core-mobile/app/seedless/services/transformKeyInfosToPubkeys.ts index 7e8164009e..441d9f958b 100644 --- a/packages/core-mobile/app/seedless/services/transformKeyInfosToPubkeys.ts +++ b/packages/core-mobile/app/seedless/services/transformKeyInfosToPubkeys.ts @@ -1,7 +1,10 @@ import * as cs from '@cubist-labs/cubesigner-sdk' import { strip0x } from '@avalabs/core-utils-sdk' -import { AddressPublicKey, Curve } from 'utils/publicKeys' -import { DEPRECATED_AVALANCHE_DERIVATION_PATH_PREFIX } from 'features/ledger/consts' +import { + AddressPublicKey, + Curve, + DEPRECATED_AVALANCHE_DERIVATION_PATH_PREFIX +} from 'utils/publicKeys' export const transformKeyInfosToPubKeys = ( keyInfos: cs.KeyInfo[] diff --git a/packages/core-mobile/app/services/wallet/WalletService.tsx b/packages/core-mobile/app/services/wallet/WalletService.tsx index 8ff0af334a..cd3d885026 100644 --- a/packages/core-mobile/app/services/wallet/WalletService.tsx +++ b/packages/core-mobile/app/services/wallet/WalletService.tsx @@ -37,7 +37,7 @@ import { import { UTCDate } from '@date-fns/utc' import { nanoToWei } from 'utils/units/converter' import { SpanName } from 'services/sentry/types' -import { Curve, isAvalanchePublicKey } from 'utils/publicKeys' +import { AVALANCHE_DERIVATION_PATH_PREFIX, Curve } from 'utils/publicKeys' import fetchWithAppCheck from 'utils/httpClient' import { AVALANCHE_MAINNET_NETWORK, @@ -996,7 +996,13 @@ class WalletService { if (walletType === WalletType.SEEDLESS) { const storedPubKeys = await SeedlessPubKeysStorage.retrieve() - const publicKeys = storedPubKeys.filter(isAvalanchePublicKey) + const publicKeys = storedPubKeys.filter(publicKey => + accounts.some(account => + publicKey.derivationPath.startsWith( + AVALANCHE_DERIVATION_PATH_PREFIX + account.index + ) + ) + ) const provider = await ModuleManager.avalancheModule.getProvider({ isTestnet diff --git a/packages/core-mobile/app/utils/publicKeys.ts b/packages/core-mobile/app/utils/publicKeys.ts index 53be796687..35487fa21b 100644 --- a/packages/core-mobile/app/utils/publicKeys.ts +++ b/packages/core-mobile/app/utils/publicKeys.ts @@ -1,5 +1,4 @@ import { NetworkVMType } from '@avalabs/vm-module-types' -import { AVALANCHE_DERIVATION_PATH_PREFIX } from 'features/ledger/consts' export const emptyAddresses = (): Record => ({ [NetworkVMType.AVM]: '', @@ -22,6 +21,11 @@ export enum Curve { export const EVM_BASE_DERIVATION_PATH_PREFIX = "m/44'/60'/" export const SVM_BASE_DERIVATION_PATH_PREFIX = "m/44'/501'/" +// Deprecated Avalanche public key path prefix +export const DEPRECATED_AVALANCHE_DERIVATION_PATH_PREFIX = "m/44'/9000'/0'/" + +export const AVALANCHE_DERIVATION_PATH_PREFIX = "m/44'/9000'/" + export type AddressPublicKey = { curve: Curve derivationPath: string @@ -34,6 +38,3 @@ export type SeedlessPublicKeys = { export const isEvmPublicKey = (publicKey: AddressPublicKey): boolean => publicKey.derivationPath.startsWith(EVM_BASE_DERIVATION_PATH_PREFIX) - -export const isAvalanchePublicKey = (publicKey: AddressPublicKey): boolean => - publicKey.derivationPath.startsWith(AVALANCHE_DERIVATION_PATH_PREFIX) From c62b62d84edcea06873710705ddfcd9b58e18470 Mon Sep 17 00:00:00 2001 From: Junghwan Date: Tue, 25 Nov 2025 16:19:43 -0500 Subject: [PATCH 3/7] add comment --- .../app/services/wallet/WalletService.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/core-mobile/app/services/wallet/WalletService.tsx b/packages/core-mobile/app/services/wallet/WalletService.tsx index cd3d885026..db63158d1d 100644 --- a/packages/core-mobile/app/services/wallet/WalletService.tsx +++ b/packages/core-mobile/app/services/wallet/WalletService.tsx @@ -958,6 +958,25 @@ class WalletService { Logger.info('burned amount is valid') } + /** + * Get X-Chain or P-Chain addresses for the given accounts. + * + * This method retrieves all external addresses for the specified accounts on either X-Chain or P-Chain. + * It supports different wallet types with different derivation strategies: + * + * - **Xpub wallets (Mnemonic, Keystone, Ledger)**: Derives addresses from each account's extended public key + * - **Seedless wallets**: Retrieves addresses from stored public keys + * - **Other wallet types**: Returns an empty array + * + * @param accounts - Array of accounts to get addresses for + * @param walletId - Unique identifier of the wallet + * @param walletType - Type of wallet (Mnemonic, Keystone, Ledger, Seedless, etc.) + * @param isTestnet - Whether to use testnet or mainnet + * @param networkType - Chain type: NetworkVMType.AVM for X-Chain or NetworkVMType.PVM for P-Chain + * @param onlyWithActivity - If true, only return addresses that have been used (xpub wallets only) + * + * @returns Promise resolving to an array of addresses (e.g., ["avax1...", "avax2..."]) + */ async getXPAddresses({ accounts, walletId, From dfb67bf3927724da45e79570d9ef9c46fc2f7f2a Mon Sep 17 00:00:00 2001 From: Junghwan Date: Wed, 26 Nov 2025 09:14:31 -0500 Subject: [PATCH 4/7] fix --- .../avalanche_getAccounts.ts | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) 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 09cbec09f3..cc5fb9ed42 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 @@ -30,28 +30,12 @@ class AvalancheGetAccountsHandler } } - // Helper function to get xpubXP for supported wallet types - const getXpubXP = async ( - walletId: string, - walletType: WalletType - ): Promise => { - try { - return await WalletService.getRawXpubXP({ - walletId, - walletType, - accountIndex: activeAccount.index - }) - } catch (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) + ? await this.getXpubXP(account.walletId, wallet.type, account.index) : undefined return { @@ -66,6 +50,23 @@ class AvalancheGetAccountsHandler return { success: true, value: accountsArray } } + + // Helper function to get xpubXP for supported wallet types + private getXpubXP = async ( + walletId: string, + walletType: WalletType, + accountIndex: number + ): Promise => { + try { + return await WalletService.getRawXpubXP({ + walletId, + walletType, + accountIndex + }) + } catch (error) { + return undefined + } + } } export const avalancheGetAccountsHandler = new AvalancheGetAccountsHandler() From 31362c00f607fcf6eb82a431c6d698ff1ed81949 Mon Sep 17 00:00:00 2001 From: Junghwan Date: Wed, 26 Nov 2025 09:22:53 -0500 Subject: [PATCH 5/7] fix --- .../avalanche_getAccounts.ts | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) 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 cc5fb9ed42..9251fba814 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,9 +1,8 @@ import { AppListenerEffectAPI } from 'store/types' import { selectAccounts, selectActiveAccount } from 'store/account/slice' -import { selectWalletById } from 'store/wallet/slice' +import { selectActiveWallet } 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 { HandleResponse, RpcRequestHandler } from '../../types' @@ -21,7 +20,14 @@ class AvalancheGetAccountsHandler ): HandleResponse => { const state = listenerApi.getState() const accounts = selectAccounts(state) + const activeWallet = selectActiveWallet(state) const activeAccount = selectActiveAccount(state) + if (!activeWallet) { + return { + success: false, + error: rpcErrors.internal('no active wallet') + } + } if (!activeAccount) { return { @@ -33,15 +39,22 @@ class AvalancheGetAccountsHandler // 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 this.getXpubXP(account.walletId, wallet.type, account.index) - : undefined + let xpubXP + + try { + xpubXP = await WalletService.getRawXpubXP({ + walletId: activeWallet.id, + walletType: activeWallet.type, + accountIndex: account.index + }) + } catch (error) { + xpubXP = undefined + } return { ...account, - walletType: wallet?.type, - walletName: wallet?.name, + walletType: activeWallet.type, + walletName: activeWallet.name, xpubXP, active: account.id === activeAccount.id } @@ -50,23 +63,6 @@ class AvalancheGetAccountsHandler return { success: true, value: accountsArray } } - - // Helper function to get xpubXP for supported wallet types - private getXpubXP = async ( - walletId: string, - walletType: WalletType, - accountIndex: number - ): Promise => { - try { - return await WalletService.getRawXpubXP({ - walletId, - walletType, - accountIndex - }) - } catch (error) { - return undefined - } - } } export const avalancheGetAccountsHandler = new AvalancheGetAccountsHandler() From 4dfcec3bee503478aa48805f73a7a5a2bbd374a8 Mon Sep 17 00:00:00 2001 From: Junghwan Date: Wed, 26 Nov 2025 15:24:01 -0500 Subject: [PATCH 6/7] fix --- .../app/services/earn/EarnService.ts | 53 +++++--- .../app/services/profile/ProfileService.ts | 48 +++++++ .../app/services/wallet/WalletService.tsx | 113 ++++------------ .../core-mobile/app/services/wallet/types.ts | 6 + .../avalanche_getAccounts.test.ts | 18 ++- .../avalanche_getAccounts.ts | 42 +++--- .../avalanche_getAddressesInRange.test.ts | 7 +- .../avalanche_getAddressesInRange.ts | 10 +- .../request/handleRequestViaVMModule.ts | 63 +++++---- .../app/utils/getAddressesFromXpubXP.ts | 126 +++++++++++++----- packages/core-mobile/app/utils/publicKeys.ts | 11 ++ 11 files changed, 311 insertions(+), 186 deletions(-) create mode 100644 packages/core-mobile/app/services/profile/ProfileService.ts diff --git a/packages/core-mobile/app/services/earn/EarnService.ts b/packages/core-mobile/app/services/earn/EarnService.ts index a5bed61db4..838e0207f6 100644 --- a/packages/core-mobile/app/services/earn/EarnService.ts +++ b/packages/core-mobile/app/services/earn/EarnService.ts @@ -29,7 +29,6 @@ import AnalyticsService from 'services/analytics/AnalyticsService' import { TokenUnit } from '@avalabs/core-utils-sdk' import { Avalanche } from '@avalabs/core-wallets-sdk' import { AvaxXP } from 'types/AvaxXP' -import { NetworkVMType } from '@avalabs/core-chains-sdk' import { getTransformedTransactions, maxGetAtomicUTXOsRetries, @@ -366,35 +365,47 @@ class EarnService { | undefined > => { try { - const currentNetworkAddresses = await WalletService.getXPAddresses({ - accounts, - walletId, - walletType, - isTestnet, - networkType: NetworkVMType.PVM, - onlyWithActivity: true - }) + const currentNetworkAddressesPromises = accounts.map(account => + WalletService.getXPExternalAddresses({ + account, + walletId, + walletType, + isTestnet + }) + ) + const currentNetworkAddresses = await Promise.all( + currentNetworkAddressesPromises + ) + const currentNetworkAddressesArray = currentNetworkAddresses + .flat() + .map(address => address.address) const currentNetworkTransactions = - currentNetworkAddresses.length > 0 + currentNetworkAddressesArray.length > 0 ? await getTransformedTransactions( - currentNetworkAddresses, + currentNetworkAddressesArray, isTestnet, startTimestamp ) : [] - const oppositeNetworkAddresses = await WalletService.getXPAddresses({ - accounts, - walletId, - walletType, - isTestnet: !isTestnet, - networkType: NetworkVMType.PVM, - onlyWithActivity: true - }) + const oppositeNetworkAddressesPromises = accounts.map(account => + WalletService.getXPExternalAddresses({ + account, + walletId, + walletType, + isTestnet: !isTestnet + }) + ) + const oppositeNetworkAddresses = await Promise.all( + oppositeNetworkAddressesPromises + ) + const oppositeNetworkAddressesArray = oppositeNetworkAddresses + .flat() + .map(address => address.address) const oppositeNetworkTransactions = - oppositeNetworkAddresses.length > 0 + oppositeNetworkAddressesArray.length > 0 ? await getTransformedTransactions( - oppositeNetworkAddresses, + oppositeNetworkAddressesArray, !isTestnet, startTimestamp ) diff --git a/packages/core-mobile/app/services/profile/ProfileService.ts b/packages/core-mobile/app/services/profile/ProfileService.ts new file mode 100644 index 0000000000..d38b86d63c --- /dev/null +++ b/packages/core-mobile/app/services/profile/ProfileService.ts @@ -0,0 +1,48 @@ +import { NetworkVMType } from '@avalabs/vm-module-types' +import Config from 'react-native-config' +import { NetworkAddresses } from 'services/wallet/types' +import fetchWithAppCheck from 'utils/httpClient' +import Logger from 'utils/Logger' + +if (!Config.CORE_PROFILE_URL) { + Logger.warn( + 'CORE_PROFILE_URL is missing. Profile service may not work properly.' + ) +} + +class ProfileService { + public async fetchXPAddresses({ + xpubXP, + networkType, + isTestnet = false, + onlyWithActivity + }: { + xpubXP: string + networkType: NetworkVMType.AVM | NetworkVMType.PVM + isTestnet: boolean + onlyWithActivity: boolean + }): Promise { + try { + const res = await fetchWithAppCheck( + `${Config.CORE_PROFILE_URL}/v1/get-addresses`, + JSON.stringify({ + networkType: networkType, + extendedPublicKey: xpubXP, + isTestnet, + onlyWithActivity + }) + ) + + if (!res.ok) { + throw new Error(`${res.status}:${res.statusText}`) + } + + return res.json() + } catch (err) { + Logger.error(`[ProfileService][fetchXPAddresses]${err}`) + throw err + } + } +} + +export default new ProfileService() diff --git a/packages/core-mobile/app/services/wallet/WalletService.tsx b/packages/core-mobile/app/services/wallet/WalletService.tsx index db63158d1d..4fba693c44 100644 --- a/packages/core-mobile/app/services/wallet/WalletService.tsx +++ b/packages/core-mobile/app/services/wallet/WalletService.tsx @@ -1,4 +1,3 @@ -import Config from 'react-native-config' import { Avalanche, BitcoinProvider, @@ -12,7 +11,6 @@ import { CreateImportCTxParams, CreateImportPTxParams, CreateSendPTxParams, - NetworkAddresses, PubKeyType, SignTransactionRequest, Wallet, @@ -37,8 +35,11 @@ import { import { UTCDate } from '@date-fns/utc' import { nanoToWei } from 'utils/units/converter' import { SpanName } from 'services/sentry/types' -import { AVALANCHE_DERIVATION_PATH_PREFIX, Curve } from 'utils/publicKeys' -import fetchWithAppCheck from 'utils/httpClient' +import { + AVALANCHE_DERIVATION_PATH_PREFIX, + Curve, + getXPAddressIndexFromDerivationPath +} from 'utils/publicKeys' import { AVALANCHE_MAINNET_NETWORK, AVALANCHE_TESTNET_NETWORK @@ -46,6 +47,9 @@ import { import ModuleManager from 'vmModule/ModuleManager' import { Network as VmNetwork } from '@avalabs/vm-module-types' import { SeedlessPubKeysStorage } from 'seedless/services/storage/SeedlessPubKeysStorage' +import { getAddressesFromXpubXP } from 'utils/getAddressesFromXpubXP' +import { xpAddressWithoutPrefix } from 'common/utils/xpAddressWIthoutPrefix' +import { AddressIndex } from '@avalabs/types' import { getAddressDerivationPath, getAssetId, @@ -280,49 +284,6 @@ class WalletService { return wallet.getRawXpubXP(accountIndex) } - public async getAddressesFromXpubXP({ - walletId, - walletType, - accountIndex, - networkType, - isTestnet = false, - onlyWithActivity - }: { - walletId: string - walletType: WalletType - accountIndex: number - networkType: NetworkVMType.AVM | NetworkVMType.PVM - isTestnet: boolean - onlyWithActivity: boolean - }): Promise { - const xpubXP = await this.getRawXpubXP({ - walletId, - walletType, - accountIndex - }) - - try { - const res = await fetchWithAppCheck( - `${Config.CORE_PROFILE_URL}/v1/get-addresses`, - JSON.stringify({ - networkType: networkType, - extendedPublicKey: xpubXP, - isTestnet, - onlyWithActivity - }) - ) - - if (!res.ok) { - throw new Error(`${res.status}:${res.statusText}`) - } - - return res.json() - } catch (err) { - Logger.error(`[WalletService.ts][getAddressesFromXpubXP]${err}`) - throw err - } - } - /** * Get atomic transactions that are in VM memory. */ @@ -968,58 +929,39 @@ class WalletService { * - **Seedless wallets**: Retrieves addresses from stored public keys * - **Other wallet types**: Returns an empty array * - * @param accounts - Array of accounts to get addresses for + * @param account - account to get addresses for * @param walletId - Unique identifier of the wallet * @param walletType - Type of wallet (Mnemonic, Keystone, Ledger, Seedless, etc.) * @param isTestnet - Whether to use testnet or mainnet - * @param networkType - Chain type: NetworkVMType.AVM for X-Chain or NetworkVMType.PVM for P-Chain - * @param onlyWithActivity - If true, only return addresses that have been used (xpub wallets only) * * @returns Promise resolving to an array of addresses (e.g., ["avax1...", "avax2..."]) */ - async getXPAddresses({ - accounts, + async getXPExternalAddresses({ walletId, walletType, - isTestnet, - networkType, - onlyWithActivity + account, + isTestnet }: { - accounts: Account[] + account: Account walletId: string walletType: WalletType isTestnet: boolean - networkType: NetworkVMType.AVM | NetworkVMType.PVM - onlyWithActivity: boolean - }): Promise { + }): Promise { if (this.hasXpub(walletType)) { - const promises = accounts - .map(account => account.index) - .map(accountIndex => - this.getAddressesFromXpubXP({ - walletId, - walletType, - networkType, - isTestnet, - accountIndex, - onlyWithActivity - }) - ) - - const networkAddresses = await Promise.all(promises) - return networkAddresses - .map(address => address.externalAddresses) - .flat() - .map(address => address.address) + const networkAddresses = await getAddressesFromXpubXP({ + isTestnet, + walletId, + walletType, + accountIndex: account.index + }) + return networkAddresses.externalAddresses } if (walletType === WalletType.SEEDLESS) { const storedPubKeys = await SeedlessPubKeysStorage.retrieve() const publicKeys = storedPubKeys.filter(publicKey => - accounts.some(account => - publicKey.derivationPath.startsWith( - AVALANCHE_DERIVATION_PATH_PREFIX + account.index - ) + publicKey.derivationPath.startsWith( + AVALANCHE_DERIVATION_PATH_PREFIX + account.index ) ) @@ -1028,10 +970,11 @@ class WalletService { } as VmNetwork) return publicKeys.map(publicKey => { const publicKeyXP = Buffer.from(publicKey.key, 'hex') - return provider.getAddress( - publicKeyXP, - networkType === NetworkVMType.AVM ? 'X' : 'P' - ) + const address = provider.getAddress(publicKeyXP, 'P') + return { + address: xpAddressWithoutPrefix(address), + index: getXPAddressIndexFromDerivationPath(publicKey.derivationPath) + } }) } diff --git a/packages/core-mobile/app/services/wallet/types.ts b/packages/core-mobile/app/services/wallet/types.ts index b9cf2f1292..9bacbf5e5d 100644 --- a/packages/core-mobile/app/services/wallet/types.ts +++ b/packages/core-mobile/app/services/wallet/types.ts @@ -16,6 +16,7 @@ import { } from '@avalabs/vm-module-types' import { SolanaProvider } from '@avalabs/core-wallets-sdk' import { Curve } from 'utils/publicKeys' +import { AddressIndex } from '@avalabs/types' export type SignTransactionRequest = | TransactionRequest @@ -268,3 +269,8 @@ export interface NetworkAddresses { externalAddresses: { address: string; index: number; hasActivity: boolean }[] internalAddresses: { address: string; index: number; hasActivity: boolean }[] } + +export type NormalizedXPAddresses = { + externalAddresses: AddressIndex[] + internalAddresses: AddressIndex[] +} 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 330dafe65e..42f27dc7f1 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,14 @@ jest.mock('store/account/slice', () => { } }) +jest.mock('store/settings/advanced', () => { + const actual = jest.requireActual('store/settings/advanced') + return { + ...actual, + selectIsDeveloperMode: () => true + } +}) + jest.mock('store/wallet/slice', () => ({ selectWalletById: () => () => ({ id: 'wallet-1', @@ -27,7 +35,8 @@ jest.mock('services/wallet/WalletService', () => ({ .fn() .mockResolvedValue( 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' - ) + ), + getXPExternalAddresses: jest.fn().mockResolvedValue([]) } })) @@ -89,7 +98,8 @@ describe('avalanche_getAccounts handler', () => { walletType: 'MNEMONIC', walletName: 'Test Wallet', xpubXP: - 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' + 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5', + xpAddresses: [] }, { id: '1', @@ -107,7 +117,8 @@ describe('avalanche_getAccounts handler', () => { walletType: 'MNEMONIC', walletName: 'Test Wallet', xpubXP: - 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' + 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5', + xpAddresses: [] } ] }) @@ -132,6 +143,7 @@ describe('avalanche_getAccounts handler', () => { expect(result.success).toBe(true) if (result.success) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const accounts = result.value as any[] expect(accounts).toHaveLength(2) expect(accounts[0].xpubXP).toBeUndefined() 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 9251fba814..0a241c1a30 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,9 +1,11 @@ import { AppListenerEffectAPI } from 'store/types' import { selectAccounts, selectActiveAccount } from 'store/account/slice' -import { selectActiveWallet } from 'store/wallet/slice' +import { selectWalletById } from 'store/wallet/slice' import { RpcMethod, RpcRequest } from 'store/rpc/types' import { rpcErrors } from '@metamask/rpc-errors' import WalletService from 'services/wallet/WalletService' +import { getXpubXPIfAvailable } from 'utils/getAddressesFromXpubXP' +import { selectIsDeveloperMode } from 'store/settings/advanced' import { HandleResponse, RpcRequestHandler } from '../../types' export type AvalancheGetAccountsRpcRequest = @@ -20,42 +22,44 @@ class AvalancheGetAccountsHandler ): HandleResponse => { const state = listenerApi.getState() const accounts = selectAccounts(state) - const activeWallet = selectActiveWallet(state) const activeAccount = selectActiveAccount(state) - if (!activeWallet) { + const isDeveloperMode = selectIsDeveloperMode(state) + if (!activeAccount) { return { success: false, - error: rpcErrors.internal('no active wallet') + error: rpcErrors.internal('no active account') } } - - if (!activeAccount) { + const wallet = selectWalletById(activeAccount.walletId)(state) + if (!wallet) { return { success: false, - error: rpcErrors.internal('no active account') + error: rpcErrors.internal('no active wallet') } } // Process accounts and add xpubXP where available const accountsArray = await Promise.all( Object.values(accounts).map(async account => { - let xpubXP + const xpubXP = await getXpubXPIfAvailable({ + walletId: wallet.id, + walletType: wallet.type, + accountIndex: account.index + }) - try { - xpubXP = await WalletService.getRawXpubXP({ - walletId: activeWallet.id, - walletType: activeWallet.type, - accountIndex: account.index - }) - } catch (error) { - xpubXP = undefined - } + const xpAddresses = await WalletService.getXPExternalAddresses({ + account, + walletId: wallet.id, + walletType: wallet.type, + isTestnet: isDeveloperMode + }) return { ...account, - walletType: activeWallet.type, - walletName: activeWallet.name, + walletType: wallet.type, + walletName: wallet.name, xpubXP, + xpAddresses, active: account.id === activeAccount.id } }) diff --git a/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.test.ts b/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.test.ts index 026d6508d2..51a17da4dd 100644 --- a/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.test.ts +++ b/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.test.ts @@ -36,8 +36,11 @@ jest.mock('store/account/slice', () => { jest .spyOn(getAddressesFromXpubXPModule, 'getAddressesFromXpubXP') .mockResolvedValue({ - external: ['fuji1abc', 'fuji1def'], - internal: ['fuji1ghi'] + externalAddresses: [ + { address: 'fuji1abc', index: 0 }, + { address: 'fuji1def', index: 1 } + ], + internalAddresses: [{ address: 'fuji1ghi', index: 0 }] }) const createRequest = (): AvalancheGetAddressesInRangeRpcRequest => ({ diff --git a/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts b/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts index 0874012953..d1df827b75 100644 --- a/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts +++ b/packages/core-mobile/app/store/rpc/handlers/avalanche_getAddressesInRange/avalanche_getAddressesInRange.ts @@ -68,12 +68,18 @@ class AvalancheGetAddressesInRangeHandler try { const addresses = await getAddressesFromXpubXP({ - isDeveloperMode: isDeveloperMode, + isTestnet: isDeveloperMode, walletId: activeWallet.id, walletType: activeWallet.type, accountIndex: activeAccount.index }) - return { success: true, value: addresses } + return { + success: true, + value: { + external: addresses.externalAddresses.map(address => address.address), + internal: addresses.internalAddresses.map(address => address.address) + } + } } catch (e) { return { success: false, diff --git a/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts b/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts index 1ac6017af0..b3f96a9616 100644 --- a/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts +++ b/packages/core-mobile/app/store/rpc/listeners/request/handleRequestViaVMModule.ts @@ -15,6 +15,9 @@ import { Account, selectActiveAccount } from 'store/account' import { selectActiveWallet } from 'store/wallet/slice' import { WalletType } from 'services/wallet/types' import WalletService from 'services/wallet/WalletService' +import { CurrentAvalancheAccount } from '@avalabs/avalanche-module' +import { selectIsDeveloperMode } from 'store/settings/advanced' +import { getXpubXPIfAvailable } from 'utils/getAddressesFromXpubXP' import { AgnosticRpcProvider, Request } from '../../types' export const handleRequestViaVMModule = async ({ @@ -67,8 +70,10 @@ export const handleRequestViaVMModule = async ({ } const { getState } = listenerApi - const activeAccount = selectActiveAccount(getState()) - const activeWallet = selectActiveWallet(getState()) + const state = getState() + const activeAccount = selectActiveAccount(state) + const activeWallet = selectActiveWallet(state) + const isDeveloperMode = selectIsDeveloperMode(state) if (!activeWallet || !activeAccount) { Logger.error('Active wallet or account not found') @@ -102,7 +107,8 @@ export const handleRequestViaVMModule = async ({ params, activeAccount, walletId: activeWallet.id, - walletType: activeWallet.type + walletType: activeWallet.type, + isTestnet: isDeveloperMode })) }, mapToVmNetwork(network) @@ -128,14 +134,16 @@ const getContext = async ({ params, activeAccount, walletId, - walletType + walletType, + isTestnet }: { method: VmModuleRpcMethod params: unknown activeAccount: Account | undefined walletId: string walletType: WalletType -}): Promise | undefined> => { + isTestnet: boolean +}): Promise | undefined> => { if ( method === VmModuleRpcMethod.AVALANCHE_SEND_TRANSACTION || method === VmModuleRpcMethod.AVALANCHE_SIGN_TRANSACTION @@ -144,24 +152,33 @@ const getContext = async ({ return undefined } - const vm = Avalanche.getVmByChainAlias(params.chainAlias as string) - const currentAddress = getAddressByVM(vm, activeAccount) - - if (!currentAddress) { - return undefined - } - - const context: Record = { currentAddress } - - if (walletType === WalletType.MNEMONIC && activeAccount) { - const xpubXP = await WalletService.getRawXpubXP({ - walletId, - walletType, - accountIndex: activeAccount.index - }) - - if (xpubXP) { - context.xpubXP = xpubXP + const context: Record = {} + + if (activeAccount) { + const vm = Avalanche.getVmByChainAlias(params.chainAlias as string) + const currentAddress = getAddressByVM(vm, activeAccount) + + if (currentAddress && (vm === 'AVM' || vm === 'PVM')) { + const xpubXP = await getXpubXPIfAvailable({ + walletId, + walletType, + accountIndex: activeAccount.index + }) + + const externalXPAddresses = await WalletService.getXPExternalAddresses({ + account: activeAccount, + walletId, + walletType, + isTestnet + }) + const account: CurrentAvalancheAccount = { + xpAddress: currentAddress, + evmAddress: activeAccount.addressC, + xpubXP, + externalXPAddresses + } + + context.account = account } } diff --git a/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts b/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts index 5d92bfb51d..df1967a013 100644 --- a/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts +++ b/packages/core-mobile/app/utils/getAddressesFromXpubXP.ts @@ -1,12 +1,12 @@ import { NetworkVMType } from '@avalabs/core-chains-sdk' import WalletService from 'services/wallet/WalletService' -import { WalletType, NetworkAddresses } from 'services/wallet/types' +import { + WalletType, + NetworkAddresses, + NormalizedXPAddresses +} from 'services/wallet/types' import { xpAddressWithoutPrefix } from 'new/common/utils/xpAddressWIthoutPrefix' - -type FlattenedAddresses = { - external: string[] - internal: string[] -} +import ProfileService from 'services/profile/ProfileService' const isResponseLonger = ( response1: NetworkAddresses, @@ -15,59 +15,123 @@ const isResponseLonger = ( return response1.externalAddresses.length > response2.externalAddresses.length } -const flattenAddresses = ( +/** + * Merges P-Chain and X-Chain addresses and removes duplicates. + * + * Since P-Chain and X-Chain use the same underlying addresses (just different prefixes), + * we merge them and deduplicate based on the address string without prefix. + * + * @param pAddresses - P-Chain addresses + * @param xAddresses - X-Chain addresses + * @returns Merged and deduplicated addresses for external and internal + */ +const mergeAddresses = ( pAddresses: NetworkAddresses, xAddresses: NetworkAddresses -): FlattenedAddresses => { +): NormalizedXPAddresses => { + // Use the longer response for external addresses to ensure we get all addresses const longerResponse = isResponseLonger(pAddresses, xAddresses) ? pAddresses : xAddresses - const external = Array.from( - new Set( - longerResponse.externalAddresses.map(a => - xpAddressWithoutPrefix(a.address) - ) - ) + // Merge and deduplicate external addresses using Map (address as key) + const externalMap = new Map() + + for (const addr of longerResponse.externalAddresses) { + const addressWithoutPrefix = xpAddressWithoutPrefix(addr.address) + // Keep the first occurrence (or you could keep the one with lower index) + if (!externalMap.has(addressWithoutPrefix)) { + externalMap.set(addressWithoutPrefix, addr.index) + } + } + + const externalAddresses = Array.from(externalMap.entries()).map( + ([address, index]) => ({ + address, + index + }) ) - const internal = Array.from( - new Set( - xAddresses.internalAddresses.map(a => xpAddressWithoutPrefix(a.address)) - ) + // Merge and deduplicate internal addresses + // Note: X-Chain typically has internal addresses, but we check both just in case + const internalMap = new Map() + + const allInternalAddresses = [ + ...xAddresses.internalAddresses, + ...pAddresses.internalAddresses + ] + + for (const addr of allInternalAddresses) { + const addressWithoutPrefix = xpAddressWithoutPrefix(addr.address) + if (!internalMap.has(addressWithoutPrefix)) { + internalMap.set(addressWithoutPrefix, addr.index) + } + } + + const internalAddresses = Array.from(internalMap.entries()).map( + ([address, index]) => ({ + address, + index + }) ) - return { external, internal } + return { externalAddresses, internalAddresses } } export const getAddressesFromXpubXP = async ({ - isDeveloperMode, + isTestnet, walletId, walletType, accountIndex }: { - isDeveloperMode: boolean + isTestnet: boolean walletId: string walletType: WalletType accountIndex: number -}): Promise<{ external: string[]; internal: string[] }> => { - const avmAddresses = await WalletService.getAddressesFromXpubXP({ +}): Promise => { + const xpubXP = await WalletService.getRawXpubXP({ walletId, walletType, - accountIndex, + accountIndex + }) + + const avmAddresses = await ProfileService.fetchXPAddresses({ + xpubXP, networkType: NetworkVMType.AVM, - isTestnet: isDeveloperMode, + isTestnet, onlyWithActivity: false }) - const pvmAddresses = await WalletService.getAddressesFromXpubXP({ - walletId, - walletType, - accountIndex, + const pvmAddresses = await ProfileService.fetchXPAddresses({ + xpubXP, networkType: NetworkVMType.PVM, - isTestnet: isDeveloperMode, + isTestnet, onlyWithActivity: false }) - return flattenAddresses(pvmAddresses, avmAddresses) + return mergeAddresses(pvmAddresses, avmAddresses) +} + +export const getXpubXPIfAvailable = async ({ + walletId, + walletType, + accountIndex +}: { + walletId: string + walletType: WalletType + accountIndex: number +}): Promise => { + let xpubXP + + try { + xpubXP = await WalletService.getRawXpubXP({ + walletId, + walletType, + accountIndex + }) + } catch (error) { + xpubXP = undefined + } + + return xpubXP } diff --git a/packages/core-mobile/app/utils/publicKeys.ts b/packages/core-mobile/app/utils/publicKeys.ts index 35487fa21b..668ada7f66 100644 --- a/packages/core-mobile/app/utils/publicKeys.ts +++ b/packages/core-mobile/app/utils/publicKeys.ts @@ -38,3 +38,14 @@ export type SeedlessPublicKeys = { export const isEvmPublicKey = (publicKey: AddressPublicKey): boolean => publicKey.derivationPath.startsWith(EVM_BASE_DERIVATION_PATH_PREFIX) + +export const getXPAddressIndexFromDerivationPath = (path: string): number => { + const unprefixed = path.replace('m/', '') + const [, , , , addressIndex] = unprefixed.split('/') + + if (!addressIndex) { + throw new Error('Invalid legacy X/P derivation path:' + path) + } + + return parseInt(addressIndex) +} From 0635849fc1843571a2db0a57f7d824af5a7fd330 Mon Sep 17 00:00:00 2001 From: Junghwan Date: Mon, 1 Dec 2025 13:29:14 -0500 Subject: [PATCH 7/7] update sdks --- packages/core-mobile/package.json | 16 +++--- yarn.lock | 90 +++++++++++++++---------------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/packages/core-mobile/package.json b/packages/core-mobile/package.json index d9b6f3f6e7..0d40abe738 100644 --- a/packages/core-mobile/package.json +++ b/packages/core-mobile/package.json @@ -29,17 +29,17 @@ "@avalabs/avalanchejs": "5.1.0-alpha.2", "@avalabs/bitcoin-module": "0.0.0-refactor-xp-derivation-paths-20251119091515", "@avalabs/bridge-unified": "4.3.0", - "@avalabs/core-bridge-sdk": "3.1.0-canary.4b3bc0b.0", - "@avalabs/core-chains-sdk": "3.1.0-canary.4b3bc0b.0", - "@avalabs/core-coingecko-sdk": "3.1.0-canary.4b3bc0b.0", - "@avalabs/core-gasless-sdk": "3.1.0-canary.4b3bc0b.0", - "@avalabs/core-utils-sdk": "3.1.0-canary.4b3bc0b.0", - "@avalabs/core-wallets-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/core-bridge-sdk": "3.1.0-canary.e97ea02.0", + "@avalabs/core-chains-sdk": "3.1.0-canary.e97ea02.0", + "@avalabs/core-coingecko-sdk": "3.1.0-canary.e97ea02.0", + "@avalabs/core-gasless-sdk": "3.1.0-canary.e97ea02.0", + "@avalabs/core-utils-sdk": "3.1.0-canary.e97ea02.0", + "@avalabs/core-wallets-sdk": "3.1.0-canary.e97ea02.0", "@avalabs/evm-module": "0.0.0-refactor-xp-derivation-paths-20251119091515", - "@avalabs/glacier-sdk": "3.1.0-canary.4b3bc0b.0", + "@avalabs/glacier-sdk": "3.1.0-canary.e97ea02.0", "@avalabs/k2-alpine": "workspace:*", "@avalabs/svm-module": "0.0.0-refactor-xp-derivation-paths-20251119091515", - "@avalabs/types": "3.1.0-canary.4b3bc0b.0", + "@avalabs/types": "3.1.0-canary.e97ea02.0", "@avalabs/vm-module-types": "0.0.0-refactor-xp-derivation-paths-20251119091515", "@babel/runtime": "7.25.7", "@bitcoinerlab/secp256k1": "1.2.0", diff --git a/yarn.lock b/yarn.lock index fbca194797..1e81ff1c2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -292,20 +292,20 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-bridge-sdk@npm:3.1.0-canary.4b3bc0b.0": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/core-bridge-sdk@npm:3.1.0-canary.4b3bc0b.0" +"@avalabs/core-bridge-sdk@npm:3.1.0-canary.e97ea02.0": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/core-bridge-sdk@npm:3.1.0-canary.e97ea02.0" dependencies: - "@avalabs/core-coingecko-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b - "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b - "@avalabs/core-wallets-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b + "@avalabs/core-coingecko-sdk": 3.1.0-canary.e97ea02.0+e97ea02 + "@avalabs/core-utils-sdk": 3.1.0-canary.e97ea02.0+e97ea02 + "@avalabs/core-wallets-sdk": 3.1.0-canary.e97ea02.0+e97ea02 peerDependencies: big.js: ^6.2.1 bitcoinjs-lib: ^5.2.0 coinselect: ^3.1.12 ethers: ^6.7.1 react: ^17.0.2 - checksum: d14b0cf1870c642bb8c32607a2ed89b8b4c242f3dbcc15efa19b3147f85fa27467312f9c18adc7d6f35725ee85e4956df839e5e146d2246349bb77da487860b9 + checksum: 93617ffec4bda00e3214fa8ff27b1618d86f28666d430ca94041bf38addfd773a02d03826ae8659e6150d1a750ab467367f254e1be38c89049725bcd1bac696a languageName: node linkType: hard @@ -318,12 +318,12 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-chains-sdk@npm:3.1.0-canary.4b3bc0b.0": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/core-chains-sdk@npm:3.1.0-canary.4b3bc0b.0" +"@avalabs/core-chains-sdk@npm:3.1.0-canary.e97ea02.0": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/core-chains-sdk@npm:3.1.0-canary.e97ea02.0" dependencies: - "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b - checksum: 4b8be834d3a827f359d67be49761dcb34048ef036ae222d19cea0acae5642fb0866098f888127a9d2c11107ea26e2ec39fd0c5b25fd26f3d062e3c84e85d1d59 + "@avalabs/core-utils-sdk": 3.1.0-canary.e97ea02.0+e97ea02 + checksum: 3d0bfea4102dc3c201721bb2345de1d2d38ab5071ededec06ac320815f6f2898bca2d253ccd61fb46c9d3c1750e5a021c16658fd9ad33a148046f73430677e6f languageName: node linkType: hard @@ -336,12 +336,12 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-coingecko-sdk@npm:3.1.0-canary.4b3bc0b.0, @avalabs/core-coingecko-sdk@npm:3.1.0-canary.4b3bc0b.0+4b3bc0b": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/core-coingecko-sdk@npm:3.1.0-canary.4b3bc0b.0" +"@avalabs/core-coingecko-sdk@npm:3.1.0-canary.e97ea02.0, @avalabs/core-coingecko-sdk@npm:3.1.0-canary.e97ea02.0+e97ea02": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/core-coingecko-sdk@npm:3.1.0-canary.e97ea02.0" dependencies: - "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0+4b3bc0b - checksum: 595f3f19bf25642dc42e3396cba75637ad1cdd90fb5fa856aacf7fa5d9005df996d89c2b18d11ccde467eb5f94eee45a40b0b05c6da42c55ac00ff8005d83450 + "@avalabs/core-utils-sdk": 3.1.0-canary.e97ea02.0+e97ea02 + checksum: a08f2406e79e290572fa23bbe091d2748021fa033c14bb2f11c068555516dfbbf2554ff545285f9141b01ad520f836c565b1830e278d13e364ba9eab6f546662 languageName: node linkType: hard @@ -354,13 +354,13 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-gasless-sdk@npm:3.1.0-canary.4b3bc0b.0": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/core-gasless-sdk@npm:3.1.0-canary.4b3bc0b.0" +"@avalabs/core-gasless-sdk@npm:3.1.0-canary.e97ea02.0": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/core-gasless-sdk@npm:3.1.0-canary.e97ea02.0" dependencies: "@noble/hashes": 1.7.1 zod: 3.23.8 - checksum: 547efb141d24af0d8f32dc799d499587c5f6cbcf6a181963c01007cbb67ecb2d037076373548f8aefbbbdc18bbd24587d8a319dee7be4cb490c60f19d3e5622f + checksum: 6c75ad13707f4184117ce273dc9c1884b1f3edece9bd0bb7ab99f1f46c2c184fa5a0cfd77113beac59d4a1174155ae8fdb695ad32ef80d48acc964c3cb8fd5cb languageName: node linkType: hard @@ -372,18 +372,18 @@ __metadata: "@avalabs/avalanchejs": 5.1.0-alpha.2 "@avalabs/bitcoin-module": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@avalabs/bridge-unified": 4.3.0 - "@avalabs/core-bridge-sdk": 3.1.0-canary.4b3bc0b.0 - "@avalabs/core-chains-sdk": 3.1.0-canary.4b3bc0b.0 - "@avalabs/core-coingecko-sdk": 3.1.0-canary.4b3bc0b.0 - "@avalabs/core-gasless-sdk": 3.1.0-canary.4b3bc0b.0 - "@avalabs/core-utils-sdk": 3.1.0-canary.4b3bc0b.0 - "@avalabs/core-wallets-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/core-bridge-sdk": 3.1.0-canary.e97ea02.0 + "@avalabs/core-chains-sdk": 3.1.0-canary.e97ea02.0 + "@avalabs/core-coingecko-sdk": 3.1.0-canary.e97ea02.0 + "@avalabs/core-gasless-sdk": 3.1.0-canary.e97ea02.0 + "@avalabs/core-utils-sdk": 3.1.0-canary.e97ea02.0 + "@avalabs/core-wallets-sdk": 3.1.0-canary.e97ea02.0 "@avalabs/evm-module": 0.0.0-refactor-xp-derivation-paths-20251119091515 - "@avalabs/glacier-sdk": 3.1.0-canary.4b3bc0b.0 + "@avalabs/glacier-sdk": 3.1.0-canary.e97ea02.0 "@avalabs/k2-alpine": "workspace:*" "@avalabs/svm-module": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@avalabs/tsconfig-mobile": "workspace:*" - "@avalabs/types": 3.1.0-canary.4b3bc0b.0 + "@avalabs/types": 3.1.0-canary.e97ea02.0 "@avalabs/vm-module-types": 0.0.0-refactor-xp-derivation-paths-20251119091515 "@babel/core": 7.28.0 "@babel/plugin-proposal-nullish-coalescing-operator": 7.18.6 @@ -703,9 +703,9 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-utils-sdk@npm:3.1.0-canary.4b3bc0b.0, @avalabs/core-utils-sdk@npm:3.1.0-canary.4b3bc0b.0+4b3bc0b": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/core-utils-sdk@npm:3.1.0-canary.4b3bc0b.0" +"@avalabs/core-utils-sdk@npm:3.1.0-canary.e97ea02.0, @avalabs/core-utils-sdk@npm:3.1.0-canary.e97ea02.0+e97ea02": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/core-utils-sdk@npm:3.1.0-canary.e97ea02.0" dependencies: "@hpke/core": 1.2.5 is-ipfs: 6.0.2 @@ -713,7 +713,7 @@ __metadata: big.js: ^6.2.1 bn.js: ^5.2.1 ethers: ^6.7.1 - checksum: 399c93344853a1646de8bca5476800d98006125ae4410de124619b3612bc44874758b8842497172e9a484bbe6e46bed6f84adff7a622432d00a5bb4bb1ae5ec0 + checksum: 205a9b5b7511ea6335b6ca5d0aaa66a7c092eb4c429ce63fc692d972587b1ab3118a127f2ef810231e00b03d5cc8801cfc0fca084f003a8053e8ae2c5fcd173e languageName: node linkType: hard @@ -753,9 +753,9 @@ __metadata: languageName: node linkType: hard -"@avalabs/core-wallets-sdk@npm:3.1.0-canary.4b3bc0b.0, @avalabs/core-wallets-sdk@npm:3.1.0-canary.4b3bc0b.0+4b3bc0b": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/core-wallets-sdk@npm:3.1.0-canary.4b3bc0b.0" +"@avalabs/core-wallets-sdk@npm:3.1.0-canary.e97ea02.0, @avalabs/core-wallets-sdk@npm:3.1.0-canary.e97ea02.0+e97ea02": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/core-wallets-sdk@npm:3.1.0-canary.e97ea02.0" dependencies: "@avalabs/avalanchejs": 5.1.0-alpha.2 "@avalabs/core-chains-sdk": 3.1.0-alpha.61 @@ -786,7 +786,7 @@ __metadata: xss: 1.0.14 peerDependencies: ethers: ^6.7.1 - checksum: 888d0b1b764c2a76afe6c3f3bad863b8ffca540f8ec3ad02ee9bbe8a8b4efa6811f1bac74f1102f84e666c3a17cbb8876742152da99b038b7797fea00f0fb8a9 + checksum: 95a6f70cd79c6cd3a541c0f40065d0f5adfb2f9faad0a2160a6151d39868f3c1ebb971174d201468d2ec47e0b86ba2dacb1072527aa9bd54cce43bb5ea74b1c1 languageName: node linkType: hard @@ -822,10 +822,10 @@ __metadata: languageName: node linkType: hard -"@avalabs/glacier-sdk@npm:3.1.0-canary.4b3bc0b.0": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/glacier-sdk@npm:3.1.0-canary.4b3bc0b.0" - checksum: d68849b63aaeb2b62625cf2a330cd3b2a12eecc5e6d867af175d839bb8399e62d0b39fb1b93a2709c56d7a1ddb94a8fd5412baca2796f125d31278b080b0fe6f +"@avalabs/glacier-sdk@npm:3.1.0-canary.e97ea02.0": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/glacier-sdk@npm:3.1.0-canary.e97ea02.0" + checksum: ff7c9ab2980210738bd3062b4b9f4549f0a8cc62967df2c78364bee9140f12cec7ac2d26cf5a6f563f8c83fbb0653c599ae33f1d9741284eb56f949ce83e6657 languageName: node linkType: hard @@ -965,10 +965,10 @@ __metadata: languageName: node linkType: hard -"@avalabs/types@npm:3.1.0-canary.4b3bc0b.0": - version: 3.1.0-canary.4b3bc0b.0 - resolution: "@avalabs/types@npm:3.1.0-canary.4b3bc0b.0" - checksum: 06b5c46895bb28e4b2ed0583c6aeb10365512da28283a94a068d830302eac9d853513ba68a7b6d3ec8acce78efd7cdcb77009f2eeb3395c325addbe070b316b4 +"@avalabs/types@npm:3.1.0-canary.e97ea02.0": + version: 3.1.0-canary.e97ea02.0 + resolution: "@avalabs/types@npm:3.1.0-canary.e97ea02.0" + checksum: 4f716bb04010e593ff3f7edc24e6a465c34fd854cd27076b6653ca84f9a390d15026445b333e69114f16489cf8df62410df1e9b4486983e12283433a460b987e languageName: node linkType: hard