Skip to content

Commit

Permalink
fix: fallback conversion rate for token market data (#4615)
Browse files Browse the repository at this point in the history
## Explanation

When the price API does not support the native currency (e.g. MATIC),
prices are fetched in ETH and an additional conversion hop is performed
to the native currency. But this hop was only being performed on the
current price, and was missing on the extended market data like
marketCap, allTimeHigh, etc.


## References

<!--
Are there any issues that this pull request is tied to? Are there other
links that reviewers should consult to understand these changes better?

For example:

* Fixes #12345
* Related to #67890
-->

## Changelog

<!--
If you're making any consumer-facing changes, list those changes here as
if you were updating a changelog, using the template below as a guide.

(CATEGORY is one of BREAKING, ADDED, CHANGED, DEPRECATED, REMOVED, or
FIXED. For security-related issues, follow the Security Advisory
process.)

Please take care to name the exact pieces of the API you've added or
changed (e.g. types, interfaces, functions, or methods).

If there are any breaking changes, make sure to offer a solution for
consumers to follow once they upgrade to the changes.

Finally, if you're only making changes to development scripts or tests,
you may replace the template below with "None".
-->

### `@metamask/assets-controllers`

- **FIXED**: On networks where the native currency is not ETH, token
market data is now correctly priced in the native currency.

## Checklist

- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [ ] I've highlighted breaking changes using the "BREAKING" category
above as appropriate
  • Loading branch information
bergeron committed Sep 4, 2024
1 parent 7ff50c9 commit 756f06d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 24 deletions.
57 changes: 36 additions & 21 deletions packages/assets-controllers/src/TokenRatesController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1326,10 +1326,11 @@ describe('TokenRatesController', () => {
});

describe('when the native currency is not supported', () => {
const fallbackRate = 0.5;
it('returns the exchange rates using ETH as a fallback currency', async () => {
nock('https://min-api.cryptocompare.com')
.get('/data/price?fsym=ETH&tsyms=LOL')
.reply(200, { LOL: 0.5 });
.reply(200, { LOL: fallbackRate });
const tokenPricesService = buildMockTokenPricesService({
fetchTokenPrices: fetchTokenPricesWithIncreasingPriceForEachToken,
validateCurrencySupported(currency: unknown): currency is string {
Expand Down Expand Up @@ -1381,47 +1382,47 @@ describe('TokenRatesController', () => {
// token price in LOL = (token price in ETH) * (ETH value in LOL)
'0x02': {
tokenAddress: '0x02',
currency: 'ETH',
currency: 'LOL',
pricePercentChange1d: 0,
priceChange1d: 0,
allTimeHigh: 4000,
allTimeLow: 900,
allTimeHigh: 4000 * fallbackRate,
allTimeLow: 900 * fallbackRate,
circulatingSupply: 2000,
dilutedMarketCap: 100,
high1d: 200,
low1d: 100,
marketCap: 1000,
dilutedMarketCap: 100 * fallbackRate,
high1d: 200 * fallbackRate,
low1d: 100 * fallbackRate,
marketCap: 1000 * fallbackRate,
marketCapPercentChange1d: 100,
price: 0.0005,
price: (1 / 1000) * fallbackRate,
pricePercentChange14d: 100,
pricePercentChange1h: 1,
pricePercentChange1y: 200,
pricePercentChange200d: 300,
pricePercentChange30d: 200,
pricePercentChange7d: 100,
totalVolume: 100,
totalVolume: 100 * fallbackRate,
},
'0x03': {
tokenAddress: '0x03',
currency: 'ETH',
currency: 'LOL',
pricePercentChange1d: 0,
priceChange1d: 0,
allTimeHigh: 4000,
allTimeLow: 900,
allTimeHigh: 4000 * fallbackRate,
allTimeLow: 900 * fallbackRate,
circulatingSupply: 2000,
dilutedMarketCap: 100,
high1d: 200,
low1d: 100,
marketCap: 1000,
dilutedMarketCap: 100 * fallbackRate,
high1d: 200 * fallbackRate,
low1d: 100 * fallbackRate,
marketCap: 1000 * fallbackRate,
marketCapPercentChange1d: 100,
price: 0.001,
price: (2 / 1000) * fallbackRate,
pricePercentChange14d: 100,
pricePercentChange1h: 1,
pricePercentChange1y: 200,
pricePercentChange200d: 300,
pricePercentChange30d: 200,
pricePercentChange7d: 100,
totalVolume: 100,
totalVolume: 100 * fallbackRate,
},
},
});
Expand Down Expand Up @@ -1981,14 +1982,28 @@ describe('TokenRatesController', () => {
"marketData": Object {
"0x89": Object {
"0x0000000000000000000000000000000000000001": Object {
"currency": "ETH",
"allTimeHigh": undefined,
"allTimeLow": undefined,
"currency": "UNSUPPORTED",
"dilutedMarketCap": undefined,
"high1d": undefined,
"low1d": undefined,
"marketCap": undefined,
"price": 0.0005,
"tokenAddress": "0x0000000000000000000000000000000000000001",
"totalVolume": undefined,
},
"0x0000000000000000000000000000000000000002": Object {
"currency": "ETH",
"allTimeHigh": undefined,
"allTimeLow": undefined,
"currency": "UNSUPPORTED",
"dilutedMarketCap": undefined,
"high1d": undefined,
"low1d": undefined,
"marketCap": undefined,
"price": 0.001,
"tokenAddress": "0x0000000000000000000000000000000000000002",
"totalVolume": undefined,
},
},
},
Expand Down
18 changes: 15 additions & 3 deletions packages/assets-controllers/src/TokenRatesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -745,16 +745,28 @@ export class TokenRatesController extends StaticIntervalPollingController<
return {};
}

// Converts the price in the fallback currency to the native currency
const convertFallbackToNative = (value: number | undefined) =>
value !== undefined && value !== null
? value * fallbackCurrencyToNativeCurrencyConversionRate
: undefined;

const updatedContractExchangeRates = Object.entries(
contractExchangeInformations,
).reduce((acc, [tokenAddress, token]) => {
acc = {
...acc,
[tokenAddress]: {
...token,
price: token.price
? token.price * fallbackCurrencyToNativeCurrencyConversionRate
: undefined,
currency: nativeCurrency,
price: convertFallbackToNative(token.price),
marketCap: convertFallbackToNative(token.marketCap),
allTimeHigh: convertFallbackToNative(token.allTimeHigh),
allTimeLow: convertFallbackToNative(token.allTimeLow),
totalVolume: convertFallbackToNative(token.totalVolume),
high1d: convertFallbackToNative(token.high1d),
low1d: convertFallbackToNative(token.low1d),
dilutedMarketCap: convertFallbackToNative(token.dilutedMarketCap),
},
};
return acc;
Expand Down

0 comments on commit 756f06d

Please sign in to comment.