diff --git a/packages/solana-wallet-snap/CHANGELOG.md b/packages/solana-wallet-snap/CHANGELOG.md index 2858f3678..4fd4a80dd 100644 --- a/packages/solana-wallet-snap/CHANGELOG.md +++ b/packages/solana-wallet-snap/CHANGELOG.md @@ -17,6 +17,12 @@ 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)) +- **BREAKING** Remove `AssetsService.fetchAssetsMarketData` and `SnapAssetsAdapter.fetchAssetsMarketData`, the `TokenPricesService` class, and `PriceApiClient.getHistoricalPrices`, all of which were only used by the removed asset handlers ([#261](https://github.com/MetaMask/internal-snaps/pull/261)) +- Remove the now-unused `PriceApiClient.getFiatExchangeRates` method and related `ExchangeRate` type, the unused `tokenPrices` unencrypted state field, the unused `fiatExchangeRates` and `historicalPrices` price API cache TTL options, and unused price API test mocks ([#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..944de7795 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": "t59sR0tGjfrGSTVgn+Zy50qRGZ4uaShrwmzWJM9qD0Q=", "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/clients/price-api/PriceApiClient.test.ts b/packages/solana-wallet-snap/src/core/clients/price-api/PriceApiClient.test.ts index cba741ba4..b1c066a88 100644 --- a/packages/solana-wallet-snap/src/core/clients/price-api/PriceApiClient.test.ts +++ b/packages/solana-wallet-snap/src/core/clients/price-api/PriceApiClient.test.ts @@ -8,8 +8,6 @@ import { InMemoryCache } from '../../caching/InMemoryCache'; import { KnownCaip19Id } from '../../constants/solana'; import { mockLogger } from '../../services/__mocks__/logger'; import type { ConfigProvider } from '../../services/config'; -import { MOCK_EXCHANGE_RATES } from '../../test/mocks/price-api/exchange-rates'; -import { MOCK_HISTORICAL_PRICES } from './mocks/historical-prices'; import { MOCK_SPOT_PRICES } from './mocks/spot-prices'; import { PriceApiClient } from './PriceApiClient'; import type { SpotPrices, VsCurrencyParam } from './types'; @@ -28,9 +26,7 @@ describe('PriceApiClient', () => { baseUrl: 'https://some-mock-url.com', chunkSize: 50, cacheTtlsMilliseconds: { - fiatExchangeRates: 0, spotPrices: 0, - historicalPrices: 0, }, }, }), @@ -46,55 +42,6 @@ describe('PriceApiClient', () => { ); }); - describe('getFiatExchangeRates', () => { - it('fetches fiat exchange rates successfully', async () => { - mockFetch.mockResolvedValueOnce({ - ok: true, - json: jest.fn().mockResolvedValueOnce(MOCK_EXCHANGE_RATES), - }); - - const result = await client.getFiatExchangeRates(); - - expect(mockFetch).toHaveBeenCalledWith( - 'https://some-mock-url.com/v1/exchange-rates/fiat', - ); - expect(result).toStrictEqual(MOCK_EXCHANGE_RATES); - }); - - it('caches the fiat exchange rates', async () => { - // TTL 0 expires on the next clock tick (`expiresAt < Date.now()`), so the - // second call can miss the cache and hit an exhausted fetch mock. - const cachingClient = new PriceApiClient( - { - get: jest.fn().mockReturnValue({ - priceApi: { - baseUrl: 'https://some-mock-url.com', - chunkSize: 50, - cacheTtlsMilliseconds: { - fiatExchangeRates: 60_000, - spotPrices: 0, - historicalPrices: 0, - }, - }, - }), - } as unknown as ConfigProvider, - mockCache, - mockFetch, - mockLogger, - ); - - mockFetch.mockResolvedValueOnce({ - ok: true, - json: jest.fn().mockResolvedValueOnce(MOCK_EXCHANGE_RATES), - }); - - await cachingClient.getFiatExchangeRates(); - await cachingClient.getFiatExchangeRates(); - - expect(mockFetch).toHaveBeenCalledTimes(1); - }); - }); - describe('getMultipleSpotPrices', () => { const mockResponse: SpotPrices = { [KnownCaip19Id.SolMainnet]: MOCK_SPOT_PRICES[KnownCaip19Id.SolMainnet]!, @@ -290,9 +237,7 @@ describe('PriceApiClient', () => { baseUrl: 'invalid-url', chunkSize: 50, cacheTtlsMilliseconds: { - fiatExchangeRates: 0, spotPrices: 0, - historicalPrices: 0, }, }, }), @@ -359,59 +304,4 @@ describe('PriceApiClient', () => { ).rejects.toThrow(/Expected/u); }); }); - - describe('getHistoricalPrices', () => { - describe('when the data is not cached', () => { - it('fetches historical prices successfully', async () => { - mockFetch.mockResolvedValueOnce({ - ok: true, - json: jest.fn().mockResolvedValueOnce(MOCK_HISTORICAL_PRICES), - }); - - const cacheSetSpy = jest.spyOn(mockCache, 'set'); - - const result = await client.getHistoricalPrices({ - assetType: KnownCaip19Id.SolMainnet, - timePeriod: '5d', - from: 123, - to: 456, - vsCurrency: 'usd', - }); - - expect(mockFetch).toHaveBeenCalledWith( - 'https://some-mock-url.com/v3/historical-prices/solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501?timePeriod=5d&from=123&to=456&vsCurrency=usd', - ); - expect(cacheSetSpy).toHaveBeenCalledWith( - 'PriceApiClient:getHistoricalPrices:{"assetType":"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501","timePeriod":"5d","from":123,"to":456,"vsCurrency":"usd"}', - MOCK_HISTORICAL_PRICES, - 0, - ); - expect(result).toStrictEqual(MOCK_HISTORICAL_PRICES); - }); - }); - - describe('when the data is cached', () => { - it('returns the cached data', async () => { - jest - .spyOn(mockCache, 'get') - .mockResolvedValueOnce(MOCK_HISTORICAL_PRICES); - - const cacheGetSpy = jest.spyOn(mockCache, 'get'); - const cacheSetSpy = jest.spyOn(mockCache, 'set'); - - const result = await client.getHistoricalPrices({ - assetType: KnownCaip19Id.SolMainnet, - timePeriod: '5d', - from: 123, - to: 456, - vsCurrency: 'usd', - }); - - expect(cacheGetSpy).toHaveBeenCalled(); - expect(mockFetch).not.toHaveBeenCalled(); - expect(result).toStrictEqual(MOCK_HISTORICAL_PRICES); - expect(cacheSetSpy).not.toHaveBeenCalled(); - }); - }); - }); }); diff --git a/packages/solana-wallet-snap/src/core/clients/price-api/PriceApiClient.ts b/packages/solana-wallet-snap/src/core/clients/price-api/PriceApiClient.ts index a1b506eaf..f7f94189e 100644 --- a/packages/solana-wallet-snap/src/core/clients/price-api/PriceApiClient.ts +++ b/packages/solana-wallet-snap/src/core/clients/price-api/PriceApiClient.ts @@ -8,23 +8,10 @@ import { CaipAssetTypeStruct } from '@metamask/utils'; import { mapKeys } from 'lodash'; import type { ICache } from '../../caching/ICache'; -import { useCache } from '../../caching/useCache'; import type { ConfigProvider } from '../../services/config'; import logger from '../../utils/logger'; -import type { - ExchangeRate, - FiatTicker, - GetHistoricalPricesParams, - GetHistoricalPricesResponse, - SpotPrices, - VsCurrencyParam, -} from './types'; -import { - GetHistoricalPricesParamsStruct, - GetHistoricalPricesResponseStruct, - SpotPricesStruct, - VsCurrencyParamStruct, -} from './types'; +import type { SpotPrices, VsCurrencyParam } from './types'; +import { SpotPricesStruct, VsCurrencyParamStruct } from './types'; export class PriceApiClient { readonly #fetch: typeof globalThis.fetch; @@ -38,9 +25,7 @@ export class PriceApiClient { readonly #cache: ICache; readonly cacheTtlsMilliseconds: { - fiatExchangeRates: number; spotPrices: number; - historicalPrices: number; }; constructor( @@ -63,37 +48,6 @@ export class PriceApiClient { this.#cache = _cache; } - async getFiatExchangeRates(): Promise> { - return useCache( - this.#getFiatExchangeRates_INTERNAL.bind(this), - this.#cache, - { - functionName: 'PriceApiClient:getFiatExchangeRates', - ttlMilliseconds: this.cacheTtlsMilliseconds.fiatExchangeRates, - }, - )(); - } - - async #getFiatExchangeRates_INTERNAL(): Promise< - Record - > { - try { - const response = await this.#fetch( - `${this.#baseUrl}/v1/exchange-rates/fiat`, - ); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); - return data; - } catch (error) { - this.#logger.error(error, 'Error fetching fiat exchange rates'); - throw error; - } - } - /** * Business logic for `getMultipleSpotPrices`. * @@ -265,68 +219,4 @@ export class PriceApiClient { ): Promise { return this.#getMultipleSpotPrices_CACHE(tokenCaip19Types, vsCurrency); } - - /** - * Business logic for `getHistoricalPrices`. - * - * @param params - The parameters for the request. - * @param params.assetType - The asset type of the token. - * @param params.timePeriod - The time period for the historical prices. - * @param params.from - The start date for the historical prices. - * @param params.to - The end date for the historical prices. - * @param params.vsCurrency - The currency to convert the prices to. - * @returns The historical prices for the token. - */ - async #getHistoricalPrices_INTERNAL( - params: GetHistoricalPricesParams, - ): Promise { - assert(params, GetHistoricalPricesParamsStruct); - - const url = buildUrl({ - baseUrl: this.#baseUrl, - path: '/v3/historical-prices/{assetType}', - pathParams: { - assetType: params.assetType, - }, - encodePathParams: false, - queryParams: { - ...(params.timePeriod && { timePeriod: params.timePeriod }), - ...(params.from && { from: params.from.toString() }), - ...(params.to && { to: params.to.toString() }), - ...(params.vsCurrency && { vsCurrency: params.vsCurrency }), - }, - }); - - const response = await this.#fetch(url); - const historicalPrices = await response.json(); - assert(historicalPrices, GetHistoricalPricesResponseStruct); - - return historicalPrices; - } - - /** - * Get historical prices for a token by calling the Price API. - * It caches the results for 1 hour. - * - * @see https://price.uat-api.cx.metamask.io/docs#/Historical%20Prices/PriceController_getHistoricalPricesByCaipAssetId - * @param params - The parameters for the request. - * @param params.assetType - The asset type of the token. - * @param params.timePeriod - The time period for the historical prices. - * @param params.from - The start date for the historical prices. - * @param params.to - The end date for the historical prices. - * @param params.vsCurrency - The currency to convert the prices to. - * @returns The historical prices for the token. - */ - async getHistoricalPrices( - params: GetHistoricalPricesParams, - ): Promise { - return useCache( - this.#getHistoricalPrices_INTERNAL.bind(this), - this.#cache, - { - functionName: 'PriceApiClient:getHistoricalPrices', - ttlMilliseconds: this.cacheTtlsMilliseconds.historicalPrices, - }, - )(params); - } } diff --git a/packages/solana-wallet-snap/src/core/clients/price-api/mocks/historical-prices.ts b/packages/solana-wallet-snap/src/core/clients/price-api/mocks/historical-prices.ts deleted file mode 100644 index c49401ef5..000000000 --- a/packages/solana-wallet-snap/src/core/clients/price-api/mocks/historical-prices.ts +++ /dev/null @@ -1,17 +0,0 @@ -export const MOCK_HISTORICAL_PRICES = { - prices: [ - [1740927906629, 0.4118878563926736], - [1740931479807, 0.42205009065536164], - [1740935079843, 0.45470438113431433], - ], - marketCaps: [ - [1740927906629, 1817840725.6040797], - [1740931479807, 1868369182.2913468], - [1740935079843, 2012074624.0219033], - ], - totalVolumes: [ - [1740927906629, 120486002.56343293], - [1740931479807, 147850728.76918542], - [1740935079843, 220405205.04882324], - ], -}; diff --git a/packages/solana-wallet-snap/src/core/clients/price-api/types.ts b/packages/solana-wallet-snap/src/core/clients/price-api/types.ts index 40ce9dc8c..abb023eb3 100644 --- a/packages/solana-wallet-snap/src/core/clients/price-api/types.ts +++ b/packages/solana-wallet-snap/src/core/clients/price-api/types.ts @@ -1,6 +1,5 @@ import type { Infer } from '@metamask/superstruct'; import { - array, boolean, enums, min, @@ -8,18 +7,12 @@ import { number, object, optional, - pattern, record, string, - tuple, union, } from '@metamask/superstruct'; import { CaipAssetTypeStruct } from '@metamask/utils'; -export type PriceApiClientConfig = { - baseUrl: string; -}; - export const CryptoTickerStruct = enums([ 'btc', 'eth', @@ -116,13 +109,6 @@ export const TickerStruct = union([ export type Ticker = Infer; -export type ExchangeRate = { - name: string; - ticker: Ticker; - value: number; - currencyType: 'fiat' | 'crypto' | 'commodity'; -}; - /** * The structure of the spot price response from the Price API as described in * [this file](https://github.com/consensys-vertical-apps/va-mmcx-price-api/blob/main/src/types/price.ts#L46-L71). @@ -197,32 +183,3 @@ export type SpotPrices = Infer; // We create aliases here for clarity. export const VsCurrencyParamStruct = TickerStruct; export type VsCurrencyParam = Infer; - -export const GetHistoricalPricesParamsStruct = object({ - assetType: CaipAssetTypeStruct, - timePeriod: optional(pattern(string(), /^[1-9][0-9]*[dmy]$/u)), // Supports days, months, years - from: optional(min(number(), 0)), - to: optional(min(number(), 0)), - vsCurrency: optional(VsCurrencyParamStruct), -}); - -export type GetHistoricalPricesParams = Infer< - typeof GetHistoricalPricesParamsStruct ->; - -export const GetHistoricalPricesResponseStruct = object({ - prices: array(tuple([number(), number()])), - marketCaps: array(tuple([number(), number()])), - totalVolumes: array(tuple([number(), number()])), -}); - -export type GetHistoricalPricesResponse = Infer< - typeof GetHistoricalPricesResponseStruct ->; - -export const GET_HISTORICAL_PRICES_RESPONSE_NULL_OBJECT: GetHistoricalPricesResponse = - { - prices: [], - marketCaps: [], - totalVolumes: [], - }; 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/core/services/assets/AssetsService.test.ts b/packages/solana-wallet-snap/src/core/services/assets/AssetsService.test.ts index 5cf6ccf95..fa21c8a2e 100644 --- a/packages/solana-wallet-snap/src/core/services/assets/AssetsService.test.ts +++ b/packages/solana-wallet-snap/src/core/services/assets/AssetsService.test.ts @@ -23,7 +23,6 @@ import { MOCK_SOLANA_RPC_GET_TOKEN_ACCOUNTS_BY_OWNER_RESPONSE } from '../__mocks import type { AccountsService } from '../accounts/AccountsService'; import type { ConfigProvider } from '../config'; import type { SolanaConnection } from '../connection'; -import type { TokenPricesService } from '../token-prices/TokenPrices'; import { SnapAssetsAdapter } from './adapters/SnapAssetsAdapter'; import type { AssetsRepository } from './AssetsRepository'; import { AssetsService } from './AssetsService'; @@ -40,7 +39,6 @@ describe('AssetsService', () => { let mockAssetsRepository: AssetsRepository; let mockAccountsService: AccountsService; let mockTokenApiClient: TokenApiClient; - let mockTokenPricesService: TokenPricesService; let mockNftApiClient: NftApiClient; let mockCache: ICache; @@ -58,14 +56,6 @@ describe('AssetsService', () => { .mockResolvedValue(SOLANA_MOCK_TOKEN_METADATA), } as unknown as TokenApiClient; - mockTokenPricesService = { - getMultipleTokenConversions: jest.fn().mockResolvedValue({}), - getMultipleTokensMarketData: jest.fn().mockResolvedValue({}), - getHistoricalPrice: jest - .fn() - .mockResolvedValue({ intervals: {}, updateTime: 0, expirationTime: 0 }), - } as unknown as TokenPricesService; - mockCache = new InMemoryCache(mockLogger); mockNftApiClient = { @@ -96,7 +86,6 @@ describe('AssetsService', () => { assetsRepository: mockAssetsRepository, accountsService: mockAccountsService, tokenApiClient: mockTokenApiClient, - tokenPricesService: mockTokenPricesService, cache: mockCache, nftApiClient: mockNftApiClient, }); @@ -195,29 +184,6 @@ describe('AssetsService', () => { }); }); - describe('fetchAssetsMarketData', () => { - it('delegates to the token prices service', async () => { - const assets = [ - { - asset: MOCK_ASSET_ENTITY_0.assetType, - unit: MOCK_ASSET_ENTITY_0.assetType, - }, - ]; - const expected = { [MOCK_ASSET_ENTITY_0.assetType]: {} }; - - jest - .spyOn(mockTokenPricesService, 'getMultipleTokensMarketData') - .mockResolvedValueOnce(expected as never); - - const result = await assetsService.fetchAssetsMarketData(assets); - - expect( - mockTokenPricesService.getMultipleTokensMarketData, - ).toHaveBeenCalledWith(assets); - expect(result).toStrictEqual(expected); - }); - }); - describe('save', () => { it('saves an asset', async () => { const spy = jest diff --git a/packages/solana-wallet-snap/src/core/services/assets/AssetsService.ts b/packages/solana-wallet-snap/src/core/services/assets/AssetsService.ts index 5a1faabf3..1ace9e37b 100644 --- a/packages/solana-wallet-snap/src/core/services/assets/AssetsService.ts +++ b/packages/solana-wallet-snap/src/core/services/assets/AssetsService.ts @@ -1,5 +1,4 @@ /* eslint-disable jsdoc/require-returns */ -import type { FungibleAssetMarketData } from '@metamask/snaps-sdk'; import type { CaipAssetType, CaipChainId } from '@metamask/utils'; import type { AssetEntity, SolanaKeyringAccount } from '../../../entities'; @@ -34,17 +33,6 @@ export class AssetsService { return this.#snapAdapter.fetch(account); } - async fetchAssetsMarketData( - assets: { - asset: CaipAssetType; - unit: CaipAssetType; - }[], - ): Promise< - Record> - > { - return this.#snapAdapter.fetchAssetsMarketData(assets); - } - async save(asset: AssetEntity): Promise { await this.saveMany([asset]); } diff --git a/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.test.ts b/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.test.ts index 1f9be1274..90c471622 100644 --- a/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.test.ts +++ b/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.test.ts @@ -16,7 +16,6 @@ import { createMockConnection } from '../../__mocks__/mockConnection'; import type { AccountsService } from '../../accounts/AccountsService'; import type { ConfigProvider } from '../../config'; import type { SolanaConnection } from '../../connection'; -import type { TokenPricesService } from '../../token-prices/TokenPrices'; import type { AssetsRepository } from '../AssetsRepository'; import { SnapAssetsAdapter } from './SnapAssetsAdapter'; @@ -27,7 +26,6 @@ describe('SnapAssetsAdapter', () => { let mockAssetsRepository: AssetsRepository; let mockAccountsService: AccountsService; let mockTokenApiClient: TokenApiClient; - let mockTokenPricesService: TokenPricesService; let mockNftApiClient: NftApiClient; let mockCache: ICache; @@ -43,10 +41,6 @@ describe('SnapAssetsAdapter', () => { getTokensMetadata: jest.fn().mockResolvedValue({}), } as unknown as TokenApiClient; - mockTokenPricesService = { - getMultipleTokensMarketData: jest.fn().mockResolvedValue({}), - } as unknown as TokenPricesService; - mockCache = new InMemoryCache(mockLogger); mockNftApiClient = { @@ -72,7 +66,6 @@ describe('SnapAssetsAdapter', () => { assetsRepository: mockAssetsRepository, accountsService: mockAccountsService, tokenApiClient: mockTokenApiClient, - tokenPricesService: mockTokenPricesService, cache: mockCache, nftApiClient: mockNftApiClient, }); diff --git a/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.ts b/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.ts index c84d13e3e..a1672d6e1 100644 --- a/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.ts +++ b/packages/solana-wallet-snap/src/core/services/assets/adapters/SnapAssetsAdapter.ts @@ -7,10 +7,7 @@ import type { } from '@metamask/keyring-api'; import { emitSnapKeyringEvent } from '@metamask/keyring-snap-sdk'; import type { Logger, Serializable } from '@metamask/snap-networks-utils'; -import type { - FungibleAssetMarketData, - FungibleAssetMetadata, -} from '@metamask/snaps-sdk'; +import type { FungibleAssetMetadata } from '@metamask/snaps-sdk'; import type { CaipAssetType, CaipChainId } from '@metamask/utils'; import { Duration, parseCaipAssetType } from '@metamask/utils'; import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token'; @@ -46,7 +43,6 @@ import { tokenAddressToCaip19 } from '../../../utils/tokenAddressToCaip19'; import type { AccountsService } from '../../accounts/AccountsService'; import type { ConfigProvider } from '../../config'; import type { SolanaConnection } from '../../connection'; -import type { TokenPricesService } from '../../token-prices/TokenPrices'; import type { AssetsRepository } from '../AssetsRepository'; import type { AssetMetadata, NonFungibleAssetMetadata } from '../types'; @@ -73,8 +69,6 @@ export class SnapAssetsAdapter { readonly #tokenApiClient: TokenApiClient; - readonly #tokenPricesService: TokenPricesService; - readonly #cache: ICache; readonly #nftApiClient: NftApiClient; @@ -90,7 +84,6 @@ export class SnapAssetsAdapter { assetsRepository, accountsService, tokenApiClient, - tokenPricesService, cache, nftApiClient, }: { @@ -100,7 +93,6 @@ export class SnapAssetsAdapter { assetsRepository: AssetsRepository; accountsService: AccountsService; tokenApiClient: TokenApiClient; - tokenPricesService: TokenPricesService; cache: ICache; nftApiClient: NftApiClient; }) { @@ -110,7 +102,6 @@ export class SnapAssetsAdapter { this.#assetsRepository = assetsRepository; this.#accountsService = accountsService; this.#tokenApiClient = tokenApiClient; - this.#tokenPricesService = tokenPricesService; this.#cache = cache; this.#nftApiClient = nftApiClient; } @@ -430,21 +421,6 @@ export class SnapAssetsAdapter { return results; } - async fetchAssetsMarketData( - assets: { - asset: CaipAssetType; - unit: CaipAssetType; - }[], - ): Promise< - Record> - > { - this.#logger.info('Fetching market data for assets', assets); - - const marketData = - await this.#tokenPricesService.getMultipleTokensMarketData(assets); - return marketData; - } - async #fetchNftAssets( account: SolanaKeyringAccount, assetIds: NftCaipAssetType[], diff --git a/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts b/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts index 423467755..ab6742d46 100644 --- a/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts +++ b/packages/solana-wallet-snap/src/core/services/config/ConfigProvider.ts @@ -71,9 +71,7 @@ export type Config = { baseUrl: string; chunkSize: number; cacheTtlsMilliseconds: { - fiatExchangeRates: number; spotPrices: number; - historicalPrices: number; }; }; tokenApi: { @@ -184,9 +182,7 @@ export class ConfigProvider { : environment.PRICE_API_BASE_URL, chunkSize: 50, cacheTtlsMilliseconds: { - fiatExchangeRates: Duration.Minute, spotPrices: Duration.Minute, - historicalPrices: Duration.Minute, }, }, tokenApi: { diff --git a/packages/solana-wallet-snap/src/core/services/state/State.ts b/packages/solana-wallet-snap/src/core/services/state/State.ts index ff42e9867..18d6ab881 100644 --- a/packages/solana-wallet-snap/src/core/services/state/State.ts +++ b/packages/solana-wallet-snap/src/core/services/state/State.ts @@ -19,7 +19,6 @@ import type { Subscription, } from '../../../entities'; import type { EventEmitter } from '../../../infrastructure'; -import type { SpotPrices } from '../../clients/price-api/types'; import type { IStateManager } from './IStateManager'; export type AccountId = string; @@ -32,7 +31,6 @@ export type UnencryptedStateValue = { // to keep track of the transactions per account. The field transactions above only stores non-spam transactions, which break the refreshAccounts cronjob logic. signatures: Record; assetEntities: Record; - tokenPrices: SpotPrices; subscriptions: Record; webSocketConnections: { closeWebSocketConnectionsBackgroundEventId: string | null; @@ -45,7 +43,6 @@ export const DEFAULT_UNENCRYPTED_STATE: UnencryptedStateValue = { transactions: {}, signatures: {}, assetEntities: {}, - tokenPrices: {}, subscriptions: {}, webSocketConnections: { closeWebSocketConnectionsBackgroundEventId: null, diff --git a/packages/solana-wallet-snap/src/core/services/token-prices/TokenPrices.test.ts b/packages/solana-wallet-snap/src/core/services/token-prices/TokenPrices.test.ts deleted file mode 100644 index 2ae91e22d..000000000 --- a/packages/solana-wallet-snap/src/core/services/token-prices/TokenPrices.test.ts +++ /dev/null @@ -1,523 +0,0 @@ -import { Duration } from '@metamask/utils'; - -import { MOCK_HISTORICAL_PRICES } from '../../clients/price-api/mocks/historical-prices'; -import { MOCK_SPOT_PRICES } from '../../clients/price-api/mocks/spot-prices'; -import type { PriceApiClient } from '../../clients/price-api/PriceApiClient'; -import type { SpotPrice } from '../../clients/price-api/types'; -import { MOCK_EXCHANGE_RATES } from '../../test/mocks/price-api/exchange-rates'; -import { trackError } from '../../utils/errors'; -import { mockLogger } from '../__mocks__/logger'; -import { ConfigProvider } from '../config'; -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { TokenPricesService } from './TokenPrices'; - -jest.mock('../../utils/errors', () => ({ - trackError: jest.fn().mockResolvedValue('tracked-error-id'), -})); - -describe('TokenPricesService', () => { - /* Crypto */ - const BTC = 'bip122:000000000019d6689c085ae165831e93/slip44:0'; - const ETH = 'eip155:1/slip44:60'; - const SOL = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501'; - const USDC = 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; - - /* Fiat */ - const EUR = 'swift:0/iso4217:EUR'; - const USD = 'swift:0/iso4217:USD'; - const BZR = 'swift:0/iso4217:BRL'; - - const UNKNOWN_CRYPTO_1 = 'unknown:1/slip44:1'; - const UNKNOWN_CRYPTO_2 = 'unknown:2/slip44:2'; - const UNKNOWN_FIAT_1 = 'swift:0/iso4217:AAA'; - const UNKNOWN_FIAT_2 = 'swift:0/iso4217:ZZZ'; - - let tokenPricesService: TokenPricesService; - let mockPriceApiClient: PriceApiClient; - let mockConfigProvider: ConfigProvider; - - beforeEach(() => { - mockPriceApiClient = { - getFiatExchangeRates: jest.fn().mockResolvedValue(MOCK_EXCHANGE_RATES), - getMultipleSpotPrices: jest.fn().mockResolvedValue(MOCK_SPOT_PRICES), - getHistoricalPrices: jest.fn().mockResolvedValue(MOCK_HISTORICAL_PRICES), - cacheTtlsMilliseconds: { - historicalPrices: Duration.Hour, - spotPrices: Duration.Hour, - }, - } as unknown as PriceApiClient; - - mockConfigProvider = new ConfigProvider(); - - tokenPricesService = new TokenPricesService({ - priceApiClient: mockPriceApiClient, - configProvider: mockConfigProvider, - logger: mockLogger, - }); - }); - - describe('getMultipleTokenConversions', () => { - it('returns empty object when no conversions provided', async () => { - const result = await tokenPricesService.getMultipleTokenConversions([]); - expect(result).toStrictEqual({}); - }); - - describe('when includeMarketData is false', () => { - it('handles fiat to fiat conversions', async () => { - const result = await tokenPricesService.getMultipleTokenConversions([ - /* Same currency */ - { from: USD, to: USD }, - { from: EUR, to: EUR }, - /* Different currency */ - { from: EUR, to: USD }, - { from: USD, to: BZR }, - { from: EUR, to: BZR }, - ]); - - expect(result).toStrictEqual( - expect.objectContaining({ - [USD]: expect.objectContaining({ - [USD]: { - rate: '1', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - [BZR]: { - rate: '5.44630000241062899996', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - [EUR]: expect.objectContaining({ - [EUR]: { - rate: '1', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - [USD]: { - rate: '1.17696630204744878672', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - [BZR]: { - rate: '6.41011157367824942681', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - }), - ); - }); - - it('handles crypto to crypto conversions', async () => { - const result = await tokenPricesService.getMultipleTokenConversions([ - /* Same currency */ - { from: BTC, to: BTC }, - { from: ETH, to: ETH }, - /* Different currency */ - { from: BTC, to: ETH }, - { from: ETH, to: SOL }, - { from: SOL, to: USDC }, - ]); - - expect(result).toStrictEqual( - expect.objectContaining({ - [BTC]: expect.objectContaining({ - [BTC]: { - rate: '1', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - [ETH]: { - rate: '44.96458169857359389595', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - [ETH]: expect.objectContaining({ - [ETH]: { - rate: '1', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - [SOL]: { - rate: '14.69103829451243642206', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - [SOL]: expect.objectContaining({ - [USDC]: { - rate: '126.65075990455942506931', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - }), - ); - }); - - it('handles crypto to fiat conversions', async () => { - const result = await tokenPricesService.getMultipleTokenConversions([ - { from: BTC, to: USD }, - { from: ETH, to: USD }, - { from: SOL, to: USD }, - ]); - - expect(result).toStrictEqual( - expect.objectContaining({ - [BTC]: expect.objectContaining({ - [USD]: { - rate: '77556.84849999227', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - [ETH]: expect.objectContaining({ - [USD]: { - rate: '1724.8431002851428', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - [SOL]: expect.objectContaining({ - [USD]: { - rate: '117.40784182214172', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - }), - ); - }); - - it('handles fiat to crypto conversions', async () => { - const result = await tokenPricesService.getMultipleTokenConversions([ - { from: USD, to: BTC }, - { from: USD, to: ETH }, - { from: USD, to: SOL }, - ]); - - expect(result).toStrictEqual( - expect.objectContaining({ - [USD]: expect.objectContaining({ - [BTC]: { - rate: '0.00001289376785339724', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - [ETH]: { - rate: '0.00057976287804652191', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - [SOL]: { - rate: '0.00851731864311819686', - conversionTime: expect.any(Number), - expirationTime: expect.any(Number), - }, - }), - }), - ); - }); - - it('handles missing data correctly', async () => { - const result = await tokenPricesService.getMultipleTokenConversions([ - { from: UNKNOWN_CRYPTO_1, to: UNKNOWN_CRYPTO_2 }, - { from: UNKNOWN_CRYPTO_1, to: UNKNOWN_FIAT_1 }, - { from: UNKNOWN_FIAT_1, to: UNKNOWN_CRYPTO_2 }, - { from: UNKNOWN_FIAT_1, to: UNKNOWN_FIAT_2 }, - ]); - - expect(result).toStrictEqual({ - [UNKNOWN_CRYPTO_1]: { - [UNKNOWN_CRYPTO_2]: null, - [UNKNOWN_FIAT_1]: null, - }, - [UNKNOWN_FIAT_1]: { - [UNKNOWN_CRYPTO_2]: null, - [UNKNOWN_FIAT_2]: null, - }, - }); - }); - }); - }); - - describe('getMultipleTokensMarketData', () => { - it('returns empty object when no assets provided', async () => { - const result = await tokenPricesService.getMultipleTokensMarketData([]); - expect(result).toStrictEqual({}); - }); - - it('returns market data in the correct nested structure with asset-to-unit conversions and correct values', async () => { - const result = await tokenPricesService.getMultipleTokensMarketData([ - { asset: BTC, unit: USD }, - { asset: ETH, unit: USD }, - { asset: SOL, unit: USD }, - { asset: SOL, unit: BTC }, - ]); - - // BTC/USD - actual values from consistent mocks - expect(result[BTC]![USD]).toStrictEqual({ - fungible: true, - marketCap: '1540421085883.0198', - totalVolume: '23748436299.895576', - circulatingSupply: '19844921', - allTimeHigh: '100847.44951017378', - allTimeLow: '62.86163248290115', - pricePercentChange: { - PT1H: -0.4456714429821922, - P1D: 1.3725526422881404, - P7D: -4.2914380354332256, - P14D: 1.3530761284206316, - P30D: -2.6647248645353425, - P200D: 44.69565022141291, - P1Y: 20.367003699380124, - }, - }); - - // ETH/USD - actual values from consistent mocks - expect(result[ETH]![USD]).toStrictEqual({ - fungible: true, - marketCap: '208326525244.77222', - totalVolume: '14672129201.423573', - circulatingSupply: '120659504.7581715', - allTimeHigh: '4522.273813243435', - allTimeLow: '0.4013827867691204', - pricePercentChange: { - PT1H: -0.16193070976498064, - P1D: 1.9964598342126199, - P7D: -10.123102834312476, - P14D: -1.7452971064771636, - P30D: -16.78602306244949, - P200D: -21.026646670919543, - P1Y: -47.45246230239663, - }, - }); - - // SOL/USD - actual values from consistent mocks - expect(result[SOL]![USD]).toStrictEqual({ - fungible: true, - marketCap: '60217502031.67665', - totalVolume: '3389485617.517553', - circulatingSupply: '512506275.4700137', - allTimeHigh: '271.90599356377726', - allTimeLow: '0.46425554356391946', - pricePercentChange: { - PT1H: -0.7015657267954617, - P1D: 1.6270441732346845, - P7D: -10.985589910714582, - P14D: 2.557473792001135, - P30D: -11.519171371325216, - P200D: -4.453777067234332, - P1Y: -35.331458644625535, - }, - }); - - // SOL/BTC - actual converted values from consistent mocks - expect(result[SOL]![BTC]).toStrictEqual({ - fungible: true, - marketCap: '776430.49190791515732749827', - totalVolume: '43703.24069470010538206139', - circulatingSupply: '512506275.4700137', - allTimeHigh: '0.00350589275895866708', - allTimeLow: '0.00000598600320336592', - pricePercentChange: { - PT1H: -0.7015657267954617, - P1D: 1.6270441732346845, - P7D: -10.985589910714582, - P14D: 2.557473792001135, - P30D: -11.519171371325216, - P200D: -4.453777067234332, - P1Y: -35.331458644625535, - }, - }); - }); - - it('only includes price percent change if Price API returns it', async () => { - jest - .spyOn(mockPriceApiClient, 'getMultipleSpotPrices') - .mockResolvedValue({ - [BTC]: { - ...MOCK_SPOT_PRICES[BTC], - pricePercentChange1h: -0.4456714429821922, - pricePercentChange1d: null, - pricePercentChange7d: null, - pricePercentChange14d: null, - pricePercentChange30d: null, - pricePercentChange200d: null, - pricePercentChange1y: null, - } as SpotPrice, - }); - - const result = await tokenPricesService.getMultipleTokensMarketData([ - { asset: BTC, unit: USD }, - ]); - - expect(result[BTC]?.[USD]?.pricePercentChange).toStrictEqual({ - PT1H: -0.4456714429821922, - }); - }); - - it('does not include price percent change field if Price API does not return any values', async () => { - jest - .spyOn(mockPriceApiClient, 'getMultipleSpotPrices') - .mockResolvedValue({ - [BTC]: { - ...MOCK_SPOT_PRICES[BTC], - pricePercentChange1h: null, - pricePercentChange1d: null, - pricePercentChange7d: null, - pricePercentChange14d: null, - pricePercentChange30d: null, - pricePercentChange200d: null, - pricePercentChange1y: null, - } as SpotPrice, - }); - - const result = await tokenPricesService.getMultipleTokensMarketData([ - { asset: BTC, unit: USD }, - ]); - - expect(result[BTC]?.[USD]?.pricePercentChange).toBeUndefined(); - }); - - it('handles missing asset data correctly by skipping those assets', async () => { - const result = await tokenPricesService.getMultipleTokensMarketData([ - { asset: UNKNOWN_CRYPTO_1, unit: USD }, - { asset: BTC, unit: USD }, - { asset: UNKNOWN_CRYPTO_2, unit: EUR }, - ]); - - // Should only include BTC since UNKNOWN_CRYPTO_1 and UNKNOWN_CRYPTO_2 don't have price data - expect(result).toStrictEqual({ - [BTC]: { - [USD]: { - fungible: true, - marketCap: '1540421085883.0198', - totalVolume: '23748436299.895576', - circulatingSupply: '19844921', - allTimeHigh: '100847.44951017378', - allTimeLow: '62.86163248290115', - pricePercentChange: { - PT1H: -0.4456714429821922, - P1D: 1.3725526422881404, - P7D: -4.2914380354332256, - P14D: 1.3530761284206316, - P30D: -2.6647248645353425, - P200D: 44.69565022141291, - P1Y: 20.367003699380124, - }, - }, - }, - }); - }); - - it('handles missing unit data correctly by skipping those conversions', async () => { - const result = await tokenPricesService.getMultipleTokensMarketData([ - { asset: BTC, unit: UNKNOWN_FIAT_1 }, - { asset: BTC, unit: USD }, - { asset: ETH, unit: UNKNOWN_FIAT_2 }, - ]); - - // Should only include BTC->USD since UNKNOWN_FIAT_1 and UNKNOWN_FIAT_2 don't have exchange rates - expect(result).toStrictEqual({ - [BTC]: { - [USD]: { - fungible: true, - marketCap: '1540421085883.0198', - totalVolume: '23748436299.895576', - circulatingSupply: '19844921', - allTimeHigh: '100847.44951017378', - allTimeLow: '62.86163248290115', - pricePercentChange: { - PT1H: -0.4456714429821922, - P1D: 1.3725526422881404, - P7D: -4.2914380354332256, - P14D: 1.3530761284206316, - P30D: -2.6647248645353425, - P200D: 44.69565022141291, - P1Y: 20.367003699380124, - }, - }, - }, - }); - }); - - it('handles zero unit rates correctly by skipping those conversions', async () => { - jest - .spyOn(mockPriceApiClient, 'getMultipleSpotPrices') - .mockResolvedValue({ - [BTC]: { - ...MOCK_SPOT_PRICES[BTC]!, - price: 0, // Zero price for unit - }, - [ETH]: MOCK_SPOT_PRICES[ETH]!, - }); - - const result = await tokenPricesService.getMultipleTokensMarketData([ - { asset: ETH, unit: BTC }, // BTC has zero price, so this should be skipped - { asset: ETH, unit: USD }, - ]); - - // Should only include ETH->USD since BTC has zero price - expect(result).toStrictEqual({ - [ETH]: { - [USD]: { - fungible: true, - marketCap: '208326525244.77222', - totalVolume: '14672129201.423573', - circulatingSupply: '120659504.7581715', - allTimeHigh: '4522.273813243435', - allTimeLow: '0.4013827867691204', - pricePercentChange: { - PT1H: -0.16193070976498064, - P1D: 1.9964598342126199, - P7D: -10.123102834312476, - P14D: -1.7452971064771636, - P30D: -16.78602306244949, - P200D: -21.026646670919543, - P1Y: -47.45246230239663, - }, - }, - }, - }); - }); - }); - - describe('getHistoricalPrice', () => { - it('returns historical prices for a token', async () => { - const result = await tokenPricesService.getHistoricalPrice(BTC, USD); - // We use the same prices for all time periods for simplicity - const expectedPrices = MOCK_HISTORICAL_PRICES.prices.map((price) => [ - price[0], - price[1]!.toString(), - ]); - - expect(result).toStrictEqual({ - intervals: { - P1D: expectedPrices, - P7D: expectedPrices, - P1M: expectedPrices, - P3M: expectedPrices, - P1Y: expectedPrices, - P1000Y: expectedPrices, - }, - updateTime: expect.any(Number), - expirationTime: expect.any(Number), - }); - }); - - it('tracks historical price fetch failures', async () => { - const error = new Error('History failed'); - - jest - .spyOn(mockPriceApiClient, 'getHistoricalPrices') - .mockRejectedValueOnce(error); - - await tokenPricesService.getHistoricalPrice(BTC, USD); - - expect(trackError).toHaveBeenCalledWith(error); - }); - }); -}); diff --git a/packages/solana-wallet-snap/src/core/services/token-prices/TokenPrices.ts b/packages/solana-wallet-snap/src/core/services/token-prices/TokenPrices.ts deleted file mode 100644 index e54da2436..000000000 --- a/packages/solana-wallet-snap/src/core/services/token-prices/TokenPrices.ts +++ /dev/null @@ -1,414 +0,0 @@ -import { CaipAssetTypeStruct } from '@metamask/keyring-api'; -import type { CaipAssetType } from '@metamask/keyring-api'; -import type { Logger } from '@metamask/snap-networks-utils'; -import type { - AssetConversion, - FungibleAssetMarketData, - HistoricalPriceIntervals, -} from '@metamask/snaps-sdk'; -import { assert } from '@metamask/superstruct'; -import { parseCaipAssetType } from '@metamask/utils'; -import BigNumber from 'bignumber.js'; -import { pick } from 'lodash'; - -import type { PriceApiClient } from '../../clients/price-api/PriceApiClient'; -import { - GET_HISTORICAL_PRICES_RESPONSE_NULL_OBJECT, - VsCurrencyParamStruct, -} from '../../clients/price-api/types'; -import type { SpotPrice } from '../../clients/price-api/types'; -import type { FiatTicker } from '../../clients/price-api/types'; -import { trackError } from '../../utils/errors'; -import { isFiat } from '../../utils/isFiat'; -import type { ConfigProvider } from '../config'; -import type { HistoricalPrice } from './types'; - -export class TokenPricesService { - readonly #priceApiClient: PriceApiClient; - - readonly #logger: Logger; - - readonly cacheTtlsMilliseconds: { - fiatExchangeRates: number; - spotPrices: number; - historicalPrices: number; - }; - - constructor({ - configProvider, - priceApiClient, - logger, - }: { - configProvider: ConfigProvider; - priceApiClient: PriceApiClient; - logger: Logger; - }) { - this.#priceApiClient = priceApiClient; - this.#logger = logger; - - const { cacheTtlsMilliseconds } = configProvider.get().priceApi; - this.cacheTtlsMilliseconds = cacheTtlsMilliseconds; - } - - /** - * Extracts the ISO 4217 currency code (aka fiat ticker) from a fiat CAIP-19 asset type. - * - * @param caipAssetType - The CAIP-19 asset type. - * @returns The fiat ticker. - */ - #extractFiatTicker(caipAssetType: CaipAssetType): FiatTicker { - if (!isFiat(caipAssetType)) { - throw new Error('Passed caipAssetType is not a fiat asset'); - } - - const fiatTicker = - parseCaipAssetType(caipAssetType).assetReference.toLowerCase(); - - return fiatTicker as FiatTicker; - } - - /** - * Fetches fiat exchange rates and crypto prices for the given assets. - * This is shared logic between getMultipleTokenConversions and getMultipleTokensMarketData. - * - * @param allAssets - Array of all CAIP asset types (both fiat and crypto). - * @returns Promise resolving to fiat exchange rates and crypto prices. - */ - async #fetchPriceData(allAssets: CaipAssetType[]): Promise<{ - fiatExchangeRates: Record; - cryptoPrices: Record; - }> { - const cryptoAssets = allAssets.filter((asset) => !isFiat(asset)); - - const [fiatExchangeRates, cryptoPrices] = await Promise.all([ - this.#priceApiClient.getFiatExchangeRates(), - this.#priceApiClient.getMultipleSpotPrices(cryptoAssets, 'usd'), - ]); - - return { fiatExchangeRates, cryptoPrices }; - } - - /** - * Get the token conversions for a list of asset pairs. - * It caches the results for 1 hour. - * - * Beware: Inside we are using the Price API's `getFiatExchangeRates` method for fiat prices, - * `getMultipleSpotPrices` for crypto prices and then using USD as an intermediate currency - * to convert the prices to the correct currency. This is not entirely accurate but it's the - * best we can do with the current API. - * - * @param conversions - The asset pairs to get the conversions for. - * @returns The token conversions. - */ - async getMultipleTokenConversions( - conversions: { from: CaipAssetType; to: CaipAssetType }[], - ): Promise< - Record> - > { - if (conversions.length === 0) { - return {}; - } - - /** - * `from` and `to` can represent both fiat and crypto assets. For us to get their values - * the best approach is to use Price API's `getFiatExchangeRates` method for fiat prices, - * `getMultipleSpotPrices` for crypto prices and then using USD as an intermediate currency - * to convert the prices to the correct currency. - */ - const allAssets = conversions.flatMap((conversion) => [ - conversion.from, - conversion.to, - ]); - - const { fiatExchangeRates, cryptoPrices } = - await this.#fetchPriceData(allAssets); - - /** - * Now that we have the data, convert the `from`s to `to`s. - * - * We need to handle the following cases: - * 1. `from` and `to` are both fiat - * 2. `from` and `to` are both crypto - * 3. `from` is fiat and `to` is crypto - * 4. `from` is crypto and `to` is fiat - * - * We also need to keep in mind that although `cryptoPrices` are indexed - * by CAIP 19 IDs, the `fiatExchangeRates` are indexed by currency symbols. - * To convert fiat currency symbols to CAIP 19 IDs, we can use the - * `this.#fiatSymbolToCaip19Id` method. - */ - - const result: Record< - CaipAssetType, - Record - > = {}; - - conversions.forEach((conversion) => { - const { from, to } = conversion; - - if (!result[from]) { - result[from] = {}; - } - - let fromUsdRate: BigNumber; - let toUsdRate: BigNumber; - - if (isFiat(from)) { - /** - * Beware: - * We need to invert the fiat exchange rate because exchange rate != spot price - */ - const fiatExchangeRate = - fiatExchangeRates[this.#extractFiatTicker(from)]?.value; - - if (!fiatExchangeRate) { - result[from][to] = null; - return; - } - - fromUsdRate = new BigNumber(1).dividedBy(fiatExchangeRate); - } else { - fromUsdRate = new BigNumber(cryptoPrices[from]?.price ?? 0); - } - - if (isFiat(to)) { - /** - * Beware: - * We need to invert the fiat exchange rate because exchange rate != spot price - */ - const fiatExchangeRate = - fiatExchangeRates[this.#extractFiatTicker(to)]?.value; - - if (!fiatExchangeRate) { - result[from][to] = null; - return; - } - - toUsdRate = new BigNumber(1).dividedBy(fiatExchangeRate); - } else { - toUsdRate = new BigNumber(cryptoPrices[to]?.price ?? 0); - } - - if (fromUsdRate.isZero() || toUsdRate.isZero()) { - result[from][to] = null; - return; - } - - const rate = fromUsdRate.dividedBy(toUsdRate).toString(); - - const now = Date.now(); - - result[from][to] = { - rate, - conversionTime: now, - expirationTime: now + this.cacheTtlsMilliseconds.historicalPrices, - }; - }); - - return result; - } - - /** - * Computes the market data object in the target currency. - * - * @param spotPrice - The spot price of the asset in source currency. - * @param rate - The rate to convert the market data to from source currency to target currency. - * @returns The market data in the target currency. - */ - #computeMarketData( - spotPrice: SpotPrice, - rate: BigNumber, - ): FungibleAssetMarketData { - const marketDataInUsd = pick(spotPrice, [ - 'marketCap', - 'totalVolume', - 'circulatingSupply', - 'allTimeHigh', - 'allTimeLow', - 'pricePercentChange1h', - 'pricePercentChange1d', - 'pricePercentChange7d', - 'pricePercentChange14d', - 'pricePercentChange30d', - 'pricePercentChange200d', - 'pricePercentChange1y', - ]); - - const toCurrency = (value: number | null | undefined): string => { - return value === null || value === undefined - ? '' - : new BigNumber(value).dividedBy(rate).toString(); - }; - - const includeIfDefined = ( - key: string, - value: number | null | undefined, - ) => { - return value === null || value === undefined ? {} : { [key]: value }; - }; - - // Variations in percent don't need to be converted, they are independent of the currency - const pricePercentChange = { - ...includeIfDefined('PT1H', marketDataInUsd.pricePercentChange1h), - ...includeIfDefined('P1D', marketDataInUsd.pricePercentChange1d), - ...includeIfDefined('P7D', marketDataInUsd.pricePercentChange7d), - ...includeIfDefined('P14D', marketDataInUsd.pricePercentChange14d), - ...includeIfDefined('P30D', marketDataInUsd.pricePercentChange30d), - ...includeIfDefined('P200D', marketDataInUsd.pricePercentChange200d), - ...includeIfDefined('P1Y', marketDataInUsd.pricePercentChange1y), - }; - - const marketDataInToCurrency = { - fungible: true, - marketCap: toCurrency(marketDataInUsd.marketCap), - totalVolume: toCurrency(marketDataInUsd.totalVolume), - circulatingSupply: (marketDataInUsd.circulatingSupply ?? 0).toString(), // Circulating supply counts the number of tokens in circulation, so we don't convert - allTimeHigh: toCurrency(marketDataInUsd.allTimeHigh), - allTimeLow: toCurrency(marketDataInUsd.allTimeLow), - // Add pricePercentChange field only if it has values - ...(Object.keys(pricePercentChange).length > 0 - ? { pricePercentChange } - : {}), - } as FungibleAssetMarketData; - - return marketDataInToCurrency; - } - - async getMultipleTokensMarketData( - assets: { - asset: CaipAssetType; - unit: CaipAssetType; - }[], - ): Promise< - Record> - > { - if (assets.length === 0) { - return {}; - } - - /** - * `asset` and `unit` can represent both fiat and crypto assets. For us to get their values - * the best approach is to use Price API's `getFiatExchangeRates` method for fiat prices, - * `getMultipleSpotPrices` for crypto prices and then using USD as an intermediate currency - * to convert the prices to the correct currency. - */ - const allAssets = assets.flatMap((asset) => [asset.asset, asset.unit]); - - const { fiatExchangeRates, cryptoPrices } = - await this.#fetchPriceData(allAssets); - - const result: Record< - CaipAssetType, - Record - > = {}; - - assets.forEach((asset) => { - const { asset: assetType, unit } = asset; - - // Skip if we don't have price data for the asset - if (!cryptoPrices[assetType]) { - return; - } - - let unitUsdRate: BigNumber; - - if (isFiat(unit)) { - /** - * Beware: - * We need to invert the fiat exchange rate because exchange rate != spot price - */ - const fiatExchangeRate = - fiatExchangeRates[this.#extractFiatTicker(unit)]?.value; - - if (!fiatExchangeRate) { - return; - } - - unitUsdRate = new BigNumber(1).dividedBy(fiatExchangeRate); - } else { - unitUsdRate = new BigNumber(cryptoPrices[unit]?.price ?? 0); - } - - if (unitUsdRate.isZero()) { - return; - } - - // Initialize the nested structure for the asset if it doesn't exist - if (!result[assetType]) { - result[assetType] = {}; - } - - // Store the market data with the unit as the key - result[assetType][unit] = this.#computeMarketData( - cryptoPrices[assetType], - unitUsdRate, - ); - }); - - return result; - } - - async getHistoricalPrice( - from: CaipAssetType, - to: CaipAssetType, - ): Promise { - assert(from, CaipAssetTypeStruct); - assert(to, CaipAssetTypeStruct); - - const toTicker = parseCaipAssetType(to).assetReference.toLowerCase(); - assert(toTicker, VsCurrencyParamStruct); - - const timePeriodsToFetch = ['1d', '7d', '1m', '3m', '1y', '1000y']; - - // For each time period, call the Price API to fetch the historical prices - const promises = timePeriodsToFetch.map(async (timePeriod) => - this.#priceApiClient - .getHistoricalPrices({ - assetType: from, - timePeriod, - vsCurrency: toTicker, - }) - // Wrap the response in an object with the time period and the response for easier reducing - .then((response) => ({ - timePeriod, - response, - })) - // Gracefully handle individual errors to avoid breaking the entire operation - .catch(async (error) => { - await trackError(error); - this.#logger.warn( - `Error fetching historical prices for ${from} to ${to} with time period ${timePeriod}. Returning null object.`, - error, - ); - return { - timePeriod, - response: GET_HISTORICAL_PRICES_RESPONSE_NULL_OBJECT, - }; - }), - ); - - const wrappedHistoricalPrices = await Promise.all(promises); - - const intervals = wrappedHistoricalPrices.reduce( - (acc, { timePeriod, response }) => { - const iso8601Interval = `P${timePeriod.toUpperCase()}`; - acc[iso8601Interval] = response.prices.map((price) => [ - price[0], - price[1].toString(), - ]); - return acc; - }, - {}, - ); - - const now = Date.now(); - - const result: HistoricalPrice = { - intervals, - updateTime: now, - expirationTime: now + this.cacheTtlsMilliseconds.historicalPrices, - }; - - return result; - } -} diff --git a/packages/solana-wallet-snap/src/core/services/token-prices/types.ts b/packages/solana-wallet-snap/src/core/services/token-prices/types.ts deleted file mode 100644 index fc2e64a2c..000000000 --- a/packages/solana-wallet-snap/src/core/services/token-prices/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { OnAssetHistoricalPriceResponse } from '@metamask/snaps-sdk'; - -export type HistoricalPrice = - NonNullable['historicalPrice']; diff --git a/packages/solana-wallet-snap/src/core/test/mocks/market-data.ts b/packages/solana-wallet-snap/src/core/test/mocks/market-data.ts deleted file mode 100644 index 3cbde9ffd..000000000 --- a/packages/solana-wallet-snap/src/core/test/mocks/market-data.ts +++ /dev/null @@ -1,243 +0,0 @@ -import type { FungibleAssetMarketData } from '@metamask/snaps-sdk'; -import type { CaipAssetType } from '@metamask/utils'; - -// Common asset types for testing -export const TEST_ASSET_TYPES = { - BTC: 'bip122:000000000019d6689c085ae165831e93/slip44:0' as CaipAssetType, - ETH: 'eip155:1/slip44:60' as CaipAssetType, - SOL: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501' as CaipAssetType, - USDC: 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' as CaipAssetType, - USD: 'swift:0/iso4217:USD' as CaipAssetType, - EUR: 'swift:0/iso4217:EUR' as CaipAssetType, - GBP: 'swift:0/iso4217:GBP' as CaipAssetType, - SPECIAL_SOL: - 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/slip44:501' as CaipAssetType, -} as const; - -// ISO 8601 duration constants -export const ISO_DURATIONS = { - PT1H: 'PT1H', - P1D: 'P1D', - P7D: 'P7D', - P14D: 'P14D', - P30D: 'P30D', - P200D: 'P200D', - P1Y: 'P1Y', -} as const; - -// Mock market data for different scenarios -export const MOCK_MARKET_DATA: Record = - { - [TEST_ASSET_TYPES.BTC]: { - fungible: true, - marketCap: '1000000000000', - totalVolume: '50000000000', - circulatingSupply: '19500000', - allTimeHigh: '120000', - allTimeLow: '67.81', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 0.5, - [ISO_DURATIONS.P1D]: 2.1, - [ISO_DURATIONS.P7D]: -1.2, - [ISO_DURATIONS.P30D]: 15.3, - [ISO_DURATIONS.P200D]: 45.1, - [ISO_DURATIONS.P1Y]: 21.4, - }, - }, - [TEST_ASSET_TYPES.ETH]: { - fungible: true, - marketCap: '400000000000', - totalVolume: '20000000000', - circulatingSupply: '120000000', - allTimeHigh: '5000', - allTimeLow: '0.43', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 1.2, - [ISO_DURATIONS.P1D]: 3.5, - [ISO_DURATIONS.P7D]: 5.1, - [ISO_DURATIONS.P30D]: 8.7, - }, - }, - [TEST_ASSET_TYPES.SOL]: { - fungible: true, - marketCap: '80000000000', - totalVolume: '3000000000', - circulatingSupply: '400000000', - allTimeHigh: '260', - allTimeLow: '0.5', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: -0.8, - [ISO_DURATIONS.P1D]: 1.5, - [ISO_DURATIONS.P7D]: -2.3, - }, - }, - [TEST_ASSET_TYPES.USDC]: { - fungible: true, - marketCap: '25000000000', - totalVolume: '1500000000', - circulatingSupply: '25000000000', - allTimeHigh: '1.05', - allTimeLow: '0.95', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 0.01, - [ISO_DURATIONS.P1D]: 0.02, - [ISO_DURATIONS.P7D]: 0.05, - }, - }, - [TEST_ASSET_TYPES.SPECIAL_SOL]: { - fungible: true, - marketCap: '50000000', - totalVolume: '2000000', - circulatingSupply: '1000000', - }, - }; - -// Mock market data for different currencies -export const MOCK_MARKET_DATA_EUR: Record< - CaipAssetType, - FungibleAssetMarketData -> = { - [TEST_ASSET_TYPES.BTC]: { - fungible: true, - marketCap: '850000000000', - totalVolume: '42500000000', - circulatingSupply: '19500000', - allTimeHigh: '102000', - allTimeLow: '57.64', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 0.3, - [ISO_DURATIONS.P1D]: 1.8, - }, - }, - [TEST_ASSET_TYPES.ETH]: { - fungible: true, - marketCap: '340000000000', - totalVolume: '17000000000', - circulatingSupply: '120000000', - allTimeHigh: '4250', - allTimeLow: '0.37', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 1.0, - [ISO_DURATIONS.P1D]: 3.0, - }, - }, -}; - -// Mock market data with minimal fields -export const MOCK_MARKET_DATA_MINIMAL: Record< - CaipAssetType, - FungibleAssetMarketData -> = { - [TEST_ASSET_TYPES.BTC]: { - fungible: true, - marketCap: '1000000000000', - // Missing other fields - }, - [TEST_ASSET_TYPES.ETH]: { - fungible: true, - // Only fungible field - }, -}; - -// Mock market data with only price percent changes -export const MOCK_MARKET_DATA_PRICE_CHANGES_ONLY: Record< - CaipAssetType, - FungibleAssetMarketData -> = { - [TEST_ASSET_TYPES.BTC]: { - fungible: true, - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 0.5, - [ISO_DURATIONS.P1D]: 2.1, - [ISO_DURATIONS.P7D]: -1.2, - }, - }, -}; - -// Mock market data with zero values -export const MOCK_MARKET_DATA_ZERO_VALUES: Record< - CaipAssetType, - FungibleAssetMarketData -> = { - [TEST_ASSET_TYPES.ETH]: { - fungible: true, - marketCap: '0', - totalVolume: '0', - circulatingSupply: '0', - allTimeHigh: '0', - allTimeLow: '0', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 0, - [ISO_DURATIONS.P1D]: 0, - [ISO_DURATIONS.P7D]: 0, - }, - }, -}; - -// Mock market data with very large numbers -export const MOCK_MARKET_DATA_LARGE_NUMBERS: Record< - CaipAssetType, - FungibleAssetMarketData -> = { - [TEST_ASSET_TYPES.BTC]: { - fungible: true, - marketCap: '999999999999999999999999999999', - totalVolume: '123456789012345678901234567890', - circulatingSupply: '21000000', - allTimeHigh: '999999999999999999999999999999', - allTimeLow: '0.000000000000000001', - pricePercentChange: { - [ISO_DURATIONS.PT1H]: 999.99, - [ISO_DURATIONS.P1D]: -999.99, - }, - }, -}; - -// Mock asset request parameters -export const MOCK_ASSET_REQUESTS = { - SINGLE_BTC_USD: [{ asset: TEST_ASSET_TYPES.BTC, unit: TEST_ASSET_TYPES.USD }], - MULTIPLE_CRYPTO_USD: [ - { asset: TEST_ASSET_TYPES.BTC, unit: TEST_ASSET_TYPES.USD }, - { asset: TEST_ASSET_TYPES.ETH, unit: TEST_ASSET_TYPES.USD }, - { asset: TEST_ASSET_TYPES.SOL, unit: TEST_ASSET_TYPES.USD }, - ], - MIXED_CURRENCIES: [ - { asset: TEST_ASSET_TYPES.BTC, unit: TEST_ASSET_TYPES.EUR }, - { asset: TEST_ASSET_TYPES.ETH, unit: TEST_ASSET_TYPES.USD }, - ], - EMPTY: [], - SPECIAL_CHARACTERS: [ - { asset: TEST_ASSET_TYPES.SPECIAL_SOL, unit: TEST_ASSET_TYPES.USD }, - ], -} as const; - -// Helper function to create mock market data for specific assets -export const createMockMarketData = ( - assets: CaipAssetType[], - dataSource: Record = MOCK_MARKET_DATA, -): Record => { - const result: Record = {}; - - for (const asset of assets) { - if (dataSource[asset]) { - result[asset] = dataSource[asset]; - } - } - - return result; -}; - -// Helper function to create mock asset requests -export const createMockAssetRequest = ( - assets: { asset: CaipAssetType; unit: CaipAssetType }[], -) => ({ - assets, -}); - -// Mock error scenarios -export const MOCK_ERRORS = { - NETWORK_TIMEOUT: new Error('Network timeout'), - INVALID_ASSET_TYPE: new Error('Invalid asset type'), - SERVICE_UNAVAILABLE: new Error('Service unavailable'), - RATE_LIMIT_EXCEEDED: new Error('Rate limit exceeded'), -} as const; diff --git a/packages/solana-wallet-snap/src/core/test/mocks/price-api/exchange-rates.ts b/packages/solana-wallet-snap/src/core/test/mocks/price-api/exchange-rates.ts deleted file mode 100644 index 8bb336df4..000000000 --- a/packages/solana-wallet-snap/src/core/test/mocks/price-api/exchange-rates.ts +++ /dev/null @@ -1,476 +0,0 @@ -import type { ExchangeRate, Ticker } from '../../../clients/price-api/types'; - -/** - * HEADS UP! Changing this mock MUST involve changing the spot prices mock too! - * Their values are interdependent and essential for the TokenPricesService tests. - */ -export const MOCK_EXCHANGE_RATES: Record = { - btc: { - name: 'Bitcoin', - ticker: 'btc', - value: 0.000009225522122806664, - currencyType: 'crypto', - }, - eth: { - name: 'Ether', - ticker: 'eth', - value: 0.0004032198954215109, - currencyType: 'crypto', - }, - ltc: { - name: 'Litecoin', - ticker: 'ltc', - value: 0.011656225789635273, - currencyType: 'crypto', - }, - bch: { - name: 'Bitcoin Cash', - ticker: 'bch', - value: 0.001982942950598187, - currencyType: 'crypto', - }, - bnb: { - name: 'Binance Coin', - ticker: 'bnb', - value: 0.0015156056764231698, - currencyType: 'crypto', - }, - eos: { - name: 'EOS', - ticker: 'eos', - value: 2.056880058128908, - currencyType: 'crypto', - }, - xrp: { - name: 'XRP', - ticker: 'xrp', - value: 0.4540842119866674, - currencyType: 'crypto', - }, - xlm: { - name: 'Lumens', - ticker: 'xlm', - value: 4.29161071887215, - currencyType: 'crypto', - }, - link: { - name: 'Chainlink', - ticker: 'link', - value: 0.07546219704388624, - currencyType: 'crypto', - }, - dot: { - name: 'Polkadot', - ticker: 'dot', - value: 0.29389602831032285, - currencyType: 'crypto', - }, - yfi: { - name: 'Yearn.finance', - ticker: 'yfi', - value: 0.00019925282680837832, - currencyType: 'crypto', - }, - usd: { - name: 'US Dollar', - ticker: 'usd', - value: 1, - currencyType: 'fiat', - }, - aed: { - name: 'United Arab Emirates Dirham', - ticker: 'aed', - value: 3.6730349953852555, - currencyType: 'fiat', - }, - ars: { - name: 'Argentine Peso', - ticker: 'ars', - value: 1206.0000013561519, - currencyType: 'fiat', - }, - aud: { - name: 'Australian Dollar', - ticker: 'aud', - value: 1.5232439935923583, - currencyType: 'fiat', - }, - bdt: { - name: 'Bangladeshi Taka', - ticker: 'bdt', - value: 122.29205113607277, - currencyType: 'fiat', - }, - bhd: { - name: 'Bahraini Dinar', - ticker: 'bhd', - value: 0.3769909979846017, - currencyType: 'fiat', - }, - bmd: { - name: 'Bermudian Dollar', - ticker: 'bmd', - value: 1, - currencyType: 'fiat', - }, - brl: { - name: 'Brazil Real', - ticker: 'brl', - value: 5.446300002410629, - currencyType: 'fiat', - }, - cad: { - name: 'Canadian Dollar', - ticker: 'cad', - value: 1.3640219988479354, - currencyType: 'fiat', - }, - chf: { - name: 'Swiss Franc', - ticker: 'chf', - value: 0.7936309928980179, - currencyType: 'fiat', - }, - clp: { - name: 'Chilean Peso', - ticker: 'clp', - value: 923.830001036303, - currencyType: 'fiat', - }, - cny: { - name: 'Chinese Yuan', - ticker: 'cny', - value: 7.166700000015684, - currencyType: 'fiat', - }, - czk: { - name: 'Czech Koruna', - ticker: 'czk', - value: 20.952984017733154, - currencyType: 'fiat', - }, - dkk: { - name: 'Danish Krone', - ticker: 'dkk', - value: 6.339276002611524, - currencyType: 'fiat', - }, - eur: { - name: 'Euro', - ticker: 'eur', - value: 0.8496419976174352, - currencyType: 'fiat', - }, - gbp: { - name: 'British Pound Sterling', - ticker: 'gbp', - value: 0.7356629966217338, - currencyType: 'fiat', - }, - gel: { - name: 'Georgian Lari', - ticker: 'gel', - value: 2.719999997416854, - currencyType: 'fiat', - }, - hkd: { - name: 'Hong Kong Dollar', - ticker: 'hkd', - value: 7.84986500616371, - currencyType: 'fiat', - }, - huf: { - name: 'Hungarian Forint', - ticker: 'huf', - value: 340.2474533753413, - currencyType: 'fiat', - }, - idr: { - name: 'Indonesian Rupiah', - ticker: 'idr', - value: 16212.776418318166, - currencyType: 'fiat', - }, - ils: { - name: 'Israeli New Shekel', - ticker: 'ils', - value: 3.3717049952207647, - currencyType: 'fiat', - }, - inr: { - name: 'Indian Rupee', - ticker: 'inr', - value: 85.59833408842695, - currencyType: 'fiat', - }, - jpy: { - name: 'Japanese Yen', - ticker: 'jpy', - value: 143.9902001614485, - currencyType: 'fiat', - }, - krw: { - name: 'South Korean Won', - ticker: 'krw', - value: 1359.3506945328236, - currencyType: 'fiat', - }, - kwd: { - name: 'Kuwaiti Dinar', - ticker: 'kwd', - value: 0.30529199289535164, - currencyType: 'fiat', - }, - lkr: { - name: 'Sri Lankan Rupee', - ticker: 'lkr', - value: 299.9010793298127, - currencyType: 'fiat', - }, - mmk: { - name: 'Burmese Kyat', - ticker: 'mmk', - value: 2098.0000023617336, - currencyType: 'fiat', - }, - mxn: { - name: 'Mexican Peso', - ticker: 'mxn', - value: 18.77348001704397, - currencyType: 'fiat', - }, - myr: { - name: 'Malaysian Ringgit', - ticker: 'myr', - value: 4.228999997038608, - currencyType: 'fiat', - }, - ngn: { - name: 'Nigerian Naira', - ticker: 'ngn', - value: 1532.4200017290473, - currencyType: 'fiat', - }, - nok: { - name: 'Norwegian Krone', - ticker: 'nok', - value: 10.109898008254978, - currencyType: 'fiat', - }, - nzd: { - name: 'New Zealand Dollar', - ticker: 'nzd', - value: 1.6478669960903807, - currencyType: 'fiat', - }, - php: { - name: 'Philippine Peso', - ticker: 'php', - value: 56.376001062558736, - currencyType: 'fiat', - }, - pkr: { - name: 'Pakistani Rupee', - ticker: 'pkr', - value: 285.2245003132019, - currencyType: 'fiat', - }, - pln: { - name: 'Polish Zloty', - ticker: 'pln', - value: 3.625871995197858, - currencyType: 'fiat', - }, - rub: { - name: 'Russian Ruble', - ticker: 'rub', - value: 78.79997408366326, - currencyType: 'fiat', - }, - sar: { - name: 'Saudi Riyal', - ticker: 'sar', - value: 3.7501600005365567, - currencyType: 'fiat', - }, - sek: { - name: 'Swedish Krona', - ticker: 'sek', - value: 9.55167101005786, - currencyType: 'fiat', - }, - sgd: { - name: 'Singapore Dollar', - ticker: 'sgd', - value: 1.2739619998345126, - currencyType: 'fiat', - }, - thb: { - name: 'Thai Baht', - ticker: 'thb', - value: 32.40583303378832, - currencyType: 'fiat', - }, - try: { - name: 'Turkish Lira', - ticker: 'try', - value: 39.788298041452094, - currencyType: 'fiat', - }, - twd: { - name: 'New Taiwan Dollar', - ticker: 'twd', - value: 29.018999031034188, - currencyType: 'fiat', - }, - uah: { - name: 'Ukrainian hryvnia', - ticker: 'uah', - value: 41.75092204711494, - currencyType: 'fiat', - }, - vef: { - name: 'Venezuelan bolívar fuerte', - ticker: 'vef', - value: 0.10012999775478468, - currencyType: 'fiat', - }, - vnd: { - name: 'Vietnamese đồng', - ticker: 'vnd', - value: 26167.73565956473, - currencyType: 'fiat', - }, - zar: { - name: 'South African Rand', - ticker: 'zar', - value: 17.638879012711193, - currencyType: 'fiat', - }, - xdr: { - name: 'IMF Special Drawing Rights', - ticker: 'xdr', - value: 0.6961849947454656, - currencyType: 'fiat', - }, - xag: { - name: 'Silver - Troy Ounce', - ticker: 'xag', - value: 0.02745114996087133, - currencyType: 'commodity', - }, - xau: { - name: 'Gold - Troy Ounce', - ticker: 'xau', - value: 0.0002992943887080938, - currencyType: 'commodity', - }, - bits: { - name: 'Bits', - ticker: 'bits', - value: 9.225522122806664, - currencyType: 'crypto', - }, - sats: { - name: 'Satoshi', - ticker: 'sats', - value: 922.5522122806664, - currencyType: 'crypto', - }, - cop: { - name: 'Colombian Peso', - ticker: 'cop', - value: 4020.329999998432, - currencyType: 'fiat', - }, - kes: { - name: 'Kenyan Shilling', - ticker: 'kes', - value: 129.20000000184513, - currencyType: 'fiat', - }, - ron: { - name: 'Romanian Leu', - ticker: 'ron', - value: 4.302400003896861, - currencyType: 'fiat', - }, - dop: { - name: 'Dominican Peso', - ticker: 'dop', - value: 59.421077000552856, - currencyType: 'fiat', - }, - crc: { - name: 'Costa Rican Colón', - ticker: 'crc', - value: 505.1511230011281, - currencyType: 'fiat', - }, - hnl: { - name: 'Honduran Lempira', - ticker: 'hnl', - value: 26.133209998558144, - currencyType: 'fiat', - }, - zmw: { - name: 'Zambian Kwacha', - ticker: 'zmw', - value: 24.02423300185325, - currencyType: 'fiat', - }, - svc: { - name: 'Salvadoran Colón', - ticker: 'svc', - value: 8.749590998008589, - currencyType: 'fiat', - }, - bam: { - name: 'Bosnia and Herzegovina Convertible Mark', - ticker: 'bam', - value: 1.6618870036093658, - currencyType: 'fiat', - }, - pen: { - name: 'Peruvian Sol', - ticker: 'pen', - value: 3.5611860013883123, - currencyType: 'fiat', - }, - gtq: { - name: 'Guatemalan Quetzal', - ticker: 'gtq', - value: 7.688288003161476, - currencyType: 'fiat', - }, - lbp: { - name: 'Lebanese Pound', - ticker: 'lbp', - value: 89577.29288500333, - currencyType: 'fiat', - }, - amd: { - name: 'Armenian Dram', - ticker: 'amd', - value: 384.5100000000923, - currencyType: 'fiat', - }, - sol: { - name: 'Solana', - ticker: 'sol', - value: 0.006629188747026665, - currencyType: 'crypto', - }, - sei: { - name: 'Sei Network', - ticker: 'sei', - value: 3.571422841670739, - currencyType: 'crypto', - }, - sonic: { - name: 'Sonic', - ticker: 'sonic', - value: 3.0932878113426843, - currencyType: 'crypto', - }, -}; diff --git a/packages/solana-wallet-snap/src/core/test/mocks/price-api/spot-prices.ts b/packages/solana-wallet-snap/src/core/test/mocks/price-api/spot-prices.ts deleted file mode 100644 index 4d24f92c5..000000000 --- a/packages/solana-wallet-snap/src/core/test/mocks/price-api/spot-prices.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * HEADS UP! Changing this mock MUST involve changing the exchange rates mock too! - * Their values are interdependent and essential for the TokenPricesService tests. - */ -export const MOCK_SPOT_PRICES = { - 'bip122:000000000019d6689c085ae165831e93/slip44:0': { - id: 'bitcoin', - price: 108383, - marketCap: 2153703484251, - allTimeHigh: 111814, - allTimeLow: 67.81, - totalVolume: 26490441505, - high1d: 108312, - low1d: 105402, - circulatingSupply: 19886487, - dilutedMarketCap: 2153703484251, - marketCapPercentChange1d: 2.32194, - priceChange1d: 2558.06, - pricePercentChange1h: 0.3843563748092404, - pricePercentChange1d: 2.417256898831376, - pricePercentChange7d: 0.5848420826167852, - pricePercentChange14d: 3.573582647113796, - pricePercentChange30d: 4.0364417287116305, - pricePercentChange200d: 6.841043820722927, - pricePercentChange1y: 74.83031943795173, - }, - 'eip155:1/slip44:60': { - id: 'ethereum', - price: 2472.85, - marketCap: 298533579846, - allTimeHigh: 4878.26, - allTimeLow: 0.432979, - totalVolume: 9053920577, - high1d: 2473.06, - low1d: 2393.31, - circulatingSupply: 120717388.8264203, - dilutedMarketCap: 298533579846, - marketCapPercentChange1d: 2.15855, - priceChange1d: 52.3, - pricePercentChange1h: 0.7092921207897362, - pricePercentChange1d: 2.160678145136992, - pricePercentChange7d: 1.7425998170003503, - pricePercentChange14d: -1.2732287255912829, - pricePercentChange30d: -2.09981500745285, - pricePercentChange200d: -36.383873763555656, - pricePercentChange1y: -27.526564808866777, - }, - 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501': { - id: 'solana', - price: 150.62, - marketCap: 80423231441, - allTimeHigh: 293.31, - allTimeLow: 0.500801, - totalVolume: 3556506112, - high1d: 150.43, - low1d: 145.46, - circulatingSupply: 534608592.310483, - dilutedMarketCap: 90908091780, - marketCapPercentChange1d: 2.29743, - priceChange1d: 3.56, - pricePercentChange1h: 0.8121844458320602, - pricePercentChange1d: 2.421143543804292, - pricePercentChange7d: 3.176470205229667, - pricePercentChange14d: 3.6015257116898223, - pricePercentChange30d: -1.7218014883767463, - pricePercentChange200d: -32.14283758271846, - pricePercentChange1y: 1.6989732581584913, - }, - 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': { - id: 'usd-coin', - price: 0.999884, - marketCap: 61656570570, - allTimeHigh: 1.17, - allTimeLow: 0.877647, - totalVolume: 7485377052, - high1d: 0.999925, - low1d: 0.999805, - circulatingSupply: 61662495506.43694, - dilutedMarketCap: 61685561207, - marketCapPercentChange1d: 0.11783, - priceChange1d: 0.00002247, - pricePercentChange1h: -0.0020655637951524234, - pricePercentChange1d: 0.002247764341345683, - pricePercentChange7d: -0.006438761910950978, - pricePercentChange14d: 0.007949688389332093, - pricePercentChange30d: 0.014871097408860527, - pricePercentChange200d: -0.024999725392617834, - pricePercentChange1y: -0.09035143373815327, - }, -}; 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; -}; diff --git a/packages/solana-wallet-snap/src/snapContext.ts b/packages/solana-wallet-snap/src/snapContext.ts index 28e86afd6..6dfc9d683 100644 --- a/packages/solana-wallet-snap/src/snapContext.ts +++ b/packages/solana-wallet-snap/src/snapContext.ts @@ -43,7 +43,6 @@ import { NftService } from './core/services/nft/NftService'; import type { IStateManager } from './core/services/state/IStateManager'; import type { UnencryptedStateValue } from './core/services/state/State'; import { DEFAULT_UNENCRYPTED_STATE, State } from './core/services/state/State'; -import { TokenPricesService } from './core/services/token-prices/TokenPrices'; import { TransactionScanService } from './core/services/transaction-scan/TransactionScan'; import { WalletService } from './core/services/wallet/WalletService'; import logger, { noOpLogger } from './core/utils/logger'; @@ -60,7 +59,6 @@ export type SnapExecutionContext = { priceApiClient: PriceApiClient; state: IStateManager; assetsService: AssetsService; - tokenPricesService: TokenPricesService; signer: Signer; transactionsService: TransactionsService; sendSolBuilder: SendSolBuilder; @@ -138,11 +136,6 @@ const priceApiClient = new PriceApiClient(configProvider, inMemoryCache); const tokenApiClient = new TokenApiClient(configProvider); const nftApiClient = new NftApiClient(configProvider, inMemoryCache); -const tokenPricesService = new TokenPricesService({ - configProvider, - priceApiClient, - logger, -}); const nameResolutionService = new NameResolutionService(connection, logger); const assetsRepository = new AssetsRepository(state); @@ -157,7 +150,6 @@ const snapAssetsAdapter = new SnapAssetsAdapter({ assetsRepository, accountsService, tokenApiClient, - tokenPricesService, cache: inMemoryCache, nftApiClient, }); @@ -277,7 +269,6 @@ const snapContext: SnapExecutionContext = { cache: stateCache, /* Services */ assetsService, - tokenPricesService, signer, transactionsService, sendSolBuilder, @@ -319,7 +310,6 @@ export { subscriptionService, tokenApiClient, tokenHelper, - tokenPricesService, transactionScanService, transactionsService, walletService,