Skip to content

Commit

Permalink
Merge pull request #280 from bnb-chain/feat/upperLimit0107
Browse files Browse the repository at this point in the history
feat: Upper limit validation
  • Loading branch information
Halibao-Lala authored Jan 10, 2025
2 parents a37c105 + 5df66de commit 718c5f8
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .release/.changeset/blue-goats-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bnb-chain/canonical-bridge-widget": patch
---

chore: Update confirmation popup amount styling
11 changes: 11 additions & 0 deletions .release/.changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"mode": "pre",
"tag": "alpha",
"initialVersions": {
"@bnb-chain/canonical-bridge-sdk": "0.4.7",
"@bnb-chain/canonical-bridge-widget": "0.5.18"
},
"changesets": [
"blue-goats-shave"
]
}
2 changes: 1 addition & 1 deletion packages/canonical-bridge-sdk/src/shared/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const formatNumber = (
useGrouping = true
) => {
const num = removeAfterDecimals(value, decimals);
return num.toLocaleString('fullwide', {
return Number(num).toLocaleString('fullwide', {
maximumFractionDigits: decimals,
useGrouping,
});
Expand Down
6 changes: 6 additions & 0 deletions packages/canonical-bridge-widget/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @bnb-chain/canonical-bridge-widget

## 0.5.19-alpha.0

### Patch Changes

- chore: Update confirmation popup amount styling

## 0.5.19

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/canonical-bridge-widget/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bnb-chain/canonical-bridge-widget",
"version": "0.5.19",
"version": "0.5.19-alpha.0",
"description": "canonical bridge widget",
"author": "bnb-chain",
"private": false,
Expand Down
2 changes: 1 addition & 1 deletion packages/canonical-bridge-widget/src/core/utils/number.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const formatNumber = (value: number, decimals = 18, useGrouping = true) => {
const num = removeAfterDecimals(value, decimals);
return num.toLocaleString('fullwide', {
return Number(num).toLocaleString('fullwide', {
maximumFractionDigits: decimals,
useGrouping,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export const LayerZeroOption = () => {
? `${formatNumber(
Number(formatUnits(BigInt(estimatedAmount?.['layerZero']), getToDecimals()['layerZero'])),
8,
false,
)}`
: '--';
}, [estimatedAmount, toTokenInfo, sendValue, getToDecimals]);
Expand Down
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
Expand Up @@ -7,12 +7,20 @@ import { useAppSelector } from '@/modules/store/StoreProvider';
import { useSolanaBalance } from '@/modules/wallet/hooks/useSolanaBalance';
import { MIN_SOL_TO_ENABLED_TX } from '@/core/constants';
import { useIsWalletCompatible } from '@/modules/wallet/hooks/useIsWalletCompatible';
import { useTokenUpperLimit } from '@/modules/aggregator/hooks/useTokenUpperLimit';
import { useBridgeConfig } from '@/index';

export const useInputValidation = () => {
const { data } = useSolanaBalance();
const isWalletCompatible = useIsWalletCompatible();
const {
transfer: { dollarUpperLimit },
} = useBridgeConfig();
const solBalance = Number(data?.formatted);
const fromChain = useAppSelector((state) => state.transfer.fromChain);
const selectedToken = useAppSelector((state) => state.transfer.selectedToken);

const priceInfo = useTokenUpperLimit(selectedToken);
const validateInput = useCallback(
({
balance,
Expand All @@ -39,6 +47,15 @@ export const useInputValidation = () => {
isError: true,
};
}
// Check upper limit
if (priceInfo?.upperLimit && Number(value) >= Number(priceInfo?.upperLimit)) {
return {
text: `Transfer value over $${formatNumber(dollarUpperLimit)} (${formatNumber(
priceInfo.upperLimit,
)} ${selectedToken?.symbol}) or equivalent is not allowed`,
isError: true,
};
}
// check if send amount is greater than token balance
if (!!balance && value > balance) {
return { text: `You have insufficient balance`, isError: true };
Expand Down Expand Up @@ -71,7 +88,14 @@ export const useInputValidation = () => {
console.log(e);
}
},
[fromChain?.chainType, solBalance, isWalletCompatible],
[
fromChain?.chainType,
solBalance,
isWalletCompatible,
priceInfo,
dollarUpperLimit,
selectedToken?.symbol,
],
);

return {
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 718c5f8

Please sign in to comment.