Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions src/hooks/useConfirmTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import { toDecimals } from 'utils/balance';
import { interpretTransferError } from 'utils/errors';
import { addTxToLocalStorage } from 'utils/inProgressTxCache';
import { validate, isTransferValid } from 'utils/transferValidation';
import {
checkCircleGeoblock,
CIRCLE_GEOBLOCK_ERROR_MESSAGE,
} from 'utils/circle-geoblock';

import type { RootState } from 'store';
import type { RelayerFee } from 'store/relay';
Expand Down Expand Up @@ -136,6 +140,15 @@ const useConfirmTransaction = (props: Props): ReturnProps => {
}
}

const isCCTPRoute = route === 'AutomaticCCTP' || route === 'CCTP';
if (isCCTPRoute) {
const isGeoblocked = await checkCircleGeoblock();
if (isGeoblocked) {
setError(CIRCLE_GEOBLOCK_ERROR_MESSAGE);
return;
}
}

dispatch(setIsTransactionInProgress(true));

try {
Expand Down
32 changes: 31 additions & 1 deletion src/hooks/useFetchQuotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
} from '@wormhole-foundation/sdk';
import { QuoteParams, QuoteResult } from 'routes/operator';
import { calculateUSDPriceRaw } from 'utils';
import {
checkCircleGeoblock,
CIRCLE_GEOBLOCK_ERROR_MESSAGE,
} from 'utils/circle-geoblock';

import config from 'config';
import { Token } from 'config/tokens';
Expand Down Expand Up @@ -46,6 +50,9 @@ export default (routes: string[], params: Params): HookReturn => {
Record<string, QuoteResult>
>({});
const [isVisible, setIsVisible] = useState(true);
const [isCircleGeoblocked, setIsCircleGeoblocked] = useState<boolean | null>(
null,
);

useEffect(() => {
const visibilityHandler = () => {
Expand All @@ -58,6 +65,15 @@ export default (routes: string[], params: Params): HookReturn => {
};
}, []);

useEffect(() => {
const hasCCTPRoute = routes.some(
(route) => route === 'AutomaticCCTP' || route === 'CCTP',
);
if (hasCCTPRoute && isCircleGeoblocked === null) {
checkCircleGeoblock().then(setIsCircleGeoblocked);
}
}, [routes, isCircleGeoblocked]);

// TODO temporary
// Calculate USD amount for temporary $10,000 Mayan limit
const { getTokenPrice } = useTokens();
Expand Down Expand Up @@ -199,7 +215,21 @@ export default (routes: string[], params: Params): HookReturn => {

config.routes.getQuotes(routes, rParams).then((quoteResults) => {
if (!unmounted) {
setUnfilteredQuotes(quoteResults);
// Add geoblocking error to CCTP routes if user is geoblocked
if (isCircleGeoblocked) {
const modifiedQuotes = { ...quoteResults };
for (const routeName in modifiedQuotes) {
if (routeName === 'AutomaticCCTP' || routeName === 'CCTP') {
modifiedQuotes[routeName] = {
success: false,
error: new Error(CIRCLE_GEOBLOCK_ERROR_MESSAGE),
};
}
}
setUnfilteredQuotes(modifiedQuotes);
} else {
setUnfilteredQuotes(quoteResults);
}
setIsFetchingInitialQuotes(false);
}
});
Expand Down
19 changes: 19 additions & 0 deletions src/utils/circle-geoblock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const checkCircleGeoblock = async (): Promise<boolean> => {
try {
const response = await fetch('https://api.circle.com/ping');

// If the user is geoblocked, Circle returns a 403 or specific error
if (!response.ok && (response.status === 403 || response.status === 451)) {
return true;
}

return false;
} catch (error) {
// In case of network errors, we should allow the transaction to proceed to avoid blocking legitimate users with connectivity issues
console.warn('Failed to check Circle geoblocking status:', error);
return false;
}
};

export const CIRCLE_GEOBLOCK_ERROR_MESSAGE =
'You are attempting a transfer from a location that is restricted by Circle.';
Loading