Skip to content

Commit

Permalink
feat: Check token price before sending transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
Halibao-Lala committed Jan 10, 2025
1 parent 5e97e6c commit 5df66de
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback, useEffect } from 'react';
import { IBridgeToken } from '@bnb-chain/canonical-bridge-sdk';

import { useBridgeConfig } from '@/CanonicalBridgeProvider';
import { IBridgeConfig, useBridgeConfig } from '@/CanonicalBridgeProvider';
import { TIME } from '@/core/constants';
import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider';
import { setIsLoadingTokenPrices, setTokenPrices } from '@/modules/aggregator/action';
Expand All @@ -21,27 +21,13 @@ interface ITokenPricesResponse {
export function TokenPricesProvider() {
const bridgeConfig = useBridgeConfig();
const dispatch = useAppDispatch();
const { fetchApiTokenPrices } = useTokenPrice();

const { isLoading, data } = useQuery<TokenPricesContextProps>({
staleTime: TIME.MINUTE * 5,
refetchInterval: TIME.MINUTE * 5,
queryKey: ['tokenPrices'],
queryFn: async () => {
const { serverEndpoint } = bridgeConfig.http;

const [cmcRes, llamaRes] = await Promise.allSettled([
axios.get<ITokenPricesResponse>(`${serverEndpoint}/api/token/cmc`),
axios.get<ITokenPricesResponse>(`${serverEndpoint}/api/token/llama`),
]);

const cmcPrices = cmcRes.status === 'fulfilled' ? cmcRes.value.data.data : {};
const llamaPrices = llamaRes.status === 'fulfilled' ? llamaRes.value.data.data : {};

return {
cmcPrices,
llamaPrices,
};
},
queryFn: async () => fetchApiTokenPrices(bridgeConfig),
});

useEffect(() => {
Expand Down Expand Up @@ -85,7 +71,25 @@ export function useTokenPrice() {
[tokenPrices],
);

const fetchApiTokenPrices = useCallback(async (bridgeConfig: IBridgeConfig) => {
const { serverEndpoint } = bridgeConfig.http;

const [cmcRes, llamaRes] = await Promise.allSettled([
axios.get<ITokenPricesResponse>(`${serverEndpoint}/api/token/cmc`),
axios.get<ITokenPricesResponse>(`${serverEndpoint}/api/token/llama`),
]);

const cmcPrices = cmcRes.status === 'fulfilled' ? cmcRes.value.data.data : {};
const llamaPrices = llamaRes.status === 'fulfilled' ? llamaRes.value.data.data : {};

return {
cmcPrices,
llamaPrices,
};
}, []);

return {
getTokenPrice,
fetchApiTokenPrices,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
STARGATE_ENDPOINT,
} from '@/core/constants';
import { useHandleTxFailure } from '@/modules/aggregator/hooks/useHandleTxFailure';
import { usePriceValidation } from '@/modules/transfer/hooks/usePriceValidation';

export const TransferConfirmButton = ({
onClose,
Expand All @@ -49,6 +50,7 @@ export const TransferConfirmButton = ({
const { formatMessage } = useIntl();
const theme = useTheme();
const { colorMode } = useColorMode();
const { validateTokenPrice } = usePriceValidation();

const { address } = useAccount();
const { address: tronAddress, signTransaction } = useTronWallet();
Expand Down Expand Up @@ -104,6 +106,17 @@ export const TransferConfirmButton = ({
}

try {
// Check whether token price exists
const result = await validateTokenPrice({
tokenSymbol: selectedToken.symbol,
tokenAddress: selectedToken.address,
});
if (!result) {
throw new Error(
`Can not get token price from API server: ${sendValue} ${selectedToken.symbol}`,
);
}

setHash(null);
setChosenBridge('');
setIsLoading(true);
Expand Down Expand Up @@ -537,6 +550,7 @@ export const TransferConfirmButton = ({
signMessageAsync,
signTransaction,
handleFailure,
validateTokenPrice,
]);

const isFeeLoading = isLoading || isGlobalFeeLoading || !transferActionInfo || !isTransferable;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useCallback } from 'react';

import { useBridgeConfig } from '@/index';
import { useTokenPrice } from '@/modules/aggregator/providers/TokenPricesProvider';

export const usePriceValidation = () => {
const { fetchApiTokenPrices } = useTokenPrice();
const bridgeConfig = useBridgeConfig();

const validateTokenPrice = useCallback(
async ({ tokenSymbol, tokenAddress }: { tokenSymbol: string; tokenAddress: string }) => {
const { cmcPrices, llamaPrices } = await fetchApiTokenPrices(bridgeConfig);

const key1 = `${tokenSymbol?.toLowerCase()}:${tokenAddress?.toLowerCase()}`;
const key3 = tokenSymbol?.toLowerCase();
const key2 = `ethereum:${key3}`;
let price =
cmcPrices?.[key1]?.price ??
llamaPrices?.[key1]?.price ??
cmcPrices?.[key2]?.price ??
llamaPrices?.[key2]?.price ??
cmcPrices?.[key3]?.price ??
llamaPrices?.[key3]?.price;
if (price !== undefined) {
price = Number(price);
}
return price;
},
[bridgeConfig, fetchApiTokenPrices],
);

return { validateTokenPrice };
};

0 comments on commit 5df66de

Please sign in to comment.