diff --git a/next.config.js b/next.config.js
index e7bc5857..2f1338fa 100644
--- a/next.config.js
+++ b/next.config.js
@@ -56,6 +56,15 @@ let nextConfig = {
"uuid",
]
: [],
+ images: {
+ dangerouslyAllowSVG: true,
+ remotePatterns: [
+ {
+ protocol: "https",
+ hostname: "**",
+ },
+ ],
+ },
webpack: (config, { dev, isServer }) => {
if (dev && isServer) checkEnv();
return config;
diff --git a/public/logo-fallback.png b/public/logo-fallback.png
new file mode 100644
index 00000000..e21e57c2
Binary files /dev/null and b/public/logo-fallback.png differ
diff --git a/src/components/AssetSelect/AssetSelectContent.tsx b/src/components/AssetSelect/AssetSelectContent.tsx
index 44a2f0ba..b3466e79 100644
--- a/src/components/AssetSelect/AssetSelectContent.tsx
+++ b/src/components/AssetSelect/AssetSelectContent.tsx
@@ -2,6 +2,7 @@ import { ArrowLeftIcon } from "@heroicons/react/20/solid";
import * as ScrollArea from "@radix-ui/react-scroll-area";
import { Asset } from "@skip-router/core";
import { matchSorter } from "match-sorter";
+import Image from "next/image";
import { useEffect, useMemo, useRef, useState } from "react";
import { formatUnits } from "viem";
@@ -93,10 +94,12 @@ function AssetSelectContent({ assets = [], balances, onChange, onClose, showChai
className="flex w-full items-center gap-4 rounded-xl p-4 text-left transition-colors hover:bg-[#ECD9D9] focus:-outline-offset-2"
onClick={() => (onClose(), onChange?.(asset))}
>
-
(e.currentTarget.src = "https://api.dicebear.com/6.x/shapes/svg")}
/>
diff --git a/src/components/AssetSelect/index.tsx b/src/components/AssetSelect/index.tsx
index b7ca3716..e4026666 100644
--- a/src/components/AssetSelect/index.tsx
+++ b/src/components/AssetSelect/index.tsx
@@ -1,5 +1,6 @@
import { ChevronDownIcon } from "@heroicons/react/20/solid";
import { Asset } from "@skip-router/core";
+import Image from "next/image";
import { useState } from "react";
import { Dialog, DialogContent, DialogTrigger } from "@/components/Dialog";
@@ -35,10 +36,12 @@ function AssetSelect({ asset, assets, balances, onChange, showChainInfo, isBalan
data-testid="select-asset"
>
{asset && (
-

(event.currentTarget.src = "https://api.dicebear.com/6.x/shapes/svg")}
/>
)}
diff --git a/src/components/ChainSelect/ChainSelectContent.tsx b/src/components/ChainSelect/ChainSelectContent.tsx
index 991334b3..8ab80080 100644
--- a/src/components/ChainSelect/ChainSelectContent.tsx
+++ b/src/components/ChainSelect/ChainSelectContent.tsx
@@ -1,6 +1,7 @@
import { ArrowLeftIcon } from "@heroicons/react/20/solid";
import * as ScrollArea from "@radix-ui/react-scroll-area";
import { matchSorter } from "match-sorter";
+import Image from "next/image";
import { useEffect, useMemo, useRef, useState } from "react";
import { Chain } from "@/hooks/useChains";
@@ -86,12 +87,14 @@ function ChainSelectContent({ chains, onChange, onClose }: Props) {
onClick={() => onChange(chain)}
data-testid="chain-item"
>
-

(e.currentTarget.src = "https://api.dicebear.com/6.x/shapes/svg")}
+ className="h-[48px] w-[48px] rounded-full object-contain"
+ width={48}
+ height={48}
+ src={chain.logoURI || "/logo-fallback.png"}
/>
+
{chain.prettyName}
{chain.chainID}
diff --git a/src/components/ConnectedWalletButton.tsx b/src/components/ConnectedWalletButton.tsx
index ae91a72a..3f7f6e71 100644
--- a/src/components/ConnectedWalletButton.tsx
+++ b/src/components/ConnectedWalletButton.tsx
@@ -1,3 +1,4 @@
+import Image from "next/image";
import { ComponentProps, forwardRef } from "react";
import { cn } from "@/utils/ui";
@@ -22,9 +23,11 @@ export const ConnectedWalletButton = forwardRef
(
ref={ref}
>
{walletLogo && (
-
)}
diff --git a/src/components/RouteDisplay/RouteEnd.tsx b/src/components/RouteDisplay/RouteEnd.tsx
index 5c71c856..68849d4a 100644
--- a/src/components/RouteDisplay/RouteEnd.tsx
+++ b/src/components/RouteDisplay/RouteEnd.tsx
@@ -1,3 +1,5 @@
+import Image from "next/image";
+
import { SimpleTooltip } from "../SimpleTooltip";
export interface RouteEndProps {
@@ -10,9 +12,11 @@ export interface RouteEndProps {
export const RouteEnd = ({ amount, symbol, logo, chain }: RouteEndProps) => {
return (
-
-
![]()
+
diff --git a/src/components/RouteDisplay/SwapStep.tsx b/src/components/RouteDisplay/SwapStep.tsx
index 1f977ae8..bd037edb 100644
--- a/src/components/RouteDisplay/SwapStep.tsx
+++ b/src/components/RouteDisplay/SwapStep.tsx
@@ -1,4 +1,5 @@
import { SwapVenue } from "@skip-router/core";
+import Image from "next/image";
import { useMemo } from "react";
import { SWAP_VENUES } from "@/constants/swap-venues";
@@ -97,19 +98,23 @@ export const SwapStep = ({ action, actions, statusData }: SwapStepProps) => {
Swap to
-
{assetOut.recommendedSymbol}
on
-
@@ -138,16 +143,18 @@ export const SwapStep = ({ action, actions, statusData }: SwapStepProps) => {
Swap
-
{assetIn.recommendedSymbol}
on
-
{
Swap
-
+
{assetIn.recommendedSymbol}
for
-
{assetOut.recommendedSymbol}
on
-
{venue.prettyName}
diff --git a/src/components/RouteDisplay/TransferStep.tsx b/src/components/RouteDisplay/TransferStep.tsx
index ceeb1197..6d5c4db8 100644
--- a/src/components/RouteDisplay/TransferStep.tsx
+++ b/src/components/RouteDisplay/TransferStep.tsx
@@ -1,4 +1,5 @@
import { BridgeType } from "@skip-router/core";
+import Image from "next/image";
import { useMemo } from "react";
import { useAssets } from "@/context/assets";
@@ -101,9 +102,11 @@ export const TransferStep = ({ action, actions, statusData }: TransferStepProps)
Transfer
from
-
@@ -113,9 +116,11 @@ export const TransferStep = ({ action, actions, statusData }: TransferStepProps)
to
-
@@ -126,8 +131,10 @@ export const TransferStep = ({ action, actions, statusData }: TransferStepProps)
with
{bridge.name.toLowerCase() !== "ibc" && (
-
Transfer
-
{asset.recommendedSymbol}
from
-
@@ -185,9 +196,11 @@ export const TransferStep = ({ action, actions, statusData }: TransferStepProps)
to
-
@@ -198,8 +211,10 @@ export const TransferStep = ({ action, actions, statusData }: TransferStepProps)
with
{bridge.name.toLowerCase() !== "ibc" && (
-
{
+ for (const op of route.operations) {
+ if ("hyperlaneTransfer" in op) return op;
+ }
+ }, [route]);
const bridgingFee = useMemo(() => {
- if (!axelarTransferOperation) return;
- const { feeAmount, feeAsset, usdFeeAmount } = axelarTransferOperation.axelarTransfer;
- const computed = (+feeAmount / Math.pow(10, feeAsset.decimals || 18)).toLocaleString("en-US", {
- maximumFractionDigits: 6,
- });
+ if (hyperlaneTransferOperation) {
+ const { feeAmount, feeAsset, usdFeeAmount } = hyperlaneTransferOperation.hyperlaneTransfer;
+ const computed = (+feeAmount / Math.pow(10, feeAsset.decimals || 6)).toLocaleString("en-US", {
+ maximumFractionDigits: 6,
+ });
+ return { inAsset: `${computed} ${feeAsset.symbol}`, inUSD: usdFeeAmount && `${formatUSD(usdFeeAmount)}` };
+ }
+ if (axelarTransferOperation) {
+ const { feeAmount, feeAsset, usdFeeAmount } = axelarTransferOperation.axelarTransfer;
+ const computed = (+feeAmount / Math.pow(10, feeAsset.decimals || 18)).toLocaleString("en-US", {
+ maximumFractionDigits: 6,
+ });
- return { inAsset: `${computed} ${feeAsset.symbol}`, inUSD: `${formatUSD(usdFeeAmount)}` };
- }, [axelarTransferOperation]);
+ return { inAsset: `${computed} ${feeAsset.symbol}`, inUSD: `${formatUSD(usdFeeAmount)}` };
+ }
+ }, [axelarTransferOperation, hyperlaneTransferOperation]);
if (!(sourceChain && sourceAsset && destinationChain && destinationAsset)) {
return null;
diff --git a/src/components/WalletModal/WalletModal.tsx b/src/components/WalletModal/WalletModal.tsx
index c120d9ec..51ca1373 100644
--- a/src/components/WalletModal/WalletModal.tsx
+++ b/src/components/WalletModal/WalletModal.tsx
@@ -2,6 +2,7 @@ import { useManager } from "@cosmos-kit/react";
import { ArrowTopRightOnSquareIcon } from "@heroicons/react/16/solid";
import { ArrowLeftIcon, FaceFrownIcon } from "@heroicons/react/20/solid";
import * as ScrollArea from "@radix-ui/react-scroll-area";
+import Image from "next/image";
import toast from "react-hot-toast";
import { useAccount, useConnect, useDisconnect } from "wagmi";
@@ -104,9 +105,11 @@ export function WalletModal({ chainType, onClose, wallets }: Props) {
onClick={() => onWalletConnect(wallet)}
>
{wallet.walletInfo.logo && (
-
= {
- assetmantle: "asset-mantle",
- cosmoshub: "cosmos",
- cryptoorgchain: "crypto-org",
- fetchhub: "fetchai",
- gravitybridge: "gravity-bridge",
- kichain: "ki-chain",
- mars: "mars-protocol",
- omniflixhub: "omniflix",
- terra2: "terra",
-};
diff --git a/src/hooks/useChains.ts b/src/hooks/useChains.ts
index 8796c0ad..8bb81f53 100644
--- a/src/hooks/useChains.ts
+++ b/src/hooks/useChains.ts
@@ -4,7 +4,6 @@ import { useQuery } from "@tanstack/react-query";
import { chainIdToName } from "@/chains";
import { chainIdToPrettyName } from "@/chains/pretty";
import { useSkipClient } from "@/solve";
-import { getChainLogo } from "@/utils/chain";
export type Chain = SkipChain & {
prettyName: string;
@@ -33,7 +32,7 @@ export function useChains(args: UseChainsQueryArgs = {}) {
...chain,
chainName: chainIdToName[chain.chainID] || chain.chainName,
prettyName: chainIdToPrettyName[chain.chainID] || chain.chainName,
- logoURI: getChainLogo(chain),
+ logoURI: chain.logoURI || "/logo-fallback.png",
};
})
.sort((chainA, chainB) => {
diff --git a/src/pages/api/chainlist/[chainName].ts b/src/pages/api/chainlist/[chainName].ts
deleted file mode 100644
index 40457783..00000000
--- a/src/pages/api/chainlist/[chainName].ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { PageConfig } from "next";
-import { NextRequest } from "next/server";
-
-import { getChainlistURI } from "@/utils/chain";
-
-export const config: PageConfig = {
- runtime: "edge",
-};
-
-export default async function handler(req: NextRequest) {
- const chainName = req.nextUrl.searchParams.get("chainName") || "";
- let response = await fetch(chainName ? getChainlistURI(chainName) : FALLBACK_URI);
- if (!response.ok) {
- response = await fetch(FALLBACK_URI);
- }
- return new Response(response.body, {
- headers: {
- "cache-control": "public, max-age=604800, immutable", // 1 week
- "content-type": response.headers.get("content-type")!,
- },
- });
-}
-
-const FALLBACK_URI = "https://api.dicebear.com/6.x/shapes/svg";
diff --git a/src/utils/chain.ts b/src/utils/chain.ts
index 64fced4f..6e4989d7 100644
--- a/src/utils/chain.ts
+++ b/src/utils/chain.ts
@@ -1,27 +1,4 @@
-import { Chain, FeeAsset } from "@skip-router/core";
-
-import { CHAIN_NAME_TO_CHAINLIST_ID, CHAINLIST_LOGO_CHAIN_IDS } from "@/constants/chainlist";
-
-export function getChainLogo(chain: Chain) {
- if (chain.logoURI && chain.logoURI.match("-light")) {
- return chain.logoURI.replace("-light", "-dark");
- }
-
- if (CHAINLIST_LOGO_CHAIN_IDS.includes(chain.chainID)) {
- return getChainlistProxyURI(chain.chainName);
- }
-
- return chain.logoURI || getChainlistProxyURI(chain.chainName);
-}
-
-export function getChainlistURI(chainName: string) {
- const name = CHAIN_NAME_TO_CHAINLIST_ID[chainName] || chainName;
- return `https://raw.githubusercontent.com/cosmostation/chainlist/main/chain/${name}/chainImg/_chainImg.svg`;
-}
-
-export function getChainlistProxyURI(chainName: string) {
- return `/api/chainlist/${chainName}`;
-}
+import { FeeAsset } from "@skip-router/core";
/**
* - deprio denoms start with 'ibc/' and 'factory/'