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
14 changes: 5 additions & 9 deletions api/_dexes/cross-swap-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
import { getMultiCallHandlerAddress } from "../_multicall-handler";
import {
getIndirectBridgeQuoteMessage,
getIndirectDestinationRoutes,
getIndirectDestinationRoute,
} from "./utils-b2bi";
import {
InvalidParamError,
Expand Down Expand Up @@ -228,21 +228,19 @@ export async function getCrossSwapQuotesForExactInputB2BI(
): Promise<CrossSwapQuotes> {
const { depositEntryPoint } = _prepCrossSwapQuotesRetrievalB2B(crossSwap);

const indirectDestinationRoutes = getIndirectDestinationRoutes({
const indirectDestinationRoute = getIndirectDestinationRoute({
originChainId: crossSwap.inputToken.chainId,
destinationChainId: crossSwap.outputToken.chainId,
inputToken: crossSwap.inputToken.address,
outputToken: crossSwap.outputToken.address,
});

if (indirectDestinationRoutes.length === 0) {
if (!indirectDestinationRoute) {
throw new InvalidParamError({
message: "No indirect bridge routes found to specified destination chain",
});
}

const [indirectDestinationRoute] = indirectDestinationRoutes;

// For EXACT_INPUT, we need to convert the amount to the intermediary output token decimals
// to get the initial bridgeable output amount.
let bridgeableOutputAmount = ConvertDecimals(
Expand Down Expand Up @@ -329,21 +327,19 @@ export async function getCrossSwapQuotesForOutputB2BI(
): Promise<CrossSwapQuotes> {
const { depositEntryPoint } = _prepCrossSwapQuotesRetrievalB2B(crossSwap);

const indirectDestinationRoutes = getIndirectDestinationRoutes({
const indirectDestinationRoute = getIndirectDestinationRoute({
originChainId: crossSwap.inputToken.chainId,
destinationChainId: crossSwap.outputToken.chainId,
inputToken: crossSwap.inputToken.address,
outputToken: crossSwap.outputToken.address,
});

if (indirectDestinationRoutes.length === 0) {
if (!indirectDestinationRoute) {
throw new InvalidParamError({
message: "No indirect bridge routes found to specified destination chain",
});
}

const [indirectDestinationRoute] = indirectDestinationRoutes;

const outputAmountWithAppFee = crossSwap.appFeePercent
? addMarkupToAmount(crossSwap.amount, crossSwap.appFeePercent)
: crossSwap.amount;
Expand Down
179 changes: 82 additions & 97 deletions api/_dexes/utils-b2bi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,127 +28,112 @@ export function isIndirectDestinationRouteSupported(params: {
inputToken: string;
outputToken: string;
}) {
return getIndirectDestinationRoutes(params).length > 0;
return !!getIndirectDestinationRoute(params);
}

export function getIndirectDestinationRoutes(params: {
export function getIndirectDestinationRoute(params: {
originChainId: number;
destinationChainId: number;
inputToken: string;
outputToken: string;
}): IndirectDestinationRoute[] {
}): IndirectDestinationRoute | undefined {
const indirectChainDestination = indirectChains.find(
(chain) =>
chain.chainId === params.destinationChainId &&
chain.intermediaryChains &&
chain.intermediaryChain &&
chain.outputTokens.some(
(token) =>
token.address.toLowerCase() === params.outputToken.toLowerCase()
)
);

if (!indirectChainDestination) {
return [];
return;
}

const indirectDestinationRoutes =
indirectChainDestination.intermediaryChains.flatMap(
(_intermediaryChainId) => {
// Check if the indirect destination chain has token enabled
const isIntermediaryOutputTokenEnabled =
indirectChainDestination.outputTokens.some(
(token) => token.address === params.outputToken
);
if (!isIntermediaryOutputTokenEnabled) {
return [];
}
const intermediaryChainId = indirectChainDestination.intermediaryChain;

// Check if input token is known
const inputToken = getTokenByAddress(
params.inputToken,
params.originChainId
);
if (!inputToken) {
return [];
}
// Check if the indirect destination chain has token enabled
const isIntermediaryOutputTokenEnabled =
indirectChainDestination.outputTokens.some(
(token) => token.address === params.outputToken
);
if (!isIntermediaryOutputTokenEnabled) {
return;
}

// Check if the indirect destination chain supports the intermediary chain
const indirectOutputToken = getTokenByAddress(
params.outputToken,
params.destinationChainId
);
if (!indirectOutputToken) {
return [];
}
// Check if input token is known
const inputToken = getTokenByAddress(params.inputToken, params.originChainId);
if (!inputToken) {
return;
}

// Check if L1 token is known
const l1TokenAddress =
TOKEN_SYMBOLS_MAP[inputToken.symbol as keyof typeof TOKEN_SYMBOLS_MAP]
?.addresses[HUB_POOL_CHAIN_ID];
if (!l1TokenAddress) {
return [];
}
const l1Token = getTokenByAddress(l1TokenAddress, HUB_POOL_CHAIN_ID);
if (!l1Token) {
return [];
}
// Check if the indirect destination chain supports the intermediary chain
const indirectOutputToken = getTokenByAddress(
params.outputToken,
params.destinationChainId
);
if (!indirectOutputToken) {
return;
}

// Check if intermediary output token is known
const intermediaryOutputTokenAddress =
l1Token.addresses[_intermediaryChainId];
if (!intermediaryOutputTokenAddress) {
return [];
}
const intermediaryOutputToken = getTokenByAddress(
intermediaryOutputTokenAddress,
_intermediaryChainId
);
if (!intermediaryOutputToken) {
return [];
}
// Check if L1 token is known
const l1TokenAddress =
TOKEN_SYMBOLS_MAP[inputToken.symbol as keyof typeof TOKEN_SYMBOLS_MAP]
?.addresses[HUB_POOL_CHAIN_ID];
if (!l1TokenAddress) {
return;
}
const l1Token = getTokenByAddress(l1TokenAddress, HUB_POOL_CHAIN_ID);
if (!l1Token) {
return;
}

// Check if there is a route from the origin chain to the intermediary chain
if (
!isRouteEnabled(
params.originChainId,
_intermediaryChainId,
params.inputToken,
intermediaryOutputTokenAddress
)
) {
return [];
}
// Check if intermediary output token is known
const intermediaryOutputTokenAddress = l1Token.addresses[intermediaryChainId];
if (!intermediaryOutputTokenAddress) {
return;
}
const intermediaryOutputToken = getTokenByAddress(
intermediaryOutputTokenAddress,
indirectChainDestination.intermediaryChain
);
if (!intermediaryOutputToken) {
return;
}

return {
inputToken: {
symbol: inputToken.symbol,
name: inputToken.name,
decimals: inputToken.decimals,
address: inputToken.addresses[params.originChainId],
chainId: params.originChainId,
coingeckoId: inputToken.coingeckoId,
},
intermediaryOutputToken: {
symbol: intermediaryOutputToken.symbol,
name: intermediaryOutputToken.name,
decimals: intermediaryOutputToken.decimals,
address: intermediaryOutputToken.addresses[_intermediaryChainId],
chainId: _intermediaryChainId,
coingeckoId: intermediaryOutputToken.coingeckoId,
},
outputToken: {
symbol: indirectOutputToken.symbol,
name: indirectOutputToken.name,
decimals: indirectOutputToken.decimals,
address: indirectOutputToken.addresses[params.destinationChainId],
chainId: params.destinationChainId,
coingeckoId: indirectOutputToken.coingeckoId,
},
};
}
);
// Check if there is a route from the origin chain to the intermediary chain
if (
!isRouteEnabled(
params.originChainId,
intermediaryChainId,
params.inputToken,
intermediaryOutputTokenAddress
)
) {
return;
}

return indirectDestinationRoutes;
return {
inputToken: {
symbol: inputToken.symbol,
decimals: inputToken.decimals,
address: inputToken.addresses[params.originChainId],
chainId: params.originChainId,
},
intermediaryOutputToken: {
symbol: intermediaryOutputToken.symbol,
decimals: intermediaryOutputToken.decimals,
address: intermediaryOutputToken.addresses[intermediaryChainId],
chainId: intermediaryChainId,
},
outputToken: {
symbol: indirectOutputToken.symbol,
decimals: indirectOutputToken.decimals,
address: indirectOutputToken.addresses[params.destinationChainId],
chainId: params.destinationChainId,
},
};
}

export function getIndirectBridgeQuoteMessage(
Expand Down Expand Up @@ -227,7 +212,7 @@ function _buildIndirectBridgeQuoteMessageToHyperCore(
function _buildBridgeQuoteMessageToHyperCore(
crossSwap: CrossSwap,
bridgeableOutputAmount: BigNumber,
indirectDestinationRoute: ReturnType<typeof getIndirectDestinationRoutes>[0],
indirectDestinationRoute: IndirectDestinationRoute,
appFee?: AppFee
) {
const {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"license": "AGPL-3.0-only",
"dependencies": {
"@across-protocol/constants": "^3.1.77",
"@across-protocol/constants": "^3.1.80",
"@across-protocol/contracts": "^4.1.9",
"@across-protocol/contracts-v4.1.1": "npm:@across-protocol/contracts@4.1.1",
"@across-protocol/sdk": "^4.3.67",
Expand Down
8 changes: 3 additions & 5 deletions scripts/chain-configs/hypercore/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ChainConfig } from "../types";
export default {
chainId: 1337, // Arbitrary chain id for HyperCore
name: "HyperCore",
fullName: "HyperCore",
fullName: "Hyperliquid",
logoPath: "./assets/logo.svg",
grayscaleLogoPath: "./assets/grayscale-logo.svg",
spokePool: {
Expand All @@ -14,12 +14,10 @@ export default {
publicRpcUrl: "https://api.hyperliquid.xyz",
blockExplorer: "https://app.hyperliquid.xyz/explorer",
blockTimeSeconds: 1,
tokens: [],
inputTokens: [],
outputTokens: ["USDT-SPOT"],
tokens: ["USDT-SPOT"],
enableCCTP: false,
omitViemConfig: true,
nativeToken: "HYPE",
// HyperCore can only be reached via HyperEVM as an intermediary chain.
intermediaryChains: [CHAIN_IDs.HYPEREVM],
intermediaryChain: CHAIN_IDs.HYPEREVM,
} as ChainConfig;
16 changes: 1 addition & 15 deletions scripts/chain-configs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,5 @@ export type ChainConfig = {
toTokenSymbol: string;
externalProjectId?: string;
}[];
intermediaryChains?: number[];
outputTokens?: (
| string
| {
symbol: string;
chainIds: number[];
}
)[];
inputTokens?: (
| string
| {
symbol: string;
chainIds: number[];
}
)[];
intermediaryChain?: number;
};
1 change: 1 addition & 0 deletions scripts/extern-configs/hyperliquid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ExternalProjectConfig } from "../types";

export default {
name: "Hyperliquid",
fullName: "Hyperliquid",
projectId: "hyperliquid",
explorer: "https://arbiscan.io",
logoPath: "./assets/logo.svg",
Expand Down
Loading