Skip to content

Commit 5fd5b7c

Browse files
authored
fix(checkout): Fetch crypto to USD conversion via our own subgraph (#2620)
1 parent 4f1805f commit 5fd5b7c

File tree

7 files changed

+290
-171
lines changed

7 files changed

+290
-171
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* eslint @typescript-eslint/naming-convention: off */
2+
3+
import axios from 'axios';
4+
import { Environment } from '@imtbl/config';
5+
import { getCryptoToUSDConversion, TokenPriceResponse } from './CryptoFiat';
6+
7+
jest.mock('axios');
8+
const mockedAxios = axios as jest.Mocked<typeof axios>;
9+
10+
const conversionsMap = new Map<string, number>();
11+
12+
const mockResponse: TokenPriceResponse = {
13+
result: [
14+
{
15+
symbol: 'WOMBAT',
16+
token_address: '0x0219d987a75f860e55d936646c60ba9a021e52ac',
17+
usd_price: '0.0001359733469',
18+
},
19+
{
20+
symbol: 'BZAI',
21+
token_address: '0x0bbb2db8d777c72516a344506fa2130040b48c13',
22+
usd_price: '0.03',
23+
},
24+
{
25+
symbol: 'WIMX',
26+
token_address: '0x3a0c2ba54d6cbd3121f01b96dfd20e99d1696c9d',
27+
usd_price: '0.89',
28+
},
29+
],
30+
};
31+
32+
describe('getCryptoToUSDConversion', () => {
33+
beforeEach(() => {
34+
conversionsMap.set('wombat', 0.0001359733469);
35+
conversionsMap.set('bzai', 0.03);
36+
conversionsMap.set('wimx', 0.89);
37+
conversionsMap.set('imx', 0.89);
38+
});
39+
40+
afterEach(() => {
41+
conversionsMap.clear();
42+
jest.clearAllMocks();
43+
});
44+
45+
it('should return the correct conversion for all tokens', async () => {
46+
mockedAxios.get.mockResolvedValue({ data: mockResponse });
47+
48+
const conversions = await getCryptoToUSDConversion(Environment.SANDBOX);
49+
expect(conversions.size).toEqual(4);
50+
expect(conversions).toEqual(conversionsMap);
51+
});
52+
53+
it('adds IMX to the conversions map', async () => {
54+
mockedAxios.get.mockResolvedValue({ data: mockResponse });
55+
56+
const conversions = await getCryptoToUSDConversion(Environment.SANDBOX);
57+
expect(conversions.get('imx')).toEqual(0.89);
58+
});
59+
});

packages/checkout/widgets-lib/src/context/crypto-fiat-context/CryptoFiat.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import axios from 'axios';
12
import { CryptoFiat, CryptoFiatConvertReturn } from '@imtbl/cryptofiat';
3+
import { IMMUTABLE_API_BASE_URL } from '@imtbl/checkout-sdk';
4+
import { Environment } from '@imtbl/config';
25
import { FiatSymbols } from './CryptoFiatContext';
36

47
export const updateConversions = (
@@ -39,3 +42,41 @@ export const getCryptoToFiatConversion = async (
3942
return new Map<string, number>();
4043
}
4144
};
45+
46+
export type TokenPriceResponse = {
47+
// eslint-disable-next-line @typescript-eslint/naming-convention
48+
result: { symbol: string; token_address: string; usd_price: string }[];
49+
};
50+
51+
async function getUSDConversionsForAll(environment: Environment) {
52+
const apiUrl = `${IMMUTABLE_API_BASE_URL[environment]}/checkout/v1/token-prices`;
53+
const response = await axios.get<TokenPriceResponse>(apiUrl);
54+
55+
const { data } = response;
56+
57+
const result: CryptoFiatConvertReturn = {};
58+
const tokens = data.result || [];
59+
for (const token of tokens) {
60+
result[token.symbol.toLowerCase()] = { usd: +token.usd_price };
61+
}
62+
63+
// if the result has wimx, then add imx to the result
64+
if (result.wimx) {
65+
result.imx = result.wimx;
66+
}
67+
68+
return result;
69+
}
70+
71+
// returns the conversion for all tokens in
72+
export const getCryptoToUSDConversion = async (
73+
environment: Environment,
74+
): Promise<Map<string, number>> => {
75+
try {
76+
const cryptoToFiatResult = await getUSDConversionsForAll(environment);
77+
78+
return updateConversions(cryptoToFiatResult, FiatSymbols.USD);
79+
} catch (err: any) {
80+
return new Map<string, number>();
81+
}
82+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { useState, useEffect } from 'react';
2+
import { Environment } from '@imtbl/config';
3+
import { getCryptoToUSDConversion } from '../../context/crypto-fiat-context/CryptoFiat';
4+
5+
export function useCryptoUSDConversion(environment: Environment | undefined) {
6+
const [conversions, setConversions] = useState<Map<string, number>>(new Map<string, number>());
7+
const [error, setError] = useState<Error | null>(null);
8+
const [loading, setLoading] = useState(true);
9+
10+
useEffect(() => {
11+
async function fetchConversions() {
12+
if (!environment) return;
13+
14+
try {
15+
const data = await getCryptoToUSDConversion(environment);
16+
setConversions(data);
17+
setError(null);
18+
} catch (err) {
19+
setError(err instanceof Error ? err : new Error(`Failed to fetch conversions: ${err}`));
20+
} finally {
21+
setLoading(false);
22+
}
23+
}
24+
25+
fetchConversions();
26+
const interval = setInterval(fetchConversions, 30000);
27+
28+
return () => clearInterval(interval);
29+
}, [environment]);
30+
31+
return { conversions, error, loading };
32+
}

0 commit comments

Comments
 (0)