Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions packages/assets-controllers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- **BREAKING:** TokenRatesController now takes a required argument `tokenPricesService` ([#3600](https://github.com/MetaMask/core/pull/3600))
- This object is responsible for fetching the prices for tokens held by this controller.
- **BREAKING:** Update signature of `TokenRatesController.updateExchangeRatesByChainId` ([#3600](https://github.com/MetaMask/core/pull/3600))
- Rename `tokenAddresses` argument to `tokenContractAddresses`
- Change the type of `tokenContractAddresses` from `string[]` to `Hex[]`
- **BREAKING:** Change signature of `TokenRatesController.fetchAndMapExchangeRates` ([#3600](https://github.com/MetaMask/core/pull/3600))
- This method now takes an object with shape `{ tokenContractAddresses: Hex[]; chainId: Hex; nativeCurrency: string; }` rather than positional arguments
- **BREAKING:** Update signature of `TokenRatesController.updateExchangeRatesByChainId` ([#3600](https://github.com/MetaMask/core/pull/3600), [#3653](https://github.com/MetaMask/core/pull/3653))
- Change the type of `tokenAddresses` from `string[]` to `Hex[]`
- **BREAKING:** Change signature of `TokenRatesController.fetchAndMapExchangeRates` ([#3600](https://github.com/MetaMask/core/pull/3600), [#3653](https://github.com/MetaMask/core/pull/3653))
- This method now takes an object with shape `{ tokenAddresses: Hex[]; chainId: Hex; nativeCurrency: string; }` rather than positional arguments
- Update TokenListController to fetch prefiltered set of tokens from the API, reducing response data and removing the need for filtering logic ([#2054](https://github.com/MetaMask/core/pull/2054))

### Removed
Expand Down
36 changes: 18 additions & 18 deletions packages/assets-controllers/src/TokenRatesController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { advanceTime } from '../../../tests/helpers';
import type {
AbstractTokenPricesService,
TokenPrice,
TokenPricesByTokenContractAddress,
TokenPricesByTokenAddress,
} from './token-prices-service/abstract-token-prices-service';
import type { TokenBalancesState } from './TokenBalancesController';
import { TokenRatesController } from './TokenRatesController';
Expand Down Expand Up @@ -1691,12 +1691,12 @@ describe('TokenRatesController', () => {
fetchTokenPrices: jest.fn().mockResolvedValue({
[tokenAddresses[0]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[0],
tokenAddress: tokenAddresses[0],
value: 0.001,
},
[tokenAddresses[1]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[1],
tokenAddress: tokenAddresses[1],
value: 0.002,
},
}),
Expand Down Expand Up @@ -1760,12 +1760,12 @@ describe('TokenRatesController', () => {
fetchTokenPrices: jest.fn().mockResolvedValue({
[tokenAddresses[0]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[0],
tokenAddress: tokenAddresses[0],
value: 0.001,
},
[tokenAddresses[1]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[1],
tokenAddress: tokenAddresses[1],
value: 0.002,
},
}),
Expand Down Expand Up @@ -1827,12 +1827,12 @@ describe('TokenRatesController', () => {
fetchTokenPrices: jest.fn().mockResolvedValue({
[tokenAddresses[0]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[0],
tokenAddress: tokenAddresses[0],
value: 0.001,
},
[tokenAddresses[1]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[1],
tokenAddress: tokenAddresses[1],
value: 0.002,
},
}),
Expand Down Expand Up @@ -1909,12 +1909,12 @@ describe('TokenRatesController', () => {
fetchTokenPrices: jest.fn().mockResolvedValue({
[tokenAddresses[0]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[0],
tokenAddress: tokenAddresses[0],
value: 0.001,
},
[tokenAddresses[1]]: {
currency: 'ETH',
tokenContractAddress: tokenAddresses[1],
tokenAddress: tokenAddresses[1],
value: 0.002,
},
}),
Expand Down Expand Up @@ -2256,31 +2256,31 @@ function buildMockTokenPricesService(
* price of each given token is incremented by one.
*
* @param args - The arguments to this function.
* @param args.tokenContractAddresses - The token contract addresses.
* @param args.tokenAddresses - The token addresses.
* @param args.currency - The currency.
* @returns The token prices.
*/
async function fetchTokenPricesWithIncreasingPriceForEachToken<
TokenAddress extends Hex,
Currency extends string,
>({
tokenContractAddresses,
tokenAddresses,
currency,
}: {
tokenContractAddresses: TokenAddress[];
tokenAddresses: TokenAddress[];
currency: Currency;
}) {
return tokenContractAddresses.reduce<
Partial<TokenPricesByTokenContractAddress<TokenAddress, Currency>>
>((obj, tokenContractAddress, i) => {
return tokenAddresses.reduce<
Partial<TokenPricesByTokenAddress<TokenAddress, Currency>>
>((obj, tokenAddress, i) => {
const tokenPrice: TokenPrice<TokenAddress, Currency> = {
tokenContractAddress,
tokenAddress,
value: (i + 1) / 1000,
currency,
};
return {
...obj,
[tokenContractAddress]: tokenPrice,
[tokenAddress]: tokenPrice,
};
}, {}) as TokenPricesByTokenContractAddress<TokenAddress, Currency>;
}, {}) as TokenPricesByTokenAddress<TokenAddress, Currency>;
}
62 changes: 31 additions & 31 deletions packages/assets-controllers/src/TokenRatesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ export class TokenRatesController extends StaticIntervalPollingControllerV1<
return;
}

const tokenContractAddresses = this.#getTokenAddresses(chainId);
if (tokenContractAddresses.length === 0) {
const tokenAddresses = this.#getTokenAddresses(chainId);
if (tokenAddresses.length === 0) {
return;
}

Expand All @@ -380,7 +380,7 @@ export class TokenRatesController extends StaticIntervalPollingControllerV1<

try {
const newContractExchangeRates = await this.#fetchAndMapExchangeRates({
tokenContractAddresses,
tokenAddresses,
chainId,
nativeCurrency,
});
Expand Down Expand Up @@ -430,42 +430,42 @@ export class TokenRatesController extends StaticIntervalPollingControllerV1<
* exchange rate between the known currency and desired currency.
*
* @param args - The arguments to this function.
* @param args.tokenContractAddresses - Contract addresses for tokens.
* @param args.tokenAddresses - Addresses for tokens.
* @param args.chainId - The EIP-155 ID of the chain where the tokens live.
* @param args.nativeCurrency - The native currency in which to request
* exchange rates.
* @returns A map from token contract address to its exchange rate in the
* native currency, or an empty map if no exchange rates can be obtained for
* the chain ID.
* @returns A map from token address to its exchange rate in the native
* currency, or an empty map if no exchange rates can be obtained for the
* chain ID.
*/
async #fetchAndMapExchangeRates({
tokenContractAddresses,
tokenAddresses,
chainId,
nativeCurrency,
}: {
tokenContractAddresses: Hex[];
tokenAddresses: Hex[];
chainId: Hex;
nativeCurrency: string;
}): Promise<ContractExchangeRates> {
if (!this.#tokenPricesService.validateChainIdSupported(chainId)) {
return tokenContractAddresses.reduce((obj, tokenContractAddress) => {
return tokenAddresses.reduce((obj, tokenAddress) => {
return {
...obj,
[tokenContractAddress]: undefined,
[tokenAddress]: undefined,
};
}, {});
}

if (this.#tokenPricesService.validateCurrencySupported(nativeCurrency)) {
return await this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({
tokenContractAddresses,
tokenAddresses,
chainId,
nativeCurrency,
});
}

return await this.#fetchAndMapExchangeRatesForUnsupportedNativeCurrency({
tokenContractAddresses,
tokenAddresses,
nativeCurrency,
});
}
Expand All @@ -489,34 +489,34 @@ export class TokenRatesController extends StaticIntervalPollingControllerV1<
* chain. Ensures that token addresses are checksum addresses.
*
* @param args - The arguments to this function.
* @param args.tokenContractAddresses - Contract addresses for tokens.
* @param args.tokenAddresses - Addresses for tokens.
* @param args.chainId - The EIP-155 ID of the chain where the tokens live.
* @param args.nativeCurrency - The native currency in which to request
* prices.
* @returns A map of the token addresses (as checksums) to their prices in the
* native currency.
*/
async #fetchAndMapExchangeRatesForSupportedNativeCurrency({
tokenContractAddresses,
tokenAddresses,
chainId,
nativeCurrency,
}: {
tokenContractAddresses: Hex[];
tokenAddresses: Hex[];
chainId: Hex;
nativeCurrency: string;
}): Promise<ContractExchangeRates> {
const tokenPricesByTokenContractAddress =
const tokenPricesByTokenAddress =
await this.#tokenPricesService.fetchTokenPrices({
tokenContractAddresses,
tokenAddresses,
chainId,
currency: nativeCurrency,
});

return Object.entries(tokenPricesByTokenContractAddress).reduce(
(obj, [tokenContractAddress, tokenPrice]) => {
return Object.entries(tokenPricesByTokenAddress).reduce(
(obj, [tokenAddress, tokenPrice]) => {
return {
...obj,
[tokenContractAddress]: tokenPrice.value,
[tokenAddress]: tokenPrice.value,
};
},
{},
Expand All @@ -529,25 +529,25 @@ export class TokenRatesController extends StaticIntervalPollingControllerV1<
* API, then convert the prices to our desired native currency.
*
* @param args - The arguments to this function.
* @param args.tokenContractAddresses - The contract addresses for the tokens you
* want to retrieve prices for.
* @param args.nativeCurrency - The currency you want the prices to be in.
* @param args.tokenAddresses - Addresses for tokens.
* @param args.nativeCurrency - The native currency in which to request
* prices.
* @returns A map of the token addresses (as checksums) to their prices in the
* native currency.
*/
async #fetchAndMapExchangeRatesForUnsupportedNativeCurrency({
tokenContractAddresses,
tokenAddresses,
nativeCurrency,
}: {
tokenContractAddresses: Hex[];
tokenAddresses: Hex[];
nativeCurrency: string;
}): Promise<ContractExchangeRates> {
const [
tokenPricesByTokenContractAddress,
tokenPricesByTokenAddress,
fallbackCurrencyToNativeCurrencyConversionRate,
] = await Promise.all([
this.#tokenPricesService.fetchTokenPrices({
tokenContractAddresses,
tokenAddresses,
currency: FALL_BACK_VS_CURRENCY,
chainId: this.config.chainId,
}),
Expand All @@ -561,11 +561,11 @@ export class TokenRatesController extends StaticIntervalPollingControllerV1<
return {};
}

return Object.entries(tokenPricesByTokenContractAddress).reduce(
(obj, [tokenContractAddress, tokenPrice]) => {
return Object.entries(tokenPricesByTokenAddress).reduce(
(obj, [tokenAddress, tokenPrice]) => {
return {
...obj,
[tokenContractAddress]:
[tokenAddress]:
tokenPrice.value * fallbackCurrencyToNativeCurrencyConversionRate,
};
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,20 @@ import type { Hex } from '@metamask/utils';
/**
* Represents the price of a token in a currency.
*/
export type TokenPrice<
TokenContractAddress extends Hex,
Currency extends string,
> = {
tokenContractAddress: TokenContractAddress;
export type TokenPrice<TokenAddress extends Hex, Currency extends string> = {
tokenAddress: TokenAddress;
value: number;
currency: Currency;
};

/**
* A map of token contract address to its price.
* A map of token address to its price.
*/
export type TokenPricesByTokenContractAddress<
TokenContractAddress extends Hex,
export type TokenPricesByTokenAddress<
TokenAddress extends Hex,
Currency extends string,
> = {
[A in TokenContractAddress]: TokenPrice<A, Currency>;
[A in TokenAddress]: TokenPrice<A, Currency>;
};

/**
Expand All @@ -28,40 +25,37 @@ export type TokenPricesByTokenContractAddress<
*
* @template ChainId - A type union of valid arguments for the `chainId`
* argument to `fetchTokenPrices`.
* @template TokenContractAddress - A type union of all token contract
* addresses. The reason this type parameter exists is so that we can guarantee
* that same addresses that `fetchTokenPrices` receives are the same addresses
* that shown up in the return value.
* @template TokenAddress - A type union of all token addresses. The reason this
* type parameter exists is so that we can guarantee that same addresses that
* `fetchTokenPrices` receives are the same addresses that shown up in the
* return value.
* @template Currency - A type union of valid arguments for the `currency`
* argument to `fetchTokenPrices`.
*/
export type AbstractTokenPricesService<
ChainId extends Hex = Hex,
TokenContractAddress extends Hex = Hex,
TokenAddress extends Hex = Hex,
Currency extends string = string,
> = {
/**
* Retrieves prices in the given currency for the tokens identified by the
* given contract addresses which are expected to live on the given chain.
* given addresses which are expected to live on the given chain.
*
* @param args - The arguments to this function.
* @param args.chainId - An EIP-155 chain ID.
* @param args.tokenContractAddresses - Contract addresses for tokens that
* live on the chain.
* @param args.tokenAddresses - Addresses for tokens that live on the chain.
* @param args.currency - The desired currency of the token prices.
* @returns The prices for the requested tokens.
*/
fetchTokenPrices({
chainId,
tokenContractAddresses,
tokenAddresses,
currency,
}: {
chainId: ChainId;
tokenContractAddresses: TokenContractAddress[];
tokenAddresses: TokenAddress[];
currency: Currency;
}): Promise<
TokenPricesByTokenContractAddress<TokenContractAddress, Currency>
>;
}): Promise<TokenPricesByTokenAddress<TokenAddress, Currency>>;

/**
* Type guard for whether the API can return token prices for the given chain
Expand Down
Loading