diff --git a/apps/maestro/src/features/CanonicalTokenDeployment/CanonicalTokenDeployment.tsx b/apps/maestro/src/features/CanonicalTokenDeployment/CanonicalTokenDeployment.tsx
index 7165b7c38..401571148 100644
--- a/apps/maestro/src/features/CanonicalTokenDeployment/CanonicalTokenDeployment.tsx
+++ b/apps/maestro/src/features/CanonicalTokenDeployment/CanonicalTokenDeployment.tsx
@@ -1,6 +1,9 @@
+import { Alert, InfoIcon } from "@axelarjs/ui";
import { useMemo, type FC } from "react";
import dynamic from "next/dynamic";
+import { useChainFromRoute } from "~/lib/hooks";
+import { useGetChainsConfig } from "~/services/axelarConfigs/hooks";
import { MultiStepDialog, StepLoading } from "~/ui/compounds/MultiStepForm";
import {
CanonicalTokenDeploymentStateProvider,
@@ -24,6 +27,20 @@ const STEPS = [Step1, Step2, Step3];
const CanonicalTokenDeployment: FC = () => {
const { state, actions } = useCanonicalTokenDeploymentStateContainer();
+ const routeChain = useChainFromRoute();
+ const { data: tokenInfo } = useGetChainsConfig({
+ axelarChainId: routeChain?.axelarChainId,
+ });
+
+ const isGatewayToken = useMemo(
+ () =>
+ (
+ tokenInfo?.assets.map((asset: any) =>
+ asset.tokenAddress.toLowerCase()
+ ) || []
+ ).includes(state.tokenDetails.tokenAddress.toLowerCase()),
+ [tokenInfo, state.tokenDetails.tokenAddress]
+ );
const CurrentStep = useMemo(() => STEPS[state.step], [state.step]);
@@ -32,6 +49,14 @@ const CanonicalTokenDeployment: FC = () => {
[state.step]
);
+ if (isGatewayToken)
+ return (
+ }>
+ This token is supported directly on Axelar and cannot be registered in
+ ITS.
+
+ );
+
return (
{
const axelarQueryClient = createAxelarQueryClient(NEXT_PUBLIC_NETWORK_ENV);
+ const axelarConfigClient = createAxelarConfigClient(NEXT_PUBLIC_NETWORK_ENV);
+
return {
req,
res,
@@ -74,6 +78,12 @@ const createContextInner = async ({ req, res }: ContextConfig) => {
axelarscanClient,
"evmChains" as const
),
+ axelarConfigs: axelarConfigs.bind(
+ null,
+ maestroKVClient,
+ axelarConfigClient,
+ "axelarConfigs" as const
+ ),
wagmiChainConfigs: WAGMI_CHAIN_CONFIGS,
},
persistence: {
@@ -186,3 +196,24 @@ async function evmChains(
return evmChainsMap;
}
+
+async function axelarConfigs(
+ kvClient: MaestroKVClient,
+ axelarConfigClient: AxelarConfigClient,
+ cacheKey: TCacheKey
+): Promise {
+ const chainConfigs = await axelarConfigClient.getChainConfigs(
+ NEXT_PUBLIC_NETWORK_ENV
+ );
+
+ const cached = await kvClient.getCached(cacheKey);
+
+ if (cached) {
+ return cached;
+ }
+
+ // cache for 1 hour
+ await kvClient.setCached(cacheKey, chainConfigs, 3600);
+
+ return chainConfigs;
+}
diff --git a/apps/maestro/src/server/routers/_app.ts b/apps/maestro/src/server/routers/_app.ts
index c8aea5728..904c5fed8 100644
--- a/apps/maestro/src/server/routers/_app.ts
+++ b/apps/maestro/src/server/routers/_app.ts
@@ -1,5 +1,6 @@
import { publicProcedure, router } from "~/server/trpc";
import { authRouter } from "./auth";
+import { axelarConfigsRouter } from "./axelarConfigs";
import { axelarjsSDKRouter } from "./axelarjsSDK";
import { axelarscanRouter } from "./axelarscan";
import { erc20Router } from "./erc20";
@@ -16,6 +17,7 @@ export const appRouter = router({
axelarscan: axelarscanRouter,
erc20: erc20Router,
axelarjsSDK: axelarjsSDKRouter,
+ axelarConfigs: axelarConfigsRouter,
interchainToken: interchainTokenRouter,
auth: authRouter,
openai: openaiRouter,
diff --git a/apps/maestro/src/server/routers/axelarConfigs/getChainConfigs.ts b/apps/maestro/src/server/routers/axelarConfigs/getChainConfigs.ts
new file mode 100644
index 000000000..648ed0c98
--- /dev/null
+++ b/apps/maestro/src/server/routers/axelarConfigs/getChainConfigs.ts
@@ -0,0 +1,37 @@
+import { TRPCError } from "@trpc/server";
+import { z } from "zod";
+
+import { publicProcedure } from "~/server/trpc";
+
+export const getConfigForChain = publicProcedure
+ .meta({
+ openapi: {
+ summary: "Get the full configs for a chain on the Axelar network",
+ description:
+ "Get the full configs for a chain on the Axelar network, including the assets registered directly on the network",
+ method: "GET",
+ path: "/axelar-chain-configs",
+ tags: ["axelar-chain-configs"],
+ },
+ })
+ .input(
+ z.object({
+ axelarChainId: z.string().max(64),
+ })
+ )
+ .output(z.any())
+ .query(async ({ ctx, input }) => {
+ try {
+ return (await ctx.configs.axelarConfigs()).chains[input.axelarChainId];
+ } catch (error) {
+ // If we get a TRPC error, we throw it
+ if (error instanceof TRPCError) {
+ throw error;
+ }
+ // otherwise, we throw an internal server error
+ throw new TRPCError({
+ code: "INTERNAL_SERVER_ERROR",
+ message: "Failed to get chain configs",
+ });
+ }
+ });
diff --git a/apps/maestro/src/server/routers/axelarConfigs/index.ts b/apps/maestro/src/server/routers/axelarConfigs/index.ts
new file mode 100644
index 000000000..b22853021
--- /dev/null
+++ b/apps/maestro/src/server/routers/axelarConfigs/index.ts
@@ -0,0 +1,8 @@
+import { router } from "~/server/trpc";
+import { getConfigForChain } from "./getChainConfigs";
+
+export const axelarConfigsRouter = router({
+ getChainConfigs: getConfigForChain,
+});
+
+export type AxelarConfigsRouter = typeof axelarConfigsRouter;
diff --git a/apps/maestro/src/services/axelarConfigs/hooks.ts b/apps/maestro/src/services/axelarConfigs/hooks.ts
new file mode 100644
index 000000000..9f657f174
--- /dev/null
+++ b/apps/maestro/src/services/axelarConfigs/hooks.ts
@@ -0,0 +1,16 @@
+import { Maybe } from "@axelarjs/utils";
+
+import { trpc } from "~/lib/trpc";
+
+export function useGetChainsConfig(input: { axelarChainId?: string }) {
+ return trpc.axelarConfigs.getChainConfigs.useQuery(
+ {
+ axelarChainId: Maybe.of(input.axelarChainId).mapOr("", String),
+ },
+ {
+ enabled: Boolean(input.axelarChainId),
+ staleTime: 1000 * 60 * 60 * 24, // 24 hours
+ refetchOnWindowFocus: false,
+ }
+ );
+}