From 51a711c20d45611c6cd38c4a1f4fb3479fe5dfc0 Mon Sep 17 00:00:00 2001 From: Ulisses Ferreira Date: Wed, 2 Sep 2026 18:31:08 +0100 Subject: [PATCH] feat(solana-wallet-snap)!: remove asset handler entry points Remove the onAssetsLookup, onAssetsConversion, onAssetHistoricalPrice, and onAssetsMarketData entry points, along with their now-unused handler modules and the endowment:assets permission. Closes WPN-2013 --- packages/solana-wallet-snap/CHANGELOG.md | 4 + .../solana-wallet-snap/snap.manifest.json | 8 +- .../onAssetHistoricalPrice.ts | 29 -- .../onAssetsConversion/onAssetsConversion.ts | 17 - .../handlers/onAssetsLookup/onAssetsLookup.ts | 30 -- .../onAssetsMarketData.test.ts | 358 ------------------ .../onAssetsMarketData/onAssetsMarketData.ts | 14 - packages/solana-wallet-snap/src/index.ts | 38 -- 8 files changed, 5 insertions(+), 493 deletions(-) delete mode 100644 packages/solana-wallet-snap/src/core/handlers/onAssetHistoricalPrice/onAssetHistoricalPrice.ts delete mode 100644 packages/solana-wallet-snap/src/core/handlers/onAssetsConversion/onAssetsConversion.ts delete mode 100644 packages/solana-wallet-snap/src/core/handlers/onAssetsLookup/onAssetsLookup.ts delete mode 100644 packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.test.ts delete mode 100644 packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.ts diff --git a/packages/solana-wallet-snap/CHANGELOG.md b/packages/solana-wallet-snap/CHANGELOG.md index 2858f3678..aee74261d 100644 --- a/packages/solana-wallet-snap/CHANGELOG.md +++ b/packages/solana-wallet-snap/CHANGELOG.md @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING** Bump `@metamask/keyring-snap-sdk` from `^9.2.1` to `^10.0.0` ([#214](https://github.com/MetaMask/internal-snaps/pull/214)) - **BREAKING** Bump `@metamask/snaps-sdk` from `^11.2.0` to `^12.0.1` ([#214](https://github.com/MetaMask/internal-snaps/pull/214)) +### Removed + +- **BREAKING** Remove the `onAssetsLookup`, `onAssetsConversion`, `onAssetHistoricalPrice`, and `onAssetsMarketData` asset handler entry points, along with the now-unused handler modules and the `endowment:assets` permission ([#261](https://github.com/MetaMask/internal-snaps/pull/261)) + ### Fixed - **BREAKING:** Preserve dapp-origin `signTransaction` and `signAndSendTransaction` payloads by signing the decoded transaction directly ([#156](https://github.com/MetaMask/internal-snaps/pull/156)) diff --git a/packages/solana-wallet-snap/snap.manifest.json b/packages/solana-wallet-snap/snap.manifest.json index ff45fdc18..f2d8330cd 100644 --- a/packages/solana-wallet-snap/snap.manifest.json +++ b/packages/solana-wallet-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "f67A1dy0bXl9jvoMuZ4heLBBs+m6bwaU20/WT30COeU=", + "shasum": "SLP6+V5eWfI09hpvzSBX5nyYVIAsPuy8INl53rSg+1k=", "location": { "npm": { "filePath": "dist/bundle.js", @@ -73,12 +73,6 @@ } } }, - "endowment:assets": { - "scopes": [ - "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", - "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" - ] - }, "endowment:name-lookup": { "chains": [ "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", diff --git a/packages/solana-wallet-snap/src/core/handlers/onAssetHistoricalPrice/onAssetHistoricalPrice.ts b/packages/solana-wallet-snap/src/core/handlers/onAssetHistoricalPrice/onAssetHistoricalPrice.ts deleted file mode 100644 index 0bf2461a7..000000000 --- a/packages/solana-wallet-snap/src/core/handlers/onAssetHistoricalPrice/onAssetHistoricalPrice.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { OnAssetHistoricalPriceHandler } from '@metamask/snaps-sdk'; -import { assert } from '@metamask/superstruct'; -import { CaipAssetTypeStruct } from '@metamask/utils'; - -import { tokenPricesService } from '../../../snapContext'; -import logger from '../../utils/logger'; - -/** - * Implements the `onAssetHistoricalPrice` handler. - * - * @see https://github.com/MetaMask/SIPs/blob/main/SIPS/sip-29.md#get-assets-historical-price - * @param params - The parameters for the `onAssetHistoricalPrice` handler. - * @returns The historical price of the asset pair. - */ -export const onAssetHistoricalPrice: OnAssetHistoricalPriceHandler = async ( - params, -) => { - logger.log('[📈 onAssetHistoricalPrice]', params); - - const { from, to } = params; - assert(from, CaipAssetTypeStruct); - assert(to, CaipAssetTypeStruct); - - const historicalPrice = await tokenPricesService.getHistoricalPrice(from, to); - - return { - historicalPrice, - }; -}; diff --git a/packages/solana-wallet-snap/src/core/handlers/onAssetsConversion/onAssetsConversion.ts b/packages/solana-wallet-snap/src/core/handlers/onAssetsConversion/onAssetsConversion.ts deleted file mode 100644 index fef0f375c..000000000 --- a/packages/solana-wallet-snap/src/core/handlers/onAssetsConversion/onAssetsConversion.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { OnAssetsConversionHandler } from '@metamask/snaps-sdk'; - -import { tokenPricesService } from '../../../snapContext'; -import logger from '../../utils/logger'; - -export const onAssetsConversion: OnAssetsConversionHandler = async (params) => { - logger.log('[💱 onAssetsConversion]', params); - - const { conversions } = params; - - const conversionRates = - await tokenPricesService.getMultipleTokenConversions(conversions); - - return { - conversionRates, - }; -}; diff --git a/packages/solana-wallet-snap/src/core/handlers/onAssetsLookup/onAssetsLookup.ts b/packages/solana-wallet-snap/src/core/handlers/onAssetsLookup/onAssetsLookup.ts deleted file mode 100644 index 5d43b213d..000000000 --- a/packages/solana-wallet-snap/src/core/handlers/onAssetsLookup/onAssetsLookup.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { CaipAssetType, FungibleAssetMetadata } from '@metamask/snaps-sdk'; -import type { OnAssetsLookupHandler } from '@metamask/snaps-sdk'; -import { parseCaipAssetType } from '@metamask/utils'; - -import { assetsService } from '../../../snapContext'; -import type { - NativeCaipAssetType, - TokenCaipAssetType, -} from '../../constants/solana'; -import logger from '../../utils/logger'; - -export const onAssetsLookup: OnAssetsLookupHandler = async (params) => { - logger.log('[🔍 onAssetsLookup]', params); - - const { assets } = params; - - /** - * TODO: Remove me when we have the new version of Snaps SDK - */ - const fungibleAssets = assets.filter((asset) => { - const { assetNamespace } = parseCaipAssetType(asset); - return assetNamespace === 'token' || assetNamespace === 'slip44'; - }) as (TokenCaipAssetType | NativeCaipAssetType)[]; - - const metadata = (await assetsService.getAssetsMetadata( - fungibleAssets, - )) as Record; - - return { assets: metadata }; -}; diff --git a/packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.test.ts b/packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.test.ts deleted file mode 100644 index e3ee6c1ea..000000000 --- a/packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.test.ts +++ /dev/null @@ -1,358 +0,0 @@ -import type { FungibleAssetMarketData } from '@metamask/snaps-sdk'; -import type { CaipAssetType } from '@metamask/utils'; - -import { assetsService } from '../../../snapContext'; -import logger from '../../utils/logger'; -import { onAssetsMarketData } from './onAssetsMarketData'; - -jest.mock('../../../snapContext', () => ({ - assetsService: { - fetchAssetsMarketData: jest.fn(), - }, -})); - -jest.mock('../../utils/logger', () => ({ - log: jest.fn(), - error: jest.fn(), -})); - -describe('onAssetsMarketData', () => { - const mockAssetsService = assetsService as jest.Mocked; - - const BTC = - 'bip122:000000000019d6689c085ae165831e93/slip44:0' as CaipAssetType; - const ETH = 'eip155:1/slip44:60' as CaipAssetType; - const SOL = - 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501' as CaipAssetType; - const USD = 'swift:0/iso4217:USD' as CaipAssetType; - const EUR = 'swift:0/iso4217:EUR' as CaipAssetType; - - const PT1H = 'PT1H'; - const P1D = 'P1D'; - const P7D = 'P7D'; - const P30D = 'P30D'; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - describe('successful scenarios', () => { - it('should return market data for crypto assets in USD', async () => { - const params = { - assets: [ - { asset: BTC, unit: USD }, - { asset: ETH, unit: USD }, - { asset: SOL, unit: USD }, - ], - }; - - const mockMarketData: Record = { - [BTC]: { - fungible: true, - marketCap: '1000000000000', - totalVolume: '50000000000', - circulatingSupply: '19500000', - allTimeHigh: '120000', - allTimeLow: '67.81', - pricePercentChange: { - [PT1H]: 0.5, - [P1D]: 2.1, - [P7D]: -1.2, - [P30D]: 15.3, - }, - }, - [ETH]: { - fungible: true, - marketCap: '400000000000', - totalVolume: '20000000000', - circulatingSupply: '120000000', - allTimeHigh: '5000', - allTimeLow: '0.43', - pricePercentChange: { - [PT1H]: 1.2, - [P1D]: 3.5, - [P7D]: 5.1, - }, - }, - [SOL]: { - fungible: true, - marketCap: '80000000000', - totalVolume: '3000000000', - circulatingSupply: '400000000', - allTimeHigh: '260', - allTimeLow: '0.5', - pricePercentChange: { - [PT1H]: -0.8, - [P1D]: 1.5, - [P7D]: -2.3, - }, - }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - - it('should return market data for crypto assets in different fiat currencies', async () => { - const params = { - assets: [ - { asset: BTC, unit: EUR }, - { asset: ETH, unit: USD }, - ], - }; - - const mockMarketData: Record = { - [BTC]: { - fungible: true, - marketCap: '850000000000', - totalVolume: '42500000000', - circulatingSupply: '19500000', - allTimeHigh: '102000', - allTimeLow: '57.64', - pricePercentChange: { - [PT1H]: 0.3, - [P1D]: 1.8, - }, - }, - [ETH]: { - fungible: true, - marketCap: '400000000000', - totalVolume: '20000000000', - circulatingSupply: '120000000', - allTimeHigh: '5000', - allTimeLow: '0.43', - pricePercentChange: { - [PT1H]: 1.2, - [P1D]: 3.5, - }, - }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - - it('should return market data with minimal fields when some data is missing', async () => { - const params = { - assets: [{ asset: BTC, unit: USD }], - }; - - const mockMarketData: Record = { - [BTC]: { - fungible: true, - marketCap: '1000000000000', - }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - - it('should return empty market data when no assets are provided', async () => { - const params = { - assets: [], - }; - - const mockMarketData: Record = {}; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - - it('should return market data with only price percent changes when other fields are null', async () => { - const params = { - assets: [{ asset: BTC, unit: USD }], - }; - - const mockMarketData: Record = { - [BTC]: { - fungible: true, - pricePercentChange: { - [PT1H]: 0.5, - [P1D]: 2.1, - [P7D]: -1.2, - }, - }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - }); - - describe('edge cases', () => { - it('should handle assets with special characters in asset types', async () => { - const specialAsset = - 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/slip44:501' as CaipAssetType; - const params = { - assets: [{ asset: specialAsset, unit: USD }], - }; - - const mockMarketData: Record = { - [specialAsset]: { - fungible: true, - marketCap: '50000000', - totalVolume: '2000000', - circulatingSupply: '1000000', - }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - - it('should handle very large numbers in market data', async () => { - const params = { - assets: [{ asset: BTC, unit: USD }], - }; - - const mockMarketData: Record = { - [BTC]: { - fungible: true, - marketCap: '999999999999999999999999999999', - totalVolume: '123456789012345678901234567890', - circulatingSupply: '21000000', - allTimeHigh: '999999999999999999999999999999', - allTimeLow: '0.000000000000000001', - pricePercentChange: { - [PT1H]: 999.99, - [P1D]: -999.99, - }, - }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - - it('should handle zero values in market data', async () => { - const params = { - assets: [{ asset: ETH, unit: USD }], - }; - - const mockMarketData: Record = { - [ETH]: { - fungible: true, - marketCap: '0', - totalVolume: '0', - circulatingSupply: '0', - allTimeHigh: '0', - allTimeLow: '0', - pricePercentChange: { - [PT1H]: 0, - [P1D]: 0, - [P7D]: 0, - }, - }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - const result = await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - expect(mockAssetsService.fetchAssetsMarketData).toHaveBeenCalledWith( - params.assets, - ); - expect(result).toStrictEqual({ marketData: mockMarketData }); - }); - }); - - describe('logging behavior', () => { - it('should log the input parameters correctly', async () => { - const params = { - assets: [ - { asset: BTC, unit: USD }, - { asset: ETH, unit: EUR }, - ], - }; - - const mockMarketData: Record = { - [BTC]: { fungible: true }, - [ETH]: { fungible: true }, - }; - - mockAssetsService.fetchAssetsMarketData.mockResolvedValue(mockMarketData); - - await onAssetsMarketData(params); - - expect(logger.log).toHaveBeenCalledWith( - '[💰 onAssetsMarketData]', - params, - ); - }); - }); -}); diff --git a/packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.ts b/packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.ts deleted file mode 100644 index 021437936..000000000 --- a/packages/solana-wallet-snap/src/core/handlers/onAssetsMarketData/onAssetsMarketData.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { OnAssetsMarketDataHandler } from '@metamask/snaps-sdk'; - -import { assetsService } from '../../../snapContext'; -import logger from '../../utils/logger'; - -export const onAssetsMarketData: OnAssetsMarketDataHandler = async (params) => { - logger.log('[💰 onAssetsMarketData]', params); - - const { assets } = params; - - const marketData = await assetsService.fetchAssetsMarketData(assets); - - return { marketData }; -}; diff --git a/packages/solana-wallet-snap/src/index.ts b/packages/solana-wallet-snap/src/index.ts index 6060f0b74..41c3c68ac 100644 --- a/packages/solana-wallet-snap/src/index.ts +++ b/packages/solana-wallet-snap/src/index.ts @@ -5,10 +5,6 @@ import { MethodNotFoundError } from '@metamask/snaps-sdk'; import type { Json, OnActiveHandler, - OnAssetHistoricalPriceHandler, - OnAssetsConversionHandler, - OnAssetsLookupHandler, - OnAssetsMarketDataHandler, OnClientRequestHandler, OnCronjobHandler, OnInactiveHandler, @@ -25,10 +21,6 @@ import type { OnRpcRequestHandler } from '@metamask/snaps-sdk'; import { assert, enums } from '@metamask/superstruct'; import BigNumber from 'bignumber.js'; -import { onAssetHistoricalPrice as onAssetHistoricalPriceHandler } from './core/handlers/onAssetHistoricalPrice/onAssetHistoricalPrice'; -import { onAssetsConversion as onAssetsConversionHandler } from './core/handlers/onAssetsConversion/onAssetsConversion'; -import { onAssetsLookup as onAssetsLookupHandler } from './core/handlers/onAssetsLookup/onAssetsLookup'; -import { onAssetsMarketData as onAssetsMarketDataHandler } from './core/handlers/onAssetsMarketData/onAssetsMarketData'; import { handlers as onCronjobHandlers } from './core/handlers/onCronjob'; import { ScheduleBackgroundEventMethod } from './core/handlers/onCronjob/backgroundEvents/ScheduleBackgroundEventMethod'; import { CronjobMethod } from './core/handlers/onCronjob/cronjobs/CronjobMethod'; @@ -207,20 +199,6 @@ export const onCronjob: OnCronjobHandler = async ({ request }) => { return result ?? null; }; -export const onAssetsLookup: OnAssetsLookupHandler = async (params) => { - const result = await withCatchAndThrowSnapError(async () => - onAssetsLookupHandler(params), - ); - return result ?? null; -}; - -export const onAssetsConversion: OnAssetsConversionHandler = async (params) => { - const result = await withCatchAndThrowSnapError(async () => - onAssetsConversionHandler(params), - ); - return result ?? null; -}; - export const onProtocolRequest: OnProtocolRequestHandler = async (params) => { const result = await withCatchAndThrowSnapError(async () => onProtocolRequestHandler(params), @@ -228,15 +206,6 @@ export const onProtocolRequest: OnProtocolRequestHandler = async (params) => { return result ?? null; }; -export const onAssetHistoricalPrice: OnAssetHistoricalPriceHandler = async ( - params, -) => { - const result = await withCatchAndThrowSnapError(async () => - onAssetHistoricalPriceHandler(params), - ); - return result ?? null; -}; - export const onClientRequest: OnClientRequestHandler = async ({ request }) => { const result = await withCatchAndThrowSnapError(async () => clientRequestHandler.handle(request), @@ -286,10 +255,3 @@ export const onNameLookup: OnNameLookupHandler = async (request) => { ); return result ?? null; }; - -export const onAssetsMarketData: OnAssetsMarketDataHandler = async (params) => { - const result = await withCatchAndThrowSnapError(async () => - onAssetsMarketDataHandler(params), - ); - return result ?? null; -};