diff --git a/wormhole-connect-loader/src/types.ts b/wormhole-connect-loader/src/types.ts
index d120dccf9..d4ce99387 100644
--- a/wormhole-connect-loader/src/types.ts
+++ b/wormhole-connect-loader/src/types.ts
@@ -76,6 +76,9 @@ export interface WormholeConnectConfig {
bridgeDefaults?: BridgeDefaults;
routes?: string[];
pageHeader?: string;
+ cctpWarning?: {
+ href: string;
+ };
pageSubHeader?: string;
searchTx?: SearchTxConfig;
moreTokens?: MoreTokenConfig;
diff --git a/wormhole-connect/src/config/index.ts b/wormhole-connect/src/config/index.ts
index d66037f7b..c12e50735 100644
--- a/wormhole-connect/src/config/index.ts
+++ b/wormhole-connect/src/config/index.ts
@@ -51,6 +51,8 @@ export const ATTEST_URL =
? ''
: 'https://wormhole-foundation.github.io/example-token-bridge-ui/#/register';
+export const USDC_BRIDGE_URL = config.cctpWarning?.href || '';
+
export const WORMHOLE_RPC_HOSTS =
ENV === 'MAINNET'
? [
diff --git a/wormhole-connect/src/config/types.ts b/wormhole-connect/src/config/types.ts
index d3343b05b..ea02b824f 100644
--- a/wormhole-connect/src/config/types.ts
+++ b/wormhole-connect/src/config/types.ts
@@ -76,6 +76,9 @@ export interface WormholeConnectConfig {
bridgeDefaults?: BridgeDefaults;
routes?: string[];
pageHeader?: string;
+ cctpWarning?: {
+ href: string;
+ };
pageSubHeader?: string;
menu?: MenuEntry[];
searchTx?: SearchTxConfig;
diff --git a/wormhole-connect/src/views/Bridge/Inputs/TokenWarnings.tsx b/wormhole-connect/src/views/Bridge/Inputs/TokenWarnings.tsx
index 89e02ca6f..cee846708 100644
--- a/wormhole-connect/src/views/Bridge/Inputs/TokenWarnings.tsx
+++ b/wormhole-connect/src/views/Bridge/Inputs/TokenWarnings.tsx
@@ -7,7 +7,7 @@ import {
setAssociatedTokenAddress,
setForeignAsset,
} from 'store/transferInput';
-import { ATTEST_URL, TOKENS } from 'config';
+import { ATTEST_URL, USDC_BRIDGE_URL, TOKENS } from 'config';
import { getWrappedTokenId } from 'utils';
import { TransferWallet, signSolanaTransaction } from 'utils/wallet';
import { joinClass } from 'utils/style';
@@ -17,6 +17,7 @@ import { CircularProgress, Link, Typography } from '@mui/material';
import AlertBanner from 'components/AlertBanner';
import RouteOperator from 'routes/operator';
import { Route } from '../../../config/types';
+import { CCTPManual_CHAINS as CCTP_CHAINS } from 'routes/cctpManual';
const useStyles = makeStyles()((theme: any) => ({
associatedTokenWarning: {
@@ -94,12 +95,21 @@ function AssociatedTokenWarning(props: Props) {
function TokenWarnings() {
const dispatch = useDispatch();
- const { toChain, token, foreignAsset, associatedTokenAddress, route } =
- useSelector((state: RootState) => state.transferInput);
+ const {
+ toChain,
+ fromChain,
+ token,
+ destToken,
+ foreignAsset,
+ associatedTokenAddress,
+ route,
+ } = useSelector((state: RootState) => state.transferInput);
const { receiving } = useSelector((state: RootState) => state.wallet);
const [showErrors, setShowErrors] = useState(false);
+ const [usdcAndNoCCTP, setUsdcAndNoCCTP] = useState(false);
const tokenConfig = TOKENS[token];
+ const destTokenConfig = TOKENS[destToken];
// check if the destination token contract is deployed
useEffect(() => {
@@ -205,11 +215,28 @@ function TokenWarnings() {
]);
useEffect(() => {
+ // if the url it's empty that means the user doesn't want this feature
+ const cctpWarningFlag = !!USDC_BRIDGE_URL;
+ // check if the token is USDC and the chains involved are not CCTP
+ const usdcAndNoCCTP =
+ cctpWarningFlag &&
+ tokenConfig?.symbol === 'USDC' &&
+ destTokenConfig?.symbol === 'USDC' &&
+ (!(toChain && CCTP_CHAINS.includes(toChain)) ||
+ !(fromChain && CCTP_CHAINS.includes(fromChain)));
+
if (!toChain || !token || !receiving.address) return;
// The tBTC associated token account will be created if it doesn't exist in the redeem tx
if (toChain === 'solana' && foreignAsset && route !== Route.TBTC) {
checkSolanaAssociatedTokenAccount();
}
+ if (usdcAndNoCCTP) {
+ setShowErrors(true);
+ setUsdcAndNoCCTP(true);
+ } else {
+ setShowErrors(false);
+ setUsdcAndNoCCTP(false);
+ }
}, [
toChain,
token,
@@ -218,6 +245,9 @@ function TokenWarnings() {
associatedTokenAddress,
checkSolanaAssociatedTokenAccount,
route,
+ tokenConfig?.symbol,
+ destTokenConfig?.symbol,
+ fromChain,
]);
const noForeignAssetWarning = (
@@ -236,9 +266,27 @@ function TokenWarnings() {
/>
);
- const content = !foreignAsset
- ? noForeignAssetWarning
- : toChain === 'solana' && route !== Route.Relay && noAssociatedTokenAccount;
+ // warning message for users that attempt to transfer USDC using a different corridor than CCTP
+ const warningNoCCTPOption = (
+
+ This transaction will transfer wrapped USDC (wUSDC) to the destination
+ chain. If you want to transfer native USDC on chains supported by Circle's
+ CCTP, use the{' '}
+
+ USDC Bridge
+
+ .
+
+ );
+
+ let content;
+ if (!foreignAsset) {
+ content = noForeignAssetWarning;
+ } else if (toChain === 'solana' && route !== Route.Relay) {
+ content = noAssociatedTokenAccount;
+ } else if (usdcAndNoCCTP) {
+ content = warningNoCCTPOption;
+ }
return (